@finos/legend-data-cube 0.3.55 → 0.3.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/view/filter/DataCubeFilterEditor.d.ts.map +1 -1
- package/lib/components/view/filter/DataCubeFilterEditor.js +228 -3
- package/lib/components/view/filter/DataCubeFilterEditor.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/core/DataCubeEngine.d.ts +3 -1
- package/lib/stores/core/DataCubeEngine.d.ts.map +1 -1
- package/lib/stores/core/DataCubeEngine.js +4 -0
- package/lib/stores/core/DataCubeEngine.js.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.js +7 -0
- package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
- package/lib/stores/core/DataCubeQueryEngine.d.ts +1 -0
- package/lib/stores/core/DataCubeQueryEngine.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryEngine.js +17 -0
- package/lib/stores/core/DataCubeQueryEngine.js.map +1 -1
- package/lib/stores/core/DataCubeSnapshotBuilderUtils.d.ts.map +1 -1
- package/lib/stores/core/DataCubeSnapshotBuilderUtils.js +6 -0
- package/lib/stores/core/DataCubeSnapshotBuilderUtils.js.map +1 -1
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__In.d.ts +38 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__In.d.ts.map +1 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__In.js +92 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__In.js.map +1 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__NotIn.d.ts +38 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__NotIn.d.ts.map +1 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__NotIn.js +93 -0
- package/lib/stores/core/filter/DataCubeQueryFilterOperation__NotIn.js.map +1 -0
- package/package.json +5 -5
- package/src/components/view/filter/DataCubeFilterEditor.tsx +367 -3
- package/src/stores/core/DataCubeEngine.tsx +4 -0
- package/src/stores/core/DataCubeQueryBuilderUtils.ts +12 -1
- package/src/stores/core/DataCubeQueryEngine.ts +17 -0
- package/src/stores/core/DataCubeSnapshotBuilderUtils.ts +8 -1
- package/src/stores/core/filter/DataCubeQueryFilterOperation__In.tsx +127 -0
- package/src/stores/core/filter/DataCubeQueryFilterOperation__NotIn.tsx +138 -0
- package/tsconfig.json +2 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataCubeQueryFilterOperation__NotIn.js","sourceRoot":"","sources":["../../../../src/stores/core/filter/DataCubeQueryFilterOperation__NotIn.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAGjF,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,2BAA2B,EAC3B,eAAe,EACf,UAAU,EACV,0BAA0B,EAC1B,kCAAkC,GAEnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,SAAS,EACT,aAAa,EACb,IAAI,EACJ,SAAS,EACT,MAAM,GACP,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAA2B,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,OAAO,mCAAoC,SAAQ,4BAA4B;IACnF,IAAa,KAAK;QAChB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,IAAa,SAAS;QACpB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,IAAa,WAAW;QACtB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,IAAa,QAAQ;QACnB,OAAO,2BAA2B,CAAC,MAAM,CAAC;IAC5C,CAAC;IAED,sBAAsB,CAAC,MAAsB;QAC3C,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE;YAC7B,sBAAsB,CAAC,IAAI;YAC3B,sBAAsB,CAAC,MAAM;YAC7B,sBAAsB,CAAC,IAAI;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,qBAAqB,CAAC,KAA6B;QACjD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,kCAAkC,CAAC,IAAI,EAAE,CAAC;YAC3D,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;gBAC1B,KAAK,CAAC,KAAmB,CAAC,MAAM,KAAK,CAAC,EACvC,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAQ,KAAK,CAAC,KAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC5C,MAAM,KAAK,GAAG,CAA2B,CAAC;gBAC1C,OAAO,CACL,KAAK,CAAC,KAAK,KAAK,SAAS;oBACzB,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC;oBAC3B,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE;wBACrB,sBAAsB,CAAC,IAAI;wBAC3B,sBAAsB,CAAC,MAAM;wBAC7B,sBAAsB,CAAC,IAAI;qBAC5B,CAAC,CACH,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,CACL,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC;YAC3B,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE;gBACrB,sBAAsB,CAAC,IAAI;gBAC3B,sBAAsB,CAAC,MAAM;gBAC7B,sBAAsB,CAAC,IAAI;aAC5B,CAAC;YACF,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;YACzB,KAAK,CAAC,KAAmB,CAAC,MAAM,GAAG,CAAC,CACtC,CAAC;IACJ,CAAC;IAED,oBAAoB,CAAC,MAAsB;QACzC,OAAO;YACL,IAAI,EAAE,kCAAkC,CAAC,IAAI;YAC7C,KAAK,EAAE;gBACL;oBACE,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,KAAK,EAAE,0BAA0B,CAAC,MAAM,CAAC,IAAI,CAAC;iBAC/C;aACF;SACF,CAAC;IACJ,CAAC;IAED,sBAAsB,CACpB,UAA8B,EAC9B,YAA8C;QAE9C,OAAO,IAAI,CAAC,0BAA0B,CACpC,qBAAqB,CACnB,kBAAkB,CAAC,GAAG,EAAE,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC,EAC/D,gBAAgB,CAAC,EAAE,EACnB,YAAY,CACb,CACF,CAAC;IACJ,CAAC;IAED,wBAAwB,CAAC,SAA0C;QACjE,uEAAuE;QACvE,OAAO,IAAI,CACT,SAAS,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE;YAC5C,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC;YACzB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;SACxB,CAAC,CACH,CAAC;IACJ,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finos/legend-data-cube",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.57",
|
|
4
4
|
"description": "Legend DataCube",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"legend",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"test:watch": "jest --watch"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@finos/legend-application": "16.0.
|
|
46
|
-
"@finos/legend-art": "7.1.
|
|
47
|
-
"@finos/legend-code-editor": "2.0.
|
|
48
|
-
"@finos/legend-graph": "32.3.
|
|
45
|
+
"@finos/legend-application": "16.0.88",
|
|
46
|
+
"@finos/legend-art": "7.1.138",
|
|
47
|
+
"@finos/legend-code-editor": "2.0.143",
|
|
48
|
+
"@finos/legend-graph": "32.3.23",
|
|
49
49
|
"@finos/legend-shared": "11.0.22",
|
|
50
50
|
"@types/react": "19.0.10",
|
|
51
51
|
"ag-grid-community": "33.1.1",
|
|
@@ -44,14 +44,26 @@ import {
|
|
|
44
44
|
FormDropdownMenuTrigger,
|
|
45
45
|
} from '../../core/DataCubeFormUtils.js';
|
|
46
46
|
import type { DataCubeViewState } from '../../../stores/view/DataCubeViewState.js';
|
|
47
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
forwardRef,
|
|
49
|
+
useCallback,
|
|
50
|
+
useEffect,
|
|
51
|
+
useRef,
|
|
52
|
+
useState,
|
|
53
|
+
useMemo,
|
|
54
|
+
} from 'react';
|
|
48
55
|
import {
|
|
49
56
|
DATE_FORMAT,
|
|
50
57
|
PRECISE_PRIMITIVE_TYPE,
|
|
51
58
|
PRIMITIVE_TYPE,
|
|
52
59
|
} from '@finos/legend-graph';
|
|
53
60
|
|
|
54
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
formatDate,
|
|
63
|
+
guaranteeIsNumber,
|
|
64
|
+
isNullable,
|
|
65
|
+
parseISO,
|
|
66
|
+
} from '@finos/legend-shared';
|
|
55
67
|
import { evaluate } from 'mathjs';
|
|
56
68
|
import { useDataCube } from '../../DataCubeProvider.js';
|
|
57
69
|
import { _findCol } from '../../../stores/core/model/DataCubeColumn.js';
|
|
@@ -360,6 +372,349 @@ const DataCubeEditorFilterConditionNodeColumnSelector = observer(
|
|
|
360
372
|
}),
|
|
361
373
|
);
|
|
362
374
|
|
|
375
|
+
const DataCubeEditorFilterConditionNodeListValueEditor = observer(
|
|
376
|
+
forwardRef<
|
|
377
|
+
HTMLElement,
|
|
378
|
+
{
|
|
379
|
+
value: DataCubeOperationValue;
|
|
380
|
+
updateValue: (value: unknown) => void;
|
|
381
|
+
view: DataCubeViewState;
|
|
382
|
+
}
|
|
383
|
+
>(function DataCubeEditorFilterConditionNodeListValueEditor(props, ref) {
|
|
384
|
+
const { value, updateValue } = props;
|
|
385
|
+
const items = useMemo(
|
|
386
|
+
() =>
|
|
387
|
+
Array.isArray(value.value)
|
|
388
|
+
? (value.value as DataCubeOperationValue[])
|
|
389
|
+
: [],
|
|
390
|
+
[value.value],
|
|
391
|
+
);
|
|
392
|
+
const idSeq = useRef(0);
|
|
393
|
+
const makeId = () => `${Date.now()}_${idSeq.current++}`;
|
|
394
|
+
type LocalItem = { id: string; value: DataCubeOperationValue };
|
|
395
|
+
const [localItems, setLocalItems] = useState<LocalItem[]>(
|
|
396
|
+
items.map((it) => ({ id: makeId(), value: it })),
|
|
397
|
+
);
|
|
398
|
+
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
|
399
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
400
|
+
const [newInput, setNewInput] = useState('');
|
|
401
|
+
|
|
402
|
+
useEffect(() => {
|
|
403
|
+
// rebuild local items from incoming value; generate ids locally
|
|
404
|
+
setLocalItems(items.map((it) => ({ id: makeId(), value: it })));
|
|
405
|
+
}, [items]);
|
|
406
|
+
|
|
407
|
+
const close = () => {
|
|
408
|
+
// commit normalized list shape when closing
|
|
409
|
+
updateValue(localItems.map((e) => e.value));
|
|
410
|
+
setAnchorEl(null);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const commit = useCallback((nextItems: LocalItem[]) => {
|
|
414
|
+
setLocalItems(nextItems);
|
|
415
|
+
}, []);
|
|
416
|
+
|
|
417
|
+
const addItem = useCallback(() => {
|
|
418
|
+
const trimmed = newInput.trim();
|
|
419
|
+
// if input provided, try to coerce to column type; else create default typed item
|
|
420
|
+
let newItem: DataCubeOperationValue;
|
|
421
|
+
const firstType = localItems[0]?.value.type ?? PRIMITIVE_TYPE.STRING;
|
|
422
|
+
switch (firstType) {
|
|
423
|
+
case PRIMITIVE_TYPE.BOOLEAN: {
|
|
424
|
+
const v = trimmed.toLowerCase();
|
|
425
|
+
const boolVal = v === 'true' || v === '1';
|
|
426
|
+
newItem = { type: firstType, value: boolVal };
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
case PRIMITIVE_TYPE.NUMBER:
|
|
430
|
+
case PRIMITIVE_TYPE.DECIMAL:
|
|
431
|
+
case PRIMITIVE_TYPE.FLOAT:
|
|
432
|
+
case PRIMITIVE_TYPE.INTEGER:
|
|
433
|
+
case PRECISE_PRIMITIVE_TYPE.INT:
|
|
434
|
+
case PRECISE_PRIMITIVE_TYPE.BIG_INT:
|
|
435
|
+
case PRECISE_PRIMITIVE_TYPE.DECIMAL:
|
|
436
|
+
case PRECISE_PRIMITIVE_TYPE.NUMERIC:
|
|
437
|
+
case PRECISE_PRIMITIVE_TYPE.DOUBLE:
|
|
438
|
+
case PRECISE_PRIMITIVE_TYPE.SMALL_INT:
|
|
439
|
+
case PRECISE_PRIMITIVE_TYPE.FLOAT:
|
|
440
|
+
case PRECISE_PRIMITIVE_TYPE.U_INT:
|
|
441
|
+
case PRECISE_PRIMITIVE_TYPE.TINY_INT:
|
|
442
|
+
case PRECISE_PRIMITIVE_TYPE.U_BIG_INT:
|
|
443
|
+
case PRECISE_PRIMITIVE_TYPE.U_SMALL_INT:
|
|
444
|
+
case PRECISE_PRIMITIVE_TYPE.U_TINY_INT: {
|
|
445
|
+
const n = Number(trimmed);
|
|
446
|
+
newItem = { type: firstType, value: isNaN(n) ? 0 : n };
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
case PRIMITIVE_TYPE.DATE:
|
|
450
|
+
case PRIMITIVE_TYPE.STRICTDATE:
|
|
451
|
+
case PRIMITIVE_TYPE.DATETIME:
|
|
452
|
+
case PRECISE_PRIMITIVE_TYPE.STRICTDATE:
|
|
453
|
+
case PRECISE_PRIMITIVE_TYPE.DATETIME:
|
|
454
|
+
case PRECISE_PRIMITIVE_TYPE.STRICTTIME:
|
|
455
|
+
case PRECISE_PRIMITIVE_TYPE.TIMESTAMP: {
|
|
456
|
+
// try parse ISO, else use formatted now
|
|
457
|
+
let dateVal = trimmed;
|
|
458
|
+
try {
|
|
459
|
+
const d = parseISO(trimmed);
|
|
460
|
+
dateVal = formatDate(d, DATE_FORMAT);
|
|
461
|
+
} catch {
|
|
462
|
+
dateVal = formatDate(new Date(), DATE_FORMAT);
|
|
463
|
+
}
|
|
464
|
+
newItem = { type: firstType, value: dateVal };
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
default:
|
|
468
|
+
newItem = { type: firstType, value: trimmed };
|
|
469
|
+
}
|
|
470
|
+
const next = [...localItems, { id: makeId(), value: newItem }];
|
|
471
|
+
commit(next);
|
|
472
|
+
setNewInput('');
|
|
473
|
+
inputRef.current?.focus();
|
|
474
|
+
}, [localItems, newInput, commit]);
|
|
475
|
+
|
|
476
|
+
// When the popover is open, allow pressing Enter (when focus is not in an
|
|
477
|
+
// input/control) to add a new item. We keep Enter behavior of individual
|
|
478
|
+
// editors (e.g. number evaluator) intact by ignoring keypress when focus
|
|
479
|
+
// is on common form controls.
|
|
480
|
+
useEffect(() => {
|
|
481
|
+
const handler = (e: KeyboardEvent): void => {
|
|
482
|
+
if (e.key !== 'Enter') {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (!anchorEl) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const active = document.activeElement as HTMLElement | null;
|
|
489
|
+
if (!active) {
|
|
490
|
+
addItem();
|
|
491
|
+
e.preventDefault();
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
const tag = active.tagName;
|
|
495
|
+
// if focus is on typical input controls, let their handlers process Enter
|
|
496
|
+
if (['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].includes(tag)) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
// otherwise, treat Enter as add
|
|
500
|
+
addItem();
|
|
501
|
+
e.preventDefault();
|
|
502
|
+
};
|
|
503
|
+
window.addEventListener('keydown', handler);
|
|
504
|
+
return () => window.removeEventListener('keydown', handler);
|
|
505
|
+
}, [anchorEl, addItem]);
|
|
506
|
+
|
|
507
|
+
const removeItem = (idx: number) => {
|
|
508
|
+
const next = localItems.filter((_, i) => i !== idx);
|
|
509
|
+
commit(next);
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const summary =
|
|
513
|
+
localItems.length === 0
|
|
514
|
+
? 'Add...'
|
|
515
|
+
: `${localItems
|
|
516
|
+
.slice(0, 2)
|
|
517
|
+
.map((entry) => {
|
|
518
|
+
const v = entry.value.value;
|
|
519
|
+
return String(v ?? '');
|
|
520
|
+
})
|
|
521
|
+
.join(
|
|
522
|
+
', ',
|
|
523
|
+
)}${localItems.length > 2 ? ` (+${localItems.length - 2})` : ''}`;
|
|
524
|
+
|
|
525
|
+
return (
|
|
526
|
+
<>
|
|
527
|
+
<button
|
|
528
|
+
ref={ref as React.RefObject<HTMLButtonElement>}
|
|
529
|
+
className="relative h-5 w-full border border-neutral-400 px-1 text-left text-sm"
|
|
530
|
+
onClick={(e) => setAnchorEl(e.currentTarget)}
|
|
531
|
+
>
|
|
532
|
+
{summary}
|
|
533
|
+
</button>
|
|
534
|
+
<BasePopover
|
|
535
|
+
open={Boolean(anchorEl)}
|
|
536
|
+
anchorEl={anchorEl}
|
|
537
|
+
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
|
538
|
+
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
|
|
539
|
+
onClose={() => close()}
|
|
540
|
+
classes={{
|
|
541
|
+
paper: 'shadow-md rounded-none border border-neutral-300 p-2',
|
|
542
|
+
}}
|
|
543
|
+
>
|
|
544
|
+
<div className="w-60">
|
|
545
|
+
<div className="max-h-40 overflow-auto">
|
|
546
|
+
{localItems.length === 0 && (
|
|
547
|
+
<div className="mb-2 text-sm text-neutral-600">
|
|
548
|
+
No values added.
|
|
549
|
+
</div>
|
|
550
|
+
)}
|
|
551
|
+
{localItems.map((entry) => {
|
|
552
|
+
const it = entry.value;
|
|
553
|
+
const id = entry.id;
|
|
554
|
+
return (
|
|
555
|
+
<div key={id} className="mb-1 flex items-center gap-2">
|
|
556
|
+
<div className="flex-1">
|
|
557
|
+
{(() => {
|
|
558
|
+
switch (it.type) {
|
|
559
|
+
case PRIMITIVE_TYPE.BOOLEAN:
|
|
560
|
+
return (
|
|
561
|
+
<DataCubeEditorFilterConditionNodeBooleanValueEditor
|
|
562
|
+
value={Boolean(it.value)}
|
|
563
|
+
updateValue={(v: boolean) => {
|
|
564
|
+
const next = localItems.slice();
|
|
565
|
+
const idx = next.findIndex(
|
|
566
|
+
(e) => e.id === id,
|
|
567
|
+
);
|
|
568
|
+
if (idx >= 0) {
|
|
569
|
+
next[idx] = {
|
|
570
|
+
id,
|
|
571
|
+
value: { type: it.type, value: v },
|
|
572
|
+
};
|
|
573
|
+
setLocalItems(next);
|
|
574
|
+
}
|
|
575
|
+
}}
|
|
576
|
+
/>
|
|
577
|
+
);
|
|
578
|
+
case PRIMITIVE_TYPE.NUMBER:
|
|
579
|
+
case PRIMITIVE_TYPE.DECIMAL:
|
|
580
|
+
case PRIMITIVE_TYPE.FLOAT:
|
|
581
|
+
case PRIMITIVE_TYPE.INTEGER:
|
|
582
|
+
case PRECISE_PRIMITIVE_TYPE.INT:
|
|
583
|
+
case PRECISE_PRIMITIVE_TYPE.BIG_INT:
|
|
584
|
+
case PRECISE_PRIMITIVE_TYPE.DECIMAL:
|
|
585
|
+
case PRECISE_PRIMITIVE_TYPE.NUMERIC:
|
|
586
|
+
case PRECISE_PRIMITIVE_TYPE.DOUBLE:
|
|
587
|
+
case PRECISE_PRIMITIVE_TYPE.SMALL_INT:
|
|
588
|
+
case PRECISE_PRIMITIVE_TYPE.FLOAT:
|
|
589
|
+
case PRECISE_PRIMITIVE_TYPE.U_INT:
|
|
590
|
+
case PRECISE_PRIMITIVE_TYPE.TINY_INT:
|
|
591
|
+
case PRECISE_PRIMITIVE_TYPE.U_BIG_INT:
|
|
592
|
+
case PRECISE_PRIMITIVE_TYPE.U_SMALL_INT:
|
|
593
|
+
case PRECISE_PRIMITIVE_TYPE.U_TINY_INT:
|
|
594
|
+
return (
|
|
595
|
+
<DataCubeEditorFilterConditionNodeNumberValueEditor
|
|
596
|
+
value={
|
|
597
|
+
!isNullable(it.value)
|
|
598
|
+
? (it.value as number)
|
|
599
|
+
: 0
|
|
600
|
+
}
|
|
601
|
+
updateValue={(v: number) => {
|
|
602
|
+
const next = localItems.slice();
|
|
603
|
+
const idx = next.findIndex(
|
|
604
|
+
(e) => e.id === id,
|
|
605
|
+
);
|
|
606
|
+
if (idx >= 0) {
|
|
607
|
+
next[idx] = {
|
|
608
|
+
id,
|
|
609
|
+
value: { type: it.type, value: v },
|
|
610
|
+
};
|
|
611
|
+
setLocalItems(next);
|
|
612
|
+
}
|
|
613
|
+
}}
|
|
614
|
+
/>
|
|
615
|
+
);
|
|
616
|
+
case PRIMITIVE_TYPE.DATE:
|
|
617
|
+
case PRIMITIVE_TYPE.STRICTDATE:
|
|
618
|
+
case PRIMITIVE_TYPE.DATETIME:
|
|
619
|
+
case PRECISE_PRIMITIVE_TYPE.STRICTDATE:
|
|
620
|
+
case PRECISE_PRIMITIVE_TYPE.DATETIME:
|
|
621
|
+
case PRECISE_PRIMITIVE_TYPE.STRICTTIME:
|
|
622
|
+
case PRECISE_PRIMITIVE_TYPE.TIMESTAMP:
|
|
623
|
+
return (
|
|
624
|
+
<DataCubeEditorFilterConditionNodeDateValueEditor
|
|
625
|
+
value={String(
|
|
626
|
+
it.value ??
|
|
627
|
+
formatDate(new Date(), DATE_FORMAT),
|
|
628
|
+
)}
|
|
629
|
+
updateValue={(v: string) => {
|
|
630
|
+
const next = localItems.slice();
|
|
631
|
+
const idx = next.findIndex(
|
|
632
|
+
(e) => e.id === id,
|
|
633
|
+
);
|
|
634
|
+
if (idx >= 0) {
|
|
635
|
+
next[idx] = {
|
|
636
|
+
id,
|
|
637
|
+
value: { type: it.type, value: v },
|
|
638
|
+
};
|
|
639
|
+
setLocalItems(next);
|
|
640
|
+
}
|
|
641
|
+
}}
|
|
642
|
+
/>
|
|
643
|
+
);
|
|
644
|
+
default:
|
|
645
|
+
return (
|
|
646
|
+
<DataCubeEditorFilterConditionNodeTextValueEditor
|
|
647
|
+
value={String(it.value ?? '')}
|
|
648
|
+
updateValue={(v: string) => {
|
|
649
|
+
const next = localItems.slice();
|
|
650
|
+
const idx = next.findIndex(
|
|
651
|
+
(e) => e.id === id,
|
|
652
|
+
);
|
|
653
|
+
if (idx >= 0) {
|
|
654
|
+
next[idx] = {
|
|
655
|
+
id,
|
|
656
|
+
value: { type: it.type, value: v },
|
|
657
|
+
};
|
|
658
|
+
setLocalItems(next);
|
|
659
|
+
}
|
|
660
|
+
}}
|
|
661
|
+
/>
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
})()}
|
|
665
|
+
</div>
|
|
666
|
+
<button
|
|
667
|
+
className="text-sm text-red-600"
|
|
668
|
+
onClick={() => {
|
|
669
|
+
const idx = localItems.findIndex((e) => e.id === id);
|
|
670
|
+
if (idx >= 0) {
|
|
671
|
+
removeItem(idx);
|
|
672
|
+
}
|
|
673
|
+
}}
|
|
674
|
+
title="Remove"
|
|
675
|
+
>
|
|
676
|
+
×
|
|
677
|
+
</button>
|
|
678
|
+
</div>
|
|
679
|
+
);
|
|
680
|
+
})}
|
|
681
|
+
</div>
|
|
682
|
+
<div className="mt-2 flex items-center gap-2">
|
|
683
|
+
<input
|
|
684
|
+
ref={inputRef}
|
|
685
|
+
className="flex-1 border border-neutral-300 px-1 text-sm"
|
|
686
|
+
placeholder="Add value"
|
|
687
|
+
value={newInput}
|
|
688
|
+
onChange={(e) => setNewInput(e.target.value)}
|
|
689
|
+
onKeyDown={(e) => {
|
|
690
|
+
if (e.key === 'Enter') {
|
|
691
|
+
addItem();
|
|
692
|
+
e.preventDefault();
|
|
693
|
+
} else if (e.key === 'Escape') {
|
|
694
|
+
close();
|
|
695
|
+
}
|
|
696
|
+
}}
|
|
697
|
+
/>
|
|
698
|
+
<button className="ml-1" onClick={addItem} title="Add">
|
|
699
|
+
+
|
|
700
|
+
</button>
|
|
701
|
+
</div>
|
|
702
|
+
<div className="mt-2 flex justify-end">
|
|
703
|
+
<FormButton
|
|
704
|
+
onClick={() => {
|
|
705
|
+
close();
|
|
706
|
+
}}
|
|
707
|
+
>
|
|
708
|
+
Done
|
|
709
|
+
</FormButton>
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
</BasePopover>
|
|
713
|
+
</>
|
|
714
|
+
);
|
|
715
|
+
}),
|
|
716
|
+
);
|
|
717
|
+
|
|
363
718
|
const DataCubeEditorFilterConditionNodeValueEditor = observer(
|
|
364
719
|
forwardRef<
|
|
365
720
|
HTMLElement,
|
|
@@ -370,7 +725,7 @@ const DataCubeEditorFilterConditionNodeValueEditor = observer(
|
|
|
370
725
|
}
|
|
371
726
|
>(function DataCubeEditorFilterConditionNodeValueEditor(props, ref) {
|
|
372
727
|
const { value, updateValue, view } = props;
|
|
373
|
-
// WIP: support
|
|
728
|
+
// WIP: support column
|
|
374
729
|
switch (value.type) {
|
|
375
730
|
case PRIMITIVE_TYPE.STRING:
|
|
376
731
|
case PRECISE_PRIMITIVE_TYPE.VARCHAR:
|
|
@@ -435,6 +790,15 @@ const DataCubeEditorFilterConditionNodeValueEditor = observer(
|
|
|
435
790
|
view={view}
|
|
436
791
|
/>
|
|
437
792
|
);
|
|
793
|
+
case DataCubeOperationAdvancedValueType.LIST:
|
|
794
|
+
return (
|
|
795
|
+
<DataCubeEditorFilterConditionNodeListValueEditor
|
|
796
|
+
ref={ref}
|
|
797
|
+
value={value}
|
|
798
|
+
updateValue={(val) => updateValue(val)}
|
|
799
|
+
view={view}
|
|
800
|
+
/>
|
|
801
|
+
);
|
|
438
802
|
case DataCubeOperationAdvancedValueType.VOID:
|
|
439
803
|
default:
|
|
440
804
|
return null;
|
|
@@ -60,6 +60,8 @@ import { DataCubeQueryFilterOperation__GreaterThanOrEqualColumn } from './filter
|
|
|
60
60
|
import { DataCubeQueryFilterOperation__Contain } from './filter/DataCubeQueryFilterOperation__Contain.js';
|
|
61
61
|
import { DataCubeQueryFilterOperation__ContainCaseInsensitive } from './filter/DataCubeQueryFilterOperation__ContainCaseInsensitive.js';
|
|
62
62
|
import { DataCubeQueryFilterOperation__NotContain } from './filter/DataCubeQueryFilterOperation__NotContain.js';
|
|
63
|
+
import { DataCubeQueryFilterOperation__In } from './filter/DataCubeQueryFilterOperation__In.js';
|
|
64
|
+
import { DataCubeQueryFilterOperation__NotIn } from './filter/DataCubeQueryFilterOperation__NotIn.js';
|
|
63
65
|
import { DataCubeQueryFilterOperation__StartWith } from './filter/DataCubeQueryFilterOperation__StartWith.js';
|
|
64
66
|
import { DataCubeQueryFilterOperation__StartWithCaseInsensitive } from './filter/DataCubeQueryFilterOperation__StartWithCaseInsensitive.js';
|
|
65
67
|
import { DataCubeQueryFilterOperation__NotStartWith } from './filter/DataCubeQueryFilterOperation__NotStartWith.js';
|
|
@@ -148,6 +150,8 @@ export abstract class DataCubeEngine {
|
|
|
148
150
|
new DataCubeQueryFilterOperation__Contain(),
|
|
149
151
|
new DataCubeQueryFilterOperation__ContainCaseInsensitive(),
|
|
150
152
|
new DataCubeQueryFilterOperation__NotContain(),
|
|
153
|
+
new DataCubeQueryFilterOperation__In(),
|
|
154
|
+
new DataCubeQueryFilterOperation__NotIn(),
|
|
151
155
|
new DataCubeQueryFilterOperation__StartWith(),
|
|
152
156
|
new DataCubeQueryFilterOperation__StartWithCaseInsensitive(),
|
|
153
157
|
new DataCubeQueryFilterOperation__NotStartWith(),
|
|
@@ -322,7 +322,7 @@ export function _colSpec(
|
|
|
322
322
|
return colSpec;
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
export function _value(value: DataCubeOperationValue) {
|
|
325
|
+
export function _value(value: DataCubeOperationValue): V1_ValueSpecification {
|
|
326
326
|
switch (value.type) {
|
|
327
327
|
case PRIMITIVE_TYPE.STRING:
|
|
328
328
|
case PRECISE_PRIMITIVE_TYPE.VARCHAR:
|
|
@@ -361,6 +361,17 @@ export function _value(value: DataCubeOperationValue) {
|
|
|
361
361
|
}
|
|
362
362
|
case DataCubeOperationAdvancedValueType.COLUMN:
|
|
363
363
|
return _property(guaranteeIsString(value.value));
|
|
364
|
+
case DataCubeOperationAdvancedValueType.LIST: {
|
|
365
|
+
// value.value is expected to be an array of DataCubeOperationValue
|
|
366
|
+
if (!Array.isArray(value.value)) {
|
|
367
|
+
throw new UnsupportedOperationError(
|
|
368
|
+
`List value must be an array for type '${DataCubeOperationAdvancedValueType.LIST}'`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
return _collection(
|
|
372
|
+
(value.value as DataCubeOperationValue[]).map((val) => _value(val)),
|
|
373
|
+
);
|
|
374
|
+
}
|
|
364
375
|
default:
|
|
365
376
|
throw new UnsupportedOperationError(
|
|
366
377
|
`Can't build value instance for unsupported type '${value.type}'`,
|
|
@@ -155,6 +155,7 @@ export enum DataCubeColumnKind {
|
|
|
155
155
|
|
|
156
156
|
export enum DataCubeOperationAdvancedValueType {
|
|
157
157
|
COLUMN = 'COLUMN',
|
|
158
|
+
LIST = 'LIST',
|
|
158
159
|
VOID = 'VOID',
|
|
159
160
|
// PARAMETER
|
|
160
161
|
}
|
|
@@ -472,6 +473,22 @@ export function isPrimitiveType(type: string) {
|
|
|
472
473
|
PRIMITIVE_TYPE.DATETIME,
|
|
473
474
|
PRIMITIVE_TYPE.STRING,
|
|
474
475
|
PRIMITIVE_TYPE.BOOLEAN,
|
|
476
|
+
PRECISE_PRIMITIVE_TYPE.INT,
|
|
477
|
+
PRECISE_PRIMITIVE_TYPE.BIG_INT,
|
|
478
|
+
PRECISE_PRIMITIVE_TYPE.DECIMAL,
|
|
479
|
+
PRECISE_PRIMITIVE_TYPE.NUMERIC,
|
|
480
|
+
PRECISE_PRIMITIVE_TYPE.DOUBLE,
|
|
481
|
+
PRECISE_PRIMITIVE_TYPE.SMALL_INT,
|
|
482
|
+
PRECISE_PRIMITIVE_TYPE.FLOAT,
|
|
483
|
+
PRECISE_PRIMITIVE_TYPE.U_INT,
|
|
484
|
+
PRECISE_PRIMITIVE_TYPE.TINY_INT,
|
|
485
|
+
PRECISE_PRIMITIVE_TYPE.U_BIG_INT,
|
|
486
|
+
PRECISE_PRIMITIVE_TYPE.U_SMALL_INT,
|
|
487
|
+
PRECISE_PRIMITIVE_TYPE.U_TINY_INT,
|
|
488
|
+
PRECISE_PRIMITIVE_TYPE.STRICTDATE,
|
|
489
|
+
PRECISE_PRIMITIVE_TYPE.STRICTTIME,
|
|
490
|
+
PRECISE_PRIMITIVE_TYPE.TIMESTAMP,
|
|
491
|
+
PRECISE_PRIMITIVE_TYPE.VARCHAR,
|
|
475
492
|
] as string[]
|
|
476
493
|
).includes(type);
|
|
477
494
|
}
|
|
@@ -233,7 +233,7 @@ export function _operationValue(
|
|
|
233
233
|
value: V1_ValueSpecification | undefined,
|
|
234
234
|
columnGetter: (name: string) => DataCubeColumn,
|
|
235
235
|
columnChecker?: ((column: DataCubeColumn) => void) | undefined,
|
|
236
|
-
) {
|
|
236
|
+
): DataCubeOperationValue {
|
|
237
237
|
if (value instanceof V1_PrimitiveValueSpecification) {
|
|
238
238
|
return _operationPrimitiveValue(value);
|
|
239
239
|
} else if (value instanceof V1_AppliedProperty) {
|
|
@@ -243,6 +243,13 @@ export function _operationValue(
|
|
|
243
243
|
value: column.name,
|
|
244
244
|
type: DataCubeOperationAdvancedValueType.COLUMN,
|
|
245
245
|
};
|
|
246
|
+
} else if (value instanceof V1_Collection) {
|
|
247
|
+
return {
|
|
248
|
+
type: DataCubeOperationAdvancedValueType.LIST,
|
|
249
|
+
value: value.values.map((val) =>
|
|
250
|
+
_operationValue(val, columnGetter, columnChecker),
|
|
251
|
+
),
|
|
252
|
+
};
|
|
246
253
|
} else if (value === undefined) {
|
|
247
254
|
return {
|
|
248
255
|
type: DataCubeOperationAdvancedValueType.VOID,
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025-present, Goldman Sachs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { DataCubeQueryFilterOperation } from './DataCubeQueryFilterOperation.js';
|
|
17
|
+
import type { DataCubeSnapshotFilterCondition } from '../DataCubeSnapshot.js';
|
|
18
|
+
import type { DataCubeColumn } from '../model/DataCubeColumn.js';
|
|
19
|
+
import {
|
|
20
|
+
DataCubeColumnDataType,
|
|
21
|
+
DataCubeFunction,
|
|
22
|
+
DataCubeQueryFilterOperator,
|
|
23
|
+
isPrimitiveType,
|
|
24
|
+
ofDataType,
|
|
25
|
+
_defaultPrimitiveTypeValue,
|
|
26
|
+
DataCubeOperationAdvancedValueType,
|
|
27
|
+
type DataCubeOperationValue,
|
|
28
|
+
} from '../DataCubeQueryEngine.js';
|
|
29
|
+
import {
|
|
30
|
+
_function,
|
|
31
|
+
_functionName,
|
|
32
|
+
_property,
|
|
33
|
+
_value,
|
|
34
|
+
} from '../DataCubeQueryBuilderUtils.js';
|
|
35
|
+
import { type V1_AppliedFunction } from '@finos/legend-graph';
|
|
36
|
+
import { _filterCondition_base } from '../DataCubeSnapshotBuilderUtils.js';
|
|
37
|
+
|
|
38
|
+
export class DataCubeQueryFilterOperation__In extends DataCubeQueryFilterOperation {
|
|
39
|
+
override get label() {
|
|
40
|
+
return 'in list of';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override get textLabel() {
|
|
44
|
+
return 'in list of';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override get description() {
|
|
48
|
+
return 'in list of';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override get operator() {
|
|
52
|
+
return DataCubeQueryFilterOperator.IN;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
isCompatibleWithColumn(column: DataCubeColumn) {
|
|
56
|
+
return ofDataType(column.type, [
|
|
57
|
+
DataCubeColumnDataType.TEXT,
|
|
58
|
+
DataCubeColumnDataType.NUMBER,
|
|
59
|
+
DataCubeColumnDataType.DATE,
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
isCompatibleWithValue(value: DataCubeOperationValue) {
|
|
64
|
+
// - advanced LIST type: { type: DataCubeOperationAdvancedValueType.LIST, value: [{ type: <primitive>, value: <primitive> }, ...] }
|
|
65
|
+
if (value.value === undefined) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (value.type === DataCubeOperationAdvancedValueType.LIST) {
|
|
69
|
+
if (
|
|
70
|
+
!Array.isArray(value.value) ||
|
|
71
|
+
(value.value as unknown[]).length === 0
|
|
72
|
+
) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return (value.value as unknown[]).every((v) => {
|
|
76
|
+
const maybe = v as DataCubeOperationValue;
|
|
77
|
+
return (
|
|
78
|
+
maybe.value !== undefined &&
|
|
79
|
+
isPrimitiveType(maybe.type) &&
|
|
80
|
+
ofDataType(maybe.type, [
|
|
81
|
+
DataCubeColumnDataType.TEXT,
|
|
82
|
+
DataCubeColumnDataType.NUMBER,
|
|
83
|
+
DataCubeColumnDataType.DATE,
|
|
84
|
+
])
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return (
|
|
89
|
+
isPrimitiveType(value.type) &&
|
|
90
|
+
ofDataType(value.type, [
|
|
91
|
+
DataCubeColumnDataType.TEXT,
|
|
92
|
+
DataCubeColumnDataType.NUMBER,
|
|
93
|
+
DataCubeColumnDataType.DATE,
|
|
94
|
+
]) &&
|
|
95
|
+
Array.isArray(value.value) &&
|
|
96
|
+
(value.value as unknown[]).length > 0
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
generateDefaultValue(column: DataCubeColumn) {
|
|
101
|
+
return {
|
|
102
|
+
type: DataCubeOperationAdvancedValueType.LIST,
|
|
103
|
+
value: [
|
|
104
|
+
{
|
|
105
|
+
type: column.type,
|
|
106
|
+
value: _defaultPrimitiveTypeValue(column.type),
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
buildConditionSnapshot(
|
|
113
|
+
expression: V1_AppliedFunction,
|
|
114
|
+
columnGetter: (name: string) => DataCubeColumn,
|
|
115
|
+
) {
|
|
116
|
+
return this._finalizeConditionSnapshot(
|
|
117
|
+
_filterCondition_base(expression, DataCubeFunction.IN, columnGetter),
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
buildConditionExpression(condition: DataCubeSnapshotFilterCondition) {
|
|
122
|
+
return _function(_functionName(DataCubeFunction.IN), [
|
|
123
|
+
_property(condition.name),
|
|
124
|
+
_value(condition.value),
|
|
125
|
+
]);
|
|
126
|
+
}
|
|
127
|
+
}
|