@visactor/vbi 0.4.15 → 0.4.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/builder/{sub-builders → features}/chart-type/chart-type-builder.d.ts +1 -1
  2. package/dist/builder/{sub-builders → features}/dimensions/dim-builder.d.ts +11 -11
  3. package/dist/builder/{sub-builders → features}/dimensions/dim-node-builder.d.ts +5 -1
  4. package/dist/builder/features/dimensions/dimension-utils.d.ts +4 -0
  5. package/dist/builder/{sub-builders/havingFilters → features/havingFilter}/having-builder.d.ts +15 -15
  6. package/dist/builder/{sub-builders/havingFilters → features/havingFilter}/having-group-builder.d.ts +4 -3
  7. package/dist/builder/{sub-builders/havingFilters → features/havingFilter}/having-node-builder.d.ts +2 -2
  8. package/dist/builder/features/havingFilter/having-utils.d.ts +9 -0
  9. package/dist/builder/features/havingFilter/index.d.ts +3 -0
  10. package/dist/builder/features/index.d.ts +9 -0
  11. package/dist/builder/features/limit/index.d.ts +1 -0
  12. package/dist/builder/features/limit/limit-builder.d.ts +31 -0
  13. package/dist/builder/features/locale/index.d.ts +1 -0
  14. package/dist/builder/features/locale/locale-builder.d.ts +31 -0
  15. package/dist/builder/{sub-builders → features}/measures/mea-builder.d.ts +10 -10
  16. package/dist/builder/{sub-builders → features}/measures/mea-node-builder.d.ts +5 -1
  17. package/dist/builder/features/measures/measure-utils.d.ts +4 -0
  18. package/dist/builder/features/theme/index.d.ts +1 -0
  19. package/dist/builder/features/theme/theme-builder.d.ts +31 -0
  20. package/dist/builder/features/undo-manager/index.d.ts +1 -0
  21. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/index.d.ts +1 -1
  22. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/where-builder.d.ts +14 -14
  23. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/where-group-builder.d.ts +2 -1
  24. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/where-node-builder.d.ts +6 -1
  25. package/dist/builder/features/whereFilter/where-utils.d.ts +9 -0
  26. package/dist/builder/index.d.ts +2 -3
  27. package/dist/builder/modules/apply-update.d.ts +2 -0
  28. package/dist/builder/modules/build-vquery.d.ts +4 -0
  29. package/dist/builder/modules/build-vseed.d.ts +8 -0
  30. package/dist/builder/modules/build.d.ts +3 -0
  31. package/dist/builder/modules/create-builder-features.d.ts +14 -0
  32. package/dist/builder/modules/encode-state-as-update.d.ts +2 -0
  33. package/dist/builder/modules/get-schema.d.ts +5 -0
  34. package/dist/builder/modules/index.d.ts +8 -0
  35. package/dist/builder/modules/is-empty.d.ts +2 -0
  36. package/dist/builder/vbi-builder.d.ts +13 -17
  37. package/dist/index.cjs +921 -598
  38. package/dist/index.d.ts +3 -2
  39. package/dist/index.js +904 -599
  40. package/dist/types/builder/VBIInterface.d.ts +7 -5
  41. package/dist/types/dsl/dimensions/dimensions.d.ts +2 -0
  42. package/dist/types/dsl/{havingFilters → havingFilter}/having.d.ts +10 -6
  43. package/dist/types/dsl/index.d.ts +4 -5
  44. package/dist/types/dsl/measures/measures.d.ts +18 -2
  45. package/dist/types/dsl/vbi/vbi.d.ts +42 -4
  46. package/dist/types/dsl/{whereFilters → whereFilter}/filters.d.ts +10 -6
  47. package/dist/utils/filter-guards.d.ts +5 -0
  48. package/dist/utils/index.d.ts +1 -0
  49. package/dist/vbi/create-vbi.d.ts +14 -0
  50. package/dist/vbi/from/from-vbi-dsl-input.d.ts +3 -0
  51. package/dist/vbi/from/set-base-dsl-fields.d.ts +3 -0
  52. package/dist/vbi/generate-empty-dsl.d.ts +3 -0
  53. package/dist/vbi/normalize/ensure-having-group.d.ts +2 -0
  54. package/dist/vbi/normalize/ensure-where-group.d.ts +2 -0
  55. package/dist/vbi/normalize/ensure-y-array.d.ts +3 -0
  56. package/dist/vbi/normalize/to-y-map.d.ts +3 -0
  57. package/dist/vbi/normalize/types.d.ts +5 -0
  58. package/dist/vbi.d.ts +14 -0
  59. package/package.json +5 -5
  60. package/dist/builder/sub-builders/havingFilters/index.d.ts +0 -3
  61. package/dist/builder/sub-builders/index.d.ts +0 -5
  62. package/dist/builder/vbi.d.ts +0 -16
  63. /package/dist/builder/{sub-builders → features}/chart-type/index.d.ts +0 -0
  64. /package/dist/builder/{sub-builders → features}/dimensions/index.d.ts +0 -0
  65. /package/dist/builder/{sub-builders → features}/measures/index.d.ts +0 -0
  66. /package/dist/builder/{undo-manager.d.ts → features/undo-manager/undo-manager.d.ts} +0 -0
package/dist/index.cjs CHANGED
@@ -24,102 +24,268 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
- preorderTraverse: ()=>vseed_namespaceObject.preorderTraverse,
27
+ HavingFilterBuilder: ()=>HavingFilterBuilder,
28
+ WhereFilterBuilder: ()=>WhereFilterBuilder,
28
29
  isVBIHavingGroup: ()=>isVBIHavingGroup,
30
+ VBIBuilder: ()=>VBIBuilder,
31
+ VBI: ()=>VBI,
32
+ isVBIHavingFilter: ()=>isVBIHavingFilter,
33
+ findTreeNodesBy: ()=>vseed_namespaceObject.findTreeNodesBy,
34
+ ThemeBuilder: ()=>ThemeBuilder,
35
+ id: ()=>id_id,
29
36
  MeasuresBuilder: ()=>MeasuresBuilder,
37
+ LimitBuilder: ()=>LimitBuilder,
30
38
  DimensionsBuilder: ()=>DimensionsBuilder,
31
- VBIBuilder: ()=>VBIBuilder,
32
39
  ChartTypeBuilder: ()=>ChartTypeBuilder,
33
40
  isVBIFilter: ()=>isVBIFilter,
34
- VBI: ()=>VBI,
35
41
  isVBIWhereGroup: ()=>isVBIWhereGroup,
36
- isVBIHavingFilter: ()=>isVBIHavingFilter,
42
+ preorderTraverse: ()=>vseed_namespaceObject.preorderTraverse,
37
43
  buildVQuery: ()=>buildVQuery,
38
- findTreeNodesBy: ()=>vseed_namespaceObject.findTreeNodesBy,
39
- id: ()=>id_id
44
+ LocaleBuilder: ()=>LocaleBuilder,
45
+ UndoManager: ()=>UndoManager
40
46
  });
47
+ const connectorMap = new Map();
48
+ const registerConnector = (id, connector)=>{
49
+ connectorMap.set(id, connector);
50
+ };
51
+ const getConnector = async (id)=>{
52
+ const connector = connectorMap.get(id);
53
+ if (!connector) throw new Error(`connector ${id} not registered`);
54
+ if ('function' == typeof connector) return connector();
55
+ return connector;
56
+ };
41
57
  const external_yjs_namespaceObject = require("yjs");
42
- class DimensionNodeBuilder {
43
- yMap;
44
- constructor(yMap){
45
- this.yMap = yMap;
46
- }
47
- getField() {
48
- return this.yMap.get('field');
49
- }
50
- setAlias(alias) {
51
- this.yMap.set('alias', alias);
52
- return this;
53
- }
54
- toJson() {
55
- return this.yMap.toJSON();
56
- }
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
+ 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;
57
107
  }
