1
1
import {
2
2
AdminForthResource , IAdminForthDataSourceConnectorBase ,
3
3
AdminForthResourceColumn ,
4
- IAdminForthSort , IAdminForthFilter
4
+ IAdminForthSort , IAdminForthSingleFilter , IAdminForthAndOrFilter
5
5
} from "../types/Back.js" ;
6
6
7
7
@@ -15,7 +15,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
15
15
client : any ;
16
16
17
17
get db ( ) {
18
- console . warn ( 'db is deprecated, use client instead' ) ;
18
+ console . warn ( '. db is deprecated, use . client instead' ) ;
19
19
return this . client ;
20
20
}
21
21
@@ -32,27 +32,84 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
32
32
}
33
33
34
34
async getRecordByPrimaryKeyWithOriginalTypes ( resource : AdminForthResource , id : string ) : Promise < any > {
35
- const data = await this . getDataWithOriginalTypes ( {
36
- resource,
37
- limit : 1 ,
35
+ const data = await this . getDataWithOriginalTypes ( {
36
+ resource,
37
+ limit : 1 ,
38
38
offset : 0 ,
39
- sort : [ ] ,
40
- filters : [ { field : this . getPrimaryKey ( resource ) , operator : AdminForthFilterOperators . EQ , value : id } ] ,
39
+ sort : [ ] ,
40
+ filters : { operator : AdminForthFilterOperators . AND , subFilters : [ { field : this . getPrimaryKey ( resource ) , operator : AdminForthFilterOperators . EQ , value : id } ] } ,
41
41
} ) ;
42
42
return data . length > 0 ? data [ 0 ] : null ;
43
43
}
44
44
45
+ validateAndNormalizeFilters ( filters : IAdminForthSingleFilter | IAdminForthAndOrFilter | Array < IAdminForthSingleFilter | IAdminForthAndOrFilter > , resource : AdminForthResource ) : { ok : boolean , error : string } {
46
+ if ( Array . isArray ( filters ) ) {
47
+ // go through all filters in array and call validation+normalization for each
48
+ // as soon as error is encountered, there is no point in calling validation for other filters
49
+ // if error is not encountered all filters will be validated and normalized
50
+ return filters . reduce ( ( result , f ) => {
51
+ if ( ! result . ok ) {
52
+ return result ;
53
+ }
54
+
55
+ return this . validateAndNormalizeFilters ( f , resource ) ;
56
+ } , { ok : true , error : '' } ) ;
57
+ }
58
+
59
+ if ( ! filters . operator ) {
60
+ return { ok : false , error : `Field "operator" not specified in filter object: ${ JSON . stringify ( filters ) } ` } ;
61
+ }
62
+
63
+ if ( ( filters as IAdminForthSingleFilter ) . field ) {
64
+ // if "field" is present, filter must be Single
65
+ if ( ! [ AdminForthFilterOperators . EQ , AdminForthFilterOperators . NE , AdminForthFilterOperators . GT ,
66
+ AdminForthFilterOperators . LT , AdminForthFilterOperators . GTE , AdminForthFilterOperators . LTE ,
67
+ AdminForthFilterOperators . LIKE , AdminForthFilterOperators . ILIKE , AdminForthFilterOperators . IN ,
68
+ AdminForthFilterOperators . NIN ] . includes ( filters . operator ) ) {
69
+ return { ok : false , error : `Field "operator" has wrong value in filter object: ${ JSON . stringify ( filters ) } ` } ;
70
+ }
71
+ const fieldObj = resource . dataSourceColumns . find ( ( col ) => col . name == ( filters as IAdminForthSingleFilter ) . field ) ;
72
+ if ( ! fieldObj ) {
73
+ const similar = suggestIfTypo ( resource . dataSourceColumns . map ( ( col ) => col . name ) , ( filters as IAdminForthSingleFilter ) . field ) ;
74
+ throw new Error ( `Field '${ ( filters as IAdminForthSingleFilter ) . field } ' not found in resource '${ resource . resourceId } '. ${ similar ? `Did you mean '${ similar } '?` : '' } ` ) ;
75
+ }
76
+ if ( filters . operator == AdminForthFilterOperators . IN || filters . operator == AdminForthFilterOperators . NIN ) {
77
+ if ( ! Array . isArray ( filters . value ) ) {
78
+ return { ok : false , error : `Value for operator '${ filters . operator } ' should be an array, in filter object: ${ JSON . stringify ( filters ) } ` } ;
79
+ }
80
+ if ( filters . value . length === 0 ) {
81
+ // nonsense
82
+ return { ok : false , error : `Filter has IN operator but empty value: ${ JSON . stringify ( filters ) } ` } ;
83
+ }
84
+ filters . value = filters . value . map ( ( val : any ) => this . setFieldValue ( fieldObj , val ) ) ;
85
+ } else {
86
+ ( filters as IAdminForthSingleFilter ) . value = this . setFieldValue ( fieldObj , ( filters as IAdminForthSingleFilter ) . value ) ;
87
+ }
88
+ } else if ( ( filters as IAdminForthAndOrFilter ) . subFilters ) {
89
+ // if "subFilters" is present, filter must be AndOr
90
+ if ( ! [ AdminForthFilterOperators . AND , AdminForthFilterOperators . OR ] . includes ( filters . operator ) ) {
91
+ return { ok : false , error : `Field "operator" has wrong value in filter object: ${ JSON . stringify ( filters ) } ` } ;
92
+ }
93
+
94
+ return this . validateAndNormalizeFilters ( ( filters as IAdminForthAndOrFilter ) . subFilters , resource ) ;
95
+ } else {
96
+ return { ok : false , error : `Fields "field" or "subFilters" are not specified in filter object: ${ JSON . stringify ( filters ) } ` } ;
97
+ }
98
+
99
+ return { ok : true , error : '' } ;
100
+ }
101
+
45
102
getDataWithOriginalTypes ( { resource, limit, offset, sort, filters } : {
46
103
resource : AdminForthResource ,
47
104
limit : number ,
48
105
offset : number ,
49
106
sort : IAdminForthSort [ ] ,
50
- filters : IAdminForthFilter [ ] ,
107
+ filters : IAdminForthAndOrFilter ,
51
108
} ) : Promise < any [ ] > {
52
109
throw new Error ( 'Method not implemented.' ) ;
53
110
}
54
111
55
- getCount ( { resource, filters } : { resource : AdminForthResource ; filters : { field : string ; operator : AdminForthFilterOperators ; value : any ; } [ ] ; } ) : Promise < number > {
112
+ getCount ( { resource, filters } : { resource : AdminForthResource ; filters : IAdminForthAndOrFilter ; } ) : Promise < number > {
56
113
throw new Error ( 'Method not implemented.' ) ;
57
114
}
58
115
@@ -80,7 +137,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
80
137
process . env . HEAVY_DEBUG && console . log ( '☝️🪲🪲🪲🪲 checkUnique|||' , column , value ) ;
81
138
const existingRecord = await this . getData ( {
82
139
resource,
83
- filters : [ { field : column . name , operator : AdminForthFilterOperators . EQ , value } ] ,
140
+ filters : { operator : AdminForthFilterOperators . AND , subFilters : [ { field : column . name , operator : AdminForthFilterOperators . EQ , value } ] } ,
84
141
limit : 1 ,
85
142
sort : [ ] ,
86
143
offset : 0 ,
@@ -130,7 +187,12 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
130
187
}
131
188
132
189
process . env . HEAVY_DEBUG && console . log ( '🪲🆕 creating record' , JSON . stringify ( recordWithOriginalValues ) ) ;
133
- const pkValue = await this . createRecordOriginalValues ( { resource, record : recordWithOriginalValues } ) ;
190
+ let pkValue = await this . createRecordOriginalValues ( { resource, record : recordWithOriginalValues } ) ;
191
+ if ( recordWithOriginalValues [ this . getPrimaryKey ( resource ) ] !== undefined ) {
192
+ // some data sources always return some value for pk, even if it is was not auto generated
193
+ // this check prevents wrong value from being used later in get request
194
+ pkValue = recordWithOriginalValues [ this . getPrimaryKey ( resource ) ] ;
195
+ }
134
196
135
197
let createdRecord = recordWithOriginalValues ;
136
198
if ( pkValue ) {
@@ -175,38 +237,19 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
175
237
throw new Error ( 'Method not implemented.' ) ;
176
238
}
177
239
178
-
179
240
async getData ( { resource, limit, offset, sort, filters, getTotals } : {
180
241
resource : AdminForthResource ,
181
242
limit : number ,
182
243
offset : number ,
183
244
sort : { field : string , direction : AdminForthSortDirections } [ ] ,
184
- filters : { field : string , operator : AdminForthFilterOperators , value : any } [ ] ,
245
+ filters : IAdminForthAndOrFilter ,
185
246
getTotals : boolean ,
186
247
} ) : Promise < { data : any [ ] , total : number } > {
187
248
if ( filters ) {
188
- for ( const f of filters ) {
189
- if ( ! f . field ) {
190
- throw new Error ( `Field "field" not specified in filter object: ${ JSON . stringify ( f ) } ` ) ;
191
- }
192
- if ( ! f . operator ) {
193
- throw new Error ( `Field "operator" not specified in filter object: ${ JSON . stringify ( f ) } ` ) ;
194
- }
195
- const fieldObj = resource . dataSourceColumns . find ( ( col ) => col . name == f . field ) ;
196
- if ( ! fieldObj ) {
197
- const similar = suggestIfTypo ( resource . dataSourceColumns . map ( ( col ) => col . name ) , f . field ) ;
198
- throw new Error ( `Field '${ f . field } ' not found in resource '${ resource . resourceId } '. ${ similar ? `Did you mean '${ similar } '?` : '' } ` ) ;
199
- }
200
- if ( f . operator == AdminForthFilterOperators . IN || f . operator == AdminForthFilterOperators . NIN ) {
201
- f . value = f . value . map ( ( val ) => this . setFieldValue ( fieldObj , val ) ) ;
202
- } else {
203
- f . value = this . setFieldValue ( fieldObj , f . value ) ;
204
- }
205
- if ( f . operator === AdminForthFilterOperators . IN && f . value . length === 0 ) {
206
- // nonsense
207
- return { data : [ ] , total : 0 } ;
208
- }
209
- } ;
249
+ const filterValidation = this . validateAndNormalizeFilters ( filters , resource ) ;
250
+ if ( ! filterValidation . ok ) {
251
+ throw new Error ( filterValidation . error ) ;
252
+ }
210
253
}
211
254
212
255
const promises : Promise < any > [ ] = [ this . getDataWithOriginalTypes ( { resource, limit, offset, sort, filters } ) ] ;
0 commit comments