@visactor/vbi 0.4.16 → 0.4.17

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 (38) hide show
  1. package/dist/builder/features/dimensions/dim-builder.d.ts +10 -10
  2. package/dist/builder/features/dimensions/dim-node-builder.d.ts +4 -0
  3. package/dist/builder/features/dimensions/dimension-utils.d.ts +4 -0
  4. package/dist/builder/features/havingFilter/having-builder.d.ts +3 -3
  5. package/dist/builder/features/measures/mea-builder.d.ts +9 -9
  6. package/dist/builder/features/measures/mea-node-builder.d.ts +4 -0
  7. package/dist/builder/features/measures/measure-utils.d.ts +4 -0
  8. package/dist/builder/features/whereFilter/where-builder.d.ts +3 -3
  9. package/dist/builder/index.d.ts +1 -1
  10. package/dist/builder/modules/apply-update.d.ts +2 -0
  11. package/dist/builder/modules/build-vquery.d.ts +4 -0
  12. package/dist/builder/modules/build-vseed.d.ts +8 -0
  13. package/dist/builder/modules/build.d.ts +3 -0
  14. package/dist/builder/modules/create-builder-features.d.ts +14 -0
  15. package/dist/builder/modules/encode-state-as-update.d.ts +2 -0
  16. package/dist/builder/modules/get-schema.d.ts +5 -0
  17. package/dist/builder/modules/index.d.ts +8 -0
  18. package/dist/builder/modules/is-empty.d.ts +2 -0
  19. package/dist/builder/vbi-builder.d.ts +7 -6
  20. package/dist/index.cjs +548 -412
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.js +546 -410
  23. package/dist/types/builder/VBIInterface.d.ts +1 -0
  24. package/dist/types/dsl/dimensions/dimensions.d.ts +2 -0
  25. package/dist/types/dsl/measures/measures.d.ts +2 -0
  26. package/dist/types/dsl/vbi/vbi.d.ts +2 -0
  27. package/dist/vbi/create-vbi.d.ts +14 -0
  28. package/dist/vbi/from/from-vbi-dsl-input.d.ts +3 -0
  29. package/dist/vbi/from/set-base-dsl-fields.d.ts +3 -0
  30. package/dist/vbi/generate-empty-dsl.d.ts +3 -0
  31. package/dist/vbi/normalize/ensure-having-group.d.ts +2 -0
  32. package/dist/vbi/normalize/ensure-where-group.d.ts +2 -0
  33. package/dist/vbi/normalize/ensure-y-array.d.ts +3 -0
  34. package/dist/vbi/normalize/to-y-map.d.ts +3 -0
  35. package/dist/vbi/normalize/types.d.ts +5 -0
  36. package/dist/vbi.d.ts +14 -0
  37. package/package.json +5 -5
  38. package/dist/builder/vbi.d.ts +0 -16
package/dist/index.js CHANGED
@@ -1,12 +1,247 @@
1
1
  import { Array as external_yjs_Array, Doc, Map as external_yjs_Map, UndoManager, applyUpdate, encodeStateAsUpdate } from "yjs";
2
+ import { pipe } from "remeda";
2
3
  import { ChartTypeEnum, findTreeNodesBy, preorderTraverse } from "@visactor/vseed";
3
4
  import { v4 } from "uuid";
