@visactor/vbi 0.4.16 → 0.4.19

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 (50) hide show
  1. package/dist/builder/adapters/index.d.ts +1 -0
  2. package/dist/builder/adapters/vquery-vseed/build-vquery.d.ts +3 -0
  3. package/dist/builder/adapters/vquery-vseed/build-vseed.d.ts +3 -0
  4. package/dist/builder/adapters/vquery-vseed/index.d.ts +7 -0
  5. package/dist/builder/adapters/vquery-vseed/types.d.ts +4 -0
  6. package/dist/builder/builder.d.ts +29 -0
  7. package/dist/builder/features/dimensions/dim-builder.d.ts +10 -10
  8. package/dist/builder/features/dimensions/dim-node-builder.d.ts +4 -0
  9. package/dist/builder/features/dimensions/dimension-utils.d.ts +4 -0
  10. package/dist/builder/features/havingFilter/having-builder.d.ts +3 -3
  11. package/dist/builder/features/havingFilter/having-node-builder.d.ts +10 -1
  12. package/dist/builder/features/measures/mea-builder.d.ts +9 -9
  13. package/dist/builder/features/measures/mea-node-builder.d.ts +4 -0
  14. package/dist/builder/features/measures/measure-utils.d.ts +4 -0
  15. package/dist/builder/features/whereFilter/where-builder.d.ts +3 -3
  16. package/dist/builder/index.d.ts +3 -2
  17. package/dist/builder/modules/apply-update.d.ts +2 -0
  18. package/dist/builder/modules/build.d.ts +3 -0
  19. package/dist/builder/modules/encode-state-as-update.d.ts +2 -0
  20. package/dist/builder/modules/get-schema.d.ts +5 -0
  21. package/dist/builder/modules/index.d.ts +5 -0
  22. package/dist/builder/modules/is-empty.d.ts +2 -0
  23. package/dist/index.cjs +617 -399
  24. package/dist/index.d.ts +7 -3
  25. package/dist/index.js +605 -396
  26. package/dist/pipeline/vqueryDSL/aggregateMap.d.ts +30 -0
  27. package/dist/pipeline/vqueryDSL/index.d.ts +2 -3
  28. package/dist/pipeline/vqueryDSL/types.d.ts +2 -3
  29. package/dist/types/builder/VBIInterface.d.ts +5 -5
  30. package/dist/types/builder/adapter.d.ts +21 -0
  31. package/dist/types/builder/index.d.ts +1 -0
  32. package/dist/types/dsl/dimensions/dimensions.d.ts +2 -0
  33. package/dist/types/dsl/havingFilter/having.d.ts +19 -0
  34. package/dist/types/dsl/index.d.ts +1 -1
  35. package/dist/types/dsl/measures/aggregate.d.ts +14 -2
  36. package/dist/types/dsl/measures/measures.d.ts +28 -4
  37. package/dist/types/dsl/vbi/vbi.d.ts +15 -2
  38. package/dist/vbi/create-vbi.d.ts +15 -0
  39. package/dist/vbi/from/from-vbi-dsl-input.d.ts +4 -0
  40. package/dist/vbi/from/set-base-dsl-fields.d.ts +3 -0
  41. package/dist/vbi/generate-empty-dsl.d.ts +3 -0
  42. package/dist/vbi/normalize/ensure-having-group.d.ts +2 -0
  43. package/dist/vbi/normalize/ensure-where-group.d.ts +2 -0
  44. package/dist/vbi/normalize/ensure-y-array.d.ts +3 -0
  45. package/dist/vbi/normalize/to-y-map.d.ts +3 -0
  46. package/dist/vbi/normalize/types.d.ts +5 -0
  47. package/dist/vbi.d.ts +1 -0
  48. package/package.json +5 -5
  49. package/dist/builder/vbi-builder.d.ts +0 -28
  50. package/dist/builder/vbi.d.ts +0 -16
