How to create a new instance of a struct that is read from file

139 Views Asked by At

I know this may seem like bad design (and I wish I didn't need to do this), but I need to read a struct that is generated automatically at run time and create a new instance of it.

The struct that I create I only need limited metadata of so that it can be passed to the Gorm Gen FieldRelateModel method (from here) where 'relModel' is the new instance I am hoping to make (see below):

    FieldRelateModel = func(relationship field.RelationshipType, fieldName string, relModel interface{}, config *field.RelateConfig) model.CreateFieldOpt {
        st := reflect.TypeOf(relModel)
        if st.Kind() == reflect.Ptr {
            st = st.Elem()
        }
        fieldType := st.String()

        if config == nil {
            config = &field.RelateConfig{}
        }
        if config.JSONTag == "" {
            config.JSONTag = ns.ColumnName("", fieldName)
        }

        return func(*model.Field) *model.Field {
            return &model.Field{
                Name:         fieldName,
                Type:         config.RelateFieldPrefix(relationship) + fieldType,
                JSONTag:      config.JSONTag,
                GORMTag:      config.GORMTag,
                NewTag:       config.NewTag,
                OverwriteTag: config.OverwriteTag,

                Relation: field.NewRelationWithModel(relationship, fieldName, fieldType, relModel),
            }
        }
    }

I am able to parse the struct and get its metadata using ast and reflect (see below), but I don't know how I can do the last step so that the 'structInstance' I return is valid when passed as the 'relModel' to the 'FieldRelateModel' function/option.

func StructExtract(filePath string) (any, error) {
    file, err := os.Open(filePath)
    if err != nil {
        fmt.Println(err)
        return nil, err
    }
    defer file.Close()

    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, filePath, file, parser.AllErrors)
    if err != nil {
        fmt.Println(err)
        return nil, err
    }

    var structType *ast.StructType

    // Iterate over the top-level declarations in the file
    for _, decl := range f.Decls {
        // Check if the declaration is a GenDecl (which can contain structs)
        genDecl, ok := decl.(*ast.GenDecl)
        if !ok {
            continue
        }

        // Iterate over the GenDecl's specs
        for _, spec := range genDecl.Specs {
            // Check if the spec is a TypeSpec (which can contain structs)
            typeSpec, ok := spec.(*ast.TypeSpec)
            if !ok {
                continue
            }

            // Check if the TypeSpec's type is a struct
            structType, ok = typeSpec.Type.(*ast.StructType)
            if !ok {
                continue
            }

            break
        }
    }

    if structType == nil {
        fmt.Println("No struct found in file.")
        return nil, err
    }

    structInstance := reflect.New(reflect.TypeOf(structType)).Elem().Interface()

    return structInstance, nil
}

Here is a go playground that I thought might make it easier if someone were to help, however, due to the nature of the problem it won't be able to run within the playground (for various reasons).

0

There are 0 best solutions below