@visactor/vbi 0.4.15 → 0.4.16

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 (44) 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 +1 -1
  3. package/dist/builder/{sub-builders → features}/dimensions/dim-node-builder.d.ts +1 -1
  4. package/dist/builder/{sub-builders/havingFilters → features/havingFilter}/having-builder.d.ts +13 -13
  5. package/dist/builder/{sub-builders/havingFilters → features/havingFilter}/having-group-builder.d.ts +4 -3
  6. package/dist/builder/{sub-builders/havingFilters → features/havingFilter}/having-node-builder.d.ts +2 -2
  7. package/dist/builder/features/havingFilter/having-utils.d.ts +9 -0
  8. package/dist/builder/features/havingFilter/index.d.ts +3 -0
  9. package/dist/builder/features/index.d.ts +9 -0
  10. package/dist/builder/features/limit/index.d.ts +1 -0
  11. package/dist/builder/features/limit/limit-builder.d.ts +31 -0
  12. package/dist/builder/features/locale/index.d.ts +1 -0
  13. package/dist/builder/features/locale/locale-builder.d.ts +31 -0
  14. package/dist/builder/{sub-builders → features}/measures/mea-builder.d.ts +1 -1
  15. package/dist/builder/{sub-builders → features}/measures/mea-node-builder.d.ts +1 -1
  16. package/dist/builder/features/theme/index.d.ts +1 -0
  17. package/dist/builder/features/theme/theme-builder.d.ts +31 -0
  18. package/dist/builder/features/undo-manager/index.d.ts +1 -0
  19. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/index.d.ts +1 -1
  20. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/where-builder.d.ts +11 -11
  21. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/where-group-builder.d.ts +2 -1
  22. package/dist/builder/{sub-builders/whereFilters → features/whereFilter}/where-node-builder.d.ts +6 -1
  23. package/dist/builder/features/whereFilter/where-utils.d.ts +9 -0
  24. package/dist/builder/index.d.ts +1 -2
  25. package/dist/builder/vbi-builder.d.ts +6 -11
  26. package/dist/builder/vbi.d.ts +2 -2
  27. package/dist/index.cjs +521 -334
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +498 -329
  30. package/dist/types/builder/VBIInterface.d.ts +6 -5
  31. package/dist/types/dsl/{havingFilters → havingFilter}/having.d.ts +10 -6
  32. package/dist/types/dsl/index.d.ts +4 -5
  33. package/dist/types/dsl/measures/measures.d.ts +16 -2
  34. package/dist/types/dsl/vbi/vbi.d.ts +40 -4
  35. package/dist/types/dsl/{whereFilters → whereFilter}/filters.d.ts +10 -6
  36. package/dist/utils/filter-guards.d.ts +5 -0
  37. package/dist/utils/index.d.ts +1 -0
  38. package/package.json +5 -5
  39. package/dist/builder/sub-builders/havingFilters/index.d.ts +0 -3
  40. package/dist/builder/sub-builders/index.d.ts +0 -5
  41. /package/dist/builder/{sub-builders → features}/chart-type/index.d.ts +0 -0
  42. /package/dist/builder/{sub-builders → features}/dimensions/index.d.ts +0 -0
  43. /package/dist/builder/{sub-builders → features}/measures/index.d.ts +0 -0
  44. /package/dist/builder/{undo-manager.d.ts → features/undo-manager/undo-manager.d.ts} +0 -0