58
- class DimensionsBuilder {
59
- dsl;
60
- constructor(_doc, dsl){
61
- this.dsl = dsl;
62
- }
63
- add(field, callback) {
64
- const dimension = {
65
- alias: field,
66
- field
67
- };
68
- const yMap = new external_yjs_namespaceObject.Map();
69
- for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
70
- this.dsl.get('dimensions').push([
71
- yMap
72
- ]);
73
- const node = new DimensionNodeBuilder(yMap);
74
- callback(node);
75
- return this;
76
- }
77
- remove(field) {
78
- const dimensions = this.dsl.get('dimensions');
79
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
80
- if (-1 !== index) this.dsl.get('dimensions').delete(index, 1);
81
- return this;
82
- }
83
- update(field, callback) {
84
- const dimensions = this.dsl.get('dimensions');
85
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
86
- if (-1 === index) throw new Error(`Dimension with field "${field}" not found`);
87
- const dimensionYMap = dimensions.get(index);
88
- const node = new DimensionNodeBuilder(dimensionYMap);
89
- callback(node);
90
- return this;
91
- }
92
- find(field) {
93
- const dimensions = this.dsl.get('dimensions');
94
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
95
- if (-1 === index) return;
96
- return new DimensionNodeBuilder(dimensions.get(index));
97
- }
98
- findAll() {
99
- const dimensions = this.dsl.get('dimensions');
100
- return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
101
- }
102
- toJson() {
103
- return this.dsl.get('dimensions').toJSON();
104
- }
105
- observe(callback) {
106
- this.dsl.get('dimensions').observe(callback);
107
- return ()=>{
108
- this.dsl.get('dimensions').unobserve(callback);
109
- };
110
- }
111
- static isDimensionNode(node) {
112
- return 'alias' in node && !('children' in node);
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
+ ];
113
148
  }
