package simpleorm import ( "reflect" "strings" "unicode" log "gitlab.com/gdulai/simpleloglvl" ) type Parser struct { typ reflect.Type Table *Table } func NewParser(obj any) *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() *Table { table := Table{Name: camelToSnake(p.typ.Name()), TypeName: p.typ.Name()} var columns []Column for field := range p.typ.Fields() { field := field col := NewColumn(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 *OrmCache) { pkConstraint := Constraint{Name: "pk_" + strings.ToLower(p.Table.Name), Type: "pk"} fkConstraints := make(map[string]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 = 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": return "INTEGER" case "time.Time", "int64": return "BIGINT" } return "VARCHAR(255)" } func camelToSnake(str string) string { var snake strings.Builder isPrevUpper := true for _, c := range str { if unicode.IsUpper(c) && !isPrevUpper { snake.WriteString("_" + string(unicode.ToUpper(c))) isPrevUpper = true } else { snake.WriteString(string(unicode.ToUpper(c))) isPrevUpper = unicode.IsUpper(c) } } return snake.String() }