package simpleorm import ( "errors" "reflect" "strings" "time" ) type Table struct { Name string Type reflect.Type Columns []Column Constraints []Constraint } func (t Table) ToDDL() string { var ddl strings.Builder ddl.WriteString("CREATE TABLE IF NOT EXISTS " + t.Name + " (") for i, col := range t.Columns { if i != 0 { ddl.WriteString(", ") } ddl.WriteString(col.ToDDL()) } for _, constr := range t.Constraints { ddl.WriteString(", " + constr.ToDDL()) } ddl.WriteString(");") return ddl.String() } func (t Table) ToSelectDML() string { var dml strings.Builder dml.WriteString("SELECT ") for i, col := range t.Columns { if i != 0 { dml.WriteString(", ") } dml.WriteString(col.Name) } dml.WriteString(" FROM " + t.Name) return dml.String() } func (t Table) ToInsertDML(count int) string { var dml strings.Builder dml.WriteString("INSERT INTO " + camelToSnake(t.Type.Name()) + " (") columnsLen := len(t.Columns) effectiveColumnsLen := 0 for i, col := range t.Columns { _, ok := col.Modifiers["pk"] if ok { continue } dml.WriteString(col.Name) if i != columnsLen-1 { dml.WriteString(", ") } effectiveColumnsLen++ } dml.WriteString(") VALUES") for i := range count { if i != 0 { dml.WriteString(", ") } for j := range effectiveColumnsLen { if j == 0 { dml.WriteString("(") } if j != effectiveColumnsLen-1 { dml.WriteString("?, ") } else { dml.WriteString("?)") } } } return dml.String() } func (t Table) ToUpdateDML(src any) string { var dml strings.Builder dml.WriteString("UPDATE " + camelToSnake(t.Type.Name()) + " SET ") var pkCol string // Colum names for i := 0; i < t.Type.NumField(); i++ { field := t.Type.Field(i) modifiers := determineModifiers(field.Tag) _, ok := modifiers["pk"] if ok { pkCol = camelToSnake(field.Name) continue } if i != t.Type.NumField()-1 { dml.WriteString(camelToSnake(field.Name) + " = ?, ") } else { dml.WriteString(camelToSnake(field.Name) + " = ? ") } } dml.WriteString("WHERE " + pkCol + " = ?") return dml.String() } func (t Table) ToDeleteDML(src any) string { var dml strings.Builder dml.WriteString("DELETE FROM " + camelToSnake(t.Type.Name()) + " WHERE ") for i := 0; i < t.Type.NumField(); i++ { field := t.Type.Field(i) modifiers := determineModifiers(field.Tag) _, ok := modifiers["pk"] if ok { dml.WriteString(camelToSnake(field.Name) + " = ?") return dml.String() } } return "" } func (t Table) createSelectResultContainer() []any { vals := make([]any, t.Type.NumField()) for i := range vals { switch t.Type.Field(i).Type.Kind().String() { case "string": var fieldContainer string vals[i] = &fieldContainer case "int": var fieldContainer int vals[i] = &fieldContainer case "int64", "time.Time": var fieldContainer int64 vals[i] = &fieldContainer } } return vals } func (t Table) prepareParams(src any) []any { var params []any for i := 0; i < t.Type.NumField(); i++ { field := t.Type.Field(i) modifiers := determineModifiers(field.Tag) _, ok := modifiers["pk"] if ok { continue } typStr := field.Type.String() switch typStr { case "time.Time": time := reflect.ValueOf(src).Field(i).Interface().(time.Time) params = append(params, time.UnixMilli()) default: params = append(params, reflect.ValueOf(src).Field(i).Interface()) } } return params } func (t Table) getPk(src any) (any, error) { for i := 0; i < t.Type.NumField(); i++ { field := t.Type.Field(i) modifiers := determineModifiers(field.Tag) _, ok := modifiers["pk"] if ok { return reflect.ValueOf(src).Field(i).Interface(), nil } } return nil, errors.New("Could not determine pk column!") }