1

I am writing microservices in Go. After some coding, I decided to give a more dynamic approach for my querying system, but I am having some issues.

What I would like to do, is call a function from a file that will query the database, set the data to the Model, and return the result. By this, I mean something like the schema below

// database_manager.go
func DbCall(query string, TableModel interface{}) interface{} {
  db, _ := sqlx.Connect(/*All my parameters and so on */)

  model := []TableModel{}
  err := db.Select(&model, query)
  if err != nil {
    return nil
  }

  return model
}

// /blog/models/blog_articles.go
type BlogArticles struct {
    Article_id int    `json:"article_id"`
    Title      string `json:"title"`
    Text       string `json:"text"`
}

// /blog/services/blog_articles.go
func CustomService() []BlogArticles {
  table = []BlogArticles
  data := DbCall("SELECT * FROM blog_articles", &table)
  return data
}

However, this approach does return different errors, ranging from "non-struct dest type interface with >1 columns (3)" to "expected slice but got interface"

this and this solutions did not help me.

I have looked at different answers around StackOverflow, but none really solve my issue.

So I thought that my issue is either unsolvable or poorly approached or that I am just making a mess.

I would like to ask those with more experience if what I am thinking and trying to do is feasible, possible, and a good way to have a dynamic approach to my goal.

To sum up a little:

  1. Does my idea make sense and is it feasible?

  2. If so, how could I potentially pass a Model from one function to another and use it in this dynamic way?

  3. Eventually, is this approach correct? Should I change my way of approaching this? Is there a better way to have my code rather dynamic?

Thanks for the help and for reading thus far

noxter
  • 186
  • 1
  • 11
  • You cannot use plain variables as types. e.g. `TableModel interface{}` and then `[]TableModel{}` is just never gonna work. Take a look at generics perhaps. But definitely re-read what an interface is. – mkopriva Oct 05 '22 at 20:31
  • Unrelated to your specific question: Use connection pools. I don't know what `sqlx.Connect` returns but it looks like it's initializing a new connection. Doing that per each `DbCall` is unwise (unnecessarily slow). – mkopriva Oct 05 '22 at 20:35
  • Why don't you just replace `data := DbCall("SELECT * FROM blog_articles", &table)` with `err := db.Select(&table, "SELECT * FROM blog_articles")`? – mkopriva Oct 05 '22 at 20:37
  • I will consider using pools. I felt like that was a thing I wanted to look at. Thanks for the tip. For the other comment, I would like to keep a file responsible for the database/query management, so I would just have to import that and use its method (DbCall e.g.) So it would've been a single function call that does all the connection, querying and stuff like this at once, without the need to do that. If you believe that won't work I may consider using the approach you advised – noxter Oct 05 '22 at 20:43
  • Maybe I misunderstand but that approach implies getting rid of proper error handling. If that is what you were looking for then I have bad news. Trying to work around normal error handling, either by using panic/recover or by outright ignoring it is a huge red flag in like the whole of the Go community. Don't do it. Don't even try. – mkopriva Oct 05 '22 at 20:48
  • And if that is not what you were trying to do then I'm failing to understand how `err := db.Select(&table, "SELECT * FROM blog_articles")` is a problem. I mean you can wrap that call in your DbCall inside your file if that is what you wish to do, that's completely fine. – mkopriva Oct 05 '22 at 20:51
  • I don't want to get rid of proper error handling. I just wanted to try to see if what I had in mind was a good thing. I will keep in mind everything you said and will use the approach you told me. I thank you for your time! – noxter Oct 05 '22 at 20:59
  • Just to clarify; the errors you've mentioned can be fixed by simply passing the `DbCall`'s `TableModel` parameter directly to `Select` (without the invalid `model := []TableModel{}` thing) [example](https://go.dev/play/p/xSILkNvMqKH). There's also no reason to return the "model" since the caller is passing a pointer to it, so they have *direct* access to the value. And once you start using a db pool you end up will `DbCall` that's just a one-liner calling `db.Select`. – mkopriva Oct 05 '22 at 21:09
  • Worked like a charm but I will keep in mind everything you told me above, pools too. I once again thank you for your patience and time! – noxter Oct 05 '22 at 21:55

0 Answers0