package/dist/index.js CHANGED
@@ -2,8 +2,7 @@ import { Array as external_yjs_Array, Doc, Map as external_yjs_Map, UndoManager,
2
2
  import { ChartTypeEnum, findTreeNodesBy, preorderTraverse } from "@visactor/vseed";
3
3
  import { v4 } from "uuid";
4
4
  import { pipe } from "remeda";
5
- import { z } from "zod";
6
- class DimensionNodeBuilder {
5
+ class MeasureNodeBuilder {
7
6
  yMap;
8
7
  constructor(yMap){
9
8
  this.yMap = yMap;
@@ -15,71 +14,83 @@ class DimensionNodeBuilder {
15
14
  this.yMap.set('alias', alias);
16
15
  return this;
17
16
  }
18
- toJson() {
17
+ setEncoding(encoding) {
18
+ this.yMap.set('encoding', encoding);
19
+ return this;
20
+ }
21
+ setAggregate(aggregate) {
22
+ this.yMap.set('aggregate', aggregate);
23
+ return this;
24
+ }
25
+ toJSON() {
19
26
  return this.yMap.toJSON();
20
27
  }
21
28
  }
22
- class DimensionsBuilder {
29
+ class MeasuresBuilder {
23
30
  dsl;
24
31
  constructor(_doc, dsl){
25
32
  this.dsl = dsl;
26
33
  }
27
34
  add(field, callback) {
28
- const dimension = {
35
+ const measure = {
29
36
  alias: field,
30
- field
37
+ field,
38
+ encoding: 'yAxis',
39
+ aggregate: {
40
+ func: 'sum'
41
+ }
31
42
  };
32
43
  const yMap = new external_yjs_Map();
33
- for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
34
- this.dsl.get('dimensions').push([
44
+ for (const [key, value] of Object.entries(measure))yMap.set(key, value);
45
+ this.dsl.get('measures').push([
35
46
  yMap
36
47
  ]);
37
- const node = new DimensionNodeBuilder(yMap);
48
+ const node = new MeasureNodeBuilder(yMap);
38
49
  callback(node);
39
50
  return this;
40
51
  }
41
52
  remove(field) {
42
- const dimensions = this.dsl.get('dimensions');
43
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
44
- if (-1 !== index) this.dsl.get('dimensions').delete(index, 1);
53
+ const measures = this.dsl.get('measures');
54
+ const index = measures.toArray().findIndex((item)=>item.get('field') === field);
55
+ if (-1 !== index) this.dsl.get('measures').delete(index, 1);
45
56
  return this;
46
57
  }
47
58
  update(field, callback) {
48
- const dimensions = this.dsl.get('dimensions');
49
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
50
- if (-1 === index) throw new Error(`Dimension with field "${field}" not found`);
51
- const dimensionYMap = dimensions.get(index);
52
- const node = new DimensionNodeBuilder(dimensionYMap);
59
+ const measures = this.dsl.get('measures');
60
+ const index = measures.toArray().findIndex((item)=>item.get('field') === field);
61
+ if (-1 === index) throw new Error(`Measure with field "${field}" not found`);
62
+ const measureYMap = measures.get(index);
63
+ const node = new MeasureNodeBuilder(measureYMap);
53
64
  callback(node);
54
65
  return this;
55
66
  }
56
67
  find(field) {
57
- const dimensions = this.dsl.get('dimensions');
58
- const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
68
+ const measures = this.dsl.get('measures');
69
+ const index = measures.toArray().findIndex((item)=>item.get('field') === field);
59
70
  if (-1 === index) return;
60
- return new DimensionNodeBuilder(dimensions.get(index));
71
+ return new MeasureNodeBuilder(measures.get(index));
61
72
  }
62
73
  findAll() {
63
- const dimensions = this.dsl.get('dimensions');
64
- return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
74
+ const measures = this.dsl.get('measures');
75
+ return measures.toArray().map((yMap)=>new MeasureNodeBuilder(yMap));
65
76
  }
66
- toJson() {
67
- return this.dsl.get('dimensions').toJSON();
77
+ toJSON() {
78
+ return this.dsl.get('measures').toJSON();
68
79
  }
69
80
  observe(callback) {
70
- this.dsl.get('dimensions').observe(callback);
81
+ this.dsl.get('measures').observe(callback);
71
82
  return ()=>{
72
- this.dsl.get('dimensions').unobserve(callback);
83
+ this.dsl.get('measures').unobserve(callback);
73
84
  };
74
85
  }
75
- static isDimensionNode(node) {
76
- return 'alias' in node && !('children' in node);
86
+ static isMeasureNode(node) {
87
+ return 'encoding' in node || 'aggregate' in node;
77
88
  }
78
- static isDimensionGroup(node) {
89
+ static isMeasureGroup(node) {
79
90
  return 'children' in node;
80
91
  }
81
92
  }
82
- class MeasureNodeBuilder {
93
+ class DimensionNodeBuilder {
83
94
  yMap;
84
95
  constructor(yMap){
85
96
  this.yMap = yMap;
@@ -91,86 +102,161 @@ class MeasureNodeBuilder {
91
102
  this.yMap.set('alias', alias);
92
103
  return this;
93
104
  }
94
- setEncoding(encoding) {
95
- this.yMap.set('encoding', encoding);
96
- return this;
97
- }
98
- setAggregate(aggregate) {
99
- this.yMap.set('aggregate', aggregate);
100
- return this;
101
- }
102
- toJson() {
105
+ toJSON() {
103
106
  return this.yMap.toJSON();
104
107
  }
105
108
  }
106
- class MeasuresBuilder {
109
+ class DimensionsBuilder {
107
110
  dsl;
108
111
  constructor(_doc, dsl){
109
112
  this.dsl = dsl;
110
113
  }
111
114
  add(field, callback) {
112
- const measure = {
115
+ const dimension = {
113
116
  alias: field,
114
- field,
115
- encoding: 'yAxis',
116
- aggregate: {
117
- func: 'sum'
118
- }
117
+ field
119
118
  };
120
119
  const yMap = new external_yjs_Map();
121
- for (const [key, value] of Object.entries(measure))yMap.set(key, value);
122
- this.dsl.get('measures').push([
120
+ for (const [key, value] of Object.entries(dimension))yMap.set(key, value);
121
+ this.dsl.get('dimensions').push([
123
122
  yMap
124
123
  ]);
125
- const node = new MeasureNodeBuilder(yMap);
124
+ const node = new DimensionNodeBuilder(yMap);
126
125
  callback(node);
127
126
  return this;
128
127
  }
129
128
  remove(field) {
130
- const measures = this.dsl.get('measures');
131
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
132
- if (-1 !== index) this.dsl.get('measures').delete(index, 1);
129
+ const dimensions = this.dsl.get('dimensions');
130
+ const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
131
+ if (-1 !== index) this.dsl.get('dimensions').delete(index, 1);
133
132
  return this;
134
133
  }
135
134
  update(field, callback) {
136
- const measures = this.dsl.get('measures');
137
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
138
- if (-1 === index) throw new Error(`Measure with field "${field}" not found`);
139
- const measureYMap = measures.get(index);
140
- const node = new MeasureNodeBuilder(measureYMap);
135
+ const dimensions = this.dsl.get('dimensions');
136
+ const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
137
+ if (-1 === index) throw new Error(`Dimension with field "${field}" not found`);
138
+ const dimensionYMap = dimensions.get(index);
139
+ const node = new DimensionNodeBuilder(dimensionYMap);
141
140
  callback(node);
142
141
  return this;
143
142
  }
144
143
  find(field) {
145
- const measures = this.dsl.get('measures');
146
- const index = measures.toArray().findIndex((item)=>item.get('field') === field);
144
+ const dimensions = this.dsl.get('dimensions');
145
+ const index = dimensions.toArray().findIndex((item)=>item.get('field') === field);
147
146
  if (-1 === index) return;
148
- return new MeasureNodeBuilder(measures.get(index));
147
+ return new DimensionNodeBuilder(dimensions.get(index));
149
148
  }
150
149
  findAll() {
151
- const measures = this.dsl.get('measures');
152
- return measures.toArray().map((yMap)=>new MeasureNodeBuilder(yMap));
150
+ const dimensions = this.dsl.get('dimensions');
151
+ return dimensions.toArray().map((yMap)=>new DimensionNodeBuilder(yMap));
153
152
  }
154
- toJson() {
155
- return this.dsl.get('measures').toJSON();
153
+ toJSON() {
154
+ return this.dsl.get('dimensions').toJSON();
156
155
  }
157
156
  observe(callback) {
158
- this.dsl.get('measures').observe(callback);
157
+ this.dsl.get('dimensions').observe(callback);
159
158
  return ()=>{
160
- this.dsl.get('measures').unobserve(callback);
159
+ this.dsl.get('dimensions').unobserve(callback);
161
160
  };
162
161
  }
163
- static isMeasureNode(node) {
164
- return 'encoding' in node || 'aggregate' in node;
162
+ static isDimensionNode(node) {
163
+ return 'alias' in node && !('children' in node);
165
164
  }
166
- static isMeasureGroup(node) {
165
+ static isDimensionGroup(node) {
167
166
  return 'children' in node;
168
167
  }
169
168
  }
169
+ class ChartTypeBuilder {
170
+ dsl;
171
+ constructor(_doc, dsl){
172
+ this.dsl = dsl;
173
+ }
174
+ observe(callback) {
175
+ const wrapper = (e, trans)=>{
176
+ if (e.keysChanged.has('chartType')) callback(e, trans);
177
+ };
178
+ this.dsl.observe(wrapper);
179
+ return ()=>{
180
+ this.dsl.unobserve(wrapper);
181
+ };
182
+ }
183
+ changeChartType(chartType) {
184
+ this.dsl.set('chartType', chartType);
185
+ }
186
+ getChartType() {
187
+ return this.dsl.get('chartType') || 'table';
188
+ }
189
+ toJSON() {
190
+ return this.dsl.get('chartType') || 'table';
191
+ }
192
+ getAvailableChartTypes() {
193
+ return [
194
+ ChartTypeEnum.Table,
195
+ ChartTypeEnum.PivotTable,
196
+ ChartTypeEnum.Line,
197
+ ChartTypeEnum.Column,
198
+ ChartTypeEnum.ColumnPercent,
199
+ ChartTypeEnum.ColumnParallel,
200
+ ChartTypeEnum.BarPercent,
201
+ ChartTypeEnum.BarParallel,
202
+ ChartTypeEnum.Area,
203
+ ChartTypeEnum.AreaPercent,
204
+ ChartTypeEnum.DualAxis,
205
+ ChartTypeEnum.Scatter,
206
+ ChartTypeEnum.Rose,
207
+ ChartTypeEnum.RoseParallel,
208
+ ChartTypeEnum.Pie,
209
+ ChartTypeEnum.Donut,
210
+ ChartTypeEnum.Radar,
211
+ ChartTypeEnum.Funnel,
212
+ ChartTypeEnum.Heatmap,
213
+ ChartTypeEnum.Boxplot,
214
+ ChartTypeEnum.Histogram
215
+ ];
216
+ }
217
+ }
170
218
  const id_id = {
171
219
  uuid: ()=>v4()
172
220
  };
173
- class HavingFiltersNodeBuilder {
221
+ function isVBIFilter(clause) {
222
+ return 'field' in clause;
223
+ }
224
+ function isVBIWhereGroup(clause) {
225
+ return 'conditions' in clause;
226
+ }
227
+ function isVBIHavingFilter(clause) {
228
+ return 'field' in clause;
229
+ }
230
+ function isVBIHavingGroup(clause) {
231
+ return 'conditions' in clause;
232
+ }
233
+ function createWhereGroup(op = 'and', groupId = 'root') {
234
+ const yMap = new external_yjs_Map();
235
+ yMap.set('id', groupId);
236
+ yMap.set('op', op);
237
+ yMap.set('conditions', new external_yjs_Array());
238
+ return yMap;
239
+ }
240
+ function isWhereGroup(yMap) {
241
+ return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
242
+ }
243
+ function findEntry(collection, entryId) {
244
+ const items = collection.toArray();
245
+ for(let index = 0; index < items.length; index++){
246
+ const item = items[index];
247
+ if (item.get('id') === entryId) return {
248
+ collection,
249
+ index,
250
+ item
251
+ };
252
+ if (isWhereGroup(item)) {
253
+ const nestedCollection = item.get('conditions');
254
+ const nestedMatch = findEntry(nestedCollection, entryId);
255
+ if (nestedMatch) return nestedMatch;
256
+ }
257
+ }
258
+ }
259
+ class WhereFilterNodeBuilder {
174
260
  yMap;
175
261
  constructor(yMap){
176
262
  this.yMap = yMap;
@@ -181,26 +267,33 @@ class HavingFiltersNodeBuilder {
181
267
  getField() {
182
268
  return this.yMap.get('field');
183
269
  }
270
+ setField(field) {
271
+ this.yMap.set('field', field);
272
+ return this;
273
+ }
184
274
  getOperator() {
185
275
  return this.yMap.get('op');
186
276
  }
187
- setValue(value) {
188
- this.yMap.set('value', value);
189
- return this;
190
- }
191
277
  setOperator(operator) {
192
278
  this.yMap.set('op', operator);
193
279
  return this;
194
280
  }
195
- toJson() {
281
+ setValue(value) {
282
+ this.yMap.set('value', value);
283
+ return this;
284
+ }
285
+ toJSON() {
196
286
  return this.yMap.toJSON();
197
287
  }
198
288
  }
199
- class HavingGroupBuilder {
289
+ class WhereGroupBuilder {
200
290
  yMap;
201
291
  constructor(yMap){
202
292
  this.yMap = yMap;
203
293
  }
294
+ getConditions() {
295
+ return this.yMap.get('conditions');
296
+ }
204
297
  getId() {
205
298
  return this.yMap.get('id');
206
299
  }
@@ -215,29 +308,24 @@ class HavingGroupBuilder {
215
308
  const yMap = new external_yjs_Map();
216
309
  yMap.set('id', id_id.uuid());
217
310
  yMap.set('field', field);
218
- const conditions = this.yMap.get('conditions');
219
- conditions.push([
311
+ this.getConditions().push([
220
312
  yMap
221
313
  ]);
222
- const node = new HavingFiltersNodeBuilder(yMap);
314
+ const node = new WhereFilterNodeBuilder(yMap);
223
315
  callback(node);
224
316
  return this;
225
317
  }
226
318
  addGroup(op, callback) {
227
- const yMap = new external_yjs_Map();
228
- yMap.set('id', id_id.uuid());
229
- yMap.set('op', op);
230
- yMap.set('conditions', new external_yjs_Array());
231
- const conditions = this.yMap.get('conditions');
232
- conditions.push([
319
+ const yMap = createWhereGroup(op, id_id.uuid());
320
+ this.getConditions().push([
233
321
  yMap
234
322
  ]);
235
- const group = new HavingGroupBuilder(yMap);
323
+ const group = new WhereGroupBuilder(yMap);
236
324
  callback(group);
237
325
  return this;
238
326
  }
239
327
  remove(idOrIndex) {
240
- const conditions = this.yMap.get('conditions');
328
+ const conditions = this.getConditions();
241
329
  if ('number' == typeof idOrIndex) {
242
330
  if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
243
331
  } else {
@@ -247,154 +335,138 @@ class HavingGroupBuilder {
247
335
  return this;
248
336
  }
249
337
  clear() {
250
- const conditions = this.yMap.get('conditions');
338
+ const conditions = this.getConditions();
251
339
  conditions.delete(0, conditions.length);
252
340
  return this;
253
341
  }
254
- toJson() {
342
+ toJSON() {
255
343
  return this.yMap.toJSON();
256
344
  }
257
345
  }
258
- class HavingFiltersBuilder {
259
- dsl;
260
- doc;
346
+ class WhereFilterBuilder {
347
+ whereFilter;
261
348
  constructor(doc, dsl){
262
- this.doc = doc;
263
- this.dsl = dsl;
264
- if (!this.dsl.get('havingFilters')) this.doc.transact(()=>{
265
- this.dsl.set('havingFilters', new external_yjs_Array());
349
+ doc.transact(()=>{
350
+ const existingWhereFilter = dsl.get('whereFilter');
351
+ if (existingWhereFilter instanceof external_yjs_Map) this.whereFilter = existingWhereFilter;
352
+ else {
353
+ this.whereFilter = createWhereGroup();
354
+ dsl.set('whereFilter', this.whereFilter);
355
+ }
356
+ if (!(this.whereFilter.get('conditions') instanceof external_yjs_Array)) this.whereFilter.set('conditions', new external_yjs_Array());
357
+ if (!this.whereFilter.get('id')) this.whereFilter.set('id', 'root');
358
+ if (!this.whereFilter.get('op')) this.whereFilter.set('op', 'and');
266
359
  });
267
360
  }
361
+ getConditions() {
362
+ return this.whereFilter.get('conditions');
363
+ }
268
364
  add(field, callback) {
269
365
  const yMap = new external_yjs_Map();
270
366
  yMap.set('id', id_id.uuid());
271
367
  yMap.set('field', field);
272
- this.dsl.get('havingFilters').push([
368
+ this.getConditions().push([
273
369
  yMap
274
370
  ]);
275
- const node = new HavingFiltersNodeBuilder(yMap);
371
+ const node = new WhereFilterNodeBuilder(yMap);
276
372
  callback(node);
277
373
  return this;
278
374
  }
279
375
  addGroup(op, callback) {
280
- const yMap = new external_yjs_Map();
281
- yMap.set('id', id_id.uuid());
282
- yMap.set('op', op);
283
- yMap.set('conditions', new external_yjs_Array());
284
- this.dsl.get('havingFilters').push([
376
+ const yMap = createWhereGroup(op, id_id.uuid());
377
+ this.getConditions().push([
285
378
  yMap
286
379
  ]);
287
- const group = new HavingGroupBuilder(yMap);
380
+ const group = new WhereGroupBuilder(yMap);
288
381
  callback(group);
289
382
  return this;
290
383
  }
291
384
  update(id, callback) {
292
- const havingFilters = this.dsl.get('havingFilters');
293
- const index = havingFilters.toArray().findIndex((item)=>item.get('id') === id);
294
- if (-1 === index) throw new Error(`Having filter with id ${id} not found`);
295
- const filterYMap = havingFilters.get(index);
296
- const node = new HavingFiltersNodeBuilder(filterYMap);
385
+ const conditions = this.getConditions();
386
+ const match = findEntry(conditions, id);
387
+ if (!match) throw new Error(`Where filter with id ${id} not found`);
388
+ if (!WhereFilterBuilder.isNode(match.item)) throw new Error(`Item with id ${id} is not a filter`);
389
+ const filterYMap = match.item;
390
+ const node = new WhereFilterNodeBuilder(filterYMap);
297
391
  callback(node);
298
392
  return this;
299
393
  }
300
394
  updateGroup(id, callback) {
301
- const havingFilters = this.dsl.get('havingFilters');
302
- const index = havingFilters.toArray().findIndex((item)=>item.get('id') === id);
303
- if (-1 === index) throw new Error(`Having group with id ${id} not found`);
304
- const yMap = havingFilters.get(index);
305
- if (!HavingFiltersBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
306
- const group = new HavingGroupBuilder(yMap);
395
+ const conditions = this.getConditions();
396
+ const match = findEntry(conditions, id);
397
+ if (!match) throw new Error(`Where group with id ${id} not found`);
398
+ const yMap = match.item;
399
+ if (!WhereFilterBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
400
+ const group = new WhereGroupBuilder(yMap);
307
401
  callback(group);
308
402
  return this;
309
403
  }
310
404
  remove(idOrIndex) {
311
- const havingFilters = this.dsl.get('havingFilters');
405
+ const conditions = this.getConditions();
312
406
  if ('number' == typeof idOrIndex) {
313
- if (idOrIndex >= 0 && idOrIndex < havingFilters.length) havingFilters.delete(idOrIndex, 1);
407
+ if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
314
408
  } else {
315
- const index = havingFilters.toArray().findIndex((item)=>item.get('id') === idOrIndex);
316
- if (-1 !== index) havingFilters.delete(index, 1);
409
+ const match = findEntry(conditions, idOrIndex);
410
+ if (match) match.collection.delete(match.index, 1);
317
411
  }
318
412
  return this;
319
413
  }
320
414
  find(id) {
321
- const havingFilters = this.dsl.get('havingFilters');
322
- const yMap = havingFilters.toArray().find((item)=>item.get('id') === id);
415
+ const conditions = this.getConditions();
416
+ const match = findEntry(conditions, id);
417
+ const yMap = match?.item;
323
418
  if (!yMap) return;
324
- if (HavingFiltersBuilder.isGroup(yMap)) return new HavingGroupBuilder(yMap);
325
- return new HavingFiltersNodeBuilder(yMap);
419
+ if (WhereFilterBuilder.isGroup(yMap)) return new WhereGroupBuilder(yMap);
420
+ return new WhereFilterNodeBuilder(yMap);
326
421
  }
327
422
  clear() {
328
- const havingFilters = this.dsl.get('havingFilters');
329
- havingFilters.delete(0, havingFilters.length);
423
+ const conditions = this.getConditions();
424
+ conditions.delete(0, conditions.length);
330
425
  return this;
331
426
  }
332
- toJson() {
333
- return this.dsl.get('havingFilters').toJSON();
427
+ toJSON() {
428
+ return this.whereFilter.toJSON();
334
429
  }
335
430
  observe(callback) {
336
- this.dsl.get('havingFilters').observe(callback);
431
+ this.whereFilter.observeDeep(callback);
337
432
  return ()=>{
338
- this.dsl.get('havingFilters').unobserve(callback);
433
+ this.whereFilter.unobserveDeep(callback);
339
434
  };
340
435
  }
341
436
  static isGroup(yMap) {
342
- return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
437
+ return isWhereGroup(yMap);
343
438
  }
344
439
  static isNode(yMap) {
345
440
  return void 0 !== yMap.get('field');
346
441
  }
347
442
  }
348
- class ChartTypeBuilder {
349
- dsl;
350
- constructor(_doc, dsl){
351
- this.dsl = dsl;
352
- }
353
- observe(callback) {
354
- const wrapper = (e, trans)=>{
355
- if (e.keysChanged.has('chartType')) callback(e, trans);
356
- };
357
- this.dsl.observe(wrapper);
358
- return ()=>{
359
- this.dsl.unobserve(wrapper);
443
+ function createHavingGroup(op = 'and', groupId = 'root') {
444
+ const yMap = new external_yjs_Map();
445
+ yMap.set('id', groupId);
446
+ yMap.set('op', op);
447
+ yMap.set('conditions', new external_yjs_Array());
448
+ return yMap;
449
+ }
450
+ function isHavingGroup(yMap) {
451
+ return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
452
+ }
453
+ function having_utils_findEntry(collection, entryId) {
454
+ const items = collection.toArray();
455
+ for(let index = 0; index < items.length; index++){
456
+ const item = items[index];
457
+ if (item.get('id') === entryId) return {
458
+ collection,
459
+ index,
460
+ item
360
461
  };
361
- }
362
- changeChartType(chartType) {
363
- this.dsl.set('chartType', chartType);
364
- }
365
- getChartType() {
366
- return this.dsl.get('chartType') || 'table';
367
- }
368
- toJson() {
369
- return this.dsl.get('chartType') || 'table';
370
- }
371
- getAvailableChartTypes() {
372
- return [
373
- ChartTypeEnum.Table,
374
- ChartTypeEnum.PivotTable,
375
- ChartTypeEnum.Line,
376
- ChartTypeEnum.Column,
377
- ChartTypeEnum.ColumnPercent,
378
- ChartTypeEnum.ColumnParallel,
379
- ChartTypeEnum.BarPercent,
380
- ChartTypeEnum.BarParallel,
381
- ChartTypeEnum.Area,
382
- ChartTypeEnum.AreaPercent,
383
- ChartTypeEnum.DualAxis,
384
- ChartTypeEnum.Scatter,
385
- ChartTypeEnum.Rose,
386
- ChartTypeEnum.RoseParallel,
387
- ChartTypeEnum.Pie,
388
- ChartTypeEnum.Donut,
389
- ChartTypeEnum.Radar,
390
- ChartTypeEnum.Funnel,
391
- ChartTypeEnum.Heatmap,
392
- ChartTypeEnum.Boxplot,
393
- ChartTypeEnum.Histogram
394
- ];
462
+ if (isHavingGroup(item)) {
463
+ const nestedCollection = item.get('conditions');
464
+ const nestedMatch = having_utils_findEntry(nestedCollection, entryId);
465
+ if (nestedMatch) return nestedMatch;
466
+ }
395
467
  }
396
468
  }
397
- class WhereFilterNodeBuilder {
469
+ class HavingFilterNodeBuilder {
398
470
  yMap;
399
471
  constructor(yMap){
400
472
  this.yMap = yMap;
@@ -408,23 +480,26 @@ class WhereFilterNodeBuilder {
408
480
  getOperator() {
409
481
  return this.yMap.get('op');
410
482
  }
411
- setOperator(operator) {
412
- this.yMap.set('op', operator);
413
- return this;
414
- }
415
483
  setValue(value) {
416
484
  this.yMap.set('value', value);
417
485
  return this;
418
486
  }
419
- toJson() {
487
+ setOperator(operator) {
488
+ this.yMap.set('op', operator);
489
+ return this;
490
+ }
491
+ toJSON() {
420
492
  return this.yMap.toJSON();
421
493
  }
422
494
  }
423
- class WhereGroupBuilder {
495
+ class HavingGroupBuilder {
424
496
  yMap;
425
497
  constructor(yMap){
426
498
  this.yMap = yMap;
427
499
  }
500
+ getConditions() {
501
+ return this.yMap.get('conditions');
502
+ }
428
503
  getId() {
429
504
  return this.yMap.get('id');
430
505
  }
@@ -439,29 +514,24 @@ class WhereGroupBuilder {
439
514
  const yMap = new external_yjs_Map();
440
515
  yMap.set('id', id_id.uuid());
441
516
  yMap.set('field', field);
442
- const conditions = this.yMap.get('conditions');
443
- conditions.push([
517
+ this.getConditions().push([
444
518
  yMap
445
519
  ]);
446
- const node = new WhereFilterNodeBuilder(yMap);
520
+ const node = new HavingFilterNodeBuilder(yMap);
447
521
  callback(node);
448
522
  return this;
449
523
  }
450
524
  addGroup(op, callback) {
451
- const yMap = new external_yjs_Map();
452
- yMap.set('id', id_id.uuid());
453
- yMap.set('op', op);
454
- yMap.set('conditions', new external_yjs_Array());
455
- const conditions = this.yMap.get('conditions');
456
- conditions.push([
525
+ const yMap = createHavingGroup(op, id_id.uuid());
526
+ this.getConditions().push([
457
527
  yMap
458
528
  ]);
459
- const group = new WhereGroupBuilder(yMap);
529
+ const group = new HavingGroupBuilder(yMap);
460
530
  callback(group);
461
531
  return this;
462
532
  }
463
533
  remove(idOrIndex) {
464
- const conditions = this.yMap.get('conditions');
534
+ const conditions = this.getConditions();
465
535
  if ('number' == typeof idOrIndex) {
466
536
  if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
467
537
  } else {
@@ -471,104 +541,183 @@ class WhereGroupBuilder {
471
541
  return this;
472
542
  }
473
543
  clear() {
474
- const conditions = this.yMap.get('conditions');
544
+ const conditions = this.getConditions();
475
545
  conditions.delete(0, conditions.length);
476
546
  return this;
477
547
  }
478
- toJson() {
548
+ toJSON() {
479
549
  return this.yMap.toJSON();
480
550
  }
481
551
  }
482
- class WhereFiltersBuilder {
483
- dsl;
484
- doc;
552
+ class HavingFilterBuilder {
553
+ havingFilter;
485
554
  constructor(doc, dsl){
486
- this.doc = doc;
487
- this.dsl = dsl;
488
- if (!this.dsl.get('whereFilters')) this.doc.transact(()=>{
489
- this.dsl.set('whereFilters', new external_yjs_Array());
555
+ doc.transact(()=>{
556
+ const existingHavingFilter = dsl.get('havingFilter');
557
+ if (existingHavingFilter instanceof external_yjs_Map) this.havingFilter = existingHavingFilter;
558
+ else {
559
+ this.havingFilter = createHavingGroup();
560
+ dsl.set('havingFilter', this.havingFilter);
561
+ }
562
+ if (!(this.havingFilter.get('conditions') instanceof external_yjs_Array)) this.havingFilter.set('conditions', new external_yjs_Array());
563
+ if (!this.havingFilter.get('id')) this.havingFilter.set('id', 'root');
564
+ if (!this.havingFilter.get('op')) this.havingFilter.set('op', 'and');
490
565
  });
491
566
  }
567
+ getConditions() {
568
+ return this.havingFilter.get('conditions');
569
+ }
492
570
  add(field, callback) {
493
571
  const yMap = new external_yjs_Map();
494
572
  yMap.set('id', id_id.uuid());
495
573
  yMap.set('field', field);
496
- this.dsl.get('whereFilters').push([
574
+ this.getConditions().push([
497
575
  yMap
498
576
  ]);
499
- const node = new WhereFilterNodeBuilder(yMap);
577
+ const node = new HavingFilterNodeBuilder(yMap);
500
578
  callback(node);
501
579
  return this;
502
580
  }
503
581
  addGroup(op, callback) {
504
- const yMap = new external_yjs_Map();
505
- yMap.set('id', id_id.uuid());
506
- yMap.set('op', op);
507
- yMap.set('conditions', new external_yjs_Array());
508
- this.dsl.get('whereFilters').push([
582
+ const yMap = createHavingGroup(op, id_id.uuid());
583
+ this.getConditions().push([
509
584
  yMap
510
585
  ]);
511
- const group = new WhereGroupBuilder(yMap);
586
+ const group = new HavingGroupBuilder(yMap);
512
587
  callback(group);
513
588
  return this;
514
589
  }
515
590
  update(id, callback) {
516
- const whereFilters = this.dsl.get('whereFilters');
517
- const index = whereFilters.toArray().findIndex((item)=>item.get('id') === id);
518
- if (-1 === index) throw new Error(`Where filter with id ${id} not found`);
519
- const filterYMap = whereFilters.get(index);
520
- const node = new WhereFilterNodeBuilder(filterYMap);
591
+ const conditions = this.getConditions();
592
+ const match = having_utils_findEntry(conditions, id);
593
+ if (!match) throw new Error(`Having filter with id ${id} not found`);
594
+ if (!HavingFilterBuilder.isNode(match.item)) throw new Error(`Item with id ${id} is not a filter`);
595
+ const filterYMap = match.item;
596
+ const node = new HavingFilterNodeBuilder(filterYMap);
521
597
  callback(node);
522
598
  return this;
523
599
  }
524
600
  updateGroup(id, callback) {
525
- const whereFilters = this.dsl.get('whereFilters');
526
- const index = whereFilters.toArray().findIndex((item)=>item.get('id') === id);
527
- if (-1 === index) throw new Error(`Where group with id ${id} not found`);
528
- const yMap = whereFilters.get(index);
529
- if (!WhereFiltersBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
530
- const group = new WhereGroupBuilder(yMap);
601
+ const conditions = this.getConditions();
602
+ const match = having_utils_findEntry(conditions, id);
603
+ if (!match) throw new Error(`Having group with id ${id} not found`);
604
+ const yMap = match.item;
605
+ if (!HavingFilterBuilder.isGroup(yMap)) throw new Error(`Item with id ${id} is not a group`);
606
+ const group = new HavingGroupBuilder(yMap);
531
607
  callback(group);
532
608
  return this;
533
609
  }
534
610
  remove(idOrIndex) {
535
- const whereFilters = this.dsl.get('whereFilters');
611
+ const conditions = this.getConditions();
536
612
  if ('number' == typeof idOrIndex) {
537
- if (idOrIndex >= 0 && idOrIndex < whereFilters.length) whereFilters.delete(idOrIndex, 1);
613
+ if (idOrIndex >= 0 && idOrIndex < conditions.length) conditions.delete(idOrIndex, 1);
538
614
  } else {
539
- const index = whereFilters.toArray().findIndex((item)=>item.get('id') === idOrIndex);
540
- if (-1 !== index) whereFilters.delete(index, 1);
615
+ const match = having_utils_findEntry(conditions, idOrIndex);
616
+ if (match) match.collection.delete(match.index, 1);
541
617
  }
542
618
  return this;
543
619
  }
544
620
  find(id) {
545
- const whereFilters = this.dsl.get('whereFilters');
546
- const yMap = whereFilters.toArray().find((item)=>item.get('id') === id);
621
+ const conditions = this.getConditions();
622
+ const match = having_utils_findEntry(conditions, id);
623
+ const yMap = match?.item;
547
624
  if (!yMap) return;
548
- if (WhereFiltersBuilder.isGroup(yMap)) return new WhereGroupBuilder(yMap);
549
- return new WhereFilterNodeBuilder(yMap);
625
+ if (HavingFilterBuilder.isGroup(yMap)) return new HavingGroupBuilder(yMap);
626
+ return new HavingFilterNodeBuilder(yMap);
550
627
  }
551
628
  clear() {
552
- const whereFilters = this.dsl.get('whereFilters');
553
- whereFilters.delete(0, whereFilters.length);
629
+ const conditions = this.getConditions();
630
+ conditions.delete(0, conditions.length);
554
631
  return this;
555
632
  }
556
- toJson() {
557
- return this.dsl.get('whereFilters').toJSON();
633
+ toJSON() {
634
+ return this.havingFilter.toJSON();
558
635
  }
559
636
  observe(callback) {
560
- this.dsl.get('whereFilters').observe(callback);
637
+ this.havingFilter.observeDeep(callback);
561
638
  return ()=>{
562
- this.dsl.get('whereFilters').unobserve(callback);
639
+ this.havingFilter.unobserveDeep(callback);
563
640
  };
564
641
  }
565
642
  static isGroup(yMap) {
566
- return void 0 !== yMap.get('op') && void 0 !== yMap.get('conditions');
643
+ return isHavingGroup(yMap);
567
644
  }
568
645
  static isNode(yMap) {
569
646
  return void 0 !== yMap.get('field');
570
647
  }
571
648
  }
649
+ class ThemeBuilder {
650
+ dsl;
651
+ constructor(_doc, dsl){
652
+ this.dsl = dsl;
653
+ }
654
+ observe(callback) {
655
+ const wrapper = (e, trans)=>{
656
+ if (e.keysChanged.has('theme')) callback(e, trans);
657
+ };
658
+ this.dsl.observe(wrapper);
659
+ return ()=>{
660
+ this.dsl.unobserve(wrapper);
661
+ };
662
+ }
663
+ setTheme(theme) {
664
+ this.dsl.set('theme', theme);
665
+ }
666
+ getTheme() {
667
+ return this.dsl.get('theme') || 'light';
668
+ }
669
+ toJSON() {
670
+ return this.getTheme();
671
+ }
672
+ }
673
+ class LocaleBuilder {
674
+ dsl;
675
+ constructor(_doc, dsl){
676
+ this.dsl = dsl;
677
+ }
678
+ observe(callback) {
679
+ const wrapper = (e, trans)=>{
680
+ if (e.keysChanged.has('locale')) callback(e, trans);
681
+ };
682
+ this.dsl.observe(wrapper);
683
+ return ()=>{
684
+ this.dsl.unobserve(wrapper);
685
+ };
686
+ }
687
+ setLocale(locale) {
688
+ this.dsl.set('locale', locale);
689
+ }
690
+ getLocale() {
691
+ return this.dsl.get('locale') || 'zh-CN';
692
+ }
693
+ toJSON() {
694
+ return this.getLocale();
695
+ }
696
+ }
697
+ class LimitBuilder {
698
+ dsl;
699
+ constructor(_doc, dsl){
700
+ this.dsl = dsl;
701
+ }
702
+ observe(callback) {
703
+ const wrapper = (e, trans)=>{
704
+ if (e.keysChanged.has('limit')) callback(e, trans);
705
+ };
706
+ this.dsl.observe(wrapper);
707
+ return ()=>{
708
+ this.dsl.unobserve(wrapper);
709
+ };
710
+ }
711
+ setLimit(limit) {
712
+ this.dsl.set('limit', limit);
713
+ }
714
+ getLimit() {
715
+ return this.dsl.get('limit');
716
+ }
717
+ toJSON() {
718
+ return this.getLimit();
719
+ }
720
+ }
572
721
  class undo_manager_UndoManager {
573
722
  manager;
574
723
  constructor(scope){
@@ -623,22 +772,19 @@ const buildGroupBy = (queryDSL, context)=>{
623
772
  };
624
773
  const buildWhere = (queryDSL, context)=>{
625
774
  const { vbiDSL } = context;
626
- const whereFilters = vbiDSL.whereFilters || [];
627
- if (0 === whereFilters.length) return queryDSL;
775
+ const whereFilter = vbiDSL.whereFilter;
776
+ if (!whereFilter || 0 === whereFilter.conditions.length) return queryDSL;
628
777
  const result = {
629
778
  ...queryDSL
630
779
  };
631
- result.where = {
632
- op: 'and',
633
- conditions: whereFilters.flatMap(mapClauseToCondition)
634
- };
780
+ result.where = mapGroupToCondition(whereFilter);
635
781
  return result;
636
782
  };
637
- function isWhereGroup(clause) {
783
+ function buildWhere_isWhereGroup(clause) {
638
784
  return 'op' in clause && 'conditions' in clause;
639
785
  }
640
786
  function mapClauseToCondition(clause) {
641
- if (isWhereGroup(clause)) return [
787
+ if (buildWhere_isWhereGroup(clause)) return [
642
788
  mapGroupToCondition(clause)
643
789
  ];
644
790
  return mapFilterToCondition(clause);
@@ -650,23 +796,62 @@ function mapGroupToCondition(group) {
650
796
  };
651
797
  }
652
798
  function mapFilterToCondition(filter) {
653
- if ('between' === filter.op) return handleBetweenFilter(filter);
799
+ if ('between' === filter.op || 'not between' === filter.op) return handleBetweenFilter(filter);
654
800
  return handleSimpleFilter(filter);
655
801
  }
656
802
  function handleBetweenFilter(filter) {
657
- const conditions = [];
658
- const value = filter.value;
659
- if (void 0 !== value.min && null !== value.min && '' !== value.min) conditions.push({
803
+ const value = normalizeBetweenValue(filter.value);
804
+ const lowerCondition = void 0 !== value.min && null !== value.min && '' !== value.min ? {
660
805
  field: filter.field,
661
806
  op: '<' === value.leftOp ? '>' : '>=',
662
807
  value: value.min
663
- });
664
- if (void 0 !== value.max && null !== value.max && '' !== value.max) conditions.push({
808
+ } : void 0;
809
+ const upperCondition = void 0 !== value.max && null !== value.max && '' !== value.max ? {
665
810
  field: filter.field,
666
811
  op: '<' === value.rightOp ? '<' : '<=',
667
812
  value: value.max
668
- });
669
- return conditions;
813
+ } : void 0;
814
+ if ('not between' === filter.op) {
815
+ const outsideConditions = [
816
+ lowerCondition && invertLowerBound(lowerCondition),
817
+ upperCondition && invertUpperBound(upperCondition)
818
+ ].filter(Boolean);
819
+ if (outsideConditions.length <= 1) return outsideConditions;
820
+ return [
821
+ {
822
+ op: 'or',
823
+ conditions: outsideConditions
824
+ }
825
+ ];
826
+ }
827
+ return [
828
+ lowerCondition,
829
+ upperCondition
830
+ ].filter(Boolean);
831
+ }
832
+ function normalizeBetweenValue(value) {
833
+ if (Array.isArray(value)) return {
834
+ min: value[0],
835
+ max: value[1],
836
+ leftOp: '<=',
837
+ rightOp: '<='
838
+ };
839
+ if ('object' == typeof value && null !== value) return value;
840
+ return {};
841
+ }
842
+ function invertLowerBound(condition) {
843
+ return {
844
+ field: condition.field,
845
+ op: '>' === condition.op ? '<=' : '<',
846
+ value: condition.value
847
+ };
848
+ }
849
+ function invertUpperBound(condition) {
850
+ return {
851
+ field: condition.field,
852
+ op: '<' === condition.op ? '>=' : '>',
853
+ value: condition.value
854
+ };
670
855
  }
671
856
  function handleSimpleFilter(filter) {
672
857
  let mappedOp = filter.op ?? '=';
@@ -685,22 +870,22 @@ function handleSimpleFilter(filter) {
685
870
  }
686
871
  const buildHaving = (queryDSL, context)=>{
687
872
  const { vbiDSL } = context;
688
- const havingFilters = vbiDSL.havingFilters || [];
689
- if (0 === havingFilters.length) return queryDSL;
873
+ const havingFilter = vbiDSL.havingFilter;
874
+ if (!havingFilter || 0 === havingFilter.conditions.length) return queryDSL;
690
875
  const result = {
691
876
  ...queryDSL
692
877
  };
693
878
  result.having = {
694
- op: 'and',
695
- conditions: havingFilters.flatMap(buildHaving_mapClauseToCondition)
879
+ op: havingFilter.op,
880
+ conditions: havingFilter.conditions.flatMap(buildHaving_mapClauseToCondition)
696
881
  };
697
882
  return result;
698
883
  };
699
- function isHavingGroup(clause) {
884
+ function buildHaving_isHavingGroup(clause) {
700
885
  return 'op' in clause && 'conditions' in clause;
701
886
  }
702
887
  function buildHaving_mapClauseToCondition(clause) {
703
- if (isHavingGroup(clause)) return [
888
+ if (buildHaving_isHavingGroup(clause)) return [
704
889
  buildHaving_mapGroupToCondition(clause)
705
890
  ];
706
891
  return buildHaving_mapFilterToCondition(clause);
@@ -753,8 +938,11 @@ class VBIBuilder {
753
938
  chartType;
754
939
  measures;
755
940
  dimensions;
756
- havingFilters;
757
- whereFilters;
941
+ havingFilter;
942
+ whereFilter;
943
+ theme;
944
+ locale;
945
+ limit;
758
946
  constructor(doc){
759
947
  this.doc = doc;
760
948
  this.dsl = doc.getMap('dsl');
@@ -762,8 +950,11 @@ class VBIBuilder {
762
950
  this.chartType = new ChartTypeBuilder(doc, this.dsl);
763
951
  this.measures = new MeasuresBuilder(doc, this.dsl);
764
952
  this.dimensions = new DimensionsBuilder(doc, this.dsl);
765
- this.havingFilters = new HavingFiltersBuilder(doc, this.dsl);
766
- this.whereFilters = new WhereFiltersBuilder(doc, this.dsl);
953
+ this.havingFilter = new HavingFilterBuilder(doc, this.dsl);
954
+ this.whereFilter = new WhereFilterBuilder(doc, this.dsl);
955
+ this.theme = new ThemeBuilder(doc, this.dsl);
956
+ this.locale = new LocaleBuilder(doc, this.dsl);
957
+ this.limit = new LimitBuilder(doc, this.dsl);
767
958
  }
768
959
  applyUpdate(update) {
769
960
  applyUpdate(this.doc, update);
@@ -800,18 +991,6 @@ class VBIBuilder {
800
991
  const result = await con.discoverSchema();
801
992
  return result;
802
993
  };
803
- setLimit(limit) {
804
- this.dsl.set('limit', limit);
805
- return this;
806
- }
807
- setLocale(locale) {
808
- this.dsl.set('locale', locale);
809
- return this;
810
- }
811
- setTheme(theme) {
812
- this.dsl.set('theme', theme);
813
- return this;
814
- }
815
994
  }
816
995
  const createVBI = ()=>({
817
996
  connectorMap: connectorMap,
@@ -822,8 +1001,16 @@ const createVBI = ()=>({
822
1001
  chartType: 'table',
823
1002
  measures: [],
824
1003
  dimensions: [],
825
- whereFilters: [],
826
- havingFilters: [],
1004
+ whereFilter: {
1005
+ id: 'root',
1006
+ op: 'and',
1007
+ conditions: []
1008
+ },
1009
+ havingFilter: {
1010
+ id: 'root',
1011
+ op: 'and',
1012
+ conditions: []
1013
+ },
827
1014
  theme: 'light',
828
1015
  locale: 'zh-CN',
829
1016
  version: 0
@@ -837,7 +1024,7 @@ const createVBI = ()=>({
837
1024
  if (vbi.theme) dsl.set('theme', vbi.theme);
838
1025
  if (vbi.limit) dsl.set('limit', vbi.limit);
839
1026
  if (vbi.locale) dsl.set('locale', vbi.locale);
840
- if (vbi.version) dsl.set('version', vbi.version);
1027
+ if (void 0 !== vbi.version) dsl.set('version', vbi.version);
841
1028
  const toYMap = (obj, ensureId = false)=>{
842
1029
  const yMap = new external_yjs_Map();
843
1030
  if (ensureId && !obj.id) yMap.set('id', id_id.uuid());
@@ -875,8 +1062,38 @@ const createVBI = ()=>({
875
1062
  });
876
1063
  return yArr;
877
1064
  };
878
- dsl.set('whereFilters', ensureYArray(vbi.whereFilters, true));
879
- dsl.set('havingFilters', ensureYArray(vbi.havingFilters, true));
1065
+ const whereFilter = vbi.whereFilter ?? {
1066
+ id: 'root',
1067
+ op: 'and',
1068
+ conditions: []
1069
+ };
1070
+ const whereGroup = whereFilter instanceof external_yjs_Map ? whereFilter : createWhereGroup();
1071
+ if (whereFilter instanceof external_yjs_Map) {
1072
+ if (!(whereGroup.get('conditions') instanceof external_yjs_Array)) whereGroup.set('conditions', new external_yjs_Array());
1073
+ if (!whereGroup.get('id')) whereGroup.set('id', 'root');
1074
+ if (!whereGroup.get('op')) whereGroup.set('op', 'and');
1075
+ } else {
1076
+ whereGroup.set('id', whereFilter.id ?? 'root');
1077
+ whereGroup.set('op', whereFilter.op ?? 'and');
1078
+ whereGroup.set('conditions', ensureYArray(whereFilter.conditions, true));
1079
+ }
1080
+ dsl.set('whereFilter', whereGroup);
1081
+ const havingFilter = vbi.havingFilter ?? {
1082
+ id: 'root',
1083
+ op: 'and',
1084
+ conditions: []
1085
+ };
1086
+ const havingGroup = havingFilter instanceof external_yjs_Map ? havingFilter : createHavingGroup();
1087
+ if (havingFilter instanceof external_yjs_Map) {
1088
+ if (!(havingGroup.get('conditions') instanceof external_yjs_Array)) havingGroup.set('conditions', new external_yjs_Array());
1089
+ if (!havingGroup.get('id')) havingGroup.set('id', 'root');
1090
+ if (!havingGroup.get('op')) havingGroup.set('op', 'and');
1091
+ } else {
1092
+ havingGroup.set('id', havingFilter.id ?? 'root');
1093
+ havingGroup.set('op', havingFilter.op ?? 'and');
1094
+ havingGroup.set('conditions', ensureYArray(havingFilter.conditions, true));
1095
+ }
1096
+ dsl.set('havingFilter', havingGroup);
880
1097
  dsl.set('measures', ensureYArray(vbi.measures));
881
1098
  dsl.set('dimensions', ensureYArray(vbi.dimensions));
882
1099
  });
@@ -884,52 +1101,4 @@ const createVBI = ()=>({
884
1101
  }
885
1102
  });
886
1103
  const VBI = createVBI();
887
- const zVBIFilter = z.object({
888
- id: z.string(),
889
- field: z.string(),
890
- op: z.string().optional(),
891
- value: z.any().optional()
892
- });
893
- const zVBIWhereGroup = z.lazy(()=>z.object({
894
- id: z.string(),
895
- op: z["enum"]([
896
- 'and',
897
- 'or'
898
- ]),
899
- conditions: z.array(zVBIWhereClause)
900
- }));
901
- const zVBIWhereClause = z.lazy(()=>z.union([
902
- zVBIFilter,
903
- zVBIWhereGroup
904
- ]));
905
- function isVBIFilter(clause) {
906
- return 'field' in clause;
907
- }
908
- function isVBIWhereGroup(clause) {
909
- return 'conditions' in clause;
910
- }
911
- const zVBIHavingFilter = z.object({
912
- id: z.string(),
913
- field: z.string(),
914
- op: z.string().optional(),
915
- value: z.any().optional()
916
- });
917
- const zVBIHavingGroup = z.lazy(()=>z.object({
918
- id: z.string(),
919
- op: z["enum"]([
920
- 'and',
921
- 'or'
922
- ]),
923
- conditions: z.array(zVBIHavingClause)
924
- }));
925
- const zVBIHavingClause = z.lazy(()=>z.union([
926
- zVBIHavingFilter,
927
- zVBIHavingGroup
928
- ]));
929
- function isVBIHavingFilter(clause) {
930
- return 'field' in clause;
931
- }
932
- function isVBIHavingGroup(clause) {
933
- return 'conditions' in clause;
934
- }
935
- export { ChartTypeBuilder, DimensionsBuilder, MeasuresBuilder, VBI, VBIBuilder, buildVQuery, findTreeNodesBy, id_id as id, isVBIFilter, isVBIHavingFilter, isVBIHavingGroup, isVBIWhereGroup, preorderTraverse };
1104
+ export { ChartTypeBuilder, DimensionsBuilder, HavingFilterBuilder, LimitBuilder, LocaleBuilder, MeasuresBuilder, ThemeBuilder, undo_manager_UndoManager as UndoManager, VBI, VBIBuilder, WhereFilterBuilder, buildVQuery, findTreeNodesBy, id_id as id, isVBIFilter, isVBIHavingFilter, isVBIHavingGroup, isVBIWhereGroup, preorderTraverse };