@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.cjs CHANGED
@@ -27,12 +27,15 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  HavingFilterBuilder: ()=>HavingFilterBuilder,
28
28
  WhereFilterBuilder: ()=>WhereFilterBuilder,
29
29
  isVBIHavingGroup: ()=>isVBIHavingGroup,
30
+ resolveVBIBuilderAdapters: ()=>resolveVBIBuilderAdapters,
30
31
  VBIBuilder: ()=>VBIBuilder,
31
32
  VBI: ()=>VBI,
32
33
  isVBIHavingFilter: ()=>isVBIHavingFilter,
33
- findTreeNodesBy: ()=>vseed_namespaceObject.findTreeNodesBy,
34
34
  ThemeBuilder: ()=>ThemeBuilder,
35
+ findTreeNodesBy: ()=>vseed_namespaceObject.findTreeNodesBy,
35
36
  id: ()=>id_id,
37
+ createVBI: ()=>createVBI,
38
+ defaultVBIBuilderAdapters: ()=>defaultVBIBuilderAdapters,
36
39
  MeasuresBuilder: ()=>MeasuresBuilder,
37
40
  LimitBuilder: ()=>LimitBuilder,
38
41
  DimensionsBuilder: ()=>DimensionsBuilder,
@@ -44,12 +47,270 @@ __webpack_require__.d(__webpack_exports__, {
44
47
  LocaleBuilder: ()=>LocaleBuilder,
45
48
  UndoManager: ()=>UndoManager
46
49
  });
50
+ const connectorMap = new Map();
51
+ const registerConnector = (id, connector)=>{
52
+ connectorMap.set(id, connector);
53
+ };
54
+ const getConnector = async (id)=>{
55
+ const connector = connectorMap.get(id);
56
+ if (!connector) throw new Error(`connector ${id} not registered`);
57
+ if ('function' == typeof connector) return connector();
58
+ return connector;
59
+ };
47
60
  const external_yjs_namespaceObject = require("yjs");