package/dist/index.js CHANGED
@@ -1,12 +1,269 @@
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 VBI_TO_VQUERY_AGGR_FUNC_MAP = {
16
+ count: 'count',
17
+ countDistinct: 'count_distinct',
18
+ sum: 'sum',
19
+ avg: 'avg',
20
+ min: 'min',
21
+ max: 'max',
22
+ variance: 'variance',
23
+ variancePop: 'variance_pop',
24
+ stddev: 'stddev',
25
+ median: 'median',
26
+ quantile: 'quantile'
27
+ };
28
+ const mapAggregateForVQuery = (aggregate)=>{
29
+ if (!aggregate) return aggregate;
30
+ const mappedFunc = VBI_TO_VQUERY_AGGR_FUNC_MAP[aggregate.func] ?? aggregate.func;
31
+ return {
32
+ ...aggregate,
33
+ func: mappedFunc
34
+ };
35
+ };
36
+ const buildSelect = (queryDSL, context)=>{
37
+ const { vbiDSL } = context;
38
+ const measures = vbiDSL.measures;
39
+ const dimensions = vbiDSL.dimensions;
40
+ const result = {
41
+ ...queryDSL
42
+ };
43
+ const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
44
+ const measureSelects = measureNodes.map((measure)=>({
45
+ field: measure.field,
46
+ alias: measure.alias,
47
+ aggr: mapAggregateForVQuery(measure.aggregate)
48
+ }));
49
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
50
+ const dimensionSelects = dimensionNodes.map((dimension)=>({
51
+ field: dimension.field,
52
+ alias: dimension.alias
53
+ }));
54
+ result.select = [
55
+ ...measureSelects,
56
+ ...dimensionSelects
57
+ ];
58
+ return result;
59
+ };
60
+ const buildGroupBy = (queryDSL, context)=>{
61
+ const result = {
62
+ ...queryDSL
63
+ };
64
+ const { vbiDSL } = context;
65
+ const dimensions = vbiDSL.dimensions;
66
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
67
+ result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
68
+ return result;
69
+ };
70
+ const buildWhere = (queryDSL, context)=>{
71
+ const { vbiDSL } = context;
72
+ const whereFilter = vbiDSL.whereFilter;
73
+ if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
74
+ const result = {
75
+ ...queryDSL
76
+ };
77
+ result.where = mapGroupToCondition(whereFilter);
78
+ return result;
79
+ };
80
+ function isWhereGroup(clause) {
81
+ return 'op' in clause && 'conditions' in clause;
82
+ }
83
+ function mapClauseToCondition(clause) {
84
+ if (isWhereGroup(clause)) return [
85
+ mapGroupToCondition(clause)
86
+ ];
87
+ return mapFilterToCondition(clause);
88
+ }
89
+ function mapGroupToCondition(group) {
90
+ return {
91
+ op: group.op,
92
+ conditions: group.conditions.flatMap(mapClauseToCondition)
93
+ };
94
+ }
95
+ function mapFilterToCondition(filter) {
96
+ if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
97
+ return handleSimpleFilter(filter);
98
+ }
99
+ function handleBetweenFilter(filter) {
100
+ const value = normalizeBetweenValue(filter.value);
101
+ const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
102
+ field: filter.field,
103
+ op: '<' === value.leftOp ? '>' : '>=',
104
+ value: value.min
105
+ } : void 0;
106
+ const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
107
+ field: filter.field,
108
+ op: '<' === value.rightOp ? '<' : '<=',
109
+ value: value.max
110
+ } : void 0;
111
+ if ('not between' === filter.op) {
112
+ const outsideConditions = [
113
+ lowerCondition && invertLowerBound(lowerCondition),
114
+ upperCondition && invertUpperBound(upperCondition)
115
+ ].filter(Boolean);
116
+ if (outsideConditions.length <= 1) return outsideConditions;
117
+ return [
118
+ {
119
+ op: 'or',
120
+ conditions: outsideConditions
121
+ }
122
+ ];
123
+ }
124
+ return [
125
+ lowerCondition,
126
+ upperCondition
127
+ ].filter(Boolean);
128
+ }
129
+ function normalizeBetweenValue(value) {
130
+ if (Array.isArray(value)) return {
131
+ min: value[0],
132
+ max: value[1],
133
+ leftOp: '<=',
134
+ rightOp: '<='
135
+ };
136
+ if ('object' == typeof value && null !== value) return value;
137
+ return {};
138
+ }
139
+ function invertLowerBound(condition) {
140
+ return {
141
+ field: condition.field,
142
+ op: '>' === condition.op ? '<=' : '<',
143
+ value: condition.value
144
+ };
145
+ }
146
+ function invertUpperBound(condition) {
147
+ return {
148
+ field: condition.field,
149
+ op: '<' === condition.op ? '>=' : '>',
150
+ value: condition.value
151
+ };
152
+ }
153
+ function handleSimpleFilter(filter) {
154
+ let mappedOp = filter.op ?? '=';
155
+ const value = filter.value;
156
+ if (Array.isArray(value)) {
157
+ if ('=' === mappedOp) mappedOp = 'in';
158
+ if ('!=' === mappedOp) mappedOp = 'not in';
159
+ }
160
+ return [
161
+ {
162
+ field: filter.field,
163
+ op: mappedOp,
164
+ value
165
+ }
166
+ ];
167
+ }
168
+ const DEFAULT_HAVING_AGGREGATE = {
169
+ func: 'sum'
170
+ };
171
+ const buildHaving = (queryDSL, context)=>{
172
+ const { vbiDSL } = context;
173
+ const havingFilter = vbiDSL.havingFilter;
174
+ if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
175
+ const result = {
176
+ ...queryDSL
177
+ };
178
+ result.having = {
179
+ op: havingFilter.op,
180
+ conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
181
+ };
182
+ return result;
183
+ };
184
+ function isHavingGroup(clause) {
185
+ return 'op' in clause && 'conditions' in clause;
186
+ }
187
+ function buildHaving_mapClauseToCondition(clause) {
188
+ if (isHavingGroup(clause)) return [
189
+ buildHaving_mapGroupToCondition(clause)
190
+ ];
191
+ return buildHaving_mapFilterToCondition(clause);
192
+ }
193
+ function buildHaving_mapGroupToCondition(group) {
194
+ return {
195
+ op: group.op,
196
+ conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
197
+ };
198
+ }
199
+ function buildHaving_mapFilterToCondition(filter) {
200
+ const mappedOp = normalizeOperator(filter.op, filter.value);
201
+ const aggregate = mapAggregateForVQuery(filter.aggregate ?? DEFAULT_HAVING_AGGREGATE);
202
+ return [
203
+ {
204
+ field: filter.field,
205
+ aggr: aggregate,
206
+ op: mappedOp,
207
+ value: filter.value
208
+ }
209
+ ];
210
+ }
211
+ function normalizeOperator(op, value) {
212
+ let mappedOp = op ?? '=';
213
+ if (Array.isArray(value)) {
214
+ if ('=' === mappedOp) mappedOp = 'in';
215
+ if ('!=' === mappedOp) mappedOp = 'not in';
216
+ }
217
+ return mappedOp;
218
+ }
219
+ const buildLimit = (queryDSL, context)=>{
220
+ const result = {
221
+ ...queryDSL
222
+ };
223
+ const limit = context.vbiDSL.limit ?? 1000;
224
+ result.limit = limit;
225
+ return result;
226
+ };
227
+ const buildVQuery = (vbiDSL, builder)=>{
228
+ const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
229
+ vbiDSL,
230
+ builder
231
+ });
232
+ return pipe({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
233
+ };
234
+ const buildVQueryDSL = ({ vbiDSL, builder })=>buildVQuery(vbiDSL, builder);
235
+ const buildVSeedDSL = async ({ vbiDSL, queryDSL })=>{
236
+ const connectorId = vbiDSL.connectorId;
237
+ const connector = await getConnector(connectorId);
238
+ const schema = await connector.discoverSchema();
239
+ const queryResult = await connector.query({
240
+ queryDSL,
241
+ schema,
242
+ connectorId
243
+ });
244
+ return {
245
+ chartType: vbiDSL.chartType,
246
+ dataset: queryResult.dataset,
247
+ theme: vbiDSL.theme,
248
+ locale: vbiDSL.locale
249
+ };
250
+ };
251
+ const defaultVBIBuilderAdapters = {
252
+ buildVQuery: buildVQueryDSL,
253
+ buildVSeed: buildVSeedDSL
254
+ };
255
+ const resolveVBIBuilderAdapters = (adapters)=>({
256
+ buildVQuery: adapters?.buildVQuery ?? defaultVBIBuilderAdapters.buildVQuery,
257
+ buildVSeed: adapters?.buildVSeed ?? defaultVBIBuilderAdapters.buildVSeed
258
+ });
5
259
  class MeasureNodeBuilder {
6
260
  yMap;
7
261
  constructor(yMap){
8
262
  this.yMap = yMap;
9
263
  }
264
+ getId() {
265
+ return this.yMap.get('id');
266
+ }
10
267
  getField() {
11
268
  return this.yMap.get('field');
12
269
  }
@@ -26,13 +283,46 @@ class MeasureNodeBuilder {
26
283
  return this.yMap.toJSON();
27
284
  }
28
285
  }
286
+ const id_id = {
287
+ uuid: ()=>v4()
288
+ };
289
+ function isVBIFilter(clause) {
290
+ return 'field' in clause;
291
+ }
292
+ function isVBIWhereGroup(clause) {
293
+ return 'conditions' in clause;
294
+ }
295
+ function isVBIHavingFilter(clause) {
296
+ return 'field' in clause;
297
+ }
298
+ function isVBIHavingGroup(clause) {
299
+ return 'conditions' in clause;
300
+ }
301
+ const getOrCreateMeasures = (dsl)=>{
302
+ const measures = dsl.get('measures');
303
+ if (measures instanceof external_yjs_Array) return measures;
304
+ const yMeasures = new external_yjs_Array();
305
+ dsl.set('measures', yMeasures);
306
+ return yMeasures;
307
+ };
308
+ const normalizeMeasureNodeIds = (measures)=>{
309
+ measures.toArray().forEach((item)=>{
310
+ if (item instanceof external_yjs_Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
311
+ });
312
+ };
313
+ const locateMeasureIndexById = (measures, measureId)=>measures.toArray().findIndex((item)=>item.get('id') === measureId);
29
314
  class MeasuresBuilder {
30
315
  dsl;
31
- constructor(_doc, dsl){
316
+ constructor(doc, dsl){
32
317
  this.dsl = dsl;
318
+ doc.transact(()=>{
319
+ const measures = getOrCreateMeasures(this.dsl);
320
+ normalizeMeasureNodeIds(measures);
321
+ });
33
322
  }
34
323
  add(field, callback) {
35
324
  const measure = {
325
+ id: id_id.uuid(),
36
326
  alias: field,
37
327
  field,
38
328
  encoding: 'yAxis',
@@ -42,45 +332,50 @@ class MeasuresBuilder {
42
332
  };
43
333
  const yMap = new external_yjs_Map();
44
334
  for (const [key, value] of Object.entries(measure))yMap.set(key, value);
45
- this.dsl.get('measures').push([
335
+ const measures = getOrCreateMeasures(this.dsl);
336
+ measures.push([
46
337
  yMap
47
338
  ]);
48
339
  const node = new MeasureNodeBuilder(yMap);
49
340
  callback(node);
50
341
  return this;
51
342
  }
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);
343
+ remove(id) {
344
+ const measures = getOrCreateMeasures(this.dsl);
345
+ const index = locateMeasureIndexById(measures, id);
346
+ if (-1 !== index) measures.delete(index, 1);
56
347
  return this;
57
348
  }
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`);
349
+ update(id, callback) {
350
+ const measures = getOrCreateMeasures(this.dsl);
351
+ const index = locateMeasureIndexById(measures, id);
352
+ if (-1 === index) throw new Error(`Measure with id "${id}" not found`);
62
353
  const measureYMap = measures.get(index);
63
354
  const node = new MeasureNodeBuilder(measureYMap);
64
355
  callback(node);
65
356
  return this;
66
357
  }
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));
358
+ find(predicate) {
359
+ const measures = getOrCreateMeasures(this.dsl);
360
+ const items = measures.toArray();
361
+ for(let index = 0; index < items.length; index++){
362
+ const node = new MeasureNodeBuilder(items[index]);
363
+ if (predicate(node, index)) return node;
364
+ }
72
365
  }
73
366
  findAll() {
74
- const measures = this.dsl.get('measures');
367
+ const measures = getOrCreateMeasures(this.dsl);
75
368
  return measures.toArray().map((yMap)=>new MeasureNodeBuilder(yMap));
76
369
  }
77
370
  toJSON() {
78
- return this.dsl.get('measures').toJSON();
371
+ const measures = getOrCreateMeasures(this.dsl);
372
+ return measures.toJSON();
79
373
  }
80
374
  observe(callback) {
81
- this.dsl.get('measures').observe(callback);
375
+ const measures = getOrCreateMeasures(this.dsl);
376
+ measures.observe(callback);
82
377
  return ()=>{
83
- this.dsl.get('measures').unobserve(callback);
378
+ measures.unobserve(callback);
84
379
  };
85
380
  }
86
381
  static isMeasureNode(node) {
@@ -95,6 +390,9 @@ class DimensionNodeBuilder {
95
390
  constructor(yMap){
96
391
  this.yMap = yMap;
97
392
  }
393
+ getId() {
394
+ return this.yMap.get('id');
395
+ }
98
396
  getField() {
99
397
  return this.yMap.get('field');
100
398
  }
@@ -106,57 +404,80 @@ class DimensionNodeBuilder {
106
404
  return this.yMap.toJSON();
107
405
  }
108
406
  }
407
+ const getOrCreateDimensions = (dsl)=>{
408
+ const dimensions = dsl.get('dimensions');
409
+ if (dimensions instanceof external_yjs_Array) return dimensions;
410
+ const yDimensions = new external_yjs_Array();
411
+ dsl.set('dimensions', yDimensions);
412
+ return yDimensions;
413
+ };
414
+ const normalizeDimensionNodeIds = (dimensions)=>{
415
+ dimensions.toArray().forEach((item)=>{
416
+ if (item instanceof external_yjs_Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
417
+ });
418
+ };
419
+ const locateDimensionIndexById = (dimensions, dimensionId)=>dimensions.toArray().findIndex((item)=>item.get('id') === dimensionId);
109
420
  class DimensionsBuilder {
110
421
  dsl;
111
- constructor(_doc, dsl){
422
+ constructor(doc, dsl){
112
423
  this.dsl = dsl;
424
+ doc.transact(()=>{
425
+ const dimensions = getOrCreateDimensions(this.dsl);
426
+ normalizeDimensionNodeIds(dimensions);
427
+ });
113
428
  }
114
429
  add(field, callback) {
115
430
  const dimension = {
431
+ id: id_id.uuid(),
116
432
  alias: field,
117
433
  field
118
434
  };
119
435
  const yMap = new external_yjs_Map();
120
436
  for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
121
- this.dsl.get('dimensions').push([
437
+ const dimensions = getOrCreateDimensions(this.dsl);
438
+ dimensions.push([
122
439
  yMap
123
440
  ]);
124
441
  const node = new DimensionNodeBuilder(yMap);
125
442
  callback(node);
126
443
  return this;
127
444
  }
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);
445
+ remove(id) {
446
+ const dimensions = getOrCreateDimensions(this.dsl);
447
+ const index = locateDimensionIndexById(dimensions, id);
448
+ if (-1 !== index) dimensions.delete(index, 1);
132
449
  return this;
133
450
  }
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`);
451
+ update(id, callback) {
452
+ const dimensions = getOrCreateDimensions(this.dsl);
453
+ const index = locateDimensionIndexById(dimensions, id);
454
+ if (-1 === index) throw new Error(`Dimension with id "${id}" not found`);
138
455
  const dimensionYMap = dimensions.get(index);
139
456
  const node = new DimensionNodeBuilder(dimensionYMap);
140
457
  callback(node);
141
458
  return this;
142
459
  }
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));
460
+ find(predicate) {
461
+ const dimensions = getOrCreateDimensions(this.dsl);
462
+ const items = dimensions.toArray();
463
+ for(let index = 0; index < items.length; index++){
464
+ const node = new DimensionNodeBuilder(items[index]);
465
+ if (predicate(node, index)) return node;
466
+ }
148
467
  }
149
468
  findAll() {
150
- const dimensions = this.dsl.get('dimensions');
469
+ const dimensions = getOrCreateDimensions(this.dsl);
151
470
  return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
152
471
  }
153
472
  toJSON() {
154
- return this.dsl.get('dimensions').toJSON();
473
+ const dimensions = getOrCreateDimensions(this.dsl);
474
+ return dimensions.toJSON();
155
475
  }
156
476
  observe(callback) {
157
- this.dsl.get('dimensions').observe(callback);
477
+ const dimensions = getOrCreateDimensions(this.dsl);
478
+ dimensions.observe(callback);
158
479
  return ()=>{
159
- this.dsl.get('dimensions').unobserve(callback);
480
+ dimensions.unobserve(callback);
160
481
  };
161
482
  }
162
483
  static isDimensionNode(node) {
@@ -215,21 +536,6 @@ class ChartTypeBuilder {
215
536
  ];
216
537
  }
217
538
  }
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
539
  function createWhereGroup(op = 'and', groupId = 'root') {
234
540
  const yMap = new external_yjs_Map();
235
541
  yMap.set('id', groupId);
@@ -237,7 +543,7 @@ function createWhereGroup(op = 'and', groupId = 'root') {
237
543
  yMap.set('conditions', new external_yjs_Array());
238
544
  return yMap;
239
545
  }
240
- function isWhereGroup(yMap) {
546
+ function where_utils_isWhereGroup(yMap) {
241
547
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
242
548
  }
243
549
  function findEntry(collection, entryId) {
@@ -249,7 +555,7 @@ function findEntry(collection, entryId) {
249
555
  index,
250
556
  item
251
557
  };
252
- if (isWhereGroup(item)) {
558
+ if (where_utils_isWhereGroup(item)) {
253
559
  const nestedCollection = item.get('conditions');
254
560
  const nestedMatch = findEntry(nestedCollection, entryId);
255
561
  if (nestedMatch) return nestedMatch;
@@ -411,13 +717,21 @@ class WhereFilterBuilder {
411
717
  }
412
718
  return this;
413
719
  }
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);
720
+ find(predicate) {
721
+ const traverse = (collection)=>{
722
+ const items = collection.toArray();
723
+ for(let index = 0; index < items.length; index++){
724
+ const yMap = items[index];
725
+ const entry = WhereFilterBuilder.isGroup(yMap) ? new WhereGroupBuilder(yMap) : new WhereFilterNodeBuilder(yMap);
726
+ if (predicate(entry, index)) return entry;
727
+ if (WhereFilterBuilder.isGroup(yMap)) {
728
+ const nestedCollection = yMap.get('conditions');
729
+ const nestedMatch = traverse(nestedCollection);
730
+ if (nestedMatch) return nestedMatch;
731
+ }
732
+ }
733
+ };
734
+ return traverse(this.getConditions());
421
735
  }
422
736
  clear() {
423
737
  const conditions = this.getConditions();
@@ -434,7 +748,7 @@ class WhereFilterBuilder {
434
748
  };
435
749
  }
436
750
  static isGroup(yMap) {
437
- return isWhereGroup(yMap);
751
+ return where_utils_isWhereGroup(yMap);
438
752
  }
439
753
  static isNode(yMap) {
440
754
  return void 0 !== yMap.get('field');
@@ -447,7 +761,7 @@ function createHavingGroup(op = 'and', groupId = 'root') {
447
761
  yMap.set('conditions', new external_yjs_Array());
448
762
  return yMap;
449
763
  }
450
- function isHavingGroup(yMap) {
764
+ function having_utils_isHavingGroup(yMap) {
451
765
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
452
766
  }
453
767
  function having_utils_findEntry(collection, entryId) {
@@ -459,7 +773,7 @@ function having_utils_findEntry(collection, entryId) {
459
773
  index,
460
774
  item
461
775
  };
462
- if (isHavingGroup(item)) {
776
+ if (having_utils_isHavingGroup(item)) {
463
777
  const nestedCollection = item.get('conditions');
464
778
  const nestedMatch = having_utils_findEntry(nestedCollection, entryId);
465
779
  if (nestedMatch) return nestedMatch;
@@ -480,6 +794,9 @@ class HavingFilterNodeBuilder {
480
794
  getOperator() {
481
795
  return this.yMap.get('op');
482
796
  }
797
+ getAggregate() {
798
+ return this.yMap.get('aggregate');
799
+ }
483
800
  setValue(value) {
484
801
  this.yMap.set('value', value);
485
802
  return this;
@@ -488,6 +805,10 @@ class HavingFilterNodeBuilder {
488
805
  this.yMap.set('op', operator);
489
806
  return this;
490
807
  }
808
+ setAggregate(aggregate) {
809
+ this.yMap.set('aggregate', aggregate);
810
+ return this;
811
+ }
491
812
  toJSON() {
492
813
  return this.yMap.toJSON();
493
814
  }
@@ -514,6 +835,9 @@ class HavingGroupBuilder {
514
835
  const yMap = new external_yjs_Map();
515
836
  yMap.set('id', id_id.uuid());
516
837
  yMap.set('field', field);
838
+ yMap.set('aggregate', {
839
+ func: 'sum'
840
+ });
517
841
  this.getConditions().push([
518
842
  yMap
519
843
  ]);
@@ -571,6 +895,9 @@ class HavingFilterBuilder {
571
895
  const yMap = new external_yjs_Map();
572
896
  yMap.set('id', id_id.uuid());
573
897
  yMap.set('field', field);
898
+ yMap.set('aggregate', {
899
+ func: 'sum'
900
+ });
574
901
  this.getConditions().push([
575
902
  yMap
576
903
  ]);
@@ -617,13 +944,21 @@ class HavingFilterBuilder {
617
944
  }
618
945
  return this;
619
946
  }
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);
947
+ find(predicate) {
948
+ const traverse = (collection)=>{
949
+ const items = collection.toArray();
950
+ for(let index = 0; index < items.length; index++){
951
+ const yMap = items[index];
952
+ const entry = HavingFilterBuilder.isGroup(yMap) ? new HavingGroupBuilder(yMap) : new HavingFilterNodeBuilder(yMap);
953
+ if (predicate(entry, index)) return entry;
954
+ if (HavingFilterBuilder.isGroup(yMap)) {
955
+ const nestedCollection = yMap.get('conditions');
956
+ const nestedMatch = traverse(nestedCollection);
957
+ if (nestedMatch) return nestedMatch;
958
+ }
959
+ }
960
+ };
961
+ return traverse(this.getConditions());
627
962
  }
628
963
  clear() {
629
964
  const conditions = this.getConditions();
@@ -640,7 +975,7 @@ class HavingFilterBuilder {
640
975
  };
641
976
  }
642
977
  static isGroup(yMap) {
643
- return isHavingGroup(yMap);
978
+ return having_utils_isHavingGroup(yMap);
644
979
  }
645
980
  static isNode(yMap) {
646
981
  return void 0 !== yMap.get('field');
@@ -739,202 +1074,30 @@ class undo_manager_UndoManager {
739
1074
  this.manager.clear(clearUndoStack, clearRedoStack);
740
1075
  }
741
1076
  }
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;
1077
+ const applyUpdateToDoc = (doc, update, transactionOrigin)=>{
1078
+ applyUpdate(doc, update, transactionOrigin);
916
1079
  };
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));
1080
+ const encodeDocStateAsUpdate = (doc, targetStateVector)=>encodeStateAsUpdate(doc, targetStateVector);
1081
+ const buildVBIDSL = (dsl)=>dsl.toJSON();
1082
+ const getCollectionLength = (value)=>{
1083
+ if (value instanceof external_yjs_Array) return value.length;
1084
+ if (Array.isArray(value)) return value.length;
1085
+ return 0;
923
1086
  };
924
- const connectorMap = new Map();
925
- const registerConnector = (id, connector)=>{
926
- connectorMap.set(id, connector);
1087
+ const isEmptyVBIDSL = (dsl)=>{
1088
+ const dimensionsLength = getCollectionLength(dsl.get('dimensions'));
1089
+ const measuresLength = getCollectionLength(dsl.get('measures'));
1090
+ return 0 === dimensionsLength && 0 === measuresLength;
927
1091
  };
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;
1092
+ const getBuilderSchema = async (dsl)=>{
1093
+ const connectorId = dsl.get('connectorId');
1094
+ const connector = await getConnector(connectorId);
1095
+ return connector.discoverSchema();
933
1096
  };
934
1097
  class VBIBuilder {
935
1098
  doc;
936
1099
  dsl;
937
- undoManager;
1100
+ adapters;
938
1101
  chartType;
939
1102
  measures;
940
1103
  dimensions;
@@ -943,9 +1106,11 @@ class VBIBuilder {
943
1106
  theme;
944
1107
  locale;
945
1108
  limit;
946
- constructor(doc){
1109
+ undoManager;
1110
+ constructor(doc, options){
947
1111
  this.doc = doc;
948
1112
  this.dsl = doc.getMap('dsl');
1113
+ this.adapters = resolveVBIBuilderAdapters(options?.adapters);
949
1114
  this.undoManager = new undo_manager_UndoManager(this.dsl);
950
1115
  this.chartType = new ChartTypeBuilder(doc, this.dsl);
951
1116
  this.measures = new MeasuresBuilder(doc, this.dsl);
@@ -956,149 +1121,193 @@ class VBIBuilder {
956
1121
  this.locale = new LocaleBuilder(doc, this.dsl);
957
1122
  this.limit = new LimitBuilder(doc, this.dsl);
958
1123
  }
959
- applyUpdate(update) {
960
- applyUpdate(this.doc, update);
961
- }
962
- encodeStateAsUpdate(targetStateVector) {
963
- return encodeStateAsUpdate(this.doc, targetStateVector);
964
- }
1124
+ applyUpdate = (update, transactionOrigin)=>applyUpdateToDoc(this.doc, update, transactionOrigin);
1125
+ encodeStateAsUpdate = (targetStateVector)=>encodeDocStateAsUpdate(this.doc, targetStateVector);
965
1126
  buildVSeed = async ()=>{
966
1127
  const vbiDSL = this.build();
967
- const connectorId = vbiDSL.connectorId;
968
- const connector = await getConnector(vbiDSL.connectorId);
969
- const queryDSL = this.buildVQuery();
970
- const schema = await connector.discoverSchema();
971
- const queryResult = await connector.query({
1128
+ const queryDSL = this.adapters.buildVQuery({
1129
+ dsl: this.dsl,
1130
+ vbiDSL,
1131
+ builder: this
1132
+ });
1133
+ return this.adapters.buildVSeed({
1134
+ dsl: this.dsl,
1135
+ vbiDSL,
972
1136
  queryDSL,
973
- schema,
974
- connectorId
1137
+ builder: this
975
1138
  });
976
- return {
977
- chartType: vbiDSL.chartType,
978
- dataset: queryResult.dataset,
979
- theme: vbiDSL.theme,
980
- locale: vbiDSL.locale
981
- };
982
1139
  };
983
1140
  buildVQuery = ()=>{
984
1141
  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;
1142
+ return this.adapters.buildVQuery({
1143
+ dsl: this.dsl,
1144
+ vbiDSL,
1145
+ builder: this
1146
+ });
993
1147
  };
1148
+ build = ()=>buildVBIDSL(this.dsl);
1149
+ isEmpty = ()=>isEmptyVBIDSL(this.dsl);
1150
+ getSchema = async ()=>getBuilderSchema(this.dsl);
994
1151
  }
995
- const createVBI = ()=>({
996
- connectorMap: connectorMap,
997
- registerConnector: registerConnector,
998
- 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));
1152
+ const shouldEnsureIdForObject = (obj, ensureId)=>{
1153
+ if (true === ensureId) return true;
1154
+ if ('field' === ensureId) return 'string' == typeof obj.field;
1155
+ return false;
1156
+ };
1157
+ const toYMap = (obj, ensureId = false)=>{
1158
+ const yMap = new external_yjs_Map();
1159
+ if (shouldEnsureIdForObject(obj, ensureId) && !obj.id) yMap.set('id', id_id.uuid());
1160
+ for (const [key, value] of Object.entries(obj)){
1161
+ if (('conditions' === key || 'children' === key) && Array.isArray(value)) {
1162
+ const yArr = new external_yjs_Array();
1163
+ for (const child of value){
1164
+ if (child instanceof external_yjs_Map) {
1165
+ yArr.push([
1166
+ child
1167
+ ]);
1168
+ continue;
1079
1169
  }
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));
1170
+ if ('object' == typeof child && null !== child) {
1171
+ yArr.push([
1172
+ toYMap(child, ensureId)
1173
+ ]);
1174
+ continue;
1095
1175
  }
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);
1176
+ yArr.push([
1177
+ child
1178
+ ]);
1179
+ }
1180
+ yMap.set(key, yArr);
1181
+ continue;
1182
+ }
1183
+ yMap.set(key, value);
1184
+ }
1185
+ return yMap;
1186
+ };
1187
+ const ensureYArray = (arr, ensureId = false)=>{
1188
+ if (!arr) return new external_yjs_Array();
1189
+ if (arr instanceof external_yjs_Array) return arr;
1190
+ const yArr = new external_yjs_Array();
1191
+ for (const item of arr){
1192
+ if (item instanceof external_yjs_Map) {
1193
+ yArr.push([
1194
+ item
1195
+ ]);
1196
+ continue;
1197
+ }
1198
+ if ('object' == typeof item && null !== item) {
1199
+ yArr.push([
1200
+ toYMap(item, ensureId)
1201
+ ]);
1202
+ continue;
1101
1203
  }
1204
+ yArr.push([
1205
+ item
1206
+ ]);
1207
+ }
1208
+ return yArr;
1209
+ };
1210
+ const getDefaultWhereFilter = ()=>({
1211
+ id: 'root',
1212
+ op: 'and',
1213
+ conditions: []
1214
+ });
1215
+ const isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1216
+ const ensureWhereGroup = (whereFilter)=>{
1217
+ const sourceWhereFilter = whereFilter instanceof external_yjs_Map || isFilterGroupInput(whereFilter) ? whereFilter : getDefaultWhereFilter();
1218
+ const whereGroup = sourceWhereFilter instanceof external_yjs_Map ? sourceWhereFilter : createWhereGroup();
1219
+ if (sourceWhereFilter instanceof external_yjs_Map) {
1220
+ if (!(whereGroup.get('conditions') instanceof external_yjs_Array)) whereGroup.set('conditions', new external_yjs_Array());
1221
+ if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1222
+ if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1223
+ return whereGroup;
1224
+ }
1225
+ whereGroup.set('id', sourceWhereFilter.id ?? 'root');
1226
+ whereGroup.set('op', sourceWhereFilter.op ?? 'and');
1227
+ whereGroup.set('conditions', ensureYArray(sourceWhereFilter.conditions, true));
1228
+ return whereGroup;
1229
+ };
1230
+ const getDefaultHavingFilter = ()=>({
1231
+ id: 'root',
1232
+ op: 'and',
1233
+ conditions: []
1102
1234
  });
1235
+ const ensure_having_group_isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1236
+ const ensureHavingGroup = (havingFilter)=>{
1237
+ const sourceHavingFilter = havingFilter instanceof external_yjs_Map || ensure_having_group_isFilterGroupInput(havingFilter) ? havingFilter : getDefaultHavingFilter();
1238
+ const havingGroup = sourceHavingFilter instanceof external_yjs_Map ? sourceHavingFilter : createHavingGroup();
1239
+ if (sourceHavingFilter instanceof external_yjs_Map) {
1240
+ if (!(havingGroup.get('conditions') instanceof external_yjs_Array)) havingGroup.set('conditions', new external_yjs_Array());
1241
+ if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1242
+ if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1243
+ return havingGroup;
1244
+ }
1245
+ havingGroup.set('id', sourceHavingFilter.id ?? 'root');
1246
+ havingGroup.set('op', sourceHavingFilter.op ?? 'and');
1247
+ havingGroup.set('conditions', ensureYArray(sourceHavingFilter.conditions, true));
1248
+ return havingGroup;
1249
+ };
1250
+ const setBaseDSLFields = (dsl, vbi)=>{
1251
+ if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
1252
+ if (vbi.chartType) dsl.set('chartType', vbi.chartType);
1253
+ if (vbi.theme) dsl.set('theme', vbi.theme);
1254
+ if (vbi.limit) dsl.set('limit', vbi.limit);
1255
+ if (vbi.locale) dsl.set('locale', vbi.locale);
1256
+ if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1257
+ };
1258
+ const fromVBIDSLInput = (vbi, options)=>{
1259
+ const doc = new Doc();
1260
+ const dsl = doc.getMap('dsl');
1261
+ doc.transact(()=>{
1262
+ setBaseDSLFields(dsl, vbi);
1263
+ dsl.set('whereFilter', ensureWhereGroup(vbi.whereFilter));
1264
+ dsl.set('havingFilter', ensureHavingGroup(vbi.havingFilter));
1265
+ dsl.set('measures', ensureYArray(vbi.measures, 'field'));
1266
+ dsl.set('dimensions', ensureYArray(vbi.dimensions, 'field'));
1267
+ });
1268
+ return new VBIBuilder(doc, options);
1269
+ };
1270
+ const generateEmptyDSL = (connectorId)=>({
1271
+ connectorId,
1272
+ chartType: 'table',
1273
+ measures: [],
1274
+ dimensions: [],
1275
+ whereFilter: {
1276
+ id: 'root',
1277
+ op: 'and',
1278
+ conditions: []
1279
+ },
1280
+ havingFilter: {
1281
+ id: 'root',
1282
+ op: 'and',
1283
+ conditions: []
1284
+ },
1285
+ theme: 'light',
1286
+ locale: 'zh-CN',
1287
+ version: 0
1288
+ });
1289
+ const mergeBuilderOptions = (base, overrides)=>{
1290
+ if (!base) return overrides;
1291
+ if (!overrides) return base;
1292
+ return {
1293
+ ...base,
1294
+ ...overrides,
1295
+ adapters: {
1296
+ ...base.adapters,
1297
+ ...overrides.adapters
1298
+ }
1299
+ };
1300
+ };
1301
+ function createVBI(defaultBuilderOptions) {
1302
+ const from = (vbi, builderOptions)=>fromVBIDSLInput(vbi, mergeBuilderOptions(defaultBuilderOptions, builderOptions));
1303
+ return {
1304
+ connectorMap: connectorMap,
1305
+ registerConnector: registerConnector,
1306
+ getConnector: getConnector,
1307
+ generateEmptyDSL: generateEmptyDSL,
1308
+ from,
1309
+ create: from
1310
+ };
1311
+ }
1103
1312
  const VBI = createVBI();
1104
- 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 };
1313
+ export { ChartTypeBuilder, DimensionsBuilder, HavingFilterBuilder, LimitBuilder, LocaleBuilder, MeasuresBuilder, ThemeBuilder, undo_manager_UndoManager as UndoManager, VBI, VBIBuilder, WhereFilterBuilder, buildVQuery, createVBI, defaultVBIBuilderAdapters, findTreeNodesBy, id_id as id, isVBIFilter, isVBIHavingFilter, isVBIHavingGroup, isVBIWhereGroup, preorderTraverse, resolveVBIBuilderAdapters };