11package query
22
33import (
4- "log"
54 "reflect"
65 "strings"
76
87 "github.com/core-go/search"
98 f "github.com/core-go/search/firestore"
109)
1110
12- type Builder [T any , F any ] struct {
11+ type Builder [F any ] struct {
1312 ModelType reflect.Type
1413}
1514
16- func UseQuery [T any , F any ]() func (F ) ([]f.Query , []string ) {
17- bu := NewBuilder [T , F ]()
18- return bu .BuildQuery
15+ func NewBuilder [F any ](resultModelType reflect.Type ) * Builder [F ] {
16+ return & Builder [F ]{ModelType : resultModelType }
1917}
20-
21- func NewBuilder [T any , F any ]() * Builder [T , F ] {
18+ func UseQuery [T any , F any ]() func (F ) ([]f.Query , []string ) {
2219 var t T
2320 resultModelType := reflect .TypeOf (t )
24- if resultModelType .Kind () == reflect .Ptr {
25- resultModelType = resultModelType .Elem ()
26- }
27- return & Builder [T , F ]{ModelType : resultModelType }
21+ b := NewBuilder [F ](resultModelType )
22+ return b .BuildQuery
2823}
29- func (b * Builder [T , F ]) BuildQuery (filter F ) ([]f.Query , []string ) {
24+ func (b * Builder [F ]) BuildQuery (filter F ) ([]f.Query , []string ) {
3025 return BuildQueryByType (filter , b .ModelType )
3126}
3227
28+ var operators = map [string ]string {
29+ "=" : "==" ,
30+ "==" : "==" ,
31+ "!=" : "!=" ,
32+ ">" : ">" ,
33+ ">=" : ">=" ,
34+ "<" : "<" ,
35+ "<=" : "<=" ,
36+ "array-contains" : "array-contains" ,
37+ "array-contains-any" : "array-contains-any" ,
38+ "in" : "in" ,
39+ "not-in" : "not-in" ,
40+ }
41+
3342func BuildQueryByType (filter interface {}, resultModelType reflect.Type ) ([]f.Query , []string ) {
3443 var query = make ([]f.Query , 0 )
3544 fields := make ([]string , 0 )
@@ -39,34 +48,34 @@ func BuildQueryByType(filter interface{}, resultModelType reflect.Type) ([]f.Que
3948 }
4049
4150 value := reflect .Indirect (reflect .ValueOf (filter ))
51+ filterType := value .Type ()
4252 numField := value .NumField ()
43- var keyword string
44- keywordFormat := map [string ]string {
45- "prefix" : "==" ,
46- "contain" : "==" ,
47- "equal" : "==" ,
48- }
4953 for i := 0 ; i < numField ; i ++ {
54+ fsName := getFirestore (filterType , i )
55+ if fsName == "-" {
56+ continue
57+ }
58+ filterType := value .Type ()
59+ operator := "=="
60+ if key , ok := filterType .Field (i ).Tag .Lookup ("operator" ); ok && len (key ) > 0 {
61+ oper , ok2 := operators [key ]
62+ if ok2 {
63+ operator = oper
64+ }
65+ }
66+
5067 field := value .Field (i )
5168 kind := field .Kind ()
5269 x := field .Interface ()
53- ps := false
5470 var psv string
5571 if kind == reflect .Ptr {
5672 if field .IsNil () {
5773 continue
74+ } else {
75+ field = field .Elem ()
76+ kind = field .Kind ()
77+ x = field .Interface ()
5878 }
59- s0 , ok0 := x .(* string )
60- if ok0 {
61- if s0 == nil || len (* s0 ) == 0 {
62- continue
63- }
64- ps = true
65- psv = * s0
66- }
67- field = field .Elem ()
68- x = field .Interface ()
69- kind = field .Kind ()
7079 }
7180 s0 , ok0 := x .(string )
7281 if ok0 {
@@ -75,119 +84,131 @@ func BuildQueryByType(filter interface{}, resultModelType reflect.Type) ([]f.Que
7584 }
7685 psv = s0
7786 }
78- ks := kind .String ()
87+ if len (fsName ) == 0 {
88+ fsName = getFirestoreName (resultModelType , filterType .Field (i ).Name )
89+ }
7990 if v , ok := x .(search.Filter ); ok {
8091 if len (v .Fields ) > 0 {
8192 for _ , key := range v .Fields {
82- i , _ , columnName := getFieldByJson (resultModelType , key )
83- if len (columnName ) <= 0 {
93+ i , _ , fsName := getFieldByJson (resultModelType , key )
94+ if len (fsName ) <= 0 {
8495 fields = fields [len (fields ):]
8596 break
8697 } else if i == - 1 {
87- columnName = key
88- }
89- fields = append (fields , columnName )
90- }
91- }
92- if len (v .Q ) > 0 {
93- keyword = strings .TrimSpace (v .Q )
94- }
95- continue
96- } else if ps || ks == "string" {
97- var keywordQuery f.Query
98- columnName := getFirestoreName (resultModelType , value .Type ().Field (i ).Name )
99- // var operator string
100- operator := "=="
101- var searchValue interface {}
102- if len (psv ) > 0 {
103- const defaultKey = "contain"
104- if key , ok := value .Type ().Field (i ).Tag .Lookup ("operator" ); ok && len (key ) > 0 {
105- operator = key
106- } else {
107- if key , ok := value .Type ().Field (i ).Tag .Lookup ("match" ); ok {
108- if format , exist := keywordFormat [key ]; exist {
109- operator = format
110- } else {
111- log .Panicf ("match not support \" %v\" format\n " , key )
112- }
113- } else if format , exist := keywordFormat [defaultKey ]; exist {
114- operator = format
98+ fsName = key
11599 }
116- }
117- searchValue = psv
118- } else if len (keyword ) > 0 {
119- if key , ok := value .Type ().Field (i ).Tag .Lookup ("keyword" ); ok {
120- if format , exist := keywordFormat [key ]; exist {
121- operator = format
122- } else {
123- log .Panicf ("keyword not support \" %v\" format\n " , key )
100+ if len (fsName ) > 0 && fsName != "-" {
101+ fields = append (fields , fsName )
124102 }
125103 }
126- searchValue = keyword
127- }
128- if len (columnName ) > 0 && len (operator ) > 0 {
129- keywordQuery = f.Query {Path : columnName , Operator : operator , Value : searchValue }
130- query = append (query , keywordQuery )
131104 }
105+ continue
106+ } else if len (fsName ) == 0 {
107+ continue
108+ }
109+ if len (psv ) > 0 {
110+ query = append (query , f.Query {Path : fsName , Operator : operator , Value : psv })
132111 } else if rangeTime , ok := x .(search.TimeRange ); ok {
133- columnName := getFirestoreName (resultModelType , value .Type ().Field (i ).Name )
134- actionTimeQuery := make ([]f.Query , 0 )
112+ timeQuery := make ([]f.Query , 0 )
135113 if rangeTime .Min == nil {
136- actionTimeQuery = []f.Query {{Path : columnName , Operator : "<=" , Value : rangeTime .Max }}
114+ timeQuery = []f.Query {{Path : fsName , Operator : "<=" , Value : rangeTime .Max }}
137115 } else if rangeTime .Max == nil {
138- actionTimeQuery = []f.Query {{Path : columnName , Operator : ">=" , Value : rangeTime .Min }}
116+ timeQuery = []f.Query {{Path : fsName , Operator : ">=" , Value : rangeTime .Min }}
139117 } else {
140- actionTimeQuery = []f.Query {{Path : columnName , Operator : "< =" , Value : rangeTime .Max }, {Path : columnName , Operator : "> =" , Value : rangeTime .Min }}
118+ timeQuery = []f.Query {{Path : fsName , Operator : "> =" , Value : rangeTime .Min }, {Path : fsName , Operator : "< =" , Value : rangeTime .Max }}
141119 }
142- query = append (query , actionTimeQuery ... )
120+ query = append (query , timeQuery ... )
143121 } else if rangeDate , ok := x .(search.DateRange ); ok {
144- columnName := getFirestoreName (resultModelType , value .Type ().Field (i ).Name )
145- actionDateQuery := make ([]f.Query , 0 )
122+ dateQuery := make ([]f.Query , 0 )
146123 if rangeDate .Min == nil && rangeDate .Max == nil {
147124 continue
148125 } else if rangeDate .Min == nil {
149- actionDateQuery = []f.Query {{Path : columnName , Operator : "<=" , Value : rangeDate .Max }}
126+ dateQuery = []f.Query {{Path : fsName , Operator : "<=" , Value : rangeDate .Max }}
150127 } else if rangeDate .Max == nil {
151- actionDateQuery = []f.Query {{Path : columnName , Operator : ">=" , Value : rangeDate .Min }}
128+ dateQuery = []f.Query {{Path : fsName , Operator : ">=" , Value : rangeDate .Min }}
152129 } else {
153- actionDateQuery = []f.Query {{Path : columnName , Operator : "< =" , Value : rangeDate .Max }, {Path : columnName , Operator : "> =" , Value : rangeDate .Min }}
130+ dateQuery = []f.Query {{Path : fsName , Operator : "> =" , Value : rangeDate .Min }, {Path : fsName , Operator : "< =" , Value : rangeDate .Max }}
154131 }
155- query = append (query , actionDateQuery ... )
132+ query = append (query , dateQuery ... )
156133 } else if numberRange , ok := x .(search.NumberRange ); ok {
157- columnName := getFirestoreName (resultModelType , value .Type ().Field (i ).Name )
158- amountQuery := make ([]f.Query , 0 )
134+ numQuery := make ([]f.Query , 0 )
159135
160136 if numberRange .Min != nil {
161- amountQuery = append (amountQuery , f.Query {Path : columnName , Operator : ">=" , Value : * numberRange .Min })
137+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">=" , Value : * numberRange .Min })
162138 } else if numberRange .Lower != nil {
163- amountQuery = append (amountQuery , f.Query {Path : columnName , Operator : ">" , Value : * numberRange .Lower })
139+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">" , Value : * numberRange .Lower })
164140 }
165141 if numberRange .Max != nil {
166- amountQuery = append (amountQuery , f.Query {Path : columnName , Operator : "<=" , Value : * numberRange .Max })
142+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<=" , Value : * numberRange .Max })
167143 } else if numberRange .Upper != nil {
168- amountQuery = append (amountQuery , f.Query {Path : columnName , Operator : "<" , Value : * numberRange .Upper })
144+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<" , Value : * numberRange .Upper })
169145 }
170146
171- if len (amountQuery ) > 0 {
172- query = append (query , amountQuery ... )
147+ if len (numQuery ) > 0 {
148+ query = append (query , numQuery ... )
173149 }
174- } else if ks == "slice" && reflect .Indirect (reflect .ValueOf (x )).Len () > 0 {
175- columnName := getFirestoreName (resultModelType , value .Type ().Field (i ).Name )
176- q := f.Query {Path : columnName , Operator : "in" , Value : x }
177- query = append (query , q )
178- } else {
179- if _ , ok := x .(search.Filter ); ks == "bool" || (strings .Contains (ks , "int" ) && x != 0 ) || (strings .Contains (ks , "float" ) && x != 0 ) || (! ok && ks == "ptr" && field .Pointer () != 0 ) {
180- v := value .Type ().Field (i ).Name
181- columnName := getFirestoreName (resultModelType , v )
182- if len (columnName ) > 0 {
183- oper := "=="
184- if key , ok := value .Type ().Field (i ).Tag .Lookup ("operator" ); ok && len (key ) > 0 {
185- oper = key
186- }
187- q := f.Query {Path : columnName , Operator : oper , Value : x }
188- query = append (query , q )
150+ } else if numberRange , ok := x .(search.Int64Range ); ok {
151+ numQuery := make ([]f.Query , 0 )
152+
153+ if numberRange .Min != nil {
154+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">=" , Value : * numberRange .Min })
155+ } else if numberRange .Lower != nil {
156+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">" , Value : * numberRange .Lower })
157+ }
158+ if numberRange .Max != nil {
159+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<=" , Value : * numberRange .Max })
160+ } else if numberRange .Upper != nil {
161+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<" , Value : * numberRange .Upper })
162+ }
163+
164+ if len (numQuery ) > 0 {
165+ query = append (query , numQuery ... )
166+ }
167+ } else if numberRange , ok := x .(search.IntRange ); ok {
168+ numQuery := make ([]f.Query , 0 )
169+
170+ if numberRange .Min != nil {
171+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">=" , Value : * numberRange .Min })
172+ } else if numberRange .Lower != nil {
173+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">" , Value : * numberRange .Lower })
174+ }
175+ if numberRange .Max != nil {
176+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<=" , Value : * numberRange .Max })
177+ } else if numberRange .Upper != nil {
178+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<" , Value : * numberRange .Upper })
179+ }
180+
181+ if len (numQuery ) > 0 {
182+ query = append (query , numQuery ... )
183+ }
184+ } else if numberRange , ok := x .(search.Int32Range ); ok {
185+ numQuery := make ([]f.Query , 0 )
186+
187+ if numberRange .Min != nil {
188+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">=" , Value : * numberRange .Min })
189+ } else if numberRange .Lower != nil {
190+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : ">" , Value : * numberRange .Lower })
191+ }
192+ if numberRange .Max != nil {
193+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<=" , Value : * numberRange .Max })
194+ } else if numberRange .Upper != nil {
195+ numQuery = append (numQuery , f.Query {Path : fsName , Operator : "<" , Value : * numberRange .Upper })
196+ }
197+
198+ if len (numQuery ) > 0 {
199+ query = append (query , numQuery ... )
200+ }
201+ } else if kind == reflect .Slice {
202+ if reflect .Indirect (reflect .ValueOf (x )).Len () > 0 {
203+ if operator == "==" {
204+ operator = "in"
189205 }
206+ q := f.Query {Path : fsName , Operator : operator , Value : x }
207+ query = append (query , q )
190208 }
209+ } else {
210+ q := f.Query {Path : fsName , Operator : operator , Value : x }
211+ query = append (query , q )
191212 }
192213 }
193214 return query , fields
@@ -216,3 +237,10 @@ func getFirestoreName(modelType reflect.Type, fieldName string) string {
216237 }
217238 return fieldName
218239}
240+ func getFirestore (filterType reflect.Type , i int ) string {
241+ field := filterType .Field (i )
242+ if tag , ok := field .Tag .Lookup ("firestore" ); ok {
243+ return strings .Split (tag , "," )[0 ]
244+ }
245+ return ""
246+ }
0 commit comments