@forestadmin-experimental/datasource-cosmos 1.8.1 → 1.8.3
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.
|
@@ -27,11 +27,34 @@ export default class AggregationConverter {
|
|
|
27
27
|
* Year: 4 chars -> "2024", Month: 7 -> "2024-01", Day: 10 -> "2024-01-15"
|
|
28
28
|
*/
|
|
29
29
|
private static DATE_OPERATION_TO_LENGTH;
|
|
30
|
+
/** Date operations that require post-processing rollup from daily data */
|
|
31
|
+
private static ROLLUP_OPERATIONS;
|
|
30
32
|
/**
|
|
31
33
|
* Build a Cosmos DB expression that truncates a date field to the given granularity.
|
|
32
|
-
* Uses LEFT() on ISO 8601 string dates
|
|
34
|
+
* Uses LEFT() on ISO 8601 string dates.
|
|
35
|
+
* Week and Quarter query at Day granularity for performance (avoids
|
|
36
|
+
* expensive computed expressions in GROUP BY) and roll up in post-processing.
|
|
33
37
|
*/
|
|
34
38
|
private static buildDateGroupExpression;
|
|
39
|
+
/**
|
|
40
|
+
* Compute the Monday of the week for a given "YYYY-MM-DD" date string.
|
|
41
|
+
*/
|
|
42
|
+
private static getMonday;
|
|
43
|
+
/**
|
|
44
|
+
* Compute the first day of the quarter for a "YYYY-MM-DD" date string.
|
|
45
|
+
* Returns "YYYY-MM-01" where MM is 01, 04, 07, or 10.
|
|
46
|
+
*/
|
|
47
|
+
private static getQuarterStart;
|
|
48
|
+
/**
|
|
49
|
+
* Reduce two values according to the aggregation operation.
|
|
50
|
+
*/
|
|
51
|
+
private static reduce;
|
|
52
|
+
/**
|
|
53
|
+
* Roll up daily aggregation results into coarser time buckets.
|
|
54
|
+
* Used for Week and Quarter to avoid expensive Cosmos DB computed expressions.
|
|
55
|
+
* Applies the correct reduction per aggregation operation.
|
|
56
|
+
*/
|
|
57
|
+
private static rollupResults;
|
|
35
58
|
/**
|
|
36
59
|
* Build aggregation query with grouping
|
|
37
60
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregation-converter.d.ts","sourceRoot":"","sources":["../../src/utils/aggregation-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,WAAW,EAEX,aAAa,EACd,MAAM,iCAAiC,CAAC;AAMzC,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS,CAGrB;IAEH,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAMlC;IAEF;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAS5B;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAC1B,WAAW,EAAE,WAAW,EACxB,aAAa,CAAC,EAAE,aAAa,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,YAAY;IAiBf;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAUvC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAIrC;IAEF;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"aggregation-converter.d.ts","sourceRoot":"","sources":["../../src/utils/aggregation-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,WAAW,EAEX,aAAa,EACd,MAAM,iCAAiC,CAAC;AAMzC,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS,CAGrB;IAEH,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAMlC;IAEF;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAS5B;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAC1B,WAAW,EAAE,WAAW,EACxB,aAAa,CAAC,EAAE,aAAa,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,YAAY;IAiBf;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAUvC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAIrC;IAEF,0EAA0E;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAgC;IAEhE;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAevC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IASxB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAO9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,MAAM;IAWrB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IA0C5B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAuC3C;;OAEG;IACH;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAIpC,MAAM,CAAC,yBAAyB,CAC9B,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC1C,WAAW,EAAE,WAAW,GACvB,eAAe,EAAE;CA8BrB"}
|
|
@@ -47,15 +47,89 @@ class AggregationConverter {
|
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
49
|
* Build a Cosmos DB expression that truncates a date field to the given granularity.
|
|
50
|
-
* Uses LEFT() on ISO 8601 string dates
|
|
50
|
+
* Uses LEFT() on ISO 8601 string dates.
|
|
51
|
+
* Week and Quarter query at Day granularity for performance (avoids
|
|
52
|
+
* expensive computed expressions in GROUP BY) and roll up in post-processing.
|
|
51
53
|
*/
|
|
52
54
|
static buildDateGroupExpression(field, operation) {
|
|
55
|
+
// Week/Quarter: query at Day level, roll up in processAggregationResults
|
|
56
|
+
if (this.ROLLUP_OPERATIONS.has(operation)) {
|
|
57
|
+
return `LEFT(${field}, 10)`;
|
|
58
|
+
}
|
|
53
59
|
const length = this.DATE_OPERATION_TO_LENGTH[operation];
|
|
54
60
|
if (!length) {
|
|
55
61
|
throw new Error(`Unsupported date operation: "${operation}"`);
|
|
56
62
|
}
|
|
57
63
|
return `LEFT(${field}, ${length})`;
|
|
58
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Compute the Monday of the week for a given "YYYY-MM-DD" date string.
|
|
67
|
+
*/
|
|
68
|
+
static getMonday(dateStr) {
|
|
69
|
+
const date = new Date(`${dateStr}T00:00:00Z`);
|
|
70
|
+
const day = date.getUTCDay(); // 0=Sun, 1=Mon, ..., 6=Sat
|
|
71
|
+
const diff = (day + 6) % 7; // days since Monday
|
|
72
|
+
date.setUTCDate(date.getUTCDate() - diff);
|
|
73
|
+
return date.toISOString().slice(0, 10);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Compute the first day of the quarter for a "YYYY-MM-DD" date string.
|
|
77
|
+
* Returns "YYYY-MM-01" where MM is 01, 04, 07, or 10.
|
|
78
|
+
*/
|
|
79
|
+
static getQuarterStart(dateStr) {
|
|
80
|
+
const month = parseInt(dateStr.slice(5, 7), 10);
|
|
81
|
+
const quarterStartMonth = Math.floor((month - 1) / 3) * 3 + 1;
|
|
82
|
+
return `${dateStr.slice(0, 4)}-${String(quarterStartMonth).padStart(2, '0')}-01`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Reduce two values according to the aggregation operation.
|
|
86
|
+
*/
|
|
87
|
+
static reduce(op, current, incoming) {
|
|
88
|
+
switch (op) {
|
|
89
|
+
case 'Max':
|
|
90
|
+
return Math.max(current, incoming);
|
|
91
|
+
case 'Min':
|
|
92
|
+
return Math.min(current, incoming);
|
|
93
|
+
default: // Sum, Count, Avg
|
|
94
|
+
return current + incoming;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Roll up daily aggregation results into coarser time buckets.
|
|
99
|
+
* Used for Week and Quarter to avoid expensive Cosmos DB computed expressions.
|
|
100
|
+
* Applies the correct reduction per aggregation operation.
|
|
101
|
+
*/
|
|
102
|
+
static rollupResults(results, aggregation) {
|
|
103
|
+
const group = aggregation.groups[0];
|
|
104
|
+
const op = aggregation.operation;
|
|
105
|
+
const bucketFn = group.operation === 'Week' ? this.getMonday : this.getQuarterStart;
|
|
106
|
+
const buckets = new Map();
|
|
107
|
+
const counts = new Map();
|
|
108
|
+
for (const result of results) {
|
|
109
|
+
const rawValue = result.group[group.field];
|
|
110
|
+
if (rawValue != null) {
|
|
111
|
+
const bucketKey = bucketFn(String(rawValue));
|
|
112
|
+
const value = Number(result.value) || 0;
|
|
113
|
+
if (buckets.has(bucketKey)) {
|
|
114
|
+
buckets.set(bucketKey, this.reduce(op, buckets.get(bucketKey), value));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
buckets.set(bucketKey, value);
|
|
118
|
+
}
|
|
119
|
+
counts.set(bucketKey, (counts.get(bucketKey) || 0) + 1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// For Avg, divide the accumulated sum by the number of days
|
|
123
|
+
if (op === 'Avg') {
|
|
124
|
+
for (const [key, sum] of buckets) {
|
|
125
|
+
buckets.set(key, sum / counts.get(key));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return Array.from(buckets.entries()).map(([key, value]) => ({
|
|
129
|
+
value,
|
|
130
|
+
group: { [group.field]: key },
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
59
133
|
/**
|
|
60
134
|
* Build aggregation query with grouping
|
|
61
135
|
*/
|
|
@@ -102,13 +176,19 @@ class AggregationConverter {
|
|
|
102
176
|
}
|
|
103
177
|
return [{ value: this.extractAggregateValue(rawResults[0]), group: {} }];
|
|
104
178
|
}
|
|
105
|
-
|
|
179
|
+
const results = rawResults.map(result => {
|
|
106
180
|
const group = {};
|
|
107
181
|
aggregation.groups.forEach((groupDef, index) => {
|
|
108
182
|
group[groupDef.field] = serializer_1.default.serializeValue(result.groupKey || result[`group${index}`]);
|
|
109
183
|
});
|
|
110
184
|
return { value: this.extractAggregateValue(result), group };
|
|
111
185
|
});
|
|
186
|
+
// Roll up daily results into Week/Quarter buckets
|
|
187
|
+
const dateOp = aggregation.groups[0]?.operation;
|
|
188
|
+
if (dateOp && this.ROLLUP_OPERATIONS.has(dateOp)) {
|
|
189
|
+
return this.rollupResults(results, aggregation);
|
|
190
|
+
}
|
|
191
|
+
return results;
|
|
112
192
|
}
|
|
113
193
|
}
|
|
114
194
|
/**
|
|
@@ -136,5 +216,7 @@ AggregationConverter.DATE_OPERATION_TO_LENGTH = {
|
|
|
136
216
|
Month: 7,
|
|
137
217
|
Day: 10,
|
|
138
218
|
};
|
|
219
|
+
/** Date operations that require post-processing rollup from daily data */
|
|
220
|
+
AggregationConverter.ROLLUP_OPERATIONS = new Set(['Week', 'Quarter']);
|
|
139
221
|
exports.default = AggregationConverter;
|
|
140
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
222
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdncmVnYXRpb24tY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2FnZ3JlZ2F0aW9uLWNvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVFBLHdFQUErQztBQUMvQyx3RUFBK0M7QUFDL0MsOERBQXNDO0FBRXRDLE1BQXFCLG9CQUFvQjtJQWtCdkM7Ozs7T0FJRztJQUNLLE1BQU0sQ0FBQyxhQUFhLENBQUMsS0FBYSxFQUFFLE9BQU8sR0FBRyxtQkFBbUI7UUFDdkUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFakQsT0FBTyxLQUFLO2FBQ1QsS0FBSyxDQUFDLElBQUksQ0FBQzthQUNYLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLENBQUM7YUFDbEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2QsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLHFCQUFxQixDQUMxQixXQUF3QixFQUN4QixhQUE2QixFQUM3QixLQUFjO1FBRWQsTUFBTSxjQUFjLEdBQUcsSUFBSSx5QkFBYyxFQUFFLENBQUM7UUFDNUMsTUFBTSxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsR0FBRyxjQUFjLENBQUMsY0FBYyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzNFLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBRXBELDZDQUE2QztRQUM3QyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUs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
|