@visactor/vbi 0.4.17 → 0.4.20

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 (60) 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/{vbi-builder.d.ts → builder.d.ts} +8 -8
  7. package/dist/builder/features/chart-type/chart-type-builder.d.ts +20 -1
  8. package/dist/builder/features/chart-type/dimension-encoding.d.ts +4 -0
  9. package/dist/builder/features/chart-type/measure-encoding.d.ts +4 -0
  10. package/dist/builder/features/chart-type/reapply-dimension-encodings.d.ts +2 -0
  11. package/dist/builder/features/chart-type/reapply-measure-encodings.d.ts +2 -0
  12. package/dist/builder/features/dimensions/dim-builder.d.ts +3 -2
  13. package/dist/builder/features/dimensions/dim-node-builder.d.ts +32 -1
  14. package/dist/builder/features/havingFilter/having-builder.d.ts +2 -2
  15. package/dist/builder/features/havingFilter/having-node-builder.d.ts +10 -1
  16. package/dist/builder/features/measures/mea-builder.d.ts +3 -2
  17. package/dist/builder/features/measures/mea-node-builder.d.ts +33 -3
  18. package/dist/builder/features/whereFilter/where-builder.d.ts +2 -2
  19. package/dist/builder/features/whereFilter/where-node-builder.d.ts +11 -2
  20. package/dist/builder/index.d.ts +2 -1
  21. package/dist/builder/modules/build.d.ts +2 -2
  22. package/dist/builder/modules/index.d.ts +2 -5
  23. package/dist/builder/modules/is-empty.d.ts +1 -1
  24. package/dist/index.cjs +1578 -386
  25. package/dist/index.d.ts +6 -3
  26. package/dist/index.js +1567 -384
  27. package/dist/pipeline/vqueryDSL/aggregateMap.d.ts +50 -0
  28. package/dist/pipeline/vqueryDSL/buildOrderBy.d.ts +2 -0
  29. package/dist/pipeline/vqueryDSL/index.d.ts +2 -3
  30. package/dist/pipeline/vqueryDSL/resolveDatePredicate.d.ts +7 -0
  31. package/dist/pipeline/vqueryDSL/types.d.ts +6 -6
  32. package/dist/types/builder/VBIInterface.d.ts +7 -7
  33. package/dist/types/builder/adapter.d.ts +23 -0
  34. package/dist/types/builder/build-vseed.d.ts +3 -0
  35. package/dist/types/builder/context.d.ts +2 -2
  36. package/dist/types/builder/index.d.ts +4 -2
  37. package/dist/types/builder/observe.d.ts +2 -1
  38. package/dist/types/connector/query.d.ts +1 -0
  39. package/dist/types/dsl/dimensions/aggregate.d.ts +15 -0
  40. package/dist/types/dsl/dimensions/dimensions.d.ts +62 -0
  41. package/dist/types/dsl/encoding.d.ts +2 -2
  42. package/dist/types/dsl/havingFilter/having.d.ts +20 -1
  43. package/dist/types/dsl/index.d.ts +6 -4
  44. package/dist/types/dsl/measures/aggregate.d.ts +14 -2
  45. package/dist/types/dsl/measures/measures.d.ts +177 -8
  46. package/dist/types/dsl/sort.d.ts +13 -0
  47. package/dist/types/dsl/vbi/vbi.d.ts +103 -7
  48. package/dist/types/dsl/whereFilter/date.d.ts +95 -0
  49. package/dist/types/dsl/whereFilter/filters.d.ts +142 -5
  50. package/dist/utils/filter-guards.d.ts +2 -2
  51. package/dist/vbi/create-vbi.d.ts +14 -14
  52. package/dist/vbi/from/from-vbi-dsl-input.d.ts +4 -3
  53. package/dist/vbi/from/set-base-dsl-fields.d.ts +2 -2
  54. package/dist/vbi/generate-empty-dsl.d.ts +2 -2
  55. package/dist/vbi/normalize/types.d.ts +3 -3
  56. package/dist/vbi.d.ts +1 -14
  57. package/package.json +5 -5
  58. package/dist/builder/modules/build-vquery.d.ts +0 -4
  59. package/dist/builder/modules/build-vseed.d.ts +0 -8
  60. package/dist/builder/modules/create-builder-features.d.ts +0 -14
package/dist/index.cjs CHANGED
@@ -27,16 +27,19 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  HavingFilterBuilder: ()=>HavingFilterBuilder,
28
28
  WhereFilterBuilder: ()=>WhereFilterBuilder,
29
29
  isVBIHavingGroup: ()=>isVBIHavingGroup,
30
- VBIBuilder: ()=>VBIBuilder,
30
+ resolveVBIChartBuilderAdapters: ()=>resolveVBIChartBuilderAdapters,
31
31
  VBI: ()=>VBI,
32
32
  isVBIHavingFilter: ()=>isVBIHavingFilter,
33
- findTreeNodesBy: ()=>vseed_namespaceObject.findTreeNodesBy,
34
33
  ThemeBuilder: ()=>ThemeBuilder,
34
+ findTreeNodesBy: ()=>vseed_namespaceObject.findTreeNodesBy,
35
35
  id: ()=>id_id,
36
+ createVBI: ()=>createVBI,
36
37
  MeasuresBuilder: ()=>MeasuresBuilder,
37
38
  LimitBuilder: ()=>LimitBuilder,
38
39
  DimensionsBuilder: ()=>DimensionsBuilder,
39
40
  ChartTypeBuilder: ()=>ChartTypeBuilder,
41
+ VBIChartBuilder: ()=>VBIChartBuilder,
42
+ defaultVBIChartBuilderAdapters: ()=>defaultVBIChartBuilderAdapters,
40
43
  isVBIFilter: ()=>isVBIFilter,
41
44
  isVBIWhereGroup: ()=>isVBIWhereGroup,
42
45
  preorderTraverse: ()=>vseed_namespaceObject.preorderTraverse,
@@ -55,229 +58,7 @@ const getConnector = async (id)=>{
55
58
  return connector;
56
59
  };
57
60
  const external_yjs_namespaceObject = require("yjs");
58
- const applyUpdateToDoc = (doc, update, transactionOrigin)=>{
59
- external_yjs_namespaceObject.applyUpdate(doc, update, transactionOrigin);
60
- };
61
- const encodeDocStateAsUpdate = (doc, targetStateVector)=>external_yjs_namespaceObject.encodeStateAsUpdate(doc, targetStateVector);
62
- const buildVBIDSL = (dsl)=>dsl.toJSON();
63
61
  const external_remeda_namespaceObject = require("remeda");