114
- static isDimensionGroup(node) {
115
- return 'children' in node;
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';
116
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
+ ];
117
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
+ };
118
281
  class MeasureNodeBuilder {
119
282
  yMap;
120
283
  constructor(yMap){
121
284
  this.yMap = yMap;
122
285
  }
286
+ getId() {
287
+ return this.yMap.get('id');
288
+ }
123
289
  getField() {
124
290
  return this.yMap.get('field');
125
291
  }
@@ -135,17 +301,52 @@ class MeasureNodeBuilder {
135
301
  this.yMap.set('aggregate', aggregate);
136
302
  return this;
137
303
  }
138
- toJson() {
304
+ toJSON() {
139
305
  return this.yMap.toJSON();
140
306
  }
141
307
  }
308
+ const vseed_namespaceObject = require("@visactor/vseed");
309
+ const external_uuid_namespaceObject = require("uuid");
310
+ const id_id = {
311
+ uuid: ()=>(0, external_uuid_namespaceObject.v4)()
312
+ };
313
+ function isVBIFilter(clause) {
314
+ return 'field' in clause;
315
+ }
316
+ function isVBIWhereGroup(clause) {
317
+ return 'conditions' in clause;
318
+ }
319
+ function isVBIHavingFilter(clause) {
320
+ return 'field' in clause;
321
+ }
322
+ function isVBIHavingGroup(clause) {
323
+ return 'conditions' in clause;
324
+ }
325
+ const getOrCreateMeasures = (dsl)=>{
326
+ const measures = dsl.get('measures');
327
+ if (measures instanceof external_yjs_namespaceObject.Array) return measures;
328
+ const yMeasures = new external_yjs_namespaceObject.Array();
329
+ dsl.set('measures', yMeasures);
330
+ return yMeasures;
331
+ };
332
+ const normalizeMeasureNodeIds = (measures)=>{
333
+ measures.toArray().forEach((item)=>{
334
+ if (item instanceof external_yjs_namespaceObject.Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
335
+ });
336
+ };
337
+ const locateMeasureIndexById = (measures, measureId)=>measures.toArray().findIndex((item)=>item.get('id') === measureId);
142
338
  class MeasuresBuilder {
143
339
  dsl;
144
- constructor(_doc, dsl){
340
+ constructor(doc, dsl){
145
341
  this.dsl = dsl;
342
+ doc.transact(()=>{
343
+ const measures = getOrCreateMeasures(this.dsl);
344
+ normalizeMeasureNodeIds(measures);
345
+ });
146
346
  }
147
347
  add(field, callback) {
148
348
  const measure = {
349
+ id: id_id.uuid(),
149
350
  alias: field,
150
351
  field,
151
352
  encoding: 'yAxis',
@@ -155,45 +356,50 @@ class MeasuresBuilder {
155
356
  };
156
357
  const yMap = new external_yjs_namespaceObject.Map();
157
358
  for (const [key, value] of Object.entries(measure))yMap.set(key, value);
158
- this.dsl.get('measures').push([
359
+ const measures = getOrCreateMeasures(this.dsl);
360
+ measures.push([
159
361
  yMap
160
362
  ]);
161
363
  const node = new MeasureNodeBuilder(yMap);
162
364
  callback(node);
163
365
  return this;
164
366
  }
165
- remove(field) {
166
- const measures = this.dsl.get('measures');
167
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
168
- if (-1 !== index) this.dsl.get('measures').delete(index, 1);
367
+ remove(id) {
368
+ const measures = getOrCreateMeasures(this.dsl);
369
+ const index = locateMeasureIndexById(measures, id);
370
+ if (-1 !== index) measures.delete(index, 1);
169
371
  return this;
170
372
  }
171
- update(field, callback) {
172
- const measures = this.dsl.get('measures');
173
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
174
- if (-1 === index) throw new Error(`Measure with field "${field}" not found`);
373
+ 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`);
175
377
  const measureYMap = measures.get(index);
176
378
  const node = new MeasureNodeBuilder(measureYMap);
177
379
  callback(node);
178
380
  return this;
179
381
  }
180
- find(field) {
181
- const measures = this.dsl.get('measures');
182
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
183
- if (-1 === index) return;
184
- return new MeasureNodeBuilder(measures.get(index));
382
+ find(predicate) {
383
+ const measures = getOrCreateMeasures(this.dsl);
384
+ const items = measures.toArray();
385
+ for(let index = 0; index < items.length; index++){
386
+ const node = new MeasureNodeBuilder(items[index]);
387
+ if (predicate(node, index)) return node;
388
+ }
185
389
  }
186
390
  findAll() {
187
- const measures = this.dsl.get('measures');
391
+ const measures = getOrCreateMeasures(this.dsl);
188
392
  return measures.toArray().map((yMap)=>new MeasureNodeBuilder(yMap));
189
393
  }
190
- toJson() {
191
- return this.dsl.get('measures').toJSON();
394
+ toJSON() {
395
+ const measures = getOrCreateMeasures(this.dsl);
396
+ return measures.toJSON();
192
397
  }
193
398
  observe(callback) {
194
- this.dsl.get('measures').observe(callback);
399
+ const measures = getOrCreateMeasures(this.dsl);
400
+ measures.observe(callback);
195
401
  return ()=>{
196
- this.dsl.get('measures').unobserve(callback);
402
+ measures.unobserve(callback);
197
403
  };
198
404
  }
199
405
  static isMeasureNode(node) {
@@ -203,12 +409,7 @@ class MeasuresBuilder {
203
409
  return 'children' in node;
204
410
  }
205
411
  }
206
- const vseed_namespaceObject = require("@visactor/vseed");
207
- const external_uuid_namespaceObject = require("uuid");
208
- const id_id = {
209
- uuid: ()=>(0, external_uuid_namespaceObject.v4)()
210
- };
211
- class HavingFiltersNodeBuilder {
412
+ class DimensionNodeBuilder {
212
413
  yMap;
213
414
  constructor(yMap){
214
415
  this.yMap = yMap;
@@ -219,26 +420,210 @@ class HavingFiltersNodeBuilder {
219
420
  getField() {
220
421
  return this.yMap.get('field');
221
422
  }
222
- getOperator() {
223
- return this.yMap.get('op');
224
- }
225
- setValue(value) {
226
- this.yMap.set('value', value);
423
+ setAlias(alias) {
424
+ this.yMap.set('alias', alias);
425
+ return this;
426
+ }
427
+ toJSON() {
428
+ return this.yMap.toJSON();
429
+ }
430
+ }
431
+ const getOrCreateDimensions = (dsl)=>{
432
+ const dimensions = dsl.get('dimensions');
433
+ if (dimensions instanceof external_yjs_namespaceObject.Array) return dimensions;
434
+ const yDimensions = new external_yjs_namespaceObject.Array();
435
+ dsl.set('dimensions', yDimensions);
436
+ return yDimensions;
437
+ };
438
+ const normalizeDimensionNodeIds = (dimensions)=>{
439
+ dimensions.toArray().forEach((item)=>{
440
+ if (item instanceof external_yjs_namespaceObject.Map && 'string' == typeof item.get('field') && !item.get('id')) item.set('id', id_id.uuid());
441
+ });
442
+ };
443
+ const locateDimensionIndexById = (dimensions, dimensionId)=>dimensions.toArray().findIndex((item)=>item.get('id') === dimensionId);
444
+ class DimensionsBuilder {
445
+ dsl;
446
+ constructor(doc, dsl){
447
+ this.dsl = dsl;
448
+ doc.transact(()=>{
449
+ const dimensions = getOrCreateDimensions(this.dsl);
450
+ normalizeDimensionNodeIds(dimensions);
451
+ });
452
+ }
453
+ add(field, callback) {
454
+ const dimension = {
455
+ id: id_id.uuid(),
456
+ alias: field,
457
+ field
458
+ };
459
+ 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);
467
+ return this;
468
+ }
469
+ remove(id) {
470
+ const dimensions = getOrCreateDimensions(this.dsl);
471
+ const index = locateDimensionIndexById(dimensions, id);
472
+ if (-1 !== index) dimensions.delete(index, 1);
227
473
  return this;
228
474
  }
475
+ 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);
482
+ return this;
483
+ }
484
+ find(predicate) {
485
+ const dimensions = getOrCreateDimensions(this.dsl);
486
+ const items = dimensions.toArray();
487
+ for(let index = 0; index < items.length; index++){
488
+ const node = new DimensionNodeBuilder(items[index]);
489
+ if (predicate(node, index)) return node;
490
+ }
491
+ }
492
+ findAll() {
493
+ const dimensions = getOrCreateDimensions(this.dsl);
494
+ return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
495
+ }
496
+ toJSON() {
497
+ const dimensions = getOrCreateDimensions(this.dsl);
498
+ return dimensions.toJSON();
499
+ }
500
+ observe(callback) {
501
+ const dimensions = getOrCreateDimensions(this.dsl);
502
+ dimensions.observe(callback);
503
+ return ()=>{
504
+ dimensions.unobserve(callback);
505
+ };
506
+ }
507
+ static isDimensionNode(node) {
508
+ return 'alias' in node && !('children' in node);
509
+ }
510
+ static isDimensionGroup(node) {
511
+ return 'children' in node;
512
+ }
513
+ }
514
+ class ChartTypeBuilder {
515
+ dsl;
516
+ constructor(_doc, dsl){
517
+ this.dsl = dsl;
518
+ }
519
+ observe(callback) {
520
+ const wrapper = (e, trans)=>{
521
+ if (e.keysChanged.has('chartType')) callback(e, trans);
522
+ };
523
+ this.dsl.observe(wrapper);
524
+ return ()=>{
525
+ this.dsl.unobserve(wrapper);
526
+ };
527
+ }
528
+ changeChartType(chartType) {
529
+ this.dsl.set('chartType', chartType);
530
+ }
531
+ getChartType() {
532
+ return this.dsl.get('chartType') || 'table';
533
+ }
534
+ toJSON() {
535
+ return this.dsl.get('chartType') || 'table';
536
+ }
537
+ getAvailableChartTypes() {
538
+ return [
539
+ vseed_namespaceObject.ChartTypeEnum.Table,
540
+ vseed_namespaceObject.ChartTypeEnum.PivotTable,
541
+ vseed_namespaceObject.ChartTypeEnum.Line,
542
+ vseed_namespaceObject.ChartTypeEnum.Column,
543
+ vseed_namespaceObject.ChartTypeEnum.ColumnPercent,
544
+ vseed_namespaceObject.ChartTypeEnum.ColumnParallel,
545
+ vseed_namespaceObject.ChartTypeEnum.BarPercent,
546
+ vseed_namespaceObject.ChartTypeEnum.BarParallel,
547
+ vseed_namespaceObject.ChartTypeEnum.Area,
548
+ vseed_namespaceObject.ChartTypeEnum.AreaPercent,
549
+ vseed_namespaceObject.ChartTypeEnum.DualAxis,
550
+ vseed_namespaceObject.ChartTypeEnum.Scatter,
551
+ vseed_namespaceObject.ChartTypeEnum.Rose,
552
+ vseed_namespaceObject.ChartTypeEnum.RoseParallel,
553
+ vseed_namespaceObject.ChartTypeEnum.Pie,
554
+ vseed_namespaceObject.ChartTypeEnum.Donut,
555
+ vseed_namespaceObject.ChartTypeEnum.Radar,
556
+ vseed_namespaceObject.ChartTypeEnum.Funnel,
557
+ vseed_namespaceObject.ChartTypeEnum.Heatmap,
558
+ vseed_namespaceObject.ChartTypeEnum.Boxplot,
559
+ vseed_namespaceObject.ChartTypeEnum.Histogram
560
+ ];
561
+ }
562
+ }
563
+ function createWhereGroup(op = 'and', groupId = 'root') {
564
+ const yMap = new external_yjs_namespaceObject.Map();
565
+ yMap.set('id', groupId);
566
+ yMap.set('op', op);
567
+ yMap.set('conditions', new external_yjs_namespaceObject.Array());
568
+ return yMap;
569
+ }
570
+ function where_utils_isWhereGroup(yMap) {
571
+ return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
572
+ }
573
+ function findEntry(collection, entryId) {
574
+ const items = collection.toArray();
575
+ for(let index = 0; index < items.length; index++){
576
+ const item = items[index];
577
+ if (item.get('id') === entryId) return {
578
+ collection,
579
+ index,
580
+ item
581
+ };
582
+ if (where_utils_isWhereGroup(item)) {
583
+ const nestedCollection = item.get('conditions');
584
+ const nestedMatch = findEntry(nestedCollection, entryId);
585
+ if (nestedMatch) return nestedMatch;
586
+ }
587
+ }
588
+ }
589
+ class WhereFilterNodeBuilder {
590
+ yMap;
591
+ constructor(yMap){
592
+ this.yMap = yMap;
593
+ }
594
+ getId() {
595
+ return this.yMap.get('id');
596
+ }
597
+ getField() {
598
+ return this.yMap.get('field');
599
+ }
600
+ setField(field) {
601
+ this.yMap.set('field', field);
602
+ return this;
603
+ }
604
+ getOperator() {
605
+ return this.yMap.get('op');
606
+ }
229
607
  setOperator(operator) {
230
608
  this.yMap.set('op', operator);
231
609
  return this;
232
610
  }
233
- toJson() {
611
+ setValue(value) {
612
+ this.yMap.set('value', value);
613
+ return this;
614
+ }
615
+ toJSON() {
234
616
  return this.yMap.toJSON();
235
617
  }
236
618
  }
237
- class HavingGroupBuilder {
619
+ class WhereGroupBuilder {
238
620
  yMap;
239
621
  constructor(yMap){
240
622
  this.yMap = yMap;
241
623
  }
624
+ getConditions() {
625
+ return this.yMap.get('conditions');
626
+ }
242
627
  getId() {
243
628
  return this.yMap.get('id');
244
629
  }
@@ -253,29 +638,24 @@ class HavingGroupBuilder {
253
638
  const yMap = new external_yjs_namespaceObject.Map();
254
639
  yMap.set('id', id_id.uuid());
255
640
  yMap.set('field', field);
256
- const conditions = this.yMap.get('conditions');
257
- conditions.push([
641
+ this.getConditions().push([
258
642
  yMap
259
643
  ]);
260
- const node = new HavingFiltersNodeBuilder(yMap);
644
+ const node = new WhereFilterNodeBuilder(yMap);
261
645
  callback(node);
262
646
  return this;
263
647
  }
264
648
  addGroup(op, callback) {
265
- const yMap = new external_yjs_namespaceObject.Map();
266
- yMap.set('id', id_id.uuid());
267
- yMap.set('op', op);
268
- yMap.set('conditions', new external_yjs_namespaceObject.Array());
269
- const conditions = this.yMap.get('conditions');
270
- conditions.push([
649
+ const yMap = createWhereGroup(op, id_id.uuid());
650
+ this.getConditions().push([
271
651
  yMap
272
652
  ]);
273
- const group = new HavingGroupBuilder(yMap);
653
+ const group = new WhereGroupBuilder(yMap);
274
654
  callback(group);
275
655
  return this;
276
656
  }
277
657
  remove(idOrIndex) {
278
- const conditions = this.yMap.get('conditions');
658
+ const conditions = this.getConditions();
279
659
  if ('number' == typeof idOrIndex) {
280
660
  if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
281
661
  } else {
@@ -285,154 +665,146 @@ class HavingGroupBuilder {
285
665
  return this;
286
666
  }
287
667
  clear() {
288
- const conditions = this.yMap.get('conditions');
668
+ const conditions = this.getConditions();
289
669
  conditions.delete(0, conditions.length);
290
670
  return this;
291
671
  }
292
- toJson() {
672
+ toJSON() {
293
673
  return this.yMap.toJSON();
294
674
  }
295
675
  }
296
- class HavingFiltersBuilder {
297
- dsl;
298
- doc;
676
+ class WhereFilterBuilder {
677
+ whereFilter;
299
678
  constructor(doc, dsl){
300
- this.doc = doc;
301
- this.dsl = dsl;
302
- if (!this.dsl.get('havingFilters')) this.doc.transact(()=>{
303
- this.dsl.set('havingFilters', new external_yjs_namespaceObject.Array());
679
+ doc.transact(()=>{
680
+ const existingWhereFilter = dsl.get('whereFilter');
681
+ if (existingWhereFilter instanceof external_yjs_namespaceObject.Map) this.whereFilter = existingWhereFilter;
682
+ else {
683
+ this.whereFilter = createWhereGroup();
684
+ dsl.set('whereFilter', this.whereFilter);
685
+ }
686
+ if (!(this.whereFilter.get('conditions') instanceof external_yjs_namespaceObject.Array)) this.whereFilter.set('conditions', new external_yjs_namespaceObject.Array());
687
+ if (!this.whereFilter.get('id')) this.whereFilter.set('id', 'root');
688
+ if (!this.whereFilter.get('op')) this.whereFilter.set('op', 'and');
304
689
  });
305
690
  }
691
+ getConditions() {
692
+ return this.whereFilter.get('conditions');
693
+ }
306
694
  add(field, callback) {
307
695
  const yMap = new external_yjs_namespaceObject.Map();
308
696
  yMap.set('id', id_id.uuid());
309
697
  yMap.set('field', field);
310
- this.dsl.get('havingFilters').push([
698
+ this.getConditions().push([
311
699
  yMap
312
700
  ]);
313
- const node = new HavingFiltersNodeBuilder(yMap);
701
+ const node = new WhereFilterNodeBuilder(yMap);
314
702
  callback(node);
315
703
  return this;
316
704
  }
317
705
  addGroup(op, callback) {
318
- const yMap = new external_yjs_namespaceObject.Map();
319
- yMap.set('id', id_id.uuid());
320
- yMap.set('op', op);
321
- yMap.set('conditions', new external_yjs_namespaceObject.Array());
322
- this.dsl.get('havingFilters').push([
706
+ const yMap = createWhereGroup(op, id_id.uuid());
707
+ this.getConditions().push([
323
708
  yMap
324
709
  ]);
325
- const group = new HavingGroupBuilder(yMap);
710
+ const group = new WhereGroupBuilder(yMap);
326
711
  callback(group);
327
712
  return this;
328
713
  }
329
714
  update(id, callback) {
330
- const havingFilters = this.dsl.get('havingFilters');
331
- const index = havingFilters.toArray().findIndex((item)=>item.get('id') === id);
332
- if (-1 === index) throw new Error(`Having filter with id ${id} not found`);
333
- const filterYMap = havingFilters.get(index);
334
- const node = new HavingFiltersNodeBuilder(filterYMap);
715
+ const conditions = this.getConditions();
716
+ const match = findEntry(conditions, id);
717
+ if (!match) throw new Error(`Where filter with id ${id} not found`);
718
+ if (!WhereFilterBuilder.isNode(match.item)) throw new Error(`Item with id ${id} is not a filter`);
719
+ const filterYMap = match.item;
720
+ const node = new WhereFilterNodeBuilder(filterYMap);
335
721
  callback(node);
336
722
  return this;
337
723
  }
338
724
  updateGroup(id, callback) {
339
- const havingFilters = this.dsl.get('havingFilters');
340
- const index = havingFilters.toArray().findIndex((item)=>item.get('id') === id);
341
- if (-1 === index) throw new Error(`Having group with id ${id} not found`);
342
- const yMap = havingFilters.get(index);
343
- if (!HavingFiltersBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
344
- const group = new HavingGroupBuilder(yMap);
725
+ const conditions = this.getConditions();
726
+ const match = findEntry(conditions, id);
727
+ if (!match) throw new Error(`Where group with id ${id} not found`);
728
+ const yMap = match.item;
729
+ if (!WhereFilterBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
730
+ const group = new WhereGroupBuilder(yMap);
345
731
  callback(group);
346
732
  return this;
347
733
  }
348
734
  remove(idOrIndex) {
349
- const havingFilters = this.dsl.get('havingFilters');
735
+ const conditions = this.getConditions();
350
736
  if ('number' == typeof idOrIndex) {
351
- if (idOrIndex >= 0 && idOrIndex < havingFilters.length) havingFilters.delete(idOrIndex, 1);
737
+ if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
352
738
  } else {
353
- const index = havingFilters.toArray().findIndex((item)=>item.get('id') === idOrIndex);
354
- if (-1 !== index) havingFilters.delete(index, 1);
739
+ const match = findEntry(conditions, idOrIndex);
740
+ if (match) match.collection.delete(match.index, 1);
355
741
  }
356
742
  return this;
357
743
  }
358
- find(id) {
359
- const havingFilters = this.dsl.get('havingFilters');
360
- const yMap = havingFilters.toArray().find((item)=>item.get('id') === id);
361
- if (!yMap) return;
362
- if (HavingFiltersBuilder.isGroup(yMap)) return new HavingGroupBuilder(yMap);
363
- return new HavingFiltersNodeBuilder(yMap);
744
+ find(predicate) {
745
+ const traverse = (collection)=>{
746
+ const items = collection.toArray();
747
+ for(let index = 0; index < items.length; index++){
748
+ const yMap = items[index];
749
+ const entry = WhereFilterBuilder.isGroup(yMap) ? new WhereGroupBuilder(yMap) : new WhereFilterNodeBuilder(yMap);
750
+ if (predicate(entry, index)) return entry;
751
+ if (WhereFilterBuilder.isGroup(yMap)) {
752
+ const nestedCollection = yMap.get('conditions');
753
+ const nestedMatch = traverse(nestedCollection);
754
+ if (nestedMatch) return nestedMatch;
755
+ }
756
+ }
757
+ };
758
+ return traverse(this.getConditions());
364
759
  }
365
760
  clear() {
366
- const havingFilters = this.dsl.get('havingFilters');
367
- havingFilters.delete(0, havingFilters.length);
761
+ const conditions = this.getConditions();
762
+ conditions.delete(0, conditions.length);
368
763
  return this;
369
764
  }
370
- toJson() {
371
- return this.dsl.get('havingFilters').toJSON();
765
+ toJSON() {
766
+ return this.whereFilter.toJSON();
372
767
  }
373
768
  observe(callback) {
374
- this.dsl.get('havingFilters').observe(callback);
769
+ this.whereFilter.observeDeep(callback);
375
770
  return ()=>{
376
- this.dsl.get('havingFilters').unobserve(callback);
771
+ this.whereFilter.unobserveDeep(callback);
377
772
  };
378
773
  }
379
774
  static isGroup(yMap) {
380
- return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
775
+ return where_utils_isWhereGroup(yMap);
381
776
  }
382
777
  static isNode(yMap) {
383
778
  return void 0 !== yMap.get('field');
384
779
  }
385
780
  }
386
- class ChartTypeBuilder {
387
- dsl;
388
- constructor(_doc, dsl){
389
- this.dsl = dsl;
390
- }
391
- observe(callback) {
392
- const wrapper = (e, trans)=>{
393
- if (e.keysChanged.has('chartType')) callback(e, trans);
394
- };
395
- this.dsl.observe(wrapper);
396
- return ()=>{
397
- this.dsl.unobserve(wrapper);
781
+ function createHavingGroup(op = 'and', groupId = 'root') {
782
+ const yMap = new external_yjs_namespaceObject.Map();
783
+ yMap.set('id', groupId);
784
+ yMap.set('op', op);
785
+ yMap.set('conditions', new external_yjs_namespaceObject.Array());
786
+ return yMap;
787
+ }
788
+ function having_utils_isHavingGroup(yMap) {
789
+ return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
790
+ }
791
+ function having_utils_findEntry(collection, entryId) {
792
+ const items = collection.toArray();
793
+ for(let index = 0; index < items.length; index++){
794
+ const item = items[index];
795
+ if (item.get('id') === entryId) return {
796
+ collection,
797
+ index,
798
+ item
398
799
  };
399
- }
400
- changeChartType(chartType) {
401
- this.dsl.set('chartType', chartType);
402
- }
403
- getChartType() {
404
- return this.dsl.get('chartType') || 'table';
405
- }
406
- toJson() {
407
- return this.dsl.get('chartType') || 'table';
408
- }
409
- getAvailableChartTypes() {
410
- return [
411
- vseed_namespaceObject.ChartTypeEnum.Table,
412
- vseed_namespaceObject.ChartTypeEnum.PivotTable,
413
- vseed_namespaceObject.ChartTypeEnum.Line,
414
- vseed_namespaceObject.ChartTypeEnum.Column,
415
- vseed_namespaceObject.ChartTypeEnum.ColumnPercent,
416
- vseed_namespaceObject.ChartTypeEnum.ColumnParallel,
417
- vseed_namespaceObject.ChartTypeEnum.BarPercent,
418
- vseed_namespaceObject.ChartTypeEnum.BarParallel,
419
- vseed_namespaceObject.ChartTypeEnum.Area,
420
- vseed_namespaceObject.ChartTypeEnum.AreaPercent,
421
- vseed_namespaceObject.ChartTypeEnum.DualAxis,
422
- vseed_namespaceObject.ChartTypeEnum.Scatter,
423
- vseed_namespaceObject.ChartTypeEnum.Rose,
424
- vseed_namespaceObject.ChartTypeEnum.RoseParallel,
425
- vseed_namespaceObject.ChartTypeEnum.Pie,
426
- vseed_namespaceObject.ChartTypeEnum.Donut,
427
- vseed_namespaceObject.ChartTypeEnum.Radar,
428
- vseed_namespaceObject.ChartTypeEnum.Funnel,
429
- vseed_namespaceObject.ChartTypeEnum.Heatmap,
430
- vseed_namespaceObject.ChartTypeEnum.Boxplot,
431
- vseed_namespaceObject.ChartTypeEnum.Histogram
432
- ];
800
+ if (having_utils_isHavingGroup(item)) {
801
+ const nestedCollection = item.get('conditions');
802
+ const nestedMatch = having_utils_findEntry(nestedCollection, entryId);
803
+ if (nestedMatch) return nestedMatch;
804
+ }
433
805
  }
434
806
  }
435
- class WhereFilterNodeBuilder {
807
+ class HavingFilterNodeBuilder {
436
808
  yMap;
437
809
  constructor(yMap){
438
810
  this.yMap = yMap;
@@ -446,23 +818,26 @@ class WhereFilterNodeBuilder {
446
818
  getOperator() {
447
819
  return this.yMap.get('op');
448
820
  }
449
- setOperator(operator) {
450
- this.yMap.set('op', operator);
451
- return this;
452
- }
453
821
  setValue(value) {
454
822
  this.yMap.set('value', value);
455
823
  return this;
456
824
  }
457
- toJson() {
825
+ setOperator(operator) {
826
+ this.yMap.set('op', operator);
827
+ return this;
828
+ }
829
+ toJSON() {
458
830
  return this.yMap.toJSON();
459
831
  }
460
832
  }
461
- class WhereGroupBuilder {
833
+ class HavingGroupBuilder {
462
834
  yMap;
463
835
  constructor(yMap){
464
836
  this.yMap = yMap;
465
837
  }
838
+ getConditions() {
839
+ return this.yMap.get('conditions');
840
+ }
466
841
  getId() {
467
842
  return this.yMap.get('id');
468
843
  }
@@ -477,29 +852,24 @@ class WhereGroupBuilder {
477
852
  const yMap = new external_yjs_namespaceObject.Map();
478
853
  yMap.set('id', id_id.uuid());
479
854
  yMap.set('field', field);
480
- const conditions = this.yMap.get('conditions');
481
- conditions.push([
855
+ this.getConditions().push([
482
856
  yMap
483
857
  ]);
484
- const node = new WhereFilterNodeBuilder(yMap);
858
+ const node = new HavingFilterNodeBuilder(yMap);
485
859
  callback(node);
486
860
  return this;
487
861
  }
488
862
  addGroup(op, callback) {
489
- const yMap = new external_yjs_namespaceObject.Map();
490
- yMap.set('id', id_id.uuid());
491
- yMap.set('op', op);
492
- yMap.set('conditions', new external_yjs_namespaceObject.Array());
493
- const conditions = this.yMap.get('conditions');
494
- conditions.push([
863
+ const yMap = createHavingGroup(op, id_id.uuid());
864
+ this.getConditions().push([
495
865
  yMap
496
866
  ]);
497
- const group = new WhereGroupBuilder(yMap);
867
+ const group = new HavingGroupBuilder(yMap);
498
868
  callback(group);
499
869
  return this;
500
870
  }
501
871
  remove(idOrIndex) {
502
- const conditions = this.yMap.get('conditions');
872
+ const conditions = this.getConditions();
503
873
  if ('number' == typeof idOrIndex) {
504
874
  if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
505
875
  } else {
@@ -509,104 +879,191 @@ class WhereGroupBuilder {
509
879
  return this;
510
880
  }
511
881
  clear() {
512
- const conditions = this.yMap.get('conditions');
882
+ const conditions = this.getConditions();
513
883
  conditions.delete(0, conditions.length);
514
884
  return this;
515
885
  }
516
- toJson() {
886
+ toJSON() {
517
887
  return this.yMap.toJSON();
518
888
  }
519
889
  }
520
- class WhereFiltersBuilder {
521
- dsl;
522
- doc;
890
+ class HavingFilterBuilder {
891
+ havingFilter;
523
892
  constructor(doc, dsl){
524
- this.doc = doc;
525
- this.dsl = dsl;
526
- if (!this.dsl.get('whereFilters')) this.doc.transact(()=>{
527
- this.dsl.set('whereFilters', new external_yjs_namespaceObject.Array());
893
+ doc.transact(()=>{
894
+ const existingHavingFilter = dsl.get('havingFilter');
895
+ if (existingHavingFilter instanceof external_yjs_namespaceObject.Map) this.havingFilter = existingHavingFilter;
896
+ else {
897
+ this.havingFilter = createHavingGroup();
898
+ dsl.set('havingFilter', this.havingFilter);
899
+ }
900
+ if (!(this.havingFilter.get('conditions') instanceof external_yjs_namespaceObject.Array)) this.havingFilter.set('conditions', new external_yjs_namespaceObject.Array());
901
+ if (!this.havingFilter.get('id')) this.havingFilter.set('id', 'root');
902
+ if (!this.havingFilter.get('op')) this.havingFilter.set('op', 'and');
528
903
  });
529
904
  }
905
+ getConditions() {
906
+ return this.havingFilter.get('conditions');
907
+ }
530
908
  add(field, callback) {
531
909
  const yMap = new external_yjs_namespaceObject.Map();
532
910
  yMap.set('id', id_id.uuid());
533
911
  yMap.set('field', field);
534
- this.dsl.get('whereFilters').push([
912
+ this.getConditions().push([
535
913
  yMap
536
914
  ]);
537
- const node = new WhereFilterNodeBuilder(yMap);
915
+ const node = new HavingFilterNodeBuilder(yMap);
538
916
  callback(node);
539
917
  return this;
540
918
  }
541
919
  addGroup(op, callback) {
542
- const yMap = new external_yjs_namespaceObject.Map();
543
- yMap.set('id', id_id.uuid());
544
- yMap.set('op', op);
545
- yMap.set('conditions', new external_yjs_namespaceObject.Array());
546
- this.dsl.get('whereFilters').push([
920
+ const yMap = createHavingGroup(op, id_id.uuid());
921
+ this.getConditions().push([
547
922
  yMap
548
923
  ]);
549
- const group = new WhereGroupBuilder(yMap);
924
+ const group = new HavingGroupBuilder(yMap);
550
925
  callback(group);
551
926
  return this;
552
927
  }
553
928
  update(id, callback) {
554
- const whereFilters = this.dsl.get('whereFilters');
555
- const index = whereFilters.toArray().findIndex((item)=>item.get('id') === id);
556
- if (-1 === index) throw new Error(`Where filter with id ${id} not found`);
557
- const filterYMap = whereFilters.get(index);
558
- const node = new WhereFilterNodeBuilder(filterYMap);
929
+ const conditions = this.getConditions();
930
+ const match = having_utils_findEntry(conditions, id);
931
+ if (!match) throw new Error(`Having filter with id ${id} not found`);
932
+ if (!HavingFilterBuilder.isNode(match.item)) throw new Error(`Item with id ${id} is not a filter`);
933
+ const filterYMap = match.item;
934
+ const node = new HavingFilterNodeBuilder(filterYMap);
559
935
  callback(node);
560
936
  return this;
561
937
  }
562
938
  updateGroup(id, callback) {
563
- const whereFilters = this.dsl.get('whereFilters');
564
- const index = whereFilters.toArray().findIndex((item)=>item.get('id') === id);
565
- if (-1 === index) throw new Error(`Where group with id ${id} not found`);
566
- const yMap = whereFilters.get(index);
567
- if (!WhereFiltersBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
568
- const group = new WhereGroupBuilder(yMap);
939
+ const conditions = this.getConditions();
940
+ const match = having_utils_findEntry(conditions, id);
941
+ if (!match) throw new Error(`Having group with id ${id} not found`);
942
+ const yMap = match.item;
943
+ if (!HavingFilterBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
944
+ const group = new HavingGroupBuilder(yMap);
569
945
  callback(group);
570
946
  return this;
571
947
  }
572
948
  remove(idOrIndex) {
573
- const whereFilters = this.dsl.get('whereFilters');
949
+ const conditions = this.getConditions();
574
950
  if ('number' == typeof idOrIndex) {
575
- if (idOrIndex >= 0 && idOrIndex < whereFilters.length) whereFilters.delete(idOrIndex, 1);
951
+ if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
576
952
  } else {
577
- const index = whereFilters.toArray().findIndex((item)=>item.get('id') === idOrIndex);
578
- if (-1 !== index) whereFilters.delete(index, 1);
953
+ const match = having_utils_findEntry(conditions, idOrIndex);
954
+ if (match) match.collection.delete(match.index, 1);
579
955
  }
580
956
  return this;
581
957
  }
582
- find(id) {
583
- const whereFilters = this.dsl.get('whereFilters');
584
- const yMap = whereFilters.toArray().find((item)=>item.get('id') === id);
585
- if (!yMap) return;
586
- if (WhereFiltersBuilder.isGroup(yMap)) return new WhereGroupBuilder(yMap);
587
- return new WhereFilterNodeBuilder(yMap);
958
+ find(predicate) {
959
+ const traverse = (collection)=>{
960
+ const items = collection.toArray();
961
+ for(let index = 0; index < items.length; index++){
962
+ const yMap = items[index];
963
+ const entry = HavingFilterBuilder.isGroup(yMap) ? new HavingGroupBuilder(yMap) : new HavingFilterNodeBuilder(yMap);
964
+ if (predicate(entry, index)) return entry;
965
+ if (HavingFilterBuilder.isGroup(yMap)) {
966
+ const nestedCollection = yMap.get('conditions');
967
+ const nestedMatch = traverse(nestedCollection);
968
+ if (nestedMatch) return nestedMatch;
969
+ }
970
+ }
971
+ };
972
+ return traverse(this.getConditions());
588
973
  }
589
974
  clear() {
590
- const whereFilters = this.dsl.get('whereFilters');
591
- whereFilters.delete(0, whereFilters.length);
975
+ const conditions = this.getConditions();
976
+ conditions.delete(0, conditions.length);
592
977
  return this;
593
978
  }
594
- toJson() {
595
- return this.dsl.get('whereFilters').toJSON();
979
+ toJSON() {
980
+ return this.havingFilter.toJSON();
596
981
  }
597
982
  observe(callback) {
598
- this.dsl.get('whereFilters').observe(callback);
983
+ this.havingFilter.observeDeep(callback);
599
984
  return ()=>{
600
- this.dsl.get('whereFilters').unobserve(callback);
985
+ this.havingFilter.unobserveDeep(callback);
601
986
  };
602
987
  }
603
988
  static isGroup(yMap) {
604
- return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
989
+ return having_utils_isHavingGroup(yMap);
605
990
  }
606
991
  static isNode(yMap) {
607
992
  return void 0 !== yMap.get('field');
608
993
  }
609
994
  }
995
+ class ThemeBuilder {
996
+ dsl;
997
+ constructor(_doc, dsl){
998
+ this.dsl = dsl;
999
+ }
1000
+ observe(callback) {
1001
+ const wrapper = (e, trans)=>{
1002
+ if (e.keysChanged.has('theme')) callback(e, trans);
1003
+ };
1004
+ this.dsl.observe(wrapper);
1005
+ return ()=>{
1006
+ this.dsl.unobserve(wrapper);
1007
+ };
1008
+ }
1009
+ setTheme(theme) {
1010
+ this.dsl.set('theme', theme);
1011
+ }
1012
+ getTheme() {
1013
+ return this.dsl.get('theme') || 'light';
1014
+ }
1015
+ toJSON() {
1016
+ return this.getTheme();
1017
+ }
1018
+ }
1019
+ class LocaleBuilder {
1020
+ dsl;
1021
+ constructor(_doc, dsl){
1022
+ this.dsl = dsl;
1023
+ }
1024
+ observe(callback) {
1025
+ const wrapper = (e, trans)=>{
1026
+ if (e.keysChanged.has('locale')) callback(e, trans);
1027
+ };
1028
+ this.dsl.observe(wrapper);
1029
+ return ()=>{
1030
+ this.dsl.unobserve(wrapper);
1031
+ };
1032
+ }
1033
+ setLocale(locale) {
1034
+ this.dsl.set('locale', locale);
1035
+ }
1036
+ getLocale() {
1037
+ return this.dsl.get('locale') || 'zh-CN';
1038
+ }
1039
+ toJSON() {
1040
+ return this.getLocale();
1041
+ }
1042
+ }
1043
+ class LimitBuilder {
1044
+ dsl;
1045
+ constructor(_doc, dsl){
1046
+ this.dsl = dsl;
1047
+ }
1048
+ observe(callback) {
1049
+ const wrapper = (e, trans)=>{
1050
+ if (e.keysChanged.has('limit')) callback(e, trans);
1051
+ };
1052
+ this.dsl.observe(wrapper);
1053
+ return ()=>{
1054
+ this.dsl.unobserve(wrapper);
1055
+ };
1056
+ }
1057
+ setLimit(limit) {
1058
+ this.dsl.set('limit', limit);
1059
+ }
1060
+ getLimit() {
1061
+ return this.dsl.get('limit');
1062
+ }
1063
+ toJSON() {
1064
+ return this.getLimit();
1065
+ }
1066
+ }
610
1067
  class UndoManager {
611
1068
  manager;
612
1069
  constructor(scope){
@@ -628,355 +1085,215 @@ class UndoManager {
628
1085
  this.manager.clear(clearUndoStack, clearRedoStack);
629
1086
  }
630
1087
  }
631
- const external_remeda_namespaceObject = require("remeda");
632
- const buildSelect = (queryDSL, context)=>{
633
- const { vbiDSL } = context;
634
- const measures = vbiDSL.measures;
635
- const dimensions = vbiDSL.dimensions;
636
- const result = {
637
- ...queryDSL
638
- };
639
- const measureNodes = measures.filter((measure)=>MeasuresBuilder.isMeasureNode(measure));
640
- const measureSelects = measureNodes.map((measure)=>({
641
- field: measure.field,
642
- alias: measure.alias,
643
- aggr: measure.aggregate
644
- }));
645
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
646
- const dimensionSelects = dimensionNodes.map((dimension)=>({
647
- field: dimension.field,
648
- alias: dimension.alias
649
- }));
650
- result.select = measureSelects.concat(dimensionSelects);
651
- return result;
652
- };
653
- const buildGroupBy = (queryDSL, context)=>{
654
- const result = {
655
- ...queryDSL
656
- };
657
- const { vbiDSL } = context;
658
- const dimensions = vbiDSL.dimensions;
659
- const dimensionNodes = dimensions.filter((dimension)=>DimensionsBuilder.isDimensionNode(dimension));
660
- result.groupBy = dimensionNodes.map((dimension)=>dimension.field);
661
- return result;
662
- };
663
- const buildWhere = (queryDSL, context)=>{
664
- const { vbiDSL } = context;
665
- const whereFilters = vbiDSL.whereFilters || [];
666
- if (0 === whereFilters.length) return queryDSL;
667
- const result = {
668
- ...queryDSL
669
- };
670
- result.where = {
671
- op: 'and',
672
- conditions: whereFilters.flatMap(mapClauseToCondition)
673
- };
674
- return result;
675
- };
676
- function isWhereGroup(clause) {
677
- return 'op' in clause && 'conditions' in clause;
678
- }
679
- function mapClauseToCondition(clause) {
680
- if (isWhereGroup(clause)) return [
681
- mapGroupToCondition(clause)
682
- ];
683
- return mapFilterToCondition(clause);
684
- }
685
- function mapGroupToCondition(group) {
686
- return {
687
- op: group.op,
688
- conditions: group.conditions.flatMap(mapClauseToCondition)
689
- };
690
- }
691
- function mapFilterToCondition(filter) {
692
- if ('between' === filter.op) return handleBetweenFilter(filter);
693
- return handleSimpleFilter(filter);
694
- }
695
- function handleBetweenFilter(filter) {
696
- const conditions = [];
697
- const value = filter.value;
698
- if (void 0 !== value.min && null !== value.min && '' !== value.min) conditions.push({
699
- field: filter.field,
700
- op: '<' === value.leftOp ? '>' : '>=',
701
- value: value.min
702
- });
703
- if (void 0 !== value.max && null !== value.max && '' !== value.max) conditions.push({
704
- field: filter.field,
705
- op: '<' === value.rightOp ? '<' : '<=',
706
- value: value.max
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)
707
1098
  });
708
- return conditions;
709
- }
710
- function handleSimpleFilter(filter) {
711
- let mappedOp = filter.op ?? '=';
712
- const value = filter.value;
713
- if (Array.isArray(value)) {
714
- if ('=' === mappedOp) mappedOp = 'in';
715
- if ('!=' === mappedOp) mappedOp = 'not in';
716
- }
717
- return [
718
- {
719
- field: filter.field,
720
- op: mappedOp,
721
- value
722
- }
723
- ];
724
- }
725
- const buildHaving = (queryDSL, context)=>{
726
- const { vbiDSL } = context;
727
- const havingFilters = vbiDSL.havingFilters || [];
728
- if (0 === havingFilters.length) return queryDSL;
729
- const result = {
730
- ...queryDSL
731
- };
732
- result.having = {
733
- op: 'and',
734
- conditions: havingFilters.flatMap(buildHaving_mapClauseToCondition)
735
- };
736
- return result;
737
- };
738
- function isHavingGroup(clause) {
739
- return 'op' in clause && 'conditions' in clause;
740
- }
741
- function buildHaving_mapClauseToCondition(clause) {
742
- if (isHavingGroup(clause)) return [
743
- buildHaving_mapGroupToCondition(clause)
744
- ];
745
- return buildHaving_mapFilterToCondition(clause);
746
- }
747
- function buildHaving_mapGroupToCondition(group) {
748
- return {
749
- op: group.op,
750
- conditions: group.conditions.flatMap(buildHaving_mapClauseToCondition)
751
- };
752
- }
753
- function buildHaving_mapFilterToCondition(filter) {
754
- const mappedOp = filter.op ?? '=';
755
- return [
756
- {
757
- field: filter.field,
758
- op: mappedOp,
759
- value: filter.value
760
- }
761
- ];
762
- }
763
- const buildLimit = (queryDSL, context)=>{
764
- const result = {
765
- ...queryDSL
766
- };
767
- const limit = context.vbiDSL.limit ?? 1000;
768
- result.limit = limit;
769
- return result;
770
- };
771
- const buildVQuery = (vbiDSL, builder)=>{
772
- const wrapper = (processor)=>(queryDSL)=>processor(queryDSL, {
773
- vbiDSL,
774
- builder
775
- });
776
- return (0, external_remeda_namespaceObject.pipe)({}, wrapper(buildSelect), wrapper(buildGroupBy), wrapper(buildWhere), wrapper(buildHaving), wrapper(buildLimit));
777
- };
778
- const connectorMap = new Map();
779
- const registerConnector = (id, connector)=>{
780
- connectorMap.set(id, connector);
781
- };
782
- const getConnector = async (id)=>{
783
- const connector = connectorMap.get(id);
784
- if (!connector) throw new Error(`connector ${id} not registered`);
785
- if ('function' == typeof connector) return connector();
786
- return connector;
787
- };
788
1099
  class VBIBuilder {
789
1100
  doc;
790
1101
  dsl;
791
- undoManager;
792
1102
  chartType;
793
1103
  measures;
794
1104
  dimensions;
795
- havingFilters;
796
- whereFilters;
1105
+ havingFilter;
1106
+ whereFilter;
1107
+ theme;
1108
+ locale;
1109
+ limit;
1110
+ undoManager;
797
1111
  constructor(doc){
798
1112
  this.doc = doc;
799
1113
  this.dsl = doc.getMap('dsl');
800
- this.undoManager = new UndoManager(this.dsl);
801
- this.chartType = new ChartTypeBuilder(doc, this.dsl);
802
- this.measures = new MeasuresBuilder(doc, this.dsl);
803
- this.dimensions = new DimensionsBuilder(doc, this.dsl);
804
- this.havingFilters = new HavingFiltersBuilder(doc, this.dsl);
805
- this.whereFilters = new WhereFiltersBuilder(doc, this.dsl);
806
- }
807
- applyUpdate(update) {
808
- external_yjs_namespaceObject.applyUpdate(this.doc, update);
809
- }
810
- encodeStateAsUpdate(targetStateVector) {
811
- return external_yjs_namespaceObject.encodeStateAsUpdate(this.doc, targetStateVector);
812
- }
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;
1124
+ }
1125
+ applyUpdate = (update, transactionOrigin)=>applyUpdateToDoc(this.doc, update, transactionOrigin);
1126
+ encodeStateAsUpdate = (targetStateVector)=>encodeDocStateAsUpdate(this.doc, targetStateVector);
813
1127
  buildVSeed = async ()=>{
814
1128
  const vbiDSL = this.build();
815
- const connectorId = vbiDSL.connectorId;
816
- const connector = await getConnector(vbiDSL.connectorId);
817
1129
  const queryDSL = this.buildVQuery();
818
- const schema = await connector.discoverSchema();
819
- const queryResult = await connector.query({
820
- queryDSL,
821
- schema,
822
- connectorId
1130
+ return buildVSeedDSL({
1131
+ vbiDSL,
1132
+ queryDSL
823
1133
  });
824
- return {
825
- chartType: vbiDSL.chartType,
826
- dataset: queryResult.dataset,
827
- theme: vbiDSL.theme,
828
- locale: vbiDSL.locale
829
- };
830
1134
  };
831
- buildVQuery = ()=>{
832
- const vbiDSL = this.build();
833
- return buildVQuery(vbiDSL, this);
834
- };
835
- build = ()=>this.dsl.toJSON();
836
- getSchema = async ()=>{
837
- const connectorId = this.dsl.get('connectorId');
838
- const con = await getConnector(connectorId);
839
- const result = await con.discoverSchema();
840
- return result;
841
- };
842
- setLimit(limit) {
843
- this.dsl.set('limit', limit);
844
- return this;
845
- }
846
- setLocale(locale) {
847
- this.dsl.set('locale', locale);
848
- return this;
1135
+ buildVQuery = ()=>buildVQueryDSL(this.dsl, this);
1136
+ build = ()=>buildVBIDSL(this.dsl);
1137
+ isEmpty = ()=>isEmptyVBIDSL(this.dsl);
1138
+ getSchema = async ()=>getBuilderSchema(this.dsl);
1139
+ }
1140
+ const shouldEnsureIdForObject = (obj, ensureId)=>{
1141
+ if (true === ensureId) return true;
1142
+ if ('field' === ensureId) return 'string' == typeof obj.field;
1143
+ return false;
1144
+ };
1145
+ const toYMap = (obj, ensureId = false)=>{
1146
+ const yMap = new external_yjs_namespaceObject.Map();
1147
+ if (shouldEnsureIdForObject(obj, ensureId) && !obj.id) yMap.set('id', id_id.uuid());
1148
+ for (const [key, value] of Object.entries(obj)){
1149
+ if (('conditions' === key || 'children' === key) && Array.isArray(value)) {
1150
+ 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
+ }
1168
+ yMap.set(key, yArr);
1169
+ continue;
1170
+ }
1171
+ yMap.set(key, value);
849
1172
  }
850
- setTheme(theme) {
851
- this.dsl.set('theme', theme);
852
- return this;
1173
+ return yMap;
1174
+ };
1175
+ const ensureYArray = (arr, ensureId = false)=>{
1176
+ if (!arr) return new external_yjs_namespaceObject.Array();
1177
+ if (arr instanceof external_yjs_namespaceObject.Array) return arr;
1178
+ 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
+ ]);
853
1195
  }
854
- }
1196
+ return yArr;
1197
+ };
1198
+ const getDefaultWhereFilter = ()=>({
1199
+ id: 'root',
1200
+ op: 'and',
1201
+ 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));
1216
+ return whereGroup;
1217
+ };
1218
+ const getDefaultHavingFilter = ()=>({
1219
+ id: 'root',
1220
+ op: 'and',
1221
+ 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));
1236
+ return havingGroup;
1237
+ };
1238
+ const setBaseDSLFields = (dsl, vbi)=>{
1239
+ if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
1240
+ if (vbi.chartType) dsl.set('chartType', vbi.chartType);
1241
+ if (vbi.theme) dsl.set('theme', vbi.theme);
1242
+ if (vbi.limit) dsl.set('limit', vbi.limit);
1243
+ if (vbi.locale) dsl.set('locale', vbi.locale);
1244
+ if (void 0 !== vbi.version) dsl.set('version', vbi.version);
1245
+ };
1246
+ const fromVBIDSLInput = (vbi)=>{
1247
+ const doc = new external_yjs_namespaceObject.Doc();
1248
+ const dsl = doc.getMap('dsl');
1249
+ doc.transact(()=>{
1250
+ setBaseDSLFields(dsl, vbi);
1251
+ dsl.set('whereFilter', ensureWhereGroup(vbi.whereFilter));
1252
+ dsl.set('havingFilter', ensureHavingGroup(vbi.havingFilter));
1253
+ dsl.set('measures', ensureYArray(vbi.measures, 'field'));
1254
+ dsl.set('dimensions', ensureYArray(vbi.dimensions, 'field'));
1255
+ });
1256
+ return new VBIBuilder(doc);
1257
+ };
1258
+ const generateEmptyDSL = (connectorId)=>({
1259
+ connectorId,
1260
+ chartType: 'table',
1261
+ measures: [],
1262
+ dimensions: [],
1263
+ whereFilter: {
1264
+ id: 'root',
1265
+ op: 'and',
1266
+ conditions: []
1267
+ },
1268
+ havingFilter: {
1269
+ id: 'root',
1270
+ op: 'and',
1271
+ conditions: []
1272
+ },
1273
+ theme: 'light',
1274
+ locale: 'zh-CN',
1275
+ version: 0
1276
+ });
855
1277
  const createVBI = ()=>({
856
1278
  connectorMap: connectorMap,
857
1279
  registerConnector: registerConnector,
858
1280
  getConnector: getConnector,
859
- generateEmptyDSL: (connectorId)=>({
860
- connectorId: connectorId,
861
- chartType: 'table',
862
- measures: [],
863
- dimensions: [],
864
- whereFilters: [],
865
- havingFilters: [],
866
- theme: 'light',
867
- locale: 'zh-CN',
868
- version: 0
869
- }),
870
- from: (vbi)=>{
871
- const doc = new external_yjs_namespaceObject.Doc();
872
- const dsl = doc.getMap('dsl');
873
- doc.transact(()=>{
874
- if (vbi.connectorId) dsl.set('connectorId', vbi.connectorId);
875
- if (vbi.chartType) dsl.set('chartType', vbi.chartType);
876
- if (vbi.theme) dsl.set('theme', vbi.theme);
877
- if (vbi.limit) dsl.set('limit', vbi.limit);
878
- if (vbi.locale) dsl.set('locale', vbi.locale);
879
- if (vbi.version) dsl.set('version', vbi.version);
880
- const toYMap = (obj, ensureId = false)=>{
881
- const yMap = new external_yjs_namespaceObject.Map();
882
- if (ensureId && !obj.id) yMap.set('id', id_id.uuid());
883
- for (const [key, value] of Object.entries(obj))if ('conditions' === key && Array.isArray(value)) {
884
- const yArr = new external_yjs_namespaceObject.Array();
885
- value.forEach((child)=>{
886
- if (child instanceof external_yjs_namespaceObject.Map) yArr.push([
887
- child
888
- ]);
889
- else if ('object' == typeof child && null !== child) yArr.push([
890
- toYMap(child, true)
891
- ]);
892
- else yArr.push([
893
- child
894
- ]);
895
- });
896
- yMap.set(key, yArr);
897
- } else yMap.set(key, value);
898
- return yMap;
899
- };
900
- const ensureYArray = (arr, ensureId = false)=>{
901
- if (!arr) return new external_yjs_namespaceObject.Array();
902
- if (arr instanceof external_yjs_namespaceObject.Array) return arr;
903
- const yArr = new external_yjs_namespaceObject.Array();
904
- arr.forEach((item)=>{
905
- if (item instanceof external_yjs_namespaceObject.Map) yArr.push([
906
- item
907
- ]);
908
- else if ('object' == typeof item && null !== item) yArr.push([
909
- toYMap(item, ensureId)
910
- ]);
911
- else yArr.push([
912
- item
913
- ]);
914
- });
915
- return yArr;
916
- };
917
- dsl.set('whereFilters', ensureYArray(vbi.whereFilters, true));
918
- dsl.set('havingFilters', ensureYArray(vbi.havingFilters, true));
919
- dsl.set('measures', ensureYArray(vbi.measures));
920
- dsl.set('dimensions', ensureYArray(vbi.dimensions));
921
- });
922
- return new VBIBuilder(doc);
923
- }
1281
+ generateEmptyDSL: generateEmptyDSL,
1282
+ from: fromVBIDSLInput,
1283
+ create: fromVBIDSLInput
924
1284
  });
925
1285
  const VBI = createVBI();
926
- const external_zod_namespaceObject = require("zod");
927
- const zVBIFilter = external_zod_namespaceObject.z.object({
928
- id: external_zod_namespaceObject.z.string(),
929
- field: external_zod_namespaceObject.z.string(),
930
- op: external_zod_namespaceObject.z.string().optional(),
931
- value: external_zod_namespaceObject.z.any().optional()
932
- });
933
- const zVBIWhereGroup = external_zod_namespaceObject.z.lazy(()=>external_zod_namespaceObject.z.object({
934
- id: external_zod_namespaceObject.z.string(),
935
- op: external_zod_namespaceObject.z["enum"]([
936
- 'and',
937
- 'or'
938
- ]),
939
- conditions: external_zod_namespaceObject.z.array(zVBIWhereClause)
940
- }));
941
- const zVBIWhereClause = external_zod_namespaceObject.z.lazy(()=>external_zod_namespaceObject.z.union([
942
- zVBIFilter,
943
- zVBIWhereGroup
944
- ]));
945
- function isVBIFilter(clause) {
946
- return 'field' in clause;
947
- }
948
- function isVBIWhereGroup(clause) {
949
- return 'conditions' in clause;
950
- }
951
- const zVBIHavingFilter = external_zod_namespaceObject.z.object({
952
- id: external_zod_namespaceObject.z.string(),
953
- field: external_zod_namespaceObject.z.string(),
954
- op: external_zod_namespaceObject.z.string().optional(),
955
- value: external_zod_namespaceObject.z.any().optional()
956
- });
957
- const zVBIHavingGroup = external_zod_namespaceObject.z.lazy(()=>external_zod_namespaceObject.z.object({
958
- id: external_zod_namespaceObject.z.string(),
959
- op: external_zod_namespaceObject.z["enum"]([
960
- 'and',
961
- 'or'
962
- ]),
963
- conditions: external_zod_namespaceObject.z.array(zVBIHavingClause)
964
- }));
965
- const zVBIHavingClause = external_zod_namespaceObject.z.lazy(()=>external_zod_namespaceObject.z.union([
966
- zVBIHavingFilter,
967
- zVBIHavingGroup
968
- ]));
969
- function isVBIHavingFilter(clause) {
970
- return 'field' in clause;
971
- }
972
- function isVBIHavingGroup(clause) {
973
- return 'conditions' in clause;
974
- }
975
1286
  exports.ChartTypeBuilder = __webpack_exports__.ChartTypeBuilder;
976
1287
  exports.DimensionsBuilder = __webpack_exports__.DimensionsBuilder;
1288
+ exports.HavingFilterBuilder = __webpack_exports__.HavingFilterBuilder;
1289
+ exports.LimitBuilder = __webpack_exports__.LimitBuilder;
1290
+ exports.LocaleBuilder = __webpack_exports__.LocaleBuilder;
977
1291
  exports.MeasuresBuilder = __webpack_exports__.MeasuresBuilder;
1292
+ exports.ThemeBuilder = __webpack_exports__.ThemeBuilder;
1293
+ exports.UndoManager = __webpack_exports__.UndoManager;
978
1294
  exports.VBI = __webpack_exports__.VBI;
979
1295
  exports.VBIBuilder = __webpack_exports__.VBIBuilder;
1296
+ exports.WhereFilterBuilder = __webpack_exports__.WhereFilterBuilder;
980
1297
  exports.buildVQuery = __webpack_exports__.buildVQuery;
981
1298
  exports.findTreeNodesBy = __webpack_exports__.findTreeNodesBy;
982
1299
  exports.id = __webpack_exports__.id;
@@ -988,9 +1305,15 @@ exports.preorderTraverse = __webpack_exports__.preorderTraverse;
988
1305
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
989
1306
  "ChartTypeBuilder",
990
1307
  "DimensionsBuilder",
1308
+ "HavingFilterBuilder",
1309
+ "LimitBuilder",
1310
+ "LocaleBuilder",
991
1311
  "MeasuresBuilder",
1312
+ "ThemeBuilder",
1313
+ "UndoManager",
992
1314
  "VBI",
993
1315
  "VBIBuilder",
1316
+ "WhereFilterBuilder",
994
1317
  "buildVQuery",
995
1318
  "findTreeNodesBy",
996
1319
  "id",