package orm import ( "fmt" "reflect" "strings" ) func (m *Model) createTableSql() string { var fields []string var fks []string for _, field := range m.Fields { isStructOrSliceOfStructs := field.Type.Kind() == reflect.Struct || ((field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array) && field.Type.Elem().Kind() == reflect.Struct) if field.PrimaryKey { fields = append(fields, fmt.Sprintf("%s %s PRIMARY KEY", field.ColumnName, field.ColumnType)) } else if (field.fk != nil && field.fk.Type != HasMany && field.fk.Type != ManyToMany) && field.isForeignKey { colType := serialToRegular(field.ColumnType) if !field.Nullable { colType += " NOT NULL " } ffk := field.fk.RelatedModel.Fields[field.fk.RelatedModel.IDField] if ffk != nil { fks = append(fks, fmt.Sprintf("%s %s REFERENCES %s(%s)", field.ColumnName, colType, field.fk.RelatedModel.TableName, field.fk.RelatedModel.Fields[field.fk.RelatedModel.IDField].ColumnName)) } } else if !isStructOrSliceOfStructs || field.ColumnType != "" { lalala := fmt.Sprintf("%s %s", field.ColumnName, field.ColumnType) if !field.Nullable { lalala += " NOT NULL" } fields = append(fields, lalala) } } inter := strings.Join(fields, ", ") if len(fks) > 0 { inter += ", " inter += strings.Join(fks, ", ") } return fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (%s);", m.TableName, inter) } func (m *Model) createJoinTableSql(relName string) string { ref, ok := m.Relationships[relName] if !ok { return "" } aTable := m.TableName joinTableName := ref.JoinTable() fct := serialToRegular(ref.Model.Fields[ref.Model.IDField].ColumnType) rct := serialToRegular(ref.RelatedModel.Fields[ref.RelatedModel.IDField].ColumnType) pkSection := fmt.Sprintf(",\nPRIMARY KEY (%s, %s_id)", fmt.Sprintf("%s_%s", aTable, pascalToSnakeCase(ref.FieldName), ), ref.RelatedModel.TableName, ) if ref.Type == HasMany || ref.Type == ManyToMany { pkSection = "" } return fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s ( %s %s REFERENCES %s(%s), %s_id %s REFERENCES %s(%s)%s );`, joinTableName, fmt.Sprintf("%s_%s", aTable, pascalToSnakeCase(ref.FieldName), ), fct, ref.Model.TableName, ref.Model.Fields[ref.Model.IDField].ColumnName, ref.RelatedModel.TableName, rct, ref.RelatedModel.TableName, ref.RelatedModel.Fields[ref.RelatedModel.IDField].ColumnName, pkSection, ) } func (m *Model) migrate(engine *Engine) error { sql := m.createTableSql() fmt.Println(sql) if !engine.dryRun { _, err := engine.conn.Exec(engine.ctx, sql) if err != nil { return err } } for relName, rel := range m.Relationships { relkey := rel.Model.Name if (rel.Type == ManyToMany && !engine.m2mSeen[relkey]) || (rel.Model.embeddedIsh && !rel.RelatedModel.embeddedIsh && rel.Type == HasMany) { if rel.Type == ManyToMany { engine.m2mSeen[relkey] = true engine.m2mSeen[rel.RelatedModel.Name] = true } jtsql := m.createJoinTableSql(relName) fmt.Println(jtsql) if !engine.dryRun { _, err := engine.conn.Exec(engine.ctx, jtsql) if err != nil { return err } } } } return nil }