64
- const buildSelect = (queryDSL, context)=>{
65
- const { vbiDSL } = context;
66
- const measures = vbiDSL.measures;
67
- const dimensions = vbiDSL.dimensions;
68
- const result = {
69
- ...queryDSL
70
- };
71
- const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
72
- const measureSelects = measureNodes.map((measure)=>({
73
- field: measure.field,
74
- alias: measure.alias,
75
- aggr: measure.aggregate
76
- }));
77
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
78
- const dimensionSelects = dimensionNodes.map((dimension)=>({
79
- field: dimension.field,
80
- alias: dimension.alias
81
- }));
82
- result.select = measureSelects.concat(dimensionSelects);
83
- return result;
84
- };
85
- const buildGroupBy = (queryDSL, context)=>{
86
- const result = {
87
- ...queryDSL
88
- };
89
- const { vbiDSL } = context;
90
- const dimensions = vbiDSL.dimensions;
91
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
92
- result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
93
- return result;
94
- };
95
- const buildWhere = (queryDSL, context)=>{
96
- const { vbiDSL } = context;
97
- const whereFilter = vbiDSL.whereFilter;
98
- if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
99
- const result = {
100
- ...queryDSL
101
- };
102
- result.where = mapGroupToCondition(whereFilter);
103
- return result;
104
- };
105
- function isWhereGroup(clause) {
106
- return 'op' in clause && 'conditions' in clause;
107
- }
108
- function mapClauseToCondition(clause) {
109
- if (isWhereGroup(clause)) return [
110
- mapGroupToCondition(clause)
111
- ];
112
- return mapFilterToCondition(clause);
113
- }
114
- function mapGroupToCondition(group) {
115
- return {
116
- op: group.op,
117
- conditions: group.conditions.flatMap(mapClauseToCondition)
118
- };
119
- }
120
- function mapFilterToCondition(filter) {
121
- if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
122
- return handleSimpleFilter(filter);
123
- }
124
- function handleBetweenFilter(filter) {
125
- const value = normalizeBetweenValue(filter.value);
126
- const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
127
- field: filter.field,
128
- op: '<' === value.leftOp ? '>' : '>=',
129
- value: value.min
130
- } : void 0;
131
- const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
132
- field: filter.field,
133
- op: '<' === value.rightOp ? '<' : '<=',
134
- value: value.max
135
- } : void 0;
136
- if ('not between' === filter.op) {
137
- const outsideConditions = [
138
- lowerCondition && invertLowerBound(lowerCondition),
139
- upperCondition && invertUpperBound(upperCondition)
140
- ].filter(Boolean);
141
- if (outsideConditions.length <= 1) return outsideConditions;
142
- return [
143
- {
144
- op: 'or',
145
- conditions: outsideConditions
146
- }
147
- ];
148
- }
149
- return [
150
- lowerCondition,
151
- upperCondition
152
- ].filter(Boolean);
153
- }
154
- function normalizeBetweenValue(value) {
155
- if (Array.isArray(value)) return {
156
- min: value[0],
157
- max: value[1],
158
- leftOp: '<=',
159
- rightOp: '<='
160
- };
161
- if ('object' == typeof value && null !== value) return value;
162
- return {};
163
- }
164
- function invertLowerBound(condition) {
165
- return {
166
- field: condition.field,
167
- op: '>' === condition.op ? '<=' : '<',
168
- value: condition.value
169
- };
170
- }
171
- function invertUpperBound(condition) {
172
- return {
173
- field: condition.field,
174
- op: '<' === condition.op ? '>=' : '>',
175
- value: condition.value
176
- };
177
- }
178
- function handleSimpleFilter(filter) {
179
- let mappedOp = filter.op ?? '=';
180
- const value = filter.value;
181
- if (Array.isArray(value)) {
182
- if ('=' === mappedOp) mappedOp = 'in';
183
- if ('!=' === mappedOp) mappedOp = 'not in';
184
- }
185
- return [
186
- {
187
- field: filter.field,
188
- op: mappedOp,
189
- value
190
- }
191
- ];
192
- }
193
- const buildHaving = (queryDSL, context)=>{
194
- const { vbiDSL } = context;
195
- const havingFilter = vbiDSL.havingFilter;
196
- if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
197
- const result = {
198
- ...queryDSL
199
- };
200
- result.having = {
201
- op: havingFilter.op,
202
- conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
203
- };
204
- return result;
205
- };
206
- function isHavingGroup(clause) {
207
- return 'op' in clause && 'conditions' in clause;
208
- }
209
- function buildHaving_mapClauseToCondition(clause) {
210
- if (isHavingGroup(clause)) return [
211
- buildHaving_mapGroupToCondition(clause)
212
- ];
213
- return buildHaving_mapFilterToCondition(clause);
214
- }
215
- function buildHaving_mapGroupToCondition(group) {
216
- return {
217
- op: group.op,
218
- conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
219
- };
220
- }
221
- function buildHaving_mapFilterToCondition(filter) {
222
- const mappedOp = filter.op ?? '=';
223
- return [
224
- {
225
- field: filter.field,
226
- op: mappedOp,
227
- value: filter.value
228
- }
229
- ];
230
- }
231
- const buildLimit = (queryDSL, context)=>{
232
- const result = {
233
- ...queryDSL
234
- };
235
- const limit = context.vbiDSL.limit ?? 1000;
236
- result.limit = limit;
237
- return result;
238
- };
239
- const buildVQuery = (vbiDSL, builder)=>{
240
- const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
241
- vbiDSL,
242
- builder
243
- });
244
- return (0, external_remeda_namespaceObject.pipe)({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
245
- };
246
- const buildVQueryDSL = (dsl, builder)=>{
247
- const vbiDSL = buildVBIDSL(dsl);
248
- return buildVQuery(vbiDSL, builder);
249
- };
250
- const buildVSeedDSL = async ({ vbiDSL, queryDSL })=>{
251
- const connectorId = vbiDSL.connectorId;
252
- const connector = await getConnector(connectorId);
253
- const schema = await connector.discoverSchema();
254
- const queryResult = await connector.query({
255
- queryDSL,
256
- schema,
257
- connectorId
258
- });
259
- return {
260
- chartType: vbiDSL.chartType,
261
- dataset: queryResult.dataset,
262
- theme: vbiDSL.theme,
263
- locale: vbiDSL.locale
264
- };
265
- };
266
- const getCollectionLength = (value)=>{
267
- if (value instanceof external_yjs_namespaceObject.Array) return value.length;
268
- if (Array.isArray(value)) return value.length;
269
- return 0;
270
- };
271
- const isEmptyVBIDSL = (dsl)=>{
272
- const dimensionsLength = getCollectionLength(dsl.get('dimensions'));
273
- const measuresLength = getCollectionLength(dsl.get('measures'));
274
- return 0 === dimensionsLength && 0 === measuresLength;
275
- };
276
- const getBuilderSchema = async (dsl)=>{
277
- const connectorId = dsl.get('connectorId');
278
- const connector = await getConnector(connectorId);
279
- return connector.discoverSchema();
280
- };
281
62
  class MeasureNodeBuilder {
282
63
  yMap;
283
64
  constructor(yMap){
@@ -289,6 +70,12 @@ class MeasureNodeBuilder {
289
70
  getField() {
290
71
  return this.yMap.get('field');
291
72
  }
73
+ getEncoding() {
74
+ return this.yMap.get('encoding');
75
+ }
76
+ getSort() {
77
+ return this.yMap.get('sort');
78
+ }
292
79
  setAlias(alias) {
293
80
  this.yMap.set('alias', alias);
294
81
  return this;
@@ -297,10 +84,29 @@ class MeasureNodeBuilder {
297
84
  this.yMap.set('encoding', encoding);
298
85
  return this;
299
86
  }
87
+ setSort(sort) {
88
+ this.yMap.set('sort', sort);
89
+ return this;
90
+ }
300
91
  setAggregate(aggregate) {
301
92
  this.yMap.set('aggregate', aggregate);
302
93
  return this;
303
94
  }
95
+ setFormat(format) {
96
+ this.yMap.set('format', format);
97
+ return this;
98
+ }
99
+ getFormat() {
100
+ return this.yMap.get('format');
101
+ }
102
+ clearFormat() {
103
+ this.yMap.delete('format');
104
+ return this;
105
+ }
106
+ clearSort() {
107
+ this.yMap.delete('sort');
108
+ return this;
109
+ }
304
110
  toJSON() {
305
111
  return this.yMap.toJSON();
306
112
  }
@@ -335,9 +141,369 @@ const normalizeMeasureNodeIds = (measures)=>{
335
141
  });
336
142
  };
337
143
  const locateMeasureIndexById = (measures, measureId)=>measures.toArray().findIndex((item)=>item.get('id') === measureId);
144
+ const MEASURE_ENCODING_SUPPORT = {
145
+ table: [
146
+ 'column'
147
+ ],
148
+ pivotTable: [
149
+ 'detail'
150
+ ],
151
+ column: [
152
+ 'yAxis',
153
+ 'detail',
154
+ 'color',
155
+ 'label',
156
+ 'tooltip'
157
+ ],
158
+ columnParallel: [
159
+ 'yAxis',
160
+ 'detail',
161
+ 'color',
162
+ 'label',
163
+ 'tooltip'
164
+ ],
165
+ columnPercent: [
166
+ 'yAxis',
167
+ 'detail',
168
+ 'color',
169
+ 'label',
170
+ 'tooltip'
171
+ ],
172
+ line: [
173
+ 'yAxis',
174
+ 'detail',
175
+ 'color',
176
+ 'label',
177
+ 'tooltip'
178
+ ],
179
+ area: [
180
+ 'yAxis',
181
+ 'detail',
182
+ 'color',
183
+ 'label',
184
+ 'tooltip'
185
+ ],
186
+ areaPercent: [
187
+ 'yAxis',
188
+ 'detail',
189
+ 'color',
190
+ 'label',
191
+ 'tooltip'
192
+ ],
193
+ bar: [
194
+ 'xAxis',
195
+ 'detail',
196
+ 'color',
197
+ 'label',
198
+ 'tooltip'
199
+ ],
200
+ barParallel: [
201
+ 'xAxis',
202
+ 'detail',
203
+ 'color',
204
+ 'label',
205
+ 'tooltip'
206
+ ],
207
+ barPercent: [
208
+ 'xAxis',
209
+ 'detail',
210
+ 'color',
211
+ 'label',
212
+ 'tooltip'
213
+ ],
214
+ dualAxis: [
215
+ 'primaryYAxis',
216
+ 'secondaryYAxis',
217
+ 'color',
218
+ 'label',
219
+ 'tooltip'
220
+ ],
221
+ scatter: [
222
+ 'xAxis',
223
+ 'yAxis',
224
+ 'size',
225
+ 'color',
226
+ 'label',
227
+ 'tooltip'
228
+ ],
229
+ pie: [
230
+ 'angle',
231
+ 'detail',
232
+ 'color',
233
+ 'label',
234
+ 'tooltip'
235
+ ],
236
+ donut: [
237
+ 'angle',
238
+ 'detail',
239
+ 'color',
240
+ 'label',
241
+ 'tooltip'
242
+ ],
243
+ rose: [
244
+ 'radius',
245
+ 'detail',
246
+ 'color',
247
+ 'label',
248
+ 'tooltip'
249
+ ],
250
+ roseParallel: [
251
+ 'radius',
252
+ 'detail',
253
+ 'color',
254
+ 'label',
255
+ 'tooltip'
256
+ ],
257
+ radar: [
258
+ 'radius',
259
+ 'detail',
260
+ 'color',
261
+ 'label',
262
+ 'tooltip'
263
+ ],
264
+ funnel: [
265
+ 'size',
266
+ 'detail',
267
+ 'color',
268
+ 'label',
269
+ 'tooltip'
270
+ ],
271
+ heatmap: [
272
+ 'color',
273
+ 'detail',
274
+ 'label',
275
+ 'tooltip'
276
+ ],
277
+ histogram: [
278
+ 'value',
279
+ 'x0',
280
+ 'x1',
281
+ 'yAxis',
282
+ 'detail',
283
+ 'color',
284
+ 'label',
285
+ 'tooltip'
286
+ ],
287
+ boxplot: [
288
+ 'value',
289
+ 'q1',
290
+ 'q3',
291
+ 'min',
292
+ 'max',
293
+ 'median',
294
+ 'outliers',
295
+ 'color',
296
+ 'label',
297
+ 'tooltip'
298
+ ],
299
+ treeMap: [
300
+ 'size',
301
+ 'detail',
302
+ 'color',
303
+ 'label',
304
+ 'tooltip'
305
+ ],
306
+ sunburst: [
307
+ 'size',
308
+ 'detail',
309
+ 'color',
310
+ 'label',
311
+ 'tooltip'
312
+ ],
313
+ circlePacking: [
314
+ 'size',
315
+ 'detail',
316
+ 'color',
317
+ 'label',
318
+ 'tooltip'
319
+ ],
320
+ raceBar: [
321
+ 'xAxis',
322
+ 'detail',
323
+ 'color',
324
+ 'label',
325
+ 'tooltip'
326
+ ],
327
+ raceColumn: [
328
+ 'yAxis',
329
+ 'detail',
330
+ 'color',
331
+ 'label',
332
+ 'tooltip'
333
+ ],
334
+ raceLine: [
335
+ 'yAxis',
336
+ 'detail',
337
+ 'color',
338
+ 'label',
339
+ 'tooltip'
340
+ ],
341
+ raceScatter: [
342
+ 'xAxis',
343
+ 'yAxis',
344
+ 'size',
345
+ 'color',
346
+ 'label',
347
+ 'tooltip'
348
+ ],
349
+ racePie: [
350
+ 'angle',
351
+ 'detail',
352
+ 'color',
353
+ 'label',
354
+ 'tooltip'
355
+ ],
356
+ raceDonut: [
357
+ 'angle',
358
+ 'detail',
359
+ 'color',
360
+ 'label',
361
+ 'tooltip'
362
+ ]
363
+ };
364
+ const repeatEncoding = (first, rest = first)=>(index)=>0 === index ? first : rest;
365
+ const STRATEGY_BY_CHART_TYPE = {
366
+ [vseed_namespaceObject.ChartTypeEnum.Table]: {
367
+ supported: MEASURE_ENCODING_SUPPORT.table,
368
+ recommend: repeatEncoding('column')
369
+ },
370
+ [vseed_namespaceObject.ChartTypeEnum.PivotTable]: {
371
+ supported: MEASURE_ENCODING_SUPPORT.pivotTable,
372
+ recommend: repeatEncoding('detail')
373
+ },
374
+ [vseed_namespaceObject.ChartTypeEnum.Column]: {
375
+ supported: MEASURE_ENCODING_SUPPORT.column,
376
+ recommend: repeatEncoding('yAxis')
377
+ },
378
+ [vseed_namespaceObject.ChartTypeEnum.ColumnParallel]: {
379
+ supported: MEASURE_ENCODING_SUPPORT.columnParallel,
380
+ recommend: repeatEncoding('yAxis')
381
+ },
382
+ [vseed_namespaceObject.ChartTypeEnum.ColumnPercent]: {
383
+ supported: MEASURE_ENCODING_SUPPORT.columnPercent,
384
+ recommend: repeatEncoding('yAxis')
385
+ },
386
+ [vseed_namespaceObject.ChartTypeEnum.Line]: {
387
+ supported: MEASURE_ENCODING_SUPPORT.line,
388
+ recommend: repeatEncoding('yAxis')
389
+ },
390
+ [vseed_namespaceObject.ChartTypeEnum.Area]: {
391
+ supported: MEASURE_ENCODING_SUPPORT.area,
392
+ recommend: repeatEncoding('yAxis')
393
+ },
394
+ [vseed_namespaceObject.ChartTypeEnum.AreaPercent]: {
395
+ supported: MEASURE_ENCODING_SUPPORT.areaPercent,
396
+ recommend: repeatEncoding('yAxis')
397
+ },
398
+ [vseed_namespaceObject.ChartTypeEnum.Bar]: {
399
+ supported: MEASURE_ENCODING_SUPPORT.bar,
400
+ recommend: repeatEncoding('xAxis')
401
+ },
402
+ [vseed_namespaceObject.ChartTypeEnum.BarParallel]: {
403
+ supported: MEASURE_ENCODING_SUPPORT.barParallel,
404
+ recommend: repeatEncoding('xAxis')
405
+ },
406
+ [vseed_namespaceObject.ChartTypeEnum.BarPercent]: {
407
+ supported: MEASURE_ENCODING_SUPPORT.barPercent,
408
+ recommend: repeatEncoding('xAxis')
409
+ },
410
+ [vseed_namespaceObject.ChartTypeEnum.DualAxis]: {
411
+ supported: MEASURE_ENCODING_SUPPORT.dualAxis,
412
+ recommend: (index)=>0 === index ? 'primaryYAxis' : 'secondaryYAxis'
413
+ },
414
+ [vseed_namespaceObject.ChartTypeEnum.Scatter]: {
415
+ supported: MEASURE_ENCODING_SUPPORT.scatter,
416
+ recommend: (index)=>0 === index ? 'xAxis' : 'yAxis'
417
+ },
418
+ [vseed_namespaceObject.ChartTypeEnum.Pie]: {
419
+ supported: MEASURE_ENCODING_SUPPORT.pie,
420
+ recommend: repeatEncoding('angle')
421
+ },
422
+ [vseed_namespaceObject.ChartTypeEnum.Donut]: {
423
+ supported: MEASURE_ENCODING_SUPPORT.donut,
424
+ recommend: repeatEncoding('angle')
425
+ },
426
+ [vseed_namespaceObject.ChartTypeEnum.Rose]: {
427
+ supported: MEASURE_ENCODING_SUPPORT.rose,
428
+ recommend: repeatEncoding('radius')
429
+ },
430
+ [vseed_namespaceObject.ChartTypeEnum.RoseParallel]: {
431
+ supported: MEASURE_ENCODING_SUPPORT.roseParallel,
432
+ recommend: repeatEncoding('radius')
433
+ },
434
+ [vseed_namespaceObject.ChartTypeEnum.Radar]: {
435
+ supported: MEASURE_ENCODING_SUPPORT.radar,
436
+ recommend: repeatEncoding('radius')
437
+ },
438
+ [vseed_namespaceObject.ChartTypeEnum.Funnel]: {
439
+ supported: MEASURE_ENCODING_SUPPORT.funnel,
440
+ recommend: repeatEncoding('size')
441
+ },
442
+ [vseed_namespaceObject.ChartTypeEnum.Heatmap]: {
443
+ supported: MEASURE_ENCODING_SUPPORT.heatmap,
444
+ recommend: repeatEncoding('color')
445
+ },
446
+ [vseed_namespaceObject.ChartTypeEnum.Histogram]: {
447
+ supported: MEASURE_ENCODING_SUPPORT.histogram,
448
+ recommend: repeatEncoding('value')
449
+ },
450
+ [vseed_namespaceObject.ChartTypeEnum.Boxplot]: {
451
+ supported: MEASURE_ENCODING_SUPPORT.boxplot,
452
+ recommend: repeatEncoding('value')
453
+ },
454
+ [vseed_namespaceObject.ChartTypeEnum.TreeMap]: {
455
+ supported: MEASURE_ENCODING_SUPPORT.treeMap,
456
+ recommend: repeatEncoding('size')
457
+ },
458
+ [vseed_namespaceObject.ChartTypeEnum.Sunburst]: {
459
+ supported: MEASURE_ENCODING_SUPPORT.sunburst,
460
+ recommend: repeatEncoding('size')
461
+ },
462
+ [vseed_namespaceObject.ChartTypeEnum.CirclePacking]: {
463
+ supported: MEASURE_ENCODING_SUPPORT.circlePacking,
464
+ recommend: repeatEncoding('size')
465
+ },
466
+ [vseed_namespaceObject.ChartTypeEnum.RaceBar]: {
467
+ supported: MEASURE_ENCODING_SUPPORT.raceBar,
468
+ recommend: repeatEncoding('xAxis')
469
+ },
470
+ [vseed_namespaceObject.ChartTypeEnum.RaceColumn]: {
471
+ supported: MEASURE_ENCODING_SUPPORT.raceColumn,
472
+ recommend: repeatEncoding('yAxis')
473
+ },
474
+ [vseed_namespaceObject.ChartTypeEnum.RaceLine]: {
475
+ supported: MEASURE_ENCODING_SUPPORT.raceLine,
476
+ recommend: repeatEncoding('yAxis')
477
+ },
478
+ [vseed_namespaceObject.ChartTypeEnum.RaceScatter]: {
479
+ supported: MEASURE_ENCODING_SUPPORT.raceScatter,
480
+ recommend: (index)=>0 === index ? 'xAxis' : 'yAxis'
481
+ },
482
+ [vseed_namespaceObject.ChartTypeEnum.RacePie]: {
483
+ supported: MEASURE_ENCODING_SUPPORT.racePie,
484
+ recommend: repeatEncoding('angle')
485
+ },
486
+ [vseed_namespaceObject.ChartTypeEnum.RaceDonut]: {
487
+ supported: MEASURE_ENCODING_SUPPORT.raceDonut,
488
+ recommend: repeatEncoding('angle')
489
+ }
490
+ };
491
+ const DEFAULT_STRATEGY = STRATEGY_BY_CHART_TYPE[vseed_namespaceObject.ChartTypeEnum.Table];
492
+ const getSupportedMeasureEncodingsForChartType = (chartType)=>[
493
+ ...(STRATEGY_BY_CHART_TYPE[chartType] || DEFAULT_STRATEGY).supported
494
+ ];
495
+ const getRecommendedMeasureEncodingsForChartType = (chartType, measureCount)=>{
496
+ const strategy = STRATEGY_BY_CHART_TYPE[chartType] || DEFAULT_STRATEGY;
497
+ if (measureCount <= 0) return [];
498
+ return Array.from({
499
+ length: measureCount
500
+ }, (_, index)=>strategy.recommend(index));
501
+ };
338
502
  class MeasuresBuilder {
503
+ doc;
339
504
  dsl;
340
505
  constructor(doc, dsl){
506
+ this.doc = doc;
341
507
  this.dsl = dsl;
342
508
  doc.transact(()=>{
343
509
  const measures = getOrCreateMeasures(this.dsl);
@@ -345,38 +511,47 @@ class MeasuresBuilder {
345
511
  });
346
512
  }
347
513
  add(field, callback) {
514
+ const measures = getOrCreateMeasures(this.dsl);
515
+ const chartType = this.dsl.get('chartType') || 'table';
516
+ const [encoding] = getRecommendedMeasureEncodingsForChartType(chartType, measures.length + 1).slice(-1);
348
517
  const measure = {
349
518
  id: id_id.uuid(),
350
519
  alias: field,
351
520
  field,
352
- encoding: 'yAxis',
521
+ encoding,
353
522
  aggregate: {
354
523
  func: 'sum'
355
524
  }
356
525
  };
357
526
  const yMap = new external_yjs_namespaceObject.Map();
358
- for (const [key, value] of Object.entries(measure))yMap.set(key, value);
359
- const measures = getOrCreateMeasures(this.dsl);
360
- measures.push([
361
- yMap
362
- ]);
363
- const node = new MeasureNodeBuilder(yMap);
364
- callback(node);
527
+ this.doc.transact(()=>{
528
+ for (const [key, value] of Object.entries(measure))yMap.set(key, value);
529
+ const measures = getOrCreateMeasures(this.dsl);
530
+ measures.push([
531
+ yMap
532
+ ]);
533
+ const node = new MeasureNodeBuilder(yMap);
534
+ callback(node);
535
+ });
365
536
  return this;
366
537
  }
367
538
  remove(id) {
368
- const measures = getOrCreateMeasures(this.dsl);
369
- const index = locateMeasureIndexById(measures, id);
370
- if (-1 !== index) measures.delete(index, 1);
539
+ this.doc.transact(()=>{
540
+ const measures = getOrCreateMeasures(this.dsl);
541
+ const index = locateMeasureIndexById(measures, id);
542
+ if (-1 !== index) measures.delete(index, 1);
543
+ });
371
544
  return this;
372
545
  }
373
546
  update(id, callback) {
374
- const measures = getOrCreateMeasures(this.dsl);
375
- const index = locateMeasureIndexById(measures, id);
376
- if (-1 === index) throw new Error(`Measure with id "${id}" not found`);
377
- const measureYMap = measures.get(index);
378
- const node = new MeasureNodeBuilder(measureYMap);
379
- callback(node);
547
+ this.doc.transact(()=>{
548
+ const measures = getOrCreateMeasures(this.dsl);
549
+ const index = locateMeasureIndexById(measures, id);
550
+ if (-1 === index) throw new Error(`Measure with id "${id}" not found`);
551
+ const measureYMap = measures.get(index);
552
+ const node = new MeasureNodeBuilder(measureYMap);
553
+ callback(node);
554
+ });
380
555
  return this;
381
556
  }
382
557
  find(predicate) {
@@ -397,9 +572,9 @@ class MeasuresBuilder {
397
572
  }
398
573
  observe(callback) {
399
574
  const measures = getOrCreateMeasures(this.dsl);
400
- measures.observe(callback);
575
+ measures.observeDeep(callback);
401
576
  return ()=>{
402
- measures.unobserve(callback);
577
+ measures.unobserveDeep(callback);
403
578
  };
404
579
  }
405
580
  static isMeasureNode(node) {
@@ -420,10 +595,36 @@ class DimensionNodeBuilder {
420
595
  getField() {
421
596
  return this.yMap.get('field');
422
597
  }
598
+ getEncoding() {
599
+ return this.yMap.get('encoding');
600
+ }
601
+ getSort() {
602
+ return this.yMap.get('sort');
603
+ }
423
604
  setAlias(alias) {
424
605
  this.yMap.set('alias', alias);
425
606
  return this;
426
607
  }
608
+ setEncoding(encoding) {
609
+ this.yMap.set('encoding', encoding);
610
+ return this;
611
+ }
612
+ setSort(sort) {
613
+ this.yMap.set('sort', sort);
614
+ return this;
615
+ }
616
+ setAggregate(aggregate) {
617
+ this.yMap.set('aggregate', aggregate);
618
+ return this;
619
+ }
620
+ clearAggregate() {
621
+ this.yMap.delete('aggregate');
622
+ return this;
623
+ }
624
+ clearSort() {
625
+ this.yMap.delete('sort');
626
+ return this;
627
+ }
427
628
  toJSON() {
428
629
  return this.yMap.toJSON();
429
630
  }
@@ -441,9 +642,423 @@ const normalizeDimensionNodeIds = (dimensions)=>{
441
642
  });
442
643
  };
443
644
  const locateDimensionIndexById = (dimensions, dimensionId)=>dimensions.toArray().findIndex((item)=>item.get('id') === dimensionId);
444
- class DimensionsBuilder {
445
- dsl;
446
- constructor(doc, dsl){
645
+ const DIMENSION_ENCODING_SUPPORT = {
646
+ table: [
647
+ 'column'
648
+ ],
649
+ pivotTable: [
650
+ 'row',
651
+ 'column'
652
+ ],
653
+ column: [
654
+ 'xAxis',
655
+ 'color',
656
+ 'detail',
657
+ 'tooltip',
658
+ 'label',
659
+ 'row',
660
+ 'column'
661
+ ],
662
+ columnParallel: [
663
+ 'xAxis',
664
+ 'color',
665
+ 'detail',
666
+ 'tooltip',
667
+ 'label',
668
+ 'row',
669
+ 'column'
670
+ ],
671
+ columnPercent: [
672
+ 'xAxis',
673
+ 'color',
674
+ 'detail',
675
+ 'tooltip',
676
+ 'label',
677
+ 'row',
678
+ 'column'
679
+ ],
680
+ line: [
681
+ 'xAxis',
682
+ 'color',
683
+ 'detail',
684
+ 'tooltip',
685
+ 'label',
686
+ 'row',
687
+ 'column'
688
+ ],
689
+ area: [
690
+ 'xAxis',
691
+ 'color',
692
+ 'detail',
693
+ 'tooltip',
694
+ 'label',
695
+ 'row',
696
+ 'column'
697
+ ],
698
+ areaPercent: [
699
+ 'xAxis',
700
+ 'color',
701
+ 'detail',
702
+ 'tooltip',
703
+ 'label',
704
+ 'row',
705
+ 'column'
706
+ ],
707
+ dualAxis: [
708
+ 'xAxis',
709
+ 'color',
710
+ 'detail',
711
+ 'tooltip',
712
+ 'label',
713
+ 'row',
714
+ 'column'
715
+ ],
716
+ bar: [
717
+ 'yAxis',
718
+ 'color',
719
+ 'detail',
720
+ 'tooltip',
721
+ 'label',
722
+ 'row',
723
+ 'column'
724
+ ],
725
+ barParallel: [
726
+ 'yAxis',
727
+ 'color',
728
+ 'detail',
729
+ 'tooltip',
730
+ 'label',
731
+ 'row',
732
+ 'column'
733
+ ],
734
+ barPercent: [
735
+ 'yAxis',
736
+ 'color',
737
+ 'detail',
738
+ 'tooltip',
739
+ 'label',
740
+ 'row',
741
+ 'column'
742
+ ],
743
+ pie: [
744
+ 'color',
745
+ 'detail',
746
+ 'tooltip',
747
+ 'label',
748
+ 'row',
749
+ 'column'
750
+ ],
751
+ donut: [
752
+ 'color',
753
+ 'detail',
754
+ 'tooltip',
755
+ 'label',
756
+ 'row',
757
+ 'column'
758
+ ],
759
+ funnel: [
760
+ 'color',
761
+ 'detail',
762
+ 'tooltip',
763
+ 'label',
764
+ 'row',
765
+ 'column'
766
+ ],
767
+ scatter: [
768
+ 'color',
769
+ 'detail',
770
+ 'tooltip',
771
+ 'label',
772
+ 'row',
773
+ 'column'
774
+ ],
775
+ rose: [
776
+ 'angle',
777
+ 'color',
778
+ 'detail',
779
+ 'tooltip',
780
+ 'label',
781
+ 'row',
782
+ 'column'
783
+ ],
784
+ roseParallel: [
785
+ 'angle',
786
+ 'color',
787
+ 'detail',
788
+ 'tooltip',
789
+ 'label',
790
+ 'row',
791
+ 'column'
792
+ ],
793
+ radar: [
794
+ 'angle',
795
+ 'color',
796
+ 'detail',
797
+ 'tooltip',
798
+ 'label',
799
+ 'row',
800
+ 'column'
801
+ ],
802
+ heatmap: [
803
+ 'xAxis',
804
+ 'yAxis',
805
+ 'color',
806
+ 'detail',
807
+ 'tooltip',
808
+ 'label',
809
+ 'row',
810
+ 'column'
811
+ ],
812
+ boxplot: [
813
+ 'xAxis',
814
+ 'color',
815
+ 'tooltip',
816
+ 'label',
817
+ 'row',
818
+ 'column'
819
+ ],
820
+ histogram: [
821
+ 'color',
822
+ 'detail',
823
+ 'tooltip',
824
+ 'label',
825
+ 'row',
826
+ 'column'
827
+ ],
828
+ treeMap: [
829
+ 'hierarchy',
830
+ 'detail',
831
+ 'tooltip',
832
+ 'label',
833
+ 'row',
834
+ 'column'
835
+ ],
836
+ sunburst: [
837
+ 'hierarchy',
838
+ 'detail',
839
+ 'tooltip',
840
+ 'label',
841
+ 'row',
842
+ 'column'
843
+ ],
844
+ circlePacking: [
845
+ 'hierarchy',
846
+ 'detail',
847
+ 'tooltip',
848
+ 'label',
849
+ 'row',
850
+ 'column'
851
+ ],
852
+ raceBar: [
853
+ 'player',
854
+ 'yAxis',
855
+ 'color',
856
+ 'detail',
857
+ 'tooltip',
858
+ 'label',
859
+ 'row',
860
+ 'column'
861
+ ],
862
+ raceColumn: [
863
+ 'player',
864
+ 'xAxis',
865
+ 'color',
866
+ 'detail',
867
+ 'tooltip',
868
+ 'label',
869
+ 'row',
870
+ 'column'
871
+ ],
872
+ raceLine: [
873
+ 'player',
874
+ 'xAxis',
875
+ 'color',
876
+ 'detail',
877
+ 'tooltip',
878
+ 'label',
879
+ 'row',
880
+ 'column'
881
+ ],
882
+ raceScatter: [
883
+ 'player',
884
+ 'color',
885
+ 'detail',
886
+ 'tooltip',
887
+ 'label',
888
+ 'row',
889
+ 'column'
890
+ ],
891
+ racePie: [
892
+ 'player',
893
+ 'color',
894
+ 'detail',
895
+ 'tooltip',
896
+ 'label',
897
+ 'row',
898
+ 'column'
899
+ ],
900
+ raceDonut: [
901
+ 'player',
902
+ 'color',
903
+ 'detail',
904
+ 'tooltip',
905
+ 'label',
906
+ 'row',
907
+ 'column'
908
+ ]
909
+ };
910
+ const dimension_encoding_repeatEncoding = (first, rest = first)=>(index)=>0 === index ? first : rest;
911
+ const alternateEncoding = (a, b)=>(index)=>index % 2 === 0 ? a : b;
912
+ const dimension_encoding_STRATEGY_BY_CHART_TYPE = {
913
+ [vseed_namespaceObject.ChartTypeEnum.Table]: {
914
+ supported: DIMENSION_ENCODING_SUPPORT.table,
915
+ recommend: dimension_encoding_repeatEncoding('column')
916
+ },
917
+ [vseed_namespaceObject.ChartTypeEnum.PivotTable]: {
918
+ supported: DIMENSION_ENCODING_SUPPORT.pivotTable,
919
+ recommend: alternateEncoding('column', 'row')
920
+ },
921
+ [vseed_namespaceObject.ChartTypeEnum.Column]: {
922
+ supported: DIMENSION_ENCODING_SUPPORT.column,
923
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
924
+ },
925
+ [vseed_namespaceObject.ChartTypeEnum.ColumnParallel]: {
926
+ supported: DIMENSION_ENCODING_SUPPORT.columnParallel,
927
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
928
+ },
929
+ [vseed_namespaceObject.ChartTypeEnum.ColumnPercent]: {
930
+ supported: DIMENSION_ENCODING_SUPPORT.columnPercent,
931
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
932
+ },
933
+ [vseed_namespaceObject.ChartTypeEnum.Line]: {
934
+ supported: DIMENSION_ENCODING_SUPPORT.line,
935
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
936
+ },
937
+ [vseed_namespaceObject.ChartTypeEnum.Area]: {
938
+ supported: DIMENSION_ENCODING_SUPPORT.area,
939
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
940
+ },
941
+ [vseed_namespaceObject.ChartTypeEnum.AreaPercent]: {
942
+ supported: DIMENSION_ENCODING_SUPPORT.areaPercent,
943
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
944
+ },
945
+ [vseed_namespaceObject.ChartTypeEnum.DualAxis]: {
946
+ supported: DIMENSION_ENCODING_SUPPORT.dualAxis,
947
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
948
+ },
949
+ [vseed_namespaceObject.ChartTypeEnum.Bar]: {
950
+ supported: DIMENSION_ENCODING_SUPPORT.bar,
951
+ recommend: dimension_encoding_repeatEncoding('yAxis', 'color')
952
+ },
953
+ [vseed_namespaceObject.ChartTypeEnum.BarParallel]: {
954
+ supported: DIMENSION_ENCODING_SUPPORT.barParallel,
955
+ recommend: dimension_encoding_repeatEncoding('yAxis', 'color')
956
+ },
957
+ [vseed_namespaceObject.ChartTypeEnum.BarPercent]: {
958
+ supported: DIMENSION_ENCODING_SUPPORT.barPercent,
959
+ recommend: dimension_encoding_repeatEncoding('yAxis', 'color')
960
+ },
961
+ [vseed_namespaceObject.ChartTypeEnum.Pie]: {
962
+ supported: DIMENSION_ENCODING_SUPPORT.pie,
963
+ recommend: dimension_encoding_repeatEncoding('color')
964
+ },
965
+ [vseed_namespaceObject.ChartTypeEnum.Donut]: {
966
+ supported: DIMENSION_ENCODING_SUPPORT.donut,
967
+ recommend: dimension_encoding_repeatEncoding('color')
968
+ },
969
+ [vseed_namespaceObject.ChartTypeEnum.Funnel]: {
970
+ supported: DIMENSION_ENCODING_SUPPORT.funnel,
971
+ recommend: dimension_encoding_repeatEncoding('color')
972
+ },
973
+ [vseed_namespaceObject.ChartTypeEnum.Scatter]: {
974
+ supported: DIMENSION_ENCODING_SUPPORT.scatter,
975
+ recommend: dimension_encoding_repeatEncoding('color')
976
+ },
977
+ [vseed_namespaceObject.ChartTypeEnum.Rose]: {
978
+ supported: DIMENSION_ENCODING_SUPPORT.rose,
979
+ recommend: dimension_encoding_repeatEncoding('angle', 'color')
980
+ },
981
+ [vseed_namespaceObject.ChartTypeEnum.RoseParallel]: {
982
+ supported: DIMENSION_ENCODING_SUPPORT.roseParallel,
983
+ recommend: dimension_encoding_repeatEncoding('angle', 'color')
984
+ },
985
+ [vseed_namespaceObject.ChartTypeEnum.Radar]: {
986
+ supported: DIMENSION_ENCODING_SUPPORT.radar,
987
+ recommend: dimension_encoding_repeatEncoding('angle', 'color')
988
+ },
989
+ [vseed_namespaceObject.ChartTypeEnum.Heatmap]: {
990
+ supported: DIMENSION_ENCODING_SUPPORT.heatmap,
991
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'yAxis')
992
+ },
993
+ [vseed_namespaceObject.ChartTypeEnum.Boxplot]: {
994
+ supported: DIMENSION_ENCODING_SUPPORT.boxplot,
995
+ recommend: dimension_encoding_repeatEncoding('xAxis', 'color')
996
+ },
997
+ [vseed_namespaceObject.ChartTypeEnum.Histogram]: {
998
+ supported: DIMENSION_ENCODING_SUPPORT.histogram,
999
+ recommend: dimension_encoding_repeatEncoding('color')
1000
+ },
1001
+ [vseed_namespaceObject.ChartTypeEnum.TreeMap]: {
1002
+ supported: DIMENSION_ENCODING_SUPPORT.treeMap,
1003
+ recommend: dimension_encoding_repeatEncoding('hierarchy')
1004
+ },
1005
+ [vseed_namespaceObject.ChartTypeEnum.Sunburst]: {
1006
+ supported: DIMENSION_ENCODING_SUPPORT.sunburst,
1007
+ recommend: dimension_encoding_repeatEncoding('hierarchy')
1008
+ },
1009
+ [vseed_namespaceObject.ChartTypeEnum.CirclePacking]: {
1010
+ supported: DIMENSION_ENCODING_SUPPORT.circlePacking,
1011
+ recommend: dimension_encoding_repeatEncoding('hierarchy')
1012
+ },
1013
+ [vseed_namespaceObject.ChartTypeEnum.RaceBar]: {
1014
+ supported: DIMENSION_ENCODING_SUPPORT.raceBar,
1015
+ recommend: (index)=>{
1016
+ if (0 === index) return 'player';
1017
+ if (1 === index) return 'yAxis';
1018
+ return 'color';
1019
+ }
1020
+ },
1021
+ [vseed_namespaceObject.ChartTypeEnum.RaceColumn]: {
1022
+ supported: DIMENSION_ENCODING_SUPPORT.raceColumn,
1023
+ recommend: (index)=>{
1024
+ if (0 === index) return 'player';
1025
+ if (1 === index) return 'xAxis';
1026
+ return 'color';
1027
+ }
1028
+ },
1029
+ [vseed_namespaceObject.ChartTypeEnum.RaceLine]: {
1030
+ supported: DIMENSION_ENCODING_SUPPORT.raceLine,
1031
+ recommend: (index)=>0 === index ? 'player' : 'color'
1032
+ },
1033
+ [vseed_namespaceObject.ChartTypeEnum.RaceScatter]: {
1034
+ supported: DIMENSION_ENCODING_SUPPORT.raceScatter,
1035
+ recommend: (index)=>0 === index ? 'player' : 'color'
1036
+ },
1037
+ [vseed_namespaceObject.ChartTypeEnum.RacePie]: {
1038
+ supported: DIMENSION_ENCODING_SUPPORT.racePie,
1039
+ recommend: (index)=>0 === index ? 'player' : 'color'
1040
+ },
1041
+ [vseed_namespaceObject.ChartTypeEnum.RaceDonut]: {
1042
+ supported: DIMENSION_ENCODING_SUPPORT.raceDonut,
1043
+ recommend: (index)=>0 === index ? 'player' : 'color'
1044
+ }
1045
+ };
1046
+ const dimension_encoding_DEFAULT_STRATEGY = dimension_encoding_STRATEGY_BY_CHART_TYPE[vseed_namespaceObject.ChartTypeEnum.Table];
1047
+ const getSupportedDimensionEncodingsForChartType = (chartType)=>[
1048
+ ...(dimension_encoding_STRATEGY_BY_CHART_TYPE[chartType] || dimension_encoding_DEFAULT_STRATEGY).supported
1049
+ ];
1050
+ const getRecommendedDimensionEncodingsForChartType = (chartType, dimensionCount)=>{
1051
+ const strategy = dimension_encoding_STRATEGY_BY_CHART_TYPE[chartType] || dimension_encoding_DEFAULT_STRATEGY;
1052
+ if (dimensionCount <= 0) return [];
1053
+ return Array.from({
1054
+ length: dimensionCount
1055
+ }, (_, index)=>strategy.recommend(index));
1056
+ };
1057
+ class DimensionsBuilder {
1058
+ doc;
1059
+ dsl;
1060
+ constructor(doc, dsl){
1061
+ this.doc = doc;
447
1062
  this.dsl = dsl;
448
1063
  doc.transact(()=>{
449
1064
  const dimensions = getOrCreateDimensions(this.dsl);
@@ -451,34 +1066,44 @@ class DimensionsBuilder {
451
1066
  });
452
1067
  }
453
1068
  add(field, callback) {
1069
+ const dimensions = getOrCreateDimensions(this.dsl);
1070
+ const chartType = this.dsl.get('chartType') || 'table';
1071
+ const [encoding] = getRecommendedDimensionEncodingsForChartType(chartType, dimensions.length + 1).slice(-1);
454
1072
  const dimension = {
455
1073
  id: id_id.uuid(),
456
1074
  alias: field,
457
- field
1075
+ field,
1076
+ encoding
458
1077
  };
459
1078
  const yMap = new external_yjs_namespaceObject.Map();
460
- for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
461
- const dimensions = getOrCreateDimensions(this.dsl);
462
- dimensions.push([
463
- yMap
464
- ]);
465
- const node = new DimensionNodeBuilder(yMap);
466
- callback(node);
1079
+ this.doc.transact(()=>{
1080
+ for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
1081
+ const dimensions = getOrCreateDimensions(this.dsl);
1082
+ dimensions.push([
1083
+ yMap
1084
+ ]);
1085
+ const node = new DimensionNodeBuilder(yMap);
1086
+ callback(node);
1087
+ });
467
1088
  return this;
468
1089
  }
469
1090
  remove(id) {
470
- const dimensions = getOrCreateDimensions(this.dsl);
471
- const index = locateDimensionIndexById(dimensions, id);
472
- if (-1 !== index) dimensions.delete(index, 1);
1091
+ this.doc.transact(()=>{
1092
+ const dimensions = getOrCreateDimensions(this.dsl);
1093
+ const index = locateDimensionIndexById(dimensions, id);
1094
+ if (-1 !== index) dimensions.delete(index, 1);
1095
+ });
473
1096
  return this;
474
1097
  }
475
1098
  update(id, callback) {
476
- const dimensions = getOrCreateDimensions(this.dsl);
477
- const index = locateDimensionIndexById(dimensions, id);
478
- if (-1 === index) throw new Error(`Dimension with id "${id}" not found`);
479
- const dimensionYMap = dimensions.get(index);
480
- const node = new DimensionNodeBuilder(dimensionYMap);
481
- callback(node);
1099
+ this.doc.transact(()=>{
1100
+ const dimensions = getOrCreateDimensions(this.dsl);
1101
+ const index = locateDimensionIndexById(dimensions, id);
1102
+ if (-1 === index) throw new Error(`Dimension with id "${id}" not found`);
1103
+ const dimensionYMap = dimensions.get(index);
1104
+ const node = new DimensionNodeBuilder(dimensionYMap);
1105
+ callback(node);
1106
+ });
482
1107
  return this;
483
1108
  }
484
1109
  find(predicate) {
@@ -499,9 +1124,9 @@ class DimensionsBuilder {
499
1124
  }
500
1125
  observe(callback) {
501
1126
  const dimensions = getOrCreateDimensions(this.dsl);
502
- dimensions.observe(callback);
1127
+ dimensions.observeDeep(callback);
503
1128
  return ()=>{
504
- dimensions.unobserve(callback);
1129
+ dimensions.unobserveDeep(callback);
505
1130
  };
506
1131
  }
507
1132
  static isDimensionNode(node) {
@@ -511,9 +1136,27 @@ class DimensionsBuilder {
511
1136
  return 'children' in node;
512
1137
  }
513
1138
  }
1139
+ const reapplyDimensionEncodings = (dsl, chartType)=>{
1140
+ const dimensions = getOrCreateDimensions(dsl);
1141
+ const nodes = dimensions.toArray().filter((item)=>item instanceof external_yjs_namespaceObject.Map && 'string' == typeof item.get('field'));
1142
+ const encodings = getRecommendedDimensionEncodingsForChartType(chartType, nodes.length);
1143
+ nodes.forEach((node, index)=>{
1144
+ node.set('encoding', encodings[index]);
1145
+ });
1146
+ };
1147
+ const reapplyMeasureEncodings = (dsl, chartType)=>{
1148
+ const measures = getOrCreateMeasures(dsl);
1149
+ const nodes = measures.toArray().filter((item)=>item instanceof external_yjs_namespaceObject.Map && 'string' == typeof item.get('field'));
1150
+ const encodings = getRecommendedMeasureEncodingsForChartType(chartType, nodes.length);
1151
+ nodes.forEach((node, index)=>{
1152
+ node.set('encoding', encodings[index]);
1153
+ });
1154
+ };
514
1155
  class ChartTypeBuilder {
1156
+ doc;
515
1157
  dsl;
516
- constructor(_doc, dsl){
1158
+ constructor(doc, dsl){
1159
+ this.doc = doc;
517
1160
  this.dsl = dsl;
518
1161
  }
519
1162
  observe(callback) {
@@ -526,11 +1169,29 @@ class ChartTypeBuilder {
526
1169
  };
527
1170
  }
528
1171
  changeChartType(chartType) {
529
- this.dsl.set('chartType', chartType);
1172
+ this.doc.transact(()=>{
1173
+ this.dsl.set('chartType', chartType);
1174
+ reapplyDimensionEncodings(this.dsl, chartType);
1175
+ reapplyMeasureEncodings(this.dsl, chartType);
1176
+ });
530
1177
  }
531
1178
  getChartType() {
532
1179
  return this.dsl.get('chartType') || 'table';
533
1180
  }
1181
+ getSupportedDimensionEncodings() {
1182
+ return getSupportedDimensionEncodingsForChartType(this.getChartType());
1183
+ }
1184
+ getRecommendedDimensionEncodings(dimensionCount) {
1185
+ const resolvedCount = dimensionCount ?? this.dsl.get('dimensions')?.length;
1186
+ return getRecommendedDimensionEncodingsForChartType(this.getChartType(), resolvedCount);
1187
+ }
1188
+ getSupportedMeasureEncodings() {
1189
+ return getSupportedMeasureEncodingsForChartType(this.getChartType());
1190
+ }
1191
+ getRecommendedMeasureEncodings(measureCount) {
1192
+ const resolvedCount = measureCount ?? this.dsl.get('measures')?.length;
1193
+ return getRecommendedMeasureEncodingsForChartType(this.getChartType(), resolvedCount);
1194
+ }
534
1195
  toJSON() {
535
1196
  return this.dsl.get('chartType') || 'table';
536
1197
  }
@@ -538,25 +1199,35 @@ class ChartTypeBuilder {
538
1199
  return [
539
1200
  vseed_namespaceObject.ChartTypeEnum.Table,
540
1201
  vseed_namespaceObject.ChartTypeEnum.PivotTable,
541
- vseed_namespaceObject.ChartTypeEnum.Line,
542
1202
  vseed_namespaceObject.ChartTypeEnum.Column,
543
- vseed_namespaceObject.ChartTypeEnum.ColumnPercent,
544
1203
  vseed_namespaceObject.ChartTypeEnum.ColumnParallel,
545
- vseed_namespaceObject.ChartTypeEnum.BarPercent,
1204
+ vseed_namespaceObject.ChartTypeEnum.ColumnPercent,
1205
+ vseed_namespaceObject.ChartTypeEnum.Bar,
546
1206
  vseed_namespaceObject.ChartTypeEnum.BarParallel,
1207
+ vseed_namespaceObject.ChartTypeEnum.BarPercent,
1208
+ vseed_namespaceObject.ChartTypeEnum.Line,
547
1209
  vseed_namespaceObject.ChartTypeEnum.Area,
548
1210
  vseed_namespaceObject.ChartTypeEnum.AreaPercent,
549
1211
  vseed_namespaceObject.ChartTypeEnum.DualAxis,
550
1212
  vseed_namespaceObject.ChartTypeEnum.Scatter,
551
- vseed_namespaceObject.ChartTypeEnum.Rose,
552
- vseed_namespaceObject.ChartTypeEnum.RoseParallel,
553
1213
  vseed_namespaceObject.ChartTypeEnum.Pie,
554
1214
  vseed_namespaceObject.ChartTypeEnum.Donut,
1215
+ vseed_namespaceObject.ChartTypeEnum.Rose,
1216
+ vseed_namespaceObject.ChartTypeEnum.RoseParallel,
555
1217
  vseed_namespaceObject.ChartTypeEnum.Radar,
556
1218
  vseed_namespaceObject.ChartTypeEnum.Funnel,
557
1219
  vseed_namespaceObject.ChartTypeEnum.Heatmap,
558
1220
  vseed_namespaceObject.ChartTypeEnum.Boxplot,
559
- vseed_namespaceObject.ChartTypeEnum.Histogram
1221
+ vseed_namespaceObject.ChartTypeEnum.Histogram,
1222
+ vseed_namespaceObject.ChartTypeEnum.TreeMap,
1223
+ vseed_namespaceObject.ChartTypeEnum.Sunburst,
1224
+ vseed_namespaceObject.ChartTypeEnum.CirclePacking,
1225
+ vseed_namespaceObject.ChartTypeEnum.RaceBar,
1226
+ vseed_namespaceObject.ChartTypeEnum.RaceColumn,
1227
+ vseed_namespaceObject.ChartTypeEnum.RaceLine,
1228
+ vseed_namespaceObject.ChartTypeEnum.RaceScatter,
1229
+ vseed_namespaceObject.ChartTypeEnum.RacePie,
1230
+ vseed_namespaceObject.ChartTypeEnum.RaceDonut
560
1231
  ];
561
1232
  }
562
1233
  }
@@ -567,7 +1238,7 @@ function createWhereGroup(op = 'and', groupId = 'root') {
567
1238
  yMap.set('conditions', new external_yjs_namespaceObject.Array());
568
1239
  return yMap;
569
1240
  }
570
- function where_utils_isWhereGroup(yMap) {
1241
+ function isWhereGroup(yMap) {
571
1242
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
572
1243
  }
573
1244
  function findEntry(collection, entryId) {
@@ -579,7 +1250,7 @@ function findEntry(collection, entryId) {
579
1250
  index,
580
1251
  item
581
1252
  };
582
- if (where_utils_isWhereGroup(item)) {
1253
+ if (isWhereGroup(item)) {
583
1254
  const nestedCollection = item.get('conditions');
584
1255
  const nestedMatch = findEntry(nestedCollection, entryId);
585
1256
  if (nestedMatch) return nestedMatch;
@@ -612,6 +1283,15 @@ class WhereFilterNodeBuilder {
612
1283
  this.yMap.set('value', value);
613
1284
  return this;
614
1285
  }
1286
+ setDate(predicate) {
1287
+ this.yMap.set('op', 'date');
1288
+ this.yMap.set('value', predicate);
1289
+ return this;
1290
+ }
1291
+ getDate() {
1292
+ if ('date' !== this.yMap.get('op')) return;
1293
+ return this.yMap.get('value');
1294
+ }
615
1295
  toJSON() {
616
1296
  return this.yMap.toJSON();
617
1297
  }
@@ -772,7 +1452,7 @@ class WhereFilterBuilder {
772
1452
  };
773
1453
  }
774
1454
  static isGroup(yMap) {
775
- return where_utils_isWhereGroup(yMap);
1455
+ return isWhereGroup(yMap);
776
1456
  }
777
1457
  static isNode(yMap) {
778
1458
  return void 0 !== yMap.get('field');
@@ -785,7 +1465,7 @@ function createHavingGroup(op = 'and', groupId = 'root') {
785
1465
  yMap.set('conditions', new external_yjs_namespaceObject.Array());
786
1466
  return yMap;
787
1467
  }
788
- function having_utils_isHavingGroup(yMap) {
1468
+ function isHavingGroup(yMap) {
789
1469
  return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
790
1470
  }
791
1471
  function having_utils_findEntry(collection, entryId) {
@@ -797,7 +1477,7 @@ function having_utils_findEntry(collection, entryId) {
797
1477
  index,
798
1478
  item
799
1479
  };
800
- if (having_utils_isHavingGroup(item)) {
1480
+ if (isHavingGroup(item)) {
801
1481
  const nestedCollection = item.get('conditions');
802
1482
  const nestedMatch = having_utils_findEntry(nestedCollection, entryId);
803
1483
  if (nestedMatch) return nestedMatch;
@@ -818,6 +1498,9 @@ class HavingFilterNodeBuilder {
818
1498
  getOperator() {
819
1499
  return this.yMap.get('op');
820
1500
  }
1501
+ getAggregate() {
1502
+ return this.yMap.get('aggregate');
1503
+ }
821
1504
  setValue(value) {
822
1505
  this.yMap.set('value', value);
823
1506
  return this;
@@ -826,6 +1509,10 @@ class HavingFilterNodeBuilder {
826
1509
  this.yMap.set('op', operator);
827
1510
  return this;
828
1511
  }
1512
+ setAggregate(aggregate) {
1513
+ this.yMap.set('aggregate', aggregate);
1514
+ return this;
1515
+ }
829
1516
  toJSON() {
830
1517
  return this.yMap.toJSON();
831
1518
  }
@@ -852,6 +1539,9 @@ class HavingGroupBuilder {
852
1539
  const yMap = new external_yjs_namespaceObject.Map();
853
1540
  yMap.set('id', id_id.uuid());
854
1541
  yMap.set('field', field);
1542
+ yMap.set('aggregate', {
1543
+ func: 'sum'
1544
+ });
855
1545
  this.getConditions().push([
856
1546
  yMap
857
1547
  ]);
@@ -909,6 +1599,9 @@ class HavingFilterBuilder {
909
1599
  const yMap = new external_yjs_namespaceObject.Map();
910
1600
  yMap.set('id', id_id.uuid());
911
1601
  yMap.set('field', field);
1602
+ yMap.set('aggregate', {
1603
+ func: 'sum'
1604
+ });
912
1605
  this.getConditions().push([
913
1606
  yMap
914
1607
  ]);
@@ -986,7 +1679,7 @@ class HavingFilterBuilder {
986
1679
  };
987
1680
  }
988
1681
  static isGroup(yMap) {
989
- return having_utils_isHavingGroup(yMap);
1682
+ return isHavingGroup(yMap);
990
1683
  }
991
1684
  static isNode(yMap) {
992
1685
  return void 0 !== yMap.get('field');
@@ -1085,20 +1778,531 @@ class UndoManager {
1085
1778
  this.manager.clear(clearUndoStack, clearRedoStack);
1086
1779
  }
1087
1780
  }
1088
- const createBuilderFeatures = (doc, dsl)=>({
1089
- undoManager: new UndoManager(dsl),
1090
- chartType: new ChartTypeBuilder(doc, dsl),
1091
- measures: new MeasuresBuilder(doc, dsl),
1092
- dimensions: new DimensionsBuilder(doc, dsl),
1093
- havingFilter: new HavingFilterBuilder(doc, dsl),
1094
- whereFilter: new WhereFilterBuilder(doc, dsl),
1095
- theme: new ThemeBuilder(doc, dsl),
1096
- locale: new LocaleBuilder(doc, dsl),
1097
- limit: new LimitBuilder(doc, dsl)
1781
+ const VBI_TO_VQUERY_MEASURE_AGGR_FUNC_MAP = {
1782
+ count: 'count',
1783
+ countDistinct: 'count_distinct',
1784
+ sum: 'sum',
1785
+ avg: 'avg',
1786
+ min: 'min',
1787
+ max: 'max',
1788
+ variance: 'variance',
1789
+ variancePop: 'variance_pop',
1790
+ stddev: 'stddev',
1791
+ median: 'median',
1792
+ quantile: 'quantile'
1793
+ };
1794
+ const VBI_TO_VQUERY_DIMENSION_AGGR_FUNC_MAP = {
1795
+ toYear: 'to_year',
1796
+ toQuarter: 'to_quarter',
1797
+ toMonth: 'to_month',
1798
+ toWeek: 'to_week',
1799
+ toDay: 'to_day',
1800
+ toHour: 'to_hour',
1801
+ toMinute: 'to_minute',
1802
+ toSecond: 'to_second'
1803
+ };
1804
+ const mapAggregateForVQuery = (aggregate)=>{
1805
+ if (!aggregate) return aggregate;
1806
+ const mappedFunc = VBI_TO_VQUERY_MEASURE_AGGR_FUNC_MAP[aggregate.func] ?? aggregate.func;
1807
+ return {
1808
+ ...aggregate,
1809
+ func: mappedFunc
1810
+ };
1811
+ };
1812
+ const mapDimensionAggregateForVQuery = (aggregate)=>{
1813
+ if (!aggregate) return aggregate;
1814
+ const mappedFunc = VBI_TO_VQUERY_DIMENSION_AGGR_FUNC_MAP[aggregate.func] ?? aggregate.func;
1815
+ return {
1816
+ ...aggregate,
1817
+ func: mappedFunc
1818
+ };
1819
+ };
1820
+ const buildSelect = (queryDSL, context)=>{
1821
+ const { vbiDSL } = context;
1822
+ const measures = vbiDSL.measures;
1823
+ const dimensions = vbiDSL.dimensions;
1824
+ const result = {
1825
+ ...queryDSL
1826
+ };
1827
+ const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
1828
+ const measureSelects = measureNodes.map((measure)=>({
1829
+ field: measure.field,
1830
+ alias: measure.id,
1831
+ aggr: mapAggregateForVQuery(measure.aggregate)
1832
+ }));
1833
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
1834
+ const dimensionSelects = dimensionNodes.map((dimension)=>{
1835
+ const aggregate = mapDimensionAggregateForVQuery(dimension.aggregate);
1836
+ if (!aggregate) return {
1837
+ field: dimension.field,
1838
+ alias: dimension.id
1839
+ };
1840
+ return {
1841
+ field: dimension.field,
1842
+ alias: dimension.id,
1843
+ aggr: aggregate
1844
+ };
1098
1845
  });
1099
- class VBIBuilder {
1846
+ result.select = [
1847
+ ...measureSelects,
1848
+ ...dimensionSelects
1849
+ ];
1850
+ return result;
1851
+ };
1852
+ const buildGroupBy = (queryDSL, context)=>{
1853
+ const result = {
1854
+ ...queryDSL
1855
+ };
1856
+ const { vbiDSL } = context;
1857
+ const dimensions = vbiDSL.dimensions;
1858
+ const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
1859
+ result.groupBy = dimensionNodes.map((dimension)=>dimension.aggregate ? dimension.id : dimension.field);
1860
+ return result;
1861
+ };
1862
+ function resolveDatePredicate(predicate, now) {
1863
+ switch(predicate.type){
1864
+ case 'range':
1865
+ return resolveRange(predicate);
1866
+ case 'period':
1867
+ return resolvePeriod(predicate);
1868
+ case 'relative':
1869
+ return resolveRelative(predicate, now ?? new Date());
1870
+ case 'current':
1871
+ return resolveCurrent(predicate, now ?? new Date());
1872
+ }
1873
+ }
1874
+ function resolveRange(p) {
1875
+ return {
1876
+ start: toDateString(p.start),
1877
+ end: toDateString(p.end),
1878
+ bounds: p.bounds ?? '[)'
1879
+ };
1880
+ }
1881
+ function resolvePeriod(p) {
1882
+ switch(p.unit){
1883
+ case 'year':
1884
+ return {
1885
+ start: `${p.year}-01-01`,
1886
+ end: `${p.year + 1}-01-01`,
1887
+ bounds: '[)'
1888
+ };
1889
+ case 'quarter':
1890
+ return resolveQuarter(p.year, p.quarter);
1891
+ case 'month':
1892
+ return resolveMonth(p.year, p.month);
1893
+ case 'week':
1894
+ return resolveISOWeek(p.year, p.week);
1895
+ case 'day':
1896
+ return resolveDay(p.date);
1897
+ }
1898
+ }
1899
+ function resolveQuarter(year, quarter) {
1900
+ const startMonth = (quarter - 1) * 3 + 1;
1901
+ const start = formatDate(year, startMonth, 1);
1902
+ const endDate = new Date(Date.UTC(year, startMonth - 1 + 3, 1));
1903
+ return {
1904
+ start,
1905
+ end: utcToDateString(endDate),
1906
+ bounds: '[)'
1907
+ };
1908
+ }
1909
+ function resolveMonth(year, month) {
1910
+ const start = formatDate(year, month, 1);
1911
+ const endDate = new Date(Date.UTC(year, month, 1));
1912
+ return {
1913
+ start,
1914
+ end: utcToDateString(endDate),
1915
+ bounds: '[)'
1916
+ };
1917
+ }
1918
+ function resolveISOWeek(year, week) {
1919
+ const jan4 = new Date(Date.UTC(year, 0, 4));
1920
+ const dayOfWeek = jan4.getUTCDay() || 7;
1921
+ const monday = new Date(jan4.getTime() - (dayOfWeek - 1) * 86400000);
1922
+ const weekStart = new Date(monday.getTime() + (week - 1) * 604800000);
1923
+ const weekEnd = new Date(weekStart.getTime() + 604800000);
1924
+ return {
1925
+ start: utcToDateString(weekStart),
1926
+ end: utcToDateString(weekEnd),
1927
+ bounds: '[)'
1928
+ };
1929
+ }
1930
+ function resolveDay(date) {
1931
+ const d = 'string' == typeof date ? new Date(date + 'T00:00:00Z') : date;
1932
+ const next = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + 1));
1933
+ return {
1934
+ start: utcToDateString(d),
1935
+ end: utcToDateString(next),
1936
+ bounds: '[)'
1937
+ };
1938
+ }
1939
+ function resolveRelative(p, now) {
1940
+ const today = truncateToDay(now);
1941
+ const offset = 'last' === p.mode ? -p.amount : p.amount;
1942
+ const shifted = shiftDate(today, offset, p.unit);
1943
+ if ('last' === p.mode) return {
1944
+ start: utcToDateString(shifted),
1945
+ end: utcToDateString(today),
1946
+ bounds: '[)'
1947
+ };
1948
+ return {
1949
+ start: utcToDateString(today),
1950
+ end: utcToDateString(shifted),
1951
+ bounds: '[)'
1952
+ };
1953
+ }
1954
+ function resolveCurrent(p, now) {
1955
+ const offset = p.offset ?? 0;
1956
+ const base = truncateToDay(now);
1957
+ const periodStart = getPeriodStart(base, p.unit, offset);
1958
+ const periodEnd = shiftDate(periodStart, 1, p.unit);
1959
+ return {
1960
+ start: utcToDateString(periodStart),
1961
+ end: utcToDateString(periodEnd),
1962
+ bounds: '[)'
1963
+ };
1964
+ }
1965
+ function getPeriodStart(date, unit, offset) {
1966
+ const y = date.getUTCFullYear();
1967
+ const m = date.getUTCMonth();
1968
+ switch(unit){
1969
+ case 'year':
1970
+ return new Date(Date.UTC(y + offset, 0, 1));
1971
+ case 'quarter':
1972
+ {
1973
+ const q = Math.floor(m / 3);
1974
+ return new Date(Date.UTC(y, (q + offset) * 3, 1));
1975
+ }
1976
+ case 'month':
1977
+ return new Date(Date.UTC(y, m + offset, 1));
1978
+ case 'week':
1979
+ {
1980
+ const dow = date.getUTCDay() || 7;
1981
+ const monday = new Date(date.getTime() - (dow - 1) * 86400000);
1982
+ return new Date(monday.getTime() + 7 * offset * 86400000);
1983
+ }
1984
+ case 'day':
1985
+ return new Date(Date.UTC(y, m, date.getUTCDate() + offset));
1986
+ default:
1987
+ return date;
1988
+ }
1989
+ }
1990
+ function shiftDate(date, amount, unit) {
1991
+ const y = date.getUTCFullYear();
1992
+ const m = date.getUTCMonth();
1993
+ const d = date.getUTCDate();
1994
+ switch(unit){
1995
+ case 'year':
1996
+ return new Date(Date.UTC(y + amount, m, d));
1997
+ case 'quarter':
1998
+ return new Date(Date.UTC(y, m + 3 * amount, d));
1999
+ case 'month':
2000
+ return new Date(Date.UTC(y, m + amount, d));
2001
+ case 'week':
2002
+ return new Date(date.getTime() + 7 * amount * 86400000);
2003
+ case 'day':
2004
+ return new Date(Date.UTC(y, m, d + amount));
2005
+ default:
2006
+ return date;
2007
+ }
2008
+ }
2009
+ function truncateToDay(date) {
2010
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
2011
+ }
2012
+ function toDateString(input) {
2013
+ if ('string' == typeof input) return input;
2014
+ return utcToDateString(input);
2015
+ }
2016
+ function utcToDateString(date) {
2017
+ return formatDate(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate());
2018
+ }
2019
+ function formatDate(year, month, day) {
2020
+ const y = String(year);
2021
+ const m = String(month).padStart(2, '0');
2022
+ const d = String(day).padStart(2, '0');
2023
+ return `${y}-${m}-${d}`;
2024
+ }
2025
+ const buildWhere = (queryDSL, context)=>{
2026
+ const { vbiDSL } = context;
2027
+ const whereFilter = vbiDSL.whereFilter;
2028
+ if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
2029
+ const result = {
2030
+ ...queryDSL
2031
+ };
2032
+ result.where = mapGroupToCondition(whereFilter);
2033
+ return result;
2034
+ };
2035
+ function buildWhere_isWhereGroup(clause) {
2036
+ return 'op' in clause && 'conditions' in clause;
2037
+ }
2038
+ function mapClauseToCondition(clause) {
2039
+ if (buildWhere_isWhereGroup(clause)) return [
2040
+ mapGroupToCondition(clause)
2041
+ ];
2042
+ return mapFilterToCondition(clause);
2043
+ }
2044
+ function mapGroupToCondition(group) {
2045
+ return {
2046
+ op: group.op,
2047
+ conditions: group.conditions.flatMap((c)=>mapClauseToCondition(c))
2048
+ };
2049
+ }
2050
+ function mapFilterToCondition(filter) {
2051
+ if ('date' === filter.op) return handleDateFilter(filter.field, filter.value);
2052
+ if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
2053
+ return handleSimpleFilter(filter);
2054
+ }
2055
+ function handleDateFilter(field, predicate) {
2056
+ const range = resolveDatePredicate(predicate);
2057
+ const startOp = '>=';
2058
+ const endOp = '[]' === range.bounds ? '<=' : '<';
2059
+ return [
2060
+ {
2061
+ field,
2062
+ op: startOp,
2063
+ value: range.start
2064
+ },
2065
+ {
2066
+ field,
2067
+ op: endOp,
2068
+ value: range.end
2069
+ }
2070
+ ];
2071
+ }
2072
+ function handleBetweenFilter(filter) {
2073
+ const value = normalizeBetweenValue(filter.value);
2074
+ const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
2075
+ field: filter.field,
2076
+ op: '<' === value.leftOp ? '>' : '>=',
2077
+ value: value.min
2078
+ } : void 0;
2079
+ const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
2080
+ field: filter.field,
2081
+ op: '<' === value.rightOp ? '<' : '<=',
2082
+ value: value.max
2083
+ } : void 0;
2084
+ if ('not between' === filter.op) {
2085
+ const outsideConditions = [
2086
+ lowerCondition && invertLowerBound(lowerCondition),
2087
+ upperCondition && invertUpperBound(upperCondition)
2088
+ ].filter(Boolean);
2089
+ if (outsideConditions.length <= 1) return outsideConditions;
2090
+ return [
2091
+ {
2092
+ op: 'or',
2093
+ conditions: outsideConditions
2094
+ }
2095
+ ];
2096
+ }
2097
+ return [
2098
+ lowerCondition,
2099
+ upperCondition
2100
+ ].filter(Boolean);
2101
+ }
2102
+ function normalizeBetweenValue(value) {
2103
+ if (Array.isArray(value)) return {
2104
+ min: value[0],
2105
+ max: value[1],
2106
+ leftOp: '<=',
2107
+ rightOp: '<='
2108
+ };
2109
+ if ('object' == typeof value && null !== value) return value;
2110
+ return {};
2111
+ }
2112
+ function invertLowerBound(condition) {
2113
+ return {
2114
+ field: condition.field,
2115
+ op: '>' === condition.op ? '<=' : '<',
2116
+ value: condition.value
2117
+ };
2118
+ }
2119
+ function invertUpperBound(condition) {
2120
+ return {
2121
+ field: condition.field,
2122
+ op: '<' === condition.op ? '>=' : '>',
2123
+ value: condition.value
2124
+ };
2125
+ }
2126
+ function handleSimpleFilter(filter) {
2127
+ let mappedOp = filter.op;
2128
+ const value = filter.value;
2129
+ if (Array.isArray(value)) {
2130
+ if ('=' === mappedOp) mappedOp = 'in';
2131
+ if ('!=' === mappedOp) mappedOp = 'not in';
2132
+ }
2133
+ return [
2134
+ {
2135
+ field: filter.field,
2136
+ op: mappedOp,
2137
+ value
2138
+ }
2139
+ ];
2140
+ }
2141
+ const buildHaving = (queryDSL, context)=>{
2142
+ const { vbiDSL } = context;
2143
+ const havingFilter = vbiDSL.havingFilter;
2144
+ if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
2145
+ const result = {
2146
+ ...queryDSL
2147
+ };
2148
+ result.having = {
2149
+ op: havingFilter.op,
2150
+ conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
2151
+ };
2152
+ return result;
2153
+ };
2154
+ function buildHaving_isHavingGroup(clause) {
2155
+ return 'op' in clause && 'conditions' in clause;
2156
+ }
2157
+ function buildHaving_mapClauseToCondition(clause) {
2158
+ if (buildHaving_isHavingGroup(clause)) return [
2159
+ buildHaving_mapGroupToCondition(clause)
2160
+ ];
2161
+ return buildHaving_mapFilterToCondition(clause);
2162
+ }
2163
+ function buildHaving_mapGroupToCondition(group) {
2164
+ return {
2165
+ op: group.op,
2166
+ conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
2167
+ };
2168
+ }
2169
+ function buildHaving_mapFilterToCondition(filter) {
2170
+ const mappedOp = normalizeOperator(filter.op, filter.value);
2171
+ const aggregate = mapAggregateForVQuery(filter.aggregate);
2172
+ return [
2173
+ {
2174
+ field: filter.field,
2175
+ aggr: aggregate,
2176
+ op: mappedOp,
2177
+ value: filter.value
2178
+ }
2179
+ ];
2180
+ }
2181
+ function normalizeOperator(op, value) {
2182
+ let mappedOp = op;
2183
+ if (Array.isArray(value)) {
2184
+ if ('=' === mappedOp) mappedOp = 'in';
2185
+ if ('!=' === mappedOp) mappedOp = 'not in';
2186
+ }
2187
+ return mappedOp;
2188
+ }
2189
+ const toOrderItem = (node)=>({
2190
+ field: node.id,
2191
+ order: node.sort?.order
2192
+ });
2193
+ const buildOrderBy = (queryDSL, context)=>{
2194
+ const result = {
2195
+ ...queryDSL
2196
+ };
2197
+ const dimensions = context.vbiDSL.dimensions.filter(DimensionsBuilder.isDimensionNode);
2198
+ const measures = context.vbiDSL.measures.filter(MeasuresBuilder.isMeasureNode);
2199
+ const sortedDimensions = dimensions.filter((node)=>node.sort);
2200
+ const sortedMeasures = measures.filter((node)=>node.sort);
2201
+ const sortedNodes = [
2202
+ ...sortedDimensions,
2203
+ ...sortedMeasures
2204
+ ];
2205
+ if (sortedNodes.length > 0) {
2206
+ result.orderBy = sortedNodes.map(toOrderItem);
2207
+ return result;
2208
+ }
2209
+ const firstDimension = dimensions[0];
2210
+ if (firstDimension) result.orderBy = [
2211
+ {
2212
+ field: firstDimension.id,
2213
+ order: 'asc'
2214
+ }
2215
+ ];
2216
+ return result;
2217
+ };
2218
+ const buildLimit = (queryDSL, context)=>{
2219
+ const result = {
2220
+ ...queryDSL
2221
+ };
2222
+ const limit = context.vbiDSL.limit ?? 1000;
2223
+ result.limit = limit;
2224
+ return result;
2225
+ };
2226
+ const buildVQuery = (vbiDSL, builder)=>{
2227
+ const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
2228
+ vbiDSL,
2229
+ builder
2230
+ });
2231
+ return (0, external_remeda_namespaceObject.pipe)({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildOrderBy), wrapper(buildLimit));
2232
+ };
2233
+ const buildVQueryDSL = ({ vbiDSL, builder })=>buildVQuery(vbiDSL, builder);
2234
+ const buildVSeedDSL = async ({ vbiDSL, queryDSL, options })=>{
2235
+ const connectorId = vbiDSL.connectorId;
2236
+ const connector = await getConnector(connectorId);
2237
+ const schema = await connector.discoverSchema();
2238
+ const queryResult = await connector.query({
2239
+ queryDSL,
2240
+ schema,
2241
+ connectorId,
2242
+ signal: options.signal
2243
+ });
2244
+ const measures = vbiDSL.measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure)).map((measure)=>{
2245
+ const nextMeasure = {
2246
+ id: measure.id,
2247
+ alias: measure.alias
2248
+ };
2249
+ if (measure.encoding) nextMeasure.encoding = measure.encoding;
2250
+ if (measure.format) if ('autoFormat' in measure.format && true === measure.format.autoFormat) nextMeasure.autoFormat = true;
2251
+ else {
2252
+ nextMeasure.autoFormat = false;
2253
+ nextMeasure.numFormat = Object.fromEntries(Object.entries(measure.format).filter(([key])=>'autoFormat' !== key));
2254
+ }
2255
+ return nextMeasure;
2256
+ });
2257
+ const dimensions = vbiDSL.dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension)).map((dimension)=>{
2258
+ const nextDimension = {
2259
+ id: dimension.id,
2260
+ alias: dimension.alias
2261
+ };
2262
+ if (dimension.encoding) nextDimension.encoding = dimension.encoding;
2263
+ return nextDimension;
2264
+ });
2265
+ return {
2266
+ chartType: vbiDSL.chartType,
2267
+ dataset: queryResult.dataset,
2268
+ dimensions,
2269
+ measures,
2270
+ theme: vbiDSL.theme,
2271
+ locale: vbiDSL.locale
2272
+ };
2273
+ };
2274
+ const defaultVBIChartBuilderAdapters = {
2275
+ buildVQuery: buildVQueryDSL,
2276
+ buildVSeed: buildVSeedDSL
2277
+ };
2278
+ const resolveVBIChartBuilderAdapters = (adapters)=>({
2279
+ buildVQuery: adapters?.buildVQuery ?? defaultVBIChartBuilderAdapters.buildVQuery,
2280
+ buildVSeed: adapters?.buildVSeed ?? defaultVBIChartBuilderAdapters.buildVSeed
2281
+ });
2282
+ const applyUpdateToDoc = (doc, update, transactionOrigin)=>{
2283
+ external_yjs_namespaceObject.applyUpdate(doc, update, transactionOrigin);
2284
+ };
2285
+ const encodeDocStateAsUpdate = (doc, targetStateVector)=>external_yjs_namespaceObject.encodeStateAsUpdate(doc, targetStateVector);
2286
+ const buildVBIChartDSL = (dsl)=>dsl.toJSON();
2287
+ const getCollectionLength = (value)=>{
2288
+ if (value instanceof external_yjs_namespaceObject.Array) return value.length;
2289
+ if (Array.isArray(value)) return value.length;
2290
+ return 0;
2291
+ };
2292
+ const isEmptyVBIChartDSL = (dsl)=>{
2293
+ const dimensionsLength = getCollectionLength(dsl.get('dimensions'));
2294
+ const measuresLength = getCollectionLength(dsl.get('measures'));
2295
+ return 0 === dimensionsLength && 0 === measuresLength;
2296
+ };
2297
+ const getBuilderSchema = async (dsl)=>{
2298
+ const connectorId = dsl.get('connectorId');
2299
+ const connector = await getConnector(connectorId);
2300
+ return connector.discoverSchema();
2301
+ };
2302
+ class VBIChartBuilder {
1100
2303
  doc;
1101
2304
  dsl;
2305
+ adapters;
1102
2306
  chartType;
1103
2307
  measures;
1104
2308
  dimensions;
@@ -1108,39 +2312,52 @@ class VBIBuilder {
1108
2312
  locale;
1109
2313
  limit;
1110
2314
  undoManager;
1111
- constructor(doc){
2315
+ constructor(doc, options){
1112
2316
  this.doc = doc;
1113
2317
  this.dsl = doc.getMap('dsl');
1114
- const features = createBuilderFeatures(doc, this.dsl);
1115
- this.undoManager = features.undoManager;
1116
- this.chartType = features.chartType;
1117
- this.measures = features.measures;
1118
- this.dimensions = features.dimensions;
1119
- this.havingFilter = features.havingFilter;
1120
- this.whereFilter = features.whereFilter;
1121
- this.theme = features.theme;
1122
- this.locale = features.locale;
1123
- this.limit = features.limit;
2318
+ this.adapters = resolveVBIChartBuilderAdapters(options?.adapters);
2319
+ this.undoManager = new UndoManager(this.dsl);
2320
+ this.chartType = new ChartTypeBuilder(doc, this.dsl);
2321
+ this.measures = new MeasuresBuilder(doc, this.dsl);
2322
+ this.dimensions = new DimensionsBuilder(doc, this.dsl);
2323
+ this.havingFilter = new HavingFilterBuilder(doc, this.dsl);
2324
+ this.whereFilter = new WhereFilterBuilder(doc, this.dsl);
2325
+ this.theme = new ThemeBuilder(doc, this.dsl);
2326
+ this.locale = new LocaleBuilder(doc, this.dsl);
2327
+ this.limit = new LimitBuilder(doc, this.dsl);
1124
2328
  }
1125
2329
  applyUpdate = (update, transactionOrigin)=>applyUpdateToDoc(this.doc, update, transactionOrigin);
1126
2330
  encodeStateAsUpdate = (targetStateVector)=>encodeDocStateAsUpdate(this.doc, targetStateVector);
1127
- buildVSeed = async ()=>{
2331
+ buildVSeed = async (options = {})=>{
1128
2332
  const vbiDSL = this.build();
1129
- const queryDSL = this.buildVQuery();
1130
- return buildVSeedDSL({
2333
+ const queryDSL = this.adapters.buildVQuery({
2334
+ dsl: this.dsl,
1131
2335
  vbiDSL,
1132
- queryDSL
2336
+ builder: this
2337
+ });
2338
+ return this.adapters.buildVSeed({
2339
+ dsl: this.dsl,
2340
+ vbiDSL,
2341
+ queryDSL,
2342
+ options,
2343
+ builder: this
2344
+ });
2345
+ };
2346
+ buildVQuery = ()=>{
2347
+ const vbiDSL = this.build();
2348
+ return this.adapters.buildVQuery({
2349
+ dsl: this.dsl,
2350
+ vbiDSL,
2351
+ builder: this
1133
2352
  });
1134
2353
  };
1135
- buildVQuery = ()=>buildVQueryDSL(this.dsl, this);
1136
- build = ()=>buildVBIDSL(this.dsl);
1137
- isEmpty = ()=>isEmptyVBIDSL(this.dsl);
2354
+ build = ()=>buildVBIChartDSL(this.dsl);
2355
+ isEmpty = ()=>isEmptyVBIChartDSL(this.dsl);
1138
2356
  getSchema = async ()=>getBuilderSchema(this.dsl);
1139
2357
  }
1140
2358
  const shouldEnsureIdForObject = (obj, ensureId)=>{
1141
2359
  if (true === ensureId) return true;
1142
- if ('field' === ensureId) return 'string' == typeof obj.field;
1143
- return false;
2360
+ return 'field' === ensureId && 'string' == typeof obj.field;
1144
2361
  };
1145
2362
  const toYMap = (obj, ensureId = false)=>{
1146
2363
  const yMap = new external_yjs_namespaceObject.Map();
@@ -1148,23 +2365,9 @@ const toYMap = (obj, ensureId = false)=>{
1148
2365
  for (const [key, value] of Object.entries(obj)){
1149
2366
  if (('conditions' === key || 'children' === key) && Array.isArray(value)) {
1150
2367
  const yArr = new external_yjs_namespaceObject.Array();
1151
- for (const child of value){
1152
- if (child instanceof external_yjs_namespaceObject.Map) {
1153
- yArr.push([
1154
- child
1155
- ]);
1156
- continue;
1157
- }
1158
- if ('object' == typeof child && null !== child) {
1159
- yArr.push([
1160
- toYMap(child, ensureId)
1161
- ]);
1162
- continue;
1163
- }
1164
- yArr.push([
1165
- child
1166
- ]);
1167
- }
2368
+ for (const child of value)yArr.push([
2369
+ toYMap(child, ensureId)
2370
+ ]);
1168
2371
  yMap.set(key, yArr);
1169
2372
  continue;
1170
2373
  }
@@ -1174,65 +2377,34 @@ const toYMap = (obj, ensureId = false)=>{
1174
2377
  };
1175
2378
  const ensureYArray = (arr, ensureId = false)=>{
1176
2379
  if (!arr) return new external_yjs_namespaceObject.Array();
1177
- if (arr instanceof external_yjs_namespaceObject.Array) return arr;
1178
2380
  const yArr = new external_yjs_namespaceObject.Array();
1179
- for (const item of arr){
1180
- if (item instanceof external_yjs_namespaceObject.Map) {
1181
- yArr.push([
1182
- item
1183
- ]);
1184
- continue;
1185
- }
1186
- if ('object' == typeof item && null !== item) {
1187
- yArr.push([
1188
- toYMap(item, ensureId)
1189
- ]);
1190
- continue;
1191
- }
1192
- yArr.push([
1193
- item
1194
- ]);
1195
- }
2381
+ for (const item of arr)yArr.push([
2382
+ toYMap(item, ensureId)
2383
+ ]);
1196
2384
  return yArr;
1197
2385
  };
1198
- const getDefaultWhereFilter = ()=>({
2386
+ const ensureWhereGroup = (whereFilter)=>{
2387
+ const source = whereFilter ?? {
1199
2388
  id: 'root',
1200
2389
  op: 'and',
1201
2390
  conditions: []
1202
- });
1203
- const isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1204
- const ensureWhereGroup = (whereFilter)=>{
1205
- const sourceWhereFilter = whereFilter instanceof external_yjs_namespaceObject.Map || isFilterGroupInput(whereFilter) ? whereFilter : getDefaultWhereFilter();
1206
- const whereGroup = sourceWhereFilter instanceof external_yjs_namespaceObject.Map ? sourceWhereFilter : createWhereGroup();
1207
- if (sourceWhereFilter instanceof external_yjs_namespaceObject.Map) {
1208
- if (!(whereGroup.get('conditions') instanceof external_yjs_namespaceObject.Array)) whereGroup.set('conditions', new external_yjs_namespaceObject.Array());
1209
- if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1210
- if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1211
- return whereGroup;
1212
- }
1213
- whereGroup.set('id', sourceWhereFilter.id ?? 'root');
1214
- whereGroup.set('op', sourceWhereFilter.op ?? 'and');
1215
- whereGroup.set('conditions', ensureYArray(sourceWhereFilter.conditions, true));
2391
+ };
2392
+ const whereGroup = createWhereGroup();
2393
+ whereGroup.set('id', source.id);
2394
+ whereGroup.set('op', source.op);
2395
+ whereGroup.set('conditions', ensureYArray(source.conditions, true));
1216
2396
  return whereGroup;
1217
2397
  };
1218
- const getDefaultHavingFilter = ()=>({
2398
+ const ensureHavingGroup = (havingFilter)=>{
2399
+ const source = havingFilter ?? {
1219
2400
  id: 'root',
1220
2401
  op: 'and',
1221
2402
  conditions: []
1222
- });
1223
- const ensure_having_group_isFilterGroupInput = (value)=>'object' == typeof value && null !== value;
1224
- const ensureHavingGroup = (havingFilter)=>{
1225
- const sourceHavingFilter = havingFilter instanceof external_yjs_namespaceObject.Map || ensure_having_group_isFilterGroupInput(havingFilter) ? havingFilter : getDefaultHavingFilter();
1226
- const havingGroup = sourceHavingFilter instanceof external_yjs_namespaceObject.Map ? sourceHavingFilter : createHavingGroup();
1227
- if (sourceHavingFilter instanceof external_yjs_namespaceObject.Map) {
1228
- if (!(havingGroup.get('conditions') instanceof external_yjs_namespaceObject.Array)) havingGroup.set('conditions', new external_yjs_namespaceObject.Array());
1229
- if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1230
- if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1231
- return havingGroup;
1232
- }
1233
- havingGroup.set('id', sourceHavingFilter.id ?? 'root');
1234
- havingGroup.set('op', sourceHavingFilter.op ?? 'and');
1235
- havingGroup.set('conditions', ensureYArray(sourceHavingFilter.conditions, true));
2403
+ };
2404
+ const havingGroup = createHavingGroup();
2405
+ havingGroup.set('id', source.id);
2406
+ havingGroup.set('op', source.op);
2407
+ havingGroup.set('conditions', ensureYArray(source.conditions, true));
1236
2408
  return havingGroup;
1237
2409
  };
1238
2410
  const setBaseDSLFields = (dsl, vbi)=>{
@@ -1243,7 +2415,7 @@ const setBaseDSLFields = (dsl, vbi)=>{
1243
2415
  if (vbi.locale) dsl.set('locale', vbi.locale);
1244
2416
  if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1245
2417
  };
1246
- const fromVBIDSLInput = (vbi)=>{
2418
+ const createChartBuilderFromVBIChartDSLInput = (vbi, options)=>{
1247
2419
  const doc = new external_yjs_namespaceObject.Doc();
1248
2420
  const dsl = doc.getMap('dsl');
1249
2421
  doc.transact(()=>{
@@ -1253,9 +2425,9 @@ const fromVBIDSLInput = (vbi)=>{
1253
2425
  dsl.set('measures', ensureYArray(vbi.measures, 'field'));
1254
2426
  dsl.set('dimensions', ensureYArray(vbi.dimensions, 'field'));
1255
2427
  });
1256
- return new VBIBuilder(doc);
2428
+ return new VBIChartBuilder(doc, options);
1257
2429
  };
1258
- const generateEmptyDSL = (connectorId)=>({
2430
+ const generateEmptyChartDSL = (connectorId)=>({
1259
2431
  connectorId,
1260
2432
  chartType: 'table',
1261
2433
  measures: [],
@@ -1274,14 +2446,28 @@ const generateEmptyDSL = (connectorId)=>({
1274
2446
  locale: 'zh-CN',
1275
2447
  version: 0
1276
2448
  });
1277
- const createVBI = ()=>({
2449
+ const mergeBuilderOptions = (base, overrides)=>{
2450
+ if (!base) return overrides;
2451
+ if (!overrides) return base;
2452
+ return {
2453
+ ...base,
2454
+ ...overrides,
2455
+ adapters: {
2456
+ ...base.adapters,
2457
+ ...overrides.adapters
2458
+ }
2459
+ };
2460
+ };
2461
+ function createVBI(defaultBuilderOptions) {
2462
+ const createChart = (vbi, builderOptions)=>createChartBuilderFromVBIChartDSLInput(vbi, mergeBuilderOptions(defaultBuilderOptions, builderOptions));
2463
+ return {
1278
2464
  connectorMap: connectorMap,
1279
2465
  registerConnector: registerConnector,
1280
2466
  getConnector: getConnector,
1281
- generateEmptyDSL: generateEmptyDSL,
1282
- from: fromVBIDSLInput,
1283
- create: fromVBIDSLInput
1284
- });
2467
+ generateEmptyChartDSL: generateEmptyChartDSL,
2468
+ createChart
2469
+ };
2470
+ }
1285
2471
  const VBI = createVBI();
1286
2472
  exports.ChartTypeBuilder = __webpack_exports__.ChartTypeBuilder;
1287
2473
  exports.DimensionsBuilder = __webpack_exports__.DimensionsBuilder;
@@ -1292,9 +2478,11 @@ exports.MeasuresBuilder = __webpack_exports__.MeasuresBuilder;
1292
2478
  exports.ThemeBuilder = __webpack_exports__.ThemeBuilder;
1293
2479
  exports.UndoManager = __webpack_exports__.UndoManager;
1294
2480
  exports.VBI = __webpack_exports__.VBI;
1295
- exports.VBIBuilder = __webpack_exports__.VBIBuilder;
2481
+ exports.VBIChartBuilder = __webpack_exports__.VBIChartBuilder;
1296
2482
  exports.WhereFilterBuilder = __webpack_exports__.WhereFilterBuilder;
1297
2483
  exports.buildVQuery = __webpack_exports__.buildVQuery;
2484
+ exports.createVBI = __webpack_exports__.createVBI;
2485
+ exports.defaultVBIChartBuilderAdapters = __webpack_exports__.defaultVBIChartBuilderAdapters;
1298
2486
  exports.findTreeNodesBy = __webpack_exports__.findTreeNodesBy;
1299
2487
  exports.id = __webpack_exports__.id;
1300
2488
  exports.isVBIFilter = __webpack_exports__.isVBIFilter;
@@ -1302,6 +2490,7 @@ exports.isVBIHavingFilter = __webpack_exports__.isVBIHavingFilter;
1302
2490
  exports.isVBIHavingGroup = __webpack_exports__.isVBIHavingGroup;
1303
2491
  exports.isVBIWhereGroup = __webpack_exports__.isVBIWhereGroup;
1304
2492
  exports.preorderTraverse = __webpack_exports__.preorderTraverse;
2493
+ exports.resolveVBIChartBuilderAdapters = __webpack_exports__.resolveVBIChartBuilderAdapters;
1305
2494
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1306
2495
  "ChartTypeBuilder",
1307
2496
  "DimensionsBuilder",
@@ -1312,16 +2501,19 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1312
2501
  "ThemeBuilder",
1313
2502
  "UndoManager",
1314
2503
  "VBI",
1315
- "VBIBuilder",
2504
+ "VBIChartBuilder",
1316
2505
  "WhereFilterBuilder",
1317
2506
  "buildVQuery",
2507
+ "createVBI",
2508
+ "defaultVBIChartBuilderAdapters",
1318
2509
  "findTreeNodesBy",
1319
2510
  "id",
1320
2511
  "isVBIFilter",
1321
2512
  "isVBIHavingFilter",
1322
2513
  "isVBIHavingGroup",
1323
2514
  "isVBIWhereGroup",
1324
- "preorderTraverse"
2515
+ "preorderTraverse",
2516
+ "resolveVBIChartBuilderAdapters"
1325
2517
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
1326
2518
  Object.defineProperty(exports, '__esModule', {
1327
2519
  value: true