@happyvertical/smrt-reports 0.57.35 → 0.57.37
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/AGENTS.md +6 -1
- package/README.md +12 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/chunks/{compiler-IUB2YNgM.js → compiler-CqTiU1S6.js} +69 -13
- package/dist/chunks/compiler-CqTiU1S6.js.map +1 -0
- package/dist/compiler.d.ts +8 -1
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +1 -1
- package/dist/index.js +28 -6
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/refresh.js +2 -2
- package/dist/refresh.js.map +1 -1
- package/dist/registry-columns.d.ts +22 -0
- package/dist/registry-columns.d.ts.map +1 -1
- package/dist/scheduler.js +1 -1
- package/dist/smrt-knowledge.json +7 -7
- package/dist/state.js +1 -1
- package/dist/state.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/views.d.ts.map +1 -1
- package/package.json +10 -10
- package/dist/chunks/compiler-IUB2YNgM.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -39,6 +39,11 @@ component tests. `./playground` supplies each screen's preview.
|
|
|
39
39
|
totals, and dimension facets. At source-query compilation,
|
|
40
40
|
dimension and bucket filters compile to `WHERE`, aggregate-measure filters
|
|
41
41
|
compile to `HAVING`, and mixed `OR`/`NOT` filter scopes fail closed.
|
|
42
|
+
- A column whose materialized schema column is neither `notNull` nor the
|
|
43
|
+
primary key also declares `isNull`/`isNotNull` (#4448), compiled to
|
|
44
|
+
`IS NULL`/`IS NOT NULL`. Report `ne`/`notIn` stay plain `<>` and exclude
|
|
45
|
+
nulls. The null tests are left out of `reportDefinitionFingerprint()`, so
|
|
46
|
+
views stored before them keep their binding.
|
|
42
47
|
- `id` is the only row identity. It must be a non-empty persisted string and is
|
|
43
48
|
never replaced by a display index or page position.
|
|
44
49
|
- The descriptor is an exposure boundary. Sensitive/secret fields, fields with
|
|
@@ -122,7 +127,7 @@ See [core recipes](../core/agents/recipes.md).
|
|
|
122
127
|
|
|
123
128
|
- Report cache tables are normal `@smrt()` tables. Runtime refresh must not create schema.
|
|
124
129
|
- Store report metadata under field `_meta.__report`; scanner and runtime decorators must stay aligned.
|
|
125
|
-
- Joins, row expressions and filtered measures (#3903) compile to the SDK's `AggregateSpec` (`fromAlias`, `joins`, `expr`, `filter`); expressions are literal data nodes because the scanner reads decorator arguments statically. Qualify every source column with `src` once a report joins (refresh filters do), put the tenant match in the join's `ON`, and joined reports rebuild (an incremental request is run as a rebuild), and drilldown refuses joined or computed group keys.
|
|
130
|
+
- Joins, row expressions and filtered measures (#3903) compile to the SDK's `AggregateSpec` (`fromAlias`, `joins`, `expr`, `filter`); expressions are literal data nodes because the scanner reads decorator arguments statically. Qualify every source column with `src` once a report joins (refresh filters do), put the tenant match in the join's `ON`, and joined reports rebuild (an incremental request is run as a rebuild), and drilldown refuses joined or computed group keys. A join key (or tenant pair) that is TEXT against UUID in the merged migration schema (text reference to a uuid id, #4441) compares as `asText` on both sides on every dialect but SQLite; `compileReportDefinition(definition, adapterType)` needs the real adapter for that, and same-typed keys stay uncast.
|
|
126
131
|
- Keep SQL generation portable. Use the SDK `buildAggregate()`/`bucketExpr()` helpers for time buckets and `$N` placeholders.
|
|
127
132
|
- Do not add a local aggregate SQL builder here; the implementation lives in `@happyvertical/sql`.
|
|
128
133
|
- Refresh runtime tables are schema-managed. Runtime refresh must fail clearly when `_smrt_report_runs`, `_smrt_report_watermarks`, or `_smrt_report_locks` have not been migrated.
|
package/README.md
CHANGED
|
@@ -106,6 +106,18 @@ class LabourByWorkOrder extends SmrtReport {
|
|
|
106
106
|
`inner`. Aliases are lower-case identifiers and not `src`. Reference a joined
|
|
107
107
|
field as `alias.field` in `@groupBy`, the aggregate and bucket decorators,
|
|
108
108
|
expressions and `where`.
|
|
109
|
+
- **Key types.** `on` and `to` may be the same type (uuid = uuid, text = text),
|
|
110
|
+
compared as they are so their indexes serve the join, or a text field against a
|
|
111
|
+
uuid one, such as a polymorphic `workRefId` string pointing at a uuid `id`.
|
|
112
|
+
When one column is text and the other uuid in the schema, the join compares both as text
|
|
113
|
+
on PostgreSQL and DuckDB (which would otherwise refuse `text = uuid` or fail on
|
|
114
|
+
a non-uuid value), so a text value that is not a uuid simply matches nothing:
|
|
115
|
+
NULL on a left join, dropped on an inner one. A uuid compares in its canonical
|
|
116
|
+
lower-case form, so a reference stored in upper case does not match. SQLite
|
|
117
|
+
stores both as TEXT and compares them uncast. The cast column cannot use its
|
|
118
|
+
index; for a large table prefer a uuid-typed reference (`@foreignKey()` or
|
|
119
|
+
`@crossPackageRef()`). The same rule applies to the tenant columns. Other
|
|
120
|
+
type pairs (an integer against a decimal, say) are compared as they are.
|
|
109
121
|
- **Tenancy is built into the join.** When the related model is tenant-scoped the
|
|
110
122
|
join also matches `tenant_id` between the two rows, so an id that points at
|
|
111
123
|
another tenant's row never matches. A tenant-scoped join from a source with no
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,37 @@ async function tenantColumn(className) {
|
|
|
15
15
|
for (const [fieldName, field] of fields.entries()) if (field?._meta?.__tenancy?.isTenantIdField) return toSnakeCase(fieldName);
|
|
16
16
|
return await fieldColumn(className, "tenantId");
|
|
17
17
|
}
|
|
18
|
+
function columnTypeReader() {
|
|
19
|
+
let tables;
|
|
20
|
+
const merged = () => {
|
|
21
|
+
if (tables === void 0) try {
|
|
22
|
+
tables = ObjectRegistry.getAllSchemasAsDefinitions();
|
|
23
|
+
} catch {
|
|
24
|
+
tables = null;
|
|
25
|
+
}
|
|
26
|
+
return tables;
|
|
27
|
+
};
|
|
28
|
+
const upper = (type) => typeof type === "string" ? type.toUpperCase() : null;
|
|
29
|
+
return (className, column) => {
|
|
30
|
+
const table = ObjectRegistry.getTableName(className);
|
|
31
|
+
const fromTable = table ? upper(merged()?.[table]?.columns?.[column]?.type) : null;
|
|
32
|
+
if (fromTable) return fromTable;
|
|
33
|
+
const names = [className];
|
|
34
|
+
if (ObjectRegistry.getTableStrategy(className) === "sti") {
|
|
35
|
+
const base = ObjectRegistry.getSTIBase(className);
|
|
36
|
+
if (base) names.push(base);
|
|
37
|
+
}
|
|
38
|
+
for (const name of names) {
|
|
39
|
+
const type = upper(ObjectRegistry.getSchema(name)?.columns?.[column]?.type);
|
|
40
|
+
if (type) return type;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function compareAsText(types, left, right) {
|
|
46
|
+
const pair = [types(left.className, left.column), types(right.className, right.column)];
|
|
47
|
+
return pair.includes("UUID") && pair.includes("TEXT");
|
|
48
|
+
}
|
|
18
49
|
function fieldPolicy(field) {
|
|
19
50
|
const meta = field?._meta ?? {};
|
|
20
51
|
const sensitivity = [field?.sensitivity, meta.sensitivity].find((value) => typeof value === "string");
|
|
@@ -103,6 +134,7 @@ async function resolveJoins(reportName, sourceName, joins) {
|
|
|
103
134
|
const resolved = [];
|
|
104
135
|
if (!joins) return resolved;
|
|
105
136
|
const sourceTenant = await tenantColumn(sourceName);
|
|
137
|
+
const columnType = columnTypeReader();
|
|
106
138
|
for (const [alias, join] of Object.entries(joins)) {
|
|
107
139
|
if (!JOIN_ALIAS.test(alias) || alias === "src" || alias.length > 32) throw new Error(`${reportName} join alias '${alias}' must be lower-case letters, digits and underscores, start with a letter, and not be 'src'`);
|
|
108
140
|
if (!join?.source || typeof join.on !== "string") throw new Error(`${reportName} join '${alias}' needs a source and an on field`);
|
|
@@ -117,6 +149,20 @@ async function resolveJoins(reportName, sourceName, joins) {
|
|
|
117
149
|
const joinedTenant = await tenantColumn(className);
|
|
118
150
|
if (joinedTenant && !sourceTenant) throw new Error(`${reportName} join '${alias}': ${className} is tenant-scoped but ${sourceName} has no tenant field to match it with`);
|
|
119
151
|
const softDelete = await fieldColumn(className, "deletedAt");
|
|
152
|
+
const keyAsText = compareAsText(columnType, {
|
|
153
|
+
className: sourceName,
|
|
154
|
+
column: onColumn
|
|
155
|
+
}, {
|
|
156
|
+
className,
|
|
157
|
+
column: targetColumn
|
|
158
|
+
});
|
|
159
|
+
const tenantAsText = joinedTenant && sourceTenant ? compareAsText(columnType, {
|
|
160
|
+
className: sourceName,
|
|
161
|
+
column: sourceTenant
|
|
162
|
+
}, {
|
|
163
|
+
className,
|
|
164
|
+
column: joinedTenant
|
|
165
|
+
}) : false;
|
|
120
166
|
resolved.push({
|
|
121
167
|
alias,
|
|
122
168
|
className,
|
|
@@ -124,9 +170,11 @@ async function resolveJoins(reportName, sourceName, joins) {
|
|
|
124
170
|
type: join.type ?? "left",
|
|
125
171
|
sourceColumn: onColumn,
|
|
126
172
|
targetColumn,
|
|
173
|
+
...keyAsText ? { keyAsText: true } : {},
|
|
127
174
|
...joinedTenant && sourceTenant ? { tenantColumns: {
|
|
128
175
|
source: sourceTenant,
|
|
129
|
-
joined: joinedTenant
|
|
176
|
+
joined: joinedTenant,
|
|
177
|
+
...tenantAsText ? { asText: true } : {}
|
|
130
178
|
} } : {},
|
|
131
179
|
...softDelete ? { softDeleteColumn: softDelete } : {}
|
|
132
180
|
});
|
|
@@ -253,17 +301,25 @@ function getReportGroupingColumns(definition) {
|
|
|
253
301
|
const columns = definition.fields.filter((field) => field.report?.kind === "group" || field.report?.kind === "bucket").map((field) => field.columnName ?? toSnakeCase(field.fieldName));
|
|
254
302
|
return columns.length > 0 ? columns : ["id"];
|
|
255
303
|
}
|
|
256
|
-
function joinCondition(join) {
|
|
257
|
-
const
|
|
304
|
+
function joinCondition(join, adapterType) {
|
|
305
|
+
const castable = adapterType !== "sqlite";
|
|
306
|
+
const equal = (left, right, asText) => asText && castable ? {
|
|
258
307
|
op: "eq",
|
|
259
|
-
left: {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
308
|
+
left: {
|
|
309
|
+
op: "asText",
|
|
310
|
+
operand: { col: left }
|
|
311
|
+
},
|
|
312
|
+
right: {
|
|
313
|
+
op: "asText",
|
|
314
|
+
operand: { col: right }
|
|
315
|
+
}
|
|
316
|
+
} : {
|
|
263
317
|
op: "eq",
|
|
264
|
-
left: { col:
|
|
265
|
-
right: { col:
|
|
266
|
-
}
|
|
318
|
+
left: { col: left },
|
|
319
|
+
right: { col: right }
|
|
320
|
+
};
|
|
321
|
+
const conditions = [equal(`src.${join.sourceColumn}`, `${join.alias}.${join.targetColumn}`, join.keyAsText)];
|
|
322
|
+
if (join.tenantColumns) conditions.push(equal(`src.${join.tenantColumns.source}`, `${join.alias}.${join.tenantColumns.joined}`, join.tenantColumns.asText));
|
|
267
323
|
if (join.softDeleteColumn) conditions.push({
|
|
268
324
|
op: "isNull",
|
|
269
325
|
operand: { col: `${join.alias}.${join.softDeleteColumn}` }
|
|
@@ -273,7 +329,7 @@ function joinCondition(join) {
|
|
|
273
329
|
operands: conditions
|
|
274
330
|
};
|
|
275
331
|
}
|
|
276
|
-
function compileReportDefinition(definition) {
|
|
332
|
+
function compileReportDefinition(definition, adapterType) {
|
|
277
333
|
const select = [];
|
|
278
334
|
const groupBy = [];
|
|
279
335
|
const reportFieldToColumn = /* @__PURE__ */ new Map();
|
|
@@ -323,7 +379,7 @@ function compileReportDefinition(definition) {
|
|
|
323
379
|
table: join.table,
|
|
324
380
|
alias: join.alias,
|
|
325
381
|
type: join.type,
|
|
326
|
-
on: joinCondition(join)
|
|
382
|
+
on: joinCondition(join, adapterType)
|
|
327
383
|
}))
|
|
328
384
|
} : {},
|
|
329
385
|
select,
|
|
@@ -338,4 +394,4 @@ async function compileReportSpec(reportCtor) {
|
|
|
338
394
|
//#endregion
|
|
339
395
|
export { getReportGroupingColumns as a, tenantColumn as c, compileReportSpec as i, buildReportDefinition as n, fieldColumn as o, compileReportDefinition as r, fieldPolicy as s, REPORT_SOURCE_ALIAS as t };
|
|
340
396
|
|
|
341
|
-
//# sourceMappingURL=compiler-
|
|
397
|
+
//# sourceMappingURL=compiler-CqTiU1S6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler-CqTiU1S6.js","names":[],"sources":["../../src/registry-columns.ts","../../src/compiler.ts"],"sourcesContent":["import { ObjectRegistry } from '@happyvertical/smrt-core';\nimport { toSnakeCase } from '@happyvertical/smrt-core/utils';\n\nexport async function fieldColumn(\n className: string,\n requested: string,\n): Promise<string | null> {\n const fields = await ObjectRegistry.getAllFields(className);\n const requestedColumn = toSnakeCase(requested);\n\n for (const [fieldName] of fields.entries()) {\n if (fieldName === requested || toSnakeCase(fieldName) === requestedColumn) {\n return requestedColumn;\n }\n }\n\n return null;\n}\n\nexport async function tenantColumn(className: string): Promise<string | null> {\n const registered = ObjectRegistry.getClass(className);\n const configuredField = registered?.tenantScopedConfig?.field;\n if (configuredField) {\n return toSnakeCase(configuredField);\n }\n\n const fields = await ObjectRegistry.getAllFields(className);\n for (const [fieldName, field] of fields.entries()) {\n if (field?._meta?.__tenancy?.isTenantIdField) {\n return toSnakeCase(fieldName);\n }\n }\n\n const tenantIdField = await fieldColumn(className, 'tenantId');\n return tenantIdField;\n}\n\ntype SchemaTables = Record<\n string,\n { columns?: Record<string, { type?: unknown }> }\n>;\n\n/**\n * Reads column types for one report build. The tables come from the same\n * merged assembly migration uses (manifest columns plus runtime overlays such\n * as `tenantScoped`'s tenant_id), built at most once per build. If assembling\n * them fails for a reason elsewhere in the registry, types fall back to each\n * class's own built schema, and a column neither describes is unknown.\n */\nexport function columnTypeReader(): (\n className: string,\n column: string,\n) => string | null {\n let tables: SchemaTables | null | undefined;\n const merged = (): SchemaTables | null => {\n if (tables === undefined) {\n try {\n tables = ObjectRegistry.getAllSchemasAsDefinitions() as SchemaTables;\n } catch {\n tables = null;\n }\n }\n return tables;\n };\n const upper = (type: unknown) =>\n typeof type === 'string' ? type.toUpperCase() : null;\n\n return (className, column) => {\n const table = ObjectRegistry.getTableName(className);\n const fromTable = table\n ? upper(merged()?.[table]?.columns?.[column]?.type)\n : null;\n if (fromTable) return fromTable;\n // An STI child's columns live on its base table's schema.\n const names = [className];\n if (ObjectRegistry.getTableStrategy(className) === 'sti') {\n const base = ObjectRegistry.getSTIBase(className);\n if (base) names.push(base);\n }\n for (const name of names) {\n const type = upper(\n ObjectRegistry.getSchema(name)?.columns?.[column]?.type,\n );\n if (type) return type;\n }\n return null;\n };\n}\n\n/**\n * Whether two key columns must be compared as text: one is UUID and the other\n * TEXT (a text reference against a uuid id, which Postgres has no operator\n * for). Every other pair, same-typed, undescribed or another mismatch,\n * compares as it is, so indexes still serve the join and numeric keys are\n * never compared by their text form.\n */\nexport function compareAsText(\n types: (className: string, column: string) => string | null,\n left: { className: string; column: string },\n right: { className: string; column: string },\n): boolean {\n const pair = [\n types(left.className, left.column),\n types(right.className, right.column),\n ];\n return pair.includes('UUID') && pair.includes('TEXT');\n}\n\n/** The registry field properties that decide who may read a column. */\nexport interface PolicyField {\n sensitive?: boolean;\n readPermission?: string;\n sensitivity?: unknown;\n _meta?: Record<string, unknown>;\n}\n\nexport function fieldPolicy(field: PolicyField | undefined): {\n sensitive: boolean;\n readPermission?: string;\n} {\n const meta = field?._meta ?? {};\n const sensitivity = [field?.sensitivity, meta.sensitivity].find(\n (value): value is string => typeof value === 'string',\n );\n return {\n sensitive:\n field?.sensitive === true ||\n meta.sensitive === true ||\n sensitivity === 'sensitive' ||\n sensitivity === 'secret',\n readPermission:\n typeof field?.readPermission === 'string'\n ? field.readPermission\n : typeof meta.readPermission === 'string'\n ? meta.readPermission\n : undefined,\n };\n}\n","import { ObjectRegistry, type SmrtObject } from '@happyvertical/smrt-core';\nimport { toSnakeCase } from '@happyvertical/smrt-core/utils';\nimport type {\n AggregateExpression,\n SqlAdapterType,\n WhereClause,\n} from '@happyvertical/sql';\nimport { getRuntimeReportOptions } from './decorators.js';\nimport {\n columnTypeReader,\n compareAsText,\n fieldColumn,\n fieldPolicy,\n tenantColumn,\n} from './registry-columns.js';\nimport type {\n AggregateSelectExpr,\n AggregateSpec,\n ReportDefinition,\n ReportFieldDefinition,\n ReportFieldMetadata,\n ReportJoinDefinition,\n ReportOperand,\n ReportOptions,\n ReportRelatedFieldPolicy,\n ReportSource,\n} from './types.js';\n\n/** The report source's alias in a query that joins other tables. */\nexport const REPORT_SOURCE_ALIAS = 'src';\n\n/** Lower-case, so snake-casing a column reference leaves the alias alone. */\nconst JOIN_ALIAS = /^[a-z][a-z0-9_]*$/;\n\nconst REPORT_BASE_FIELDS = new Set([\n 'id',\n 'slug',\n 'context',\n 'created_at',\n 'updated_at',\n 'createdAt',\n 'updatedAt',\n 'refreshedAt',\n]);\n\nfunction isConstructor(\n value: ReportSource,\n): value is new (\n ...args: any[]\n) => SmrtObject {\n return typeof value === 'function';\n}\n\nfunction sourceClassName(source: ReportSource): string {\n if (typeof source === 'string') return source;\n return source.name;\n}\n\nfunction reportOptionsFromRegistry(\n reportCtor: new (...args: any[]) => SmrtObject,\n): ReportOptions | undefined {\n const registered =\n ObjectRegistry.getClassByConstructor(reportCtor) ??\n ObjectRegistry.getClass(reportCtor.name);\n return (registered?.config as { report?: ReportOptions } | undefined)?.report;\n}\n\nfunction getReportOptions(\n reportCtor: new (...args: any[]) => SmrtObject,\n): ReportOptions {\n const options =\n getRuntimeReportOptions(reportCtor) ??\n reportOptionsFromRegistry(reportCtor);\n if (!options?.source) {\n throw new Error(\n `${reportCtor.name} is missing @report({ source }) metadata. ` +\n `Decorate the report class with @report({ source: SourceClass }).`,\n );\n }\n return options;\n}\n\nfunction getRegisteredClassName(\n ctor: new (...args: any[]) => SmrtObject,\n): string {\n const registered =\n ObjectRegistry.getClassByConstructor(ctor) ??\n ObjectRegistry.getClass(ctor.name);\n return registered?.qualifiedName ?? registered?.name ?? ctor.name;\n}\n\nfunction resolveTableName(className: string): string {\n const tableName = ObjectRegistry.getTableName(className);\n if (!tableName) {\n throw new Error(\n `No SMRT table registered for ${className}. ` +\n `Ensure the class is decorated with @smrt() and its manifest is loaded.`,\n );\n }\n return tableName;\n}\n\nfunction parseWhereKey(key: string): { field: string; suffix: string } {\n const trimmed = key.trim();\n const operators = [\n ' is not null',\n ' is null',\n ' not in',\n ' like',\n ' in',\n ' !=',\n ' >=',\n ' <=',\n ' >',\n ' <',\n ' =',\n ];\n const lower = trimmed.toLowerCase();\n for (const operator of operators) {\n if (lower.endsWith(operator)) {\n return {\n field: trimmed.slice(0, -operator.length).trim(),\n suffix: operator,\n };\n }\n }\n return { field: trimmed, suffix: '' };\n}\n\nfunction normalizeConditionKey(\n key: string,\n mapField: (field: string) => string,\n): string {\n const { field, suffix } = parseWhereKey(key);\n const mapped = mapField(field);\n return suffix ? `${mapped}${suffix}` : mapped;\n}\n\nfunction normalizeWhere(\n where: WhereClause | undefined,\n mapField: (field: string) => string,\n): WhereClause | undefined {\n if (!where) return undefined;\n\n if (Array.isArray(where)) {\n return where.map((andGroup) =>\n andGroup.map((condition: Record<string, any>) =>\n Object.fromEntries(\n Object.entries(condition).map(([key, value]) => [\n normalizeConditionKey(key, mapField),\n value,\n ]),\n ),\n ),\n );\n }\n\n return Object.fromEntries(\n Object.entries(where).map(([key, value]) => [\n normalizeConditionKey(key, mapField),\n value,\n ]),\n );\n}\n\nfunction readReportMetadata(field: any): ReportFieldMetadata | undefined {\n return field?._meta?.__report ?? field?.__report;\n}\n\nfunction isReportSystemField(fieldName: string, field: any): boolean {\n return (\n REPORT_BASE_FIELDS.has(fieldName) ||\n field?._meta?.__smrtSystemField ||\n field?._meta?.__tenancy?.isTenantIdField\n );\n}\n\nasync function resolveJoins(\n reportName: string,\n sourceName: string,\n joins: ReportOptions['joins'],\n): Promise<ReportJoinDefinition[]> {\n const resolved: ReportJoinDefinition[] = [];\n if (!joins) return resolved;\n const sourceTenant = await tenantColumn(sourceName);\n const columnType = columnTypeReader();\n\n for (const [alias, join] of Object.entries(joins)) {\n if (\n !JOIN_ALIAS.test(alias) ||\n alias === REPORT_SOURCE_ALIAS ||\n alias.length > 32\n ) {\n throw new Error(\n `${reportName} join alias '${alias}' must be lower-case letters, digits and underscores, start with a letter, and not be '${REPORT_SOURCE_ALIAS}'`,\n );\n }\n if (!join?.source || typeof join.on !== 'string') {\n throw new Error(\n `${reportName} join '${alias}' needs a source and an on field`,\n );\n }\n if (\n join.type !== undefined &&\n join.type !== 'inner' &&\n join.type !== 'left'\n ) {\n throw new Error(\n `${reportName} join '${alias}' type must be 'inner' or 'left'`,\n );\n }\n const className = sourceClassName(join.source);\n const table = resolveTableName(className);\n const onColumn = await fieldColumn(sourceName, join.on);\n if (!onColumn) {\n throw new Error(\n `${reportName} join '${alias}': ${sourceName} has no field '${join.on}'`,\n );\n }\n const to = join.to ?? 'id';\n const targetColumn = to === 'id' ? 'id' : await fieldColumn(className, to);\n if (!targetColumn) {\n throw new Error(\n `${reportName} join '${alias}': ${className} has no field '${to}'`,\n );\n }\n\n // A tenant-scoped related model is matched within the source row's tenant,\n // so ids that collide across tenants never join. A source with no tenant\n // cannot say which tenant's related rows to match.\n const joinedTenant = await tenantColumn(className);\n if (joinedTenant && !sourceTenant) {\n throw new Error(\n `${reportName} join '${alias}': ${className} is tenant-scoped but ${sourceName} has no tenant field to match it with`,\n );\n }\n const softDelete = await fieldColumn(className, 'deletedAt');\n // Keys of different schema types (a text reference to a uuid id) compare\n // as text: Postgres has no text = uuid operator, and a text value that is\n // not a uuid then matches nothing instead of failing the rebuild.\n const keyAsText = compareAsText(\n columnType,\n { className: sourceName, column: onColumn },\n { className, column: targetColumn },\n );\n const tenantAsText =\n joinedTenant && sourceTenant\n ? compareAsText(\n columnType,\n { className: sourceName, column: sourceTenant },\n { className, column: joinedTenant },\n )\n : false;\n resolved.push({\n alias,\n className,\n table,\n type: join.type ?? 'left',\n sourceColumn: onColumn,\n targetColumn,\n ...(keyAsText ? { keyAsText: true } : {}),\n ...(joinedTenant && sourceTenant\n ? {\n tenantColumns: {\n source: sourceTenant,\n joined: joinedTenant,\n ...(tenantAsText ? { asText: true } : {}),\n },\n }\n : {}),\n ...(softDelete ? { softDeleteColumn: softDelete } : {}),\n });\n }\n return resolved;\n}\n\nfunction operandColumns(node: unknown, found: string[] = []): string[] {\n if (!node || typeof node !== 'object') return found;\n const record = node as Record<string, unknown>;\n if (typeof record.col === 'string') found.push(record.col);\n for (const key of ['left', 'right', 'later', 'earlier', 'operand']) {\n operandColumns(record[key], found);\n }\n if (Array.isArray(record.operands)) {\n for (const operand of record.operands) operandColumns(operand, found);\n }\n return found;\n}\n\n/** Every model field a report field reads, as written (`status`, `wo.title`). */\nfunction referencedColumns(\n fieldName: string,\n report: ReportFieldMetadata,\n): string[] {\n if (report.kind === 'group') {\n return report.expr\n ? operandColumns(report.expr)\n : [report.sourceColumn ?? fieldName];\n }\n if (report.kind === 'bucket') return [report.sourceColumn];\n return [\n ...(report.column ? [report.column] : []),\n ...operandColumns(report.expr),\n ...operandColumns(report.filter),\n ];\n}\n\nasync function relatedPolicies(\n reportName: string,\n fieldName: string,\n report: ReportFieldMetadata,\n joins: ReportJoinDefinition[],\n): Promise<ReportRelatedFieldPolicy[]> {\n const policies: ReportRelatedFieldPolicy[] = [];\n for (const ref of referencedColumns(fieldName, report)) {\n if (!ref.includes('.')) continue;\n const parts = ref.split('.');\n const join =\n parts.length === 2 ? joins.find((j) => j.alias === parts[0]) : undefined;\n if (!join) {\n throw new Error(\n `${reportName}.${fieldName} reads '${ref}', which is not a column of a declared join`,\n );\n }\n const related = parts[1];\n const registryFields = await ObjectRegistry.getAllFields(join.className);\n const key = toSnakeCase(related);\n const found = [...registryFields.entries()].find(\n ([name]) => name === related || toSnakeCase(name) === key,\n );\n if (!found && key !== 'id') {\n throw new Error(\n `${reportName}.${fieldName} reads '${ref}', but ${join.className} has no field '${related}'`,\n );\n }\n const policy = fieldPolicy(found?.[1] as Parameters<typeof fieldPolicy>[0]);\n policies.push({\n alias: join.alias,\n fieldName: related,\n sensitive: policy.sensitive,\n ...(policy.readPermission\n ? { readPermission: policy.readPermission }\n : {}),\n });\n }\n return policies;\n}\n\nexport async function buildReportDefinition(\n reportCtor: new (...args: any[]) => SmrtObject,\n): Promise<ReportDefinition> {\n const options = getReportOptions(reportCtor);\n const reportClassName = getRegisteredClassName(reportCtor);\n const sourceName = sourceClassName(options.source);\n const sourceTable = resolveTableName(sourceName);\n const fields = await ObjectRegistry.getAllFields(reportClassName);\n const joins = await resolveJoins(reportCtor.name, sourceName, options.joins);\n if (joins.length > 0 && options.refresh?.mode === 'incremental') {\n throw new Error(\n `${reportCtor.name} joins ${joins.map((join) => join.className).join(', ')} and cannot refresh incrementally: ` +\n `a change to a joined row does not move the source watermark. Use mode: 'rebuild'.`,\n );\n }\n\n const reportFields: ReportFieldDefinition[] = [];\n for (const [fieldName, field] of fields.entries()) {\n const report = readReportMetadata(field);\n if (!report) {\n if (!isReportSystemField(fieldName, field) && !field?.transient) {\n throw new Error(\n `Report field ${reportCtor.name}.${fieldName} is neither a grouping key nor an aggregate. ` +\n `Add @groupBy(), a time-bucket decorator, or an aggregate decorator.`,\n );\n }\n continue;\n }\n\n const related = await relatedPolicies(\n reportCtor.name,\n fieldName,\n report,\n joins,\n );\n reportFields.push({\n fieldName,\n columnName: toSnakeCase(fieldName),\n type: field.type,\n report,\n ...(related.length > 0 ? { related } : {}),\n });\n }\n\n return {\n reportClassName,\n sourceClassName: sourceName,\n sourceTable,\n ...(joins.length > 0 ? { joins } : {}),\n fields: reportFields,\n where: options.where,\n having: options.having,\n refresh: options.refresh,\n };\n}\n\n/**\n * A model field as a query column. Without joins it is the bare column, as\n * before. With joins every column is qualified: a bare field by the source\n * alias, `alias.field` by its join, so a column the source and a joined table\n * share (`tenant_id`, `deleted_at`) is never ambiguous.\n */\nfunction columnFor(\n ref: string,\n definition: Pick<ReportDefinition, 'joins'>,\n): string {\n const joins = definition.joins ?? [];\n if (!ref.includes('.')) {\n const column = toSnakeCase(ref);\n return joins.length > 0 ? `${REPORT_SOURCE_ALIAS}.${column}` : column;\n }\n const parts = ref.split('.');\n if (parts.length !== 2 || !joins.some((join) => join.alias === parts[0])) {\n throw new Error(\n `Report column '${ref}' is not a column of a declared join`,\n );\n }\n return `${parts[0]}.${toSnakeCase(parts[1])}`;\n}\n\nfunction mapOperand(\n node: ReportOperand,\n mapColumn: (ref: string) => string,\n): ReportOperand {\n if (!node || typeof node !== 'object') return node;\n const record = node as Record<string, unknown>;\n if (typeof record.col === 'string') return { col: mapColumn(record.col) };\n const out: Record<string, unknown> = { ...record };\n for (const key of ['left', 'right', 'later', 'earlier', 'operand']) {\n if (record[key] !== undefined) {\n out[key] = mapOperand(record[key] as ReportOperand, mapColumn);\n }\n }\n if (Array.isArray(record.operands)) {\n out.operands = record.operands.map((operand) =>\n mapOperand(operand as ReportOperand, mapColumn),\n );\n }\n return out as ReportOperand;\n}\n\nfunction sourceColumn(\n field: ReportFieldDefinition,\n definition: Pick<ReportDefinition, 'joins'>,\n): string {\n const report = field.report;\n if (!report) {\n throw new Error(`Report field ${field.fieldName} is missing metadata`);\n }\n if (report.kind === 'group') {\n return columnFor(report.sourceColumn ?? field.fieldName, definition);\n }\n if (report.kind === 'bucket') {\n return columnFor(report.sourceColumn, definition);\n }\n if (report.kind === 'aggregate') {\n if (!report.column) return '';\n return columnFor(report.column, definition);\n }\n return '';\n}\n\nexport function getReportGroupingColumns(\n definition: Pick<ReportDefinition, 'fields'>,\n): string[] {\n const columns = definition.fields\n .filter(\n (field) =>\n field.report?.kind === 'group' || field.report?.kind === 'bucket',\n )\n .map((field) => field.columnName ?? toSnakeCase(field.fieldName));\n return columns.length > 0 ? columns : ['id'];\n}\n\n/** The join condition: the key, the tenant match, and no soft-deleted related row. */\nfunction joinCondition(\n join: ReportJoinDefinition,\n adapterType: SqlAdapterType | undefined,\n): AggregateExpression {\n // SQLite stores a uuid as TEXT, so its keys already compare; a cast there\n // would only stop the joined id's index serving the join.\n const castable = adapterType !== 'sqlite';\n const equal = (\n left: string,\n right: string,\n asText: boolean | undefined,\n ): AggregateExpression =>\n asText && castable\n ? {\n op: 'eq',\n left: { op: 'asText', operand: { col: left } },\n right: { op: 'asText', operand: { col: right } },\n }\n : { op: 'eq', left: { col: left }, right: { col: right } };\n const conditions: AggregateExpression[] = [\n equal(\n `${REPORT_SOURCE_ALIAS}.${join.sourceColumn}`,\n `${join.alias}.${join.targetColumn}`,\n join.keyAsText,\n ),\n ];\n if (join.tenantColumns) {\n conditions.push(\n equal(\n `${REPORT_SOURCE_ALIAS}.${join.tenantColumns.source}`,\n `${join.alias}.${join.tenantColumns.joined}`,\n join.tenantColumns.asText,\n ),\n );\n }\n if (join.softDeleteColumn) {\n conditions.push({\n op: 'isNull',\n operand: { col: `${join.alias}.${join.softDeleteColumn}` },\n });\n }\n return conditions.length === 1\n ? conditions[0]\n : { op: 'and', operands: conditions };\n}\n\n/**\n * Compile a report definition to an aggregate spec. `adapterType` is the\n * database the spec will run on: a join whose key columns have different\n * schema types (a text reference to a uuid id) compares them as text, except\n * on SQLite, where both are already TEXT. Omitted, the join casts.\n */\nexport function compileReportDefinition(\n definition: ReportDefinition,\n adapterType?: SqlAdapterType,\n): AggregateSpec {\n const select: AggregateSelectExpr[] = [];\n const groupBy: string[] = [];\n const reportFieldToColumn = new Map<string, string>();\n const mapColumn = (ref: string) => columnFor(ref, definition);\n\n for (const field of definition.fields) {\n const outputColumn = field.columnName ?? toSnakeCase(field.fieldName);\n reportFieldToColumn.set(field.fieldName, outputColumn);\n reportFieldToColumn.set(outputColumn, outputColumn);\n\n const report = field.report;\n if (!report) continue;\n\n if (report.kind === 'group') {\n select.push(\n report.expr\n ? { expr: mapOperand(report.expr, mapColumn), as: outputColumn }\n : { column: sourceColumn(field, definition), as: outputColumn },\n );\n groupBy.push(outputColumn);\n continue;\n }\n\n if (report.kind === 'bucket') {\n select.push({\n bucket: report.unit,\n column: sourceColumn(field, definition),\n as: outputColumn,\n });\n groupBy.push(outputColumn);\n continue;\n }\n\n select.push({\n fn: report.fn,\n column: report.column ? sourceColumn(field, definition) : undefined,\n ...(report.expr ? { expr: mapOperand(report.expr, mapColumn) } : {}),\n ...(report.filter\n ? { filter: mapOperand(report.filter, mapColumn) }\n : {}),\n as: outputColumn,\n distinct: report.distinct,\n });\n }\n\n if (select.length === 0) {\n throw new Error(\n `${definition.reportClassName} has no report fields. ` +\n `Add @groupBy(), a time-bucket decorator, or an aggregate decorator.`,\n );\n }\n\n const joins = definition.joins ?? [];\n return {\n from: definition.sourceTable,\n ...(joins.length > 0\n ? {\n fromAlias: REPORT_SOURCE_ALIAS,\n joins: joins.map((join) => ({\n table: join.table,\n alias: join.alias,\n type: join.type,\n on: joinCondition(join, adapterType),\n })),\n }\n : {}),\n select,\n groupBy,\n where: normalizeWhere(definition.where, mapColumn),\n having: normalizeWhere(\n definition.having,\n (field) => reportFieldToColumn.get(field) ?? toSnakeCase(field),\n ),\n };\n}\n\nexport async function compileReportSpec(\n reportCtor: new (...args: any[]) => SmrtObject,\n): Promise<AggregateSpec> {\n return compileReportDefinition(await buildReportDefinition(reportCtor));\n}\n"],"mappings":"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"}
|
package/dist/compiler.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { type SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
import type { SqlAdapterType } from '@happyvertical/sql';
|
|
2
3
|
import type { AggregateSpec, ReportDefinition } from './types.js';
|
|
3
4
|
/** The report source's alias in a query that joins other tables. */
|
|
4
5
|
export declare const REPORT_SOURCE_ALIAS = "src";
|
|
5
6
|
export declare function buildReportDefinition(reportCtor: new (...args: any[]) => SmrtObject): Promise<ReportDefinition>;
|
|
6
7
|
export declare function getReportGroupingColumns(definition: Pick<ReportDefinition, 'fields'>): string[];
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Compile a report definition to an aggregate spec. `adapterType` is the
|
|
10
|
+
* database the spec will run on: a join whose key columns have different
|
|
11
|
+
* schema types (a text reference to a uuid id) compares them as text, except
|
|
12
|
+
* on SQLite, where both are already TEXT. Omitted, the join casts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function compileReportDefinition(definition: ReportDefinition, adapterType?: SqlAdapterType): AggregateSpec;
|
|
8
15
|
export declare function compileReportSpec(reportCtor: new (...args: any[]) => SmrtObject): Promise<AggregateSpec>;
|
|
9
16
|
//# sourceMappingURL=compiler.d.ts.map
|
package/dist/compiler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3E,OAAO,KAAK,EAEV,cAAc,EAEf,MAAM,oBAAoB,CAAC;AAS5B,OAAO,KAAK,EAEV,aAAa,EACb,gBAAgB,EAQjB,MAAM,YAAY,CAAC;AAEpB,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AA+TzC,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,GAC7C,OAAO,CAAC,gBAAgB,CAAC,CAoD3B;AAoED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAC3C,MAAM,EAAE,CAQV;AAiDD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,gBAAgB,EAC5B,WAAW,CAAC,EAAE,cAAc,GAC3B,aAAa,CA2Ef;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,GAC7C,OAAO,CAAC,aAAa,CAAC,CAExB"}
|
package/dist/compiler.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as getReportGroupingColumns, i as compileReportSpec, n as buildReportDefinition, r as compileReportDefinition, t as REPORT_SOURCE_ALIAS } from "./chunks/compiler-
|
|
1
|
+
import { a as getReportGroupingColumns, i as compileReportSpec, n as buildReportDefinition, r as compileReportDefinition, t as REPORT_SOURCE_ALIAS } from "./chunks/compiler-CqTiU1S6.js";
|
|
2
2
|
export { REPORT_SOURCE_ALIAS, buildReportDefinition, compileReportDefinition, compileReportSpec, getReportGroupingColumns };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { aggregate, avg, count, day, getRuntimeReportOptions, groupBy, hour, max, min, minute, month, quarter, report, sum, week, year } from "./decorators.js";
|
|
2
|
-
import { a as getReportGroupingColumns, c as tenantColumn, i as compileReportSpec, n as buildReportDefinition, r as compileReportDefinition, s as fieldPolicy } from "./chunks/compiler-
|
|
2
|
+
import { a as getReportGroupingColumns, c as tenantColumn, i as compileReportSpec, n as buildReportDefinition, r as compileReportDefinition, s as fieldPolicy } from "./chunks/compiler-CqTiU1S6.js";
|
|
3
3
|
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";
|
|
4
4
|
import { adapterTypeFromDb, refreshReport, reportRowIdentity } from "./refresh.js";
|
|
5
5
|
import { ReportScheduleRunner, SmrtPrincipalReportRefreshTask, SmrtReportRefreshTask, enqueueReportRefresh, ensureReportRefreshSchedules, registerReportRefreshExecutionAuthorityHost, registerReportRefreshInterceptor, registerReportRefreshJobIntegritySigner } from "./scheduler.js";
|
|
@@ -275,7 +275,7 @@ function isColumnBackedField(field) {
|
|
|
275
275
|
"manyToMany"
|
|
276
276
|
].includes(field.type ?? "");
|
|
277
277
|
}
|
|
278
|
-
function reportColumn(field, registryField, joins = []) {
|
|
278
|
+
function reportColumn(field, registryField, joins = [], nullableColumns = /* @__PURE__ */ new Set()) {
|
|
279
279
|
const policy = fieldPolicy(registryField);
|
|
280
280
|
const relatedRestricted = (field.related ?? []).some((related) => related.sensitive || related.readPermission);
|
|
281
281
|
if (policy.sensitive || policy.readPermission || relatedRestricted || !isColumnBackedField(registryField)) return;
|
|
@@ -283,7 +283,8 @@ function reportColumn(field, registryField, joins = []) {
|
|
|
283
283
|
const report = field.report;
|
|
284
284
|
if (!report) return void 0;
|
|
285
285
|
const type = queryType(field.type ?? registryField?.type);
|
|
286
|
-
const
|
|
286
|
+
const valueOperators = filterOperatorsFor(type);
|
|
287
|
+
const filterOperators = valueOperators && nullableColumns.has(id) ? [...valueOperators, ...NULL_TEST_OPERATORS] : valueOperators;
|
|
287
288
|
const base = {
|
|
288
289
|
id,
|
|
289
290
|
fieldName: field.fieldName,
|
|
@@ -349,6 +350,13 @@ function toQueryField(column) {
|
|
|
349
350
|
...column.filterOperators === void 0 ? {} : { filterOperators: [...column.filterOperators] }
|
|
350
351
|
};
|
|
351
352
|
}
|
|
353
|
+
var NULL_TEST_OPERATORS = ["isNotNull", "isNull"];
|
|
354
|
+
function nullableReportColumns(reportClassName) {
|
|
355
|
+
const columns = ObjectRegistry.getSchema(reportClassName)?.columns ?? {};
|
|
356
|
+
const nullable = /* @__PURE__ */ new Set();
|
|
357
|
+
for (const [name, column] of Object.entries(columns)) if (column.notNull !== true && column.primaryKey !== true) nullable.add(name);
|
|
358
|
+
return nullable;
|
|
359
|
+
}
|
|
352
360
|
function filterOperatorsFor(type) {
|
|
353
361
|
switch (type) {
|
|
354
362
|
case "string": return [
|
|
@@ -569,7 +577,8 @@ async function buildReportAdapterDescriptor(reportCtor, options = {}) {
|
|
|
569
577
|
const registered = registeredClass(reportCtor);
|
|
570
578
|
const fields = await ObjectRegistry.getAllFields(definition.reportClassName);
|
|
571
579
|
const tenantField = configuredTenantField(registered?.tenantScopedConfig?.field);
|
|
572
|
-
const
|
|
580
|
+
const nullableColumns = nullableReportColumns(definition.reportClassName);
|
|
581
|
+
const columns = [identityColumn(), ...definition.fields.map((field) => reportColumn(field, fields.get(field.fieldName), definition.joins, nullableColumns)).filter((field) => Boolean(field))].sort((left, right) => left.id.localeCompare(right.id));
|
|
573
582
|
const schema = {
|
|
574
583
|
version: 1,
|
|
575
584
|
identityField: "id",
|
|
@@ -674,12 +683,16 @@ function inverseOperator(operator) {
|
|
|
674
683
|
case "lte": return "gt";
|
|
675
684
|
case "in": return "notIn";
|
|
676
685
|
case "notIn": return "in";
|
|
686
|
+
case "isNull": return "isNotNull";
|
|
687
|
+
case "isNotNull": return "isNull";
|
|
677
688
|
case "like": return reportFilterError("Report filters do not support negating a LIKE predicate");
|
|
678
689
|
}
|
|
679
690
|
}
|
|
680
691
|
function collectionCondition(field, operator, value) {
|
|
681
692
|
const keyFor = (suffix2) => suffix2 ? `${field} ${suffix2}` : field;
|
|
682
693
|
const scalar = (key, scalarValue) => [[{ [key]: scalarValue }]];
|
|
694
|
+
if (operator === "isNull") return scalar(field, null);
|
|
695
|
+
if (operator === "isNotNull") return scalar(keyFor("!="), null);
|
|
683
696
|
if (operator === "in") {
|
|
684
697
|
const values = value;
|
|
685
698
|
const nonNull = values.filter((entry) => entry !== null);
|
|
@@ -2018,6 +2031,9 @@ function stable(value) {
|
|
|
2018
2031
|
const object = plainObject(value, "Report surface value");
|
|
2019
2032
|
return "{" + Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stable(object[key])}`).join(",") + "}";
|
|
2020
2033
|
}
|
|
2034
|
+
function withoutNullTests(operators) {
|
|
2035
|
+
return operators.filter((operator) => operator !== "isNull" && operator !== "isNotNull");
|
|
2036
|
+
}
|
|
2021
2037
|
function reportDefinitionFingerprint(descriptor) {
|
|
2022
2038
|
const definition = {
|
|
2023
2039
|
resourceId: descriptor.resourceId,
|
|
@@ -2035,7 +2051,7 @@ function reportDefinitionFingerprint(descriptor) {
|
|
|
2035
2051
|
projectable: column.projectable === true,
|
|
2036
2052
|
sortable: column.sortable === true,
|
|
2037
2053
|
facetable: column.facetable === true,
|
|
2038
|
-
filterOperators: column.filterOperators ?? [],
|
|
2054
|
+
filterOperators: withoutNullTests(column.filterOperators ?? []),
|
|
2039
2055
|
capabilities: [...column.capabilities].sort(),
|
|
2040
2056
|
sensitivity: column.sensitivity ?? null,
|
|
2041
2057
|
sourceColumn: column.sourceColumn ?? null,
|
|
@@ -2044,7 +2060,13 @@ function reportDefinitionFingerprint(descriptor) {
|
|
|
2044
2060
|
distinct: column.distinct ?? null,
|
|
2045
2061
|
...column.semantics ? { semantics: column.semantics } : {}
|
|
2046
2062
|
})),
|
|
2047
|
-
schema:
|
|
2063
|
+
schema: {
|
|
2064
|
+
...descriptor.schema,
|
|
2065
|
+
fields: descriptor.schema.fields.map((field) => field.filterOperators ? {
|
|
2066
|
+
...field,
|
|
2067
|
+
filterOperators: withoutNullTests(field.filterOperators)
|
|
2068
|
+
} : field)
|
|
2069
|
+
},
|
|
2048
2070
|
...descriptor.semantics ? { semantics: descriptor.semantics } : {}
|
|
2049
2071
|
};
|
|
2050
2072
|
return "rv1_" + createHash("sha256").update(stable(definition), "utf8").digest("base64url");
|