@powerhousedao/analytics-engine-knex 6.0.0-dev.105 → 6.0.0-dev.107
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 +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -0
- package/package.json +11 -7
- package/dist/src/KnexAnalyticsStore.d.ts +0 -52
- package/dist/src/KnexAnalyticsStore.d.ts.map +0 -1
- package/dist/src/KnexQueryExecutor.d.ts +0 -12
- package/dist/src/KnexQueryExecutor.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -6
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -9625
- package/dist/src/util.d.ts +0 -6
- package/dist/src/util.d.ts.map +0 -1
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AnalyticsPath, AnalyticsSeries, AnalyticsSeriesInput, AnalyticsSeriesQuery, AnalyticsUpdateCallback, IAnalyticsProfiler, IAnalyticsStore } from "@powerhousedao/analytics-engine-core";
|
|
2
|
+
import { Knex } from "knex";
|
|
3
|
+
|
|
4
|
+
//#region src/KnexAnalyticsStore.d.ts
|
|
5
|
+
type AnalyticsSeriesRecord = {
|
|
6
|
+
id: number;
|
|
7
|
+
source: string;
|
|
8
|
+
start: Date;
|
|
9
|
+
end: Date | null;
|
|
10
|
+
metric: string;
|
|
11
|
+
value: number;
|
|
12
|
+
unit: string | null;
|
|
13
|
+
fn: string;
|
|
14
|
+
params: Record<string, any> | null;
|
|
15
|
+
[dimension: `dim_${string}`]: string;
|
|
16
|
+
dimensionMetadata?: Record<string, string>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Using an interface here, so that a null implementation can be used in production,
|
|
20
|
+
* without the added overhead of calling toString().
|
|
21
|
+
*/
|
|
22
|
+
interface IQuery {
|
|
23
|
+
toString(): string;
|
|
24
|
+
}
|
|
25
|
+
interface IKnexQueryExecutor {
|
|
26
|
+
execute<T extends {}, U>(query: Knex.QueryBuilder<T, U>): Promise<any>;
|
|
27
|
+
}
|
|
28
|
+
type KnexAnalyticsStoreOptions = {
|
|
29
|
+
executor: IKnexQueryExecutor;
|
|
30
|
+
knex: Knex;
|
|
31
|
+
};
|
|
32
|
+
declare class KnexAnalyticsStore implements IAnalyticsStore {
|
|
33
|
+
protected readonly _executor: IKnexQueryExecutor;
|
|
34
|
+
protected readonly _knex: Knex;
|
|
35
|
+
private readonly _subscriptionManager;
|
|
36
|
+
constructor({
|
|
37
|
+
executor,
|
|
38
|
+
knex
|
|
39
|
+
}: KnexAnalyticsStoreOptions);
|
|
40
|
+
destroy(): void;
|
|
41
|
+
clearSeriesBySource(source: AnalyticsPath, cleanUpDimensions?: boolean): Promise<number>;
|
|
42
|
+
clearEmptyAnalyticsDimensions(): Promise<any>;
|
|
43
|
+
getMatchingSeries(query: AnalyticsSeriesQuery): Promise<AnalyticsSeries[]>;
|
|
44
|
+
addSeriesValue(input: AnalyticsSeriesInput): Promise<void>;
|
|
45
|
+
addSeriesValues(inputs: AnalyticsSeriesInput[]): Promise<void>;
|
|
46
|
+
private _formatQueryRecords;
|
|
47
|
+
private _buildViewQuery;
|
|
48
|
+
private _buildDimensionQuery;
|
|
49
|
+
private _linkDimensions;
|
|
50
|
+
private _createDimensionPath;
|
|
51
|
+
private addDimensionMetadata;
|
|
52
|
+
getDimensions(): Promise<any>;
|
|
53
|
+
getMetrics(): Promise<any>;
|
|
54
|
+
getCurrencies(): Promise<any>;
|
|
55
|
+
subscribeToSource(path: AnalyticsPath, callback: AnalyticsUpdateCallback): () => void;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/KnexQueryExecutor.d.ts
|
|
59
|
+
declare class KnexQueryExecutor implements IKnexQueryExecutor {
|
|
60
|
+
private readonly _queryLogger?;
|
|
61
|
+
private readonly _resultsLogger?;
|
|
62
|
+
private readonly _profiler?;
|
|
63
|
+
private _index;
|
|
64
|
+
constructor(_queryLogger?: ((index: number, query: string) => void) | undefined, _resultsLogger?: ((index: number, results: any) => void) | undefined, _profiler?: IAnalyticsProfiler | undefined);
|
|
65
|
+
execute<T extends object, U>(query: Knex.QueryBuilder<T, U>): Promise<any>;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { AnalyticsSeriesRecord, type IKnexQueryExecutor, IQuery, KnexAnalyticsStore, type KnexAnalyticsStoreOptions, KnexQueryExecutor };
|
|
69
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/KnexAnalyticsStore.ts","../src/KnexQueryExecutor.ts"],"mappings":";;;;KAgBY,qBAAA;EACV,EAAA;EACA,MAAA;EACA,KAAA,EAAO,IAAA;EACP,GAAA,EAAK,IAAA;EACL,MAAA;EACA,KAAA;EACA,IAAA;EACA,EAAA;EACA,MAAA,EAAQ,MAAA;EAAA,CACP,SAAA;EACD,iBAAA,GAAoB,MAAA;AAAA;;;;;UAOL,MAAA;EACf,QAAA;AAAA;AAAA,UAGe,kBAAA;EACf,OAAA,kBAAyB,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,CAAA,EAAG,CAAA,IAAK,OAAA;AAAA;AAAA,KAGhD,yBAAA;EACV,QAAA,EAAU,kBAAA;EACV,IAAA,EAAM,IAAA;AAAA;AAAA,cAGK,kBAAA,YAA8B,eAAA;EAAA,mBACtB,SAAA,EAAW,kBAAA;EAAA,mBACX,KAAA,EAAO,IAAA;EAAA,iBACT,oBAAA;;IAGI,QAAA;IAAU;EAAA,GAAQ,yBAAA;EAKhC,OAAA,CAAA;EAIM,mBAAA,CACX,MAAA,EAAQ,aAAA,EACR,iBAAA,aACC,OAAA;EAgBU,6BAAA,CAAA,GAA6B,OAAA;EAa7B,iBAAA,CACX,KAAA,EAAO,oBAAA,GACN,OAAA,CAAQ,eAAA;EAuCE,cAAA,CAAe,KAAA,EAAO,oBAAA,GAAoB,OAAA;EAI1C,eAAA,CAAgB,MAAA,EAAQ,oBAAA,KAAsB,OAAA;EAAA,QAyDnD,mBAAA;EAAA,QAoCA,eAAA;EAAA,QA0BA,oBAAA;EAAA,QAWM,eAAA;EAAA,QA8BA,oBAAA;EAAA,QAUA,oBAAA;EAoBD,aAAA,CAAA,GAAa,OAAA;EAqCb,UAAA,CAAA,GAAU,OAAA;EAuBV,aAAA,CAAA,GAAa,OAAA;EAUnB,iBAAA,CACL,IAAA,EAAM,aAAA,EACN,QAAA,EAAU,uBAAA;AAAA;;;cC7YD,iBAAA,YAA6B,kBAAA;EAAA,iBAIrB,YAAA;EAAA,iBACA,cAAA;EAAA,iBACA,SAAA;EAAA,QALX,MAAA;cAGW,YAAA,KAAgB,KAAA,UAAe,KAAA,gCAC/B,cAAA,KAAkB,KAAA,UAAe,OAAA,6BACjC,SAAA,GAAY,kBAAA;EAOzB,OAAA,qBAAA,CACJ,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,CAAA,EAAG,CAAA,IAC3B,OAAA;AAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { AnalyticsPath, AnalyticsSubscriptionManager } from "@powerhousedao/analytics-engine-core";
|
|
2
|
+
import { pascalCase } from "change-case";
|
|
3
|
+
import { DateTime } from "luxon";
|
|
4
|
+
//#region src/KnexAnalyticsStore.ts
|
|
5
|
+
var KnexAnalyticsStore = class {
|
|
6
|
+
_executor;
|
|
7
|
+
_knex;
|
|
8
|
+
_subscriptionManager = new AnalyticsSubscriptionManager();
|
|
9
|
+
constructor({ executor, knex }) {
|
|
10
|
+
this._executor = executor;
|
|
11
|
+
this._knex = knex;
|
|
12
|
+
}
|
|
13
|
+
destroy() {
|
|
14
|
+
this._knex.destroy();
|
|
15
|
+
}
|
|
16
|
+
async clearSeriesBySource(source, cleanUpDimensions = false) {
|
|
17
|
+
const query = this._knex("AnalyticsSeries").whereLike("source", source.toString("/%")).delete();
|
|
18
|
+
let result = await this._executor.execute(query);
|
|
19
|
+
if (cleanUpDimensions) result += await this.clearEmptyAnalyticsDimensions();
|
|
20
|
+
this._subscriptionManager.notifySubscribers([source]);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
async clearEmptyAnalyticsDimensions() {
|
|
24
|
+
const query = this._knex("AnalyticsDimension AS AD").whereNotExists((q) => q.select("*").from("AnalyticsSeries_AnalyticsDimension AS ASAD").where("ASAD.dimensionId", this._knex.ref("AD.id"))).delete();
|
|
25
|
+
return await this._executor.execute(query);
|
|
26
|
+
}
|
|
27
|
+
async getMatchingSeries(query) {
|
|
28
|
+
const units = query.currency ? query.currency.firstSegment().filters : null;
|
|
29
|
+
const analyticsView = this._buildViewQuery("AV", Object.keys(query.select), query.metrics.map((m) => m), units, query.end);
|
|
30
|
+
const baseQuery = this._knex(this._knex.raw(analyticsView)).select("AV.*");
|
|
31
|
+
for (const [dimension, paths] of Object.entries(query.select)) {
|
|
32
|
+
baseQuery.leftJoin(`AnalyticsDimension as ${dimension}`, (q) => {
|
|
33
|
+
q.on(`${dimension}.path`, `dim_${dimension}`);
|
|
34
|
+
});
|
|
35
|
+
baseQuery.select(`${dimension}.icon as dim_icon`);
|
|
36
|
+
baseQuery.select(`${dimension}.description as dim_description`);
|
|
37
|
+
baseQuery.select(`${dimension}.label as dim_label`);
|
|
38
|
+
if (paths.length == 1) baseQuery.andWhereLike(`dim_${dimension}`, paths[0].toString("/%"));
|
|
39
|
+
else if (paths.length > 1) baseQuery.andWhere((q) => {
|
|
40
|
+
paths.forEach((p) => q.orWhereLike(`dim_${dimension}`, p.toString("/%")));
|
|
41
|
+
return q;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
baseQuery.orderBy("start");
|
|
45
|
+
const results = await this._executor.execute(baseQuery);
|
|
46
|
+
return this._formatQueryRecords(results, Object.keys(query.select));
|
|
47
|
+
}
|
|
48
|
+
async addSeriesValue(input) {
|
|
49
|
+
return this.addSeriesValues([input]);
|
|
50
|
+
}
|
|
51
|
+
async addSeriesValues(inputs) {
|
|
52
|
+
const dimensionsMap = {};
|
|
53
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
54
|
+
const input = inputs[i];
|
|
55
|
+
const query = this._knex("AnalyticsSeries").insert({
|
|
56
|
+
start: input.start.toJSDate(),
|
|
57
|
+
end: input.end ? input.end.toJSDate() : null,
|
|
58
|
+
source: input.source.toString("/"),
|
|
59
|
+
metric: pascalCase(input.metric),
|
|
60
|
+
value: input.value,
|
|
61
|
+
unit: input.unit || null,
|
|
62
|
+
fn: input.fn || "Single",
|
|
63
|
+
params: input.params || null
|
|
64
|
+
}, "id");
|
|
65
|
+
const record = await this._executor.execute(query);
|
|
66
|
+
for (const [dim, path] of Object.entries(inputs[i].dimensions || {})) {
|
|
67
|
+
if (!dimensionsMap[dim]) dimensionsMap[dim] = {};
|
|
68
|
+
const pKey = path.toString("/");
|
|
69
|
+
if (!dimensionsMap[dim][pKey]) dimensionsMap[dim][pKey] = [];
|
|
70
|
+
dimensionsMap[dim][pKey].push(record[0].id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const [dim, pathMap] of Object.entries(dimensionsMap)) await this._linkDimensions(dim, pathMap);
|
|
74
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
75
|
+
const metaDimension = inputs[i].dimensionMetadata;
|
|
76
|
+
if (!metaDimension) continue;
|
|
77
|
+
await this.addDimensionMetadata(metaDimension.path, metaDimension.icon, metaDimension.label, metaDimension.description);
|
|
78
|
+
}
|
|
79
|
+
const sourcePaths = inputs.map((input) => input.source);
|
|
80
|
+
this._subscriptionManager.notifySubscribers(sourcePaths);
|
|
81
|
+
}
|
|
82
|
+
_formatQueryRecords(records, dimensions) {
|
|
83
|
+
return records.map((r) => {
|
|
84
|
+
const result = {
|
|
85
|
+
id: r.id,
|
|
86
|
+
source: AnalyticsPath.fromString(r.source.slice(0, -1)),
|
|
87
|
+
start: DateTime.fromJSDate(r.start),
|
|
88
|
+
end: r.end ? DateTime.fromJSDate(r.end) : null,
|
|
89
|
+
metric: r.metric,
|
|
90
|
+
value: r.value,
|
|
91
|
+
unit: r.unit,
|
|
92
|
+
fn: r.fn,
|
|
93
|
+
params: r.params,
|
|
94
|
+
dimensions: {}
|
|
95
|
+
};
|
|
96
|
+
dimensions.forEach((d) => result.dimensions[d] = {
|
|
97
|
+
path: AnalyticsPath.fromString(r[`dim_${d}`] ? r[`dim_${d}`].slice(0, -1) : "?"),
|
|
98
|
+
icon: r[`dim_icon`] ? r[`dim_icon`] : "",
|
|
99
|
+
label: r[`dim_label`] ? r[`dim_label`] : "",
|
|
100
|
+
description: r[`dim_description`] ? r[`dim_description`] : ""
|
|
101
|
+
});
|
|
102
|
+
return result;
|
|
103
|
+
}).sort((a, b) => a.id - b.id);
|
|
104
|
+
}
|
|
105
|
+
_buildViewQuery(name, dimensions, metrics, units, until) {
|
|
106
|
+
const baseQuery = this._knex("AnalyticsSeries as AS_inner").select("*").whereIn("metric", metrics);
|
|
107
|
+
for (const dimension of dimensions) baseQuery.select(this._buildDimensionQuery(dimension));
|
|
108
|
+
if (units && units.length > 0 && units[0] !== "") baseQuery.whereIn("unit", units);
|
|
109
|
+
if (until) baseQuery.where("start", "<", until.toISO());
|
|
110
|
+
return `(${baseQuery.toString()}) AS "${name}"`;
|
|
111
|
+
}
|
|
112
|
+
_buildDimensionQuery(dimension) {
|
|
113
|
+
const seriesIdRef = this._knex.ref("AS_inner.id");
|
|
114
|
+
return this._knex("AnalyticsSeries_AnalyticsDimension as ASAD").leftJoin("AnalyticsDimension as AD", "AD.id", "ASAD.dimensionId").where("ASAD.seriesId", seriesIdRef).where("AD.dimension", dimension).select("path").as(`dim_${dimension}`);
|
|
115
|
+
}
|
|
116
|
+
async _linkDimensions(dimension, pathMap) {
|
|
117
|
+
const query = this._knex("AnalyticsDimension").select("path", "id").where("dimension", dimension).whereIn("path", Object.keys(pathMap));
|
|
118
|
+
const dimensionIds = await this._executor.execute(query);
|
|
119
|
+
for (const [path, ids] of Object.entries(pathMap)) {
|
|
120
|
+
const i = dimensionIds.findIndex((record) => record.path == path);
|
|
121
|
+
const dimensionId = i < 0 ? await this._createDimensionPath(dimension, path) : dimensionIds[i].id;
|
|
122
|
+
for (let j = 0; j < ids.length; j++) {
|
|
123
|
+
const query = this._knex("AnalyticsSeries_AnalyticsDimension").insert({
|
|
124
|
+
seriesId: ids[j],
|
|
125
|
+
dimensionId
|
|
126
|
+
});
|
|
127
|
+
await this._executor.execute(query);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async _createDimensionPath(dimension, path) {
|
|
132
|
+
const query = this._knex("AnalyticsDimension").insert({
|
|
133
|
+
dimension,
|
|
134
|
+
path
|
|
135
|
+
}, "id");
|
|
136
|
+
return (await this._executor.execute(query))[0].id;
|
|
137
|
+
}
|
|
138
|
+
async addDimensionMetadata(path, icon, label, description) {
|
|
139
|
+
if (!icon && !label && !description) return;
|
|
140
|
+
const query = this._knex("AnalyticsDimension").where("path", `${path.toString()}/`).update({
|
|
141
|
+
icon: icon ? icon : "",
|
|
142
|
+
label: label ? label : "",
|
|
143
|
+
description: description ? description : ""
|
|
144
|
+
});
|
|
145
|
+
await this._executor.execute(query);
|
|
146
|
+
}
|
|
147
|
+
async getDimensions() {
|
|
148
|
+
const query = this._knex.select("dimension", "path", "icon", "label", "description").from("AnalyticsDimension").whereNotNull("path").whereNot("path", "").whereNot("path", "/");
|
|
149
|
+
const grouped = (await this._executor.execute(query)).reduce((acc, row) => {
|
|
150
|
+
if (!acc[row.dimension]) acc[row.dimension] = {
|
|
151
|
+
name: row.dimension,
|
|
152
|
+
values: []
|
|
153
|
+
};
|
|
154
|
+
acc[row.dimension].values.push({
|
|
155
|
+
path: row.path,
|
|
156
|
+
icon: row.icon,
|
|
157
|
+
label: row.label,
|
|
158
|
+
description: row.description
|
|
159
|
+
});
|
|
160
|
+
return acc;
|
|
161
|
+
}, {});
|
|
162
|
+
return Object.values(grouped);
|
|
163
|
+
}
|
|
164
|
+
async getMetrics() {
|
|
165
|
+
const query = this._knex("AnalyticsSeries").select("metric").distinct().whereNotNull("metric");
|
|
166
|
+
const filtered = (await this._executor.execute(query)).map((l) => l.metric);
|
|
167
|
+
[
|
|
168
|
+
"Budget",
|
|
169
|
+
"Forecast",
|
|
170
|
+
"Actuals",
|
|
171
|
+
"PaymentsOnChain",
|
|
172
|
+
"PaymentsOffChainIncluded"
|
|
173
|
+
].forEach((metric) => {
|
|
174
|
+
if (!filtered.includes(metric)) filtered.push(metric);
|
|
175
|
+
});
|
|
176
|
+
return filtered;
|
|
177
|
+
}
|
|
178
|
+
async getCurrencies() {
|
|
179
|
+
const query = this._knex("AnalyticsSeries").select("unit").distinct().whereNotNull("unit");
|
|
180
|
+
return (await this._executor.execute(query)).map((c) => c.unit);
|
|
181
|
+
}
|
|
182
|
+
subscribeToSource(path, callback) {
|
|
183
|
+
return this._subscriptionManager.subscribeToPath(path, callback);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/KnexQueryExecutor.ts
|
|
188
|
+
var KnexQueryExecutor = class {
|
|
189
|
+
_index = 0;
|
|
190
|
+
constructor(_queryLogger, _resultsLogger, _profiler) {
|
|
191
|
+
this._queryLogger = _queryLogger;
|
|
192
|
+
this._resultsLogger = _resultsLogger;
|
|
193
|
+
this._profiler = _profiler;
|
|
194
|
+
if (this._profiler) this._profiler.push("Knex");
|
|
195
|
+
}
|
|
196
|
+
async execute(query) {
|
|
197
|
+
const index = this._index++;
|
|
198
|
+
if (this._queryLogger) this._queryLogger(index, query.toString());
|
|
199
|
+
let results;
|
|
200
|
+
if (this._profiler) results = await this._profiler.record("Query", async () => await query);
|
|
201
|
+
else results = await query;
|
|
202
|
+
if (this._resultsLogger) this._resultsLogger(index, results);
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
//#endregion
|
|
207
|
+
export { KnexAnalyticsStore, KnexQueryExecutor };
|
|
208
|
+
|
|
209
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/KnexAnalyticsStore.ts","../src/KnexQueryExecutor.ts"],"sourcesContent":["import {\n AnalyticsPath,\n AnalyticsSubscriptionManager,\n type AnalyticsDimension,\n type AnalyticsSeries,\n type AnalyticsSeriesInput,\n type AnalyticsSeriesQuery,\n type AnalyticsUpdateCallback,\n type IAnalyticsStore,\n} from \"@powerhousedao/analytics-engine-core\";\nimport { pascalCase } from \"change-case\";\nimport type { Knex } from \"knex\";\nimport { DateTime } from \"luxon\";\n\ntype DimensionsMap = Record<string, Record<string, number[]>>;\n\nexport type AnalyticsSeriesRecord = {\n id: number;\n source: string;\n start: Date;\n end: Date | null;\n metric: string;\n value: number;\n unit: string | null;\n fn: string;\n params: Record<string, any> | null;\n [dimension: `dim_${string}`]: string;\n dimensionMetadata?: Record<string, string>;\n};\n\n/**\n * Using an interface here, so that a null implementation can be used in production,\n * without the added overhead of calling toString().\n */\nexport interface IQuery {\n toString(): string;\n}\n\nexport interface IKnexQueryExecutor {\n execute<T extends {}, U>(query: Knex.QueryBuilder<T, U>): Promise<any>;\n}\n\nexport type KnexAnalyticsStoreOptions = {\n executor: IKnexQueryExecutor;\n knex: Knex;\n};\n\nexport class KnexAnalyticsStore implements IAnalyticsStore {\n protected readonly _executor: IKnexQueryExecutor;\n protected readonly _knex: Knex;\n private readonly _subscriptionManager: AnalyticsSubscriptionManager =\n new AnalyticsSubscriptionManager();\n\n public constructor({ executor, knex }: KnexAnalyticsStoreOptions) {\n this._executor = executor;\n this._knex = knex;\n }\n\n public destroy() {\n this._knex.destroy();\n }\n\n public async clearSeriesBySource(\n source: AnalyticsPath,\n cleanUpDimensions: boolean = false,\n ): Promise<number> {\n const query = this._knex(\"AnalyticsSeries\")\n .whereLike(\"source\", source.toString(\"/%\"))\n .delete();\n\n let result: number = await this._executor.execute(query);\n\n if (cleanUpDimensions) {\n result += await this.clearEmptyAnalyticsDimensions();\n }\n\n this._subscriptionManager.notifySubscribers([source]);\n\n return result;\n }\n\n public async clearEmptyAnalyticsDimensions() {\n const query = this._knex(\"AnalyticsDimension AS AD\")\n .whereNotExists((q) =>\n q\n .select(\"*\")\n .from(\"AnalyticsSeries_AnalyticsDimension AS ASAD\")\n .where(\"ASAD.dimensionId\", this._knex.ref(\"AD.id\")),\n )\n .delete();\n\n return await this._executor.execute(query);\n }\n\n public async getMatchingSeries(\n query: AnalyticsSeriesQuery,\n ): Promise<AnalyticsSeries[]> {\n const units = query.currency ? query.currency.firstSegment().filters : null;\n const analyticsView = this._buildViewQuery(\n \"AV\",\n Object.keys(query.select),\n query.metrics.map((m) => m),\n units,\n query.end,\n );\n\n const baseQuery = this._knex<AnalyticsSeriesRecord>(\n this._knex.raw(analyticsView),\n ).select(\"AV.*\");\n\n // Add dimension filter(s)\n for (const [dimension, paths] of Object.entries(query.select)) {\n baseQuery.leftJoin(`AnalyticsDimension as ${dimension}`, (q) => {\n q.on(`${dimension}.path`, `dim_${dimension}`);\n });\n baseQuery.select(`${dimension}.icon as dim_icon`);\n baseQuery.select(`${dimension}.description as dim_description`);\n baseQuery.select(`${dimension}.label as dim_label`);\n if (paths.length == 1) {\n baseQuery.andWhereLike(`dim_${dimension}`, paths[0].toString(\"/%\"));\n } else if (paths.length > 1) {\n baseQuery.andWhere((q) => {\n paths.forEach((p) =>\n q.orWhereLike(`dim_${dimension}`, p.toString(\"/%\")),\n );\n return q;\n });\n }\n }\n baseQuery.orderBy(\"start\");\n\n const results = await this._executor.execute(baseQuery);\n return this._formatQueryRecords(results, Object.keys(query.select));\n }\n\n public async addSeriesValue(input: AnalyticsSeriesInput) {\n return this.addSeriesValues([input]);\n }\n\n public async addSeriesValues(inputs: AnalyticsSeriesInput[]) {\n const dimensionsMap: DimensionsMap = {};\n\n for (let i = 0; i < inputs.length; i++) {\n const input = inputs[i];\n const query = this._knex<AnalyticsSeriesRecord>(\"AnalyticsSeries\").insert(\n {\n start: input.start.toJSDate(),\n end: input.end ? input.end.toJSDate() : null,\n source: input.source.toString(\"/\"),\n metric: pascalCase(input.metric),\n value: input.value,\n unit: input.unit || null,\n fn: input.fn || \"Single\",\n params: input.params || null,\n },\n \"id\",\n );\n\n const record = await this._executor.execute(query);\n for (const [dim, path] of Object.entries(inputs[i].dimensions || {})) {\n if (!dimensionsMap[dim]) {\n dimensionsMap[dim] = {};\n }\n\n const pKey = path.toString(\"/\");\n if (!dimensionsMap[dim][pKey]) {\n dimensionsMap[dim][pKey] = [];\n }\n\n dimensionsMap[dim][pKey].push(record[0].id);\n }\n }\n\n for (const [dim, pathMap] of Object.entries(dimensionsMap)) {\n await this._linkDimensions(dim, pathMap);\n }\n\n // Adding dimension metadata\n for (let i = 0; i < inputs.length; i++) {\n const metaDimension: any = inputs[i].dimensionMetadata;\n if (!metaDimension) {\n continue;\n }\n await this.addDimensionMetadata(\n metaDimension.path,\n metaDimension.icon,\n metaDimension.label,\n metaDimension.description,\n );\n }\n\n // notify subscribers about updates\n const sourcePaths = inputs.map((input) => input.source);\n this._subscriptionManager.notifySubscribers(sourcePaths);\n }\n\n private _formatQueryRecords(\n records: AnalyticsSeriesRecord[],\n dimensions: string[],\n ): AnalyticsSeries[] {\n const formatted = records.map((r: AnalyticsSeriesRecord) => {\n const result = {\n id: r.id,\n source: AnalyticsPath.fromString(r.source.slice(0, -1)),\n start: DateTime.fromJSDate(r.start),\n end: r.end ? DateTime.fromJSDate(r.end) : null,\n metric: r.metric,\n value: r.value,\n unit: r.unit,\n fn: r.fn,\n params: r.params,\n dimensions: {} as Record<string, AnalyticsDimension>,\n };\n\n dimensions.forEach(\n (d) =>\n (result.dimensions[d] = {\n path: AnalyticsPath.fromString(\n r[`dim_${d}`] ? r[`dim_${d}`].slice(0, -1) : \"?\",\n ),\n icon: r[`dim_icon`] ? r[`dim_icon`] : \"\",\n label: r[`dim_label`] ? r[`dim_label`] : \"\",\n description: r[`dim_description`] ? r[`dim_description`] : \"\",\n }),\n );\n return result;\n });\n\n // sort by id\n return formatted.sort((a, b) => a.id - b.id);\n }\n\n private _buildViewQuery(\n name: string,\n dimensions: string[],\n metrics: string[],\n units: string[] | null,\n until: DateTime | null,\n ) {\n const baseQuery = this._knex(\"AnalyticsSeries as AS_inner\")\n .select(\"*\")\n .whereIn(\"metric\", metrics);\n\n for (const dimension of dimensions) {\n baseQuery.select(this._buildDimensionQuery(dimension));\n }\n\n if (units && units.length > 0 && units[0] !== \"\") {\n baseQuery.whereIn(\"unit\", units);\n }\n\n if (until) {\n baseQuery.where(\"start\", \"<\", until.toISO());\n }\n\n return `(${baseQuery.toString()}) AS \"${name}\"`;\n }\n\n private _buildDimensionQuery(dimension: string) {\n const seriesIdRef = this._knex.ref(\"AS_inner.id\");\n\n return this._knex(\"AnalyticsSeries_AnalyticsDimension as ASAD\")\n .leftJoin(\"AnalyticsDimension as AD\", \"AD.id\", \"ASAD.dimensionId\")\n .where(\"ASAD.seriesId\", seriesIdRef)\n .where(\"AD.dimension\", dimension)\n .select(\"path\")\n .as(`dim_${dimension}`);\n }\n\n private async _linkDimensions(\n dimension: string,\n pathMap: Record<string, number[]>,\n ) {\n const query = this._knex(\"AnalyticsDimension\")\n .select(\"path\", \"id\")\n .where(\"dimension\", dimension)\n .whereIn(\"path\", Object.keys(pathMap));\n\n const dimensionIds = await this._executor.execute(query);\n\n for (const [path, ids] of Object.entries(pathMap)) {\n const i = dimensionIds.findIndex((record: any) => record.path == path);\n\n const dimensionId =\n i < 0\n ? await this._createDimensionPath(dimension, path)\n : dimensionIds[i].id;\n\n for (let j = 0; j < ids.length; j++) {\n const query = this._knex(\"AnalyticsSeries_AnalyticsDimension\").insert({\n seriesId: ids[j],\n dimensionId,\n });\n\n await this._executor.execute(query);\n }\n }\n }\n\n private async _createDimensionPath(dimension: string, path: string) {\n const query = this._knex(\"AnalyticsDimension\").insert(\n { dimension, path },\n \"id\",\n );\n\n const result = await this._executor.execute(query);\n return result[0].id;\n }\n\n private async addDimensionMetadata(\n path: string,\n icon: string | null | undefined,\n label: string | null | undefined,\n description: string | null | undefined,\n ) {\n if (!icon && !label && !description) {\n return;\n }\n const query = this._knex(\"AnalyticsDimension\")\n .where(\"path\", `${path.toString()}/`)\n .update({\n icon: icon ? icon : \"\",\n label: label ? label : \"\",\n description: description ? description : \"\",\n });\n\n await this._executor.execute(query);\n }\n\n public async getDimensions() {\n // Fetch all rows from the database\n const query = this._knex\n .select(\"dimension\", \"path\", \"icon\", \"label\", \"description\")\n .from(\"AnalyticsDimension\")\n .whereNotNull(\"path\")\n .whereNot(\"path\", \"\")\n .whereNot(\"path\", \"/\");\n\n const rows = await this._executor.execute(query);\n\n // Process the rows to group them by dimension and format them\n const grouped = rows.reduce((acc: any, row: any) => {\n // If the dimension is not yet in the accumulator, add it\n if (!acc[row.dimension]) {\n acc[row.dimension] = {\n name: row.dimension,\n values: [],\n };\n }\n\n // Add the path, icon, label, and description to the dimension's values\n acc[row.dimension].values.push({\n path: row.path,\n icon: row.icon,\n label: row.label,\n description: row.description,\n });\n\n return acc;\n }, {});\n\n // Convert the grouped object to an array\n const dimensionPaths: any = Object.values(grouped);\n return dimensionPaths;\n }\n\n public async getMetrics() {\n const query = this._knex(\"AnalyticsSeries\")\n .select(\"metric\")\n .distinct()\n .whereNotNull(\"metric\");\n\n const list = await this._executor.execute(query);\n const filtered = list.map((l: any) => l.metric);\n const metrics = [\n \"Budget\",\n \"Forecast\",\n \"Actuals\",\n \"PaymentsOnChain\",\n \"PaymentsOffChainIncluded\",\n ];\n metrics.forEach((metric) => {\n if (!filtered.includes(metric)) {\n filtered.push(metric);\n }\n });\n return filtered;\n }\n\n public async getCurrencies() {\n const query = this._knex(\"AnalyticsSeries\")\n .select(\"unit\")\n .distinct()\n .whereNotNull(\"unit\");\n\n const currencies = await this._executor.execute(query);\n return currencies.map((c: any) => c.unit);\n }\n\n public subscribeToSource(\n path: AnalyticsPath,\n callback: AnalyticsUpdateCallback,\n ): () => void {\n return this._subscriptionManager.subscribeToPath(path, callback);\n }\n}\n","import { type IAnalyticsProfiler } from \"@powerhousedao/analytics-engine-core\";\nimport type { Knex } from \"knex\";\nimport { type IKnexQueryExecutor } from \"./KnexAnalyticsStore.js\";\n\nexport class KnexQueryExecutor implements IKnexQueryExecutor {\n private _index: number = 0;\n\n constructor(\n private readonly _queryLogger?: (index: number, query: string) => void,\n private readonly _resultsLogger?: (index: number, results: any) => void,\n private readonly _profiler?: IAnalyticsProfiler,\n ) {\n if (this._profiler) {\n this._profiler.push(\"Knex\");\n }\n }\n\n async execute<T extends object, U>(\n query: Knex.QueryBuilder<T, U>,\n ): Promise<any> {\n const index = this._index++;\n\n if (this._queryLogger) {\n this._queryLogger(index, query.toString());\n }\n\n let results;\n if (this._profiler) {\n // profile the query\n results = await this._profiler.record(\"Query\", async () => await query);\n } else {\n results = await query;\n }\n\n if (this._resultsLogger) {\n this._resultsLogger(index, results);\n }\n\n return results;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/analytics-engine-knex",
|
|
3
|
-
"version": "6.0.0-dev.
|
|
3
|
+
"version": "6.0.0-dev.107",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,25 +12,29 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"types": "./dist/
|
|
16
|
-
"import": "./dist/
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"dist
|
|
20
|
+
"dist"
|
|
21
21
|
],
|
|
22
|
-
"
|
|
22
|
+
"dependencies": {
|
|
23
23
|
"date-fns": "4.1.0",
|
|
24
24
|
"knex": "3.1.0",
|
|
25
25
|
"luxon": "3.7.2",
|
|
26
26
|
"pg": "8.18.0",
|
|
27
|
+
"change-case": "5.4.4",
|
|
28
|
+
"@powerhousedao/analytics-engine-core": "6.0.0-dev.107"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
27
31
|
"@types/pg": "8.16.0",
|
|
28
32
|
"vitest": "3.2.4",
|
|
29
33
|
"@types/luxon": "3.7.1",
|
|
30
|
-
"
|
|
34
|
+
"tsdown": "0.21.0"
|
|
31
35
|
},
|
|
32
36
|
"scripts": {
|
|
33
|
-
"build:bundle": "
|
|
37
|
+
"build:bundle": "tsdown",
|
|
34
38
|
"test": "vitest --run ./**/*.test.ts"
|
|
35
39
|
}
|
|
36
40
|
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { Knex } from "knex";
|
|
2
|
-
import { AnalyticsPath, type AnalyticsSeries, type AnalyticsSeriesInput, type AnalyticsSeriesQuery, type IAnalyticsStore, type AnalyticsUpdateCallback } 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 type KnexAnalyticsStoreOptions = {
|
|
27
|
-
executor: IKnexQueryExecutor;
|
|
28
|
-
knex: Knex;
|
|
29
|
-
};
|
|
30
|
-
export declare class KnexAnalyticsStore implements IAnalyticsStore {
|
|
31
|
-
protected readonly _executor: IKnexQueryExecutor;
|
|
32
|
-
protected readonly _knex: Knex;
|
|
33
|
-
private readonly _subscriptionManager;
|
|
34
|
-
constructor({ executor, knex }: KnexAnalyticsStoreOptions);
|
|
35
|
-
destroy(): void;
|
|
36
|
-
clearSeriesBySource(source: AnalyticsPath, cleanUpDimensions?: boolean): Promise<number>;
|
|
37
|
-
clearEmptyAnalyticsDimensions(): Promise<any>;
|
|
38
|
-
getMatchingSeries(query: AnalyticsSeriesQuery): Promise<AnalyticsSeries[]>;
|
|
39
|
-
addSeriesValue(input: AnalyticsSeriesInput): Promise<void>;
|
|
40
|
-
addSeriesValues(inputs: AnalyticsSeriesInput[]): Promise<void>;
|
|
41
|
-
private _formatQueryRecords;
|
|
42
|
-
private _buildViewQuery;
|
|
43
|
-
private _buildDimensionQuery;
|
|
44
|
-
private _linkDimensions;
|
|
45
|
-
private _createDimensionPath;
|
|
46
|
-
private addDimensionMetadata;
|
|
47
|
-
getDimensions(): Promise<any>;
|
|
48
|
-
getMetrics(): Promise<any>;
|
|
49
|
-
getCurrencies(): Promise<any>;
|
|
50
|
-
subscribeToSource(path: AnalyticsPath, callback: AnalyticsUpdateCallback): () => void;
|
|
51
|
-
}
|
|
52
|
-
//# sourceMappingURL=KnexAnalyticsStore.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"KnexAnalyticsStore.d.ts","sourceRoot":"","sources":["../../src/KnexAnalyticsStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAE7B,MAAM,sCAAsC,CAAC;AAK9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACnC,CAAC,SAAS,EAAE,OAAO,MAAM,EAAE,GAAG,MAAM,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACxE;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF,qBAAa,kBAAmB,YAAW,eAAe;IACxD,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACjD,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CACA;gBAElB,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,yBAAyB;IAKzD,OAAO;IAID,mBAAmB,CAC9B,MAAM,EAAE,aAAa,EACrB,iBAAiB,GAAE,OAAe,GACjC,OAAO,CAAC,MAAM,CAAC;IAgBL,6BAA6B;IAa7B,iBAAiB,CAC5B,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,eAAe,EAAE,CAAC;IAuChB,cAAc,CAAC,KAAK,EAAE,oBAAoB;IAI1C,eAAe,CAAC,MAAM,EAAE,oBAAoB,EAAE;IAyD3D,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,oBAAoB;YAWd,eAAe;YA8Bf,oBAAoB;YAUpB,oBAAoB;IAoBrB,aAAa;IAqCb,UAAU;IAuBV,aAAa;IAUnB,iBAAiB,CACtB,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,uBAAuB,GAChC,MAAM,IAAI;CAGd"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type IAnalyticsProfiler } from "@powerhousedao/analytics-engine-core";
|
|
2
|
-
import type { Knex } from "knex";
|
|
3
|
-
import { type IKnexQueryExecutor } from "./KnexAnalyticsStore.js";
|
|
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 object, U>(query: Knex.QueryBuilder<T, U>): Promise<any>;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=KnexQueryExecutor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"KnexQueryExecutor.d.ts","sourceRoot":"","sources":["../../src/KnexQueryExecutor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,qBAAa,iBAAkB,YAAW,kBAAkB;IAIxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAL7B,OAAO,CAAC,MAAM,CAAa;gBAGR,YAAY,CAAC,GAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,aAAA,EACrD,cAAc,CAAC,GAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,aAAA,EACtD,SAAS,CAAC,EAAE,kBAAkB,YAAA;IAO3C,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAC/B,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,OAAO,CAAC,GAAG,CAAC;CAqBhB"}
|
package/dist/src/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export * from "./KnexAnalyticsStore.js";
|
|
2
|
-
export { KnexQueryExecutor } from "./KnexQueryExecutor.js";
|
|
3
|
-
export type { IKnexQueryExecutor, KnexAnalyticsStoreOptions, } from "./KnexAnalyticsStore.js";
|
|
4
|
-
export type { SqlQueryLogger, SqlResultsLogger } from "./util.js";
|
|
5
|
-
export { defaultQueryLogger, defaultResultsLogger } from "./util.js";
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EACV,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|