github.com/octohelm/storage@v0.0.0-20240516030302-1ac2cc1ea347/pkg/sqlbuilder/def_column.go (about) 1 package sqlbuilder 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "strings" 8 9 "github.com/octohelm/x/types" 10 ) 11 12 type Column interface { 13 SqlExpr 14 TableDefinition 15 Def() ColumnDef 16 Expr(query string, args ...any) *Ex 17 Of(table Table) Column 18 With(optionFns ...ColOptionFunc) Column 19 MatchName(name string) bool 20 Name() string 21 FieldName() string 22 } 23 24 type ColumnSetter interface { 25 SetFieldName(name string) 26 SetColumnDef(def ColumnDef) 27 } 28 29 type ColOptionFunc func(c ColumnSetter) 30 31 func ColField(fieldName string) ColOptionFunc { 32 return func(c ColumnSetter) { 33 c.SetFieldName(fieldName) 34 } 35 } 36 37 func ColDef(def ColumnDef) ColOptionFunc { 38 return func(c ColumnSetter) { 39 c.SetColumnDef(def) 40 } 41 } 42 43 func ColTypeOf(v any, tagValue string) ColOptionFunc { 44 return func(c ColumnSetter) { 45 c.SetColumnDef(*ColumnDefFromTypeAndTag(types.FromRType(reflect.TypeOf(v)), tagValue)) 46 } 47 } 48 49 func Col(name string, fns ...ColOptionFunc) Column { 50 c := &column[any]{ 51 name: strings.ToLower(name), 52 def: ColumnDef{}, 53 } 54 55 for i := range fns { 56 fns[i](c) 57 } 58 59 return c 60 } 61 62 var _ TableDefinition = (*column[any])(nil) 63 64 type column[T any] struct { 65 name string 66 fieldName string 67 table Table 68 def ColumnDef 69 } 70 71 func (c *column[T]) SetFieldName(name string) { 72 c.fieldName = name 73 } 74 75 func (c *column[T]) SetColumnDef(def ColumnDef) { 76 c.def = def 77 } 78 79 func (c *column[T]) FieldName() string { 80 return c.fieldName 81 } 82 83 func (c *column[T]) Def() ColumnDef { 84 return c.def 85 } 86 87 func (c *column[T]) With(optionFns ...ColOptionFunc) Column { 88 cc := &column[T]{ 89 name: c.name, 90 fieldName: c.fieldName, 91 table: c.table, 92 def: c.def, 93 } 94 95 for i := range optionFns { 96 optionFns[i](c) 97 } 98 99 return cc 100 } 101 102 func (c *column[T]) MatchName(name string) bool { 103 if name == "" { 104 return false 105 } 106 107 // first child upper should be fieldName 108 if name[0] >= 'A' && name[0] <= 'Z' { 109 return c.fieldName == name 110 } 111 112 return c.name == name 113 } 114 115 func (c *column[T]) T() Table { 116 return c.table 117 } 118 119 func (c *column[T]) Name() string { 120 return c.name 121 } 122 123 func (c column[T]) Of(table Table) Column { 124 return &column[T]{ 125 table: table, 126 name: c.name, 127 fieldName: c.fieldName, 128 def: c.def, 129 } 130 } 131 132 func (c *column[T]) IsNil() bool { 133 return c == nil 134 } 135 136 func (c *column[T]) Ex(ctx context.Context) *Ex { 137 toggles := TogglesFromContext(ctx) 138 if toggles.Is(ToggleMultiTable) { 139 if c.table == nil { 140 panic(fmt.Errorf("table of %s is not defined", c.name)) 141 } 142 if toggles.Is(ToggleNeedAutoAlias) { 143 return Expr("?.? AS ?", c.table, Expr(c.name), Expr(fmt.Sprintf("%s__%s", c.table.TableName(), c.name))).Ex(ctx) 144 } 145 return Expr("?.?", c.table, Expr(c.name)).Ex(ctx) 146 } 147 return ExactlyExpr(c.name).Ex(ctx) 148 } 149 150 func (c *column[T]) Expr(query string, args ...any) *Ex { 151 n := len(args) 152 e := Expr("") 153 e.Grow(n) 154 155 qc := 0 156 157 for _, key := range []byte(query) { 158 switch key { 159 case '#': 160 e.WriteExpr(c) 161 case '?': 162 e.WriteQueryByte(key) 163 if n > qc { 164 e.AppendArgs(args[qc]) 165 qc++ 166 } 167 default: 168 e.WriteQueryByte(key) 169 } 170 } 171 172 return e 173 } 174 175 func (c *column[T]) By(ops ...ColumnValueExpr[T]) Assignment { 176 if len(ops) == 0 { 177 return nil 178 } 179 values := make([]any, len(ops)) 180 for i := range ops { 181 values[i] = ops[i](c) 182 } 183 return ColumnsAndValues(c, values...) 184 } 185 186 func (c *column[T]) V(operator ColumnValueExpr[T]) SqlExpr { 187 return operator(c) 188 }