dbgate-datalib 6.4.3-alpha.1 → 6.5.0

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.
@@ -0,0 +1,471 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.computeChartBucketCardinality = exports.fillChartTimelineBuckets = exports.aggregateChartNumericValuesFromChild = exports.aggregateChartNumericValuesFromSource = exports.autoAggregateCompactTimelineChart = exports.compareChartDatesParsed = exports.computeDateBucketDistance = exports.computeChartBucketKey = exports.incrementChartDate = exports.stringifyChartDate = exports.tryParseChartDate = exports.getChartDebugPrint = void 0;
7
+ const toPairs_1 = __importDefault(require("lodash/toPairs"));
8
+ const sumBy_1 = __importDefault(require("lodash/sumBy"));
9
+ const chartDefinitions_1 = require("./chartDefinitions");
10
+ const date_fns_1 = require("date-fns");
11
+ function getChartDebugPrint(chart) {
12
+ let res = '';
13
+ res += `Chart: ${chart.definition.chartType} (${chart.definition.xdef.transformFunction})\n`;
14
+ for (const key of chart.bucketKeysOrdered) {
15
+ res += `${key}: ${(0, toPairs_1.default)(chart.buckets[key])
16
+ .map(([k, v]) => `${k}=${v}`)
17
+ .join(', ')}\n`;
18
+ }
19
+ return res;
20
+ }
21
+ exports.getChartDebugPrint = getChartDebugPrint;
22
+ function tryParseChartDate(dateInput) {
23
+ if (dateInput instanceof Date) {
24
+ return {
25
+ year: dateInput.getFullYear(),
26
+ month: dateInput.getMonth() + 1,
27
+ day: dateInput.getDate(),
28
+ hour: dateInput.getHours(),
29
+ minute: dateInput.getMinutes(),
30
+ second: dateInput.getSeconds(),
31
+ fraction: undefined, // Date object does not have fraction
32
+ };
33
+ }
34
+ if (typeof dateInput !== 'string')
35
+ return null;
36
+ const m = dateInput.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(Z|[+-]\d{2}:\d{2})?)?$/);
37
+ if (!m)
38
+ return null;
39
+ const [_notUsed, year, month, day, hour, minute, second, fraction] = m;
40
+ return {
41
+ year: parseInt(year, 10),
42
+ month: parseInt(month, 10),
43
+ day: parseInt(day, 10),
44
+ hour: parseInt(hour, 10) || 0,
45
+ minute: parseInt(minute, 10) || 0,
46
+ second: parseInt(second, 10) || 0,
47
+ fraction: fraction || undefined,
48
+ };
49
+ }
50
+ exports.tryParseChartDate = tryParseChartDate;
51
+ function pad2Digits(number) {
52
+ return ('00' + number).slice(-2);
53
+ }
54
+ function stringifyChartDate(value, transform) {
55
+ switch (transform) {
56
+ case 'date:year':
57
+ return `${value.year}`;
58
+ case 'date:month':
59
+ return `${value.year}-${pad2Digits(value.month)}`;
60
+ case 'date:day':
61
+ return `${value.year}-${pad2Digits(value.month)}-${pad2Digits(value.day)}`;
62
+ case 'date:hour':
63
+ return `${value.year}-${pad2Digits(value.month)}-${pad2Digits(value.day)} ${pad2Digits(value.hour)}`;
64
+ case 'date:minute':
65
+ return `${value.year}-${pad2Digits(value.month)}-${pad2Digits(value.day)} ${pad2Digits(value.hour)}:${pad2Digits(value.minute)}`;
66
+ default:
67
+ return '';
68
+ }
69
+ }
70
+ exports.stringifyChartDate = stringifyChartDate;
71
+ function incrementChartDate(value, transform) {
72
+ var _a, _b, _c, _d;
73
+ const dateRepresentation = new Date(value.year, ((_a = value.month) !== null && _a !== void 0 ? _a : 1) - 1, (_b = value.day) !== null && _b !== void 0 ? _b : 1, (_c = value.hour) !== null && _c !== void 0 ? _c : 0, (_d = value.minute) !== null && _d !== void 0 ? _d : 0);
74
+ let newDateRepresentation;
75
+ switch (transform) {
76
+ case 'date:year':
77
+ newDateRepresentation = (0, date_fns_1.addYears)(dateRepresentation, 1);
78
+ break;
79
+ case 'date:month':
80
+ newDateRepresentation = (0, date_fns_1.addMonths)(dateRepresentation, 1);
81
+ break;
82
+ case 'date:day':
83
+ newDateRepresentation = (0, date_fns_1.addDays)(dateRepresentation, 1);
84
+ break;
85
+ case 'date:hour':
86
+ newDateRepresentation = (0, date_fns_1.addHours)(dateRepresentation, 1);
87
+ break;
88
+ case 'date:minute':
89
+ newDateRepresentation = (0, date_fns_1.addMinutes)(dateRepresentation, 1);
90
+ break;
91
+ }
92
+ switch (transform) {
93
+ case 'date:year':
94
+ return { year: newDateRepresentation.getFullYear() };
95
+ case 'date:month':
96
+ return {
97
+ year: newDateRepresentation.getFullYear(),
98
+ month: newDateRepresentation.getMonth() + 1,
99
+ };
100
+ case 'date:day':
101
+ return {
102
+ year: newDateRepresentation.getFullYear(),
103
+ month: newDateRepresentation.getMonth() + 1,
104
+ day: newDateRepresentation.getDate(),
105
+ };
106
+ case 'date:hour':
107
+ return {
108
+ year: newDateRepresentation.getFullYear(),
109
+ month: newDateRepresentation.getMonth() + 1,
110
+ day: newDateRepresentation.getDate(),
111
+ hour: newDateRepresentation.getHours(),
112
+ };
113
+ case 'date:minute':
114
+ return {
115
+ year: newDateRepresentation.getFullYear(),
116
+ month: newDateRepresentation.getMonth() + 1,
117
+ day: newDateRepresentation.getDate(),
118
+ hour: newDateRepresentation.getHours(),
119
+ minute: newDateRepresentation.getMinutes(),
120
+ };
121
+ }
122
+ }
123
+ exports.incrementChartDate = incrementChartDate;
124
+ function computeChartBucketKey(dateParsed, chart, row) {
125
+ switch (chart.definition.xdef.transformFunction) {
126
+ case 'date:year':
127
+ return [dateParsed ? `${dateParsed.year}` : null, { year: dateParsed.year }];
128
+ case 'date:month':
129
+ return [
130
+ dateParsed ? `${dateParsed.year}-${pad2Digits(dateParsed.month)}` : null,
131
+ {
132
+ year: dateParsed.year,
133
+ month: dateParsed.month,
134
+ },
135
+ ];
136
+ case 'date:day':
137
+ return [
138
+ dateParsed ? `${dateParsed.year}-${pad2Digits(dateParsed.month)}-${pad2Digits(dateParsed.day)}` : null,
139
+ {
140
+ year: dateParsed.year,
141
+ month: dateParsed.month,
142
+ day: dateParsed.day,
143
+ },
144
+ ];
145
+ case 'date:hour':
146
+ return [
147
+ dateParsed
148
+ ? `${dateParsed.year}-${pad2Digits(dateParsed.month)}-${pad2Digits(dateParsed.day)} ${pad2Digits(dateParsed.hour)}`
149
+ : null,
150
+ {
151
+ year: dateParsed.year,
152
+ month: dateParsed.month,
153
+ day: dateParsed.day,
154
+ hour: dateParsed.hour,
155
+ },
156
+ ];
157
+ case 'date:minute':
158
+ return [
159
+ dateParsed
160
+ ? `${dateParsed.year}-${pad2Digits(dateParsed.month)}-${pad2Digits(dateParsed.day)} ${pad2Digits(dateParsed.hour)}:${pad2Digits(dateParsed.minute)}`
161
+ : null,
162
+ {
163
+ year: dateParsed.year,
164
+ month: dateParsed.month,
165
+ day: dateParsed.day,
166
+ hour: dateParsed.hour,
167
+ minute: dateParsed.minute,
168
+ },
169
+ ];
170
+ case 'identity':
171
+ default:
172
+ return [row[chart.definition.xdef.field], null];
173
+ }
174
+ }
175
+ exports.computeChartBucketKey = computeChartBucketKey;
176
+ function computeDateBucketDistance(begin, end, transform) {
177
+ switch (transform) {
178
+ case 'date:year':
179
+ return end.year - begin.year;
180
+ case 'date:month':
181
+ return (end.year - begin.year) * 12 + (end.month - begin.month);
182
+ case 'date:day':
183
+ return ((end.year - begin.year) * 365 +
184
+ (end.month - begin.month) * 30 + // rough approximation
185
+ (end.day - begin.day));
186
+ case 'date:hour':
187
+ return ((end.year - begin.year) * 365 * 24 +
188
+ (end.month - begin.month) * 30 * 24 + // rough approximation
189
+ (end.day - begin.day) * 24 +
190
+ (end.hour - begin.hour));
191
+ case 'date:minute':
192
+ return ((end.year - begin.year) * 365 * 24 * 60 +
193
+ (end.month - begin.month) * 30 * 24 * 60 + // rough approximation
194
+ (end.day - begin.day) * 24 * 60 +
195
+ (end.hour - begin.hour) * 60 +
196
+ (end.minute - begin.minute));
197
+ case 'identity':
198
+ default:
199
+ return NaN;
200
+ }
201
+ }
202
+ exports.computeDateBucketDistance = computeDateBucketDistance;
203
+ function compareChartDatesParsed(a, b, transform) {
204
+ switch (transform) {
205
+ case 'date:year':
206
+ return a.year - b.year;
207
+ case 'date:month':
208
+ return a.year === b.year ? a.month - b.month : a.year - b.year;
209
+ case 'date:day':
210
+ return a.year === b.year && a.month === b.month
211
+ ? a.day - b.day
212
+ : a.year === b.year
213
+ ? a.month - b.month
214
+ : a.year - b.year;
215
+ case 'date:hour':
216
+ return a.year === b.year && a.month === b.month && a.day === b.day
217
+ ? a.hour - b.hour
218
+ : a.year === b.year && a.month === b.month
219
+ ? a.day - b.day
220
+ : a.year === b.year
221
+ ? a.month - b.month
222
+ : a.year - b.year;
223
+ case 'date:minute':
224
+ return a.year === b.year && a.month === b.month && a.day === b.day && a.hour === b.hour
225
+ ? a.minute - b.minute
226
+ : a.year === b.year && a.month === b.month && a.day === b.day
227
+ ? a.hour - b.hour
228
+ : a.year === b.year && a.month === b.month
229
+ ? a.day - b.day
230
+ : a.year === b.year
231
+ ? a.month - b.month
232
+ : a.year - b.year;
233
+ }
234
+ }
235
+ exports.compareChartDatesParsed = compareChartDatesParsed;
236
+ function getParentDateBucketKey(bucketKey, transform) {
237
+ switch (transform) {
238
+ case 'date:year':
239
+ return null; // no parent for year
240
+ case 'date:month':
241
+ return bucketKey.slice(0, 4);
242
+ case 'date:day':
243
+ return bucketKey.slice(0, 7);
244
+ case 'date:hour':
245
+ return bucketKey.slice(0, 10);
246
+ case 'date:minute':
247
+ return bucketKey.slice(0, 13);
248
+ }
249
+ }
250
+ function getParentDateBucketTransform(transform) {
251
+ switch (transform) {
252
+ case 'date:year':
253
+ return null; // no parent for year
254
+ case 'date:month':
255
+ return 'date:year';
256
+ case 'date:day':
257
+ return 'date:month';
258
+ case 'date:hour':
259
+ return 'date:day';
260
+ case 'date:minute':
261
+ return 'date:hour';
262
+ default:
263
+ return null;
264
+ }
265
+ }
266
+ function getParentKeyParsed(date, transform) {
267
+ switch (transform) {
268
+ case 'date:year':
269
+ return null; // no parent for year
270
+ case 'date:month':
271
+ return { year: date.year };
272
+ case 'date:day':
273
+ return { year: date.year, month: date.month };
274
+ case 'date:hour':
275
+ return { year: date.year, month: date.month, day: date.day };
276
+ case 'date:minute':
277
+ return { year: date.year, month: date.month, day: date.day, hour: date.hour };
278
+ default:
279
+ return null;
280
+ }
281
+ }
282
+ function createParentChartAggregation(chart) {
283
+ if (chart.isGivenDefinition) {
284
+ // if the chart is created with a given definition, we cannot create a parent aggregation
285
+ return null;
286
+ }
287
+ const parentTransform = getParentDateBucketTransform(chart.definition.xdef.transformFunction);
288
+ if (!parentTransform) {
289
+ return null;
290
+ }
291
+ const res = {
292
+ definition: Object.assign(Object.assign({}, chart.definition), { xdef: Object.assign(Object.assign({}, chart.definition.xdef), { transformFunction: parentTransform }) }),
293
+ rowsAdded: chart.rowsAdded,
294
+ bucketKeysOrdered: [],
295
+ buckets: {},
296
+ bucketKeyDateParsed: {},
297
+ isGivenDefinition: false,
298
+ invalidXRows: chart.invalidXRows,
299
+ invalidYRows: Object.assign({}, chart.invalidYRows),
300
+ validYRows: Object.assign({}, chart.validYRows),
301
+ topDistinctValues: Object.assign({}, chart.topDistinctValues),
302
+ availableColumns: chart.availableColumns,
303
+ };
304
+ for (const [bucketKey, bucketValues] of Object.entries(chart.buckets)) {
305
+ const parentKey = getParentDateBucketKey(bucketKey, chart.definition.xdef.transformFunction);
306
+ if (!parentKey) {
307
+ // skip if the bucket is already a parent
308
+ continue;
309
+ }
310
+ res.bucketKeyDateParsed[parentKey] = getParentKeyParsed(chart.bucketKeyDateParsed[bucketKey], chart.definition.xdef.transformFunction);
311
+ aggregateChartNumericValuesFromChild(res, parentKey, bucketValues);
312
+ }
313
+ const bucketKeys = Object.keys(res.buckets).sort();
314
+ res.minX = bucketKeys.length > 0 ? bucketKeys[0] : null;
315
+ res.maxX = bucketKeys.length > 0 ? bucketKeys[bucketKeys.length - 1] : null;
316
+ return res;
317
+ }
318
+ function autoAggregateCompactTimelineChart(chart) {
319
+ var _a;
320
+ while (true) {
321
+ const fromParsed = chart.bucketKeyDateParsed[chart.minX];
322
+ const toParsed = chart.bucketKeyDateParsed[chart.maxX];
323
+ if (!fromParsed || !toParsed) {
324
+ return chart; // cannot fill timeline buckets without valid date range
325
+ }
326
+ const transform = chart.definition.xdef.transformFunction;
327
+ if (!transform.startsWith('date:')) {
328
+ return chart; // cannot aggregate non-date charts
329
+ }
330
+ const dateDistance = computeDateBucketDistance(fromParsed, toParsed, transform);
331
+ if (dateDistance < ((_a = chart.definition.xdef.parentAggregateLimit) !== null && _a !== void 0 ? _a : chartDefinitions_1.ChartConstDefaults.parentAggregateLimit)) {
332
+ return chart; // no need to aggregate further, the distance is less than the limit
333
+ }
334
+ const parentChart = createParentChartAggregation(chart);
335
+ if (!parentChart) {
336
+ return chart; // cannot create parent aggregation
337
+ }
338
+ chart = parentChart;
339
+ }
340
+ }
341
+ exports.autoAggregateCompactTimelineChart = autoAggregateCompactTimelineChart;
342
+ function aggregateChartNumericValuesFromSource(chart, bucketKey, numericColumns, row) {
343
+ for (const ydef of chart.definition.ydefs) {
344
+ if (numericColumns[ydef.field] == null) {
345
+ if (row[ydef.field]) {
346
+ chart.invalidYRows[ydef.field] = (chart.invalidYRows[ydef.field] || 0) + 1; // increment invalid row count if the field is not numeric
347
+ }
348
+ continue;
349
+ }
350
+ chart.validYRows[ydef.field] = (chart.validYRows[ydef.field] || 0) + 1; // increment valid row count
351
+ let distinctValues = chart.topDistinctValues[ydef.field];
352
+ if (!distinctValues) {
353
+ distinctValues = new Set();
354
+ chart.topDistinctValues[ydef.field] = distinctValues;
355
+ }
356
+ if (distinctValues.size < chartDefinitions_1.ChartLimits.MAX_DISTINCT_VALUES) {
357
+ chart.topDistinctValues[ydef.field].add(numericColumns[ydef.field]);
358
+ }
359
+ switch (ydef.aggregateFunction) {
360
+ case 'sum':
361
+ chart.buckets[bucketKey][ydef.field] =
362
+ (chart.buckets[bucketKey][ydef.field] || 0) + (numericColumns[ydef.field] || 0);
363
+ break;
364
+ case 'first':
365
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
366
+ chart.buckets[bucketKey][ydef.field] = numericColumns[ydef.field];
367
+ }
368
+ break;
369
+ case 'last':
370
+ chart.buckets[bucketKey][ydef.field] = numericColumns[ydef.field];
371
+ break;
372
+ case 'min':
373
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
374
+ chart.buckets[bucketKey][ydef.field] = numericColumns[ydef.field];
375
+ }
376
+ else {
377
+ chart.buckets[bucketKey][ydef.field] = Math.min(chart.buckets[bucketKey][ydef.field], numericColumns[ydef.field]);
378
+ }
379
+ break;
380
+ case 'max':
381
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
382
+ chart.buckets[bucketKey][ydef.field] = numericColumns[ydef.field];
383
+ }
384
+ else {
385
+ chart.buckets[bucketKey][ydef.field] = Math.max(chart.buckets[bucketKey][ydef.field], numericColumns[ydef.field]);
386
+ }
387
+ break;
388
+ case 'count':
389
+ chart.buckets[bucketKey][ydef.field] = (chart.buckets[bucketKey][ydef.field] || 0) + 1;
390
+ break;
391
+ case 'avg':
392
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
393
+ chart.buckets[bucketKey][ydef.field] = [numericColumns[ydef.field], 1]; // [sum, count]
394
+ }
395
+ else {
396
+ chart.buckets[bucketKey][ydef.field][0] += numericColumns[ydef.field];
397
+ chart.buckets[bucketKey][ydef.field][1] += 1;
398
+ }
399
+ break;
400
+ }
401
+ }
402
+ }
403
+ exports.aggregateChartNumericValuesFromSource = aggregateChartNumericValuesFromSource;
404
+ function aggregateChartNumericValuesFromChild(chart, bucketKey, childBucketValues) {
405
+ for (const ydef of chart.definition.ydefs) {
406
+ if (childBucketValues[ydef.field] == undefined) {
407
+ continue; // skip if the field is not present in the child bucket
408
+ }
409
+ if (!chart.buckets[bucketKey]) {
410
+ chart.buckets[bucketKey] = {};
411
+ }
412
+ switch (ydef.aggregateFunction) {
413
+ case 'sum':
414
+ case 'count':
415
+ chart.buckets[bucketKey][ydef.field] =
416
+ (chart.buckets[bucketKey][ydef.field] || 0) + (childBucketValues[ydef.field] || 0);
417
+ break;
418
+ case 'min':
419
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
420
+ chart.buckets[bucketKey][ydef.field] = childBucketValues[ydef.field];
421
+ }
422
+ else {
423
+ chart.buckets[bucketKey][ydef.field] = Math.min(chart.buckets[bucketKey][ydef.field], childBucketValues[ydef.field]);
424
+ }
425
+ break;
426
+ case 'max':
427
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
428
+ chart.buckets[bucketKey][ydef.field] = childBucketValues[ydef.field];
429
+ }
430
+ else {
431
+ chart.buckets[bucketKey][ydef.field] = Math.max(chart.buckets[bucketKey][ydef.field], childBucketValues[ydef.field]);
432
+ }
433
+ break;
434
+ case 'avg':
435
+ if (chart.buckets[bucketKey][ydef.field] === undefined) {
436
+ chart.buckets[bucketKey][ydef.field] = childBucketValues[ydef.field];
437
+ }
438
+ else {
439
+ chart.buckets[bucketKey][ydef.field][0] += childBucketValues[ydef.field][0];
440
+ chart.buckets[bucketKey][ydef.field][1] += childBucketValues[ydef.field][1];
441
+ }
442
+ break;
443
+ case 'first':
444
+ case 'last':
445
+ throw new Error(`Cannot aggregate ${ydef.aggregateFunction} for ${ydef.field} in child bucket`);
446
+ }
447
+ }
448
+ }
449
+ exports.aggregateChartNumericValuesFromChild = aggregateChartNumericValuesFromChild;
450
+ function fillChartTimelineBuckets(chart) {
451
+ const fromParsed = chart.bucketKeyDateParsed[chart.minX];
452
+ const toParsed = chart.bucketKeyDateParsed[chart.maxX];
453
+ if (!fromParsed || !toParsed) {
454
+ return; // cannot fill timeline buckets without valid date range
455
+ }
456
+ const transform = chart.definition.xdef.transformFunction;
457
+ let currentParsed = fromParsed;
458
+ while (compareChartDatesParsed(currentParsed, toParsed, transform) <= 0) {
459
+ const bucketKey = stringifyChartDate(currentParsed, transform);
460
+ if (!chart.buckets[bucketKey]) {
461
+ chart.buckets[bucketKey] = {};
462
+ chart.bucketKeyDateParsed[bucketKey] = currentParsed;
463
+ }
464
+ currentParsed = incrementChartDate(currentParsed, transform);
465
+ }
466
+ }
467
+ exports.fillChartTimelineBuckets = fillChartTimelineBuckets;
468
+ function computeChartBucketCardinality(bucket) {
469
+ return (0, sumBy_1.default)(Object.keys(bucket), field => bucket[field]);
470
+ }
471
+ exports.computeChartBucketCardinality = computeChartBucketCardinality;
package/lib/index.d.ts CHANGED
@@ -23,3 +23,5 @@ export * from './FreeTableGridDisplay';
23
23
  export * from './FreeTableModel';
24
24
  export * from './CustomGridDisplay';
25
25
  export * from './ScriptDrivedDeployer';
26
+ export * from './chartDefinitions';
27
+ export * from './chartProcessor';
package/lib/index.js CHANGED
@@ -39,3 +39,5 @@ __exportStar(require("./FreeTableGridDisplay"), exports);
39
39
  __exportStar(require("./FreeTableModel"), exports);
40
40
  __exportStar(require("./CustomGridDisplay"), exports);
41
41
  __exportStar(require("./ScriptDrivedDeployer"), exports);
42
+ __exportStar(require("./chartDefinitions"), exports);
43
+ __exportStar(require("./chartProcessor"), exports);
@@ -0,0 +1 @@
1
+ export {};