@powerhousedao/analytics-engine-core 6.2.3-dev.6 → 6.2.3-dev.60
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.
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -21
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AnalyticsDimension, AnalyticsGranularity, AnalyticsPath, AnalyticsPathSegment, AnalyticsPeriod, AnalyticsQuery, AnalyticsSerializerTypes, AnalyticsSeries, AnalyticsSeriesInput, AnalyticsSeriesQuery, AnalyticsUpdateCallback, CompoundAnalyticsQuery, IAnalyticsStore, MultiCurrencyConversion } from "@powerhousedao/shared/analytics";
|
|
2
2
|
import { DateTime } from "luxon";
|
|
3
|
-
|
|
4
3
|
//#region src/AnalyticsProfiler.d.ts
|
|
5
4
|
interface IAnalyticsProfiler {
|
|
6
5
|
get prefix(): string;
|
|
@@ -10,7 +9,7 @@ interface IAnalyticsProfiler {
|
|
|
10
9
|
record: <T>(metric: string, fn: () => Promise<T>) => Promise<T>;
|
|
11
10
|
recordSync: <T>(metric: string, fn: () => T) => T;
|
|
12
11
|
}
|
|
13
|
-
declare class AnalyticsProfiler implements IAnalyticsProfiler {
|
|
12
|
+
export declare class AnalyticsProfiler implements IAnalyticsProfiler {
|
|
14
13
|
private readonly _ns;
|
|
15
14
|
private readonly _logger;
|
|
16
15
|
private readonly _stack;
|
|
@@ -24,7 +23,7 @@ declare class AnalyticsProfiler implements IAnalyticsProfiler {
|
|
|
24
23
|
recordSync<T>(metric: string, fn: () => T): T;
|
|
25
24
|
updatePrefix(): void;
|
|
26
25
|
}
|
|
27
|
-
declare class PassthroughAnalyticsProfiler implements IAnalyticsProfiler {
|
|
26
|
+
export declare class PassthroughAnalyticsProfiler implements IAnalyticsProfiler {
|
|
28
27
|
get prefix(): string;
|
|
29
28
|
push(_system: string): void;
|
|
30
29
|
pop(): void;
|
|
@@ -52,7 +51,7 @@ type GroupedPeriodResult = {
|
|
|
52
51
|
type GroupedPeriodResults = Array<GroupedPeriodResult>;
|
|
53
52
|
//#endregion
|
|
54
53
|
//#region src/AnalyticsQueryEngine.d.ts
|
|
55
|
-
declare class AnalyticsQueryEngine {
|
|
54
|
+
export declare class AnalyticsQueryEngine {
|
|
56
55
|
private readonly _analyticsStore;
|
|
57
56
|
private readonly _profiler;
|
|
58
57
|
constructor(_analyticsStore: IAnalyticsStore, profiler?: IAnalyticsProfiler);
|
|
@@ -69,14 +68,14 @@ declare class AnalyticsQueryEngine {
|
|
|
69
68
|
}
|
|
70
69
|
//#endregion
|
|
71
70
|
//#region src/AnalyticsSubscriptionManager.d.ts
|
|
72
|
-
declare class NotificationError extends Error {
|
|
71
|
+
export declare class NotificationError extends Error {
|
|
73
72
|
readonly innerErrors: Error[];
|
|
74
73
|
constructor(errors: Error[]);
|
|
75
74
|
}
|
|
76
75
|
/**
|
|
77
76
|
* Manages subscriptions for analytics paths.
|
|
78
77
|
*/
|
|
79
|
-
declare class AnalyticsSubscriptionManager {
|
|
78
|
+
export declare class AnalyticsSubscriptionManager {
|
|
80
79
|
private _subscriptions;
|
|
81
80
|
/**
|
|
82
81
|
* Subscribe to updates for an analytics path. A subscribed function will be
|
|
@@ -123,8 +122,9 @@ interface ISqlExecutor {
|
|
|
123
122
|
}
|
|
124
123
|
//#endregion
|
|
125
124
|
//#region src/util.d.ts
|
|
126
|
-
declare const defaultQueryLogger: (tag: string) => SqlQueryLogger;
|
|
127
|
-
declare const defaultResultsLogger: (tag: string) => SqlResultsLogger;
|
|
125
|
+
export declare const defaultQueryLogger: (tag: string) => SqlQueryLogger;
|
|
126
|
+
export declare const defaultResultsLogger: (tag: string) => SqlResultsLogger;
|
|
128
127
|
//#endregion
|
|
129
|
-
export { type AnalyticsDimension, AnalyticsGranularity, AnalyticsPath, AnalyticsPathSegment, AnalyticsPeriod,
|
|
128
|
+
export { type AnalyticsDimension, AnalyticsGranularity, AnalyticsPath, AnalyticsPathSegment, AnalyticsPeriod, type AnalyticsQuery, AnalyticsSerializerTypes, type AnalyticsSeries, type AnalyticsSeriesInput, type AnalyticsSeriesQuery, type AnalyticsUpdateCallback, type GroupedPeriodResult, type GroupedPeriodResults, type IAnalyticsProfiler, type IAnalyticsStore, type ISqlExecutor, type SqlQueryLogger, type SqlResultsLogger };
|
|
129
|
+
export {};
|
|
130
130
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/AnalyticsProfiler.ts","../src/AnalyticsDiscretizer.ts","../src/AnalyticsQueryEngine.ts","../src/AnalyticsSubscriptionManager.ts","../src/types.ts","../src/util.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/AnalyticsProfiler.ts","../src/AnalyticsDiscretizer.ts","../src/AnalyticsQueryEngine.ts","../src/AnalyticsSubscriptionManager.ts","../src/types.ts","../src/util.ts"],"mappings":";;;UAAiB;MACX;EAEJ,OAAO;EACP;EACA,eAAe;EAEf,SAAS,GAAG,gBAAgB,UAAU,QAAQ,OAAO,QAAQ;EAC7D,aAAa,GAAG,gBAAgB,UAAU,MAAM;;qBAGrC,6BAA6B;mBAKrB;mBACA;mBALF;UACT;EAER,YACmB,aACA,UAAU,oBAAoB;MAK7C;EAIJ,KAAK;EAML;EAMA,aAAa;EAMP,OAAO,GAAG,gBAAgB,UAAU,QAAQ,KAAK,QAAQ;EAW/D,WAAW,GAAG,gBAAgB,UAAU,IAAI;EAW5C;;qBASW,wCAAwC;MAC/C;EAIJ,KAAK;EAIL;EAIA,aAAa;EAIP,OAAO,GAAG,gBAAgB,UAAU,QAAQ,KAAE,QAAA;EAIpD,WAAW,GAAG,gBAAgB,UAAU,IAAC;;;;KC9E/B;EACV;EACA,OAAO;EACP,KAAK;EACL,MAAM;IACJ,YAAY,eAAe;IAC3B;IACA;IACA;;;;IAKA;;;KAIQ,uBAAuB,MAAM;;;qBCd5B;mBAIQ;mBAHF;EAEjB,YACmB,iBAAiB,iBAClC,WAAW;EAKA,gBACX,OAAO,yBACN,QAAQ;EA0DE,QAAQ,OAAO,iBAAiB,QAAQ;EAsBxC,qBACX,OAAO,gBACP,KAAK,0BACJ,QAAQ;UAwCH;UAgBA;UAoDA;UAiBM;UAcN;UAUA;EAmBK,iBAAiB;;;;qBCzRnB,0BAA0B;WACrB,aAAa;EAE7B,YAAY,QAAQ;;;;;qBAWT;UACH;;;;;;;;;;;;;;;EAgBD,gBACL,MAAM,eACN,UAAU;;;;;;EA4BL,kBAAkB,OAAO;;;;UAkExB;;;;UAUA;;;;;;UA+CA;;;;KC3LE,kBAAkB,eAAe;KAEjC,oBAAoB,eAAe;UAE9B;EACf,QAAQ,gBAAgB,qBAAqB;;;;qBCHlC,qBAAkB,gBACd;qBAKJ,uBAAoB,gBAChB"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ import { AnalyticsGranularity, AnalyticsPath, AnalyticsPathSegment, AnalyticsPer
|
|
|
2
2
|
import { DateTime, Interval } from "luxon";
|
|
3
3
|
//#region src/AnalyticsProfiler.ts
|
|
4
4
|
var AnalyticsProfiler = class {
|
|
5
|
+
_ns;
|
|
6
|
+
_logger;
|
|
5
7
|
_stack = [];
|
|
6
8
|
_prefix = "";
|
|
7
9
|
constructor(_ns, _logger) {
|
|
@@ -110,7 +112,7 @@ const _createFactoryFn = (range) => {
|
|
|
110
112
|
case AnalyticsGranularity.Hourly: result = _nextHourlyPeriod(current, range.end);
|
|
111
113
|
}
|
|
112
114
|
if (result === null) current = null;
|
|
113
|
-
else current = result.end
|
|
115
|
+
else current = result.end;
|
|
114
116
|
return result;
|
|
115
117
|
};
|
|
116
118
|
};
|
|
@@ -128,13 +130,14 @@ const _nextAnnualPeriod = (nextStart, seriesEnd) => {
|
|
|
128
130
|
return {
|
|
129
131
|
period: "annual",
|
|
130
132
|
start: nextStart,
|
|
131
|
-
end: DateTime.utc(inputUtc.year,
|
|
133
|
+
end: DateTime.utc(inputUtc.year + 1, 1, 1)
|
|
132
134
|
};
|
|
133
135
|
};
|
|
134
136
|
const _nextSemiAnnualPeriod = (nextStart, seriesEnd) => {
|
|
135
137
|
if (seriesEnd <= nextStart) return null;
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
+
const inputUtc = nextStart.toUTC();
|
|
139
|
+
const midYear = DateTime.utc(inputUtc.year, 7, 1);
|
|
140
|
+
const endYear = DateTime.utc(inputUtc.year + 1, 1, 1);
|
|
138
141
|
let endDate;
|
|
139
142
|
if (midYear > nextStart) endDate = midYear;
|
|
140
143
|
else endDate = endYear;
|
|
@@ -153,7 +156,7 @@ const _nextQuarterlyPeriod = (nextStart, seriesEnd) => {
|
|
|
153
156
|
if (startMonth < 3) endDate = DateTime.utc(nextStartUtc.year, 4, 1);
|
|
154
157
|
else if (startMonth < 6) endDate = DateTime.utc(nextStartUtc.year, 7, 1);
|
|
155
158
|
else if (startMonth < 9) endDate = DateTime.utc(nextStartUtc.year, 10, 1);
|
|
156
|
-
else endDate = DateTime.utc(nextStartUtc.year
|
|
159
|
+
else endDate = DateTime.utc(nextStartUtc.year + 1, 1, 1);
|
|
157
160
|
if (endDate > seriesEnd) endDate = seriesEnd;
|
|
158
161
|
return {
|
|
159
162
|
period: "quarterly",
|
|
@@ -203,7 +206,7 @@ const _nextDailyPeriod = (nextStart, seriesEnd) => {
|
|
|
203
206
|
};
|
|
204
207
|
const _nextHourlyPeriod = (nextStart, seriesEnd) => {
|
|
205
208
|
if (seriesEnd <= nextStart) return null;
|
|
206
|
-
let endDate = nextStart.toUTC().plus({ hours: 1 });
|
|
209
|
+
let endDate = nextStart.toUTC().plus({ hours: 1 }).startOf("hour");
|
|
207
210
|
if (endDate > seriesEnd) {
|
|
208
211
|
if (nextStart.hour !== seriesEnd.hour) endDate = seriesEnd.toUTC();
|
|
209
212
|
}
|
|
@@ -261,29 +264,30 @@ var AnalyticsDiscretizer = class AnalyticsDiscretizer {
|
|
|
261
264
|
return Object.values(result);
|
|
262
265
|
}
|
|
263
266
|
static _getPeriodString(p) {
|
|
267
|
+
const startUtc = p.start.toUTC();
|
|
264
268
|
switch (p.period) {
|
|
265
|
-
case "annual": return
|
|
266
|
-
case "semiAnnual": return `${
|
|
267
|
-
case "quarterly": return `${
|
|
269
|
+
case "annual": return startUtc.year.toString();
|
|
270
|
+
case "semiAnnual": return `${startUtc.year}/${startUtc.month < 7 ? "H1" : "H2"}`;
|
|
271
|
+
case "quarterly": return `${startUtc.year}/Q${getQuarter(startUtc)}`;
|
|
268
272
|
case "monthly":
|
|
269
|
-
const month =
|
|
273
|
+
const month = startUtc.month;
|
|
270
274
|
const formattedMonth = month < 10 ? `0${month}` : `${month}`;
|
|
271
|
-
return `${
|
|
272
|
-
case "weekly": return `${
|
|
275
|
+
return `${startUtc.year}/${formattedMonth}`;
|
|
276
|
+
case "weekly": return `${startUtc.weekYear}/W${startUtc.weekNumber}`;
|
|
273
277
|
case "daily":
|
|
274
|
-
const monthD =
|
|
275
|
-
const day =
|
|
278
|
+
const monthD = startUtc.month;
|
|
279
|
+
const day = startUtc.day;
|
|
276
280
|
const formattedMonthD = monthD < 10 ? `0${monthD}` : `${monthD}`;
|
|
277
281
|
const formattedDay = day < 10 ? `0${day}` : `${day}`;
|
|
278
|
-
return `${
|
|
282
|
+
return `${startUtc.year}/${formattedMonthD}/${formattedDay}`;
|
|
279
283
|
case "hourly":
|
|
280
|
-
const monthH =
|
|
281
|
-
const dayH =
|
|
282
|
-
const hourH =
|
|
284
|
+
const monthH = startUtc.month;
|
|
285
|
+
const dayH = startUtc.day;
|
|
286
|
+
const hourH = startUtc.hour;
|
|
283
287
|
const formattedMonthH = monthH < 10 ? `0${monthH}` : `${monthH}`;
|
|
284
288
|
const formattedDayH = dayH < 10 ? `0${dayH}` : `${dayH}`;
|
|
285
289
|
const formattedHourH = hourH < 10 ? `0${hourH}` : `${hourH}`;
|
|
286
|
-
return `${
|
|
290
|
+
return `${startUtc.year}/${formattedMonthH}/${formattedDayH}/${formattedHourH}`;
|
|
287
291
|
default: return p.period;
|
|
288
292
|
}
|
|
289
293
|
}
|
|
@@ -324,6 +328,7 @@ var AnalyticsDiscretizer = class AnalyticsDiscretizer {
|
|
|
324
328
|
}
|
|
325
329
|
static _discretizeSeries(series, periods) {
|
|
326
330
|
const result = {};
|
|
331
|
+
if (periods.length === 0) return result;
|
|
327
332
|
for (const s of series) {
|
|
328
333
|
let oldSum = this._getValue(s, periods[0].start);
|
|
329
334
|
for (const p of periods) {
|
|
@@ -349,13 +354,13 @@ var AnalyticsDiscretizer = class AnalyticsDiscretizer {
|
|
|
349
354
|
}
|
|
350
355
|
}
|
|
351
356
|
static _getSingleValue(series, when) {
|
|
352
|
-
return when
|
|
357
|
+
return when > series.start ? series.value : 0;
|
|
353
358
|
}
|
|
354
359
|
static _getVestValue(series, when) {
|
|
355
360
|
const now = when;
|
|
356
361
|
const start = series.start;
|
|
357
362
|
const end = series.end;
|
|
358
|
-
const cliff = series.params?.cliff ? DateTime.fromISO(series.params.cliff) : null;
|
|
363
|
+
const cliff = series.params?.cliff ? DateTime.fromISO(series.params.cliff, { zone: "utc" }) : null;
|
|
359
364
|
if (now < start || cliff && now < cliff) return 0;
|
|
360
365
|
else if (end && now >= end) return series.value;
|
|
361
366
|
const a = Interval.fromDateTimes(start, now);
|
|
@@ -405,6 +410,7 @@ var AnalyticsDiscretizer = class AnalyticsDiscretizer {
|
|
|
405
410
|
//#endregion
|
|
406
411
|
//#region src/AnalyticsQueryEngine.ts
|
|
407
412
|
var AnalyticsQueryEngine = class {
|
|
413
|
+
_analyticsStore;
|
|
408
414
|
_profiler;
|
|
409
415
|
constructor(_analyticsStore, profiler) {
|
|
410
416
|
this._analyticsStore = _analyticsStore;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/AnalyticsProfiler.ts","../src/AnalyticsTimeSlicer.ts","../src/AnalyticsDiscretizer.ts","../src/AnalyticsQueryEngine.ts","../src/AnalyticsSubscriptionManager.ts","../src/util.ts"],"sourcesContent":["export interface IAnalyticsProfiler {\n get prefix(): string;\n\n push: (system: string) => void;\n pop: () => void;\n popAndReturn: (result: any) => any;\n\n record: <T>(metric: string, fn: () => Promise<T>) => Promise<T>;\n recordSync: <T>(metric: string, fn: () => T) => T;\n}\n\nexport class AnalyticsProfiler implements IAnalyticsProfiler {\n private readonly _stack: string[] = [];\n private _prefix: string = \"\";\n\n constructor(\n private readonly _ns: string,\n private readonly _logger: (metricName: string, ms: number) => void,\n ) {\n this._prefix = _ns;\n }\n\n get prefix(): string {\n return this._prefix;\n }\n\n push(system: string): void {\n this._stack.push(system);\n\n this.updatePrefix();\n }\n\n pop(): void {\n if (this._stack.pop()) {\n this.updatePrefix();\n }\n }\n\n popAndReturn(result: any): any {\n this.pop();\n\n return result;\n }\n\n async record<T>(metric: string, fn: () => Promise<T>): Promise<T> {\n const start = performance.now();\n const fullMetric = `${this.prefix}.${metric}`;\n\n try {\n return await fn();\n } finally {\n this._logger(fullMetric, performance.now() - start);\n }\n }\n\n recordSync<T>(metric: string, fn: () => T): T {\n const start = performance.now();\n const fullMetric = `${this.prefix}.${metric}`;\n\n try {\n return fn();\n } finally {\n this._logger(fullMetric, performance.now() - start);\n }\n }\n\n updatePrefix(): void {\n if (this._stack.length > 0) {\n this._prefix = `${this._ns}.${this._stack.join(\".\")}`;\n } else {\n this._prefix = this._ns;\n }\n }\n}\n\nexport class PassthroughAnalyticsProfiler implements IAnalyticsProfiler {\n get prefix(): string {\n return \"\";\n }\n\n push(_system: string) {\n //\n }\n\n pop() {\n //\n }\n\n popAndReturn(result: any) {\n return result;\n }\n\n async record<T>(metric: string, fn: () => Promise<T>) {\n return await fn();\n }\n\n recordSync<T>(metric: string, fn: () => T) {\n return fn();\n }\n}\n","import { DateTime } from \"luxon\";\nimport { AnalyticsGranularity } from \"./AnalyticsQuery.js\";\n\nexport type AnalyticsRange = {\n start: DateTime;\n end: DateTime;\n granularity: AnalyticsGranularity;\n};\n\nexport type AnalyticsPeriod = {\n period: string;\n start: DateTime;\n end: DateTime;\n};\n\ninterface AnalyticsPeriodSeries {\n start: DateTime;\n end: DateTime;\n granularity: AnalyticsGranularity;\n next(): AnalyticsPeriod | null;\n}\n\nexport const getPeriodSeriesArray = (\n range: AnalyticsRange,\n): AnalyticsPeriod[] => {\n const result: AnalyticsPeriod[] = [];\n const series = getPeriodSeries(range);\n\n let next = series.next();\n while (next) {\n result.push(next);\n next = series.next();\n }\n\n return result;\n};\n\nexport const getPeriodSeries = (\n range: AnalyticsRange,\n): AnalyticsPeriodSeries => {\n return {\n ...range,\n next: _createFactoryFn(range),\n };\n};\n\nconst _createFactoryFn = (range: AnalyticsRange) => {\n let current: DateTime | null = range.start;\n\n return () => {\n if (current == null) {\n return null;\n }\n\n let result: AnalyticsPeriod | null = null;\n switch (range.granularity) {\n case AnalyticsGranularity.Total:\n result = _nextTotalPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Annual:\n result = _nextAnnualPeriod(current, range.end);\n break;\n case AnalyticsGranularity.SemiAnnual:\n result = _nextSemiAnnualPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Quarterly:\n result = _nextQuarterlyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Monthly:\n result = _nextMonthlyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Weekly:\n result = _nextWeeklyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Daily:\n result = _nextDailyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Hourly:\n result = _nextHourlyPeriod(current, range.end);\n }\n\n // Update current to start of next period\n if (result === null) {\n current = null;\n } else {\n current = result.end.plus({ milliseconds: 1 });\n }\n\n return result;\n };\n};\n\nconst _nextTotalPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n return {\n period: \"total\",\n start: nextStart,\n end: seriesEnd,\n };\n};\n\nexport const _nextAnnualPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n const inputUtc = nextStart.toUTC();\n const oneYearLater = DateTime.utc(\n inputUtc.year,\n inputUtc.month,\n inputUtc.day,\n ).plus({ years: 1 });\n\n return {\n period: \"annual\",\n start: nextStart,\n end: oneYearLater,\n };\n};\n\nexport const _nextSemiAnnualPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n const midYear = DateTime.utc(nextStart.year, 7, 1);\n const endYear = DateTime.utc(nextStart.year, 12, 31, 23, 59, 59, 999);\n\n let endDate: DateTime;\n if (midYear > nextStart) {\n endDate = midYear;\n } else {\n endDate = endYear;\n }\n\n if (endDate > seriesEnd) {\n endDate = seriesEnd;\n }\n\n return {\n period: \"semiAnnual\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextQuarterlyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n let endDate: DateTime;\n const nextStartUtc = nextStart.toUTC();\n const startMonth = nextStartUtc.month;\n\n if (startMonth < 3) {\n endDate = DateTime.utc(nextStartUtc.year, 4, 1);\n } else if (startMonth < 6) {\n endDate = DateTime.utc(nextStartUtc.year, 7, 1);\n } else if (startMonth < 9) {\n endDate = DateTime.utc(nextStartUtc.year, 10, 1);\n } else {\n endDate = DateTime.utc(nextStartUtc.year, 12, 31, 23, 59, 59, 999);\n }\n\n if (endDate > seriesEnd) {\n endDate = seriesEnd;\n }\n\n return {\n period: \"quarterly\",\n start: nextStart,\n end: endDate,\n };\n};\nexport const _nextMonthlyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Get the first day of the next month\n const nextStartUtc = nextStart.toUTC();\n let endDate = DateTime.utc(\n nextStartUtc.year,\n nextStartUtc.month,\n nextStartUtc.day,\n )\n .plus({ months: 1 })\n .startOf(\"month\");\n\n // If the end date is after the series end, then use the series end as the end date\n if (endDate > seriesEnd) {\n if (!nextStart.hasSame(seriesEnd, \"month\")) {\n endDate = seriesEnd;\n }\n }\n\n // Otherwise, return the end date as the first day of the next month\n return {\n period: \"monthly\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextWeeklyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Calculate the start of the next week (Monday)\n const nextStartUtc = nextStart.toUTC();\n const nextWeekStartUTC = DateTime.utc(\n nextStartUtc.year,\n nextStartUtc.month,\n nextStartUtc.day,\n )\n .plus({ weeks: 1 })\n .startOf(\"week\");\n\n // If the calculated next week start is later or equal to the series end date, return the series end\n if (nextWeekStartUTC > seriesEnd)\n if (!nextWeekStartUTC.hasSame(seriesEnd, \"day\")) {\n return {\n period: \"weekly\",\n start: nextStart,\n end: seriesEnd,\n };\n }\n\n return {\n period: \"weekly\",\n start: nextStart,\n end: nextWeekStartUTC,\n };\n};\n\nexport const _nextDailyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Set the end date to the start of the next day\n const nextStartUtc = nextStart.toUTC();\n let endDate = nextStartUtc.plus({ days: 1 }).startOf(\"day\");\n if (endDate > seriesEnd || endDate.hasSame(seriesEnd, \"day\")) {\n endDate = seriesEnd;\n }\n\n return {\n period: \"daily\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextHourlyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n const startDate = nextStart.toUTC();\n let endDate = startDate.plus({ hours: 1 });\n\n if (endDate > seriesEnd) {\n if (nextStart.hour !== seriesEnd.hour) {\n endDate = seriesEnd.toUTC();\n }\n }\n\n return {\n period: \"hourly\",\n start: nextStart,\n end: endDate,\n };\n};\n","/* eslint-disable @typescript-eslint/no-redundant-type-constituents */\n/* eslint-disable no-case-declarations */\nimport { DateTime, Interval } from \"luxon\";\nimport type { AnalyticsGranularity } from \"./AnalyticsQuery.js\";\nimport {\n type AnalyticsDimension,\n type AnalyticsSeries,\n} from \"./AnalyticsQuery.js\";\nimport {\n type AnalyticsPeriod,\n type AnalyticsRange,\n getPeriodSeriesArray,\n} from \"./AnalyticsTimeSlicer.js\";\n\nexport const getQuarter = (date: DateTime) => {\n return Math.floor((date.month - 1) / 3) + 1;\n};\n\nexport type GroupedPeriodResult = {\n period: string;\n start: DateTime;\n end: DateTime;\n rows: Array<{\n dimensions: Record<string, AnalyticsDimension>;\n metric: string;\n unit: string | null;\n value: number;\n\n /**\n * The sum of all metric values over this period?\n */\n sum: number;\n }>;\n};\n\nexport type GroupedPeriodResults = Array<GroupedPeriodResult>;\n\nexport class AnalyticsDiscretizer {\n public static discretize(\n series: AnalyticsSeries<string>[],\n dimensions: string[],\n start: DateTime | null,\n end: DateTime | null,\n granularity: AnalyticsGranularity,\n ): GroupedPeriodResults {\n const index = this._buildIndex(series, dimensions);\n const periods = getPeriodSeriesArray(\n this._calculateRange(start, end, granularity, series),\n );\n const disretizedResults = this._discretizeNode(\n index,\n {},\n dimensions,\n periods,\n );\n const groupedResults = this._groupResultsByPeriod(\n periods,\n disretizedResults,\n );\n\n return groupedResults;\n }\n\n private static _calculateRange(\n start: DateTime | null,\n end: DateTime | null,\n granularity: AnalyticsGranularity,\n results: AnalyticsSeries<any>[],\n ) {\n let calculatedStart: DateTime | null = start || null;\n let calculatedEnd: DateTime | null = end || null;\n\n if (calculatedStart == null || calculatedEnd == null) {\n for (const r of results) {\n if (calculatedStart == null) {\n calculatedStart = r.start;\n }\n\n const endValue = r.end || r.start;\n if (calculatedEnd == null || calculatedEnd < endValue) {\n calculatedEnd = endValue;\n }\n }\n }\n\n if (calculatedStart == null || calculatedEnd == null) {\n throw new Error(\"Cannot determine query start and/or end.\");\n }\n\n return {\n start: calculatedStart,\n end: calculatedEnd,\n granularity,\n } as AnalyticsRange;\n }\n\n public static _groupResultsByPeriod(\n periods: AnalyticsPeriod[],\n dimensionedResults: DimensionedSeries[],\n ): GroupedPeriodResults {\n const result: Record<string, GroupedPeriodResult> = {};\n\n for (const p of periods) {\n const id = p.start.toISO() + \"-\" + p.period;\n const period = AnalyticsDiscretizer._getPeriodString(p);\n result[id] = {\n period: period,\n start: p.start,\n end: p.end,\n rows: [],\n };\n }\n\n for (const r of dimensionedResults) {\n for (const period of Object.keys(r.series)) {\n result[period].rows.push({\n dimensions: r.dimensions,\n metric: r.metric,\n unit: r.unit == \"__NULL__\" ? null : r.unit,\n value: r.series[period].inc,\n sum: r.series[period].sum,\n });\n }\n }\n\n return Object.values(result);\n }\n\n static _getPeriodString(p: AnalyticsPeriod) {\n switch (p.period) {\n case \"annual\":\n return p.start.year.toString();\n case \"semiAnnual\":\n return `${p.start.year}/${p.start.month < 7 ? \"H1\" : \"H2\"}`;\n case \"quarterly\":\n return `${p.start.year}/Q${getQuarter(p.start)}`;\n case \"monthly\":\n const month = p.start.toUTC().month;\n const formattedMonth = month < 10 ? `0${month}` : `${month}`;\n return `${p.start.year}/${formattedMonth}`;\n case \"weekly\":\n return `${p.start.weekYear}/W${p.start.weekNumber}`;\n case \"daily\":\n const monthD = p.start.month;\n const day = p.start.day;\n const formattedMonthD = monthD < 10 ? `0${monthD}` : `${monthD}`;\n const formattedDay = day < 10 ? `0${day}` : `${day}`;\n return `${p.start.year}/${formattedMonthD}/${formattedDay}`;\n case \"hourly\":\n const monthH = p.start.month;\n const dayH = p.start.day;\n const hourH = p.start.hour;\n const formattedMonthH = monthH < 10 ? `0${monthH}` : `${monthH}`;\n const formattedDayH = dayH < 10 ? `0${dayH}` : `${dayH}`;\n const formattedHourH = hourH < 10 ? `0${hourH}` : `${hourH}`;\n return `${p.start.year}/${formattedMonthH}/${formattedDayH}/${formattedHourH}`;\n default:\n return p.period;\n }\n }\n\n public static _discretizeNode(\n node: DiscretizerIndexNode,\n dimensionValues: Record<string, string>,\n remainingDimensions: string[],\n periods: AnalyticsPeriod[],\n ): DimensionedSeries[] {\n const result: DimensionedSeries[] = [];\n\n if (remainingDimensions.length > 0) {\n const subdimension = remainingDimensions[0] as string;\n Object.keys(node).forEach((subdimensionValue, _index, _arr) => {\n const newDimensionValues = { ...dimensionValues };\n newDimensionValues[subdimension] = subdimensionValue;\n result.push(\n ...this._discretizeNode(\n node[subdimensionValue] as DiscretizerIndexNode,\n newDimensionValues,\n remainingDimensions.slice(1),\n periods,\n ),\n );\n });\n } else {\n Object.keys(node).forEach((metric) => {\n result.push(\n ...this._discretizeLeaf(\n node[metric] as DiscretizerIndexLeaf,\n periods,\n metric,\n dimensionValues,\n ),\n );\n });\n }\n\n return result;\n }\n\n public static _discretizeLeaf(\n leaf: DiscretizerIndexLeaf,\n periods: AnalyticsPeriod[],\n metric: string,\n dimensionValues: Record<string, string>,\n ): DimensionedSeries[] {\n const result: DimensionedSeries[] = [];\n Object.keys(leaf).forEach((unit) => {\n const metaDimensions: any = {};\n Object.keys(dimensionValues).forEach((k) => {\n metaDimensions[k] = {\n path: leaf[unit][0].dimensions[k],\n icon: leaf[unit][0].dimensions.icon,\n label: leaf[unit][0].dimensions.label,\n description: leaf[unit][0].dimensions.description,\n };\n });\n result.push({\n unit,\n metric,\n dimensions: metaDimensions as any,\n series: this._discretizeSeries(leaf[unit], periods),\n });\n });\n\n return result;\n }\n\n public static _discretizeSeries(\n series: AnalyticsSeries<string>[],\n periods: AnalyticsPeriod[],\n ): Series {\n const result: Series = {};\n\n for (const s of series) {\n let oldSum = this._getValue(s, periods[0].start);\n for (const p of periods) {\n const newSum = this._getValue(s, p.end);\n const id = `${p.start.toISO()}-${p.period}`;\n\n // const id = p.period;\n if (result[id]) {\n result[id].inc += newSum - oldSum;\n result[id].sum += newSum;\n } else {\n result[id] = {\n inc: newSum - oldSum,\n sum: newSum,\n };\n }\n\n oldSum = newSum;\n }\n }\n\n return result;\n }\n\n public static _getValue(\n series: AnalyticsSeries<string>,\n when: DateTime,\n ): number {\n switch (series.fn) {\n case \"Single\":\n return this._getSingleValue(series, when);\n case \"DssVest\":\n return this._getVestValue(series, when);\n default:\n // todo: logging interface\n //console.error(`Unknown analytics series function: '${series.fn}'`);\n return 0.0;\n }\n }\n\n public static _getSingleValue(\n series: AnalyticsSeries<string>,\n when: DateTime,\n ): number {\n return when >= series.start ? series.value : 0.0;\n }\n\n public static _getVestValue(\n series: AnalyticsSeries<string>,\n when: DateTime,\n ): number {\n const now = when;\n const start = series.start;\n const end = series.end;\n\n const cliff = series.params?.cliff\n ? DateTime.fromISO(series.params.cliff! as string)\n : null;\n if (now < start || (cliff && now < cliff)) {\n return 0.0;\n } else if (end && now >= end) {\n return series.value;\n }\n\n const a = Interval.fromDateTimes(start, now);\n const b = Interval.fromDateTimes(start, end || now);\n\n return (a.length() / b.length()) * series.value;\n }\n\n public static _buildIndex(\n series: AnalyticsSeries<string>[],\n dimensions: string[],\n ): DiscretizerIndexNode {\n const result: DiscretizerIndexNode | any = {};\n const map: DiscretizerIndexLeaf = {};\n const dimName = dimensions[0] || \"\";\n\n for (const s of series) {\n const dimValue = s.dimensions[dimName];\n if (undefined === map[dimValue]) {\n map[dimValue] = [];\n }\n map[dimValue].push(s);\n }\n\n if (dimensions.length > 1) {\n const newDimensions = dimensions.slice(1);\n Object.keys(map).forEach((k) => {\n result[k] = this._buildIndex(map[k], newDimensions);\n });\n } else {\n Object.keys(map).forEach((k) => {\n result[k] = this._buildMetricsIndex(map[k]);\n });\n }\n\n return result;\n }\n\n public static _buildMetricsIndex(\n series: AnalyticsSeries<string>[],\n ): DiscretizerIndexNode {\n const result: DiscretizerIndexNode = {};\n\n const map: DiscretizerIndexLeaf = {};\n for (const s of series) {\n const metric = s.metric;\n if (undefined === map[metric]) {\n map[metric] = [];\n }\n\n map[metric].push(s);\n }\n\n Object.keys(map).forEach((k) => (result[k] = this._buildUnitIndex(map[k])));\n return result;\n }\n\n public static _buildUnitIndex(\n series: AnalyticsSeries<string>[],\n ): DiscretizerIndexLeaf {\n const result: DiscretizerIndexLeaf = {};\n\n for (const s of series) {\n const unit = s.unit || \"__NULL__\";\n if (undefined === result[unit]) {\n result[unit] = [];\n }\n\n result[unit].push(s);\n }\n\n return result;\n }\n}\n\ntype DiscretizerIndexLeaf = { [k: string]: AnalyticsSeries<string>[] };\ntype DiscretizerIndexNode = {\n [k: string]: DiscretizerIndexNode | DiscretizerIndexLeaf;\n};\ntype Series = Record<\n string,\n {\n /**\n * How much the metric increased from the beginning of the series to the end of the specified period.\n */\n inc: number;\n\n /**\n * The sum of all metric values from the beginning of the series to the end of the specified period.\n */\n sum: number;\n }\n>;\ntype DimensionedSeries = {\n unit: string;\n metric: string;\n dimensions: Record<string, AnalyticsDimension>;\n series: Series;\n};\n","/* eslint-disable @typescript-eslint/no-redundant-type-constituents */\nimport {\n AnalyticsDiscretizer,\n type GroupedPeriodResults,\n type GroupedPeriodResult,\n} from \"./AnalyticsDiscretizer.js\";\nimport { AnalyticsPath } from \"./AnalyticsPath.js\";\nimport {\n type IAnalyticsProfiler,\n PassthroughAnalyticsProfiler,\n} from \"./AnalyticsProfiler.js\";\nimport {\n type AnalyticsQuery,\n type AnalyticsSeries,\n type AnalyticsSeriesQuery,\n type CompoundAnalyticsQuery,\n type MultiCurrencyConversion,\n CompoundOperator,\n} from \"./AnalyticsQuery.js\";\nimport { type IAnalyticsStore } from \"./IAnalyticsStore.js\";\n\nexport class AnalyticsQueryEngine {\n private readonly _profiler: IAnalyticsProfiler;\n\n public constructor(\n private readonly _analyticsStore: IAnalyticsStore,\n profiler?: IAnalyticsProfiler,\n ) {\n this._profiler = profiler ?? new PassthroughAnalyticsProfiler();\n }\n\n public async executeCompound(\n query: CompoundAnalyticsQuery,\n ): Promise<GroupedPeriodResults> {\n let result: GroupedPeriodResults;\n\n const inputsQuery: AnalyticsQuery = {\n start: query.start,\n end: query.end,\n granularity: query.granularity,\n lod: query.lod,\n select: query.select,\n metrics: query.expression.inputs.metrics,\n currency: query.expression.inputs.currency,\n };\n\n const operandQuery: AnalyticsQuery = {\n start: query.start,\n end: query.end,\n granularity: query.granularity,\n lod: { priceData: 1 },\n select: { priceData: [AnalyticsPath.fromString(\"atlas\")] },\n metrics: [query.expression.operand.metric],\n currency: query.expression.operand.currency,\n };\n\n const inputExecute = await this.execute(inputsQuery);\n const operandExecute = await this.execute(operandQuery);\n\n if (\n [CompoundOperator.VectorAdd, CompoundOperator.VectorSubtract].includes(\n query.expression.operator,\n )\n ) {\n result = await this._profiler.record(\n \"ApplyVectorOperator\",\n async () =>\n await this._applyVectorOperator(\n inputExecute,\n operandExecute,\n query.expression.operator,\n query.expression.resultCurrency,\n ),\n );\n } else {\n result = await this._profiler.record(\n \"ApplyScalarOperator\",\n async () =>\n await this._applyScalarOperator(\n inputExecute,\n operandExecute,\n query.expression.operator,\n query.expression.operand.useSum,\n query.expression.resultCurrency,\n ),\n );\n }\n\n return result;\n }\n\n public async execute(query: AnalyticsQuery): Promise<GroupedPeriodResults> {\n const seriesResults = await this._executeSeriesQuery(query);\n\n const normalizedSeriesResults = this._profiler.recordSync(\"ApplyLODs\", () =>\n this._applyLods(seriesResults, query.lod),\n );\n\n const dimensions = Object.keys(query.select);\n const discretizedResult = this._profiler.recordSync(\"Discretize\", () =>\n normalizedSeriesResults.length < 1\n ? []\n : AnalyticsDiscretizer.discretize(\n normalizedSeriesResults,\n dimensions,\n query.start,\n query.end,\n query.granularity,\n ),\n );\n return discretizedResult;\n }\n\n public async executeMultiCurrency(\n query: AnalyticsQuery,\n mcc: MultiCurrencyConversion,\n ): Promise<GroupedPeriodResults> {\n const baseQuery: AnalyticsQuery = {\n ...query,\n currency: mcc.targetCurrency ?? query.currency,\n };\n let result = await this.execute(baseQuery);\n\n for (const conversion of mcc.conversions) {\n const nextQuery: CompoundAnalyticsQuery = {\n start: query.start,\n end: query.end,\n granularity: query.granularity,\n lod: query.lod,\n select: query.select,\n expression: {\n inputs: {\n metrics: baseQuery.metrics,\n currency: conversion.currency,\n },\n operator: CompoundOperator.ScalarMultiply,\n operand: {\n metric: conversion.metric,\n currency: mcc.targetCurrency,\n useSum: true,\n },\n resultCurrency: mcc.targetCurrency,\n },\n };\n\n const executedCompound = await this.executeCompound(nextQuery);\n result = await this._applyVectorOperator(\n result,\n executedCompound,\n CompoundOperator.VectorAdd,\n mcc.targetCurrency,\n );\n }\n return result;\n }\n\n private _applyVectorOperator(\n inputsA: GroupedPeriodResults,\n inputsB: GroupedPeriodResults,\n operator: CompoundOperator,\n _resultCurrency?: AnalyticsPath,\n ): Promise<GroupedPeriodResults> {\n if (\n [CompoundOperator.ScalarMultiply, CompoundOperator.ScalarDivide].includes(\n operator,\n )\n ) {\n throw new Error(\"Invalid operator for vector operation\");\n }\n return Promise.resolve(inputsB);\n }\n\n private _applyScalarOperator(\n inputs: GroupedPeriodResults, // expected input is the budget & actuals in 2022 monthly granularity in MKR\n operand: GroupedPeriodResults, // expected input is the daily mkr price change in 2022 monthly granularity in DAI\n operator: CompoundOperator, // expected to me multiply and later addition\n useOperandSum: boolean,\n resultCurrency?: AnalyticsPath, // expected to be DAI\n ): Promise<GroupedPeriodResults> {\n if (\n [CompoundOperator.VectorAdd, CompoundOperator.VectorSubtract].includes(\n operator,\n )\n ) {\n throw new Error(\"Invalid operator for scalar operation\");\n }\n\n const result: GroupedPeriodResults = [];\n const operandMap: Record<string, number> = {};\n const key = useOperandSum ? \"sum\" : \"value\";\n\n for (const operandPeriod of operand) {\n if (operandPeriod.rows.length > 0) {\n operandMap[operandPeriod.period] = operandPeriod.rows[0][key];\n }\n }\n\n // let previousValue: number = 1;\n for (const inputPeriod of inputs) {\n const outputPeriod: GroupedPeriodResult = {\n period: inputPeriod.period,\n start: inputPeriod.start,\n end: inputPeriod.end,\n rows: inputPeriod.rows.map((row) => {\n const newRow = {\n dimensions: row.dimensions,\n metric: row.metric,\n unit: resultCurrency ? resultCurrency.toString() : row.unit,\n value: this._calculateOutputValue(\n row.value,\n operator,\n operandMap[inputPeriod.period],\n ),\n sum: -1,\n };\n return newRow;\n }),\n };\n result.push(outputPeriod);\n }\n\n return Promise.resolve(result);\n }\n\n private _calculateOutputValue(\n input: number,\n operator: CompoundOperator,\n operand: number,\n ): number {\n switch (operator) {\n case CompoundOperator.VectorAdd:\n return input + operand;\n case CompoundOperator.VectorSubtract:\n return input - operand;\n case CompoundOperator.ScalarMultiply:\n return input * operand;\n case CompoundOperator.ScalarDivide:\n return input / operand;\n }\n }\n\n private async _executeSeriesQuery(\n query: AnalyticsQuery,\n ): Promise<AnalyticsSeries[]> {\n const seriesQuery: AnalyticsSeriesQuery = {\n start: query.start,\n end: query.end,\n select: query.select,\n metrics: query.metrics,\n currency: query.currency,\n };\n\n return await this._analyticsStore.getMatchingSeries(seriesQuery);\n }\n\n private _applyLods(\n series: AnalyticsSeries[],\n lods: Record<string, number | null>,\n ): AnalyticsSeries<string>[] {\n return series.map((result) => ({\n ...result,\n dimensions: this._applyDimensionsLods(result.dimensions, lods),\n }));\n }\n\n private _applyDimensionsLods(\n dimensionMap: Record<string, AnalyticsPath> | any,\n lods: Record<string, number | null>,\n ) {\n const result: Record<string, string> | any = {};\n for (const [dimension, lod] of Object.entries(lods)) {\n if (lod !== null && dimensionMap[dimension]) {\n result[dimension] = dimensionMap[dimension][\"path\"]\n .applyLod(lod)\n .toString();\n result[\"icon\"] = dimensionMap[dimension][\"icon\"].toString();\n result[\"label\"] = dimensionMap[dimension][\"label\"].toString();\n result[\"description\"] =\n dimensionMap[dimension][\"description\"].toString();\n }\n }\n return result;\n }\n\n public async getDimensions(): Promise<any> {\n return await this._analyticsStore.getDimensions();\n }\n\n /*public async getMetrics(): Promise<string[]> {\n return await this._analyticsStore.getMetrics();\n }\n\n public async getCurrencies(): Promise<string[]> {\n return await this._analyticsStore.getCurrencies();\n }*/\n}\n","import type { AnalyticsPath } from \"./AnalyticsPath.js\";\nimport type { AnalyticsUpdateCallback } from \"./IAnalyticsStore.js\";\n\nexport class NotificationError extends Error {\n public readonly innerErrors: Error[];\n\n constructor(errors: Error[]) {\n super(errors.map((e) => e.message).join(\"\\n\"));\n\n this.name = \"NotificationError\";\n this.innerErrors = errors;\n }\n}\n\n/**\n * Manages subscriptions for analytics paths.\n */\nexport class AnalyticsSubscriptionManager {\n private _subscriptions: Map<string, Set<AnalyticsUpdateCallback>> = new Map();\n\n /**\n * Subscribe to updates for an analytics path. A subscribed function will be\n * called for:\n *\n * - exact path matches\n * - matching child paths (i.e. an update to /a/b/c will trigger a callback\n * for /a/b/c, /a/b, and /a)\n * - wildcard matches\n *\n * @param path The analytics path to subscribe to.\n * @param callback Function to be called when the path is updated.\n *\n * @returns A function that, when called, unsubscribes from the updates.\n */\n public subscribeToPath(\n path: AnalyticsPath,\n callback: AnalyticsUpdateCallback,\n ): () => void {\n const pathString = this.normalizePath(path.toString(\"/\"));\n\n if (!this._subscriptions.has(pathString)) {\n this._subscriptions.set(pathString, new Set());\n }\n\n this._subscriptions.get(pathString)!.add(callback);\n\n return () => {\n const callbacks = this._subscriptions.get(pathString);\n if (callbacks) {\n callbacks.delete(callback);\n\n // only remove the path entry if there are no more callbacks\n if (callbacks.size === 0) {\n this._subscriptions.delete(pathString);\n }\n }\n };\n }\n\n /**\n * Notifies subscribers about updates to paths.\n *\n * @param paths The paths that were updated.\n */\n public notifySubscribers(paths: AnalyticsPath[]): void {\n if (paths.length === 0 || this._subscriptions.size === 0) {\n return;\n }\n\n const errors: Error[] = [];\n for (const path of paths) {\n const pathString = this.normalizePath(path.toString(\"/\"));\n const pathPrefixes = this.getPathPrefixes(pathString);\n\n const matchingSubscriptions: Array<{\n prefix: string;\n callbacks: Set<AnalyticsUpdateCallback>;\n }> = [];\n\n // add the exact prefix matches\n pathPrefixes\n .filter((prefix) => this._subscriptions.has(prefix))\n .forEach((prefix) => {\n matchingSubscriptions.push({\n prefix,\n callbacks: this._subscriptions.get(prefix)!,\n });\n });\n\n // check all wildcard patterns\n for (const [\n subscriptionPath,\n callbacks,\n ] of this._subscriptions.entries()) {\n // skip if it's already in the exact matches\n if (pathPrefixes.includes(subscriptionPath)) {\n continue;\n }\n\n // hceck if this subscription path (which might have wildcards) matches the update path\n if (this.pathMatchesWildcardPattern(pathString, subscriptionPath)) {\n matchingSubscriptions.push({\n prefix: subscriptionPath,\n callbacks,\n });\n }\n }\n\n if (matchingSubscriptions.length === 0) continue;\n\n // guarantee delivery to all subscribers\n for (const { callbacks } of matchingSubscriptions) {\n for (const callback of callbacks) {\n try {\n callback(path);\n } catch (e) {\n errors.push(e as Error);\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new NotificationError(errors);\n }\n }\n\n /**\n * Normalizes a path string to ensure consistent comparison.\n */\n private normalizePath(path: string): string {\n // Handle potential double slashes by first splitting on slashes and rejoining\n const parts = path.split(\"/\").filter((p) => p.length > 0);\n const normalized = \"/\" + parts.join(\"/\");\n return normalized;\n }\n\n /**\n * Checks if a path matches a subscription pattern that may contain wildcards.\n */\n private pathMatchesWildcardPattern(\n updatePath: string,\n subscriptionPath: string,\n ): boolean {\n // Handle the wildcard segment case\n if (subscriptionPath.includes(\"*\")) {\n const updateSegments = updatePath.split(\"/\").filter((s) => s.length > 0);\n const subscriptionSegments = subscriptionPath\n .split(\"/\")\n .filter((s) => s.length > 0);\n\n // If subscription is longer than the update path, it can't match\n if (subscriptionSegments.length > updateSegments.length) {\n return false;\n }\n\n // Compare each segment\n for (let i = 0; i < subscriptionSegments.length; i++) {\n const subSegment = subscriptionSegments[i];\n const updateSegment = updateSegments[i];\n\n // If segment is * or starts with * (wildcard), it matches anything\n if (subSegment === \"*\" || subSegment.startsWith(\"*:\")) {\n continue;\n }\n\n // Otherwise, segments should match exactly\n if (subSegment !== updateSegment) {\n return false;\n }\n }\n\n return true;\n }\n\n // If no wildcards, check if subscription is a prefix of the update path\n return (\n updatePath === subscriptionPath ||\n updatePath.startsWith(subscriptionPath + \"/\")\n );\n }\n\n /**\n * Gets all path prefixes for a given path.\n *\n * For example, for '/a/b/c' it returns ['/a', '/a/b', '/a/b/c'].\n */\n private getPathPrefixes(path: string): string[] {\n const segments = path.split(\"/\").filter((s) => s.length > 0);\n const prefixes: string[] = [];\n\n let currentPath = \"\";\n for (const segment of segments) {\n currentPath = currentPath ? `${currentPath}/${segment}` : `/${segment}`;\n prefixes.push(currentPath);\n }\n\n if (prefixes.length === 0 && path === \"/\") {\n prefixes.push(\"/\");\n }\n\n return prefixes;\n }\n}\n","import type { SqlQueryLogger, SqlResultsLogger } from \"./types.js\";\n\nexport const defaultQueryLogger =\n (tag: string): SqlQueryLogger =>\n (index: number, query: string) => {\n console.log(`[${tag}][Q:${index}]: ${query}\\n`);\n };\n\nexport const defaultResultsLogger =\n (tag: string): SqlResultsLogger =>\n (index: number, results: any) => {\n if (Array.isArray(results)) {\n console.log(`[${tag}][R:${index}]: ${results.length} results\\n`);\n } else {\n console.log(`[${tag}][R:${index}]: Received ${typeof results}.\\n`);\n }\n };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/AnalyticsProfiler.ts","../src/AnalyticsTimeSlicer.ts","../src/AnalyticsDiscretizer.ts","../src/AnalyticsQueryEngine.ts","../src/AnalyticsSubscriptionManager.ts","../src/util.ts"],"sourcesContent":["export interface IAnalyticsProfiler {\n get prefix(): string;\n\n push: (system: string) => void;\n pop: () => void;\n popAndReturn: (result: any) => any;\n\n record: <T>(metric: string, fn: () => Promise<T>) => Promise<T>;\n recordSync: <T>(metric: string, fn: () => T) => T;\n}\n\nexport class AnalyticsProfiler implements IAnalyticsProfiler {\n private readonly _stack: string[] = [];\n private _prefix: string = \"\";\n\n constructor(\n private readonly _ns: string,\n private readonly _logger: (metricName: string, ms: number) => void,\n ) {\n this._prefix = _ns;\n }\n\n get prefix(): string {\n return this._prefix;\n }\n\n push(system: string): void {\n this._stack.push(system);\n\n this.updatePrefix();\n }\n\n pop(): void {\n if (this._stack.pop()) {\n this.updatePrefix();\n }\n }\n\n popAndReturn(result: any): any {\n this.pop();\n\n return result;\n }\n\n async record<T>(metric: string, fn: () => Promise<T>): Promise<T> {\n const start = performance.now();\n const fullMetric = `${this.prefix}.${metric}`;\n\n try {\n return await fn();\n } finally {\n this._logger(fullMetric, performance.now() - start);\n }\n }\n\n recordSync<T>(metric: string, fn: () => T): T {\n const start = performance.now();\n const fullMetric = `${this.prefix}.${metric}`;\n\n try {\n return fn();\n } finally {\n this._logger(fullMetric, performance.now() - start);\n }\n }\n\n updatePrefix(): void {\n if (this._stack.length > 0) {\n this._prefix = `${this._ns}.${this._stack.join(\".\")}`;\n } else {\n this._prefix = this._ns;\n }\n }\n}\n\nexport class PassthroughAnalyticsProfiler implements IAnalyticsProfiler {\n get prefix(): string {\n return \"\";\n }\n\n push(_system: string) {\n //\n }\n\n pop() {\n //\n }\n\n popAndReturn(result: any) {\n return result;\n }\n\n async record<T>(metric: string, fn: () => Promise<T>) {\n return await fn();\n }\n\n recordSync<T>(metric: string, fn: () => T) {\n return fn();\n }\n}\n","import { DateTime } from \"luxon\";\nimport { AnalyticsGranularity } from \"./AnalyticsQuery.js\";\n\n// Boundary convention: periods are half-open intervals [start, end), where\n// each period's end is exactly the next period's start. Calendar-aligned\n// granularities anchor to the UTC calendar (ISO 8601): a period boundary sits\n// at T00:00:00.000Z of the first day of the calendar year / half-year /\n// quarter / month / ISO week / day / hour. The first period of a series may\n// be partial (it starts at the query start); subsequent periods start on the\n// calendar boundary. An instant exactly at a boundary belongs to the period\n// that starts there (see AnalyticsDiscretizer._getSingleValue).\n\nexport type AnalyticsRange = {\n start: DateTime;\n end: DateTime;\n granularity: AnalyticsGranularity;\n};\n\nexport type AnalyticsPeriod = {\n period: string;\n start: DateTime;\n end: DateTime;\n};\n\ninterface AnalyticsPeriodSeries {\n start: DateTime;\n end: DateTime;\n granularity: AnalyticsGranularity;\n next(): AnalyticsPeriod | null;\n}\n\nexport const getPeriodSeriesArray = (\n range: AnalyticsRange,\n): AnalyticsPeriod[] => {\n const result: AnalyticsPeriod[] = [];\n const series = getPeriodSeries(range);\n\n let next = series.next();\n while (next) {\n result.push(next);\n next = series.next();\n }\n\n return result;\n};\n\nexport const getPeriodSeries = (\n range: AnalyticsRange,\n): AnalyticsPeriodSeries => {\n return {\n ...range,\n next: _createFactoryFn(range),\n };\n};\n\nconst _createFactoryFn = (range: AnalyticsRange) => {\n let current: DateTime | null = range.start;\n\n return () => {\n if (current == null) {\n return null;\n }\n\n let result: AnalyticsPeriod | null = null;\n switch (range.granularity) {\n case AnalyticsGranularity.Total:\n result = _nextTotalPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Annual:\n result = _nextAnnualPeriod(current, range.end);\n break;\n case AnalyticsGranularity.SemiAnnual:\n result = _nextSemiAnnualPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Quarterly:\n result = _nextQuarterlyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Monthly:\n result = _nextMonthlyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Weekly:\n result = _nextWeeklyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Daily:\n result = _nextDailyPeriod(current, range.end);\n break;\n case AnalyticsGranularity.Hourly:\n result = _nextHourlyPeriod(current, range.end);\n }\n\n // Update current to start of next period. Periods are half-open\n // [start, end), so the next period starts exactly at this period's end.\n if (result === null) {\n current = null;\n } else {\n current = result.end;\n }\n\n return result;\n };\n};\n\nconst _nextTotalPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n return {\n period: \"total\",\n start: nextStart,\n end: seriesEnd,\n };\n};\n\nexport const _nextAnnualPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Anchor to the UTC calendar year, like the other granularities: the\n // period ends at January 1st of the following year, so the first period\n // may be partial and every later period spans a full calendar year.\n const inputUtc = nextStart.toUTC();\n const endDate = DateTime.utc(inputUtc.year + 1, 1, 1);\n\n return {\n period: \"annual\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextSemiAnnualPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n const inputUtc = nextStart.toUTC();\n const midYear = DateTime.utc(inputUtc.year, 7, 1);\n const endYear = DateTime.utc(inputUtc.year + 1, 1, 1);\n\n let endDate: DateTime;\n if (midYear > nextStart) {\n endDate = midYear;\n } else {\n endDate = endYear;\n }\n\n if (endDate > seriesEnd) {\n endDate = seriesEnd;\n }\n\n return {\n period: \"semiAnnual\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextQuarterlyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n let endDate: DateTime;\n const nextStartUtc = nextStart.toUTC();\n const startMonth = nextStartUtc.month;\n\n if (startMonth < 3) {\n endDate = DateTime.utc(nextStartUtc.year, 4, 1);\n } else if (startMonth < 6) {\n endDate = DateTime.utc(nextStartUtc.year, 7, 1);\n } else if (startMonth < 9) {\n endDate = DateTime.utc(nextStartUtc.year, 10, 1);\n } else {\n endDate = DateTime.utc(nextStartUtc.year + 1, 1, 1);\n }\n\n if (endDate > seriesEnd) {\n endDate = seriesEnd;\n }\n\n return {\n period: \"quarterly\",\n start: nextStart,\n end: endDate,\n };\n};\nexport const _nextMonthlyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Get the first day of the next month\n const nextStartUtc = nextStart.toUTC();\n let endDate = DateTime.utc(\n nextStartUtc.year,\n nextStartUtc.month,\n nextStartUtc.day,\n )\n .plus({ months: 1 })\n .startOf(\"month\");\n\n // If the end date is after the series end, then use the series end as the end date\n if (endDate > seriesEnd) {\n if (!nextStart.hasSame(seriesEnd, \"month\")) {\n endDate = seriesEnd;\n }\n }\n\n // Otherwise, return the end date as the first day of the next month\n return {\n period: \"monthly\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextWeeklyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Calculate the start of the next week (Monday)\n const nextStartUtc = nextStart.toUTC();\n const nextWeekStartUTC = DateTime.utc(\n nextStartUtc.year,\n nextStartUtc.month,\n nextStartUtc.day,\n )\n .plus({ weeks: 1 })\n .startOf(\"week\");\n\n // If the calculated next week start is later or equal to the series end date, return the series end\n if (nextWeekStartUTC > seriesEnd)\n if (!nextWeekStartUTC.hasSame(seriesEnd, \"day\")) {\n return {\n period: \"weekly\",\n start: nextStart,\n end: seriesEnd,\n };\n }\n\n return {\n period: \"weekly\",\n start: nextStart,\n end: nextWeekStartUTC,\n };\n};\n\nexport const _nextDailyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Set the end date to the start of the next day\n const nextStartUtc = nextStart.toUTC();\n let endDate = nextStartUtc.plus({ days: 1 }).startOf(\"day\");\n if (endDate > seriesEnd || endDate.hasSame(seriesEnd, \"day\")) {\n endDate = seriesEnd;\n }\n\n return {\n period: \"daily\",\n start: nextStart,\n end: endDate,\n };\n};\n\nexport const _nextHourlyPeriod = (\n nextStart: DateTime,\n seriesEnd: DateTime,\n): AnalyticsPeriod | null => {\n if (seriesEnd <= nextStart) {\n return null;\n }\n\n // Anchor to the top of the hour: the first period may be partial, every\n // later period covers a full clock hour.\n const startDate = nextStart.toUTC();\n let endDate = startDate.plus({ hours: 1 }).startOf(\"hour\");\n\n if (endDate > seriesEnd) {\n if (nextStart.hour !== seriesEnd.hour) {\n endDate = seriesEnd.toUTC();\n }\n }\n\n return {\n period: \"hourly\",\n start: nextStart,\n end: endDate,\n };\n};\n","/* eslint-disable @typescript-eslint/no-redundant-type-constituents */\n/* eslint-disable no-case-declarations */\nimport { DateTime, Interval } from \"luxon\";\nimport type { AnalyticsGranularity } from \"./AnalyticsQuery.js\";\nimport {\n type AnalyticsDimension,\n type AnalyticsSeries,\n} from \"./AnalyticsQuery.js\";\nimport {\n type AnalyticsPeriod,\n type AnalyticsRange,\n getPeriodSeriesArray,\n} from \"./AnalyticsTimeSlicer.js\";\n\nexport const getQuarter = (date: DateTime) => {\n return Math.floor((date.month - 1) / 3) + 1;\n};\n\nexport type GroupedPeriodResult = {\n period: string;\n start: DateTime;\n end: DateTime;\n rows: Array<{\n dimensions: Record<string, AnalyticsDimension>;\n metric: string;\n unit: string | null;\n value: number;\n\n /**\n * The sum of all metric values over this period?\n */\n sum: number;\n }>;\n};\n\nexport type GroupedPeriodResults = Array<GroupedPeriodResult>;\n\nexport class AnalyticsDiscretizer {\n public static discretize(\n series: AnalyticsSeries<string>[],\n dimensions: string[],\n start: DateTime | null,\n end: DateTime | null,\n granularity: AnalyticsGranularity,\n ): GroupedPeriodResults {\n const index = this._buildIndex(series, dimensions);\n const periods = getPeriodSeriesArray(\n this._calculateRange(start, end, granularity, series),\n );\n const disretizedResults = this._discretizeNode(\n index,\n {},\n dimensions,\n periods,\n );\n const groupedResults = this._groupResultsByPeriod(\n periods,\n disretizedResults,\n );\n\n return groupedResults;\n }\n\n private static _calculateRange(\n start: DateTime | null,\n end: DateTime | null,\n granularity: AnalyticsGranularity,\n results: AnalyticsSeries<any>[],\n ) {\n let calculatedStart: DateTime | null = start || null;\n let calculatedEnd: DateTime | null = end || null;\n\n if (calculatedStart == null || calculatedEnd == null) {\n for (const r of results) {\n if (calculatedStart == null) {\n calculatedStart = r.start;\n }\n\n const endValue = r.end || r.start;\n if (calculatedEnd == null || calculatedEnd < endValue) {\n calculatedEnd = endValue;\n }\n }\n }\n\n if (calculatedStart == null || calculatedEnd == null) {\n throw new Error(\"Cannot determine query start and/or end.\");\n }\n\n return {\n start: calculatedStart,\n end: calculatedEnd,\n granularity,\n } as AnalyticsRange;\n }\n\n public static _groupResultsByPeriod(\n periods: AnalyticsPeriod[],\n dimensionedResults: DimensionedSeries[],\n ): GroupedPeriodResults {\n const result: Record<string, GroupedPeriodResult> = {};\n\n for (const p of periods) {\n const id = p.start.toISO() + \"-\" + p.period;\n const period = AnalyticsDiscretizer._getPeriodString(p);\n result[id] = {\n period: period,\n start: p.start,\n end: p.end,\n rows: [],\n };\n }\n\n for (const r of dimensionedResults) {\n for (const period of Object.keys(r.series)) {\n result[period].rows.push({\n dimensions: r.dimensions,\n metric: r.metric,\n unit: r.unit == \"__NULL__\" ? null : r.unit,\n value: r.series[period].inc,\n sum: r.series[period].sum,\n });\n }\n }\n\n return Object.values(result);\n }\n\n static _getPeriodString(p: AnalyticsPeriod) {\n // Period boundaries are anchored to the UTC calendar (see\n // AnalyticsTimeSlicer), so labels are derived from the UTC view of the\n // period start, never from a zoned start's local calendar fields.\n const startUtc = p.start.toUTC();\n switch (p.period) {\n case \"annual\":\n return startUtc.year.toString();\n case \"semiAnnual\":\n return `${startUtc.year}/${startUtc.month < 7 ? \"H1\" : \"H2\"}`;\n case \"quarterly\":\n return `${startUtc.year}/Q${getQuarter(startUtc)}`;\n case \"monthly\":\n const month = startUtc.month;\n const formattedMonth = month < 10 ? `0${month}` : `${month}`;\n return `${startUtc.year}/${formattedMonth}`;\n case \"weekly\":\n return `${startUtc.weekYear}/W${startUtc.weekNumber}`;\n case \"daily\":\n const monthD = startUtc.month;\n const day = startUtc.day;\n const formattedMonthD = monthD < 10 ? `0${monthD}` : `${monthD}`;\n const formattedDay = day < 10 ? `0${day}` : `${day}`;\n return `${startUtc.year}/${formattedMonthD}/${formattedDay}`;\n case \"hourly\":\n const monthH = startUtc.month;\n const dayH = startUtc.day;\n const hourH = startUtc.hour;\n const formattedMonthH = monthH < 10 ? `0${monthH}` : `${monthH}`;\n const formattedDayH = dayH < 10 ? `0${dayH}` : `${dayH}`;\n const formattedHourH = hourH < 10 ? `0${hourH}` : `${hourH}`;\n return `${startUtc.year}/${formattedMonthH}/${formattedDayH}/${formattedHourH}`;\n default:\n return p.period;\n }\n }\n\n public static _discretizeNode(\n node: DiscretizerIndexNode,\n dimensionValues: Record<string, string>,\n remainingDimensions: string[],\n periods: AnalyticsPeriod[],\n ): DimensionedSeries[] {\n const result: DimensionedSeries[] = [];\n\n if (remainingDimensions.length > 0) {\n const subdimension = remainingDimensions[0] as string;\n Object.keys(node).forEach((subdimensionValue, _index, _arr) => {\n const newDimensionValues = { ...dimensionValues };\n newDimensionValues[subdimension] = subdimensionValue;\n result.push(\n ...this._discretizeNode(\n node[subdimensionValue] as DiscretizerIndexNode,\n newDimensionValues,\n remainingDimensions.slice(1),\n periods,\n ),\n );\n });\n } else {\n Object.keys(node).forEach((metric) => {\n result.push(\n ...this._discretizeLeaf(\n node[metric] as DiscretizerIndexLeaf,\n periods,\n metric,\n dimensionValues,\n ),\n );\n });\n }\n\n return result;\n }\n\n public static _discretizeLeaf(\n leaf: DiscretizerIndexLeaf,\n periods: AnalyticsPeriod[],\n metric: string,\n dimensionValues: Record<string, string>,\n ): DimensionedSeries[] {\n const result: DimensionedSeries[] = [];\n Object.keys(leaf).forEach((unit) => {\n const metaDimensions: any = {};\n Object.keys(dimensionValues).forEach((k) => {\n metaDimensions[k] = {\n path: leaf[unit][0].dimensions[k],\n icon: leaf[unit][0].dimensions.icon,\n label: leaf[unit][0].dimensions.label,\n description: leaf[unit][0].dimensions.description,\n };\n });\n result.push({\n unit,\n metric,\n dimensions: metaDimensions as any,\n series: this._discretizeSeries(leaf[unit], periods),\n });\n });\n\n return result;\n }\n\n public static _discretizeSeries(\n series: AnalyticsSeries<string>[],\n periods: AnalyticsPeriod[],\n ): Series {\n const result: Series = {};\n\n // An empty range (start equal to end) produces no periods; there is\n // nothing to attribute values to.\n if (periods.length === 0) {\n return result;\n }\n\n for (const s of series) {\n let oldSum = this._getValue(s, periods[0].start);\n for (const p of periods) {\n // Periods are half-open [start, end): the cumulative value \"as of\"\n // a boundary excludes values stamped exactly on it, so a value at\n // an exact period start is attributed to the period that starts\n // there, not the one that ends there.\n const newSum = this._getValue(s, p.end);\n const id = `${p.start.toISO()}-${p.period}`;\n\n // const id = p.period;\n if (result[id]) {\n result[id].inc += newSum - oldSum;\n result[id].sum += newSum;\n } else {\n result[id] = {\n inc: newSum - oldSum,\n sum: newSum,\n };\n }\n\n oldSum = newSum;\n }\n }\n\n return result;\n }\n\n public static _getValue(\n series: AnalyticsSeries<string>,\n when: DateTime,\n ): number {\n switch (series.fn) {\n case \"Single\":\n return this._getSingleValue(series, when);\n case \"DssVest\":\n return this._getVestValue(series, when);\n default:\n // todo: logging interface\n //console.error(`Unknown analytics series function: '${series.fn}'`);\n return 0.0;\n }\n }\n\n public static _getSingleValue(\n series: AnalyticsSeries<string>,\n when: DateTime,\n ): number {\n // Strictly greater than: the cumulative value at instant t covers values\n // stamped before t only. Periods are half-open [start, end), so a value\n // stamped exactly at a boundary belongs to the period that starts there.\n return when > series.start ? series.value : 0.0;\n }\n\n public static _getVestValue(\n series: AnalyticsSeries<string>,\n when: DateTime,\n ): number {\n const now = when;\n const start = series.start;\n const end = series.end;\n\n const cliff = series.params?.cliff\n ? DateTime.fromISO(series.params.cliff! as string, { zone: \"utc\" })\n : null;\n if (now < start || (cliff && now < cliff)) {\n return 0.0;\n } else if (end && now >= end) {\n return series.value;\n }\n\n const a = Interval.fromDateTimes(start, now);\n const b = Interval.fromDateTimes(start, end || now);\n\n return (a.length() / b.length()) * series.value;\n }\n\n public static _buildIndex(\n series: AnalyticsSeries<string>[],\n dimensions: string[],\n ): DiscretizerIndexNode {\n const result: DiscretizerIndexNode | any = {};\n const map: DiscretizerIndexLeaf = {};\n const dimName = dimensions[0] || \"\";\n\n for (const s of series) {\n const dimValue = s.dimensions[dimName];\n if (undefined === map[dimValue]) {\n map[dimValue] = [];\n }\n map[dimValue].push(s);\n }\n\n if (dimensions.length > 1) {\n const newDimensions = dimensions.slice(1);\n Object.keys(map).forEach((k) => {\n result[k] = this._buildIndex(map[k], newDimensions);\n });\n } else {\n Object.keys(map).forEach((k) => {\n result[k] = this._buildMetricsIndex(map[k]);\n });\n }\n\n return result;\n }\n\n public static _buildMetricsIndex(\n series: AnalyticsSeries<string>[],\n ): DiscretizerIndexNode {\n const result: DiscretizerIndexNode = {};\n\n const map: DiscretizerIndexLeaf = {};\n for (const s of series) {\n const metric = s.metric;\n if (undefined === map[metric]) {\n map[metric] = [];\n }\n\n map[metric].push(s);\n }\n\n Object.keys(map).forEach((k) => (result[k] = this._buildUnitIndex(map[k])));\n return result;\n }\n\n public static _buildUnitIndex(\n series: AnalyticsSeries<string>[],\n ): DiscretizerIndexLeaf {\n const result: DiscretizerIndexLeaf = {};\n\n for (const s of series) {\n const unit = s.unit || \"__NULL__\";\n if (undefined === result[unit]) {\n result[unit] = [];\n }\n\n result[unit].push(s);\n }\n\n return result;\n }\n}\n\ntype DiscretizerIndexLeaf = { [k: string]: AnalyticsSeries<string>[] };\ntype DiscretizerIndexNode = {\n [k: string]: DiscretizerIndexNode | DiscretizerIndexLeaf;\n};\ntype Series = Record<\n string,\n {\n /**\n * How much the metric increased from the beginning of the series to the end of the specified period.\n */\n inc: number;\n\n /**\n * The sum of all metric values from the beginning of the series to the end of the specified period.\n */\n sum: number;\n }\n>;\ntype DimensionedSeries = {\n unit: string;\n metric: string;\n dimensions: Record<string, AnalyticsDimension>;\n series: Series;\n};\n","/* eslint-disable @typescript-eslint/no-redundant-type-constituents */\nimport {\n AnalyticsDiscretizer,\n type GroupedPeriodResults,\n type GroupedPeriodResult,\n} from \"./AnalyticsDiscretizer.js\";\nimport { AnalyticsPath } from \"./AnalyticsPath.js\";\nimport {\n type IAnalyticsProfiler,\n PassthroughAnalyticsProfiler,\n} from \"./AnalyticsProfiler.js\";\nimport {\n type AnalyticsQuery,\n type AnalyticsSeries,\n type AnalyticsSeriesQuery,\n type CompoundAnalyticsQuery,\n type MultiCurrencyConversion,\n CompoundOperator,\n} from \"./AnalyticsQuery.js\";\nimport { type IAnalyticsStore } from \"./IAnalyticsStore.js\";\n\nexport class AnalyticsQueryEngine {\n private readonly _profiler: IAnalyticsProfiler;\n\n public constructor(\n private readonly _analyticsStore: IAnalyticsStore,\n profiler?: IAnalyticsProfiler,\n ) {\n this._profiler = profiler ?? new PassthroughAnalyticsProfiler();\n }\n\n public async executeCompound(\n query: CompoundAnalyticsQuery,\n ): Promise<GroupedPeriodResults> {\n let result: GroupedPeriodResults;\n\n const inputsQuery: AnalyticsQuery = {\n start: query.start,\n end: query.end,\n granularity: query.granularity,\n lod: query.lod,\n select: query.select,\n metrics: query.expression.inputs.metrics,\n currency: query.expression.inputs.currency,\n };\n\n const operandQuery: AnalyticsQuery = {\n start: query.start,\n end: query.end,\n granularity: query.granularity,\n lod: { priceData: 1 },\n select: { priceData: [AnalyticsPath.fromString(\"atlas\")] },\n metrics: [query.expression.operand.metric],\n currency: query.expression.operand.currency,\n };\n\n const inputExecute = await this.execute(inputsQuery);\n const operandExecute = await this.execute(operandQuery);\n\n if (\n [CompoundOperator.VectorAdd, CompoundOperator.VectorSubtract].includes(\n query.expression.operator,\n )\n ) {\n result = await this._profiler.record(\n \"ApplyVectorOperator\",\n async () =>\n await this._applyVectorOperator(\n inputExecute,\n operandExecute,\n query.expression.operator,\n query.expression.resultCurrency,\n ),\n );\n } else {\n result = await this._profiler.record(\n \"ApplyScalarOperator\",\n async () =>\n await this._applyScalarOperator(\n inputExecute,\n operandExecute,\n query.expression.operator,\n query.expression.operand.useSum,\n query.expression.resultCurrency,\n ),\n );\n }\n\n return result;\n }\n\n public async execute(query: AnalyticsQuery): Promise<GroupedPeriodResults> {\n const seriesResults = await this._executeSeriesQuery(query);\n\n const normalizedSeriesResults = this._profiler.recordSync(\"ApplyLODs\", () =>\n this._applyLods(seriesResults, query.lod),\n );\n\n const dimensions = Object.keys(query.select);\n const discretizedResult = this._profiler.recordSync(\"Discretize\", () =>\n normalizedSeriesResults.length < 1\n ? []\n : AnalyticsDiscretizer.discretize(\n normalizedSeriesResults,\n dimensions,\n query.start,\n query.end,\n query.granularity,\n ),\n );\n return discretizedResult;\n }\n\n public async executeMultiCurrency(\n query: AnalyticsQuery,\n mcc: MultiCurrencyConversion,\n ): Promise<GroupedPeriodResults> {\n const baseQuery: AnalyticsQuery = {\n ...query,\n currency: mcc.targetCurrency ?? query.currency,\n };\n let result = await this.execute(baseQuery);\n\n for (const conversion of mcc.conversions) {\n const nextQuery: CompoundAnalyticsQuery = {\n start: query.start,\n end: query.end,\n granularity: query.granularity,\n lod: query.lod,\n select: query.select,\n expression: {\n inputs: {\n metrics: baseQuery.metrics,\n currency: conversion.currency,\n },\n operator: CompoundOperator.ScalarMultiply,\n operand: {\n metric: conversion.metric,\n currency: mcc.targetCurrency,\n useSum: true,\n },\n resultCurrency: mcc.targetCurrency,\n },\n };\n\n const executedCompound = await this.executeCompound(nextQuery);\n result = await this._applyVectorOperator(\n result,\n executedCompound,\n CompoundOperator.VectorAdd,\n mcc.targetCurrency,\n );\n }\n return result;\n }\n\n private _applyVectorOperator(\n inputsA: GroupedPeriodResults,\n inputsB: GroupedPeriodResults,\n operator: CompoundOperator,\n _resultCurrency?: AnalyticsPath,\n ): Promise<GroupedPeriodResults> {\n if (\n [CompoundOperator.ScalarMultiply, CompoundOperator.ScalarDivide].includes(\n operator,\n )\n ) {\n throw new Error(\"Invalid operator for vector operation\");\n }\n return Promise.resolve(inputsB);\n }\n\n private _applyScalarOperator(\n inputs: GroupedPeriodResults, // expected input is the budget & actuals in 2022 monthly granularity in MKR\n operand: GroupedPeriodResults, // expected input is the daily mkr price change in 2022 monthly granularity in DAI\n operator: CompoundOperator, // expected to me multiply and later addition\n useOperandSum: boolean,\n resultCurrency?: AnalyticsPath, // expected to be DAI\n ): Promise<GroupedPeriodResults> {\n if (\n [CompoundOperator.VectorAdd, CompoundOperator.VectorSubtract].includes(\n operator,\n )\n ) {\n throw new Error(\"Invalid operator for scalar operation\");\n }\n\n const result: GroupedPeriodResults = [];\n const operandMap: Record<string, number> = {};\n const key = useOperandSum ? \"sum\" : \"value\";\n\n for (const operandPeriod of operand) {\n if (operandPeriod.rows.length > 0) {\n operandMap[operandPeriod.period] = operandPeriod.rows[0][key];\n }\n }\n\n // let previousValue: number = 1;\n for (const inputPeriod of inputs) {\n const outputPeriod: GroupedPeriodResult = {\n period: inputPeriod.period,\n start: inputPeriod.start,\n end: inputPeriod.end,\n rows: inputPeriod.rows.map((row) => {\n const newRow = {\n dimensions: row.dimensions,\n metric: row.metric,\n unit: resultCurrency ? resultCurrency.toString() : row.unit,\n value: this._calculateOutputValue(\n row.value,\n operator,\n operandMap[inputPeriod.period],\n ),\n sum: -1,\n };\n return newRow;\n }),\n };\n result.push(outputPeriod);\n }\n\n return Promise.resolve(result);\n }\n\n private _calculateOutputValue(\n input: number,\n operator: CompoundOperator,\n operand: number,\n ): number {\n switch (operator) {\n case CompoundOperator.VectorAdd:\n return input + operand;\n case CompoundOperator.VectorSubtract:\n return input - operand;\n case CompoundOperator.ScalarMultiply:\n return input * operand;\n case CompoundOperator.ScalarDivide:\n return input / operand;\n }\n }\n\n private async _executeSeriesQuery(\n query: AnalyticsQuery,\n ): Promise<AnalyticsSeries[]> {\n const seriesQuery: AnalyticsSeriesQuery = {\n start: query.start,\n end: query.end,\n select: query.select,\n metrics: query.metrics,\n currency: query.currency,\n };\n\n return await this._analyticsStore.getMatchingSeries(seriesQuery);\n }\n\n private _applyLods(\n series: AnalyticsSeries[],\n lods: Record<string, number | null>,\n ): AnalyticsSeries<string>[] {\n return series.map((result) => ({\n ...result,\n dimensions: this._applyDimensionsLods(result.dimensions, lods),\n }));\n }\n\n private _applyDimensionsLods(\n dimensionMap: Record<string, AnalyticsPath> | any,\n lods: Record<string, number | null>,\n ) {\n const result: Record<string, string> | any = {};\n for (const [dimension, lod] of Object.entries(lods)) {\n if (lod !== null && dimensionMap[dimension]) {\n result[dimension] = dimensionMap[dimension][\"path\"]\n .applyLod(lod)\n .toString();\n result[\"icon\"] = dimensionMap[dimension][\"icon\"].toString();\n result[\"label\"] = dimensionMap[dimension][\"label\"].toString();\n result[\"description\"] =\n dimensionMap[dimension][\"description\"].toString();\n }\n }\n return result;\n }\n\n public async getDimensions(): Promise<any> {\n return await this._analyticsStore.getDimensions();\n }\n\n /*public async getMetrics(): Promise<string[]> {\n return await this._analyticsStore.getMetrics();\n }\n\n public async getCurrencies(): Promise<string[]> {\n return await this._analyticsStore.getCurrencies();\n }*/\n}\n","import type { AnalyticsPath } from \"./AnalyticsPath.js\";\nimport type { AnalyticsUpdateCallback } from \"./IAnalyticsStore.js\";\n\nexport class NotificationError extends Error {\n public readonly innerErrors: Error[];\n\n constructor(errors: Error[]) {\n super(errors.map((e) => e.message).join(\"\\n\"));\n\n this.name = \"NotificationError\";\n this.innerErrors = errors;\n }\n}\n\n/**\n * Manages subscriptions for analytics paths.\n */\nexport class AnalyticsSubscriptionManager {\n private _subscriptions: Map<string, Set<AnalyticsUpdateCallback>> = new Map();\n\n /**\n * Subscribe to updates for an analytics path. A subscribed function will be\n * called for:\n *\n * - exact path matches\n * - matching child paths (i.e. an update to /a/b/c will trigger a callback\n * for /a/b/c, /a/b, and /a)\n * - wildcard matches\n *\n * @param path The analytics path to subscribe to.\n * @param callback Function to be called when the path is updated.\n *\n * @returns A function that, when called, unsubscribes from the updates.\n */\n public subscribeToPath(\n path: AnalyticsPath,\n callback: AnalyticsUpdateCallback,\n ): () => void {\n const pathString = this.normalizePath(path.toString(\"/\"));\n\n if (!this._subscriptions.has(pathString)) {\n this._subscriptions.set(pathString, new Set());\n }\n\n this._subscriptions.get(pathString)!.add(callback);\n\n return () => {\n const callbacks = this._subscriptions.get(pathString);\n if (callbacks) {\n callbacks.delete(callback);\n\n // only remove the path entry if there are no more callbacks\n if (callbacks.size === 0) {\n this._subscriptions.delete(pathString);\n }\n }\n };\n }\n\n /**\n * Notifies subscribers about updates to paths.\n *\n * @param paths The paths that were updated.\n */\n public notifySubscribers(paths: AnalyticsPath[]): void {\n if (paths.length === 0 || this._subscriptions.size === 0) {\n return;\n }\n\n const errors: Error[] = [];\n for (const path of paths) {\n const pathString = this.normalizePath(path.toString(\"/\"));\n const pathPrefixes = this.getPathPrefixes(pathString);\n\n const matchingSubscriptions: Array<{\n prefix: string;\n callbacks: Set<AnalyticsUpdateCallback>;\n }> = [];\n\n // add the exact prefix matches\n pathPrefixes\n .filter((prefix) => this._subscriptions.has(prefix))\n .forEach((prefix) => {\n matchingSubscriptions.push({\n prefix,\n callbacks: this._subscriptions.get(prefix)!,\n });\n });\n\n // check all wildcard patterns\n for (const [\n subscriptionPath,\n callbacks,\n ] of this._subscriptions.entries()) {\n // skip if it's already in the exact matches\n if (pathPrefixes.includes(subscriptionPath)) {\n continue;\n }\n\n // hceck if this subscription path (which might have wildcards) matches the update path\n if (this.pathMatchesWildcardPattern(pathString, subscriptionPath)) {\n matchingSubscriptions.push({\n prefix: subscriptionPath,\n callbacks,\n });\n }\n }\n\n if (matchingSubscriptions.length === 0) continue;\n\n // guarantee delivery to all subscribers\n for (const { callbacks } of matchingSubscriptions) {\n for (const callback of callbacks) {\n try {\n callback(path);\n } catch (e) {\n errors.push(e as Error);\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new NotificationError(errors);\n }\n }\n\n /**\n * Normalizes a path string to ensure consistent comparison.\n */\n private normalizePath(path: string): string {\n // Handle potential double slashes by first splitting on slashes and rejoining\n const parts = path.split(\"/\").filter((p) => p.length > 0);\n const normalized = \"/\" + parts.join(\"/\");\n return normalized;\n }\n\n /**\n * Checks if a path matches a subscription pattern that may contain wildcards.\n */\n private pathMatchesWildcardPattern(\n updatePath: string,\n subscriptionPath: string,\n ): boolean {\n // Handle the wildcard segment case\n if (subscriptionPath.includes(\"*\")) {\n const updateSegments = updatePath.split(\"/\").filter((s) => s.length > 0);\n const subscriptionSegments = subscriptionPath\n .split(\"/\")\n .filter((s) => s.length > 0);\n\n // If subscription is longer than the update path, it can't match\n if (subscriptionSegments.length > updateSegments.length) {\n return false;\n }\n\n // Compare each segment\n for (let i = 0; i < subscriptionSegments.length; i++) {\n const subSegment = subscriptionSegments[i];\n const updateSegment = updateSegments[i];\n\n // If segment is * or starts with * (wildcard), it matches anything\n if (subSegment === \"*\" || subSegment.startsWith(\"*:\")) {\n continue;\n }\n\n // Otherwise, segments should match exactly\n if (subSegment !== updateSegment) {\n return false;\n }\n }\n\n return true;\n }\n\n // If no wildcards, check if subscription is a prefix of the update path\n return (\n updatePath === subscriptionPath ||\n updatePath.startsWith(subscriptionPath + \"/\")\n );\n }\n\n /**\n * Gets all path prefixes for a given path.\n *\n * For example, for '/a/b/c' it returns ['/a', '/a/b', '/a/b/c'].\n */\n private getPathPrefixes(path: string): string[] {\n const segments = path.split(\"/\").filter((s) => s.length > 0);\n const prefixes: string[] = [];\n\n let currentPath = \"\";\n for (const segment of segments) {\n currentPath = currentPath ? `${currentPath}/${segment}` : `/${segment}`;\n prefixes.push(currentPath);\n }\n\n if (prefixes.length === 0 && path === \"/\") {\n prefixes.push(\"/\");\n }\n\n return prefixes;\n }\n}\n","import type { SqlQueryLogger, SqlResultsLogger } from \"./types.js\";\n\nexport const defaultQueryLogger =\n (tag: string): SqlQueryLogger =>\n (index: number, query: string) => {\n console.log(`[${tag}][Q:${index}]: ${query}\\n`);\n };\n\nexport const defaultResultsLogger =\n (tag: string): SqlResultsLogger =>\n (index: number, results: any) => {\n if (Array.isArray(results)) {\n console.log(`[${tag}][R:${index}]: ${results.length} results\\n`);\n } else {\n console.log(`[${tag}][R:${index}]: Received ${typeof results}.\\n`);\n }\n };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/analytics-engine-core",
|
|
3
|
-
"version": "6.2.3-dev.
|
|
3
|
+
"version": "6.2.3-dev.60",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"luxon": "3.7.2",
|
|
27
|
-
"@powerhousedao/shared": "6.2.3-dev.
|
|
27
|
+
"@powerhousedao/shared": "6.2.3-dev.60"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/luxon": "3.7.1",
|
|
31
|
-
"vitest": "
|
|
32
|
-
"tsdown": "0.
|
|
31
|
+
"vitest": "5.0.3",
|
|
32
|
+
"tsdown": "0.23.0"
|
|
33
33
|
},
|
|
34
34
|
"description": "Powerhouse analytics engine — time-series query engine for document drive metrics and usage data.",
|
|
35
35
|
"keywords": [
|