@visactor/vbi 0.0.0 → 0.4.13

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.
Files changed (29) hide show
  1. package/LICENSE +21 -0
  2. package/dist/builder/sub-builders/havingFilters/having-builder.d.ts +33 -20
  3. package/dist/builder/sub-builders/havingFilters/having-group-builder.d.ts +48 -0
  4. package/dist/builder/sub-builders/havingFilters/having-node-builder.d.ts +8 -0
  5. package/dist/builder/sub-builders/havingFilters/index.d.ts +1 -0
  6. package/dist/builder/sub-builders/index.d.ts +1 -1
  7. package/dist/builder/sub-builders/whereFilters/index.d.ts +1 -0
  8. package/dist/builder/sub-builders/whereFilters/where-builder.d.ts +30 -17
  9. package/dist/builder/sub-builders/whereFilters/where-group-builder.d.ts +48 -0
  10. package/dist/builder/sub-builders/whereFilters/where-node-builder.d.ts +8 -0
  11. package/dist/index.cjs +424 -129
  12. package/dist/index.js +406 -120
  13. package/dist/pipeline/index.d.ts +1 -1
  14. package/dist/pipeline/vqueryDSL/buildGroupBy.d.ts +2 -0
  15. package/dist/pipeline/vqueryDSL/buildHaving.d.ts +2 -0
  16. package/dist/pipeline/vqueryDSL/buildLimit.d.ts +2 -0
  17. package/dist/pipeline/vqueryDSL/buildSelect.d.ts +2 -0
  18. package/dist/pipeline/vqueryDSL/buildWhere.d.ts +2 -0
  19. package/dist/pipeline/vqueryDSL/index.d.ts +4 -1
  20. package/dist/pipeline/vqueryDSL/types.d.ts +7 -0
  21. package/dist/types/dsl/havingFilters/having.d.ts +12 -7
  22. package/dist/types/dsl/index.d.ts +4 -2
  23. package/dist/types/dsl/vbi/vbi.d.ts +2 -10
  24. package/dist/types/dsl/whereFilters/filters.d.ts +12 -1
  25. package/dist/types/index.d.ts +0 -1
  26. package/dist/utils/id.d.ts +3 -0
  27. package/dist/utils/index.d.ts +1 -0
  28. package/package.json +38 -23
  29. package/dist/pipeline/vqueryDSL/buildVQuery.d.ts +0 -4
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { Array as external_yjs_Array, Doc, Map as external_yjs_Map, UndoManager, applyUpdate, encodeStateAsUpdate } from "yjs";
2
2
  import { ChartTypeEnum, findTreeNodesBy, preorderTraverse } from "@visactor/vseed";
3
- import { z } from "zod";
3
+ import { v4 } from "uuid";
4
4
  import { pipe } from "remeda";
