1- import { IAdminForthDataSourceConnector , AdminForthResource , AdminForthResourceColumn } from '../types/Back.js' ;
1+ import { IAdminForthDataSourceConnector , IAdminForthSingleFilter , IAdminForthAndOrFilter , AdminForthResource , AdminForthResourceColumn } from '../types/Back.js' ;
22import AdminForthBaseConnector from './baseConnector.js' ;
33import dayjs from 'dayjs' ;
44import { createClient } from '@clickhouse/client'
@@ -162,60 +162,107 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
162162 [ AdminForthFilterOperators . ILIKE ] : 'ILIKE' ,
163163 [ AdminForthFilterOperators . IN ] : 'IN' ,
164164 [ AdminForthFilterOperators . NIN ] : 'NOT IN' ,
165+ [ AdminForthFilterOperators . AND ] : 'AND' ,
166+ [ AdminForthFilterOperators . OR ] : 'OR' ,
165167 } ;
166168
167169 SortDirectionsMap = {
168170 [ AdminForthSortDirections . asc ] : 'ASC' ,
169171 [ AdminForthSortDirections . desc ] : 'DESC' ,
170172 } ;
173+
174+ getFilterString ( resource : AdminForthResource , filter : IAdminForthSingleFilter | IAdminForthAndOrFilter ) : string {
175+ if ( ( filter as IAdminForthSingleFilter ) . field ) {
176+ // filter is a Single filter
177+ let field = ( filter as IAdminForthSingleFilter ) . field ;
178+ const column = resource . dataSourceColumns . find ( ( col ) => col . name == field ) ;
179+ let placeholder = `{f$?:${ column . _underlineType } }` ;
180+ let operator = this . OperatorsMap [ filter . operator ] ;
181+ if ( filter . operator == AdminForthFilterOperators . IN || filter . operator == AdminForthFilterOperators . NIN ) {
182+ placeholder = `(${ filter . value . map ( ( _ , j ) => `{p$?:${ column . _underlineType } }` ) . join ( ', ' ) } )` ;
183+ }
184+
185+ return `${ field } ${ operator } ${ placeholder } ` ;
186+ }
187+
188+ // filter is a AndOr filter
189+ return ( filter as IAdminForthAndOrFilter ) . subFilters . map ( ( f ) => {
190+ if ( ( f as IAdminForthSingleFilter ) . field ) {
191+ // subFilter is a Single filter
192+ return this . getFilterString ( resource , f ) ;
193+ }
194+
195+ // subFilter is a AndOr filter - add parentheses
196+ return `(${ this . getFilterString ( resource , f ) } )` ;
197+ } ) . join ( ` ${ this . OperatorsMap [ filter . operator ] } ` ) ;
198+ }
171199
172- whereClause (
173- resource : AdminForthResource ,
174- filters : { field : string , operator : AdminForthFilterOperators , value : any } [ ]
175- ) : string {
176- return filters . length ? `WHERE ${ filters . map ( ( f , i ) => {
177- const column = resource . dataSourceColumns . find ( ( col ) => col . name == f . field ) ;
178- let placeholder = `{f${ i } :${ column . _underlineType } }` ;
179- let field = f . field ;
180- let operator = this . OperatorsMap [ f . operator ] ;
181- if ( f . operator == AdminForthFilterOperators . IN || f . operator == AdminForthFilterOperators . NIN ) {
182- placeholder = `(${ f . value . map ( ( _ , j ) => `{p${ i } _${ j } :${
183- column . _underlineType
184- } }`) . join ( ', ' ) } )`;
200+ getFilterParams ( filter : IAdminForthSingleFilter | IAdminForthAndOrFilter ) : any [ ] {
201+ if ( ( filter as IAdminForthSingleFilter ) . field ) {
202+ // filter is a Single filter
203+ if ( filter . operator == AdminForthFilterOperators . LIKE || filter . operator == AdminForthFilterOperators . ILIKE ) {
204+ return [ { 'f' : `%${ filter . value } %` } ] ;
205+ } else if ( filter . operator == AdminForthFilterOperators . IN || filter . operator == AdminForthFilterOperators . NIN ) {
206+ return [ { 'p' : filter . value } ] ;
207+ } else {
208+ return [ { 'f' : ( filter as IAdminForthSingleFilter ) . value } ] ;
185209 }
210+ }
186211
187- return `${ field } ${ operator } ${ placeholder } `
188- } ) . join ( ' AND ' ) } ` : '' ;
212+ // filter is a AndOrFilter
213+ return ( filter as IAdminForthAndOrFilter ) . subFilters . reduce ( ( params : any [ ] , f : IAdminForthSingleFilter | IAdminForthAndOrFilter ) => {
214+ return params . concat ( this . getFilterParams ( f ) ) ;
215+ } , [ ] ) ;
189216 }
190217
191- whereParams (
192- filters : { field : string , operator : AdminForthFilterOperators , value : any } [ ]
193- ) : any {
194- const params = { } ;
195- filters . length ? filters . forEach ( ( f , i ) => {
196- // for arrays do set in map
197- const v = f . value ;
198-
199- if ( f . operator == AdminForthFilterOperators . LIKE || f . operator == AdminForthFilterOperators . ILIKE ) {
200- params [ `f${ i } ` ] = `%${ v } %` ;
201- } else if ( f . operator == AdminForthFilterOperators . IN || f . operator == AdminForthFilterOperators . NIN ) {
202- v . forEach ( ( _ , j ) => {
203- params [ `p${ i } _${ j } ` ] = v [ j ] ;
204- } ) ;
205- } else {
206- params [ `f${ i } ` ] = v ;
218+ whereParams ( filters : IAdminForthAndOrFilter ) : any {
219+ if ( filters . subFilters . length === 0 ) {
220+ return { } ;
221+ }
222+ const paramsArray = this . getFilterParams ( filters ) ;
223+ const params = paramsArray . reduce ( ( acc , param , paramIndex ) => {
224+ if ( param . f !== undefined ) {
225+ acc [ `f${ paramIndex } ` ] = param . f ;
226+ }
227+ else if ( param . p !== undefined ) {
228+ param . p . forEach ( ( paramValue : any , paramValueIndex : number ) => acc [ `p${ paramIndex } _${ paramValueIndex } ` ] = paramValue ) ;
207229 }
208- } ) : [ ] ;
230+
231+ return acc ;
232+ } , { } ) ;
209233
210234 return params ;
235+ }
236+
237+ whereClause (
238+ resource : AdminForthResource ,
239+ filters : IAdminForthAndOrFilter
240+ ) : {
241+ where : string ,
242+ params : any ,
243+ } {
244+ if ( filters . subFilters . length === 0 ) {
245+ return {
246+ where : '' ,
247+ params : { } ,
248+ }
249+ }
250+ const params = this . whereParams ( filters ) ;
251+ const where = Object . keys ( params ) . reduce ( ( w , paramKey ) => {
252+ // remove first char of string (will be "f" or "p") to leave only index
253+ const keyIndex = paramKey . substring ( 1 ) ;
254+ return w . replace ( '$?' , keyIndex ) ;
255+ } , `WHERE ${ this . getFilterString ( resource , filters ) } ` ) ;
256+
257+ return { where, params } ;
211258 }
212259
213260 async getDataWithOriginalTypes ( { resource, limit, offset, sort, filters } : {
214261 resource : AdminForthResource ,
215262 limit : number ,
216263 offset : number ,
217264 sort : { field : string , direction : AdminForthSortDirections } [ ] ,
218- filters : { field : string , operator : AdminForthFilterOperators , value : any } [ ] ,
265+ filters : IAdminForthAndOrFilter ,
219266 } ) : Promise < any [ ] > {
220267 const columns = resource . dataSourceColumns . map ( ( col ) => {
221268 // for decimal cast to string
@@ -226,9 +273,7 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
226273 } ) . join ( ', ' ) ;
227274 const tableName = resource . table ;
228275
229- const where = this . whereClause ( resource , filters ) ;
230-
231- const params = this . whereParams ( filters ) ;
276+ const { where, params } = this . whereClause ( resource , filters ) ;
232277
233278 const orderBy = sort . length ? `ORDER BY ${ sort . map ( ( s ) => `${ s . field } ${ this . SortDirectionsMap [ s . direction ] } ` ) . join ( ', ' ) } ` : '' ;
234279
@@ -262,16 +307,15 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
262307 filters,
263308 } : {
264309 resource : AdminForthResource ;
265- filters : { field : string , operator : AdminForthFilterOperators , value : any } [ ] ;
310+ filters : IAdminForthAndOrFilter ;
266311 } ) : Promise < number > {
267312 const tableName = resource . table ;
268- const where = this . whereClause ( resource , filters ) ;
269- const d = this . whereParams ( filters ) ;
313+ const { where, params } = this . whereClause ( resource , filters ) ;
270314
271315 const countQ = await this . client . query ( {
272316 query : `SELECT COUNT(*) as count FROM ${ tableName } ${ where } ` ,
273317 format : 'JSONEachRow' ,
274- query_params : d ,
318+ query_params : params ,
275319 } ) ;
276320 const countResp = await countQ . json ( )
277321 return + countResp [ 0 ] [ 'count' ] ;
0 commit comments