Skip to content

Commit 2e30666

Browse files
committed
Refactor sql builder
1 parent 99f04ad commit 2e30666

8 files changed

Lines changed: 312 additions & 303 deletions

File tree

cassandra/query/query_builder.go

Lines changed: 108 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package query
22

33
import (
4+
"database/sql"
45
"fmt"
56
"reflect"
67
"strings"
@@ -15,31 +16,27 @@ const (
1516
)
1617

1718
type Builder[T any, F any] struct {
18-
TableName string
19-
ModelType reflect.Type
20-
BuildParam func(int) string
19+
TableName string
20+
ModelType reflect.Type
2121
}
2222

23-
func UseQuery[T any, F any](tableName string, options ...func(int) string) func(F) (string, []interface{}) {
24-
b := NewBuilder[T, F](tableName, options...)
23+
func UseQuery[T any, F any](db *sql.DB, tableName string) func(F) (string, []interface{}) {
24+
b := NewBuilder[T, F](db, tableName)
2525
return b.BuildQuery
2626
}
27-
func NewBuilder[T any, F any](tableName string, options ...func(int) string) *Builder[T, F] {
28-
var build func(int) string
29-
if len(options) > 0 {
30-
build = options[0]
31-
} else {
32-
build = BuildParam
33-
}
27+
func NewBuilder[T any, F any](db *sql.DB, tableName string) *Builder[T, F] {
28+
return NewBuilderWithDriver[T, F](tableName)
29+
}
30+
func NewBuilderWithDriver[T any, F any](tableName string) *Builder[T, F] {
3431
var t T
3532
resultModelType := reflect.TypeOf(t)
3633
if resultModelType.Kind() == reflect.Ptr {
3734
resultModelType = resultModelType.Elem()
3835
}
39-
return &Builder[T, F]{TableName: tableName, ModelType: resultModelType, BuildParam: build}
36+
return &Builder[T, F]{TableName: tableName, ModelType: resultModelType}
4037
}
4138
func (b *Builder[T, F]) BuildQuery(filter F) (string, []interface{}) {
42-
return Build(filter, b.TableName, b.ModelType, b.BuildParam)
39+
return Build(filter, b.TableName, b.ModelType)
4340
}
4441

4542
const (
@@ -69,12 +66,17 @@ func getJoinFromSqlBuilderTag(typeOfField reflect.StructField) *string {
6966

7067
func getColumnNameFromSqlBuilderTag(typeOfField reflect.StructField) *string {
7168
return getStringFromTag(typeOfField, "sql_builder", "column:")
72-
}
73-
74-
func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam func(int) string) (string, []interface{}) {
75-
if buildParam == nil {
76-
buildParam = BuildParam
69+
/*tag := typeOfField.Tag
70+
properties := strings.Split(tag.Get("sql_builder"), ";")
71+
for _, property := range properties {
72+
if strings.HasPrefix(property, "column:") {
73+
column := property[7:]
74+
return &column
75+
}
7776
}
77+
return nil*/
78+
}
79+
func Build(filter interface{}, tableName string, modelType reflect.Type) (string, []interface{}) {
7880
s1 := ""
7981
rawConditions := make([]string, 0)
8082
queryValues := make([]interface{}, 0)
@@ -85,93 +87,65 @@ func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam
8587
fields := make([]string, 0)
8688
var excluding []string
8789
var keyword string
88-
value := reflect.Indirect(reflect.ValueOf(fm))
89-
typeOfValue := value.Type()
90+
value := reflect.Indirect(reflect.ValueOf(filter))
91+
filterType := value.Type()
9092
numField := value.NumField()
9193
var idCol string
9294
marker := 0
93-
fCount := 0
9495
for i := 0; i < numField; i++ {
96+
columnName := getColumn(filterType, i)
97+
if columnName == "-" {
98+
continue
99+
}
95100
field := value.Field(i)
96101
kind := field.Kind()
97102
x := field.Interface()
98-
typeOfField := value.Type().Field(i)
99-
param := buildParam(marker + 1)
100-
101-
if v, ok := x.(*s.Filter); ok {
102-
if len(v.Fields) > 0 {
103-
for _, key := range v.Fields {
104-
i, _, columnName := getFieldByJson(modelType, key)
105-
if len(columnName) < 0 {
106-
fields = fields[len(fields):]
107-
break
108-
} else if i > -1 {
109-
fields = append(fields, columnName)
110-
}
111-
}
112-
}
113-
if len(fields) > 0 {
114-
s1 = `select ` + strings.Join(fields, ",") + ` from ` + tableName
115-
}
116-
if len(v.Sort) > 0 {
117-
sortString = buildSort(v.Sort, modelType)
118-
}
119-
}
120-
121-
columnName, existCol := getColumnName(value.Type(), typeOfField.Name)
122-
if !existCol {
123-
columnName, _ = getColumnName(modelType, typeOfField.Name)
124-
}
125-
126-
columnNameFromSqlBuilderTag := getColumnNameFromSqlBuilderTag(typeOfField)
127-
if columnNameFromSqlBuilderTag != nil {
128-
columnName = *columnNameFromSqlBuilderTag
129-
}
130-
131-
joinFromSqlBuilderTag := getJoinFromSqlBuilderTag(typeOfField)
132-
if joinFromSqlBuilderTag != nil {
133-
rawJoin = append(rawJoin, *joinFromSqlBuilderTag)
134-
}
135-
ps := false
136-
var value2 string
137-
tag := typeOfValue.Field(i).Tag
103+
tf := value.Type().Field(i)
104+
fieldTypeName := tf.Type.String()
105+
typeOfField := value.Type().Field(i) // ???
106+
var psv string
138107
isContinue := false
139-
isStrPointer := false
108+
param := buildParam(marker + 1)
140109
if kind == reflect.Ptr {
141110
if field.IsNil() {
142-
isContinue = true
143-
isStrPointer = true
144-
} else {
145-
s0, ok0 := x.(*string)
146-
if ok0 {
147-
if s0 == nil || len(*s0) == 0 {
148-
isContinue = true
149-
isStrPointer = true
150-
}
151-
ps = true
152-
value2 = *s0
111+
if fieldTypeName != "*string" {
112+
continue
113+
} else {
114+
isContinue = true
153115
}
116+
} else {
154117
field = field.Elem()
155-
x = field.Interface()
156118
kind = field.Kind()
119+
x = field.Interface()
157120
}
158121
}
159-
if !isStrPointer {
122+
if !isContinue {
160123
s0, ok0 := x.(string)
161124
if ok0 {
162125
if len(s0) == 0 {
163126
isContinue = true
164127
}
165-
value2 = s0
128+
psv = s0
166129
}
167130
}
131+
if len(columnName) == 0 {
132+
_, _, columnName = getFieldByJson(modelType, tf.Name)
133+
}
134+
columnNameFromSqlBuilderTag := getColumnNameFromSqlBuilderTag(typeOfField)
135+
if columnNameFromSqlBuilderTag != nil {
136+
columnName = *columnNameFromSqlBuilderTag
137+
}
138+
139+
joinFromSqlBuilderTag := getJoinFromSqlBuilderTag(typeOfField)
140+
if joinFromSqlBuilderTag != nil {
141+
rawJoin = append(rawJoin, *joinFromSqlBuilderTag)
142+
}
168143
if isContinue {
169144
if len(keyword) > 0 {
170-
qMatch, isQ := tag.Lookup("q")
145+
qMatch, isQ := tf.Tag.Lookup("q")
171146
if isQ {
172147
if qMatch == "=" {
173148
qQueryValues = append(qQueryValues, keyword)
174-
175149
} else if qMatch == "like" {
176150
qQueryValues = append(qQueryValues, buildQ(keyword))
177151
} else {
@@ -183,6 +157,23 @@ func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam
183157
continue
184158
}
185159
if v, ok := x.(s.Filter); ok {
160+
if len(v.Fields) > 0 {
161+
for _, key := range v.Fields {
162+
i, _, columnName := getFieldByJson(modelType, key)
163+
if len(columnName) < 0 {
164+
fields = fields[len(fields):]
165+
break
166+
} else if i > -1 {
167+
fields = append(fields, columnName)
168+
}
169+
}
170+
}
171+
if len(fields) > 0 {
172+
s1 = `select ` + strings.Join(fields, ",") + ` from ` + tableName
173+
}
174+
if len(v.Sort) > 0 {
175+
sortString = buildSort(v.Sort, modelType)
176+
}
186177
if v.Excluding != nil && len(v.Excluding) > 0 {
187178
index, _, columnName := getFieldByBson(value.Type(), "_id")
188179
if !(index == -1 || columnName == "") {
@@ -194,25 +185,22 @@ func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam
194185
keyword = strings.TrimSpace(v.Q)
195186
}
196187
continue
197-
} else if ps || kind == reflect.String {
198-
if len(value2) > 0 {
199-
key, ok := tag.Lookup("operator")
200-
if !ok {
201-
key, _ = tag.Lookup("q")
202-
}
203-
if key == "=" {
204-
rawConditions = append(rawConditions, fmt.Sprintf("%s %s %s", columnName, "=", param))
188+
} else if len(psv) > 0 {
189+
key, ok := tf.Tag.Lookup("operator")
190+
if !ok {
191+
key, _ = tf.Tag.Lookup("q")
192+
}
193+
if key == "=" {
194+
rawConditions = append(rawConditions, fmt.Sprintf("%s %s %s", columnName, "=", param))
195+
} else {
196+
rawConditions = append(rawConditions, fmt.Sprintf("%s %s %s", columnName, like, param))
197+
if key == "like" {
198+
queryValues = append(queryValues, buildQ(psv))
205199
} else {
206-
rawConditions = append(rawConditions, fmt.Sprintf("%s %s %s", columnName, like, param))
207-
fCount = fCount + 1
208-
if key == "like" {
209-
queryValues = append(queryValues, buildQ(value2))
210-
} else {
211-
queryValues = append(queryValues, prefix(value2))
212-
}
200+
queryValues = append(queryValues, prefix(psv))
213201
}
214-
marker++
215202
}
203+
marker++
216204
} else if dateTime, ok := x.(s.TimeRange); ok {
217205
if dateTime.Min != nil {
218206
rawConditions = append(rawConditions, fmt.Sprintf("%s %s %s", columnName, greaterEqualThan, param))
@@ -306,7 +294,7 @@ func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam
306294
marker += field.Len()
307295
}
308296
} else {
309-
key, ok := tag.Lookup("operator")
297+
key, ok := tf.Tag.Lookup("operator")
310298
if !ok {
311299
key = "="
312300
}
@@ -338,23 +326,18 @@ func Build(fm interface{}, tableName string, modelType reflect.Type, buildParam
338326
for i, s := range qCols {
339327
param := buildParam(marker + 1)
340328
qConditions = append(qConditions, fmt.Sprintf("%s %s %s", s, like, param))
341-
fCount = fCount + 1
342329
queryValues = append(queryValues, qQueryValues[i])
343330
marker++
344331
}
345332
if len(qConditions) > 0 {
346333
rawConditions = append(rawConditions, " ("+strings.Join(qConditions, " or ")+") ")
347334
}
348335
}
349-
allowFiltering := ""
350-
if fCount >= 1 {
351-
allowFiltering = " allow filtering"
352-
}
353336
if len(rawConditions) > 0 {
354-
s2 := s1 + ` where ` + strings.Join(rawConditions, " AND ") + sortString + allowFiltering
337+
s2 := s1 + ` where ` + strings.Join(rawConditions, " and ") + sortString
355338
return s2, queryValues
356339
}
357-
s3 := s1 + sortString + allowFiltering
340+
s3 := s1 + sortString
358341
return s3, queryValues
359342
}
360343
func extractArray(values []interface{}, field interface{}) []interface{} {
@@ -389,6 +372,27 @@ func getFieldByJson(modelType reflect.Type, jsonName string) (int, string, strin
389372
}
390373
return -1, jsonName, jsonName
391374
}
375+
func getColumn(filterType reflect.Type, i int) string {
376+
field := filterType.Field(i)
377+
if tag2, ok := field.Tag.Lookup("gorm"); ok {
378+
if tag2 == "-" {
379+
return tag2
380+
}
381+
if has := strings.Contains(tag2, "column"); has {
382+
str1 := strings.Split(tag2, ";")
383+
num := len(str1)
384+
for k := 0; k < num; k++ {
385+
str2 := strings.Split(str1[k], ":")
386+
for j := 0; j < len(str2); j++ {
387+
if str2[j] == "column" {
388+
return str2[j+1]
389+
}
390+
}
391+
}
392+
}
393+
}
394+
return ""
395+
}
392396
func getFieldByBson(modelType reflect.Type, bsonName string) (int, string, string) {
393397
numField := modelType.NumField()
394398
for i := 0; i < numField; i++ {
@@ -503,7 +507,7 @@ func getSortType(sortType string) string {
503507
}
504508
}
505509

506-
func BuildParam(i int) string {
510+
func buildParam(i int) string {
507511
return "?"
508512
}
509513
func buildParametersFrom(i int, numCol int, buildParam func(i int) string) string {

date_range.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@ package search
33
import "time"
44

55
type DateRange struct {
6-
Min *time.Time `yaml:"min" mapstructure:"min" json:"min,omitempty" gorm:"column:startdate" bson:"min,omitempty" dynamodbav:"min,omitempty" firestore:"min,omitempty"`
7-
Max *time.Time `yaml:"max" mapstructure:"max" json:"max,omitempty" gorm:"column:max" bson:"max,omitempty" dynamodbav:"max,omitempty" firestore:"max,omitempty"`
8-
Bottom *time.Time `yaml:"bottom" mapstructure:"bottom" json:"bottom,omitempty" gorm:"column:bottom" bson:"bottom,omitempty" dynamodbav:"bottom,omitempty" firestore:"bottom,omitempty"`
9-
Top *time.Time `yaml:"top" mapstructure:"top" json:"top,omitempty" gorm:"column:top" bson:"top,omitempty" dynamodbav:"top,omitempty" firestore:"top,omitempty"`
10-
Floor *time.Time `yaml:"floor" mapstructure:"floor" json:"floor,omitempty" gorm:"column:floor" bson:"floor,omitempty" dynamodbav:"floor,omitempty" firestore:"floor,omitempty"`
11-
Ceiling *time.Time `yaml:"ceiling" mapstructure:"ceiling" json:"ceiling,omitempty" gorm:"column:ceiling" bson:"ceiling,omitempty" dynamodbav:"ceiling,omitempty" firestore:"ceiling,omitempty"`
12-
Lower *time.Time `yaml:"lower" mapstructure:"lower" json:"lower,omitempty" gorm:"column:lower" bson:"lower,omitempty" dynamodbav:"lower,omitempty" firestore:"lower,omitempty"`
13-
Upper *time.Time `yaml:"upper" mapstructure:"upper" json:"upper,omitempty" gorm:"column:upper" bson:"upper,omitempty" dynamodbav:"upper,omitempty" firestore:"upper,omitempty"`
6+
Min *time.Time `yaml:"min" mapstructure:"min" json:"min,omitempty" gorm:"column:startdate" bson:"min,omitempty" dynamodbav:"min,omitempty" firestore:"min,omitempty"`
7+
Max *time.Time `yaml:"max" mapstructure:"max" json:"max,omitempty" gorm:"column:max" bson:"max,omitempty" dynamodbav:"max,omitempty" firestore:"max,omitempty"`
8+
Bottom *time.Time `yaml:"bottom" mapstructure:"bottom" json:"bottom,omitempty" gorm:"column:bottom" bson:"bottom,omitempty" dynamodbav:"bottom,omitempty" firestore:"bottom,omitempty"`
9+
Top *time.Time `yaml:"top" mapstructure:"top" json:"top,omitempty" gorm:"column:top" bson:"top,omitempty" dynamodbav:"top,omitempty" firestore:"top,omitempty"`
1410
}

0 commit comments

Comments
 (0)