@happyvertical/smrt-reports 0.37.2 → 0.37.4
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/aggregate.js +1 -5
- package/dist/compiler.js +138 -185
- package/dist/compiler.js.map +1 -1
- package/dist/decorators.js +53 -68
- package/dist/decorators.js.map +1 -1
- package/dist/index.js +80 -152
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/refresh.js +423 -667
- package/dist/refresh.js.map +1 -1
- package/dist/scheduler.js +330 -395
- package/dist/scheduler.js.map +1 -1
- package/dist/smrt-knowledge.json +7 -7
- package/dist/state.js +305 -305
- package/dist/state.js.map +1 -1
- package/dist/types.js +0 -2
- package/package.json +9 -9
- package/dist/aggregate.js.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,162 +1,90 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { bucketExpr, buildAggregate } from "@happyvertical/sql";
|
|
3
|
-
import { buildReportDefinition } from "./compiler.js";
|
|
4
|
-
import { compileReportDefinition, compileReportSpec, getReportGroupingColumns } from "./compiler.js";
|
|
1
|
+
import { bucketExpr, buildAggregate } from "./aggregate.js";
|
|
5
2
|
import { aggregate, avg, count, day, getRuntimeReportOptions, groupBy, hour, max, min, minute, month, quarter, report, sum, week, year } from "./decorators.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { buildReportDefinition, compileReportDefinition, compileReportSpec, getReportGroupingColumns } from "./compiler.js";
|
|
4
|
+
import { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, SmrtReportLock, SmrtReportLockCollection, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, assertReportTablesReady, scopeKeyForTenant } from "./state.js";
|
|
5
|
+
import { refreshReport, reportRowIdentity } from "./refresh.js";
|
|
6
|
+
import { ReportScheduleRunner, SmrtReportRefreshTask, enqueueReportRefresh, ensureReportRefreshSchedules, registerReportRefreshInterceptor } from "./scheduler.js";
|
|
7
|
+
import { validateColumnName } from "@happyvertical/sql";
|
|
8
|
+
import { ObjectRegistry, SmrtCollection, SmrtObject } from "@happyvertical/smrt-core";
|
|
9
9
|
import { toSnakeCase } from "@happyvertical/smrt-core/utils";
|
|
10
10
|
import { getTenantId } from "@happyvertical/smrt-tenancy";
|
|
11
|
-
|
|
12
|
-
import { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, SmrtReportLock, SmrtReportLockCollection, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, assertReportTablesReady, scopeKeyForTenant } from "./state.js";
|
|
11
|
+
//#region src/report.ts
|
|
13
12
|
function registryColumnName(fieldName, field) {
|
|
14
|
-
|
|
15
|
-
field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName)
|
|
16
|
-
);
|
|
13
|
+
return validateColumnName(field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName));
|
|
17
14
|
}
|
|
18
15
|
function findFieldColumn(fields, fieldName) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return registryColumnName(name, field);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return validateColumnName(requestedColumn);
|
|
16
|
+
const direct = fields.get(fieldName);
|
|
17
|
+
if (direct) return registryColumnName(fieldName, direct);
|
|
18
|
+
const requestedColumn = toSnakeCase(fieldName);
|
|
19
|
+
for (const [name, field] of fields.entries()) if (toSnakeCase(name) === requestedColumn) return registryColumnName(name, field);
|
|
20
|
+
return validateColumnName(requestedColumn);
|
|
28
21
|
}
|
|
29
22
|
function findTenantColumn(fields, configuredField) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
for (const [fieldName, field] of fields.entries()) {
|
|
34
|
-
if (fieldName === "tenantId" || field?._meta?.__tenancy?.isTenantIdField) {
|
|
35
|
-
return registryColumnName(fieldName, field);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
class SmrtReport extends SmrtObject {
|
|
41
|
-
static _isReportBase = true;
|
|
42
|
-
refreshedAt = null;
|
|
43
|
-
constructor(options = {}) {
|
|
44
|
-
super(options);
|
|
45
|
-
if (options.refreshedAt !== void 0) {
|
|
46
|
-
this.refreshedAt = options.refreshedAt instanceof Date ? options.refreshedAt : options.refreshedAt ? new Date(options.refreshedAt) : null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
isStale(ttlMs) {
|
|
50
|
-
if (!this.refreshedAt) return true;
|
|
51
|
-
if (ttlMs === void 0) return false;
|
|
52
|
-
return Date.now() - this.refreshedAt.getTime() > ttlMs;
|
|
53
|
-
}
|
|
54
|
-
async refresh(options = {}) {
|
|
55
|
-
const result = await refreshReport(this.constructor, {
|
|
56
|
-
...options,
|
|
57
|
-
db: this.db
|
|
58
|
-
});
|
|
59
|
-
this.refreshedAt = result.refreshedAt;
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
23
|
+
if (configuredField) return registryColumnName(configuredField, fields.get(configuredField));
|
|
24
|
+
for (const [fieldName, field] of fields.entries()) if (fieldName === "tenantId" || field?._meta?.__tenancy?.isTenantIdField) return registryColumnName(fieldName, field);
|
|
25
|
+
return null;
|
|
62
26
|
}
|
|
63
|
-
class
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
SmrtReportCollection,
|
|
123
|
-
SmrtReportLock,
|
|
124
|
-
SmrtReportLockCollection,
|
|
125
|
-
SmrtReportRefreshTask,
|
|
126
|
-
SmrtReportRun,
|
|
127
|
-
SmrtReportRunCollection,
|
|
128
|
-
SmrtReportSchedule,
|
|
129
|
-
SmrtReportScheduleCollection,
|
|
130
|
-
SmrtReportWatermark,
|
|
131
|
-
SmrtReportWatermarkCollection,
|
|
132
|
-
aggregate,
|
|
133
|
-
assertReportTablesReady,
|
|
134
|
-
avg,
|
|
135
|
-
bucketExpr,
|
|
136
|
-
buildAggregate,
|
|
137
|
-
buildReportDefinition,
|
|
138
|
-
compileReportDefinition,
|
|
139
|
-
compileReportSpec,
|
|
140
|
-
count,
|
|
141
|
-
day,
|
|
142
|
-
enqueueReportRefresh,
|
|
143
|
-
ensureReportRefreshSchedules,
|
|
144
|
-
getReportGroupingColumns,
|
|
145
|
-
getRuntimeReportOptions,
|
|
146
|
-
groupBy,
|
|
147
|
-
hour,
|
|
148
|
-
max,
|
|
149
|
-
min,
|
|
150
|
-
minute,
|
|
151
|
-
month,
|
|
152
|
-
quarter,
|
|
153
|
-
refreshReport,
|
|
154
|
-
registerReportRefreshInterceptor,
|
|
155
|
-
report,
|
|
156
|
-
reportRowIdentity,
|
|
157
|
-
scopeKeyForTenant,
|
|
158
|
-
sum,
|
|
159
|
-
week,
|
|
160
|
-
year
|
|
27
|
+
var SmrtReport = class extends SmrtObject {
|
|
28
|
+
static _isReportBase = true;
|
|
29
|
+
refreshedAt = null;
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
super(options);
|
|
32
|
+
if (options.refreshedAt !== void 0) this.refreshedAt = options.refreshedAt instanceof Date ? options.refreshedAt : options.refreshedAt ? new Date(options.refreshedAt) : null;
|
|
33
|
+
}
|
|
34
|
+
isStale(ttlMs) {
|
|
35
|
+
if (!this.refreshedAt) return true;
|
|
36
|
+
if (ttlMs === void 0) return false;
|
|
37
|
+
return Date.now() - this.refreshedAt.getTime() > ttlMs;
|
|
38
|
+
}
|
|
39
|
+
async refresh(options = {}) {
|
|
40
|
+
const result = await refreshReport(this.constructor, {
|
|
41
|
+
...options,
|
|
42
|
+
db: this.db
|
|
43
|
+
});
|
|
44
|
+
this.refreshedAt = result.refreshedAt;
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var SmrtReportCollection = class extends SmrtCollection {
|
|
49
|
+
async refreshIfStale() {
|
|
50
|
+
const reportCtor = this.getItemClass();
|
|
51
|
+
const refresh = (await buildReportDefinition(reportCtor)).refresh;
|
|
52
|
+
if (!refresh?.ttl || refresh.manual) return;
|
|
53
|
+
const registered = ObjectRegistry.getClassByConstructor(reportCtor) ?? ObjectRegistry.getClass(reportCtor.name);
|
|
54
|
+
const reportClass = registered?.qualifiedName ?? registered?.name ?? reportCtor.name;
|
|
55
|
+
const tableName = ObjectRegistry.getTableName(reportClass);
|
|
56
|
+
if (!tableName) return;
|
|
57
|
+
const fields = await ObjectRegistry.getAllFields(reportClass);
|
|
58
|
+
const safeTableName = validateColumnName(tableName);
|
|
59
|
+
const refreshedAtColumn = findFieldColumn(fields, "refreshedAt");
|
|
60
|
+
const tenantColumn = findTenantColumn(fields, registered?.tenantScopedConfig?.field);
|
|
61
|
+
const tenantId = getTenantId() ?? null;
|
|
62
|
+
const result = tenantColumn ? await this.db.query(`SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName} WHERE ${tenantColumn} ${tenantId ? "= ?" : "IS NULL"}`, ...tenantId ? [tenantId] : []) : await this.db.query(`SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName}`);
|
|
63
|
+
const refreshedAt = result.rows[0]?.refreshed_at ? new Date(result.rows[0].refreshed_at) : null;
|
|
64
|
+
if (!(!refreshedAt || Date.now() - refreshedAt.getTime() > refresh.ttl)) return;
|
|
65
|
+
await refreshReport(reportCtor, {
|
|
66
|
+
db: this.db,
|
|
67
|
+
mode: refresh.mode ?? "rebuild",
|
|
68
|
+
trigger: "ttl",
|
|
69
|
+
tenantId
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async refresh(options = {}) {
|
|
73
|
+
return refreshReport(this.getItemClass(), {
|
|
74
|
+
...options,
|
|
75
|
+
db: this.db
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async list(options = {}) {
|
|
79
|
+
await this.refreshIfStale();
|
|
80
|
+
return super.list(options);
|
|
81
|
+
}
|
|
82
|
+
async get(filter, options = {}) {
|
|
83
|
+
await this.refreshIfStale();
|
|
84
|
+
return super.get(filter, options);
|
|
85
|
+
}
|
|
161
86
|
};
|
|
162
|
-
//#
|
|
87
|
+
//#endregion
|
|
88
|
+
export { REPORT_LOCKS_TABLE, REPORT_REFRESH_TASKS_TABLE, REPORT_RUNS_TABLE, REPORT_RUNTIME_TABLES, REPORT_SCHEDULER_TABLES, REPORT_SCHEDULES_TABLE, REPORT_WATERMARKS_TABLE, ReportScheduleRunner, SmrtReport, SmrtReportCollection, SmrtReportLock, SmrtReportLockCollection, SmrtReportRefreshTask, SmrtReportRun, SmrtReportRunCollection, SmrtReportSchedule, SmrtReportScheduleCollection, SmrtReportWatermark, SmrtReportWatermarkCollection, aggregate, assertReportTablesReady, avg, bucketExpr, buildAggregate, buildReportDefinition, compileReportDefinition, compileReportSpec, count, day, enqueueReportRefresh, ensureReportRefreshSchedules, getReportGroupingColumns, getRuntimeReportOptions, groupBy, hour, max, min, minute, month, quarter, refreshReport, registerReportRefreshInterceptor, report, reportRowIdentity, scopeKeyForTenant, sum, week, year };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/report.ts"],"sourcesContent":["import {\n ObjectRegistry,\n SmrtCollection,\n SmrtObject,\n type SmrtObjectOptions,\n} from '@happyvertical/smrt-core';\nimport { toSnakeCase } from '@happyvertical/smrt-core/utils';\nimport { getTenantId } from '@happyvertical/smrt-tenancy';\nimport { validateColumnName } from '@happyvertical/sql';\nimport { buildReportDefinition } from './compiler.js';\nimport { refreshReport } from './refresh.js';\nimport type { ReportRefreshOptions, ReportRefreshResult } from './types.js';\n\ntype RegistryField = {\n columnName?: string;\n _meta?: {\n columnName?: string;\n __tenancy?: { isTenantIdField?: boolean };\n };\n};\n\nfunction registryColumnName(fieldName: string, field?: RegistryField): string {\n return validateColumnName(\n field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName),\n );\n}\n\nfunction findFieldColumn(\n fields: Map<string, RegistryField>,\n fieldName: string,\n): string {\n const direct = fields.get(fieldName);\n if (direct) return registryColumnName(fieldName, direct);\n const requestedColumn = toSnakeCase(fieldName);\n for (const [name, field] of fields.entries()) {\n if (toSnakeCase(name) === requestedColumn) {\n return registryColumnName(name, field);\n }\n }\n return validateColumnName(requestedColumn);\n}\n\nfunction findTenantColumn(\n fields: Map<string, RegistryField>,\n configuredField?: string,\n): string | null {\n if (configuredField) {\n return registryColumnName(configuredField, fields.get(configuredField));\n }\n for (const [fieldName, field] of fields.entries()) {\n if (fieldName === 'tenantId' || field?._meta?.__tenancy?.isTenantIdField) {\n return registryColumnName(fieldName, field);\n }\n }\n return null;\n}\n\nexport class SmrtReport extends SmrtObject {\n static readonly _isReportBase = true as const;\n\n refreshedAt: Date | null = null;\n\n constructor(options: SmrtObjectOptions = {}) {\n super(options);\n if (options.refreshedAt !== undefined) {\n this.refreshedAt =\n options.refreshedAt instanceof Date\n ? options.refreshedAt\n : options.refreshedAt\n ? new Date(options.refreshedAt)\n : null;\n }\n }\n\n isStale(ttlMs?: number): boolean {\n if (!this.refreshedAt) return true;\n if (ttlMs === undefined) return false;\n return Date.now() - this.refreshedAt.getTime() > ttlMs;\n }\n\n async refresh(\n options: Omit<ReportRefreshOptions, 'db'> = {},\n ): Promise<ReportRefreshResult> {\n const result = await refreshReport(this.constructor as typeof SmrtReport, {\n ...options,\n db: this.db,\n });\n this.refreshedAt = result.refreshedAt;\n return result;\n }\n}\n\nexport class SmrtReportCollection<\n ModelType extends SmrtReport,\n> extends SmrtCollection<ModelType> {\n private async refreshIfStale(): Promise<void> {\n const reportCtor = this.getItemClass();\n const definition = await buildReportDefinition(reportCtor);\n const refresh = definition.refresh;\n if (!refresh?.ttl || refresh.manual) return;\n\n const registered =\n ObjectRegistry.getClassByConstructor(reportCtor) ??\n ObjectRegistry.getClass(reportCtor.name);\n const reportClass =\n registered?.qualifiedName ?? registered?.name ?? reportCtor.name;\n const tableName = ObjectRegistry.getTableName(reportClass);\n if (!tableName) return;\n\n const fields = (await ObjectRegistry.getAllFields(reportClass)) as Map<\n string,\n RegistryField\n >;\n const safeTableName = validateColumnName(tableName);\n const refreshedAtColumn = findFieldColumn(fields, 'refreshedAt');\n const tenantColumn = findTenantColumn(\n fields,\n registered?.tenantScopedConfig?.field,\n );\n const tenantId = getTenantId() ?? null;\n const result = tenantColumn\n ? await this.db.query(\n `SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName} WHERE ${tenantColumn} ${tenantId ? '= ?' : 'IS NULL'}`,\n ...(tenantId ? [tenantId] : []),\n )\n : await this.db.query(\n `SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName}`,\n );\n const refreshedAt = result.rows[0]?.refreshed_at\n ? new Date(result.rows[0].refreshed_at as string)\n : null;\n const stale =\n !refreshedAt || Date.now() - refreshedAt.getTime() > refresh.ttl;\n if (!stale) return;\n\n await refreshReport(reportCtor, {\n db: this.db,\n mode: refresh.mode ?? 'rebuild',\n trigger: 'ttl',\n tenantId,\n });\n }\n\n async refresh(\n options: Omit<ReportRefreshOptions, 'db'> = {},\n ): Promise<ReportRefreshResult> {\n return refreshReport(this.getItemClass(), {\n ...options,\n db: this.db,\n });\n }\n\n override async list(\n options: Parameters<SmrtCollection<ModelType>['list']>[0] = {},\n ): Promise<ModelType[]> {\n await this.refreshIfStale();\n return super.list(options);\n }\n\n override async get(\n filter: Parameters<SmrtCollection<ModelType>['get']>[0],\n options: Parameters<SmrtCollection<ModelType>['get']>[1] = {},\n ): Promise<ModelType | null> {\n await this.refreshIfStale();\n return super.get(filter, options);\n }\n}\n"],"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/report.ts"],"sourcesContent":["import {\n ObjectRegistry,\n SmrtCollection,\n SmrtObject,\n type SmrtObjectOptions,\n} from '@happyvertical/smrt-core';\nimport { toSnakeCase } from '@happyvertical/smrt-core/utils';\nimport { getTenantId } from '@happyvertical/smrt-tenancy';\nimport { validateColumnName } from '@happyvertical/sql';\nimport { buildReportDefinition } from './compiler.js';\nimport { refreshReport } from './refresh.js';\nimport type { ReportRefreshOptions, ReportRefreshResult } from './types.js';\n\ntype RegistryField = {\n columnName?: string;\n _meta?: {\n columnName?: string;\n __tenancy?: { isTenantIdField?: boolean };\n };\n};\n\nfunction registryColumnName(fieldName: string, field?: RegistryField): string {\n return validateColumnName(\n field?.columnName ?? field?._meta?.columnName ?? toSnakeCase(fieldName),\n );\n}\n\nfunction findFieldColumn(\n fields: Map<string, RegistryField>,\n fieldName: string,\n): string {\n const direct = fields.get(fieldName);\n if (direct) return registryColumnName(fieldName, direct);\n const requestedColumn = toSnakeCase(fieldName);\n for (const [name, field] of fields.entries()) {\n if (toSnakeCase(name) === requestedColumn) {\n return registryColumnName(name, field);\n }\n }\n return validateColumnName(requestedColumn);\n}\n\nfunction findTenantColumn(\n fields: Map<string, RegistryField>,\n configuredField?: string,\n): string | null {\n if (configuredField) {\n return registryColumnName(configuredField, fields.get(configuredField));\n }\n for (const [fieldName, field] of fields.entries()) {\n if (fieldName === 'tenantId' || field?._meta?.__tenancy?.isTenantIdField) {\n return registryColumnName(fieldName, field);\n }\n }\n return null;\n}\n\nexport class SmrtReport extends SmrtObject {\n static readonly _isReportBase = true as const;\n\n refreshedAt: Date | null = null;\n\n constructor(options: SmrtObjectOptions = {}) {\n super(options);\n if (options.refreshedAt !== undefined) {\n this.refreshedAt =\n options.refreshedAt instanceof Date\n ? options.refreshedAt\n : options.refreshedAt\n ? new Date(options.refreshedAt)\n : null;\n }\n }\n\n isStale(ttlMs?: number): boolean {\n if (!this.refreshedAt) return true;\n if (ttlMs === undefined) return false;\n return Date.now() - this.refreshedAt.getTime() > ttlMs;\n }\n\n async refresh(\n options: Omit<ReportRefreshOptions, 'db'> = {},\n ): Promise<ReportRefreshResult> {\n const result = await refreshReport(this.constructor as typeof SmrtReport, {\n ...options,\n db: this.db,\n });\n this.refreshedAt = result.refreshedAt;\n return result;\n }\n}\n\nexport class SmrtReportCollection<\n ModelType extends SmrtReport,\n> extends SmrtCollection<ModelType> {\n private async refreshIfStale(): Promise<void> {\n const reportCtor = this.getItemClass();\n const definition = await buildReportDefinition(reportCtor);\n const refresh = definition.refresh;\n if (!refresh?.ttl || refresh.manual) return;\n\n const registered =\n ObjectRegistry.getClassByConstructor(reportCtor) ??\n ObjectRegistry.getClass(reportCtor.name);\n const reportClass =\n registered?.qualifiedName ?? registered?.name ?? reportCtor.name;\n const tableName = ObjectRegistry.getTableName(reportClass);\n if (!tableName) return;\n\n const fields = (await ObjectRegistry.getAllFields(reportClass)) as Map<\n string,\n RegistryField\n >;\n const safeTableName = validateColumnName(tableName);\n const refreshedAtColumn = findFieldColumn(fields, 'refreshedAt');\n const tenantColumn = findTenantColumn(\n fields,\n registered?.tenantScopedConfig?.field,\n );\n const tenantId = getTenantId() ?? null;\n const result = tenantColumn\n ? await this.db.query(\n `SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName} WHERE ${tenantColumn} ${tenantId ? '= ?' : 'IS NULL'}`,\n ...(tenantId ? [tenantId] : []),\n )\n : await this.db.query(\n `SELECT MAX(${refreshedAtColumn}) AS refreshed_at FROM ${safeTableName}`,\n );\n const refreshedAt = result.rows[0]?.refreshed_at\n ? new Date(result.rows[0].refreshed_at as string)\n : null;\n const stale =\n !refreshedAt || Date.now() - refreshedAt.getTime() > refresh.ttl;\n if (!stale) return;\n\n await refreshReport(reportCtor, {\n db: this.db,\n mode: refresh.mode ?? 'rebuild',\n trigger: 'ttl',\n tenantId,\n });\n }\n\n async refresh(\n options: Omit<ReportRefreshOptions, 'db'> = {},\n ): Promise<ReportRefreshResult> {\n return refreshReport(this.getItemClass(), {\n ...options,\n db: this.db,\n });\n }\n\n override async list(\n options: Parameters<SmrtCollection<ModelType>['list']>[0] = {},\n ): Promise<ModelType[]> {\n await this.refreshIfStale();\n return super.list(options);\n }\n\n override async get(\n filter: Parameters<SmrtCollection<ModelType>['get']>[0],\n options: Parameters<SmrtCollection<ModelType>['get']>[1] = {},\n ): Promise<ModelType | null> {\n await this.refreshIfStale();\n return super.get(filter, options);\n }\n}\n"],"mappings":"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"}
|
package/dist/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"timestamp":
|
|
3
|
+
"timestamp": 1782943594711,
|
|
4
4
|
"packageName": "@happyvertical/smrt-reports",
|
|
5
|
-
"packageVersion": "0.37.
|
|
5
|
+
"packageVersion": "0.37.4",
|
|
6
6
|
"objects": {
|
|
7
7
|
"@happyvertical/smrt-reports:SmrtReport": {
|
|
8
8
|
"name": "smrtreport",
|