@@ -216,4 +216,292 @@ export function getLayerCatalogRenderLayers(parts, catalogId, layersOnMap) {
216216export function getMainLayerFromCatalog ( layerParts , catalogId , layersOnMap ) {
217217 const renderLayers = getLayerCatalogRenderLayers ( layerParts , catalogId , layersOnMap ) ;
218218 return layersOnMap . find ( item => item . id === renderLayers [ 0 ] ) ;
219- }
219+ }
220+ // 要判断一下是否是二维数组的filter
221+ function isSimpleComparison ( filter ) {
222+ if ( ! filter || ! Array . isArray ( filter ) ) {
223+ return false ;
224+ }
225+ const [ operator , ...operands ] = filter ;
226+
227+ const simpleOps = [ '==' , '!=' , '>' , '>=' , '<' , '<=' , 'in' , '!in' , 'has' , '!has' ] ;
228+ const logicalOps = [ 'all' , 'any' , 'none' ] ;
229+ if ( simpleOps . includes ( operator ) ) {
230+ // has / !has:只要求一个字段名
231+ if ( operator === 'has' || operator === '!has' ) {
232+ // 排除这种: ['has', ['get', 'name']]
233+ return typeof operands [ 0 ] === 'string' ;
234+ }
235+ // in / !in:field + 至少一个值
236+ if ( operator === 'in' || operator === '!in' ) {
237+ if ( typeof operands [ 0 ] !== 'string' ) { return false ; }
238+ return operands . length > 1 ;
239+ }
240+ // 普通比较:field + value
241+ return operands . length === 2 && typeof operands [ 0 ] === 'string' ;
242+ }
243+ if ( logicalOps . includes ( operator ) ) {
244+ if ( operands . length === 0 ) { return false ; }
245+ return operands . every ( ( item ) => isSimpleComparison ( item ) ) ;
246+ }
247+ return false ;
248+ }
249+
250+ // 处理类似"O'Reilly"这种字符串,在SQL语句中需要转,单引号需要处理
251+ function formatValue ( value ) {
252+ if ( typeof value === 'string' ) {
253+ return `'${ value . replace ( / ' / g, "''" ) } '` ;
254+ }
255+ return String ( value ) ;
256+ }
257+
258+ // 判断空值
259+ function isNullvalue ( value ) {
260+ return [ null , '' , undefined ] . includes ( value ) ;
261+ }
262+
263+ function mapboxFilterToCqlFilter ( filter ) {
264+ if ( ! isSimpleComparison ( filter ) ) {
265+ return '' ;
266+ }
267+ const [ operator , ...operands ] = filter ;
268+ const field = operands [ 0 ] ;
269+ let value ;
270+ switch ( operator ) {
271+ case '>' :
272+ case '>=' :
273+ case '<' :
274+ case '<=' : {
275+ value = operands [ 1 ] ;
276+ return `${ field } ${ operator } ${ formatValue ( value ) } ` ;
277+ }
278+ case '==' : {
279+ value = operands [ 1 ] ;
280+ if ( isNullvalue ( value ) ) {
281+ return `${ field } IS NULL` ;
282+ }
283+ return `${ field } == ${ formatValue ( value ) } ` ;
284+ }
285+ case '!=' : {
286+ value = operands [ 1 ] ;
287+ if ( isNullvalue ( value ) ) {
288+ return `${ field } IS NOT NULL` ;
289+ }
290+ return `${ field } <> ${ formatValue ( value ) } ` ;
291+ }
292+ case 'in' : {
293+ const values = operands . slice ( 1 ) ;
294+ return `${ field } IN (${ values . map ( ( v ) => formatValue ( v ) ) . join ( ', ' ) } )` ;
295+ }
296+ case '!in' : {
297+ const values = operands . slice ( 1 ) ;
298+ return `${ field } NOT IN (${ values . map ( ( v ) => formatValue ( v ) ) . join ( ', ' ) } )` ;
299+ }
300+ // TODO
301+ // case 'has': {
302+ // const field = operands[0];
303+ // return tableFieldNames?.includes(field) ? '1=1' : '1=0';
304+ // }
305+ // case '!has': {
306+ // const field = operands[0];
307+ // return tableFieldNames?.includes(field) ? '1=0' : '1=1';
308+ // }
309+ case 'all' : {
310+ return operands
311+ . map ( ( item ) => mapboxFilterToCqlFilter ( item ) )
312+ . filter ( Boolean )
313+ . map ( ( item ) => `${ item } ` )
314+ . join ( ' AND ' ) ;
315+ }
316+ case 'any' : {
317+ return operands
318+ . map ( ( item ) => mapboxFilterToCqlFilter ( item ) )
319+ . filter ( Boolean )
320+ . map ( ( item ) => `(${ item } )` )
321+ . join ( ' OR ' ) ;
322+ }
323+ case 'none' : {
324+ return operands
325+ . map ( ( item ) => mapboxFilterToCqlFilter ( item ) )
326+ . filter ( Boolean )
327+ . map ( ( item ) => `NOT (${ item } )` )
328+ . join ( ' AND ' ) ;
329+ }
330+ default :
331+ return '' ;
332+ }
333+ }
334+
335+ // none的情况下,全部用Not一个一个包裹,会报错(应该是接口问题),反转即可
336+ function negateComparison ( filter ) {
337+ const op = filter [ 0 ] ;
338+ const args = filter . slice ( 1 ) ;
339+ switch ( op ) {
340+ case '==' :
341+ return mapboxFilterToWfsFilter ( [ '!=' , ...args ] ) ;
342+ case '!=' :
343+ return mapboxFilterToWfsFilter ( [ '==' , ...args ] ) ;
344+ case '>' :
345+ return mapboxFilterToWfsFilter ( [ '<=' , ...args ] ) ;
346+ case '>=' :
347+ return mapboxFilterToWfsFilter ( [ '<' , ...args ] ) ;
348+ case '<' :
349+ return mapboxFilterToWfsFilter ( [ '>=' , ...args ] ) ;
350+ case '<=' :
351+ return mapboxFilterToWfsFilter ( [ '>' , ...args ] ) ;
352+ case 'in' :
353+ return mapboxFilterToWfsFilter ( [ '!in' , ...args ] ) ;
354+ case '!in' :
355+ return mapboxFilterToWfsFilter ( [ 'in' , ...args ] ) ;
356+ // case 'has':
357+ // return mapboxFilterToWfsFilter(['!has', ...args], fieldNames, tableFieldNames);
358+ // case '!has':
359+ // return mapboxFilterToWfsFilter(['has', ...args], fieldNames, tableFieldNames);
360+ default :
361+ return '' ;
362+ }
363+ }
364+
365+ function mapboxFilterToWfsFilterBody ( filter ) {
366+ if ( ! isSimpleComparison ( filter ) ) {
367+ return '' ;
368+ }
369+ const [ operator , ...operands ] = filter ;
370+ const fieldRef = ( field ) => `<fes:ValueReference>${ field } </fes:ValueReference>` ;
371+ const literal = ( value ) => `<fes:Literal>${ value } </fes:Literal>` ;
372+ switch ( operator ) {
373+ case '==' : {
374+ const [ field , value ] = operands ;
375+ if ( isNullvalue ( value ) ) {
376+ return `
377+ <fes:PropertyIsNull>
378+ ${ fieldRef ( field ) }
379+ </fes:PropertyIsNull>` ;
380+ }
381+ return `
382+ <fes:PropertyIsEqualTo>
383+ ${ fieldRef ( field ) }
384+ ${ literal ( value ) }
385+ </fes:PropertyIsEqualTo>` ;
386+ }
387+ case '!=' : {
388+ const [ field , value ] = operands ;
389+ if ( isNullvalue ( value ) ) {
390+ return `
391+ <fes:PropertyIsNotNull>
392+ ${ fieldRef ( field ) }
393+ </fes:PropertyIsNotNull>` ;
394+ }
395+ return `
396+ <fes:PropertyIsNotEqualTo>
397+ ${ fieldRef ( field ) }
398+ ${ literal ( value ) }
399+ </fes:PropertyIsNotEqualTo>` ;
400+ }
401+ case '>' :
402+ return `
403+ <fes:PropertyIsGreaterThan>
404+ ${ fieldRef ( operands [ 0 ] ) }
405+ ${ literal ( operands [ 1 ] ) }
406+ </fes:PropertyIsGreaterThan>` ;
407+ case '>=' :
408+ return `
409+ <fes:PropertyIsGreaterThanOrEqualTo>
410+ ${ fieldRef ( operands [ 0 ] ) }
411+ ${ literal ( operands [ 1 ] ) }
412+ </fes:PropertyIsGreaterThanOrEqualTo>` ;
413+ case '<' :
414+ return `
415+ <fes:PropertyIsLessThan>
416+ ${ fieldRef ( operands [ 0 ] ) }
417+ ${ literal ( operands [ 1 ] ) }
418+ </fes:PropertyIsLessThan>` ;
419+ case '<=' :
420+ return `
421+ <fes:PropertyIsLessThanOrEqualTo>
422+ ${ fieldRef ( operands [ 0 ] ) }
423+ ${ literal ( operands [ 1 ] ) }
424+ </fes:PropertyIsLessThanOrEqualTo>` ;
425+ case 'in' : {
426+ const field = operands [ 0 ] ;
427+ const values = operands . slice ( 1 ) ;
428+ return `
429+ <fes:Or>${ values
430+ . map (
431+ ( v ) => `
432+ <fes:PropertyIsEqualTo>
433+ ${ fieldRef ( field ) }
434+ ${ literal ( v ) }
435+ </fes:PropertyIsEqualTo>`
436+ )
437+ . join ( '' ) } </fes:Or>`;
438+ }
439+ case '!in' : {
440+ const field = operands [ 0 ] ;
441+ const values = operands . slice ( 1 ) ;
442+ return `
443+ <fes:Not><fes:Or>${ values
444+ . map (
445+ ( v ) => `
446+ <fes:PropertyIsEqualTo>
447+ ${ fieldRef ( field ) }
448+ ${ literal ( v ) }
449+ </fes:PropertyIsEqualTo>`
450+ )
451+ . join ( '' ) } </fes:Or></fes:Not>`;
452+ }
453+ // TODO,has条件暂时是用null判断,不准确
454+ // case 'has': { ... }
455+ // case '!has': { ... }
456+ case 'all' : {
457+ const children = operands
458+ . map ( ( item ) => mapboxFilterToWfsFilterBody ( item ) . trim ( ) )
459+ . filter ( Boolean ) ;
460+ return children . length
461+ ? `
462+ <fes:And>
463+ ${ children . join ( '' ) }
464+ </fes:And>`
465+ : '' ;
466+ }
467+ case 'any' : {
468+ const children = operands
469+ . map ( ( item ) => mapboxFilterToWfsFilterBody ( item ) . trim ( ) )
470+ . filter ( Boolean ) ;
471+ return children . length
472+ ? `
473+ <fes:Or>
474+ ${ children . join ( '' ) }
475+ </fes:Or>`
476+ : '' ;
477+ }
478+ case 'none' : {
479+ const children = operands . map ( ( item ) => negateComparison ( item ) . trim ( ) ) . filter ( Boolean ) ;
480+ return children . length
481+ ? `
482+ <fes:And>
483+ ${ children . join ( '' ) }
484+ </fes:And>`
485+ : '' ;
486+ }
487+ default :
488+ return '' ;
489+ }
490+ }
491+
492+ function mapboxFilterToWfsFilter ( filter ) {
493+ const body = mapboxFilterToWfsFilterBody ( filter ) ;
494+ if ( ! body ) { return '' ; }
495+ return `<fes:Filter>${ body }
496+ </fes:Filter>` ;
497+ }
498+
499+ export function mapboxFilterToQueryFilter ( filter , type = 'SQL' ) {
500+ if ( type === 'SQL' ) {
501+ return mapboxFilterToCqlFilter ( filter ) ;
502+ }
503+ if ( type === 'XML' ) {
504+ return mapboxFilterToWfsFilter ( filter ) ;
505+ }
506+ return '' ;
507+ }
0 commit comments