4
- import { pipe } from "remeda";
5
+ const connectorMap = new Map();
6
+ const registerConnector = (id, connector)=>{
7
+ connectorMap.set(id, connector);
8
+ };
9
+ const getConnector = async (id)=>{
10
+ const connector = connectorMap.get(id);
11
+ if (!connector) throw new Error(`connector ${id} not registered`);
12
+ if ('function' == typeof connector) return connector();
13
+ return connector;
14
+ };
15
+ const applyUpdateToDoc = (doc, update, transactionOrigin)=>{
16
+ applyUpdate(doc, update, transactionOrigin);
17
+ };
18
+ const encodeDocStateAsUpdate = (doc, targetStateVector)=>encodeStateAsUpdate(doc, targetStateVector);
19
+ const buildVBIDSL = (dsl)=>dsl.toJSON();
20
+ const buildSelect = (queryDSL, context)=>{
21
+ const { vbiDSL } = context;
22
+ const measures = vbiDSL.measures;
23
+ const dimensions = vbiDSL.dimensions;
24
+ const result = {
25
+ ...queryDSL
26
+ };
27
+ const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
28
+ const measureSelects = measureNodes.map((measure)=>({
29
+ field: measure.field,
30
+ alias: measure.alias,
31
+ aggr: measure.aggregate
32
+ }));
33
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
34
+ const dimensionSelects = dimensionNodes.map((dimension)=>({
35
+ field: dimension.field,
36
+ alias: dimension.alias
37
+ }));
38
+ result.select = measureSelects.concat(dimensionSelects);
39
+ return result;
40
+ };
41
+ const buildGroupBy = (queryDSL, context)=>{
42
+ const result = {
43
+ ...queryDSL
44
+ };
45
+ const { vbiDSL } = context;
46
+ const dimensions = vbiDSL.dimensions;
47
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
48
+ result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
49
+ return result;
50
+ };
51
+ const buildWhere = (queryDSL, context)=>{
52
+ const { vbiDSL } = context;
53
+ const whereFilter = vbiDSL.whereFilter;
54
+ if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
55
+ const result = {
56
+ ...queryDSL
57
+ };
58
+ result.where = mapGroupToCondition(whereFilter);
59
+ return result;
60
+ };
61
+ function isWhereGroup(clause) {
62
+ return 'op' in clause && 'conditions' in clause;
63
+ }
64
+ function mapClauseToCondition(clause) {
65
+ if (isWhereGroup(clause)) return [
66
+ mapGroupToCondition(clause)
67
+ ];
68
+ return mapFilterToCondition(clause);
69
+ }
70
+ function mapGroupToCondition(group) {
71
+ return {
72
+ op: group.op,
73
+ conditions: group.conditions.flatMap(mapClauseToCondition)
74
+ };
75
+ }
76
+ function mapFilterToCondition(filter) {
77
+ if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
78
+ return handleSimpleFilter(filter);
79
+ }
80
+ function handleBetweenFilter(filter) {
81
+ const value = normalizeBetweenValue(filter.value);
82
+ const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
83
+ field: filter.field,
84
+ op: '<' === value.leftOp ? '>' : '>=',
85
+ value: value.min
86
+ } : void 0;
87
+ const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
88
+ field: filter.field,
89
+ op: '<' === value.rightOp ? '<' : '<=',
90
+ value: value.max
91
+ } : void 0;
92
+ if ('not between' === filter.op) {
93
+ const outsideConditions = [
94
+ lowerCondition && invertLowerBound(lowerCondition),
95
+ upperCondition && invertUpperBound(upperCondition)
96
+ ].filter(Boolean);
97
+ if (outsideConditions.length <= 1) return outsideConditions;
98
+ return [
99
+ {
100
+ op: 'or',
101
+ conditions: outsideConditions
102
+ }
103
+ ];
104
+ }
105
+ return [
106
+ lowerCondition,
107
+ upperCondition
108
+ ].filter(Boolean);
109
+ }
110
+ function normalizeBetweenValue(value) {
111
+ if (Array.isArray(value)) return {
112
+ min: value[0],
113
+ max: value[1],
114
+ leftOp: '<=',
115
+ rightOp: '<='
116
+ };
117
+ if ('object' == typeof value && null !== value) return value;
118
+ return {};
119
+ }
120
+ function invertLowerBound(condition) {
121
+ return {
122
+ field: condition.field,
123
+ op: '>' === condition.op ? '<=' : '<',
124
+ value: condition.value
125
+ };
126
+ }
127
+ function invertUpperBound(condition) {
128
+ return {
129
+ field: condition.field,
130
+ op: '<' === condition.op ? '>=' : '>',
131
+ value: condition.value
132
+ };
133
+ }
134
+ function handleSimpleFilter(filter) {
135
+ let mappedOp = filter.op ?? '=';
136
+ const value = filter.value;
137
+ if (Array.isArray(value)) {
138
+ if ('=' === mappedOp) mappedOp = 'in';
139
+ if ('!=' === mappedOp) mappedOp = 'not in';
140
+ }
141
+ return [
142
+ {
143
+ field: filter.field,
144
+ op: mappedOp,
145
+ value
146
+ }
147
+ ];
148
+ }
149
+ const buildHaving = (queryDSL, context)=>{
150
+ const { vbiDSL } = context;
151
+ const havingFilter = vbiDSL.havingFilter;
152
+ if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
153
+ const result = {
154
+ ...queryDSL
155
+ };
156
+ result.having = {
157
+ op: havingFilter.op,
158
+ conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
159
+ };
160
+ return result;
161
+ };
162
+ function isHavingGroup(clause) {
163
+ return 'op' in clause && 'conditions' in clause;
164
+ }
165
+ function buildHaving_mapClauseToCondition(clause) {
166
+ if (isHavingGroup(clause)) return [
167
+ buildHaving_mapGroupToCondition(clause)
168
+ ];
169
+ return buildHaving_mapFilterToCondition(clause);
170
+ }
171
+ function buildHaving_mapGroupToCondition(group) {
172
+ return {
173
+ op: group.op,
174
+ conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
175
+ };
176
+ }
177
+ function buildHaving_mapFilterToCondition(filter) {
178
+ const mappedOp = filter.op ?? '=';
179
+ return [
180
+ {
181
+ field: filter.field,
182
+ op: mappedOp,
183
+ value: filter.value
184
+ }
185
+ ];
186
+ }
187
+ const buildLimit = (queryDSL, context)=>{
188
+ const result = {
189
+ ...queryDSL
190
+ };
191
+ const limit = context.vbiDSL.limit ?? 1000;
192
+ result.limit = limit;
193
+ return result;
194
+ };
195
+ const buildVQuery = (vbiDSL, builder)=>{
196
+ const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
197
+ vbiDSL,
198
+ builder
199
+ });
200
+ return pipe({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
201
+ };
202
+ const buildVQueryDSL = (dsl, builder)=>{
203
+ const vbiDSL = buildVBIDSL(dsl);
204
+ return buildVQuery(vbiDSL, builder);
205
+ };
206
+ const buildVSeedDSL = async ({ vbiDSL, queryDSL })=>{
207
+ const connectorId = vbiDSL.connectorId;
208
+ const connector = await getConnector(connectorId);
209
+ const schema = await connector.discoverSchema();
210
+ const queryResult = await connector.query({
211
+ queryDSL,
212
+ schema,
213
+ connectorId
214
+ });
215
+ return {
216
+ chartType: vbiDSL.chartType,
217
+ dataset: queryResult.dataset,
218
+ theme: vbiDSL.theme,
219
+ locale: vbiDSL.locale
220
+ };
221
+ };
222
+ const getCollectionLength = (value)=>{
223
+ if (value instanceof external_yjs_Array) return value.length;
224
+ if (Array.isArray(value)) return value.length;
225
+ return 0;
226
+ };
227
+ const isEmptyVBIDSL = (dsl)=>{
228
+ const dimensionsLength = getCollectionLength(dsl.get('dimensions'));
229
+ const measuresLength = getCollectionLength(dsl.get('measures'));
230
+ return 0 === dimensionsLength && 0 === measuresLength;
231
+ };
232
+ const getBuilderSchema = async (dsl)=>{
233
+ const connectorId = dsl.get('connectorId');
234
+ const connector = await getConnector(connectorId);
235
+ return connector.discoverSchema();
236
+ };
5
237
  class MeasureNodeBuilder {
6
238
  yMap;
7
239
  constructor(yMap){
8
240
  this.yMap = yMap;
9
241
  }
242
+ getId() {
243
+ return this.yMap.get('id');
244
+ }
10
245
  getField() {
11
246
  return this.yMap.get('field');
12
247
  }
@@ -26,13 +261,46 @@ class MeasureNodeBuilder {
26
261
  return this.yMap.toJSON();
27
262
  }
28
263
  }
264
+ const id_id = {
265
+ uuid: ()=>v4()
266
+ };
267
+ function isVBIFilter(clause) {
268
+ return 'field' in clause;
269
+ }
270
+ function isVBIWhereGroup(clause) {
271
+ return 'conditions' in clause;
272
+ }
273
+ function isVBIHavingFilter(clause) {
274
+ return 'field' in clause;
275
+ }
276
+ function isVBIHavingGroup(clause) {
277
+ return 'conditions' in clause;
278
+ }
279
+ const getOrCreateMeasures = (dsl)=>{
280
+ const measures = dsl.get('measures');
281
+ if (measures instanceof external_yjs_Array) return measures;
282
+ const yMeasures = new external_yjs_Array();
283
+ dsl.set('measures', yMeasures);
284
+ return yMeasures;
285
+ };
286
+ const normalizeMeasureNodeIds = (measures)=>{
287
+ measures.toArray().forEach((item)=>{
288
+ if (item instanceof external_yjs_Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
289
+ });
290
+ };
291
+ const locateMeasureIndexById = (measures, measureId)=>measures.toArray().findIndex((item)=>item.get('id') === measureId);
29
292
  class MeasuresBuilder {
30
293
  dsl;
31
- constructor(_doc, dsl){
294
+ constructor(doc, dsl){
32
295
  this.dsl = dsl;
296
+ doc.transact(()=>{
297
+ const measures = getOrCreateMeasures(this.dsl);
298
+ normalizeMeasureNodeIds(measures);
299
+ });
33
300
  }
34
301
  add(field, callback) {
35
302
  const measure = {
303
+ id: id_id.uuid(),
36
304
  alias: field,
37
305
  field,
38
306
  encoding: 'yAxis',
@@ -42,45 +310,50 @@ class MeasuresBuilder {
42
310
  };
43
311
  const yMap = new external_yjs_Map();
44
312
  for (const [key, value] of Object.entries(measure))yMap.set(key, value);
45
- this.dsl.get('measures').push([
313
+ const measures = getOrCreateMeasures(this.dsl);
314
+ measures.push([
46
315
  yMap
47
316
  ]);
48
317
  const node = new MeasureNodeBuilder(yMap);
49
318
  callback(node);
50
319
  return this;
51
320
  }
52
- remove(field) {
53
- const measures = this.dsl.get('measures');
54
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
55
- if (-1 !== index) this.dsl.get('measures').delete(index, 1);
321
+ remove(id) {
322
+ const measures = getOrCreateMeasures(this.dsl);
323
+ const index = locateMeasureIndexById(measures, id);
324
+ if (-1 !== index) measures.delete(index, 1);
56
325
  return this;
57
326
  }
58
- update(field, callback) {
59
- const measures = this.dsl.get('measures');
60
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
61
- if (-1 === index) throw new Error(`Measure with field "${field}" not found`);
327
+ update(id, callback) {
328
+ const measures = getOrCreateMeasures(this.dsl);
329
+ const index = locateMeasureIndexById(measures, id);
330
+ if (-1 === index) throw new Error(`Measure with id "${id}" not found`);
62
331
  const measureYMap = measures.get(index);
63
332
  const node = new MeasureNodeBuilder(measureYMap);
64
333
  callback(node);
65
334
  return this;
66
335
  }
67
- find(field) {
68
- const measures = this.dsl.get('measures');
69
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
70
- if (-1 === index) return;
71
- return new MeasureNodeBuilder(measures.get(index));
336
+ find(predicate) {
337
+ const measures = getOrCreateMeasures(this.dsl);
338
+ const items = measures.toArray();
339
+ for(let index = 0; index < items.length; index++){
340
+ const node = new MeasureNodeBuilder(items[index]);
341
+ if (predicate(node, index)) return node;
342
+ }
72
343
  }
73
344
  findAll() {
74
- const measures = this.dsl.get('measures');
345
+ const measures = getOrCreateMeasures(this.dsl);
75
346
  return measures.toArray().map((yMap)=>new MeasureNodeBuilder(yMap));
76
347
  }
77
348
  toJSON() {
78
- return this.dsl.get('measures').toJSON();
349
+ const measures = getOrCreateMeasures(this.dsl);
350
+ return measures.toJSON();
79
351
  }
80
352
  observe(callback) {
81
- this.dsl.get('measures').observe(callback);
353
+ const measures = getOrCreateMeasures(this.dsl);
354
+ measures.observe(callback);
82
355
  return ()=>{
83
- this.dsl.get('measures').unobserve(callback);
356
+ measures.unobserve(callback);
84
357
  };
85
358
  }
86
359
  static isMeasureNode(node) {
@@ -95,6 +368,9 @@ class DimensionNodeBuilder {
95
368
  constructor(yMap){
96
369
  this.yMap = yMap;
97
370
  }
371
+ getId() {
372
+ return this.yMap.get('id');
373
+ }
98
374
  getField() {
99
375
  return this.yMap.get('field');
100
376
  }
@@ -106,57 +382,80 @@ class DimensionNodeBuilder {
106
382
  return this.yMap.toJSON();
107
383
  }
108
384
  }
385
+ const getOrCreateDimensions = (dsl)=>{
386
+ const dimensions = dsl.get('dimensions');
387
+ if (dimensions instanceof external_yjs_Array) return dimensions;
388
+ const yDimensions = new external_yjs_Array();
389
+ dsl.set('dimensions', yDimensions);
390
+ return yDimensions;
391
+ };
392
+ const normalizeDimensionNodeIds = (dimensions)=>{
393
+ dimensions.toArray().forEach((item)=>{
394
+ if (item instanceof external_yjs_Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
395
+ });
396
+ };
397
+ const locateDimensionIndexById = (dimensions, dimensionId)=>dimensions.toArray().findIndex((item)=>item.get('id') === dimensionId);
109
398
  class DimensionsBuilder {
110
399
  dsl;
111
- constructor(_doc, dsl){
400
+ constructor(doc, dsl){
112
401
  this.dsl = dsl;
402
+ doc.transact(()=>{
403
+ const dimensions = getOrCreateDimensions(this.dsl);
404
+ normalizeDimensionNodeIds(dimensions);
405
+ });
113
406
  }
114
407
  add(field, callback) {
115
408
  const dimension = {
409
+ id: id_id.uuid(),
116
410
  alias: field,
117
411
  field
118
412
  };
119
413
  const yMap = new external_yjs_Map();
120
414
  for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
121
- this.dsl.get('dimensions').push([
415
+ const dimensions = getOrCreateDimensions(this.dsl);
416
+ dimensions.push([
122
417
  yMap
123
418
  ]);
124
419
  const node = new DimensionNodeBuilder(yMap);
125
420
  callback(node);
126
421
  return this;
127
422
  }
128
- remove(field) {
129
- const dimensions = this.dsl.get('dimensions');
130
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
131
- if (-1 !== index) this.dsl.get('dimensions').delete(index, 1);
423
+ remove(id) {
424
+ const dimensions = getOrCreateDimensions(this.dsl);
425
+ const index = locateDimensionIndexById(dimensions, id);
426
+ if (-1 !== index) dimensions.delete(index, 1);
132
427
  return this;
133
428
  }
134
- update(field, callback) {
135
- const dimensions = this.dsl.get('dimensions');
136
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
137
- if (-1 === index) throw new Error(`Dimension with field "${field}" not found`);
429
+ update(id, callback) {
430
+ const dimensions = getOrCreateDimensions(this.dsl);
431
+ const index = locateDimensionIndexById(dimensions, id);
432
+ if (-1 === index) throw new Error(`Dimension with id "${id}" not found`);
138
433
  const dimensionYMap = dimensions.get(index);
139
434
  const node = new DimensionNodeBuilder(dimensionYMap);
140
435
  callback(node);
141
436
  return this;
142
437
  }
143
- find(field) {
144
- const dimensions = this.dsl.get('dimensions');
145
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
146
- if (-1 === index) return;
147
- return new DimensionNodeBuilder(dimensions.get(index));
438
+ find(predicate) {
439
+ const dimensions = getOrCreateDimensions(this.dsl);
440
+ const items = dimensions.toArray();
441
+ for(let index = 0; index < items.length; index++){
442
+ const node = new DimensionNodeBuilder(items[index]);
443
+ if (predicate(node, index)) return node;
444
+ }
148
445
  }
149
446
  findAll() {
150
- const dimensions = this.dsl.get('dimensions');
447
+ const dimensions = getOrCreateDimensions(this.dsl);
151
448
  return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
152
449
  }
153
450
  toJSON() {
154
- return this.dsl.get('dimensions').toJSON();
451
+ const dimensions = getOrCreateDimensions(this.dsl);
452
+ return dimensions.toJSON();
155
453
  }
156
454
  observe(callback) {
157
- this.dsl.get('dimensions').observe(callback);
455
+ const dimensions = getOrCreateDimensions(this.dsl);
456
+ dimensions.observe(callback);
158
457
  return ()=>{
159
- this.dsl.get('dimensions').unobserve(callback);
458
+ dimensions.unobserve(callback);
160
459
  };
161
460
  }
162
461
  static isDimensionNode(node) {
@@ -215,21 +514,6 @@ class ChartTypeBuilder {
215
514
  ];
216
515
  }
217
516
  }
218
- const id_id = {
219
- uuid: ()=>v4()
220
- };
221
- function isVBIFilter(clause) {
222
- return 'field' in clause;
223
- }
224
- function isVBIWhereGroup(clause) {
225
- return 'conditions' in clause;
226
- }
227
- function isVBIHavingFilter(clause) {
228
- return 'field' in clause;
229
- }
230
- function isVBIHavingGroup(clause) {
231
- return 'conditions' in clause;
232
- }
233
517
  function createWhereGroup(op = 'and', groupId = 'root') {
234
518
  const yMap = new external_yjs_Map();
235
519
  yMap.set('id', groupId);
@@ -237,7 +521,7 @@ function createWhereGroup(op = 'and', groupId = 'root') {
237
521
  yMap.set('conditions', new external_yjs_Array());
238
522
  return yMap;
239
523
  }
240
- function isWhereGroup(yMap) {
524
+ function where_utils_isWhereGroup(yMap) {
241
525
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
242
526
  }
243
527
  function findEntry(collection, entryId) {
@@ -249,7 +533,7 @@ function findEntry(collection, entryId) {
249
533
  index,
250
534
  item
251
535
  };
252
- if (isWhereGroup(item)) {
536
+ if (where_utils_isWhereGroup(item)) {
253
537
  const nestedCollection = item.get('conditions');
254
538
  const nestedMatch = findEntry(nestedCollection, entryId);
255
539
  if (nestedMatch) return nestedMatch;
@@ -411,13 +695,21 @@ class WhereFilterBuilder {
411
695
  }
412
696
  return this;
413
697
  }
414
- find(id) {
415
- const conditions = this.getConditions();
416
- const match = findEntry(conditions, id);
417
- const yMap = match?.item;
418
- if (!yMap) return;
419
- if (WhereFilterBuilder.isGroup(yMap)) return new WhereGroupBuilder(yMap);
420
- return new WhereFilterNodeBuilder(yMap);
698
+ find(predicate) {
699
+ const traverse = (collection)=>{
700
+ const items = collection.toArray();
701
+ for(let index = 0; index < items.length; index++){
702
+ const yMap = items[index];
703
+ const entry = WhereFilterBuilder.isGroup(yMap) ? new WhereGroupBuilder(yMap) : new WhereFilterNodeBuilder(yMap);
704
+ if (predicate(entry, index)) return entry;
705
+ if (WhereFilterBuilder.isGroup(yMap)) {
706
+ const nestedCollection = yMap.get('conditions');
707
+ const nestedMatch = traverse(nestedCollection);
708
+ if (nestedMatch) return nestedMatch;
709
+ }
710
+ }
711
+ };
712
+ return traverse(this.getConditions());
421
713
  }
422
714
  clear() {
423
715
  const conditions = this.getConditions();
@@ -434,7 +726,7 @@ class WhereFilterBuilder {
434
726
  };
435
727
  }
436
728
  static isGroup(yMap) {
437
- return isWhereGroup(yMap);
729
+ return where_utils_isWhereGroup(yMap);
438
730
  }
439
731
  static isNode(yMap) {
440
732
  return void 0 !== yMap.get('field');
@@ -447,7 +739,7 @@ function createHavingGroup(op = 'and', groupId = 'root') {
447
739
  yMap.set('conditions', new external_yjs_Array());
448
740
  return yMap;
449
741
  }
450
- function isHavingGroup(yMap) {
742
+ function having_utils_isHavingGroup(yMap) {
451
743
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
452
744
  }
453
745
  function having_utils_findEntry(collection, entryId) {
@@ -459,7 +751,7 @@ function having_utils_findEntry(collection, entryId) {
459
751
  index,
460
752
  item
461
753
  };
462
- if (isHavingGroup(item)) {
754
+ if (having_utils_isHavingGroup(item)) {
463
755
  const nestedCollection = item.get('conditions');
464
756
  const nestedMatch = having_utils_findEntry(nestedCollection, entryId);
465
757
  if (nestedMatch) return nestedMatch;
@@ -617,13 +909,21 @@ class HavingFilterBuilder {
617
909
  }
618
910
  return this;
619
911
  }
620
- find(id) {
621
- const conditions = this.getConditions();
622
- const match = having_utils_findEntry(conditions, id);
623
- const yMap = match?.item;
624
- if (!yMap) return;
625
- if (HavingFilterBuilder.isGroup(yMap)) return new HavingGroupBuilder(yMap);
626
- return new HavingFilterNodeBuilder(yMap);
912
+ find(predicate) {
913
+ const traverse = (collection)=>{
914
+ const items = collection.toArray();
915
+ for(let index = 0; index < items.length; index++){
916
+ const yMap = items[index];
917
+ const entry = HavingFilterBuilder.isGroup(yMap) ? new HavingGroupBuilder(yMap) : new HavingFilterNodeBuilder(yMap);
918
+ if (predicate(entry, index)) return entry;
919
+ if (HavingFilterBuilder.isGroup(yMap)) {
920
+ const nestedCollection = yMap.get('conditions');
921
+ const nestedMatch = traverse(nestedCollection);
922
+ if (nestedMatch) return nestedMatch;
923
+ }
924
+ }
925
+ };
926
+ return traverse(this.getConditions());
627
927
  }
628
928
  clear() {
629
929
  const conditions = this.getConditions();
@@ -640,7 +940,7 @@ class HavingFilterBuilder {
640
940
  };
641
941
  }
642
942
  static isGroup(yMap) {
643
- return isHavingGroup(yMap);
943
+ return having_utils_isHavingGroup(yMap);
644
944
  }
645
945
  static isNode(yMap) {
646
946
  return void 0 !== yMap.get('field');
@@ -739,202 +1039,20 @@ class undo_manager_UndoManager {
739
1039
  this.manager.clear(clearUndoStack, clearRedoStack);
740
1040
  }
741
1041
  }
742
- const buildSelect = (queryDSL, context)=>{
743
- const { vbiDSL } = context;
744
- const measures = vbiDSL.measures;
745
- const dimensions = vbiDSL.dimensions;
746
- const result = {
747
- ...queryDSL
748
- };
749
- const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
750
- const measureSelects = measureNodes.map((measure)=>({
751
- field: measure.field,
752
- alias: measure.alias,
753
- aggr: measure.aggregate
754
- }));
755
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
756
- const dimensionSelects = dimensionNodes.map((dimension)=>({
757
- field: dimension.field,
758
- alias: dimension.alias
759
- }));
760
- result.select = measureSelects.concat(dimensionSelects);
761
- return result;
762
- };
763
- const buildGroupBy = (queryDSL, context)=>{
764
- const result = {
765
- ...queryDSL
766
- };
767
- const { vbiDSL } = context;
768
- const dimensions = vbiDSL.dimensions;
769
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
770
- result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
771
- return result;
772
- };
773
- const buildWhere = (queryDSL, context)=>{
774
- const { vbiDSL } = context;
775
- const whereFilter = vbiDSL.whereFilter;
776
- if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
777
- const result = {
778
- ...queryDSL
779
- };
780
- result.where = mapGroupToCondition(whereFilter);
781
- return result;
782
- };
783
- function buildWhere_isWhereGroup(clause) {
784
- return 'op' in clause && 'conditions' in clause;
785
- }
786
- function mapClauseToCondition(clause) {
787
- if (buildWhere_isWhereGroup(clause)) return [
788
- mapGroupToCondition(clause)
789
- ];
790
- return mapFilterToCondition(clause);
791
- }
792
- function mapGroupToCondition(group) {
793
- return {
794
- op: group.op,
795
- conditions: group.conditions.flatMap(mapClauseToCondition)
796
- };
797
- }
798
- function mapFilterToCondition(filter) {
799
- if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
800
- return handleSimpleFilter(filter);
801
- }
802
- function handleBetweenFilter(filter) {
803
- const value = normalizeBetweenValue(filter.value);
804
- const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
805
- field: filter.field,
806
- op: '<' === value.leftOp ? '>' : '>=',
807
- value: value.min
808
- } : void 0;
809
- const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
810
- field: filter.field,
811
- op: '<' === value.rightOp ? '<' : '<=',
812
- value: value.max
813
- } : void 0;
814
- if ('not between' === filter.op) {
815
- const outsideConditions = [
816
- lowerCondition && invertLowerBound(lowerCondition),
817
- upperCondition && invertUpperBound(upperCondition)
818
- ].filter(Boolean);
819
- if (outsideConditions.length <= 1) return outsideConditions;
820
- return [
821
- {
822
- op: 'or',
823
- conditions: outsideConditions
824
- }
825
- ];
826
- }
827
- return [
828
- lowerCondition,
829
- upperCondition
830
- ].filter(Boolean);
831
- }
832
- function normalizeBetweenValue(value) {
833
- if (Array.isArray(value)) return {
834
- min: value[0],
835
- max: value[1],
836
- leftOp: '<=',
837
- rightOp: '<='
838
- };
839
- if ('object' == typeof value && null !== value) return value;
840
- return {};
841
- }
842
- function invertLowerBound(condition) {
843
- return {
844
- field: condition.field,
845
- op: '>' === condition.op ? '<=' : '<',
846
- value: condition.value
847
- };
848
- }
849
- function invertUpperBound(condition) {
850
- return {
851
- field: condition.field,
852
- op: '<' === condition.op ? '>=' : '>',
853
- value: condition.value
854
- };
855
- }
856
- function handleSimpleFilter(filter) {
857
- let mappedOp = filter.op ?? '=';
858
- const value = filter.value;
859
- if (Array.isArray(value)) {
860
- if ('=' === mappedOp) mappedOp = 'in';
861
- if ('!=' === mappedOp) mappedOp = 'not in';
862
- }
863
- return [
864
- {
865
- field: filter.field,
866
- op: mappedOp,
867
- value
868
- }
869
- ];
870
- }
871
- const buildHaving = (queryDSL, context)=>{
872
- const { vbiDSL } = context;
873
- const havingFilter = vbiDSL.havingFilter;
874
- if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
875
- const result = {
876
- ...queryDSL
877
- };
878
- result.having = {
879
- op: havingFilter.op,
880
- conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
881
- };
882
- return result;
883
- };
884
- function buildHaving_isHavingGroup(clause) {
885
- return 'op' in clause && 'conditions' in clause;
886
- }
887
- function buildHaving_mapClauseToCondition(clause) {
888
- if (buildHaving_isHavingGroup(clause)) return [
889
- buildHaving_mapGroupToCondition(clause)
890
- ];
891
- return buildHaving_mapFilterToCondition(clause);
892
- }
893
- function buildHaving_mapGroupToCondition(group) {
894
- return {
895
- op: group.op,
896
- conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
897
- };
898
- }
899
- function buildHaving_mapFilterToCondition(filter) {
900
- const mappedOp = filter.op ?? '=';
901
- return [
902
- {
903
- field: filter.field,
904
- op: mappedOp,
905
- value: filter.value
906
- }
907
- ];
908
- }
909
- const buildLimit = (queryDSL, context)=>{
910
- const result = {
911
- ...queryDSL
912
- };
913
- const limit = context.vbiDSL.limit ?? 1000;
914
- result.limit = limit;
915
- return result;
916
- };
917
- const buildVQuery = (vbiDSL, builder)=>{
918
- const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
919
- vbiDSL,
920
- builder
921
- });
922
- return pipe({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
923
- };
924
- const connectorMap = new Map();
925
- const registerConnector = (id, connector)=>{
926
- connectorMap.set(id, connector);
927
- };
928
- const getConnector = async (id)=>{
929
- const connector = connectorMap.get(id);
930
- if (!connector) throw new Error(`connector ${id} not registered`);
931
- if ('function' == typeof connector) return connector();
932
- return connector;
933
- };
1042
+ const createBuilderFeatures = (doc, dsl)=>({
1043
+ undoManager: new undo_manager_UndoManager(dsl),
1044
+ chartType: new ChartTypeBuilder(doc, dsl),
1045
+ measures: new MeasuresBuilder(doc, dsl),
1046
+ dimensions: new DimensionsBuilder(doc, dsl),
1047
+ havingFilter: new HavingFilterBuilder(doc, dsl),
1048
+ whereFilter: new WhereFilterBuilder(doc, dsl),
1049
+ theme: new ThemeBuilder(doc, dsl),
1050
+ locale: new LocaleBuilder(doc, dsl),
1051
+ limit: new LimitBuilder(doc, dsl)
1052
+ });
934
1053
  class VBIBuilder {
935
1054
  doc;
936
1055
  dsl;
937
- undoManager;
938
1056
  chartType;
939
1057
  measures;
940
1058
  dimensions;
@@ -943,162 +1061,180 @@ class VBIBuilder {
943
1061
  theme;
944
1062
  locale;
945
1063
  limit;
1064
+ undoManager;
946
1065
  constructor(doc){
947
1066
  this.doc = doc;
948
1067
  this.dsl = doc.getMap('dsl');
949
- this.undoManager = new undo_manager_UndoManager(this.dsl);
950
- this.chartType = new ChartTypeBuilder(doc, this.dsl);
951
- this.measures = new MeasuresBuilder(doc, this.dsl);
952
- this.dimensions = new DimensionsBuilder(doc, this.dsl);
953
- this.havingFilter = new HavingFilterBuilder(doc, this.dsl);
954
- this.whereFilter = new WhereFilterBuilder(doc, this.dsl);
955
- this.theme = new ThemeBuilder(doc, this.dsl);
956
- this.locale = new LocaleBuilder(doc, this.dsl);
957
- this.limit = new LimitBuilder(doc, this.dsl);
958
- }
959
- applyUpdate(update) {
960
- applyUpdate(this.doc, update);
961
- }
962
- encodeStateAsUpdate(targetStateVector) {
963
- return encodeStateAsUpdate(this.doc, targetStateVector);
964
- }
1068
+ const features = createBuilderFeatures(doc, this.dsl);
1069
+ this.undoManager = features.undoManager;
1070
+ this.chartType = features.chartType;
1071
+ this.measures = features.measures;
1072
+ this.dimensions = features.dimensions;
1073
+ this.havingFilter = features.havingFilter;
1074
+ this.whereFilter = features.whereFilter;
1075
+ this.theme = features.theme;
1076
+ this.locale = features.locale;
1077
+ this.limit = features.limit;
1078
+ }
1079
+ applyUpdate = (update, transactionOrigin)=>applyUpdateToDoc(this.doc, update, transactionOrigin);
1080
+ encodeStateAsUpdate = (targetStateVector)=>encodeDocStateAsUpdate(this.doc, targetStateVector);
965
1081
  buildVSeed = async ()=>{
966
1082
  const vbiDSL = this.build();
967
- const connectorId = vbiDSL.connectorId;
968
- const connector = await getConnector(vbiDSL.connectorId);
969
1083
  const queryDSL = this.buildVQuery();
970
- const schema = await connector.discoverSchema();
971
- const queryResult = await connector.query({
972
- queryDSL,
973
- schema,
974
- connectorId
1084
+ return buildVSeedDSL({
1085
+ vbiDSL,
1086
+ queryDSL
975
1087
  });
976
- return {
977
- chartType: vbiDSL.chartType,
978
- dataset: queryResult.dataset,
979
- theme: vbiDSL.theme,
980
- locale: vbiDSL.locale
981
- };
982
- };
983
- buildVQuery = ()=>{
984
- const vbiDSL = this.build();
985
- return buildVQuery(vbiDSL, this);
986
- };
987
- build = ()=>this.dsl.toJSON();
988
- getSchema = async ()=>{
989
- const connectorId = this.dsl.get('connectorId');
990
- const con = await getConnector(connectorId);
991
- const result = await con.discoverSchema();
992
- return result;
993
1088
  };
1089
+ buildVQuery = ()=>buildVQueryDSL(this.dsl, this);
1090
+ build = ()=>buildVBIDSL(this.dsl);
1091
+ isEmpty = ()=>isEmptyVBIDSL(this.dsl);
1092
+ getSchema = async ()=>getBuilderSchema(this.dsl);
994
1093
  }
1094
+ const shouldEnsureIdForObject = (obj, ensureId)=>{
1095
+ if (true === ensureId) return true;
1096
+ if ('field' === ensureId) return 'string' == typeof obj.field;
1097
+ return false;
1098
+ };
1099
+ const toYMap = (obj, ensureId = false)=>{
1100
+ const yMap = new external_yjs_Map();
1101
+ if (shouldEnsureIdForObject(obj, ensureId) && !obj.id) yMap.set('id', id_id.uuid());
1102
+ for (const [key, value] of Object.entries(obj)){
1103
+ if (('conditions' === key || 'children' === key) && Array.isArray(value)) {
1104
+ const yArr = new external_yjs_Array();
1105
+ for (const child of value){
1106
+ if (child instanceof external_yjs_Map) {
1107
+ yArr.push([
1108
+ child
1109
+ ]);
1110
+ continue;
1111
+ }
1112
+ if ('object' == typeof child && null !== child) {
1113
+ yArr.push([
1114
+ toYMap(child, ensureId)
1115
+ ]);
1116
+ continue;
1117
+ }
1118
+ yArr.push([
1119
+ child
1120
+ ]);
1121
+ }
1122
+ yMap.set(key, yArr);
1123
+ continue;
1124
+ }
1125
+ yMap.set(key, value);
1126
+ }
1127
+ return yMap;
1128
+ };
1129
+ const ensureYArray = (arr, ensureId = false)=>{
1130
+ if (!arr) return new external_yjs_Array();
1131
+ if (arr instanceof external_yjs_Array) return arr;
1132
+ const yArr = new external_yjs_Array();
1133
+ for (const item of arr){
1134
+ if (item instanceof external_yjs_Map) {
1135
+ yArr.push([
1136
+ item
1137
+ ]);
1138
+ continue;
1139
+ }
1140
+ if ('object' == typeof item && null !== item) {
1141
+ yArr.push([
1142
+ toYMap(item, ensureId)
1143
+ ]);
1144
+ continue;
1145
+ }
1146
+ yArr.push([
1147
+ item
1148
+ ]);
1149
+ }
1150
+ return yArr;
1151
+ };
1152
+ const getDefaultWhereFilter = ()=>({
1153
+ id: 'root',
1154
+ op: 'and',
1155
+ conditions: []
1156
+ });
1157
+ const isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1158
+ const ensureWhereGroup = (whereFilter)=>{
1159
+ const sourceWhereFilter = whereFilter instanceof external_yjs_Map || isFilterGroupInput(whereFilter) ? whereFilter : getDefaultWhereFilter();
1160
+ const whereGroup = sourceWhereFilter instanceof external_yjs_Map ? sourceWhereFilter : createWhereGroup();
1161
+ if (sourceWhereFilter instanceof external_yjs_Map) {
1162
+ if (!(whereGroup.get('conditions') instanceof external_yjs_Array)) whereGroup.set('conditions', new external_yjs_Array());
1163
+ if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1164
+ if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1165
+ return whereGroup;
1166
+ }
1167
+ whereGroup.set('id', sourceWhereFilter.id ?? 'root');
1168
+ whereGroup.set('op', sourceWhereFilter.op ?? 'and');
1169
+ whereGroup.set('conditions', ensureYArray(sourceWhereFilter.conditions, true));
1170
+ return whereGroup;
1171
+ };
1172
+ const getDefaultHavingFilter = ()=>({
1173
+ id: 'root',
1174
+ op: 'and',
1175
+ conditions: []
1176
+ });
1177
+ const ensure_having_group_isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1178
+ const ensureHavingGroup = (havingFilter)=>{
1179
+ const sourceHavingFilter = havingFilter instanceof external_yjs_Map || ensure_having_group_isFilterGroupInput(havingFilter) ? havingFilter : getDefaultHavingFilter();
1180
+ const havingGroup = sourceHavingFilter instanceof external_yjs_Map ? sourceHavingFilter : createHavingGroup();
1181
+ if (sourceHavingFilter instanceof external_yjs_Map) {
1182
+ if (!(havingGroup.get('conditions') instanceof external_yjs_Array)) havingGroup.set('conditions', new external_yjs_Array());
1183
+ if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1184
+ if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1185
+ return havingGroup;
1186
+ }
1187
+ havingGroup.set('id', sourceHavingFilter.id ?? 'root');
1188
+ havingGroup.set('op', sourceHavingFilter.op ?? 'and');
1189
+ havingGroup.set('conditions', ensureYArray(sourceHavingFilter.conditions, true));
1190
+ return havingGroup;
1191
+ };
1192
+ const setBaseDSLFields = (dsl, vbi)=>{
1193
+ if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
1194
+ if (vbi.chartType) dsl.set('chartType', vbi.chartType);
1195
+ if (vbi.theme) dsl.set('theme', vbi.theme);
1196
+ if (vbi.limit) dsl.set('limit', vbi.limit);
1197
+ if (vbi.locale) dsl.set('locale', vbi.locale);
1198
+ if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1199
+ };
1200
+ const fromVBIDSLInput = (vbi)=>{
1201
+ const doc = new Doc();
1202
+ const dsl = doc.getMap('dsl');
1203
+ doc.transact(()=>{
1204
+ setBaseDSLFields(dsl, vbi);
1205
+ dsl.set('whereFilter', ensureWhereGroup(vbi.whereFilter));
1206
+ dsl.set('havingFilter', ensureHavingGroup(vbi.havingFilter));
1207
+ dsl.set('measures', ensureYArray(vbi.measures, 'field'));
1208
+ dsl.set('dimensions', ensureYArray(vbi.dimensions, 'field'));
1209
+ });
1210
+ return new VBIBuilder(doc);
1211
+ };
1212
+ const generateEmptyDSL = (connectorId)=>({
1213
+ connectorId,
1214
+ chartType: 'table',
1215
+ measures: [],
1216
+ dimensions: [],
1217
+ whereFilter: {
1218
+ id: 'root',
1219
+ op: 'and',
1220
+ conditions: []
1221
+ },
1222
+ havingFilter: {
1223
+ id: 'root',
1224
+ op: 'and',
1225
+ conditions: []
1226
+ },
1227
+ theme: 'light',
1228
+ locale: 'zh-CN',
1229
+ version: 0
1230
+ });
995
1231
  const createVBI = ()=>({
996
1232
  connectorMap: connectorMap,
997
1233
  registerConnector: registerConnector,
998
1234
  getConnector: getConnector,
999
- generateEmptyDSL: (connectorId)=>({
1000
- connectorId: connectorId,
1001
- chartType: 'table',
1002
- measures: [],
1003
- dimensions: [],
1004
- whereFilter: {
1005
- id: 'root',
1006
- op: 'and',
1007
- conditions: []
1008
- },
1009
- havingFilter: {
1010
- id: 'root',
1011
- op: 'and',
1012
- conditions: []
1013
- },
1014
- theme: 'light',
1015
- locale: 'zh-CN',
1016
- version: 0
1017
- }),
1018
- from: (vbi)=>{
1019
- const doc = new Doc();
1020
- const dsl = doc.getMap('dsl');
1021
- doc.transact(()=>{
1022
- if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
1023
- if (vbi.chartType) dsl.set('chartType', vbi.chartType);
1024
- if (vbi.theme) dsl.set('theme', vbi.theme);
1025
- if (vbi.limit) dsl.set('limit', vbi.limit);
1026
- if (vbi.locale) dsl.set('locale', vbi.locale);
1027
- if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1028
- const toYMap = (obj, ensureId = false)=>{
1029
- const yMap = new external_yjs_Map();
1030
- if (ensureId && !obj.id) yMap.set('id', id_id.uuid());
1031
- for (const [key, value] of Object.entries(obj))if ('conditions' === key && Array.isArray(value)) {
1032
- const yArr = new external_yjs_Array();
1033
- value.forEach((child)=>{
1034
- if (child instanceof external_yjs_Map) yArr.push([
1035
- child
1036
- ]);
1037
- else if ('object' == typeof child && null !== child) yArr.push([
1038
- toYMap(child, true)
1039
- ]);
1040
- else yArr.push([
1041
- child
1042
- ]);
1043
- });
1044
- yMap.set(key, yArr);
1045
- } else yMap.set(key, value);
1046
- return yMap;
1047
- };
1048
- const ensureYArray = (arr, ensureId = false)=>{
1049
- if (!arr) return new external_yjs_Array();
1050
- if (arr instanceof external_yjs_Array) return arr;
1051
- const yArr = new external_yjs_Array();
1052
- arr.forEach((item)=>{
1053
- if (item instanceof external_yjs_Map) yArr.push([
1054
- item
1055
- ]);
1056
- else if ('object' == typeof item && null !== item) yArr.push([
1057
- toYMap(item, ensureId)
1058
- ]);
1059
- else yArr.push([
1060
- item
1061
- ]);
1062
- });
1063
- return yArr;
1064
- };
1065
- const whereFilter = vbi.whereFilter ?? {
1066
- id: 'root',
1067
- op: 'and',
1068
- conditions: []
1069
- };
1070
- const whereGroup = whereFilter instanceof external_yjs_Map ? whereFilter : createWhereGroup();
1071
- if (whereFilter instanceof external_yjs_Map) {
1072
- if (!(whereGroup.get('conditions') instanceof external_yjs_Array)) whereGroup.set('conditions', new external_yjs_Array());
1073
- if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1074
- if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1075
- } else {
1076
- whereGroup.set('id', whereFilter.id ?? 'root');
1077
- whereGroup.set('op', whereFilter.op ?? 'and');
1078
- whereGroup.set('conditions', ensureYArray(whereFilter.conditions, true));
1079
- }
1080
- dsl.set('whereFilter', whereGroup);
1081
- const havingFilter = vbi.havingFilter ?? {
1082
- id: 'root',
1083
- op: 'and',
1084
- conditions: []
1085
- };
1086
- const havingGroup = havingFilter instanceof external_yjs_Map ? havingFilter : createHavingGroup();
1087
- if (havingFilter instanceof external_yjs_Map) {
1088
- if (!(havingGroup.get('conditions') instanceof external_yjs_Array)) havingGroup.set('conditions', new external_yjs_Array());
1089
- if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1090
- if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1091
- } else {
1092
- havingGroup.set('id', havingFilter.id ?? 'root');
1093
- havingGroup.set('op', havingFilter.op ?? 'and');
1094
- havingGroup.set('conditions', ensureYArray(havingFilter.conditions, true));
1095
- }
1096
- dsl.set('havingFilter', havingGroup);
1097
- dsl.set('measures', ensureYArray(vbi.measures));
1098
- dsl.set('dimensions', ensureYArray(vbi.dimensions));
1099
- });
1100
- return new VBIBuilder(doc);
1101
- }
1235
+ generateEmptyDSL: generateEmptyDSL,
1236
+ from: fromVBIDSLInput,
1237
+ create: fromVBIDSLInput
1102
1238
  });
1103
1239
  const VBI = createVBI();
1104
1240
  export { ChartTypeBuilder, DimensionsBuilder, HavingFilterBuilder, LimitBuilder, LocaleBuilder, MeasuresBuilder, ThemeBuilder, undo_manager_UndoManager as UndoManager, VBI, VBIBuilder, WhereFilterBuilder, buildVQuery, findTreeNodesBy, id_id as id, isVBIFilter, isVBIHavingFilter, isVBIHavingGroup, isVBIWhereGroup, preorderTraverse };