package schema import ( "reflect" "strings" "git.gdulai.com/gdulai/simpleorm/util" log "gitlab.com/gdulai/simpleloglvl" ) type Parser struct { typ reflect.Type columns []Column constraints []Constraint } func NewParser[T any](obj T) *Parser { objType := reflect.TypeOf(obj) return &Parser{typ: objType} } // Step 1 of the parsing, it creates the table instance and func (p *Parser) ParseColumns() { var columns []Column for field := range p.typ.Fields() { field := field col := NewColumn(util.CamelToSnake((field.Name)), field.Name, determineType(field.Type), field.Tag) columns = append(columns, col) } p.columns = columns } // Step 2 of the parsing, it creates the constrains with the table references func (p *Parser) ParseConstraints(tableParsers map[string]*Parser) { pkConstraint := Constraint{Name: "pk_" + strings.ToLower(util.CamelToSnake((p.typ.Name()))), Type: "pk"} fkConstraints := make(map[string]Constraint) for _, col := range p.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, ".") refTypeName := fkModParts[0] refTableName := util.CamelToSnake(refTypeName) parser, ok := tableParsers[refTypeName] if !ok { log.LogError("[ORM] Reference table not found", refTypeName) } fkId, ok := col.Modifiers["fk_id"] if fkId == "" { fkId = "fk_" + strings.ToLower(refTableName) } fkConstraint, ok := fkConstraints[fkId] if !ok { fkConstraint = Constraint{Name: fkId, Type: "fk", RefTypeName: refTypeName} } fkConstraint.Columns = append(fkConstraint.Columns, col) refField := fkModParts[1] for _, refC := range parser.columns { if refC.FieldName == refField { fkConstraint.RefColumns = append(fkConstraint.RefColumns, refC) } } fkConstraints[fkId] = fkConstraint } p.constraints = append(p.constraints, pkConstraint) for _, fkConstraint := range fkConstraints { p.constraints = append(p.constraints, fkConstraint) } } // Step 3 of the paring, create the schema.Table instance // Returns the schema.Table pointer func (p Parser) ParseTable() *Table { return &Table{name: util.CamelToSnake(p.typ.Name()), typ: p.typ, columns: p.columns, constraints: p.constraints} } 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)" }