Background:
I have various models for DB Tables which basically consists of structs having fields which map to Table columns.
When I am required to do a query on particular table so I do the following,
tableStruct := []models.ModelName{} // Assuming ModelName is a model witch struct of the format of some table column.
models.DB.Where("column_name = ?", "abc").All(&tableName) // Ignore the syntax its of soda pop
// I get all the data from the table corresponding to this query in tableStruct
Now the problem:
If I get the modelName from some query or api request, then how can I evaluate this expression.
modelName := "xyzModel"
tableStruct := []models. `modelName` {} // How can I evaluate this expression?
In Python it’s simply:
tableStruct = eval(f"models.{modelName}"+"{}")
How can I achieve this functionality in Golang. If not possible then please suggest some other way for the above problem.
As an interpreted language, Python allows evaluating a string as code at runtime (which BTW can be dangerous to do if the string is received from an unknown origin). Go does not have that convenience.
Instead, you can maintain a map from names to models, e.g.
Can you provide more context around how you’re going to use this? Python is a dynamic programming language where code doesn’t need to track object’s types as long as they follow the same protocols (have the same attributes, if they’re callable, indexable, etc.). Go is not dynamic and requires that expressions produce statically-typed values. Because of this major difference, there are some patterns that work in Python but cannot work in Go and need to be refactored. If your models don’t have any common methods (or, as models, perhaps have no methods), then you have to store them as interface{}s.
However, It looks like you’re not storing model instances, but instead their types so you can instantiate them. You could do something similar in Go, but you will need to keep a map of your types manually, like Christoph said. There’s no way to lookup a type or a function from a package, even with the reflect package.
var modelTypes = map[string]reflect.Type{
reflect.TypeOf(Model1{}),
reflect.TypeOf(Model2{}),
// ...
}
func query(modelName string) (interface{}, error) {
modelType, ok := modelTypes[modelName]
if !ok {
return nil, errBadType
}
sliceType := reflect.SliceOf(modelType)
slicePtr := reflect.New(sliceType) // pointer to ensure it's addressable
slicePtr.Elem().Set(reflect.MakeSlice(sliceType, 0, 4)) // arbitrary initial capacity
models.DB.Where("column_name = ?", "abc").All(slicePtr.Interface())
// Because types must be static, and Go doesn't yet support
// generics, you're stuck with an interface{} that holds the
// proper []ModelType inside. The caller will have to
// type assert the result to the proper type.
return slicePtr.Elem().Interface(), nil
}
We might be able to provide alternatives to having the caller know and convert the type if we see what you do with the result.