@objectstack/service-analytics 8.0.1 → 9.0.1
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.cjs +401 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -3
- package/dist/index.d.ts +104 -3
- package/dist/index.js +399 -13
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -83,6 +83,73 @@ interface CompiledDataset {
|
|
|
83
83
|
type RelationshipResolver = (baseObject: string, relationshipName: string) => string | undefined;
|
|
84
84
|
declare function compileDataset(dataset: Dataset, resolver?: RelationshipResolver): CompiledDataset;
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Dimension display-label resolution (ADR-0021).
|
|
88
|
+
*
|
|
89
|
+
* Analytics groups by the raw stored value of a dimension field. For two field
|
|
90
|
+
* kinds that value is NOT human-readable:
|
|
91
|
+
*
|
|
92
|
+
* - **select** — grouped by the stored option `value` (e.g. `backlog`), but the
|
|
93
|
+
* user-facing text is the option `label` (e.g. `Backlog`).
|
|
94
|
+
* - **lookup / master_detail** — grouped by the foreign-key `id` (e.g.
|
|
95
|
+
* `8eqtuKI4G9IhUsPS`), but the user-facing text is the related record's
|
|
96
|
+
* display field (its name/title).
|
|
97
|
+
*
|
|
98
|
+
* `resolveDimensionLabels` post-processes the result rows IN PLACE, replacing the
|
|
99
|
+
* raw value at `row[dimension.name]` with its display label when one is found.
|
|
100
|
+
* Unresolved values are left untouched so an orphaned id still renders as itself
|
|
101
|
+
* rather than blanking out. Date / number / plain-string dimensions are no-ops.
|
|
102
|
+
*
|
|
103
|
+
* The resolution LOGIC lives here (and is unit-tested); the low-level capabilities
|
|
104
|
+
* — reading an object's field map and fetching id→label pairs — are injected via
|
|
105
|
+
* {@link DimensionLabelDeps} so this module stays free of any engine dependency.
|
|
106
|
+
*/
|
|
107
|
+
/** The minimal field shape this resolver needs. */
|
|
108
|
+
interface FieldMetaLite {
|
|
109
|
+
type?: string;
|
|
110
|
+
/** Lookup / master_detail target object name. */
|
|
111
|
+
reference?: string;
|
|
112
|
+
/** Select options — the value→label source. */
|
|
113
|
+
options?: Array<{
|
|
114
|
+
value: unknown;
|
|
115
|
+
label?: string;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
118
|
+
/** Capabilities the resolver needs from the runtime (injected by the plugin). */
|
|
119
|
+
interface DimensionLabelDeps {
|
|
120
|
+
/** Return the field map for an object, or `undefined` if unknown. */
|
|
121
|
+
getObjectFields(objectName: string): Record<string, FieldMetaLite> | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Fetch a map of `id → display label` for the given ids of a target object.
|
|
124
|
+
* The implementation chooses the target's display field. Returning an empty
|
|
125
|
+
* map (e.g. no display field, no data access) leaves the ids unresolved.
|
|
126
|
+
*/
|
|
127
|
+
fetchRecordLabels(targetObject: string, ids: unknown[]): Promise<Map<unknown, string>>;
|
|
128
|
+
}
|
|
129
|
+
/** Date-dimension granularity (mirrors the dataset `dateGranularity` enum). */
|
|
130
|
+
type DateGranularity = 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
131
|
+
/**
|
|
132
|
+
* Replace raw dimension values with display labels, in place.
|
|
133
|
+
*
|
|
134
|
+
* @param baseObject - the dataset's base object (where the dimension fields live)
|
|
135
|
+
* @param dims - selected dimensions as `{ name, field, type?, dateGranularity? }`
|
|
136
|
+
* (row key = `name`)
|
|
137
|
+
* @param rows - result rows, mutated in place
|
|
138
|
+
* @param deps - injected runtime capabilities
|
|
139
|
+
*/
|
|
140
|
+
declare function resolveDimensionLabels(baseObject: string, dims: Array<{
|
|
141
|
+
name: string;
|
|
142
|
+
field: string;
|
|
143
|
+
type?: string;
|
|
144
|
+
dateGranularity?: DateGranularity | string;
|
|
145
|
+
}>, rows: Record<string, unknown>[], deps: DimensionLabelDeps): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Pick the display field for an object from its field map, by convention:
|
|
148
|
+
* an explicit `name`/`title`/`label` field, else the first text-like field.
|
|
149
|
+
* Returns `undefined` when nothing suitable exists.
|
|
150
|
+
*/
|
|
151
|
+
declare function pickDisplayField(fields: Record<string, FieldMetaLite> | undefined): string | undefined;
|
|
152
|
+
|
|
86
153
|
/**
|
|
87
154
|
* Configuration for AnalyticsService.
|
|
88
155
|
*/
|
|
@@ -153,6 +220,24 @@ interface AnalyticsServiceConfig {
|
|
|
153
220
|
relationshipResolver?: RelationshipResolver;
|
|
154
221
|
/** Pre-defined datasets to compile + register at construction (ADR-0021). */
|
|
155
222
|
datasets?: Dataset[];
|
|
223
|
+
/**
|
|
224
|
+
* ADR-0021 — resolve raw dimension values to human display labels. When
|
|
225
|
+
* provided, `queryDataset` post-processes result rows so a `select` dimension
|
|
226
|
+
* shows its option label (not the stored value) and a `lookup`/`master_detail`
|
|
227
|
+
* dimension shows the related record's display name (not the FK id). Injected
|
|
228
|
+
* by the plugin from the `data` engine; omit to keep raw values.
|
|
229
|
+
*/
|
|
230
|
+
labelResolver?: DimensionLabelDeps;
|
|
231
|
+
/**
|
|
232
|
+
* ADR-0037 Phase 3 — draft data preview. Resolve the PENDING `seed` draft
|
|
233
|
+
* rows for an object (returns null when the object has no pending seed).
|
|
234
|
+
* When provided and `queryDataset` is called with `previewDrafts`, the
|
|
235
|
+
* selection is evaluated over these rows in memory instead of the engine —
|
|
236
|
+
* the Live Canvas charts real numbers from the drafted sample data, and
|
|
237
|
+
* because publish materializes the SAME seed, the numbers are continuous
|
|
238
|
+
* across the publish boundary. Reads only; never touches physical tables.
|
|
239
|
+
*/
|
|
240
|
+
draftRowsResolver?: (objectName: string, context?: ExecutionContext) => Promise<Record<string, unknown>[] | null>;
|
|
156
241
|
}
|
|
157
242
|
/**
|
|
158
243
|
* AnalyticsService — Multi-driver analytics orchestrator.
|
|
@@ -182,6 +267,10 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
182
267
|
private readonly datasetRegistry;
|
|
183
268
|
/** Optional object-graph resolver used when compiling datasets. */
|
|
184
269
|
private readonly relationshipResolver?;
|
|
270
|
+
/** Optional dimension display-label resolver (select options / lookup names). */
|
|
271
|
+
private readonly labelResolver?;
|
|
272
|
+
/** ADR-0037 P3: pending-seed row resolver for draft data preview. */
|
|
273
|
+
private readonly draftRowsResolver?;
|
|
185
274
|
readonly cubeRegistry: CubeRegistry;
|
|
186
275
|
private readonly logger;
|
|
187
276
|
constructor(config?: AnalyticsServiceConfig);
|
|
@@ -207,6 +296,14 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
207
296
|
private resolveReadScopes;
|
|
208
297
|
/**
|
|
209
298
|
* Execute an analytical query by delegating to the first capable strategy.
|
|
299
|
+
*
|
|
300
|
+
* A strategy can discover only AT EXECUTION TIME that the underlying driver
|
|
301
|
+
* cannot serve it — the canonical case is NativeSQLStrategy on an in-memory
|
|
302
|
+
* driver, whose `execute()` returns null for raw SQL (the auto-bridge throws
|
|
303
|
+
* `RAW_SQL_UNSUPPORTED`). That is a capability miss, not a query error: fall
|
|
304
|
+
* back to the next capable strategy (e.g. ObjectQLStrategy over the
|
|
305
|
+
* aggregate bridge) instead of failing — or worse, fabricating empty rows.
|
|
306
|
+
* Any other error propagates untouched.
|
|
210
307
|
*/
|
|
211
308
|
query(query: AnalyticsQuery, context?: ExecutionContext): Promise<AnalyticsResult>;
|
|
212
309
|
/**
|
|
@@ -221,7 +318,9 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
221
318
|
* runs the selection through the `DatasetExecutor` with the request context so
|
|
222
319
|
* tenant/RLS scoping (D-C) is applied. See {@link IAnalyticsService.queryDataset}.
|
|
223
320
|
*/
|
|
224
|
-
queryDataset(dataset: Dataset, selection: DatasetSelection, context?: ExecutionContext
|
|
321
|
+
queryDataset(dataset: Dataset, selection: DatasetSelection, context?: ExecutionContext, options?: {
|
|
322
|
+
previewDrafts?: boolean;
|
|
323
|
+
}): Promise<AnalyticsResult>;
|
|
225
324
|
/**
|
|
226
325
|
* Get cube metadata for discovery.
|
|
227
326
|
*/
|
|
@@ -249,7 +348,9 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
249
348
|
/** Build a minimal Cube from the fields referenced by an AnalyticsQuery. */
|
|
250
349
|
private inferCubeFromQuery;
|
|
251
350
|
/**
|
|
252
|
-
* Walk the strategy chain and return the first strategy that can handle the
|
|
351
|
+
* Walk the strategy chain and return the first strategy that can handle the
|
|
352
|
+
* query. `skip` excludes strategies that already proved incapable at
|
|
353
|
+
* execution time (see {@link query}'s RAW_SQL_UNSUPPORTED fallback).
|
|
253
354
|
*/
|
|
254
355
|
private resolveStrategy;
|
|
255
356
|
}
|
|
@@ -495,4 +596,4 @@ declare class ObjectQLStrategy implements AnalyticsStrategy {
|
|
|
495
596
|
private buildFieldMeta;
|
|
496
597
|
}
|
|
497
598
|
|
|
498
|
-
export { AnalyticsService, type AnalyticsServiceConfig, AnalyticsServicePlugin, type AnalyticsServicePluginOptions, type CompareTo, type CompiledDataset, CubeRegistry, DatasetExecutor, type DerivedMeasureSpec, NativeSQLStrategy, ObjectQLStrategy, type RelationshipResolver, combineFilters, compileDataset, compileScopedFilterToSql, evaluateDerivedMeasures, mergeByDimensions, shiftRange };
|
|
599
|
+
export { AnalyticsService, type AnalyticsServiceConfig, AnalyticsServicePlugin, type AnalyticsServicePluginOptions, type CompareTo, type CompiledDataset, CubeRegistry, DatasetExecutor, type DerivedMeasureSpec, type DimensionLabelDeps, type FieldMetaLite, NativeSQLStrategy, ObjectQLStrategy, type RelationshipResolver, combineFilters, compileDataset, compileScopedFilterToSql, evaluateDerivedMeasures, mergeByDimensions, pickDisplayField, resolveDimensionLabels, shiftRange };
|
package/dist/index.d.ts
CHANGED
|
@@ -83,6 +83,73 @@ interface CompiledDataset {
|
|
|
83
83
|
type RelationshipResolver = (baseObject: string, relationshipName: string) => string | undefined;
|
|
84
84
|
declare function compileDataset(dataset: Dataset, resolver?: RelationshipResolver): CompiledDataset;
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Dimension display-label resolution (ADR-0021).
|
|
88
|
+
*
|
|
89
|
+
* Analytics groups by the raw stored value of a dimension field. For two field
|
|
90
|
+
* kinds that value is NOT human-readable:
|
|
91
|
+
*
|
|
92
|
+
* - **select** — grouped by the stored option `value` (e.g. `backlog`), but the
|
|
93
|
+
* user-facing text is the option `label` (e.g. `Backlog`).
|
|
94
|
+
* - **lookup / master_detail** — grouped by the foreign-key `id` (e.g.
|
|
95
|
+
* `8eqtuKI4G9IhUsPS`), but the user-facing text is the related record's
|
|
96
|
+
* display field (its name/title).
|
|
97
|
+
*
|
|
98
|
+
* `resolveDimensionLabels` post-processes the result rows IN PLACE, replacing the
|
|
99
|
+
* raw value at `row[dimension.name]` with its display label when one is found.
|
|
100
|
+
* Unresolved values are left untouched so an orphaned id still renders as itself
|
|
101
|
+
* rather than blanking out. Date / number / plain-string dimensions are no-ops.
|
|
102
|
+
*
|
|
103
|
+
* The resolution LOGIC lives here (and is unit-tested); the low-level capabilities
|
|
104
|
+
* — reading an object's field map and fetching id→label pairs — are injected via
|
|
105
|
+
* {@link DimensionLabelDeps} so this module stays free of any engine dependency.
|
|
106
|
+
*/
|
|
107
|
+
/** The minimal field shape this resolver needs. */
|
|
108
|
+
interface FieldMetaLite {
|
|
109
|
+
type?: string;
|
|
110
|
+
/** Lookup / master_detail target object name. */
|
|
111
|
+
reference?: string;
|
|
112
|
+
/** Select options — the value→label source. */
|
|
113
|
+
options?: Array<{
|
|
114
|
+
value: unknown;
|
|
115
|
+
label?: string;
|
|
116
|
+
}>;
|
|
117
|
+
}
|
|
118
|
+
/** Capabilities the resolver needs from the runtime (injected by the plugin). */
|
|
119
|
+
interface DimensionLabelDeps {
|
|
120
|
+
/** Return the field map for an object, or `undefined` if unknown. */
|
|
121
|
+
getObjectFields(objectName: string): Record<string, FieldMetaLite> | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Fetch a map of `id → display label` for the given ids of a target object.
|
|
124
|
+
* The implementation chooses the target's display field. Returning an empty
|
|
125
|
+
* map (e.g. no display field, no data access) leaves the ids unresolved.
|
|
126
|
+
*/
|
|
127
|
+
fetchRecordLabels(targetObject: string, ids: unknown[]): Promise<Map<unknown, string>>;
|
|
128
|
+
}
|
|
129
|
+
/** Date-dimension granularity (mirrors the dataset `dateGranularity` enum). */
|
|
130
|
+
type DateGranularity = 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
131
|
+
/**
|
|
132
|
+
* Replace raw dimension values with display labels, in place.
|
|
133
|
+
*
|
|
134
|
+
* @param baseObject - the dataset's base object (where the dimension fields live)
|
|
135
|
+
* @param dims - selected dimensions as `{ name, field, type?, dateGranularity? }`
|
|
136
|
+
* (row key = `name`)
|
|
137
|
+
* @param rows - result rows, mutated in place
|
|
138
|
+
* @param deps - injected runtime capabilities
|
|
139
|
+
*/
|
|
140
|
+
declare function resolveDimensionLabels(baseObject: string, dims: Array<{
|
|
141
|
+
name: string;
|
|
142
|
+
field: string;
|
|
143
|
+
type?: string;
|
|
144
|
+
dateGranularity?: DateGranularity | string;
|
|
145
|
+
}>, rows: Record<string, unknown>[], deps: DimensionLabelDeps): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Pick the display field for an object from its field map, by convention:
|
|
148
|
+
* an explicit `name`/`title`/`label` field, else the first text-like field.
|
|
149
|
+
* Returns `undefined` when nothing suitable exists.
|
|
150
|
+
*/
|
|
151
|
+
declare function pickDisplayField(fields: Record<string, FieldMetaLite> | undefined): string | undefined;
|
|
152
|
+
|
|
86
153
|
/**
|
|
87
154
|
* Configuration for AnalyticsService.
|
|
88
155
|
*/
|
|
@@ -153,6 +220,24 @@ interface AnalyticsServiceConfig {
|
|
|
153
220
|
relationshipResolver?: RelationshipResolver;
|
|
154
221
|
/** Pre-defined datasets to compile + register at construction (ADR-0021). */
|
|
155
222
|
datasets?: Dataset[];
|
|
223
|
+
/**
|
|
224
|
+
* ADR-0021 — resolve raw dimension values to human display labels. When
|
|
225
|
+
* provided, `queryDataset` post-processes result rows so a `select` dimension
|
|
226
|
+
* shows its option label (not the stored value) and a `lookup`/`master_detail`
|
|
227
|
+
* dimension shows the related record's display name (not the FK id). Injected
|
|
228
|
+
* by the plugin from the `data` engine; omit to keep raw values.
|
|
229
|
+
*/
|
|
230
|
+
labelResolver?: DimensionLabelDeps;
|
|
231
|
+
/**
|
|
232
|
+
* ADR-0037 Phase 3 — draft data preview. Resolve the PENDING `seed` draft
|
|
233
|
+
* rows for an object (returns null when the object has no pending seed).
|
|
234
|
+
* When provided and `queryDataset` is called with `previewDrafts`, the
|
|
235
|
+
* selection is evaluated over these rows in memory instead of the engine —
|
|
236
|
+
* the Live Canvas charts real numbers from the drafted sample data, and
|
|
237
|
+
* because publish materializes the SAME seed, the numbers are continuous
|
|
238
|
+
* across the publish boundary. Reads only; never touches physical tables.
|
|
239
|
+
*/
|
|
240
|
+
draftRowsResolver?: (objectName: string, context?: ExecutionContext) => Promise<Record<string, unknown>[] | null>;
|
|
156
241
|
}
|
|
157
242
|
/**
|
|
158
243
|
* AnalyticsService — Multi-driver analytics orchestrator.
|
|
@@ -182,6 +267,10 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
182
267
|
private readonly datasetRegistry;
|
|
183
268
|
/** Optional object-graph resolver used when compiling datasets. */
|
|
184
269
|
private readonly relationshipResolver?;
|
|
270
|
+
/** Optional dimension display-label resolver (select options / lookup names). */
|
|
271
|
+
private readonly labelResolver?;
|
|
272
|
+
/** ADR-0037 P3: pending-seed row resolver for draft data preview. */
|
|
273
|
+
private readonly draftRowsResolver?;
|
|
185
274
|
readonly cubeRegistry: CubeRegistry;
|
|
186
275
|
private readonly logger;
|
|
187
276
|
constructor(config?: AnalyticsServiceConfig);
|
|
@@ -207,6 +296,14 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
207
296
|
private resolveReadScopes;
|
|
208
297
|
/**
|
|
209
298
|
* Execute an analytical query by delegating to the first capable strategy.
|
|
299
|
+
*
|
|
300
|
+
* A strategy can discover only AT EXECUTION TIME that the underlying driver
|
|
301
|
+
* cannot serve it — the canonical case is NativeSQLStrategy on an in-memory
|
|
302
|
+
* driver, whose `execute()` returns null for raw SQL (the auto-bridge throws
|
|
303
|
+
* `RAW_SQL_UNSUPPORTED`). That is a capability miss, not a query error: fall
|
|
304
|
+
* back to the next capable strategy (e.g. ObjectQLStrategy over the
|
|
305
|
+
* aggregate bridge) instead of failing — or worse, fabricating empty rows.
|
|
306
|
+
* Any other error propagates untouched.
|
|
210
307
|
*/
|
|
211
308
|
query(query: AnalyticsQuery, context?: ExecutionContext): Promise<AnalyticsResult>;
|
|
212
309
|
/**
|
|
@@ -221,7 +318,9 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
221
318
|
* runs the selection through the `DatasetExecutor` with the request context so
|
|
222
319
|
* tenant/RLS scoping (D-C) is applied. See {@link IAnalyticsService.queryDataset}.
|
|
223
320
|
*/
|
|
224
|
-
queryDataset(dataset: Dataset, selection: DatasetSelection, context?: ExecutionContext
|
|
321
|
+
queryDataset(dataset: Dataset, selection: DatasetSelection, context?: ExecutionContext, options?: {
|
|
322
|
+
previewDrafts?: boolean;
|
|
323
|
+
}): Promise<AnalyticsResult>;
|
|
225
324
|
/**
|
|
226
325
|
* Get cube metadata for discovery.
|
|
227
326
|
*/
|
|
@@ -249,7 +348,9 @@ declare class AnalyticsService implements IAnalyticsService {
|
|
|
249
348
|
/** Build a minimal Cube from the fields referenced by an AnalyticsQuery. */
|
|
250
349
|
private inferCubeFromQuery;
|
|
251
350
|
/**
|
|
252
|
-
* Walk the strategy chain and return the first strategy that can handle the
|
|
351
|
+
* Walk the strategy chain and return the first strategy that can handle the
|
|
352
|
+
* query. `skip` excludes strategies that already proved incapable at
|
|
353
|
+
* execution time (see {@link query}'s RAW_SQL_UNSUPPORTED fallback).
|
|
253
354
|
*/
|
|
254
355
|
private resolveStrategy;
|
|
255
356
|
}
|
|
@@ -495,4 +596,4 @@ declare class ObjectQLStrategy implements AnalyticsStrategy {
|
|
|
495
596
|
private buildFieldMeta;
|
|
496
597
|
}
|
|
497
598
|
|
|
498
|
-
export { AnalyticsService, type AnalyticsServiceConfig, AnalyticsServicePlugin, type AnalyticsServicePluginOptions, type CompareTo, type CompiledDataset, CubeRegistry, DatasetExecutor, type DerivedMeasureSpec, NativeSQLStrategy, ObjectQLStrategy, type RelationshipResolver, combineFilters, compileDataset, compileScopedFilterToSql, evaluateDerivedMeasures, mergeByDimensions, shiftRange };
|
|
599
|
+
export { AnalyticsService, type AnalyticsServiceConfig, AnalyticsServicePlugin, type AnalyticsServicePluginOptions, type CompareTo, type CompiledDataset, CubeRegistry, DatasetExecutor, type DerivedMeasureSpec, type DimensionLabelDeps, type FieldMetaLite, NativeSQLStrategy, ObjectQLStrategy, type RelationshipResolver, combineFilters, compileDataset, compileScopedFilterToSql, evaluateDerivedMeasures, mergeByDimensions, pickDisplayField, resolveDimensionLabels, shiftRange };
|