package parser import ( "reflect" "strings" cache "git.gdulai.com/gdulai/simpleorm/cache" "git.gdulai.com/gdulai/simpleorm/schema" "git.gdulai.com/gdulai/simpleorm/util" log "gitlab.com/gdulai/simpleloglvl" ) type Parser struct { typ reflect.Type Table *schema.Table } func NewParser[T any](obj T) *Parser { objType := reflect.TypeOf(obj) return &Parser{typ: objType} } // This is step 1 of the parsing, it creates the table instance and func (p *Parser) ParseColumns() *schema.Table { table := schema.Table{Name: util.CamelToSnake(p.typ.Name()), Type: p.typ} var columns []schema.Column for field := range p.typ.Fields() { field := field col := schema.NewColumn(util.CamelToSnake((field.Name)), field.Name, determineType(field.Type), field.Tag) columns = append(columns, col) } table.Columns = columns p.Table = &table return p.Table } func (p *Parser) ParseConstraints(cache *cache.SchemaCache) { pkConstraint := schema.Constraint{Name: "pk_" + strings.ToLower(p.Table.Name), Type: "pk"} fkConstraints := make(map[string]schema.Constraint) for _, col := range p.Table.Columns { _, ok := col.Modifiers["pk"] if ok { pkConstraint.Columns = append(pkConstraint.Columns, col) continue } fkMod, ok := col.Modifiers["fk"] if !ok { continue } fkModParts := strings.Split(fkMod, ".") refTable, ok := cache.Get(fkModParts[0]) if !ok { log.LogError("[ORM] Table %s not found in OrmCache!", fkModParts[0]) return } fkId, ok := col.Modifiers["fk_id"] if fkId == "" { fkId = "fk_" + strings.ToLower(refTable.Name) } fkConstraint, ok := fkConstraints[fkId] if !ok { fkConstraint = schema.Constraint{Name: fkId, Type: "fk", RefTable: refTable} } fkConstraint.Columns = append(fkConstraint.Columns, col) refField := fkModParts[1] for _, refC := range refTable.Columns { if refC.FieldName == refField { fkConstraint.RefColumns = append(fkConstraint.RefColumns, refC) } } fkConstraints[fkId] = fkConstraint } p.Table.Constraints = append(p.Table.Constraints, pkConstraint) for _, fkConstraint := range fkConstraints { p.Table.Constraints = append(p.Table.Constraints, fkConstraint) } } func determineType(typ reflect.Type) string { typStr := typ.String() switch typStr { case "string": return "TEXT" case "int", "bool": return "INTEGER" case "time.Time", "int64": return "BIGINT" } return "VARCHAR(255)" }