@platforma-sdk/model 1.44.13 → 1.45.0
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/dist/annotations/converter.cjs +29 -0
- package/dist/annotations/converter.cjs.map +1 -0
- package/dist/annotations/converter.d.ts +3 -0
- package/dist/annotations/converter.d.ts.map +1 -0
- package/dist/annotations/converter.js +27 -0
- package/dist/annotations/converter.js.map +1 -0
- package/dist/annotations/index.d.ts +3 -0
- package/dist/annotations/index.d.ts.map +1 -0
- package/dist/annotations/types.d.ts +22 -0
- package/dist/annotations/types.d.ts.map +1 -0
- package/dist/components/PlAnnotations/filter.d.ts.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.cjs +1 -372
- package/dist/components/PlAnnotations/filters_ui.cjs.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.d.ts +11 -756
- package/dist/components/PlAnnotations/filters_ui.d.ts.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.js +2 -370
- package/dist/components/PlAnnotations/filters_ui.js.map +1 -1
- package/dist/components/PlAnnotations/index.d.ts.map +1 -1
- package/dist/components/PlAnnotations/types.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/filters/converter.cjs +101 -0
- package/dist/filters/converter.cjs.map +1 -0
- package/dist/filters/converter.d.ts +5 -0
- package/dist/filters/converter.d.ts.map +1 -0
- package/dist/filters/converter.js +98 -0
- package/dist/filters/converter.js.map +1 -0
- package/dist/filters/index.d.ts +3 -0
- package/dist/filters/index.d.ts.map +1 -0
- package/dist/filters/types.d.ts +102 -0
- package/dist/filters/types.d.ts.map +1 -0
- package/dist/index.cjs +10 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/package.json.cjs +1 -1
- package/dist/package.json.js +1 -1
- package/dist/render/util/column_collection.cjs +2 -2
- package/dist/render/util/column_collection.cjs.map +1 -1
- package/dist/render/util/column_collection.d.ts +2 -2
- package/dist/render/util/column_collection.d.ts.map +1 -1
- package/dist/render/util/column_collection.js +2 -2
- package/dist/render/util/column_collection.js.map +1 -1
- package/dist/render/util/pcolumn_data.cjs +4 -0
- package/dist/render/util/pcolumn_data.cjs.map +1 -1
- package/dist/render/util/pcolumn_data.d.ts.map +1 -1
- package/dist/render/util/pcolumn_data.js +4 -0
- package/dist/render/util/pcolumn_data.js.map +1 -1
- package/package.json +7 -6
- package/src/annotations/converter.test.ts +74 -0
- package/src/annotations/converter.ts +28 -0
- package/src/annotations/index.ts +2 -0
- package/src/annotations/types.ts +23 -0
- package/src/components/PlAnnotations/filter.ts +1 -0
- package/src/components/PlAnnotations/filters_ui.test.ts +1 -0
- package/src/components/PlAnnotations/filters_ui.ts +56 -439
- package/src/components/PlAnnotations/index.ts +1 -0
- package/src/components/PlAnnotations/types.ts +1 -0
- package/src/components/index.ts +1 -1
- package/src/filters/converter.test.ts +336 -0
- package/src/filters/converter.ts +119 -0
- package/src/filters/index.ts +2 -0
- package/src/filters/types.ts +47 -0
- package/src/index.ts +2 -0
- package/src/render/util/column_collection.ts +19 -19
- package/src/render/util/pcolumn_data.ts +4 -0
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import type { SUniversalPColumnId } from '@milaboratories/pl-model-common';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { convertFilterUiToExpressions } from './converter';
|
|
4
|
+
import { FilterSpec } from './types';
|
|
5
|
+
|
|
6
|
+
describe('convertFilterUiToExpressions', () => {
|
|
7
|
+
it('should compile "or" filter to ptabler expression', () => {
|
|
8
|
+
const uiFilter: FilterSpec = {
|
|
9
|
+
type: 'or',
|
|
10
|
+
filters: [
|
|
11
|
+
{ type: 'isNA', column: 'colA' as unknown as SUniversalPColumnId },
|
|
12
|
+
{ type: 'patternEquals', column: 'colB' as unknown as SUniversalPColumnId, value: 'test' },
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
16
|
+
expect(result.type).toBe('or');
|
|
17
|
+
expect((result as any).operands).toHaveLength(2);
|
|
18
|
+
expect((result as any).operands[0].type).toBe('is_na');
|
|
19
|
+
expect((result as any).operands[1].type).toBe('eq');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should compile "and" filter to ptabler expression', () => {
|
|
23
|
+
const uiFilter: FilterSpec = {
|
|
24
|
+
type: 'and',
|
|
25
|
+
filters: [
|
|
26
|
+
{ type: 'isNA', column: 'colA' as unknown as SUniversalPColumnId },
|
|
27
|
+
{ type: 'greaterThan', column: 'colNum' as unknown as SUniversalPColumnId, x: 10 },
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
31
|
+
expect(result.type).toBe('and');
|
|
32
|
+
expect((result as any).operands).toHaveLength(2);
|
|
33
|
+
expect((result as any).operands[0].type).toBe('is_na');
|
|
34
|
+
expect((result as any).operands[1].type).toBe('gt');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should compile "not" filter to ptabler expression', () => {
|
|
38
|
+
const uiFilter: FilterSpec = {
|
|
39
|
+
type: 'not',
|
|
40
|
+
filter: { type: 'isNA', column: 'colA' as unknown as SUniversalPColumnId },
|
|
41
|
+
};
|
|
42
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
43
|
+
expect(result.type).toBe('not');
|
|
44
|
+
expect((result as any).value.type).toBe('is_na');
|
|
45
|
+
expect((result as any).value.value.type).toBe('col');
|
|
46
|
+
expect((result as any).value.value.name).toBe('colA');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should compile "isNA" filter to ptabler expression', () => {
|
|
50
|
+
const uiFilter: FilterSpec = { type: 'isNA', column: 'colA' as unknown as SUniversalPColumnId };
|
|
51
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
52
|
+
expect(result as any).toEqual({
|
|
53
|
+
type: 'is_na',
|
|
54
|
+
value: { type: 'col', name: 'colA' },
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should compile "isNotNA" filter to ptabler expression', () => {
|
|
59
|
+
const uiFilter: FilterSpec = { type: 'isNotNA', column: 'colA' as unknown as SUniversalPColumnId };
|
|
60
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
61
|
+
expect(result as any).toEqual({
|
|
62
|
+
type: 'is_not_na',
|
|
63
|
+
value: { type: 'col', name: 'colA' },
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should compile "patternEquals" filter to ptabler expression', () => {
|
|
68
|
+
const uiFilter: FilterSpec = { type: 'patternEquals', column: 'colB' as unknown as SUniversalPColumnId, value: 'abc' };
|
|
69
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
70
|
+
expect(result as any).toEqual({
|
|
71
|
+
type: 'eq',
|
|
72
|
+
lhs: { type: 'col', name: 'colB' },
|
|
73
|
+
rhs: { type: 'const', value: 'abc' },
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should compile "patternNotEquals" filter to ptabler expression', () => {
|
|
78
|
+
const uiFilter: FilterSpec = { type: 'patternNotEquals', column: 'colB' as unknown as SUniversalPColumnId, value: 'abc' };
|
|
79
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
80
|
+
expect(result as any).toEqual({
|
|
81
|
+
type: 'neq',
|
|
82
|
+
lhs: { type: 'col', name: 'colB' },
|
|
83
|
+
rhs: { type: 'const', value: 'abc' },
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should compile "patternContainSubsequence" filter to ptabler expression', () => {
|
|
88
|
+
const uiFilter: FilterSpec = { type: 'patternContainSubsequence', column: 'colC' as unknown as SUniversalPColumnId, value: 'sub' };
|
|
89
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
90
|
+
expect(result.type).toBe('str_contains');
|
|
91
|
+
expect((result as any).value).toEqual({ type: 'col', name: 'colC' });
|
|
92
|
+
expect((result as any).pattern).toEqual({ type: 'const', value: 'sub' });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should compile "patternNotContainSubsequence" filter to ptabler expression', () => {
|
|
96
|
+
const uiFilter: FilterSpec = { type: 'patternNotContainSubsequence', column: 'colC' as unknown as SUniversalPColumnId, value: 'sub' };
|
|
97
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
98
|
+
expect(result.type).toBe('not');
|
|
99
|
+
expect((result as any).value.type).toBe('str_contains');
|
|
100
|
+
expect((result as any).value.value).toEqual({ type: 'col', name: 'colC' });
|
|
101
|
+
expect((result as any).value.pattern).toEqual({ type: 'const', value: 'sub' });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should compile numerical comparison filters to ptabler expressions', () => {
|
|
105
|
+
const testCases = [
|
|
106
|
+
{ type: 'equal' as const, expected: 'eq' },
|
|
107
|
+
{ type: 'lessThan' as const, expected: 'lt' },
|
|
108
|
+
{ type: 'greaterThan' as const, expected: 'gt' },
|
|
109
|
+
{ type: 'lessThanOrEqual' as const, expected: 'le' },
|
|
110
|
+
{ type: 'greaterThanOrEqual' as const, expected: 'ge' },
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
testCases.forEach(({ type, expected }) => {
|
|
114
|
+
const uiFilter: FilterSpec = { type, column: 'colNum' as unknown as SUniversalPColumnId, x: 10 };
|
|
115
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
116
|
+
expect(result as any).toEqual({
|
|
117
|
+
type: expected,
|
|
118
|
+
lhs: { type: 'col', name: 'colNum' },
|
|
119
|
+
rhs: { type: 'const', value: 10 },
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should compile "lessThanColumn" filter to ptabler expression', () => {
|
|
125
|
+
const uiFilter: FilterSpec = {
|
|
126
|
+
type: 'lessThanColumn',
|
|
127
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
128
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
129
|
+
};
|
|
130
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
131
|
+
expect(result as any).toEqual({
|
|
132
|
+
type: 'lt',
|
|
133
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
134
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should compile "lessThanColumn" filter with minDiff to ptabler expression', () => {
|
|
139
|
+
const uiFilter: FilterSpec = {
|
|
140
|
+
type: 'lessThanColumn',
|
|
141
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
142
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
143
|
+
minDiff: 5,
|
|
144
|
+
};
|
|
145
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
146
|
+
expect(result as any).toEqual({
|
|
147
|
+
type: 'lt',
|
|
148
|
+
lhs: {
|
|
149
|
+
type: 'plus',
|
|
150
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
151
|
+
rhs: { type: 'const', value: 5 },
|
|
152
|
+
},
|
|
153
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should compile "greaterThanColumn" filter to ptabler expression', () => {
|
|
158
|
+
const uiFilter: FilterSpec = {
|
|
159
|
+
type: 'greaterThanColumn',
|
|
160
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
161
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
162
|
+
};
|
|
163
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
164
|
+
expect(result as any).toEqual({
|
|
165
|
+
type: 'gt',
|
|
166
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
167
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should compile "greaterThanColumn" filter with minDiff to ptabler expression', () => {
|
|
172
|
+
const uiFilter: FilterSpec = {
|
|
173
|
+
type: 'greaterThanColumn',
|
|
174
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
175
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
176
|
+
minDiff: 7,
|
|
177
|
+
};
|
|
178
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
179
|
+
expect(result as any).toEqual({
|
|
180
|
+
type: 'gt',
|
|
181
|
+
lhs: {
|
|
182
|
+
type: 'plus',
|
|
183
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
184
|
+
rhs: { type: 'const', value: 7 },
|
|
185
|
+
},
|
|
186
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should compile "equalToColumn" filter to ptabler expression', () => {
|
|
191
|
+
const uiFilter: FilterSpec = {
|
|
192
|
+
type: 'equalToColumn',
|
|
193
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
194
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
195
|
+
};
|
|
196
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
197
|
+
expect(result as any).toEqual({
|
|
198
|
+
type: 'eq',
|
|
199
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
200
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should compile "greaterThanColumnOrEqual" filter to ptabler expression', () => {
|
|
205
|
+
const uiFilter: FilterSpec = {
|
|
206
|
+
type: 'greaterThanColumnOrEqual',
|
|
207
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
208
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
209
|
+
};
|
|
210
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
211
|
+
expect(result as any).toEqual({
|
|
212
|
+
type: 'ge',
|
|
213
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
214
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should compile "greaterThanColumnOrEqual" filter with minDiff to ptabler expression', () => {
|
|
219
|
+
const uiFilter: FilterSpec = {
|
|
220
|
+
type: 'greaterThanColumnOrEqual',
|
|
221
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
222
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
223
|
+
minDiff: 2,
|
|
224
|
+
};
|
|
225
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
226
|
+
expect(result as any).toEqual({
|
|
227
|
+
type: 'ge',
|
|
228
|
+
lhs: {
|
|
229
|
+
type: 'plus',
|
|
230
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
231
|
+
rhs: { type: 'const', value: 2 },
|
|
232
|
+
},
|
|
233
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should compile "lessThanColumnOrEqual" filter to ptabler expression', () => {
|
|
238
|
+
const uiFilter: FilterSpec = {
|
|
239
|
+
type: 'lessThanColumnOrEqual',
|
|
240
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
241
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
242
|
+
};
|
|
243
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
244
|
+
expect(result as any).toEqual({
|
|
245
|
+
type: 'le',
|
|
246
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
247
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should compile "lessThanColumnOrEqual" filter with minDiff to ptabler expression', () => {
|
|
252
|
+
const uiFilter: FilterSpec = {
|
|
253
|
+
type: 'lessThanColumnOrEqual',
|
|
254
|
+
column: 'colNum1' as unknown as SUniversalPColumnId,
|
|
255
|
+
rhs: 'colNum2' as unknown as SUniversalPColumnId,
|
|
256
|
+
minDiff: 3,
|
|
257
|
+
};
|
|
258
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
259
|
+
expect(result as any).toEqual({
|
|
260
|
+
type: 'le',
|
|
261
|
+
lhs: {
|
|
262
|
+
type: 'plus',
|
|
263
|
+
lhs: { type: 'col', name: 'colNum1' },
|
|
264
|
+
rhs: { type: 'const', value: 3 },
|
|
265
|
+
},
|
|
266
|
+
rhs: { type: 'col', name: 'colNum2' },
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should compile "topN" filter to ptabler expression', () => {
|
|
271
|
+
const uiFilter: FilterSpec = { type: 'topN', column: 'colNum' as unknown as SUniversalPColumnId, n: 5 };
|
|
272
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
273
|
+
expect(result as any).toEqual({
|
|
274
|
+
type: 'le',
|
|
275
|
+
lhs: {
|
|
276
|
+
type: 'rank',
|
|
277
|
+
orderBy: [{ type: 'col', name: 'colNum' }],
|
|
278
|
+
partitionBy: [],
|
|
279
|
+
descending: true,
|
|
280
|
+
},
|
|
281
|
+
rhs: { type: 'const', value: 5 },
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should compile "bottomN" filter to ptabler expression', () => {
|
|
286
|
+
const uiFilter: FilterSpec = { type: 'bottomN', column: 'colNum' as unknown as SUniversalPColumnId, n: 3 };
|
|
287
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
288
|
+
expect(result as any).toEqual({
|
|
289
|
+
type: 'le',
|
|
290
|
+
lhs: {
|
|
291
|
+
type: 'rank',
|
|
292
|
+
orderBy: [{ type: 'col', name: 'colNum' }],
|
|
293
|
+
partitionBy: [],
|
|
294
|
+
descending: undefined, // ptabler-js sets descending to undefined when false
|
|
295
|
+
},
|
|
296
|
+
rhs: { type: 'const', value: 3 },
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should compile nested filters to ptabler expressions', () => {
|
|
301
|
+
const uiFilter: FilterSpec = {
|
|
302
|
+
type: 'and',
|
|
303
|
+
filters: [
|
|
304
|
+
{
|
|
305
|
+
type: 'or',
|
|
306
|
+
filters: [
|
|
307
|
+
{ type: 'isNA', column: 'colA' as unknown as SUniversalPColumnId },
|
|
308
|
+
{ type: 'patternEquals', column: 'colB' as unknown as SUniversalPColumnId, value: 'test' },
|
|
309
|
+
],
|
|
310
|
+
},
|
|
311
|
+
{ type: 'greaterThan', column: 'colNum' as unknown as SUniversalPColumnId, x: 10 },
|
|
312
|
+
],
|
|
313
|
+
};
|
|
314
|
+
const result = convertFilterUiToExpressions(uiFilter);
|
|
315
|
+
expect(result.type).toBe('and');
|
|
316
|
+
expect((result as any).operands).toHaveLength(2);
|
|
317
|
+
expect((result as any).operands[0].type).toBe('or');
|
|
318
|
+
expect((result as any).operands[0].operands).toHaveLength(2);
|
|
319
|
+
expect((result as any).operands[1].type).toBe('gt');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should throw error for OR filter with no operands', () => {
|
|
323
|
+
const uiFilter: FilterSpec = { type: 'or', filters: [] };
|
|
324
|
+
expect(() => convertFilterUiToExpressions(uiFilter)).toThrow('OR filter requires at least one operand');
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('should throw error for AND filter with no operands', () => {
|
|
328
|
+
const uiFilter: FilterSpec = { type: 'and', filters: [] };
|
|
329
|
+
expect(() => convertFilterUiToExpressions(uiFilter)).toThrow('AND filter requires at least one operand');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should throw error for undefined filter type', () => {
|
|
333
|
+
const uiFilter: FilterSpec = { type: undefined };
|
|
334
|
+
expect(() => convertFilterUiToExpressions(uiFilter)).toThrow('Filter type is undefined, this should not happen');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { assertNever } from '@milaboratories/pl-model-common';
|
|
2
|
+
import { and, col, lit, or, rank, type Expression, type ExpressionImpl } from '@milaboratories/ptabler-expression-js';
|
|
3
|
+
import type { FilterSpec } from '../filters';
|
|
4
|
+
|
|
5
|
+
export function convertFilterUiToExpressionImpl(value: FilterSpec): ExpressionImpl {
|
|
6
|
+
if (value.type === 'or') {
|
|
7
|
+
const expressions = value.filters.filter((f) => f.type !== undefined).map(convertFilterUiToExpressionImpl);
|
|
8
|
+
if (expressions.length === 0) {
|
|
9
|
+
throw new Error('OR filter requires at least one operand');
|
|
10
|
+
}
|
|
11
|
+
return or(...expressions);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (value.type === 'and') {
|
|
15
|
+
const expressions = value.filters.filter((f) => f.type !== undefined).map(convertFilterUiToExpressionImpl);
|
|
16
|
+
if (expressions.length === 0) {
|
|
17
|
+
throw new Error('AND filter requires at least one operand');
|
|
18
|
+
}
|
|
19
|
+
return and(...expressions);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (value.type === 'not') {
|
|
23
|
+
return convertFilterUiToExpressionImpl(value.filter).not();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (value.type === 'isNA') {
|
|
27
|
+
return col(value.column).isNull();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (value.type === 'isNotNA') {
|
|
31
|
+
return col(value.column).isNotNull();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (value.type === 'patternEquals') {
|
|
35
|
+
return col(value.column).eq(lit(value.value));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (value.type === 'patternNotEquals') {
|
|
39
|
+
return col(value.column).neq(lit(value.value));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (value.type === 'patternContainSubsequence') {
|
|
43
|
+
return col(value.column).strContains(value.value, false, true);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (value.type === 'patternNotContainSubsequence') {
|
|
47
|
+
return col(value.column).strContains(value.value, false, true).not();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (value.type === 'equal') {
|
|
51
|
+
return col(value.column).eq(lit(value.x));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (value.type === 'lessThan') {
|
|
55
|
+
return col(value.column).lt(lit(value.x));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (value.type === 'greaterThan') {
|
|
59
|
+
return col(value.column).gt(lit(value.x));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (value.type === 'lessThanOrEqual') {
|
|
63
|
+
return col(value.column).le(lit(value.x));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (value.type === 'greaterThanOrEqual') {
|
|
67
|
+
return col(value.column).ge(lit(value.x));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (value.type === 'equalToColumn') {
|
|
71
|
+
return col(value.column).eq(col(value.rhs));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (value.type === 'greaterThanColumn') {
|
|
75
|
+
if (value.minDiff !== undefined && value.minDiff !== 0) {
|
|
76
|
+
return col(value.column).plus(lit(value.minDiff)).gt(col(value.rhs));
|
|
77
|
+
}
|
|
78
|
+
return col(value.column).gt(col(value.rhs));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (value.type === 'lessThanColumn') {
|
|
82
|
+
if (value.minDiff !== undefined && value.minDiff !== 0) {
|
|
83
|
+
return col(value.column).plus(lit(value.minDiff)).lt(col(value.rhs));
|
|
84
|
+
}
|
|
85
|
+
return col(value.column).lt(col(value.rhs));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (value.type === 'greaterThanColumnOrEqual') {
|
|
89
|
+
if (value.minDiff !== undefined && value.minDiff !== 0) {
|
|
90
|
+
return col(value.column).plus(lit(value.minDiff)).ge(col(value.rhs));
|
|
91
|
+
}
|
|
92
|
+
return col(value.column).ge(col(value.rhs));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (value.type === 'lessThanColumnOrEqual') {
|
|
96
|
+
if (value.minDiff !== undefined && value.minDiff !== 0) {
|
|
97
|
+
return col(value.column).plus(lit(value.minDiff)).le(col(value.rhs));
|
|
98
|
+
}
|
|
99
|
+
return col(value.column).le(col(value.rhs));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (value.type === 'topN') {
|
|
103
|
+
return rank(col(value.column), true).over([]).le(lit(value.n));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (value.type === 'bottomN') {
|
|
107
|
+
return rank(col(value.column), false).over([]).le(lit(value.n));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (value.type === undefined) {
|
|
111
|
+
throw new Error('Filter type is undefined, this should not happen');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
assertNever(value);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function convertFilterUiToExpressions(value: FilterSpec): Expression {
|
|
118
|
+
return convertFilterUiToExpressionImpl(value).toJSON();
|
|
119
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { PColumnSpec, SUniversalPColumnId } from '@milaboratories/pl-model-common';
|
|
2
|
+
|
|
3
|
+
export type SimplifiedPColumnSpec = Pick<PColumnSpec, 'valueType' | 'annotations'>;
|
|
4
|
+
|
|
5
|
+
export type SimplifiedUniversalPColumnEntry = {
|
|
6
|
+
id: SUniversalPColumnId;
|
|
7
|
+
label: string;
|
|
8
|
+
obj: SimplifiedPColumnSpec;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type FilterSpecNode<Leaf, Common = {}> =
|
|
12
|
+
| Common & Leaf
|
|
13
|
+
| Common & { type: 'not'; filter: Common & Leaf }
|
|
14
|
+
| Common & { type: 'or'; filters: FilterSpecNode<Leaf, Common>[] }
|
|
15
|
+
| Common & { type: 'and'; filters: FilterSpecNode<Leaf, Common>[] };
|
|
16
|
+
|
|
17
|
+
export type FilterSpecLeaf =
|
|
18
|
+
| { type: undefined }
|
|
19
|
+
| { type: 'isNA'; column: SUniversalPColumnId }
|
|
20
|
+
| { type: 'isNotNA'; column: SUniversalPColumnId }
|
|
21
|
+
|
|
22
|
+
| { type: 'patternEquals'; column: SUniversalPColumnId; value: string }
|
|
23
|
+
| { type: 'patternNotEquals'; column: SUniversalPColumnId; value: string }
|
|
24
|
+
| { type: 'patternContainSubsequence'; column: SUniversalPColumnId; value: string }
|
|
25
|
+
| { type: 'patternNotContainSubsequence'; column: SUniversalPColumnId; value: string }
|
|
26
|
+
|
|
27
|
+
| { type: 'topN'; column: SUniversalPColumnId; n: number }
|
|
28
|
+
| { type: 'bottomN'; column: SUniversalPColumnId; n: number }
|
|
29
|
+
|
|
30
|
+
| { type: 'equal'; column: SUniversalPColumnId; x: number }
|
|
31
|
+
| { type: 'lessThan'; column: SUniversalPColumnId; x: number }
|
|
32
|
+
| { type: 'greaterThan'; column: SUniversalPColumnId; x: number }
|
|
33
|
+
| { type: 'lessThanOrEqual'; column: SUniversalPColumnId; x: number }
|
|
34
|
+
| { type: 'greaterThanOrEqual'; column: SUniversalPColumnId; x: number }
|
|
35
|
+
|
|
36
|
+
| { type: 'equalToColumn'; column: SUniversalPColumnId; rhs: SUniversalPColumnId }
|
|
37
|
+
| { type: 'lessThanColumn'; column: SUniversalPColumnId; rhs: SUniversalPColumnId; minDiff?: number }
|
|
38
|
+
| { type: 'greaterThanColumn'; column: SUniversalPColumnId; rhs: SUniversalPColumnId; minDiff?: number }
|
|
39
|
+
| { type: 'lessThanColumnOrEqual'; column: SUniversalPColumnId; rhs: SUniversalPColumnId; minDiff?: number }
|
|
40
|
+
| { type: 'greaterThanColumnOrEqual'; column: SUniversalPColumnId; rhs: SUniversalPColumnId; minDiff?: number };
|
|
41
|
+
|
|
42
|
+
export type FilterSpec<Leaf extends FilterSpecLeaf = FilterSpecLeaf, Common = {}> =
|
|
43
|
+
FilterSpecNode<Leaf, Common>;
|
|
44
|
+
|
|
45
|
+
export type FilterSpecType = Exclude<FilterSpec, { type: undefined }>['type'];
|
|
46
|
+
|
|
47
|
+
export type FilterSpecOfType<T extends FilterSpecType> = Extract<FilterSpec, { type: T }>;
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,8 @@ export * from './sdk_info';
|
|
|
12
12
|
export * from './raw_globals';
|
|
13
13
|
export * from './block_api_v1';
|
|
14
14
|
export * from './block_api_v2';
|
|
15
|
+
export * from './filters';
|
|
16
|
+
export * from './annotations';
|
|
15
17
|
|
|
16
18
|
// reexporting everything from SDK model
|
|
17
19
|
export * from '@milaboratories/pl-model-common';
|
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AnchoredIdDeriver,
|
|
3
|
+
AnchoredPColumnSelector,
|
|
4
|
+
AxisFilterByIdx,
|
|
5
|
+
AxisFilterValue,
|
|
3
6
|
AxisId,
|
|
7
|
+
NativePObjectId,
|
|
8
|
+
PartitionedDataInfoEntries,
|
|
4
9
|
PColumn,
|
|
5
10
|
PColumnSelector,
|
|
6
11
|
PColumnSpec,
|
|
12
|
+
PColumnValues,
|
|
7
13
|
PObjectId,
|
|
8
|
-
SUniversalPColumnId,
|
|
9
|
-
AxisFilterValue,
|
|
10
|
-
AxisFilterByIdx,
|
|
11
|
-
AnchoredPColumnSelector,
|
|
12
|
-
PartitionedDataInfoEntries,
|
|
13
14
|
ResolveAnchorsOptions,
|
|
14
|
-
|
|
15
|
-
PColumnValues,
|
|
15
|
+
SUniversalPColumnId,
|
|
16
16
|
} from '@milaboratories/pl-model-common';
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
resolveAnchors,
|
|
20
|
-
getAxisId,
|
|
21
|
-
isPColumnSpec,
|
|
18
|
+
Annotation,
|
|
22
19
|
canonicalizeAxisId,
|
|
23
|
-
isPartitionedDataInfoEntries,
|
|
24
|
-
entriesToDataInfo,
|
|
25
20
|
deriveNativeId,
|
|
26
|
-
|
|
21
|
+
entriesToDataInfo,
|
|
22
|
+
getAxisId,
|
|
23
|
+
isPartitionedDataInfoEntries,
|
|
24
|
+
isPColumnSpec,
|
|
25
|
+
resolveAnchors,
|
|
26
|
+
selectorsToPredicate,
|
|
27
27
|
} from '@milaboratories/pl-model-common';
|
|
28
|
+
import canonicalize from 'canonicalize';
|
|
29
|
+
import type { Optional } from 'utility-types';
|
|
28
30
|
import type { TreeNodeAccessor } from '../accessor';
|
|
31
|
+
import type { PColumnDataUniversal } from '../api';
|
|
32
|
+
import { filterDataInfoEntries } from './axis_filtering';
|
|
29
33
|
import type { LabelDerivationOps, TraceEntry } from './label';
|
|
30
34
|
import { deriveLabels } from './label';
|
|
31
|
-
import
|
|
35
|
+
import { convertOrParsePColumnData, getUniquePartitionKeys } from './pcolumn_data';
|
|
32
36
|
import type { APColumnSelectorWithSplit, PColumnSelectorWithSplit } from './split_selectors';
|
|
33
|
-
import canonicalize from 'canonicalize';
|
|
34
|
-
import { getUniquePartitionKeys, convertOrParsePColumnData } from './pcolumn_data';
|
|
35
|
-
import { filterDataInfoEntries } from './axis_filtering';
|
|
36
|
-
import type { PColumnDataUniversal } from '../api';
|
|
37
37
|
|
|
38
38
|
function isPColumnValues(value: unknown): value is PColumnValues {
|
|
39
39
|
if (!Array.isArray(value)) return false;
|
|
@@ -142,11 +142,13 @@ export function getPartitionKeysList(
|
|
|
142
142
|
|
|
143
143
|
case RT_JSON_PARTITIONED:
|
|
144
144
|
case RT_BINARY_PARTITIONED:
|
|
145
|
+
case RT_PARQUET_PARTITIONED:
|
|
145
146
|
keyLength = meta['partitionKeyLength'];
|
|
146
147
|
break;
|
|
147
148
|
|
|
148
149
|
case RT_BINARY_SUPER_PARTITIONED:
|
|
149
150
|
case RT_JSON_SUPER_PARTITIONED:
|
|
151
|
+
case RT_PARQUET_SUPER_PARTITIONED:
|
|
150
152
|
keyLength = meta['superPartitionKeyLength'] + meta['partitionKeyLength'];
|
|
151
153
|
break;
|
|
152
154
|
}
|
|
@@ -155,6 +157,7 @@ export function getPartitionKeysList(
|
|
|
155
157
|
case RT_RESOURCE_MAP:
|
|
156
158
|
case RT_JSON_PARTITIONED:
|
|
157
159
|
case RT_BINARY_PARTITIONED:
|
|
160
|
+
case RT_PARQUET_PARTITIONED:
|
|
158
161
|
for (let keyStr of acc.listInputFields()) {
|
|
159
162
|
if (rt === RT_BINARY_PARTITIONED) {
|
|
160
163
|
keyStr = removeIndexSuffix(keyStr).baseKey;
|
|
@@ -168,6 +171,7 @@ export function getPartitionKeysList(
|
|
|
168
171
|
case RT_RESOURCE_MAP_PARTITIONED:
|
|
169
172
|
case RT_BINARY_SUPER_PARTITIONED:
|
|
170
173
|
case RT_JSON_SUPER_PARTITIONED:
|
|
174
|
+
case RT_PARQUET_SUPER_PARTITIONED:
|
|
171
175
|
for (const supKeyStr of acc.listInputFields()) {
|
|
172
176
|
const keyPrefix = [...JSON.parse(supKeyStr)] as PColumnKey;
|
|
173
177
|
|