@powerhousedao/analytics-engine-knex 0.1.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,45 @@
1
+ import { Knex } from "knex";
2
+ import { AnalyticsPath, AnalyticsSeries, AnalyticsSeriesInput, AnalyticsSeriesQuery, IAnalyticsStore } from "@powerhousedao/analytics-engine-core";
3
+ export type AnalyticsSeriesRecord = {
4
+ id: number;
5
+ source: string;
6
+ start: Date;
7
+ end: Date | null;
8
+ metric: string;
9
+ value: number;
10
+ unit: string | null;
11
+ fn: string;
12
+ params: Record<string, any> | null;
13
+ [dimension: `dim_${string}`]: string;
14
+ dimensionMetadata?: Record<string, string>;
15
+ };
16
+ /**
17
+ * Using an interface here, so that a null implementation can be used in production,
18
+ * without the added overhead of calling toString().
19
+ */
20
+ export interface IQuery {
21
+ toString(): string;
22
+ }
23
+ export interface IKnexQueryExecutor {
24
+ execute<T extends {}, U>(query: Knex.QueryBuilder<T, U>): Promise<any>;
25
+ }
26
+ export declare class KnexAnalyticsStore implements IAnalyticsStore {
27
+ protected readonly _executor: IKnexQueryExecutor;
28
+ protected readonly _knex: Knex;
29
+ constructor(_executor: IKnexQueryExecutor, knex?: Knex);
30
+ destroy(): void;
31
+ clearSeriesBySource(source: AnalyticsPath, cleanUpDimensions?: boolean): Promise<any>;
32
+ clearEmptyAnalyticsDimensions(): Promise<any>;
33
+ getMatchingSeries(query: AnalyticsSeriesQuery): Promise<AnalyticsSeries[]>;
34
+ addSeriesValue(input: AnalyticsSeriesInput): Promise<void>;
35
+ addSeriesValues(inputs: AnalyticsSeriesInput[]): Promise<void>;
36
+ private _formatQueryRecords;
37
+ private _buildViewQuery;
38
+ private _buildDimensionQuery;
39
+ private _linkDimensions;
40
+ private _createDimensionPath;
41
+ private addDimensionMetadata;
42
+ getDimensions(): Promise<any>;
43
+ getMetrics(): Promise<any>;
44
+ getCurrencies(): Promise<any>;
45
+ }
@@ -0,0 +1,258 @@
1
+ import knexFactory from "knex";
2
+ import { DateTime } from "luxon";
3
+ import { AnalyticsPath, } from "@powerhousedao/analytics-engine-core";
4
+ function toPascalCase(str) {
5
+ return str
6
+ .replace(/\w+/g, function (word) {
7
+ return word[0].toUpperCase() + word.slice(1);
8
+ })
9
+ .replace(/\s+/g, "");
10
+ }
11
+ export class KnexAnalyticsStore {
12
+ _executor;
13
+ _knex;
14
+ constructor(_executor, knex) {
15
+ this._executor = _executor;
16
+ this._knex =
17
+ knex ||
18
+ knexFactory({
19
+ client: "sqlite3",
20
+ });
21
+ }
22
+ destroy() {
23
+ this._knex.destroy();
24
+ }
25
+ async clearSeriesBySource(source, cleanUpDimensions = false) {
26
+ const query = this._knex("AnalyticsSeries")
27
+ .whereLike("source", source.toString("/%"))
28
+ .delete();
29
+ let result = await this._executor.execute(query);
30
+ if (cleanUpDimensions) {
31
+ result += await this.clearEmptyAnalyticsDimensions();
32
+ }
33
+ return result;
34
+ }
35
+ async clearEmptyAnalyticsDimensions() {
36
+ const query = this._knex("AnalyticsDimension AS AD")
37
+ .whereNotExists((q) => q
38
+ .select("*")
39
+ .from("AnalyticsSeries_AnalyticsDimension AS ASAD")
40
+ .where("ASAD.dimensionId", this._knex.ref("AD.id")))
41
+ .delete();
42
+ return await this._executor.execute(query);
43
+ }
44
+ async getMatchingSeries(query) {
45
+ const analyticsView = this._buildViewQuery("AV", Object.keys(query.select), query.metrics.map((m) => m), query.currency.firstSegment().filters, query.end);
46
+ const baseQuery = this._knex(this._knex.raw(analyticsView)).select("AV.*");
47
+ // Add dimension filter(s)
48
+ for (const [dimension, paths] of Object.entries(query.select)) {
49
+ baseQuery.leftJoin(`AnalyticsDimension as ${dimension}`, (q) => {
50
+ q.on(`${dimension}.path`, `dim_${dimension}`);
51
+ });
52
+ baseQuery.select(`${dimension}.icon as dim_icon`);
53
+ baseQuery.select(`${dimension}.description as dim_description`);
54
+ baseQuery.select(`${dimension}.label as dim_label`);
55
+ if (paths.length == 1) {
56
+ baseQuery.andWhereLike(`dim_${dimension}`, paths[0].toString("/%"));
57
+ }
58
+ else if (paths.length > 1) {
59
+ baseQuery.andWhere((q) => {
60
+ paths.forEach((p) => q.orWhereLike(`dim_${dimension}`, p.toString("/%")));
61
+ return q;
62
+ });
63
+ }
64
+ }
65
+ baseQuery.orderBy("start");
66
+ const results = await this._executor.execute(baseQuery);
67
+ return this._formatQueryRecords(results, Object.keys(query.select));
68
+ }
69
+ async addSeriesValue(input) {
70
+ return this.addSeriesValues([input]);
71
+ }
72
+ async addSeriesValues(inputs) {
73
+ const dimensionsMap = {};
74
+ for (let i = 0; i < inputs.length; i++) {
75
+ const input = inputs[i];
76
+ const query = this._knex("AnalyticsSeries").insert({
77
+ start: input.start.toJSDate(),
78
+ end: input.end ? input.end.toJSDate() : null,
79
+ source: input.source.toString("/"),
80
+ metric: toPascalCase(input.metric),
81
+ value: input.value,
82
+ unit: input.unit || null,
83
+ fn: input.fn || "Single",
84
+ params: input.params || null,
85
+ }, "id");
86
+ const record = await this._executor.execute(query);
87
+ for (const [dim, path] of Object.entries(inputs[i].dimensions || {})) {
88
+ if (!dimensionsMap[dim]) {
89
+ dimensionsMap[dim] = {};
90
+ }
91
+ const pKey = path.toString("/");
92
+ if (!dimensionsMap[dim][pKey]) {
93
+ dimensionsMap[dim][pKey] = [];
94
+ }
95
+ dimensionsMap[dim][pKey].push(record[0].id);
96
+ }
97
+ }
98
+ for (const [dim, pathMap] of Object.entries(dimensionsMap)) {
99
+ await this._linkDimensions(dim, pathMap);
100
+ }
101
+ // Adding dimension metadata
102
+ for (let i = 0; i < inputs.length; i++) {
103
+ const metaDimension = inputs[i].dimensionMetadata;
104
+ if (!metaDimension) {
105
+ continue;
106
+ }
107
+ await this.addDimensionMetadata(metaDimension.path, metaDimension.icon, metaDimension.label, metaDimension.description);
108
+ }
109
+ }
110
+ _formatQueryRecords(records, dimensions) {
111
+ const formatted = records.map((r) => {
112
+ const result = {
113
+ id: r.id,
114
+ source: AnalyticsPath.fromString(r.source.slice(0, -1)),
115
+ start: DateTime.fromJSDate(r.start),
116
+ end: r.end ? DateTime.fromJSDate(r.end) : null,
117
+ metric: r.metric,
118
+ value: r.value,
119
+ unit: r.unit,
120
+ fn: r.fn,
121
+ params: r.params,
122
+ dimensions: {},
123
+ };
124
+ dimensions.forEach((d) => (result.dimensions[d] = {
125
+ path: AnalyticsPath.fromString(r[`dim_${d}`] ? r[`dim_${d}`].slice(0, -1) : "?"),
126
+ icon: r[`dim_icon`] ? r[`dim_icon`] : "",
127
+ label: r[`dim_label`] ? r[`dim_label`] : "",
128
+ description: r[`dim_description`] ? r[`dim_description`] : "",
129
+ }));
130
+ return result;
131
+ });
132
+ // sort by id
133
+ return formatted.sort((a, b) => a.id - b.id);
134
+ }
135
+ _buildViewQuery(name, dimensions, metrics, units, until) {
136
+ const baseQuery = this._knex("AnalyticsSeries as AS_inner")
137
+ .select("*")
138
+ .whereIn("metric", metrics);
139
+ for (const dimension of dimensions) {
140
+ baseQuery.select(this._buildDimensionQuery(dimension));
141
+ }
142
+ if (units && units[0] !== "") {
143
+ baseQuery.whereIn("unit", units);
144
+ }
145
+ if (until) {
146
+ baseQuery.where("start", "<", until.toISO());
147
+ }
148
+ return `(${baseQuery.toString()}) AS "${name}"`;
149
+ }
150
+ _buildDimensionQuery(dimension) {
151
+ const seriesIdRef = this._knex.ref("AS_inner.id");
152
+ return this._knex("AnalyticsSeries_AnalyticsDimension as ASAD")
153
+ .leftJoin("AnalyticsDimension as AD", "AD.id", "ASAD.dimensionId")
154
+ .where("ASAD.seriesId", seriesIdRef)
155
+ .where("AD.dimension", dimension)
156
+ .select("path")
157
+ .as(`dim_${dimension}`);
158
+ }
159
+ async _linkDimensions(dimension, pathMap) {
160
+ const query = this._knex("AnalyticsDimension")
161
+ .select("path", "id")
162
+ .where("dimension", dimension)
163
+ .whereIn("path", Object.keys(pathMap));
164
+ const dimensionIds = await this._executor.execute(query);
165
+ for (const [path, ids] of Object.entries(pathMap)) {
166
+ const i = dimensionIds.findIndex((record) => record.path == path);
167
+ const dimensionId = i < 0
168
+ ? await this._createDimensionPath(dimension, path)
169
+ : dimensionIds[i].id;
170
+ for (let j = 0; j < ids.length; j++) {
171
+ const query = this._knex("AnalyticsSeries_AnalyticsDimension").insert({
172
+ seriesId: ids[j],
173
+ dimensionId,
174
+ });
175
+ await this._executor.execute(query);
176
+ }
177
+ }
178
+ }
179
+ async _createDimensionPath(dimension, path) {
180
+ const query = this._knex("AnalyticsDimension").insert({ dimension, path }, "id");
181
+ const result = await this._executor.execute(query);
182
+ return result[0].id;
183
+ }
184
+ async addDimensionMetadata(path, icon, label, description) {
185
+ if (!icon && !label && !description) {
186
+ return;
187
+ }
188
+ const query = this._knex("AnalyticsDimension")
189
+ .where("path", `${path.toString()}/`)
190
+ .update({
191
+ icon: icon ? icon : "",
192
+ label: label ? label : "",
193
+ description: description ? description : "",
194
+ });
195
+ await this._executor.execute(query);
196
+ }
197
+ async getDimensions() {
198
+ // Fetch all rows from the database
199
+ const query = this._knex
200
+ .select("dimension", "path", "icon", "label", "description")
201
+ .from("AnalyticsDimension")
202
+ .whereNotNull("path")
203
+ .whereNot("path", "")
204
+ .whereNot("path", "/");
205
+ const rows = await this._executor.execute(query);
206
+ // Process the rows to group them by dimension and format them
207
+ const grouped = rows.reduce((acc, row) => {
208
+ // If the dimension is not yet in the accumulator, add it
209
+ if (!acc[row.dimension]) {
210
+ acc[row.dimension] = {
211
+ name: row.dimension,
212
+ values: [],
213
+ };
214
+ }
215
+ // Add the path, icon, label, and description to the dimension's values
216
+ acc[row.dimension].values.push({
217
+ path: row.path,
218
+ icon: row.icon,
219
+ label: row.label,
220
+ description: row.description,
221
+ });
222
+ return acc;
223
+ }, {});
224
+ // Convert the grouped object to an array
225
+ const dimensionPaths = Object.values(grouped);
226
+ return dimensionPaths;
227
+ }
228
+ async getMetrics() {
229
+ const query = this._knex("AnalyticsSeries")
230
+ .select("metric")
231
+ .distinct()
232
+ .whereNotNull("metric");
233
+ const list = await this._executor.execute(query);
234
+ const filtered = list.map((l) => l.metric);
235
+ const metrics = [
236
+ "Budget",
237
+ "Forecast",
238
+ "Actuals",
239
+ "PaymentsOnChain",
240
+ "PaymentsOffChainIncluded",
241
+ ];
242
+ metrics.forEach((metric) => {
243
+ if (!filtered.includes(metric)) {
244
+ filtered.push(metric);
245
+ }
246
+ });
247
+ return filtered;
248
+ }
249
+ async getCurrencies() {
250
+ const query = this._knex("AnalyticsSeries")
251
+ .select("unit")
252
+ .distinct()
253
+ .whereNotNull("unit");
254
+ const currencies = await this._executor.execute(query);
255
+ return currencies.map((c) => c.unit);
256
+ }
257
+ }
258
+ //# sourceMappingURL=KnexAnalyticsStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnexAnalyticsStore.js","sourceRoot":"","sources":["../src/KnexAnalyticsStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { IAnalyticsProfiler } from "@powerhousedao/analytics-engine-core";
2
+ import { Knex } from "knex";
3
+ import { IKnexQueryExecutor } from "./KnexAnalyticsStore";
4
+ export declare class KnexQueryExecutor implements IKnexQueryExecutor {
5
+ private readonly _queryLogger?;
6
+ private readonly _resultsLogger?;
7
+ private readonly _profiler?;
8
+ private _index;
9
+ constructor(_queryLogger?: ((index: number, query: string) => void) | undefined, _resultsLogger?: ((index: number, results: any) => void) | undefined, _profiler?: IAnalyticsProfiler | undefined);
10
+ execute<T extends {}, U>(query: Knex.QueryBuilder<T, U>): Promise<any>;
11
+ }
@@ -0,0 +1,33 @@
1
+ export class KnexQueryExecutor {
2
+ _queryLogger;
3
+ _resultsLogger;
4
+ _profiler;
5
+ _index = 0;
6
+ constructor(_queryLogger, _resultsLogger, _profiler) {
7
+ this._queryLogger = _queryLogger;
8
+ this._resultsLogger = _resultsLogger;
9
+ this._profiler = _profiler;
10
+ if (this._profiler) {
11
+ this._profiler.push("Knex");
12
+ }
13
+ }
14
+ async execute(query) {
15
+ const index = this._index++;
16
+ if (this._queryLogger) {
17
+ this._queryLogger(index, query.toString());
18
+ }
19
+ let results;
20
+ if (this._profiler) {
21
+ // profile the query
22
+ results = await this._profiler.record("Query", async () => await query);
23
+ }
24
+ else {
25
+ results = await query;
26
+ }
27
+ if (this._resultsLogger) {
28
+ this._resultsLogger(index, results);
29
+ }
30
+ return results;
31
+ }
32
+ }
33
+ //# sourceMappingURL=KnexQueryExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnexQueryExecutor.js","sourceRoot":"","sources":["../src/KnexQueryExecutor.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,iBAAiB;IAIT;IACA;IACA;IALX,MAAM,GAAW,CAAC,CAAC;IAE3B,YACmB,YAAqD,EACrD,cAAsD,EACtD,SAA8B;QAF9B,iBAAY,GAAZ,YAAY,CAAyC;QACrD,mBAAc,GAAd,cAAc,CAAwC;QACtD,cAAS,GAAT,SAAS,CAAqB;QAE/C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAkB,KAA8B;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAE5B,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,OAAO,CAAC;QACZ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,oBAAoB;YACpB,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;QAC1E,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,MAAM,KAAK,CAAC;QACxB,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export { KnexAnalyticsStore } from "./KnexAnalyticsStore.js";
2
+ export { KnexQueryExecutor } from "./KnexQueryExecutor.js";
3
+ export type { IKnexQueryExecutor } from "./KnexAnalyticsStore.js";
4
+ export type { SqlQueryLogger, SqlResultsLogger } from "./util.js";
5
+ export { defaultQueryLogger, defaultResultsLogger } from "./util.js";
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { KnexAnalyticsStore } from "./KnexAnalyticsStore.js";
2
+ export { KnexQueryExecutor } from "./KnexQueryExecutor.js";
3
+ export { defaultQueryLogger, defaultResultsLogger } from "./util.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
package/dist/util.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export type SqlQueryLogger = (index: number, query: string) => void;
2
+ export type SqlResultsLogger = (index: number, results: any) => void;
3
+ export declare const defaultQueryLogger: (tag: string) => SqlQueryLogger;
4
+ export declare const defaultResultsLogger: (tag: string) => SqlResultsLogger;
package/dist/util.js ADDED
@@ -0,0 +1,12 @@
1
+ export const defaultQueryLogger = (tag) => (index, query) => {
2
+ console.log(`[${tag}][Q:${index}]: ${query}\n`);
3
+ };
4
+ export const defaultResultsLogger = (tag) => (index, results) => {
5
+ if (Array.isArray(results)) {
6
+ console.log(`[${tag}][R:${index}]: ${results.length} results\n`);
7
+ }
8
+ else {
9
+ console.log(`[${tag}][R:${index}]: Received ${typeof results}.\n`);
10
+ }
11
+ };
12
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,kBAAkB,GAC7B,CAAC,GAAW,EAAkB,EAAE,CAChC,CAAC,KAAa,EAAE,KAAa,EAAE,EAAE;IAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC;AAClD,CAAC,CAAC;AAEJ,MAAM,CAAC,MAAM,oBAAoB,GAC/B,CAAC,GAAW,EAAoB,EAAE,CAClC,CAAC,KAAa,EAAE,OAAY,EAAE,EAAE;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,KAAK,MAAM,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;IACnE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,KAAK,eAAe,OAAO,OAAO,KAAK,CAAC,CAAC;IACrE,CAAC;AACH,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@powerhousedao/analytics-engine-knex",
3
+ "version": "0.1.0",
4
+ "license": "AGPL-3.0-only",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "dev": "tsc-watch",
16
+ "build": "rm -rf dist/ && tsc",
17
+ "test": "vitest"
18
+ },
19
+ "dependencies": {
20
+ "@powerhousedao/analytics-engine-core": "0.1.0",
21
+ "@types/luxon": "^3.4.2",
22
+ "@types/node": "^22.4.2",
23
+ "@types/pg": "^8.11.6",
24
+ "date-fns": "^3.6.0",
25
+ "knex": "^3.1.0",
26
+ "luxon": "^3.5.0",
27
+ "pg": "^8.12.0"
28
+ },
29
+ "devDependencies": {
30
+ "tsc-watch": "^6.2.0",
31
+ "typescript": "^5.6.3",
32
+ "vitest": "^2.0.5"
33
+ }
34
+ }