Skip to content

Commit 6b2661e

Browse files
[update] 新增mapboxFilter转SQL或者XML查询语句的方法
(review by zq)
1 parent c961a86 commit 6b2661e

File tree

1 file changed

+289
-1
lines changed

1 file changed

+289
-1
lines changed

src/common/mapping/utils/util.js

Lines changed: 289 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,292 @@ export function getLayerCatalogRenderLayers(parts, catalogId, layersOnMap) {
216216
export 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

Comments
 (0)