61
+ const external_remeda_namespaceObject = require("remeda");
62
+ const VBI_TO_VQUERY_AGGR_FUNC_MAP = {
63
+ count: 'count',
64
+ countDistinct: 'count_distinct',
65
+ sum: 'sum',
66
+ avg: 'avg',
67
+ min: 'min',
68
+ max: 'max',
69
+ variance: 'variance',
70
+ variancePop: 'variance_pop',
71
+ stddev: 'stddev',
72
+ median: 'median',
73
+ quantile: 'quantile'
74
+ };
75
+ const mapAggregateForVQuery = (aggregate)=>{
76
+ if (!aggregate) return aggregate;
77
+ const mappedFunc = VBI_TO_VQUERY_AGGR_FUNC_MAP[aggregate.func] ?? aggregate.func;
78
+ return {
79
+ ...aggregate,
80
+ func: mappedFunc
81
+ };
82
+ };
83
+ const buildSelect = (queryDSL, context)=>{
84
+ const { vbiDSL } = context;
85
+ const measures = vbiDSL.measures;
86
+ const dimensions = vbiDSL.dimensions;
87
+ const result = {
88
+ ...queryDSL
89
+ };
90
+ const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
91
+ const measureSelects = measureNodes.map((measure)=>({
92
+ field: measure.field,
93
+ alias: measure.alias,
94
+ aggr: mapAggregateForVQuery(measure.aggregate)
95
+ }));
96
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
97
+ const dimensionSelects = dimensionNodes.map((dimension)=>({
98
+ field: dimension.field,
99
+ alias: dimension.alias
100
+ }));
101
+ result.select = [
102
+ ...measureSelects,
103
+ ...dimensionSelects
104
+ ];
105
+ return result;
106
+ };
107
+ const buildGroupBy = (queryDSL, context)=>{
108
+ const result = {
109
+ ...queryDSL
110
+ };
111
+ const { vbiDSL } = context;
112
+ const dimensions = vbiDSL.dimensions;
113
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
114
+ result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
115
+ return result;
116
+ };
117
+ const buildWhere = (queryDSL, context)=>{
118
+ const { vbiDSL } = context;
119
+ const whereFilter = vbiDSL.whereFilter;
120
+ if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
121
+ const result = {
122
+ ...queryDSL
123
+ };
124
+ result.where = mapGroupToCondition(whereFilter);
125
+ return result;
126
+ };
127
+ function isWhereGroup(clause) {
128
+ return 'op' in clause && 'conditions' in clause;
129
+ }
130
+ function mapClauseToCondition(clause) {
131
+ if (isWhereGroup(clause)) return [
132
+ mapGroupToCondition(clause)
133
+ ];
134
+ return mapFilterToCondition(clause);
135
+ }
136
+ function mapGroupToCondition(group) {
137
+ return {
138
+ op: group.op,
139
+ conditions: group.conditions.flatMap(mapClauseToCondition)
140
+ };
141
+ }
142
+ function mapFilterToCondition(filter) {
143
+ if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
144
+ return handleSimpleFilter(filter);
145
+ }
146
+ function handleBetweenFilter(filter) {
147
+ const value = normalizeBetweenValue(filter.value);
148
+ const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
149
+ field: filter.field,
150
+ op: '<' === value.leftOp ? '>' : '>=',
151
+ value: value.min
152
+ } : void 0;
153
+ const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
154
+ field: filter.field,
155
+ op: '<' === value.rightOp ? '<' : '<=',
156
+ value: value.max
157
+ } : void 0;
158
+ if ('not between' === filter.op) {
159
+ const outsideConditions = [
160
+ lowerCondition && invertLowerBound(lowerCondition),
161
+ upperCondition && invertUpperBound(upperCondition)
162
+ ].filter(Boolean);
163
+ if (outsideConditions.length <= 1) return outsideConditions;
164
+ return [
165
+ {
166
+ op: 'or',
167
+ conditions: outsideConditions
168
+ }
169
+ ];
170
+ }
171
+ return [
172
+ lowerCondition,
173
+ upperCondition
174
+ ].filter(Boolean);
175
+ }
176
+ function normalizeBetweenValue(value) {
177
+ if (Array.isArray(value)) return {
178
+ min: value[0],
179
+ max: value[1],
180
+ leftOp: '<=',
181
+ rightOp: '<='
182
+ };
183
+ if ('object' == typeof value && null !== value) return value;
184
+ return {};
185
+ }
186
+ function invertLowerBound(condition) {
187
+ return {
188
+ field: condition.field,
189
+ op: '>' === condition.op ? '<=' : '<',
190
+ value: condition.value
191
+ };
192
+ }
193
+ function invertUpperBound(condition) {
194
+ return {
195
+ field: condition.field,
196
+ op: '<' === condition.op ? '>=' : '>',
197
+ value: condition.value
198
+ };
199
+ }
200
+ function handleSimpleFilter(filter) {
201
+ let mappedOp = filter.op ?? '=';
202
+ const value = filter.value;
203
+ if (Array.isArray(value)) {
204
+ if ('=' === mappedOp) mappedOp = 'in';
205
+ if ('!=' === mappedOp) mappedOp = 'not in';
206
+ }
207
+ return [
208
+ {
209
+ field: filter.field,
210
+ op: mappedOp,
211
+ value
212
+ }
213
+ ];
214
+ }
215
+ const DEFAULT_HAVING_AGGREGATE = {
216
+ func: 'sum'
217
+ };
218
+ const buildHaving = (queryDSL, context)=>{
219
+ const { vbiDSL } = context;
220
+ const havingFilter = vbiDSL.havingFilter;
221
+ if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
222
+ const result = {
223
+ ...queryDSL
224
+ };
225
+ result.having = {
226
+ op: havingFilter.op,
227
+ conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
228
+ };
229
+ return result;
230
+ };
231
+ function isHavingGroup(clause) {
232
+ return 'op' in clause && 'conditions' in clause;
233
+ }
234
+ function buildHaving_mapClauseToCondition(clause) {
235
+ if (isHavingGroup(clause)) return [
236
+ buildHaving_mapGroupToCondition(clause)
237
+ ];
238
+ return buildHaving_mapFilterToCondition(clause);
239
+ }
240
+ function buildHaving_mapGroupToCondition(group) {
241
+ return {
242
+ op: group.op,
243
+ conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
244
+ };
245
+ }
246
+ function buildHaving_mapFilterToCondition(filter) {
247
+ const mappedOp = normalizeOperator(filter.op, filter.value);
248
+ const aggregate = mapAggregateForVQuery(filter.aggregate ?? DEFAULT_HAVING_AGGREGATE);
249
+ return [
250
+ {
251
+ field: filter.field,
252
+ aggr: aggregate,
253
+ op: mappedOp,
254
+ value: filter.value
255
+ }
256
+ ];
257
+ }
258
+ function normalizeOperator(op, value) {
259
+ let mappedOp = op ?? '=';
260
+ if (Array.isArray(value)) {
261
+ if ('=' === mappedOp) mappedOp = 'in';
262
+ if ('!=' === mappedOp) mappedOp = 'not in';
263
+ }
264
+ return mappedOp;
265
+ }
266
+ const buildLimit = (queryDSL, context)=>{
267
+ const result = {
268
+ ...queryDSL
269
+ };
270
+ const limit = context.vbiDSL.limit ?? 1000;
271
+ result.limit = limit;
272
+ return result;
273
+ };
274
+ const buildVQuery = (vbiDSL, builder)=>{
275
+ const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
276
+ vbiDSL,
277
+ builder
278
+ });
279
+ return (0, external_remeda_namespaceObject.pipe)({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
280
+ };
281
+ const buildVQueryDSL = ({ vbiDSL, builder })=>buildVQuery(vbiDSL, builder);
282
+ const buildVSeedDSL = async ({ vbiDSL, queryDSL })=>{
283
+ const connectorId = vbiDSL.connectorId;
284
+ const connector = await getConnector(connectorId);
285
+ const schema = await connector.discoverSchema();
286
+ const queryResult = await connector.query({
287
+ queryDSL,
288
+ schema,
289
+ connectorId
290
+ });
291
+ return {
292
+ chartType: vbiDSL.chartType,
293
+ dataset: queryResult.dataset,
294
+ theme: vbiDSL.theme,
295
+ locale: vbiDSL.locale
296
+ };
297
+ };
298
+ const defaultVBIBuilderAdapters = {
299
+ buildVQuery: buildVQueryDSL,
300
+ buildVSeed: buildVSeedDSL
301
+ };
302
+ const resolveVBIBuilderAdapters = (adapters)=>({
303
+ buildVQuery: adapters?.buildVQuery ?? defaultVBIBuilderAdapters.buildVQuery,
304
+ buildVSeed: adapters?.buildVSeed ?? defaultVBIBuilderAdapters.buildVSeed
305
+ });
48
306
  class MeasureNodeBuilder {
49
307
  yMap;
50
308
  constructor(yMap){
51
309
  this.yMap = yMap;
52
310
  }
311
+ getId() {
312
+ return this.yMap.get('id');
313
+ }
53
314
  getField() {
54
315
  return this.yMap.get('field');
55
316
  }
@@ -69,13 +330,48 @@ class MeasureNodeBuilder {
69
330
  return this.yMap.toJSON();
70
331
  }
71
332
  }
333
+ const vseed_namespaceObject = require("@visactor/vseed");
334
+ const external_uuid_namespaceObject = require("uuid");
335
+ const id_id = {
336
+ uuid: ()=>(0, external_uuid_namespaceObject.v4)()
337
+ };
338
+ function isVBIFilter(clause) {
339
+ return 'field' in clause;
340
+ }
341
+ function isVBIWhereGroup(clause) {
342
+ return 'conditions' in clause;
343
+ }
344
+ function isVBIHavingFilter(clause) {
345
+ return 'field' in clause;
346
+ }
347
+ function isVBIHavingGroup(clause) {
348
+ return 'conditions' in clause;
349
+ }
350
+ const getOrCreateMeasures = (dsl)=>{
351
+ const measures = dsl.get('measures');
352
+ if (measures instanceof external_yjs_namespaceObject.Array) return measures;
353
+ const yMeasures = new external_yjs_namespaceObject.Array();
354
+ dsl.set('measures', yMeasures);
355
+ return yMeasures;
356
+ };
357
+ const normalizeMeasureNodeIds = (measures)=>{
358
+ measures.toArray().forEach((item)=>{
359
+ if (item instanceof external_yjs_namespaceObject.Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
360
+ });
361
+ };
362
+ const locateMeasureIndexById = (measures, measureId)=>measures.toArray().findIndex((item)=>item.get('id') === measureId);
72
363
  class MeasuresBuilder {
73
364
  dsl;
74
- constructor(_doc, dsl){
365
+ constructor(doc, dsl){
75
366
  this.dsl = dsl;
367
+ doc.transact(()=>{
368
+ const measures = getOrCreateMeasures(this.dsl);
369
+ normalizeMeasureNodeIds(measures);
370
+ });
76
371
  }
77
372
  add(field, callback) {
78
373
  const measure = {
374
+ id: id_id.uuid(),
79
375
  alias: field,
80
376
  field,
81
377
  encoding: 'yAxis',
@@ -85,45 +381,50 @@ class MeasuresBuilder {
85
381
  };
86
382
  const yMap = new external_yjs_namespaceObject.Map();
87
383
  for (const [key, value] of Object.entries(measure))yMap.set(key, value);
88
- this.dsl.get('measures').push([
384
+ const measures = getOrCreateMeasures(this.dsl);
385
+ measures.push([
89
386
  yMap
90
387
  ]);
91
388
  const node = new MeasureNodeBuilder(yMap);
92
389
  callback(node);
93
390
  return this;
94
391
  }
95
- remove(field) {
96
- const measures = this.dsl.get('measures');
97
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
98
- if (-1 !== index) this.dsl.get('measures').delete(index, 1);
392
+ remove(id) {
393
+ const measures = getOrCreateMeasures(this.dsl);
394
+ const index = locateMeasureIndexById(measures, id);
395
+ if (-1 !== index) measures.delete(index, 1);
99
396
  return this;
100
397
  }
101
- update(field, callback) {
102
- const measures = this.dsl.get('measures');
103
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
104
- if (-1 === index) throw new Error(`Measure with field "${field}" not found`);
398
+ update(id, callback) {
399
+ const measures = getOrCreateMeasures(this.dsl);
400
+ const index = locateMeasureIndexById(measures, id);
401
+ if (-1 === index) throw new Error(`Measure with id "${id}" not found`);
105
402
  const measureYMap = measures.get(index);
106
403
  const node = new MeasureNodeBuilder(measureYMap);
107
404
  callback(node);
108
405
  return this;
109
406
  }
110
- find(field) {
111
- const measures = this.dsl.get('measures');
112
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
113
- if (-1 === index) return;
114
- return new MeasureNodeBuilder(measures.get(index));
407
+ find(predicate) {
408
+ const measures = getOrCreateMeasures(this.dsl);
409
+ const items = measures.toArray();
410
+ for(let index = 0; index < items.length; index++){
411
+ const node = new MeasureNodeBuilder(items[index]);
412
+ if (predicate(node, index)) return node;
413
+ }
115
414
  }
116
415
  findAll() {
117
- const measures = this.dsl.get('measures');
416
+ const measures = getOrCreateMeasures(this.dsl);
118
417
  return measures.toArray().map((yMap)=>new MeasureNodeBuilder(yMap));
119
418
  }
120
419
  toJSON() {
121
- return this.dsl.get('measures').toJSON();
420
+ const measures = getOrCreateMeasures(this.dsl);
421
+ return measures.toJSON();
122
422
  }
123
423
  observe(callback) {
124
- this.dsl.get('measures').observe(callback);
424
+ const measures = getOrCreateMeasures(this.dsl);
425
+ measures.observe(callback);
125
426
  return ()=>{
126
- this.dsl.get('measures').unobserve(callback);
427
+ measures.unobserve(callback);
127
428
  };
128
429
  }
129
430
  static isMeasureNode(node) {
@@ -138,6 +439,9 @@ class DimensionNodeBuilder {
138
439
  constructor(yMap){
139
440
  this.yMap = yMap;
140
441
  }
442
+ getId() {
443
+ return this.yMap.get('id');
444
+ }
141
445
  getField() {
142
446
  return this.yMap.get('field');
143
447
  }
@@ -149,57 +453,80 @@ class DimensionNodeBuilder {
149
453
  return this.yMap.toJSON();
150
454
  }
151
455
  }
456
+ const getOrCreateDimensions = (dsl)=>{
457
+ const dimensions = dsl.get('dimensions');
458
+ if (dimensions instanceof external_yjs_namespaceObject.Array) return dimensions;
459
+ const yDimensions = new external_yjs_namespaceObject.Array();
460
+ dsl.set('dimensions', yDimensions);
461
+ return yDimensions;
462
+ };
463
+ const normalizeDimensionNodeIds = (dimensions)=>{
464
+ dimensions.toArray().forEach((item)=>{
465
+ if (item instanceof external_yjs_namespaceObject.Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
466
+ });
467
+ };
468
+ const locateDimensionIndexById = (dimensions, dimensionId)=>dimensions.toArray().findIndex((item)=>item.get('id') === dimensionId);
152
469
  class DimensionsBuilder {
153
470
  dsl;
154
- constructor(_doc, dsl){
471
+ constructor(doc, dsl){
155
472
  this.dsl = dsl;
473
+ doc.transact(()=>{
474
+ const dimensions = getOrCreateDimensions(this.dsl);
475
+ normalizeDimensionNodeIds(dimensions);
476
+ });
156
477
  }
157
478
  add(field, callback) {
158
479
  const dimension = {
480
+ id: id_id.uuid(),
159
481
  alias: field,
160
482
  field
161
483
  };
162
484
  const yMap = new external_yjs_namespaceObject.Map();
163
485
  for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
164
- this.dsl.get('dimensions').push([
486
+ const dimensions = getOrCreateDimensions(this.dsl);
487
+ dimensions.push([
165
488
  yMap
166
489
  ]);
167
490
  const node = new DimensionNodeBuilder(yMap);
168
491
  callback(node);
169
492
  return this;
170
493
  }
171
- remove(field) {
172
- const dimensions = this.dsl.get('dimensions');
173
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
174
- if (-1 !== index) this.dsl.get('dimensions').delete(index, 1);
494
+ remove(id) {
495
+ const dimensions = getOrCreateDimensions(this.dsl);
496
+ const index = locateDimensionIndexById(dimensions, id);
497
+ if (-1 !== index) dimensions.delete(index, 1);
175
498
  return this;
176
499
  }
177
- update(field, callback) {
178
- const dimensions = this.dsl.get('dimensions');
179
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
180
- if (-1 === index) throw new Error(`Dimension with field "${field}" not found`);
500
+ update(id, callback) {
501
+ const dimensions = getOrCreateDimensions(this.dsl);
502
+ const index = locateDimensionIndexById(dimensions, id);
503
+ if (-1 === index) throw new Error(`Dimension with id "${id}" not found`);
181
504
  const dimensionYMap = dimensions.get(index);
182
505
  const node = new DimensionNodeBuilder(dimensionYMap);
183
506
  callback(node);
184
507
  return this;
185
508
  }
186
- find(field) {
187
- const dimensions = this.dsl.get('dimensions');
188
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
189
- if (-1 === index) return;
190
- return new DimensionNodeBuilder(dimensions.get(index));
509
+ find(predicate) {
510
+ const dimensions = getOrCreateDimensions(this.dsl);
511
+ const items = dimensions.toArray();
512
+ for(let index = 0; index < items.length; index++){
513
+ const node = new DimensionNodeBuilder(items[index]);
514
+ if (predicate(node, index)) return node;
515
+ }
191
516
  }
192
517
  findAll() {
193
- const dimensions = this.dsl.get('dimensions');
518
+ const dimensions = getOrCreateDimensions(this.dsl);
194
519
  return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
195
520
  }
196
521
  toJSON() {
197
- return this.dsl.get('dimensions').toJSON();
522
+ const dimensions = getOrCreateDimensions(this.dsl);
523
+ return dimensions.toJSON();
198
524
  }
199
525
  observe(callback) {
200
- this.dsl.get('dimensions').observe(callback);
526
+ const dimensions = getOrCreateDimensions(this.dsl);
527
+ dimensions.observe(callback);
201
528
  return ()=>{
202
- this.dsl.get('dimensions').unobserve(callback);
529
+ dimensions.unobserve(callback);
203
530
  };
204
531
  }
205
532
  static isDimensionNode(node) {
@@ -209,7 +536,6 @@ class DimensionsBuilder {
209
536
  return 'children' in node;
210
537
  }
211
538
  }
212
- const vseed_namespaceObject = require("@visactor/vseed");
213
539
  class ChartTypeBuilder {
214
540
  dsl;
215
541
  constructor(_doc, dsl){
@@ -259,22 +585,6 @@ class ChartTypeBuilder {
259
585
  ];
260
586
  }
261
587
  }
262
- const external_uuid_namespaceObject = require("uuid");
263
- const id_id = {
264
- uuid: ()=>(0, external_uuid_namespaceObject.v4)()
265
- };
266
- function isVBIFilter(clause) {
267
- return 'field' in clause;
268
- }
269
- function isVBIWhereGroup(clause) {
270
- return 'conditions' in clause;
271
- }
272
- function isVBIHavingFilter(clause) {
273
- return 'field' in clause;
274
- }
275
- function isVBIHavingGroup(clause) {
276
- return 'conditions' in clause;
277
- }
278
588
  function createWhereGroup(op = 'and', groupId = 'root') {
279
589
  const yMap = new external_yjs_namespaceObject.Map();
280
590
  yMap.set('id', groupId);
@@ -282,7 +592,7 @@ function createWhereGroup(op = 'and', groupId = 'root') {
282
592
  yMap.set('conditions', new external_yjs_namespaceObject.Array());
283
593
  return yMap;
284
594
  }
285
- function isWhereGroup(yMap) {
595
+ function where_utils_isWhereGroup(yMap) {
286
596
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
287
597
  }
288
598
  function findEntry(collection, entryId) {
@@ -294,7 +604,7 @@ function findEntry(collection, entryId) {
294
604
  index,
295
605
  item
296
606
  };
297
- if (isWhereGroup(item)) {
607
+ if (where_utils_isWhereGroup(item)) {
298
608
  const nestedCollection = item.get('conditions');
299
609
  const nestedMatch = findEntry(nestedCollection, entryId);
300
610
  if (nestedMatch) return nestedMatch;
@@ -456,13 +766,21 @@ class WhereFilterBuilder {
456
766
  }
457
767
  return this;
458
768
  }
459
- find(id) {
460
- const conditions = this.getConditions();
461
- const match = findEntry(conditions, id);
462
- const yMap = match?.item;
463
- if (!yMap) return;
464
- if (WhereFilterBuilder.isGroup(yMap)) return new WhereGroupBuilder(yMap);
465
- return new WhereFilterNodeBuilder(yMap);
769
+ find(predicate) {
770
+ const traverse = (collection)=>{
771
+ const items = collection.toArray();
772
+ for(let index = 0; index < items.length; index++){
773
+ const yMap = items[index];
774
+ const entry = WhereFilterBuilder.isGroup(yMap) ? new WhereGroupBuilder(yMap) : new WhereFilterNodeBuilder(yMap);
775
+ if (predicate(entry, index)) return entry;
776
+ if (WhereFilterBuilder.isGroup(yMap)) {
777
+ const nestedCollection = yMap.get('conditions');
778
+ const nestedMatch = traverse(nestedCollection);
779
+ if (nestedMatch) return nestedMatch;
780
+ }
781
+ }
782
+ };
783
+ return traverse(this.getConditions());
466
784
  }
467
785
  clear() {
468
786
  const conditions = this.getConditions();
@@ -479,7 +797,7 @@ class WhereFilterBuilder {
479
797
  };
480
798
  }
481
799
  static isGroup(yMap) {
482
- return isWhereGroup(yMap);
800
+ return where_utils_isWhereGroup(yMap);
483
801
  }
484
802
  static isNode(yMap) {
485
803
  return void 0 !== yMap.get('field');
@@ -492,7 +810,7 @@ function createHavingGroup(op = 'and', groupId = 'root') {
492
810
  yMap.set('conditions', new external_yjs_namespaceObject.Array());
493
811
  return yMap;
494
812
  }
495
- function isHavingGroup(yMap) {
813
+ function having_utils_isHavingGroup(yMap) {
496
814
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
497
815
  }
498
816
  function having_utils_findEntry(collection, entryId) {
@@ -504,7 +822,7 @@ function having_utils_findEntry(collection, entryId) {
504
822
  index,
505
823
  item
506
824
  };
507
- if (isHavingGroup(item)) {
825
+ if (having_utils_isHavingGroup(item)) {
508
826
  const nestedCollection = item.get('conditions');
509
827
  const nestedMatch = having_utils_findEntry(nestedCollection, entryId);
510
828
  if (nestedMatch) return nestedMatch;
@@ -525,6 +843,9 @@ class HavingFilterNodeBuilder {
525
843
  getOperator() {
526
844
  return this.yMap.get('op');
527
845
  }
846
+ getAggregate() {
847
+ return this.yMap.get('aggregate');
848
+ }
528
849
  setValue(value) {
529
850
  this.yMap.set('value', value);
530
851
  return this;
@@ -533,6 +854,10 @@ class HavingFilterNodeBuilder {
533
854
  this.yMap.set('op', operator);
534
855
  return this;
535
856
  }
857
+ setAggregate(aggregate) {
858
+ this.yMap.set('aggregate', aggregate);
859
+ return this;
860
+ }
536
861
  toJSON() {
537
862
  return this.yMap.toJSON();
538
863
  }
@@ -559,6 +884,9 @@ class HavingGroupBuilder {
559
884
  const yMap = new external_yjs_namespaceObject.Map();
560
885
  yMap.set('id', id_id.uuid());
561
886
  yMap.set('field', field);
887
+ yMap.set('aggregate', {
888
+ func: 'sum'
889
+ });
562
890
  this.getConditions().push([
563
891
  yMap
564
892
  ]);
@@ -616,6 +944,9 @@ class HavingFilterBuilder {
616
944
  const yMap = new external_yjs_namespaceObject.Map();
617
945
  yMap.set('id', id_id.uuid());
618
946
  yMap.set('field', field);
947
+ yMap.set('aggregate', {
948
+ func: 'sum'
949
+ });
619
950
  this.getConditions().push([
620
951
  yMap
621
952
  ]);
@@ -662,13 +993,21 @@ class HavingFilterBuilder {
662
993
  }
663
994
  return this;
664
995
  }
665
- find(id) {
666
- const conditions = this.getConditions();
667
- const match = having_utils_findEntry(conditions, id);
668
- const yMap = match?.item;
669
- if (!yMap) return;
670
- if (HavingFilterBuilder.isGroup(yMap)) return new HavingGroupBuilder(yMap);
671
- return new HavingFilterNodeBuilder(yMap);
996
+ find(predicate) {
997
+ const traverse = (collection)=>{
998
+ const items = collection.toArray();
999
+ for(let index = 0; index < items.length; index++){
1000
+ const yMap = items[index];
1001
+ const entry = HavingFilterBuilder.isGroup(yMap) ? new HavingGroupBuilder(yMap) : new HavingFilterNodeBuilder(yMap);
1002
+ if (predicate(entry, index)) return entry;
1003
+ if (HavingFilterBuilder.isGroup(yMap)) {
1004
+ const nestedCollection = yMap.get('conditions');
1005
+ const nestedMatch = traverse(nestedCollection);
1006
+ if (nestedMatch) return nestedMatch;
1007
+ }
1008
+ }
1009
+ };
1010
+ return traverse(this.getConditions());
672
1011
  }
673
1012
  clear() {
674
1013
  const conditions = this.getConditions();
@@ -685,7 +1024,7 @@ class HavingFilterBuilder {
685
1024
  };
686
1025
  }
687
1026
  static isGroup(yMap) {
688
- return isHavingGroup(yMap);
1027
+ return having_utils_isHavingGroup(yMap);
689
1028
  }
690
1029
  static isNode(yMap) {
691
1030
  return void 0 !== yMap.get('field');
@@ -784,203 +1123,30 @@ class UndoManager {
784
1123
  this.manager.clear(clearUndoStack, clearRedoStack);
785
1124
  }
786
1125
  }
787
- const external_remeda_namespaceObject = require("remeda");
788
- const buildSelect = (queryDSL, context)=>{
789
- const { vbiDSL } = context;
790
- const measures = vbiDSL.measures;
791
- const dimensions = vbiDSL.dimensions;
792
- const result = {
793
- ...queryDSL
794
- };
795
- const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
796
- const measureSelects = measureNodes.map((measure)=>({
797
- field: measure.field,
798
- alias: measure.alias,
799
- aggr: measure.aggregate
800
- }));
801
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
802
- const dimensionSelects = dimensionNodes.map((dimension)=>({
803
- field: dimension.field,
804
- alias: dimension.alias
805
- }));
806
- result.select = measureSelects.concat(dimensionSelects);
807
- return result;
1126
+ const applyUpdateToDoc = (doc, update, transactionOrigin)=>{
1127
+ external_yjs_namespaceObject.applyUpdate(doc, update, transactionOrigin);
808
1128
  };
809
- const buildGroupBy = (queryDSL, context)=>{
810
- const result = {
811
- ...queryDSL
812
- };
813
- const { vbiDSL } = context;
814
- const dimensions = vbiDSL.dimensions;
815
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
816
- result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
817
- return result;
1129
+ const encodeDocStateAsUpdate = (doc, targetStateVector)=>external_yjs_namespaceObject.encodeStateAsUpdate(doc, targetStateVector);
1130
+ const buildVBIDSL = (dsl)=>dsl.toJSON();
1131
+ const getCollectionLength = (value)=>{
1132
+ if (value instanceof external_yjs_namespaceObject.Array) return value.length;
1133
+ if (Array.isArray(value)) return value.length;
1134
+ return 0;
818
1135
  };
819
- const buildWhere = (queryDSL, context)=>{
820
- const { vbiDSL } = context;
821
- const whereFilter = vbiDSL.whereFilter;
822
- if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
823
- const result = {
824
- ...queryDSL
825
- };
826
- result.where = mapGroupToCondition(whereFilter);
827
- return result;
1136
+ const isEmptyVBIDSL = (dsl)=>{
1137
+ const dimensionsLength = getCollectionLength(dsl.get('dimensions'));
1138
+ const measuresLength = getCollectionLength(dsl.get('measures'));
1139
+ return 0 === dimensionsLength && 0 === measuresLength;
828
1140
  };
829
- function buildWhere_isWhereGroup(clause) {
830
- return 'op' in clause && 'conditions' in clause;
831
- }
832
- function mapClauseToCondition(clause) {
833
- if (buildWhere_isWhereGroup(clause)) return [
834
- mapGroupToCondition(clause)
835
- ];
836
- return mapFilterToCondition(clause);
837
- }
838
- function mapGroupToCondition(group) {
839
- return {
840
- op: group.op,
841
- conditions: group.conditions.flatMap(mapClauseToCondition)
842
- };
843
- }
844
- function mapFilterToCondition(filter) {
845
- if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
846
- return handleSimpleFilter(filter);
847
- }
848
- function handleBetweenFilter(filter) {
849
- const value = normalizeBetweenValue(filter.value);
850
- const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
851
- field: filter.field,
852
- op: '<' === value.leftOp ? '>' : '>=',
853
- value: value.min
854
- } : void 0;
855
- const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
856
- field: filter.field,
857
- op: '<' === value.rightOp ? '<' : '<=',
858
- value: value.max
859
- } : void 0;
860
- if ('not between' === filter.op) {
861
- const outsideConditions = [
862
- lowerCondition && invertLowerBound(lowerCondition),
863
- upperCondition && invertUpperBound(upperCondition)
864
- ].filter(Boolean);
865
- if (outsideConditions.length <= 1) return outsideConditions;
866
- return [
867
- {
868
- op: 'or',
869
- conditions: outsideConditions
870
- }
871
- ];
872
- }
873
- return [
874
- lowerCondition,
875
- upperCondition
876
- ].filter(Boolean);
877
- }
878
- function normalizeBetweenValue(value) {
879
- if (Array.isArray(value)) return {
880
- min: value[0],
881
- max: value[1],
882
- leftOp: '<=',
883
- rightOp: '<='
884
- };
885
- if ('object' == typeof value && null !== value) return value;
886
- return {};
887
- }
888
- function invertLowerBound(condition) {
889
- return {
890
- field: condition.field,
891
- op: '>' === condition.op ? '<=' : '<',
892
- value: condition.value
893
- };
894
- }
895
- function invertUpperBound(condition) {
896
- return {
897
- field: condition.field,
898
- op: '<' === condition.op ? '>=' : '>',
899
- value: condition.value
900
- };
901
- }
902
- function handleSimpleFilter(filter) {
903
- let mappedOp = filter.op ?? '=';
904
- const value = filter.value;
905
- if (Array.isArray(value)) {
906
- if ('=' === mappedOp) mappedOp = 'in';
907
- if ('!=' === mappedOp) mappedOp = 'not in';
908
- }
909
- return [
910
- {
911
- field: filter.field,
912
- op: mappedOp,
913
- value
914
- }
915
- ];
916
- }
917
- const buildHaving = (queryDSL, context)=>{
918
- const { vbiDSL } = context;
919
- const havingFilter = vbiDSL.havingFilter;
920
- if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
921
- const result = {
922
- ...queryDSL
923
- };
924
- result.having = {
925
- op: havingFilter.op,
926
- conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
927
- };
928
- return result;
929
- };
930
- function buildHaving_isHavingGroup(clause) {
931
- return 'op' in clause && 'conditions' in clause;
932
- }
933
- function buildHaving_mapClauseToCondition(clause) {
934
- if (buildHaving_isHavingGroup(clause)) return [
935
- buildHaving_mapGroupToCondition(clause)
936
- ];
937
- return buildHaving_mapFilterToCondition(clause);
938
- }
939
- function buildHaving_mapGroupToCondition(group) {
940
- return {
941
- op: group.op,
942
- conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
943
- };
944
- }
945
- function buildHaving_mapFilterToCondition(filter) {
946
- const mappedOp = filter.op ?? '=';
947
- return [
948
- {
949
- field: filter.field,
950
- op: mappedOp,
951
- value: filter.value
952
- }
953
- ];
954
- }
955
- const buildLimit = (queryDSL, context)=>{
956
- const result = {
957
- ...queryDSL
958
- };
959
- const limit = context.vbiDSL.limit ?? 1000;
960
- result.limit = limit;
961
- return result;
962
- };
963
- const buildVQuery = (vbiDSL, builder)=>{
964
- const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
965
- vbiDSL,
966
- builder
967
- });
968
- return (0, external_remeda_namespaceObject.pipe)({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
969
- };
970
- const connectorMap = new Map();
971
- const registerConnector = (id, connector)=>{
972
- connectorMap.set(id, connector);
973
- };
974
- const getConnector = async (id)=>{
975
- const connector = connectorMap.get(id);
976
- if (!connector) throw new Error(`connector ${id} not registered`);
977
- if ('function' == typeof connector) return connector();
978
- return connector;
1141
+ const getBuilderSchema = async (dsl)=>{
1142
+ const connectorId = dsl.get('connectorId');
1143
+ const connector = await getConnector(connectorId);
1144
+ return connector.discoverSchema();
979
1145
  };
980
1146
  class VBIBuilder {
981
1147
  doc;
982
1148
  dsl;
983
- undoManager;
1149
+ adapters;
984
1150
  chartType;
985
1151
  measures;
986
1152
  dimensions;
@@ -989,9 +1155,11 @@ class VBIBuilder {
989
1155
  theme;
990
1156
  locale;
991
1157
  limit;
992
- constructor(doc){
1158
+ undoManager;
1159
+ constructor(doc, options){
993
1160
  this.doc = doc;
994
1161
  this.dsl = doc.getMap('dsl');
1162
+ this.adapters = resolveVBIBuilderAdapters(options?.adapters);
995
1163
  this.undoManager = new UndoManager(this.dsl);
996
1164
  this.chartType = new ChartTypeBuilder(doc, this.dsl);
997
1165
  this.measures = new MeasuresBuilder(doc, this.dsl);
@@ -1002,150 +1170,194 @@ class VBIBuilder {
1002
1170
  this.locale = new LocaleBuilder(doc, this.dsl);
1003
1171
  this.limit = new LimitBuilder(doc, this.dsl);
1004
1172
  }
1005
- applyUpdate(update) {
1006
- external_yjs_namespaceObject.applyUpdate(this.doc, update);
1007
- }
1008
- encodeStateAsUpdate(targetStateVector) {
1009
- return external_yjs_namespaceObject.encodeStateAsUpdate(this.doc, targetStateVector);
1010
- }
1173
+ applyUpdate = (update, transactionOrigin)=>applyUpdateToDoc(this.doc, update, transactionOrigin);
1174
+ encodeStateAsUpdate = (targetStateVector)=>encodeDocStateAsUpdate(this.doc, targetStateVector);
1011
1175
  buildVSeed = async ()=>{
1012
1176
  const vbiDSL = this.build();
1013
- const connectorId = vbiDSL.connectorId;
1014
- const connector = await getConnector(vbiDSL.connectorId);
1015
- const queryDSL = this.buildVQuery();
1016
- const schema = await connector.discoverSchema();
1017
- const queryResult = await connector.query({
1177
+ const queryDSL = this.adapters.buildVQuery({
1178
+ dsl: this.dsl,
1179
+ vbiDSL,
1180
+ builder: this
1181
+ });
1182
+ return this.adapters.buildVSeed({
1183
+ dsl: this.dsl,
1184
+ vbiDSL,
1018
1185
  queryDSL,
1019
- schema,
1020
- connectorId
1186
+ builder: this
1021
1187
  });
1022
- return {
1023
- chartType: vbiDSL.chartType,
1024
- dataset: queryResult.dataset,
1025
- theme: vbiDSL.theme,
1026
- locale: vbiDSL.locale
1027
- };
1028
1188
  };
1029
1189
  buildVQuery = ()=>{
1030
1190
  const vbiDSL = this.build();
1031
- return buildVQuery(vbiDSL, this);
1032
- };
1033
- build = ()=>this.dsl.toJSON();
1034
- getSchema = async ()=>{
1035
- const connectorId = this.dsl.get('connectorId');
1036
- const con = await getConnector(connectorId);
1037
- const result = await con.discoverSchema();
1038
- return result;
1191
+ return this.adapters.buildVQuery({
1192
+ dsl: this.dsl,
1193
+ vbiDSL,
1194
+ builder: this
1195
+ });
1039
1196
  };
1197
+ build = ()=>buildVBIDSL(this.dsl);
1198
+ isEmpty = ()=>isEmptyVBIDSL(this.dsl);
1199
+ getSchema = async ()=>getBuilderSchema(this.dsl);
1040
1200
  }
1041
- const createVBI = ()=>({
1042
- connectorMap: connectorMap,
1043
- registerConnector: registerConnector,
1044
- getConnector: getConnector,
1045
- generateEmptyDSL: (connectorId)=>({
1046
- connectorId: connectorId,
1047
- chartType: 'table',
1048
- measures: [],
1049
- dimensions: [],
1050
- whereFilter: {
1051
- id: 'root',
1052
- op: 'and',
1053
- conditions: []
1054
- },
1055
- havingFilter: {
1056
- id: 'root',
1057
- op: 'and',
1058
- conditions: []
1059
- },
1060
- theme: 'light',
1061
- locale: 'zh-CN',
1062
- version: 0
1063
- }),
1064
- from: (vbi)=>{
1065
- const doc = new external_yjs_namespaceObject.Doc();
1066
- const dsl = doc.getMap('dsl');
1067
- doc.transact(()=>{
1068
- if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
1069
- if (vbi.chartType) dsl.set('chartType', vbi.chartType);
1070
- if (vbi.theme) dsl.set('theme', vbi.theme);
1071
- if (vbi.limit) dsl.set('limit', vbi.limit);
1072
- if (vbi.locale) dsl.set('locale', vbi.locale);
1073
- if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1074
- const toYMap = (obj, ensureId = false)=>{
1075
- const yMap = new external_yjs_namespaceObject.Map();
1076
- if (ensureId && !obj.id) yMap.set('id', id_id.uuid());
1077
- for (const [key, value] of Object.entries(obj))if ('conditions' === key && Array.isArray(value)) {
1078
- const yArr = new external_yjs_namespaceObject.Array();
1079
- value.forEach((child)=>{
1080
- if (child instanceof external_yjs_namespaceObject.Map) yArr.push([
1081
- child
1082
- ]);
1083
- else if ('object' == typeof child && null !== child) yArr.push([
1084
- toYMap(child, true)
1085
- ]);
1086
- else yArr.push([
1087
- child
1088
- ]);
1089
- });
1090
- yMap.set(key, yArr);
1091
- } else yMap.set(key, value);
1092
- return yMap;
1093
- };
1094
- const ensureYArray = (arr, ensureId = false)=>{
1095
- if (!arr) return new external_yjs_namespaceObject.Array();
1096
- if (arr instanceof external_yjs_namespaceObject.Array) return arr;
1097
- const yArr = new external_yjs_namespaceObject.Array();
1098
- arr.forEach((item)=>{
1099
- if (item instanceof external_yjs_namespaceObject.Map) yArr.push([
1100
- item
1101
- ]);
1102
- else if ('object' == typeof item && null !== item) yArr.push([
1103
- toYMap(item, ensureId)
1104
- ]);
1105
- else yArr.push([
1106
- item
1107
- ]);
1108
- });
1109
- return yArr;
1110
- };
1111
- const whereFilter = vbi.whereFilter ?? {
1112
- id: 'root',
1113
- op: 'and',
1114
- conditions: []
1115
- };
1116
- const whereGroup = whereFilter instanceof external_yjs_namespaceObject.Map ? whereFilter : createWhereGroup();
1117
- if (whereFilter instanceof external_yjs_namespaceObject.Map) {
1118
- if (!(whereGroup.get('conditions') instanceof external_yjs_namespaceObject.Array)) whereGroup.set('conditions', new external_yjs_namespaceObject.Array());
1119
- if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1120
- if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1121
- } else {
1122
- whereGroup.set('id', whereFilter.id ?? 'root');
1123
- whereGroup.set('op', whereFilter.op ?? 'and');
1124
- whereGroup.set('conditions', ensureYArray(whereFilter.conditions, true));
1201
+ const shouldEnsureIdForObject = (obj, ensureId)=>{
1202
+ if (true === ensureId) return true;
1203
+ if ('field' === ensureId) return 'string' == typeof obj.field;
1204
+ return false;
1205
+ };
1206
+ const toYMap = (obj, ensureId = false)=>{
1207
+ const yMap = new external_yjs_namespaceObject.Map();
1208
+ if (shouldEnsureIdForObject(obj, ensureId) && !obj.id) yMap.set('id', id_id.uuid());
1209
+ for (const [key, value] of Object.entries(obj)){
1210
+ if (('conditions' === key || 'children' === key) && Array.isArray(value)) {
1211
+ const yArr = new external_yjs_namespaceObject.Array();
1212
+ for (const child of value){
1213
+ if (child instanceof external_yjs_namespaceObject.Map) {
1214
+ yArr.push([
1215
+ child
1216
+ ]);
1217
+ continue;
1125
1218
  }
1126
- dsl.set('whereFilter', whereGroup);
1127
- const havingFilter = vbi.havingFilter ?? {
1128
- id: 'root',
1129
- op: 'and',
1130
- conditions: []
1131
- };
1132
- const havingGroup = havingFilter instanceof external_yjs_namespaceObject.Map ? havingFilter : createHavingGroup();
1133
- if (havingFilter instanceof external_yjs_namespaceObject.Map) {
1134
- if (!(havingGroup.get('conditions') instanceof external_yjs_namespaceObject.Array)) havingGroup.set('conditions', new external_yjs_namespaceObject.Array());
1135
- if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1136
- if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1137
- } else {
1138
- havingGroup.set('id', havingFilter.id ?? 'root');
1139
- havingGroup.set('op', havingFilter.op ?? 'and');
1140
- havingGroup.set('conditions', ensureYArray(havingFilter.conditions, true));
1219
+ if ('object' == typeof child && null !== child) {
1220
+ yArr.push([
1221
+ toYMap(child, ensureId)
1222
+ ]);
1223
+ continue;
1141
1224
  }
1142
- dsl.set('havingFilter', havingGroup);
1143
- dsl.set('measures', ensureYArray(vbi.measures));
1144
- dsl.set('dimensions', ensureYArray(vbi.dimensions));
1145
- });
1146
- return new VBIBuilder(doc);
1225
+ yArr.push([
1226
+ child
1227
+ ]);
1228
+ }
1229
+ yMap.set(key, yArr);
1230
+ continue;
1231
+ }
1232
+ yMap.set(key, value);
1233
+ }
1234
+ return yMap;
1235
+ };
1236
+ const ensureYArray = (arr, ensureId = false)=>{
1237
+ if (!arr) return new external_yjs_namespaceObject.Array();
1238
+ if (arr instanceof external_yjs_namespaceObject.Array) return arr;
1239
+ const yArr = new external_yjs_namespaceObject.Array();
1240
+ for (const item of arr){
1241
+ if (item instanceof external_yjs_namespaceObject.Map) {
1242
+ yArr.push([
1243
+ item
1244
+ ]);
1245
+ continue;
1246
+ }
1247
+ if ('object' == typeof item && null !== item) {
1248
+ yArr.push([
1249
+ toYMap(item, ensureId)
1250
+ ]);
1251
+ continue;
1147
1252
  }
1253
+ yArr.push([
1254
+ item
1255
+ ]);
1256
+ }
1257
+ return yArr;
1258
+ };
1259
+ const getDefaultWhereFilter = ()=>({
1260
+ id: 'root',
1261
+ op: 'and',
1262
+ conditions: []
1263
+ });
1264
+ const isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1265
+ const ensureWhereGroup = (whereFilter)=>{
1266
+ const sourceWhereFilter = whereFilter instanceof external_yjs_namespaceObject.Map || isFilterGroupInput(whereFilter) ? whereFilter : getDefaultWhereFilter();
1267
+ const whereGroup = sourceWhereFilter instanceof external_yjs_namespaceObject.Map ? sourceWhereFilter : createWhereGroup();
1268
+ if (sourceWhereFilter instanceof external_yjs_namespaceObject.Map) {
1269
+ if (!(whereGroup.get('conditions') instanceof external_yjs_namespaceObject.Array)) whereGroup.set('conditions', new external_yjs_namespaceObject.Array());
1270
+ if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1271
+ if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1272
+ return whereGroup;
1273
+ }
1274
+ whereGroup.set('id', sourceWhereFilter.id ?? 'root');
1275
+ whereGroup.set('op', sourceWhereFilter.op ?? 'and');
1276
+ whereGroup.set('conditions', ensureYArray(sourceWhereFilter.conditions, true));
1277
+ return whereGroup;
1278
+ };
1279
+ const getDefaultHavingFilter = ()=>({
1280
+ id: 'root',
1281
+ op: 'and',
1282
+ conditions: []
1148
1283
  });
1284
+ const ensure_having_group_isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1285
+ const ensureHavingGroup = (havingFilter)=>{
1286
+ const sourceHavingFilter = havingFilter instanceof external_yjs_namespaceObject.Map || ensure_having_group_isFilterGroupInput(havingFilter) ? havingFilter : getDefaultHavingFilter();
1287
+ const havingGroup = sourceHavingFilter instanceof external_yjs_namespaceObject.Map ? sourceHavingFilter : createHavingGroup();
1288
+ if (sourceHavingFilter instanceof external_yjs_namespaceObject.Map) {
1289
+ if (!(havingGroup.get('conditions') instanceof external_yjs_namespaceObject.Array)) havingGroup.set('conditions', new external_yjs_namespaceObject.Array());
1290
+ if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1291
+ if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1292
+ return havingGroup;
1293
+ }
1294
+ havingGroup.set('id', sourceHavingFilter.id ?? 'root');
1295
+ havingGroup.set('op', sourceHavingFilter.op ?? 'and');
1296
+ havingGroup.set('conditions', ensureYArray(sourceHavingFilter.conditions, true));
1297
+ return havingGroup;
1298
+ };
1299
+ const setBaseDSLFields = (dsl, vbi)=>{
1300
+ if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
1301
+ if (vbi.chartType) dsl.set('chartType', vbi.chartType);
1302
+ if (vbi.theme) dsl.set('theme', vbi.theme);
1303
+ if (vbi.limit) dsl.set('limit', vbi.limit);
1304
+ if (vbi.locale) dsl.set('locale', vbi.locale);
1305
+ if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1306
+ };
1307
+ const fromVBIDSLInput = (vbi, options)=>{
1308
+ const doc = new external_yjs_namespaceObject.Doc();
1309
+ const dsl = doc.getMap('dsl');
1310
+ doc.transact(()=>{
1311
+ setBaseDSLFields(dsl, vbi);
1312
+ dsl.set('whereFilter', ensureWhereGroup(vbi.whereFilter));
1313
+ dsl.set('havingFilter', ensureHavingGroup(vbi.havingFilter));
1314
+ dsl.set('measures', ensureYArray(vbi.measures, 'field'));
1315
+ dsl.set('dimensions', ensureYArray(vbi.dimensions, 'field'));
1316
+ });
1317
+ return new VBIBuilder(doc, options);
1318
+ };
1319
+ const generateEmptyDSL = (connectorId)=>({
1320
+ connectorId,
1321
+ chartType: 'table',
1322
+ measures: [],
1323
+ dimensions: [],
1324
+ whereFilter: {
1325
+ id: 'root',
1326
+ op: 'and',
1327
+ conditions: []
1328
+ },
1329
+ havingFilter: {
1330
+ id: 'root',
1331
+ op: 'and',
1332
+ conditions: []
1333
+ },
1334
+ theme: 'light',
1335
+ locale: 'zh-CN',
1336
+ version: 0
1337
+ });
1338
+ const mergeBuilderOptions = (base, overrides)=>{
1339
+ if (!base) return overrides;
1340
+ if (!overrides) return base;
1341
+ return {
1342
+ ...base,
1343
+ ...overrides,
1344
+ adapters: {
1345
+ ...base.adapters,
1346
+ ...overrides.adapters
1347
+ }
1348
+ };
1349
+ };
1350
+ function createVBI(defaultBuilderOptions) {
1351
+ const from = (vbi, builderOptions)=>fromVBIDSLInput(vbi, mergeBuilderOptions(defaultBuilderOptions, builderOptions));
1352
+ return {
1353
+ connectorMap: connectorMap,
1354
+ registerConnector: registerConnector,
1355
+ getConnector: getConnector,
1356
+ generateEmptyDSL: generateEmptyDSL,
1357
+ from,
1358
+ create: from
1359
+ };
1360
+ }
1149
1361
  const VBI = createVBI();
1150
1362
  exports.ChartTypeBuilder = __webpack_exports__.ChartTypeBuilder;
1151
1363
  exports.DimensionsBuilder = __webpack_exports__.DimensionsBuilder;
@@ -1159,6 +1371,8 @@ exports.VBI = __webpack_exports__.VBI;
1159
1371
  exports.VBIBuilder = __webpack_exports__.VBIBuilder;
1160
1372
  exports.WhereFilterBuilder = __webpack_exports__.WhereFilterBuilder;
1161
1373
  exports.buildVQuery = __webpack_exports__.buildVQuery;
1374
+ exports.createVBI = __webpack_exports__.createVBI;
1375
+ exports.defaultVBIBuilderAdapters = __webpack_exports__.defaultVBIBuilderAdapters;
1162
1376
  exports.findTreeNodesBy = __webpack_exports__.findTreeNodesBy;
1163
1377
  exports.id = __webpack_exports__.id;
1164
1378
  exports.isVBIFilter = __webpack_exports__.isVBIFilter;
@@ -1166,6 +1380,7 @@ exports.isVBIHavingFilter = __webpack_exports__.isVBIHavingFilter;
1166
1380
  exports.isVBIHavingGroup = __webpack_exports__.isVBIHavingGroup;
1167
1381
  exports.isVBIWhereGroup = __webpack_exports__.isVBIWhereGroup;
1168
1382
  exports.preorderTraverse = __webpack_exports__.preorderTraverse;
1383
+ exports.resolveVBIBuilderAdapters = __webpack_exports__.resolveVBIBuilderAdapters;
1169
1384
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1170
1385
  "ChartTypeBuilder",
1171
1386
  "DimensionsBuilder",
@@ -1179,13 +1394,16 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1179
1394
  "VBIBuilder",
1180
1395
  "WhereFilterBuilder",
1181
1396
  "buildVQuery",
1397
+ "createVBI",
1398
+ "defaultVBIBuilderAdapters",
1182
1399
  "findTreeNodesBy",
1183
1400
  "id",
1184
1401
  "isVBIFilter",
1185
1402
  "isVBIHavingFilter",
1186
1403
  "isVBIHavingGroup",
1187
1404
  "isVBIWhereGroup",
1188
- "preorderTraverse"
1405
+ "preorderTraverse",
1406
+ "resolveVBIBuilderAdapters"
1189
1407
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
1190
1408
  Object.defineProperty(exports, '__esModule', {
1191
1409
  value: true