golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.87k stars 17.65k forks source link

Creating type register, delete type related functions #19124

Closed PumpkinSeed closed 7 years ago

PumpkinSeed commented 7 years ago

Basically it is not an issue, but I don't find the solution, I read about a lot and ask it many times on SO.

What version of Go are you using (go version)?

go1.7 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64" GOBIN="" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/loow/gopath" GORACE="" GOROOT="/usr/lib/golang" GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64" CC="gcc" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build217134262=/tmp/go-build -gno-record-gcc-switches" CXX="g++" CGO_ENABLED="1"

The core idea

Creating a Database Manager which is getting a json request which is contain sql related data for example the basic json looks like: {"method": "first", "table": "users"}. The method mean getting the first row from table. There is many of tables, all of them a struct which is represent the table. The database ORM is the gorm so this json is looks like after I connect to the database something like: db.First(&user) where the db is a *gorm.DB and the user is an instance of the Users struct. The core question how I get an instance of the struct where I only have a table name?

First solution

First solution which is working, but there is a problem what I detail after. So there is many of struct where a struct look like:

type Users struct {
    ID uint  
    Name string  
    Email string  
    Token string 
}
func (u *Users) TableName() string {
    return "users"
}

So there is fields and a method which is return the table name. There is a map which stores the table names and return back a pointer instance of the given struct.

var Models = map[string]interface{}{
    "users":   new(Users),
    "categories": new(Categories),
}

The Operation struct have one field, the *gorm.DB and many of functions for example, the first:

func (o Operation) First(model string) string {
    modelStruct := Models[model]
    o.DB.First(modelStruct)
    response, _ := json.Marshal(modelStruct)
    clear(modelStruct)
    return string(response)
}

This function is just doing the database call and return it as a json after clear the pointer.

func clear(v interface{}) {
    p := reflect.ValueOf(v).Elem()
    p.Set(reflect.Zero(p.Type()))
}

This is working but when I want to call the First in concurrancy the clear not working instead of got a panic of nil pointer. If I don't clear the gorm take an extra where because thinking it is an old request.

Second solution

It is not working, but I need something similar. I have a type register.

var typeRegistry = make(map[string]reflect.Type)

func init() {
    typeRegistry["users"] = reflect.TypeOf(Users{})
}

When I get it I want to use the reflect.New function.

var modelStruct = reflect.New(typeRegistry[model]).Elem()

But this is return a reflect.Value, It would be great, but in this case the functions which is related to the struct will disappear. So the gorm return back an error, there isn't function TableName.

Real question

I know the Go is a static language, but how can I handle these types, for always creating the proper instance of the struct?

ALTree commented 7 years ago

Hi,

the Go project does not use its bug tracker for general discussion or asking questions. The Github bug tracker is only used for tracking bugs and proposals going through the Proposal Process.

ask it many times on SO

Please see the Questions wiki page; it has a list of good places for asking questions. If the question wasn't answered on stackoverflow, please try on one of the other go forum on the web, thanks. It's likely that nobody will answer your question here on the issue tracker, because as I wrote we only use it for issues.

Closing, since this is not a bug.