5
+ import { z } from "zod";
5
6
  class DimensionNodeBuilder {
6
7
  yMap;
7
8
  constructor(yMap){
@@ -166,20 +167,88 @@ class MeasuresBuilder {
166
167
  return 'children' in node;
167
168
  }
168
169
  }
170
+ const id_id = {
171
+ uuid: ()=>v4()
172
+ };
169
173
  class HavingFiltersNodeBuilder {
170
174
  yMap;
171
175
  constructor(yMap){
172
176
  this.yMap = yMap;
173
177
  }
178
+ getId() {
179
+ return this.yMap.get('id');
180
+ }
174
181
  getField() {
175
182
  return this.yMap.get('field');
176
183
  }
184
+ getOperator() {
185
+ return this.yMap.get('op');
186
+ }
177
187
  setValue(value) {
178
188
  this.yMap.set('value', value);
179
189
  return this;
180
190
  }
181
191
  setOperator(operator) {
182
- this.yMap.set('operator', operator);
192
+ this.yMap.set('op', operator);
193
+ return this;
194
+ }
195
+ toJson() {
196
+ return this.yMap.toJSON();
197
+ }
198
+ }
199
+ class HavingGroupBuilder {
200
+ yMap;
201
+ constructor(yMap){
202
+ this.yMap = yMap;
203
+ }
204
+ getId() {
205
+ return this.yMap.get('id');
206
+ }
207
+ getOperator() {
208
+ return this.yMap.get('op');
209
+ }
210
+ setOperator(op) {
211
+ this.yMap.set('op', op);
212
+ return this;
213
+ }
214
+ add(field, callback) {
215
+ const yMap = new external_yjs_Map();
216
+ yMap.set('id', id_id.uuid());
217
+ yMap.set('field', field);
218
+ const conditions = this.yMap.get('conditions');
219
+ conditions.push([
220
+ yMap
221
+ ]);
222
+ const node = new HavingFiltersNodeBuilder(yMap);
223
+ callback(node);
224
+ return this;
225
+ }
226
+ addGroup(op, callback) {
227
+ const yMap = new external_yjs_Map();
228
+ yMap.set('id', id_id.uuid());
229
+ yMap.set('op', op);
230
+ yMap.set('conditions', new external_yjs_Array());
231
+ const conditions = this.yMap.get('conditions');
232
+ conditions.push([
233
+ yMap
234
+ ]);
235
+ const group = new HavingGroupBuilder(yMap);
236
+ callback(group);
237
+ return this;
238
+ }
239
+ remove(idOrIndex) {
240
+ const conditions = this.yMap.get('conditions');
241
+ if ('number' == typeof idOrIndex) {
242
+ if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
243
+ } else {
244
+ const index = conditions.toArray().findIndex((item)=>item.get('id') === idOrIndex);
245
+ if (-1 !== index) conditions.delete(index, 1);
246
+ }
247
+ return this;
248
+ }
249
+ clear() {
250
+ const conditions = this.yMap.get('conditions');
251
+ conditions.delete(0, conditions.length);
183
252
  return this;
184
253
  }
185
254
  toJson() {
@@ -188,54 +257,76 @@ class HavingFiltersNodeBuilder {
188
257
  }
189
258
  class HavingFiltersBuilder {
190
259
  dsl;
191
- constructor(_doc, dsl){
260
+ doc;
261
+ constructor(doc, dsl){
262
+ this.doc = doc;
192
263
  this.dsl = dsl;
264
+ if (!this.dsl.get('havingFilters')) this.doc.transact(()=>{
265
+ this.dsl.set('havingFilters', new external_yjs_Array());
266
+ });
193
267
  }
194
268
  add(field, callback) {
195
- if (!field || 'string' != typeof field) throw new Error('Field is required and must be a string');
196
- const defaultFilter = {
197
- field,
198
- operator: 'eq',
199
- value: null
200
- };
201
269
  const yMap = new external_yjs_Map();
202
- for (const [key, value] of Object.entries(defaultFilter))yMap.set(key, value);
270
+ yMap.set('id', id_id.uuid());
271
+ yMap.set('field', field);
203
272
  this.dsl.get('havingFilters').push([
204
273
  yMap
205
274
  ]);
206
- const filterNode = new HavingFiltersNodeBuilder(yMap);
207
- callback(filterNode);
275
+ const node = new HavingFiltersNodeBuilder(yMap);
276
+ callback(node);
208
277
  return this;
209
278
  }
210
- update(field, callback) {
279
+ addGroup(op, callback) {
280
+ const yMap = new external_yjs_Map();
281
+ yMap.set('id', id_id.uuid());
282
+ yMap.set('op', op);
283
+ yMap.set('conditions', new external_yjs_Array());
284
+ this.dsl.get('havingFilters').push([
285
+ yMap
286
+ ]);
287
+ const group = new HavingGroupBuilder(yMap);
288
+ callback(group);
289
+ return this;
290
+ }
291
+ update(id, callback) {
211
292
  const havingFilters = this.dsl.get('havingFilters');
212
- const index = havingFilters.toArray().findIndex((item)=>item.get('field') === field);
213
- if (-1 === index) throw new Error(`Having filter with field "${field}" not found`);
293
+ const index = havingFilters.toArray().findIndex((item)=>item.get('id') === id);
294
+ if (-1 === index) throw new Error(`Having filter with id ${id} not found`);
214
295
  const filterYMap = havingFilters.get(index);
215
296
  const node = new HavingFiltersNodeBuilder(filterYMap);
216
297
  callback(node);
217
298
  return this;
218
299
  }
219
- remove(field) {
220
- if (!field || 'string' != typeof field) console.error('[HavingFiltersBuilder] Invalid field name:', field);
300
+ updateGroup(id, callback) {
221
301
  const havingFilters = this.dsl.get('havingFilters');
222
- const index = havingFilters.toArray().findIndex((item)=>item.get('field') === field);
223
- if (-1 !== index) this.dsl.get('havingFilters').delete(index, 1);
302
+ const index = havingFilters.toArray().findIndex((item)=>item.get('id') === id);
303
+ if (-1 === index) throw new Error(`Having group with id ${id} not found`);
304
+ const yMap = havingFilters.get(index);
305
+ if (!HavingFiltersBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
306
+ const group = new HavingGroupBuilder(yMap);
307
+ callback(group);
224
308
  return this;
225
309
  }
226
- find(field) {
310
+ remove(idOrIndex) {
227
311
  const havingFilters = this.dsl.get('havingFilters');
228
- const index = havingFilters.toArray().findIndex((item)=>item.get('field') === field);
229
- if (-1 === index) return;
230
- return new HavingFiltersNodeBuilder(havingFilters.get(index));
312
+ if ('number' == typeof idOrIndex) {
313
+ if (idOrIndex >= 0 && idOrIndex < havingFilters.length) havingFilters.delete(idOrIndex, 1);
314
+ } else {
315
+ const index = havingFilters.toArray().findIndex((item)=>item.get('id') === idOrIndex);
316
+ if (-1 !== index) havingFilters.delete(index, 1);
317
+ }
318
+ return this;
231
319
  }
232
- findAll() {
320
+ find(id) {
233
321
  const havingFilters = this.dsl.get('havingFilters');
234
- return havingFilters.toArray().map((yMap)=>new HavingFiltersNodeBuilder(yMap));
322
+ const yMap = havingFilters.toArray().find((item)=>item.get('id') === id);
323
+ if (!yMap) return;
324
+ if (HavingFiltersBuilder.isGroup(yMap)) return new HavingGroupBuilder(yMap);
325
+ return new HavingFiltersNodeBuilder(yMap);
235
326
  }
236
327
  clear() {
237
328
  const havingFilters = this.dsl.get('havingFilters');
238
- if (havingFilters.length > 0) havingFilters.delete(0, havingFilters.length);
329
+ havingFilters.delete(0, havingFilters.length);
239
330
  return this;
240
331
  }
241
332
  toJson() {
@@ -247,6 +338,12 @@ class HavingFiltersBuilder {
247
338
  this.dsl.get('havingFilters').unobserve(callback);
248
339
  };
249
340
  }
341
+ static isGroup(yMap) {
342
+ return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
343
+ }
344
+ static isNode(yMap) {
345
+ return void 0 !== yMap.get('field');
346
+ }
250
347
  }
251
348
  class ChartTypeBuilder {
252
349
  dsl;
@@ -302,11 +399,17 @@ class WhereFilterNodeBuilder {
302
399
  constructor(yMap){
303
400
  this.yMap = yMap;
304
401
  }
402
+ getId() {
403
+ return this.yMap.get('id');
404
+ }
305
405
  getField() {
306
406
  return this.yMap.get('field');
307
407
  }
408
+ getOperator() {
409
+ return this.yMap.get('op');
410
+ }
308
411
  setOperator(operator) {
309
- this.yMap.set('operator', operator);
412
+ this.yMap.set('op', operator);
310
413
  return this;
311
414
  }
312
415
  setValue(value) {
@@ -317,6 +420,65 @@ class WhereFilterNodeBuilder {
317
420
  return this.yMap.toJSON();
318
421
  }
319
422
  }
423
+ class WhereGroupBuilder {
424
+ yMap;
425
+ constructor(yMap){
426
+ this.yMap = yMap;
427
+ }
428
+ getId() {
429
+ return this.yMap.get('id');
430
+ }
431
+ getOperator() {
432
+ return this.yMap.get('op');
433
+ }
434
+ setOperator(op) {
435
+ this.yMap.set('op', op);
436
+ return this;
437
+ }
438
+ add(field, callback) {
439
+ const yMap = new external_yjs_Map();
440
+ yMap.set('id', id_id.uuid());
441
+ yMap.set('field', field);
442
+ const conditions = this.yMap.get('conditions');
443
+ conditions.push([
444
+ yMap
445
+ ]);
446
+ const node = new WhereFilterNodeBuilder(yMap);
447
+ callback(node);
448
+ return this;
449
+ }
450
+ addGroup(op, callback) {
451
+ const yMap = new external_yjs_Map();
452
+ yMap.set('id', id_id.uuid());
453
+ yMap.set('op', op);
454
+ yMap.set('conditions', new external_yjs_Array());
455
+ const conditions = this.yMap.get('conditions');
456
+ conditions.push([
457
+ yMap
458
+ ]);
459
+ const group = new WhereGroupBuilder(yMap);
460
+ callback(group);
461
+ return this;
462
+ }
463
+ remove(idOrIndex) {
464
+ const conditions = this.yMap.get('conditions');
465
+ if ('number' == typeof idOrIndex) {
466
+ if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
467
+ } else {
468
+ const index = conditions.toArray().findIndex((item)=>item.get('id') === idOrIndex);
469
+ if (-1 !== index) conditions.delete(index, 1);
470
+ }
471
+ return this;
472
+ }
473
+ clear() {
474
+ const conditions = this.yMap.get('conditions');
475
+ conditions.delete(0, conditions.length);
476
+ return this;
477
+ }
478
+ toJson() {
479
+ return this.yMap.toJSON();
480
+ }
481
+ }
320
482
  class WhereFiltersBuilder {
321
483
  dsl;
322
484
  doc;
@@ -328,11 +490,9 @@ class WhereFiltersBuilder {
328
490
  });
329
491
  }
330
492
  add(field, callback) {
331
- const filter = {
332
- field
333
- };
334
493
  const yMap = new external_yjs_Map();
335
- for (const [key, value] of Object.entries(filter))yMap.set(key, value);
494
+ yMap.set('id', id_id.uuid());
495
+ yMap.set('field', field);
336
496
  this.dsl.get('whereFilters').push([
337
497
  yMap
338
498
  ]);
@@ -340,31 +500,53 @@ class WhereFiltersBuilder {
340
500
  callback(node);
341
501
  return this;
342
502
  }
343
- update(field, callback) {
503
+ addGroup(op, callback) {
504
+ const yMap = new external_yjs_Map();
505
+ yMap.set('id', id_id.uuid());
506
+ yMap.set('op', op);
507
+ yMap.set('conditions', new external_yjs_Array());
508
+ this.dsl.get('whereFilters').push([
509
+ yMap
510
+ ]);
511
+ const group = new WhereGroupBuilder(yMap);
512
+ callback(group);
513
+ return this;
514
+ }
515
+ update(id, callback) {
344
516
  const whereFilters = this.dsl.get('whereFilters');
345
- const index = whereFilters.toArray().findIndex((item)=>item.get('field') === field);
346
- if (-1 === index) throw new Error(`Where filter with field ${field} not found`);
517
+ const index = whereFilters.toArray().findIndex((item)=>item.get('id') === id);
518
+ if (-1 === index) throw new Error(`Where filter with id ${id} not found`);
347
519
  const filterYMap = whereFilters.get(index);
348
520
  const node = new WhereFilterNodeBuilder(filterYMap);
349
521
  callback(node);
350
522
  return this;
351
523
  }
352
- remove(field) {
524
+ updateGroup(id, callback) {
353
525
  const whereFilters = this.dsl.get('whereFilters');
354
- const index = whereFilters.toArray().findIndex((item)=>item.get('field') === field);
355
- if (-1 === index) return this;
356
- whereFilters.delete(index, 1);
526
+ const index = whereFilters.toArray().findIndex((item)=>item.get('id') === id);
527
+ if (-1 === index) throw new Error(`Where group with id ${id} not found`);
528
+ const yMap = whereFilters.get(index);
529
+ if (!WhereFiltersBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
530
+ const group = new WhereGroupBuilder(yMap);
531
+ callback(group);
357
532
  return this;
358
533
  }
359
- find(field) {
534
+ remove(idOrIndex) {
360
535
  const whereFilters = this.dsl.get('whereFilters');
361
- const index = whereFilters.toArray().findIndex((item)=>item.get('field') === field);
362
- if (-1 === index) return;
363
- return new WhereFilterNodeBuilder(whereFilters.get(index));
536
+ if ('number' == typeof idOrIndex) {
537
+ if (idOrIndex >= 0 && idOrIndex < whereFilters.length) whereFilters.delete(idOrIndex, 1);
538
+ } else {
539
+ const index = whereFilters.toArray().findIndex((item)=>item.get('id') === idOrIndex);
540
+ if (-1 !== index) whereFilters.delete(index, 1);
541
+ }
542
+ return this;
364
543
  }
365
- findAll() {
544
+ find(id) {
366
545
  const whereFilters = this.dsl.get('whereFilters');
367
- return whereFilters.toArray().map((yMap)=>new WhereFilterNodeBuilder(yMap));
546
+ const yMap = whereFilters.toArray().find((item)=>item.get('id') === id);
547
+ if (!yMap) return;
548
+ if (WhereFiltersBuilder.isGroup(yMap)) return new WhereGroupBuilder(yMap);
549
+ return new WhereFilterNodeBuilder(yMap);
368
550
  }
369
551
  clear() {
370
552
  const whereFilters = this.dsl.get('whereFilters');
@@ -380,61 +562,13 @@ class WhereFiltersBuilder {
380
562
  this.dsl.get('whereFilters').unobserve(callback);
381
563
  };
382
564
  }
565
+ static isGroup(yMap) {
566
+ return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
567
+ }
568
+ static isNode(yMap) {
569
+ return void 0 !== yMap.get('field');
570
+ }
383
571
  }
384
- const zVBIHavingFilter = z.object({
385
- field: z.string(),
386
- operator: z.string().optional(),
387
- value: z.any().optional()
388
- });
389
- const zVBIHavingArray = z.array(zVBIHavingFilter);
390
- const buildVQuery = (vbiDSL, builder)=>{
391
- const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
392
- vbiDSL,
393
- builder
394
- });
395
- return pipe({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildOrderBy), wrapper(buildLimit));
396
- };
397
- const buildWhere = (queryDSL, context)=>{
398
- const { vbiDSL } = context;
399
- const whereFilters = vbiDSL.whereFilters || [];
400
- if (0 === whereFilters.length) return queryDSL;
401
- const result = {
402
- ...queryDSL
403
- };
404
- result.where = {
405
- op: 'and',
406
- conditions: whereFilters.flatMap((filter)=>{
407
- if ('between' === filter.operator && filter.value && 'object' == typeof filter.value && !Array.isArray(filter.value)) {
408
- const conditions = [];
409
- if (void 0 !== filter.value.min && null !== filter.value.min && '' !== filter.value.min) conditions.push({
410
- field: filter.field,
411
- op: '<' === filter.value.leftOp ? '>' : '>=',
412
- value: filter.value.min
413
- });
414
- if (void 0 !== filter.value.max && null !== filter.value.max && '' !== filter.value.max) conditions.push({
415
- field: filter.field,
416
- op: '<' === filter.value.rightOp ? '<' : '<=',
417
- value: filter.value.max
418
- });
419
- return conditions;
420
- }
421
- let mappedOp = filter.operator ?? '=';
422
- if (Array.isArray(filter.value)) {
423
- if ('=' === mappedOp) mappedOp = 'in';
424
- if ('!=' === mappedOp) mappedOp = 'not in';
425
- }
426
- return [
427
- {
428
- field: filter.field,
429
- op: mappedOp,
430
- value: filter.value
431
- }
432
- ];
433
- })
434
- };
435
- return result;
436
- };
437
- const buildOrderBy = (queryDSL, context)=>queryDSL;
438
572
  const buildSelect = (queryDSL, context)=>{
439
573
  const { vbiDSL } = context;
440
574
  const measures = vbiDSL.measures;
@@ -466,14 +600,68 @@ const buildGroupBy = (queryDSL, context)=>{
466
600
  result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
467
601
  return result;
468
602
  };
469
- const buildLimit = (queryDSL, context)=>{
603
+ const buildWhere = (queryDSL, context)=>{
604
+ const { vbiDSL } = context;
605
+ const whereFilters = vbiDSL.whereFilters || [];
606
+ if (0 === whereFilters.length) return queryDSL;
470
607
  const result = {
471
608
  ...queryDSL
472
609
  };
473
- const limit = context.vbiDSL.limit ?? 1000;
474
- result.limit = limit;
610
+ result.where = {
611
+ op: 'and',
612
+ conditions: whereFilters.flatMap(mapClauseToCondition)
613
+ };
475
614
  return result;
476
615
  };
616
+ function isWhereGroup(clause) {
617
+ return 'op' in clause && 'conditions' in clause;
618
+ }
619
+ function mapClauseToCondition(clause) {
620
+ if (isWhereGroup(clause)) return [
621
+ mapGroupToCondition(clause)
622
+ ];
623
+ return mapFilterToCondition(clause);
624
+ }
625
+ function mapGroupToCondition(group) {
626
+ return {
627
+ op: group.op,
628
+ conditions: group.conditions.flatMap(mapClauseToCondition)
629
+ };
630
+ }
631
+ function mapFilterToCondition(filter) {
632
+ if ('between' === filter.op) return handleBetweenFilter(filter);
633
+ return handleSimpleFilter(filter);
634
+ }
635
+ function handleBetweenFilter(filter) {
636
+ const conditions = [];
637
+ const value = filter.value;
638
+ if (void 0 !== value.min && null !== value.min && '' !== value.min) conditions.push({
639
+ field: filter.field,
640
+ op: '<' === value.leftOp ? '>' : '>=',
641
+ value: value.min
642
+ });
643
+ if (void 0 !== value.max && null !== value.max && '' !== value.max) conditions.push({
644
+ field: filter.field,
645
+ op: '<' === value.rightOp ? '<' : '<=',
646
+ value: value.max
647
+ });
648
+ return conditions;
649
+ }
650
+ function handleSimpleFilter(filter) {
651
+ let mappedOp = filter.op ?? '=';
652
+ const value = filter.value;
653
+ if (Array.isArray(value)) {
654
+ if ('=' === mappedOp) mappedOp = 'in';
655
+ if ('!=' === mappedOp) mappedOp = 'not in';
656
+ }
657
+ return [
658
+ {
659
+ field: filter.field,
660
+ op: mappedOp,
661
+ value
662
+ }
663
+ ];
664
+ }
477
665
  const buildHaving = (queryDSL, context)=>{
478
666
  const { vbiDSL } = context;
479
667
  const havingFilters = vbiDSL.havingFilters || [];
@@ -483,17 +671,50 @@ const buildHaving = (queryDSL, context)=>{
483
671
  };
484
672
  result.having = {
485
673
  op: 'and',
486
- conditions: havingFilters.map((filter)=>{
487
- const mappedOp = filter.operator ?? '=';
488
- return {
489
- field: filter.field,
490
- op: mappedOp,
491
- value: filter.value
492
- };
493
- })
674
+ conditions: havingFilters.flatMap(buildHaving_mapClauseToCondition)
675
+ };
676
+ return result;
677
+ };
678
+ function isHavingGroup(clause) {
679
+ return 'op' in clause && 'conditions' in clause;
680
+ }
681
+ function buildHaving_mapClauseToCondition(clause) {
682
+ if (isHavingGroup(clause)) return [
683
+ buildHaving_mapGroupToCondition(clause)
684
+ ];
685
+ return buildHaving_mapFilterToCondition(clause);
686
+ }
687
+ function buildHaving_mapGroupToCondition(group) {
688
+ return {
689
+ op: group.op,
690
+ conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
691
+ };
692
+ }
693
+ function buildHaving_mapFilterToCondition(filter) {
694
+ const mappedOp = filter.op ?? '=';
695
+ return [
696
+ {
697
+ field: filter.field,
698
+ op: mappedOp,
699
+ value: filter.value
700
+ }
701
+ ];
702
+ }
703
+ const buildLimit = (queryDSL, context)=>{
704
+ const result = {
705
+ ...queryDSL
494
706
  };
707
+ const limit = context.vbiDSL.limit ?? 1000;
708
+ result.limit = limit;
495
709
  return result;
496
710
  };
711
+ const buildVQuery = (vbiDSL, builder)=>{
712
+ const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
713
+ vbiDSL,
714
+ builder
715
+ });
716
+ return pipe({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
717
+ };
497
718
  const connectorMap = new Map();
498
719
  const registerConnector = (id, connector)=>{
499
720
  connectorMap.set(id, connector);
@@ -596,7 +817,27 @@ const createVBI = ()=>({
596
817
  if (vbi.limit) dsl.set('limit', vbi.limit);
597
818
  if (vbi.locale) dsl.set('locale', vbi.locale);
598
819
  if (vbi.version) dsl.set('version', vbi.version);
599
- const ensureYArray = (arr)=>{
820
+ const toYMap = (obj, ensureId = false)=>{
821
+ const yMap = new external_yjs_Map();
822
+ if (ensureId && !obj.id) yMap.set('id', id_id.uuid());
823
+ for (const [key, value] of Object.entries(obj))if ('conditions' === key && Array.isArray(value)) {
824
+ const yArr = new external_yjs_Array();
825
+ value.forEach((child)=>{
826
+ if (child instanceof external_yjs_Map) yArr.push([
827
+ child
828
+ ]);
829
+ else if ('object' == typeof child && null !== child) yArr.push([
830
+ toYMap(child, true)
831
+ ]);
832
+ else yArr.push([
833
+ child
834
+ ]);
835
+ });
836
+ yMap.set(key, yArr);
837
+ } else yMap.set(key, value);
838
+ return yMap;
839
+ };
840
+ const ensureYArray = (arr, ensureId = false)=>{
600
841
  if (!arr) return new external_yjs_Array();
601
842
  if (arr instanceof external_yjs_Array) return arr;
602
843
  const yArr = new external_yjs_Array();
@@ -604,20 +845,17 @@ const createVBI = ()=>({
604
845
  if (item instanceof external_yjs_Map) yArr.push([
605
846
  item
606
847
  ]);
607
- else if ('object' == typeof item && null !== item) {
608
- const yMap = new external_yjs_Map();
609
- for (const [key, value] of Object.entries(item))yMap.set(key, value);
610
- yArr.push([
611
- yMap
612
- ]);
613
- } else yArr.push([
848
+ else if ('object' == typeof item && null !== item) yArr.push([
849
+ toYMap(item, ensureId)
850
+ ]);
851
+ else yArr.push([
614
852
  item
615
853
  ]);
616
854
  });
617
855
  return yArr;
618
856
  };
619
- dsl.set('whereFilters', ensureYArray(vbi.whereFilters));
620
- dsl.set('havingFilters', ensureYArray(vbi.havingFilters));
857
+ dsl.set('whereFilters', ensureYArray(vbi.whereFilters, true));
858
+ dsl.set('havingFilters', ensureYArray(vbi.havingFilters, true));
621
859
  dsl.set('measures', ensureYArray(vbi.measures));
622
860
  dsl.set('dimensions', ensureYArray(vbi.dimensions));
623
861
  });
@@ -625,4 +863,52 @@ const createVBI = ()=>({
625
863
  }
626
864
  });
627
865
  const VBI = createVBI();
628
- export { ChartTypeBuilder, DimensionsBuilder, MeasuresBuilder, VBI, VBIBuilder, buildVQuery, findTreeNodesBy, preorderTraverse, zVBIHavingArray, zVBIHavingFilter };
866
+ const zVBIFilter = z.object({
867
+ id: z.string(),
868
+ field: z.string(),
869
+ op: z.string().optional(),
870
+ value: z.any().optional()
871
+ });
872
+ const zVBIWhereGroup = z.lazy(()=>z.object({
873
+ id: z.string(),
874
+ op: z["enum"]([
875
+ 'and',
876
+ 'or'
877
+ ]),
878
+ conditions: z.array(zVBIWhereClause)
879
+ }));
880
+ const zVBIWhereClause = z.lazy(()=>z.union([
881
+ zVBIFilter,
882
+ zVBIWhereGroup
883
+ ]));
884
+ function isVBIFilter(clause) {
885
+ return 'field' in clause;
886
+ }
887
+ function isVBIWhereGroup(clause) {
888
+ return 'conditions' in clause;
889
+ }
890
+ const zVBIHavingFilter = z.object({
891
+ id: z.string(),
892
+ field: z.string(),
893
+ op: z.string().optional(),
894
+ value: z.any().optional()
895
+ });
896
+ const zVBIHavingGroup = z.lazy(()=>z.object({
897
+ id: z.string(),
898
+ op: z["enum"]([
899
+ 'and',
900
+ 'or'
901
+ ]),
902
+ conditions: z.array(zVBIHavingClause)
903
+ }));
904
+ const zVBIHavingClause = z.lazy(()=>z.union([
905
+ zVBIHavingFilter,
906
+ zVBIHavingGroup
907
+ ]));
908
+ function isVBIHavingFilter(clause) {
909
+ return 'field' in clause;
910
+ }
911
+ function isVBIHavingGroup(clause) {
912
+ return 'conditions' in clause;
913
+ }
914
+ export { ChartTypeBuilder, DimensionsBuilder, MeasuresBuilder, VBI, VBIBuilder, buildVQuery, findTreeNodesBy, id_id as id, isVBIFilter, isVBIHavingFilter, isVBIHavingGroup, isVBIWhereGroup, preorderTraverse };
@@ -1 +1 @@
1
- export { buildVQuery } from './vqueryDSL';
1
+ export { buildVQuery } from './vqueryDSL/index';
@@ -0,0 +1,2 @@
1
+ import type { buildPipe } from './types';
2
+ export declare const buildGroupBy: buildPipe;