@objectstack/service-analytics 17.3.0 → 17.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +298 -0
- package/dist/index.cjs +442 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -14
- package/dist/index.d.ts +145 -14
- package/dist/index.js +424 -77
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.d.cts
CHANGED
|
@@ -8,12 +8,26 @@ import { Plugin, PluginContext } from '@objectstack/core';
|
|
|
8
8
|
/**
|
|
9
9
|
* CubeRegistry — Central registry for analytics cube definitions.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The registry is the single source of truth for cube metadata discovery:
|
|
12
|
+
* `getMeta()` maps every registered cube's measure/dimension `label` onto the
|
|
13
|
+
* `CubeMeta` titles served by `GET /api/v1/analytics/meta`, and the strategy
|
|
14
|
+
* chain resolves a query's cube through it.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Three sources write to it, all of them from `AnalyticsService`:
|
|
17
|
+
* 1. **Manifest definitions** — `AnalyticsServiceConfig.cubes` (`registerAll`),
|
|
18
|
+
* i.e. explicit cube definitions authored in `objectstack.config.ts`.
|
|
19
|
+
* 2. **Compiled datasets** (ADR-0021) — `compileDataset()`'s Cube, registered
|
|
20
|
+
* under the dataset's name by `queryDataset`.
|
|
21
|
+
* 3. **Ad-hoc query inference** — `ensureCube` / `inferCubeFromQuery` mints a
|
|
22
|
+
* minimal Cube from the members an `AnalyticsQuery` references, once
|
|
23
|
+
* `assertInferableCube` (#3867) has confirmed the name is a registered
|
|
24
|
+
* object. It infers from the QUERY, never from the object's field schema.
|
|
25
|
+
*
|
|
26
|
+
* This list used to read "two sources: manifest definitions, and object schema
|
|
27
|
+
* inference". Neither half was right: sources 2 and 3 were missing, and object
|
|
28
|
+
* schema inference is `inferFromObject` below, which no path in this repository
|
|
29
|
+
* calls (#15019). It is described at the method rather than advertised here,
|
|
30
|
+
* because listing it would promise a source the platform does not deliver.
|
|
17
31
|
*/
|
|
18
32
|
declare class CubeRegistry {
|
|
19
33
|
private cubes;
|
|
@@ -34,14 +48,36 @@ declare class CubeRegistry {
|
|
|
34
48
|
/** Remove all cubes. */
|
|
35
49
|
clear(): void;
|
|
36
50
|
/**
|
|
37
|
-
* Auto-generate a cube definition from an object
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
51
|
+
* Auto-generate a cube definition from an object's FIELD SCHEMA, and register
|
|
52
|
+
* it under `objectName`.
|
|
53
|
+
*
|
|
54
|
+
* ⚠️ Nothing in this repository calls this — the only in-tree caller is a unit
|
|
55
|
+
* test, and every cube the platform registers itself comes from one of the
|
|
56
|
+
* three sources named on the class above (#15019). That is not the same thing
|
|
57
|
+
* as unreachable: `CubeRegistry` is exported from the package entry and
|
|
58
|
+
* `AnalyticsService.cubeRegistry` is public, so a consumer of
|
|
59
|
+
* `@objectstack/service-analytics` can call it, and what it mints does reach
|
|
60
|
+
* the wire — `getMeta()` serves the labels below as `CubeMeta` titles. Whether
|
|
61
|
+
* this published method is removed or wired up as a real cube source is #15019.
|
|
62
|
+
*
|
|
63
|
+
* Heuristic rules, measured by driving the built package (the list this
|
|
64
|
+
* replaces claimed three behaviours the code does not have — `min`/`max`
|
|
65
|
+
* measures, a `count` measure for booleans, and a computed-field exclusion):
|
|
66
|
+
* - `number` / `currency` / `percent` fields → one `sum` and one `avg` measure
|
|
67
|
+
* each, labelled with the field's label plus ` (Sum)` / ` (Avg)`. No `min`
|
|
68
|
+
* or `max` measure is minted.
|
|
69
|
+
* - EVERY field becomes a dimension; there is no computed-field exclusion (the
|
|
70
|
+
* `fields` parameter carries no flag one could exclude on).
|
|
71
|
+
* - `boolean` fields become a `boolean` DIMENSION and nothing else — no count
|
|
72
|
+
* measure is minted for them.
|
|
73
|
+
* - `date` / `datetime` fields → `time` dimensions granulated
|
|
74
|
+
* day/week/month/quarter/year.
|
|
75
|
+
* - A default `count` measure labelled `Count` is always added.
|
|
76
|
+
*
|
|
77
|
+
* Those three defaults (`Count`, and the two composites) are English literals
|
|
78
|
+
* with no i18n hook; #14492's ruling listed the `Count` one as a site to carry
|
|
79
|
+
* the `builtinAggregate` discriminator, and it was left alone because no
|
|
80
|
+
* in-repo path reaches it.
|
|
45
81
|
*
|
|
46
82
|
* @param objectName - The snake_case object name (used as table/cube name)
|
|
47
83
|
* @param fields - Array of field descriptors `{ name, type, label? }`
|
|
@@ -520,6 +556,24 @@ interface AnalyticsServiceConfig {
|
|
|
520
556
|
defaultCurrency?: string;
|
|
521
557
|
max?: number;
|
|
522
558
|
} | undefined;
|
|
559
|
+
/**
|
|
560
|
+
* [#15684] The SQL dialect of the datasource backing `object` — `'sqlite'`,
|
|
561
|
+
* `'postgres'`, `'mysql'`, or `undefined` when the host cannot answer.
|
|
562
|
+
*
|
|
563
|
+
* The three SQL compilers need it for ONE thing: the case-EXACT text family
|
|
564
|
+
* (`$contains` / `$notContains` / `$startsWith` / `$endsWith`, #4706 Q2 = A)
|
|
565
|
+
* has no construct that is case-exact and parses on every dialect. A plain
|
|
566
|
+
* `LIKE` is case-exact on Postgres alone — SQLite folds ASCII case
|
|
567
|
+
* unconditionally, so the query's own `where` AND the RLS read scope
|
|
568
|
+
* admitted rows the predicate excludes there (over-reach, #3948). The
|
|
569
|
+
* per-dialect table lives in `text-match-sql.ts`.
|
|
570
|
+
*
|
|
571
|
+
* Answered by the plugin from the driver that will EXECUTE the statement, so
|
|
572
|
+
* the driver stays the single source of truth for its own dialect. A host
|
|
573
|
+
* that wires nothing keeps the `LIKE` the compilers always emitted —
|
|
574
|
+
* "cannot answer, do not block".
|
|
575
|
+
*/
|
|
576
|
+
sqlDialect?: (object: string) => string | undefined;
|
|
523
577
|
/** Pre-defined datasets to compile + register at construction (ADR-0021). */
|
|
524
578
|
datasets?: Dataset[];
|
|
525
579
|
/**
|
|
@@ -718,6 +772,42 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
718
772
|
queryDataset(dataset: Dataset, selection: DatasetSelection, context?: ExecutionContext, options?: {
|
|
719
773
|
previewDrafts?: boolean;
|
|
720
774
|
}): Promise<AnalyticsResult>;
|
|
775
|
+
/**
|
|
776
|
+
* The dataset dimensions this selection GROUPED THE GRID BY, resolved against
|
|
777
|
+
* the dataset definition. Shared by drill metadata, row-value label
|
|
778
|
+
* resolution and — through {@link enrichResultColumns} — the dimension column
|
|
779
|
+
* headers, so all three answer "which dimensions" the same way.
|
|
780
|
+
*/
|
|
781
|
+
private selectedDimensions;
|
|
782
|
+
/**
|
|
783
|
+
* ADR-0021 — describe the result's COLUMNS from the dataset's own authored
|
|
784
|
+
* definition: a measure's `label` / `format` / `currency` / `percentScale` /
|
|
785
|
+
* `builtinAggregate` and the `type` its aggregate really returns, then a
|
|
786
|
+
* dimension column's header `label`.
|
|
787
|
+
*
|
|
788
|
+
* **Every key here is read off the DATASET** (the authored measure or
|
|
789
|
+
* dimension) **and `sourceFieldMeta`** (the source object's declared field
|
|
790
|
+
* metadata). Not one is read off `result.rows`. That is what makes this one
|
|
791
|
+
* seam serve both paths that produce a dataset response — the live engine
|
|
792
|
+
* query and the ADR-0037 P3 draft-data preview — and it is why #16097 was a
|
|
793
|
+
* defect rather than a deliberate omission: the preview branch returns ~250
|
|
794
|
+
* lines before this ran, so a response over drafted seed rows carried none of
|
|
795
|
+
* these keys and a renderer fell back to humanizing the raw measure name and
|
|
796
|
+
* guessing a percent scale from magnitude — the exact failures #5537,
|
|
797
|
+
* objectui#3136 and #14492 each closed on the live path.
|
|
798
|
+
*
|
|
799
|
+
* Extracted rather than copied onto the second path, for the reason the
|
|
800
|
+
* `type` correction below already gives for living here at all: this is ONE
|
|
801
|
+
* rule holding both halves of the question, and a per-path copy would be two
|
|
802
|
+
* implementations of it, free to drift.
|
|
803
|
+
*
|
|
804
|
+
* ⛔ Not here, and deliberately: dimension VALUE label resolution
|
|
805
|
+
* ({@link resolveDimensionLabels}), which rewrites the grouped value in each
|
|
806
|
+
* ROW. That reads the rows, it is the one enrichment a seed-draft row set can
|
|
807
|
+
* make unnecessary, and the preview path skips it on purpose — see the note
|
|
808
|
+
* at that early return.
|
|
809
|
+
*/
|
|
810
|
+
private enrichResultColumns;
|
|
721
811
|
/**
|
|
722
812
|
* Get cube metadata for discovery.
|
|
723
813
|
*/
|
|
@@ -1221,7 +1311,37 @@ declare class DatasetExecutor {
|
|
|
1221
1311
|
*/
|
|
1222
1312
|
declare function mergeByDimensions(base: Record<string, unknown>[], extra: Record<string, unknown>[], dimensions: string[], valueColumns: string[]): Record<string, unknown>[];
|
|
1223
1313
|
|
|
1224
|
-
|
|
1314
|
+
/**
|
|
1315
|
+
* [#14079] What a caller can tell this compiler about the columns a read scope
|
|
1316
|
+
* names, beyond the scope itself.
|
|
1317
|
+
*/
|
|
1318
|
+
interface ReadScopeCompileOptions {
|
|
1319
|
+
/**
|
|
1320
|
+
* Is `field` a column whose STORED value is never text — a declared numeric
|
|
1321
|
+
* or boolean scalar (`NON_TEXT_STORED_VALUE_TYPES`, `@objectstack/spec`)?
|
|
1322
|
+
* When it answers `true`, a text operator over that column compiles to the
|
|
1323
|
+
* contract's constant (`1 = 0` for the positive operators, `1 = 1` for
|
|
1324
|
+
* `$notContains`) instead of a `LIKE` that coerces on SQLite and is refused
|
|
1325
|
+
* at query time on Postgres (SQLSTATE 42883). Absent, or answering `false`,
|
|
1326
|
+
* keeps the `LIKE` — the answer for a text column and for a caller that
|
|
1327
|
+
* cannot classify one (`non-text-column.ts` carries the argument).
|
|
1328
|
+
*/
|
|
1329
|
+
nonTextColumn?: (field: string) => boolean;
|
|
1330
|
+
/**
|
|
1331
|
+
* [#15684] The SQL dialect that will EXECUTE this scope — `'sqlite'` /
|
|
1332
|
+
* `'postgres'` / `'mysql'`. Anything else, including absent, is `'unknown'`
|
|
1333
|
+
* and keeps the plain `LIKE` this compiler always emitted.
|
|
1334
|
+
*
|
|
1335
|
+
* The case-EXACT text family (#4706 Q2 = A) needs it: SQLite's `LIKE` folds
|
|
1336
|
+
* ASCII case unconditionally, so a policy written `{ name: { $contains:
|
|
1337
|
+
* 'acme' } }` ADMITTED `ACME Corp` there — rows the predicate excludes,
|
|
1338
|
+
* which on a read scope is over-reach (#3948), not a loose filter. The
|
|
1339
|
+
* per-dialect construct table lives in `text-match-sql.ts`; both of this
|
|
1340
|
+
* compiler's consumers fill this in from the driver that owns the object.
|
|
1341
|
+
*/
|
|
1342
|
+
dialect?: string;
|
|
1343
|
+
}
|
|
1344
|
+
declare function compileScopedFilterToSql(filter: FilterCondition, alias: string, options?: ReadScopeCompileOptions): {
|
|
1225
1345
|
sql: string;
|
|
1226
1346
|
params: unknown[];
|
|
1227
1347
|
};
|
|
@@ -1702,6 +1822,17 @@ declare class ObjectQLStrategy implements AnalyticsStrategy {
|
|
|
1702
1822
|
* 3. `<field>` — bare column on the cube's table.
|
|
1703
1823
|
*/
|
|
1704
1824
|
private lookupMember;
|
|
1825
|
+
/**
|
|
1826
|
+
* [#14079] The (object, field) a filter member binds against — the echo's
|
|
1827
|
+
* copy of `NativeSQLStrategy.resolveStorageTarget`, kept beside the
|
|
1828
|
+
* `LIKE_SQL_OPS` table for the same reason that table is a copy: this file
|
|
1829
|
+
* renders a description of the statement THAT compiler produces, and the
|
|
1830
|
+
* declared-type test both apply is keyed by object and field. A dotted
|
|
1831
|
+
* `sql` is a relationship path (ADR-0071): every segment but the last is a
|
|
1832
|
+
* hop whose join alias is the dot-to-`__` spelling the dataset compiler keys
|
|
1833
|
+
* `cube.joins` by, the last is the column.
|
|
1834
|
+
*/
|
|
1835
|
+
private resolveStorageTarget;
|
|
1705
1836
|
private resolveFieldName;
|
|
1706
1837
|
private resolveMeasureAggregation;
|
|
1707
1838
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -8,12 +8,26 @@ import { Plugin, PluginContext } from '@objectstack/core';
|
|
|
8
8
|
/**
|
|
9
9
|
* CubeRegistry — Central registry for analytics cube definitions.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The registry is the single source of truth for cube metadata discovery:
|
|
12
|
+
* `getMeta()` maps every registered cube's measure/dimension `label` onto the
|
|
13
|
+
* `CubeMeta` titles served by `GET /api/v1/analytics/meta`, and the strategy
|
|
14
|
+
* chain resolves a query's cube through it.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Three sources write to it, all of them from `AnalyticsService`:
|
|
17
|
+
* 1. **Manifest definitions** — `AnalyticsServiceConfig.cubes` (`registerAll`),
|
|
18
|
+
* i.e. explicit cube definitions authored in `objectstack.config.ts`.
|
|
19
|
+
* 2. **Compiled datasets** (ADR-0021) — `compileDataset()`'s Cube, registered
|
|
20
|
+
* under the dataset's name by `queryDataset`.
|
|
21
|
+
* 3. **Ad-hoc query inference** — `ensureCube` / `inferCubeFromQuery` mints a
|
|
22
|
+
* minimal Cube from the members an `AnalyticsQuery` references, once
|
|
23
|
+
* `assertInferableCube` (#3867) has confirmed the name is a registered
|
|
24
|
+
* object. It infers from the QUERY, never from the object's field schema.
|
|
25
|
+
*
|
|
26
|
+
* This list used to read "two sources: manifest definitions, and object schema
|
|
27
|
+
* inference". Neither half was right: sources 2 and 3 were missing, and object
|
|
28
|
+
* schema inference is `inferFromObject` below, which no path in this repository
|
|
29
|
+
* calls (#15019). It is described at the method rather than advertised here,
|
|
30
|
+
* because listing it would promise a source the platform does not deliver.
|
|
17
31
|
*/
|
|
18
32
|
declare class CubeRegistry {
|
|
19
33
|
private cubes;
|
|
@@ -34,14 +48,36 @@ declare class CubeRegistry {
|
|
|
34
48
|
/** Remove all cubes. */
|
|
35
49
|
clear(): void;
|
|
36
50
|
/**
|
|
37
|
-
* Auto-generate a cube definition from an object
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
51
|
+
* Auto-generate a cube definition from an object's FIELD SCHEMA, and register
|
|
52
|
+
* it under `objectName`.
|
|
53
|
+
*
|
|
54
|
+
* ⚠️ Nothing in this repository calls this — the only in-tree caller is a unit
|
|
55
|
+
* test, and every cube the platform registers itself comes from one of the
|
|
56
|
+
* three sources named on the class above (#15019). That is not the same thing
|
|
57
|
+
* as unreachable: `CubeRegistry` is exported from the package entry and
|
|
58
|
+
* `AnalyticsService.cubeRegistry` is public, so a consumer of
|
|
59
|
+
* `@objectstack/service-analytics` can call it, and what it mints does reach
|
|
60
|
+
* the wire — `getMeta()` serves the labels below as `CubeMeta` titles. Whether
|
|
61
|
+
* this published method is removed or wired up as a real cube source is #15019.
|
|
62
|
+
*
|
|
63
|
+
* Heuristic rules, measured by driving the built package (the list this
|
|
64
|
+
* replaces claimed three behaviours the code does not have — `min`/`max`
|
|
65
|
+
* measures, a `count` measure for booleans, and a computed-field exclusion):
|
|
66
|
+
* - `number` / `currency` / `percent` fields → one `sum` and one `avg` measure
|
|
67
|
+
* each, labelled with the field's label plus ` (Sum)` / ` (Avg)`. No `min`
|
|
68
|
+
* or `max` measure is minted.
|
|
69
|
+
* - EVERY field becomes a dimension; there is no computed-field exclusion (the
|
|
70
|
+
* `fields` parameter carries no flag one could exclude on).
|
|
71
|
+
* - `boolean` fields become a `boolean` DIMENSION and nothing else — no count
|
|
72
|
+
* measure is minted for them.
|
|
73
|
+
* - `date` / `datetime` fields → `time` dimensions granulated
|
|
74
|
+
* day/week/month/quarter/year.
|
|
75
|
+
* - A default `count` measure labelled `Count` is always added.
|
|
76
|
+
*
|
|
77
|
+
* Those three defaults (`Count`, and the two composites) are English literals
|
|
78
|
+
* with no i18n hook; #14492's ruling listed the `Count` one as a site to carry
|
|
79
|
+
* the `builtinAggregate` discriminator, and it was left alone because no
|
|
80
|
+
* in-repo path reaches it.
|
|
45
81
|
*
|
|
46
82
|
* @param objectName - The snake_case object name (used as table/cube name)
|
|
47
83
|
* @param fields - Array of field descriptors `{ name, type, label? }`
|
|
@@ -520,6 +556,24 @@ interface AnalyticsServiceConfig {
|
|
|
520
556
|
defaultCurrency?: string;
|
|
521
557
|
max?: number;
|
|
522
558
|
} | undefined;
|
|
559
|
+
/**
|
|
560
|
+
* [#15684] The SQL dialect of the datasource backing `object` — `'sqlite'`,
|
|
561
|
+
* `'postgres'`, `'mysql'`, or `undefined` when the host cannot answer.
|
|
562
|
+
*
|
|
563
|
+
* The three SQL compilers need it for ONE thing: the case-EXACT text family
|
|
564
|
+
* (`$contains` / `$notContains` / `$startsWith` / `$endsWith`, #4706 Q2 = A)
|
|
565
|
+
* has no construct that is case-exact and parses on every dialect. A plain
|
|
566
|
+
* `LIKE` is case-exact on Postgres alone — SQLite folds ASCII case
|
|
567
|
+
* unconditionally, so the query's own `where` AND the RLS read scope
|
|
568
|
+
* admitted rows the predicate excludes there (over-reach, #3948). The
|
|
569
|
+
* per-dialect table lives in `text-match-sql.ts`.
|
|
570
|
+
*
|
|
571
|
+
* Answered by the plugin from the driver that will EXECUTE the statement, so
|
|
572
|
+
* the driver stays the single source of truth for its own dialect. A host
|
|
573
|
+
* that wires nothing keeps the `LIKE` the compilers always emitted —
|
|
574
|
+
* "cannot answer, do not block".
|
|
575
|
+
*/
|
|
576
|
+
sqlDialect?: (object: string) => string | undefined;
|
|
523
577
|
/** Pre-defined datasets to compile + register at construction (ADR-0021). */
|
|
524
578
|
datasets?: Dataset[];
|
|
525
579
|
/**
|
|
@@ -718,6 +772,42 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
718
772
|
queryDataset(dataset: Dataset, selection: DatasetSelection, context?: ExecutionContext, options?: {
|
|
719
773
|
previewDrafts?: boolean;
|
|
720
774
|
}): Promise<AnalyticsResult>;
|
|
775
|
+
/**
|
|
776
|
+
* The dataset dimensions this selection GROUPED THE GRID BY, resolved against
|
|
777
|
+
* the dataset definition. Shared by drill metadata, row-value label
|
|
778
|
+
* resolution and — through {@link enrichResultColumns} — the dimension column
|
|
779
|
+
* headers, so all three answer "which dimensions" the same way.
|
|
780
|
+
*/
|
|
781
|
+
private selectedDimensions;
|
|
782
|
+
/**
|
|
783
|
+
* ADR-0021 — describe the result's COLUMNS from the dataset's own authored
|
|
784
|
+
* definition: a measure's `label` / `format` / `currency` / `percentScale` /
|
|
785
|
+
* `builtinAggregate` and the `type` its aggregate really returns, then a
|
|
786
|
+
* dimension column's header `label`.
|
|
787
|
+
*
|
|
788
|
+
* **Every key here is read off the DATASET** (the authored measure or
|
|
789
|
+
* dimension) **and `sourceFieldMeta`** (the source object's declared field
|
|
790
|
+
* metadata). Not one is read off `result.rows`. That is what makes this one
|
|
791
|
+
* seam serve both paths that produce a dataset response — the live engine
|
|
792
|
+
* query and the ADR-0037 P3 draft-data preview — and it is why #16097 was a
|
|
793
|
+
* defect rather than a deliberate omission: the preview branch returns ~250
|
|
794
|
+
* lines before this ran, so a response over drafted seed rows carried none of
|
|
795
|
+
* these keys and a renderer fell back to humanizing the raw measure name and
|
|
796
|
+
* guessing a percent scale from magnitude — the exact failures #5537,
|
|
797
|
+
* objectui#3136 and #14492 each closed on the live path.
|
|
798
|
+
*
|
|
799
|
+
* Extracted rather than copied onto the second path, for the reason the
|
|
800
|
+
* `type` correction below already gives for living here at all: this is ONE
|
|
801
|
+
* rule holding both halves of the question, and a per-path copy would be two
|
|
802
|
+
* implementations of it, free to drift.
|
|
803
|
+
*
|
|
804
|
+
* ⛔ Not here, and deliberately: dimension VALUE label resolution
|
|
805
|
+
* ({@link resolveDimensionLabels}), which rewrites the grouped value in each
|
|
806
|
+
* ROW. That reads the rows, it is the one enrichment a seed-draft row set can
|
|
807
|
+
* make unnecessary, and the preview path skips it on purpose — see the note
|
|
808
|
+
* at that early return.
|
|
809
|
+
*/
|
|
810
|
+
private enrichResultColumns;
|
|
721
811
|
/**
|
|
722
812
|
* Get cube metadata for discovery.
|
|
723
813
|
*/
|
|
@@ -1221,7 +1311,37 @@ declare class DatasetExecutor {
|
|
|
1221
1311
|
*/
|
|
1222
1312
|
declare function mergeByDimensions(base: Record<string, unknown>[], extra: Record<string, unknown>[], dimensions: string[], valueColumns: string[]): Record<string, unknown>[];
|
|
1223
1313
|
|
|
1224
|
-
|
|
1314
|
+
/**
|
|
1315
|
+
* [#14079] What a caller can tell this compiler about the columns a read scope
|
|
1316
|
+
* names, beyond the scope itself.
|
|
1317
|
+
*/
|
|
1318
|
+
interface ReadScopeCompileOptions {
|
|
1319
|
+
/**
|
|
1320
|
+
* Is `field` a column whose STORED value is never text — a declared numeric
|
|
1321
|
+
* or boolean scalar (`NON_TEXT_STORED_VALUE_TYPES`, `@objectstack/spec`)?
|
|
1322
|
+
* When it answers `true`, a text operator over that column compiles to the
|
|
1323
|
+
* contract's constant (`1 = 0` for the positive operators, `1 = 1` for
|
|
1324
|
+
* `$notContains`) instead of a `LIKE` that coerces on SQLite and is refused
|
|
1325
|
+
* at query time on Postgres (SQLSTATE 42883). Absent, or answering `false`,
|
|
1326
|
+
* keeps the `LIKE` — the answer for a text column and for a caller that
|
|
1327
|
+
* cannot classify one (`non-text-column.ts` carries the argument).
|
|
1328
|
+
*/
|
|
1329
|
+
nonTextColumn?: (field: string) => boolean;
|
|
1330
|
+
/**
|
|
1331
|
+
* [#15684] The SQL dialect that will EXECUTE this scope — `'sqlite'` /
|
|
1332
|
+
* `'postgres'` / `'mysql'`. Anything else, including absent, is `'unknown'`
|
|
1333
|
+
* and keeps the plain `LIKE` this compiler always emitted.
|
|
1334
|
+
*
|
|
1335
|
+
* The case-EXACT text family (#4706 Q2 = A) needs it: SQLite's `LIKE` folds
|
|
1336
|
+
* ASCII case unconditionally, so a policy written `{ name: { $contains:
|
|
1337
|
+
* 'acme' } }` ADMITTED `ACME Corp` there — rows the predicate excludes,
|
|
1338
|
+
* which on a read scope is over-reach (#3948), not a loose filter. The
|
|
1339
|
+
* per-dialect construct table lives in `text-match-sql.ts`; both of this
|
|
1340
|
+
* compiler's consumers fill this in from the driver that owns the object.
|
|
1341
|
+
*/
|
|
1342
|
+
dialect?: string;
|
|
1343
|
+
}
|
|
1344
|
+
declare function compileScopedFilterToSql(filter: FilterCondition, alias: string, options?: ReadScopeCompileOptions): {
|
|
1225
1345
|
sql: string;
|
|
1226
1346
|
params: unknown[];
|
|
1227
1347
|
};
|
|
@@ -1702,6 +1822,17 @@ declare class ObjectQLStrategy implements AnalyticsStrategy {
|
|
|
1702
1822
|
* 3. `<field>` — bare column on the cube's table.
|
|
1703
1823
|
*/
|
|
1704
1824
|
private lookupMember;
|
|
1825
|
+
/**
|
|
1826
|
+
* [#14079] The (object, field) a filter member binds against — the echo's
|
|
1827
|
+
* copy of `NativeSQLStrategy.resolveStorageTarget`, kept beside the
|
|
1828
|
+
* `LIKE_SQL_OPS` table for the same reason that table is a copy: this file
|
|
1829
|
+
* renders a description of the statement THAT compiler produces, and the
|
|
1830
|
+
* declared-type test both apply is keyed by object and field. A dotted
|
|
1831
|
+
* `sql` is a relationship path (ADR-0071): every segment but the last is a
|
|
1832
|
+
* hop whose join alias is the dot-to-`__` spelling the dataset compiler keys
|
|
1833
|
+
* `cube.joins` by, the last is the column.
|
|
1834
|
+
*/
|
|
1835
|
+
private resolveStorageTarget;
|
|
1705
1836
|
private resolveFieldName;
|
|
1706
1837
|
private resolveMeasureAggregation;
|
|
1707
1838
|
/**
|