@objectstack/service-analytics 17.0.0-rc.4 → 17.0.0-rc.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -105,23 +105,32 @@ type RelationshipResolver = (baseObject: string, relationshipName: string) => st
105
105
  */
106
106
  interface DatasetCompileOptions {
107
107
  /**
108
- * [#5115] The datasource `objectName` DECLARES (`object.datasource`), or
109
- * `undefined` when nothing authoritative can answer (no data engine, unknown
110
- * object).
108
+ * [#5115] The datasource `objectName` is BOUND to, or `undefined` when nothing
109
+ * authoritative can answer (no data engine, unknown object) — or when nothing
110
+ * binds the object at all and it rides the deployment's default datasource.
111
111
  *
112
112
  * With it the compiler can settle at COMPILE time what #5033 could only
113
113
  * report at QUERY time: a dataset whose join crosses datasources declares a
114
114
  * statement no driver can execute, because the analytics engine lowers the
115
115
  * whole dataset into ONE SQL statement on the base object's datasource.
116
116
  *
117
- * IMPORTANT `'default'` is not an answer. In `ObjectQL.getDriver`'s
118
- * resolution order an explicit `object.datasource` other than `'default'`
119
- * wins outright (step 1); `'default'` is the schema's DEFAULT value and means
120
- * only "no explicit binding", after which routing is decided by
121
- * `datasourceMapping` rules, the ADR-0057 §3.6 lifecycle split, and the
122
- * owning package's `defaultDatasource` none of which are visible from here.
123
- * The compiler therefore treats `'default'`/`undefined` as UNANSWERED. See
124
- * {@link compileDataset}.
117
+ * [#5288] What the host supplies here changed shape, the rule below did not.
118
+ * It used to be the object's DECLARED `datasource` step 1 of the five
119
+ * `ObjectQL.getDriver` routes by so an object placed by a
120
+ * `datasourceMapping` rule, by the ADR-0057 §3.6 lifecycle split, or by its
121
+ * package's `defaultDatasource` answered `'default'` and was read here as
122
+ * unanswered. The built-in host (`plugin.ts`) now asks the engine's own
123
+ * resolver instead, so those three placements ARE visible from here and a join
124
+ * between two objects bound to two different datasources is decidable
125
+ * whichever mechanism bound them.
126
+ *
127
+ * Still deliberately UNANSWERED: `'default'`, and the object that no rule
128
+ * places anywhere. The deployment's default driver keeps its natural name
129
+ * (#3826), so "rides the default" is reported as `undefined` rather than as a
130
+ * name — which means a join from a bound object to a default-riding one stays
131
+ * undecidable here and remains the query-time diagnostic's business (#5288
132
+ * records this boundary; widening it is #5115's follow-up, not this rule's).
133
+ * See {@link compileDataset}.
125
134
  */
126
135
  getObjectDatasource?: (objectName: string) => string | undefined;
127
136
  /**
@@ -407,6 +416,15 @@ interface AnalyticsServiceConfig {
407
416
  * datasources before any query is ever built. Absence keeps the pre-#5115
408
417
  * behaviour exactly ("cannot answer, do not block") — the query-time
409
418
  * diagnostic above stays as the backstop.
419
+ *
420
+ * [#5288] "Bound to" above is the whole contract, and it took until #5288 for
421
+ * the built-in host to honour it: `plugin.ts` answered with the object's
422
+ * DECLARED `datasource` — step 1 of the five `ObjectQL.getDriver` routes by —
423
+ * so an object placed by a `datasourceMapping` rule, by the ADR-0057 §3.6
424
+ * lifecycle split, or by its package's `defaultDatasource` reported
425
+ * `'default'` and sent the message above to the wrong database. It now asks
426
+ * `ObjectQL.resolveEffectiveDatasource`. A custom host owes the same answer:
427
+ * the datasource an object is BOUND to, `undefined` when nothing binds it.
410
428
  */
411
429
  getObjectDatasource?: (objectName: string) => string | undefined;
412
430
  /**
@@ -665,6 +683,13 @@ declare class AnalyticsService implements IAnalyticsService {
665
683
  * the data path's `resolveQueryFields`: they are engine-assigned rather than
666
684
  * declared, and a gate stricter than the engine it guards would reject
667
685
  * queries that used to work.
686
+ *
687
+ * [#5918] Its `stripPrefix` below is deliberately NOT narrowed the way the two
688
+ * MINTS were. This is a RESOLVER — it mirrors `lookupMember`'s tiers to answer
689
+ * "which Metric will the strategy read", and that tier order did not change.
690
+ * What changed is what can reach it: a dotted measure is now either a
691
+ * `<cube>.` qualifier or a key the cube itself declares, because every other
692
+ * dotted spelling is refused at the mint before this gate runs.
668
693
  */
669
694
  private assertMeasureFields;
670
695
  /**
@@ -1041,6 +1066,19 @@ declare class DatasetExecutor {
1041
1066
  * ISO strings chronologically, and bucket keys are minted sort-stable.)
1042
1067
  */
1043
1068
  private timeDimensionsOf;
1069
+ /**
1070
+ * The EFFECTIVE bucket size one dimension is grouped at for this selection,
1071
+ * or `undefined` when it is not a date dimension or nothing states a size (in
1072
+ * which case the runtime groups the raw column).
1073
+ *
1074
+ * One definition, two readers, deliberately: {@link buildQuery} uses it to
1075
+ * decide the `GROUP BY`, and {@link runCompare} uses it to realign the
1076
+ * comparison pass's bucket keys (#6007). Those two MUST agree — realigning
1077
+ * `month` keys a query grouped by `quarter` would move every comparison value
1078
+ * onto a bucket that does not exist — and the way to make them agree is to
1079
+ * have one of them, not two that look alike.
1080
+ */
1081
+ private granularityOf;
1044
1082
  private buildQuery;
1045
1083
  private runCompare;
1046
1084
  }
@@ -1464,6 +1502,14 @@ declare class ObjectQLStrategy implements AnalyticsStrategy {
1464
1502
  * string — `String(…)`, the same normalisation `like-pattern.ts` applies at the
1465
1503
  * two SQL emitters and `driver-sql`'s `applyLike` applies at the driver, so one
1466
1504
  * `$contains` means one thing on every face (#5567's invariant).
1505
+ *
1506
+ * [#5234] Those four `String(…)` calls now only ever see a value that renders
1507
+ * faithfully: `fieldLeaves` refuses an object comparand on this family before a
1508
+ * leaf exists. That ordering is load-bearing rather than incidental — this arm
1509
+ * is a PRODUCER for the engine, so stringifying an object here would have
1510
+ * laundered it into `'[object Object]'` and handed a driver a perfectly
1511
+ * well-typed string. A strict driver downstream could never have seen the shape
1512
+ * it was strict about, which is why the guard sits at the door and not here.
1467
1513
  */
1468
1514
  private convertFilter;
1469
1515
  private extractObjectName;
package/dist/index.d.ts CHANGED
@@ -105,23 +105,32 @@ type RelationshipResolver = (baseObject: string, relationshipName: string) => st
105
105
  */
106
106
  interface DatasetCompileOptions {
107
107
  /**
108
- * [#5115] The datasource `objectName` DECLARES (`object.datasource`), or
109
- * `undefined` when nothing authoritative can answer (no data engine, unknown
110
- * object).
108
+ * [#5115] The datasource `objectName` is BOUND to, or `undefined` when nothing
109
+ * authoritative can answer (no data engine, unknown object) — or when nothing
110
+ * binds the object at all and it rides the deployment's default datasource.
111
111
  *
112
112
  * With it the compiler can settle at COMPILE time what #5033 could only
113
113
  * report at QUERY time: a dataset whose join crosses datasources declares a
114
114
  * statement no driver can execute, because the analytics engine lowers the
115
115
  * whole dataset into ONE SQL statement on the base object's datasource.
116
116
  *
117
- * IMPORTANT `'default'` is not an answer. In `ObjectQL.getDriver`'s
118
- * resolution order an explicit `object.datasource` other than `'default'`
119
- * wins outright (step 1); `'default'` is the schema's DEFAULT value and means
120
- * only "no explicit binding", after which routing is decided by
121
- * `datasourceMapping` rules, the ADR-0057 §3.6 lifecycle split, and the
122
- * owning package's `defaultDatasource` none of which are visible from here.
123
- * The compiler therefore treats `'default'`/`undefined` as UNANSWERED. See
124
- * {@link compileDataset}.
117
+ * [#5288] What the host supplies here changed shape, the rule below did not.
118
+ * It used to be the object's DECLARED `datasource` step 1 of the five
119
+ * `ObjectQL.getDriver` routes by so an object placed by a
120
+ * `datasourceMapping` rule, by the ADR-0057 §3.6 lifecycle split, or by its
121
+ * package's `defaultDatasource` answered `'default'` and was read here as
122
+ * unanswered. The built-in host (`plugin.ts`) now asks the engine's own
123
+ * resolver instead, so those three placements ARE visible from here and a join
124
+ * between two objects bound to two different datasources is decidable
125
+ * whichever mechanism bound them.
126
+ *
127
+ * Still deliberately UNANSWERED: `'default'`, and the object that no rule
128
+ * places anywhere. The deployment's default driver keeps its natural name
129
+ * (#3826), so "rides the default" is reported as `undefined` rather than as a
130
+ * name — which means a join from a bound object to a default-riding one stays
131
+ * undecidable here and remains the query-time diagnostic's business (#5288
132
+ * records this boundary; widening it is #5115's follow-up, not this rule's).
133
+ * See {@link compileDataset}.
125
134
  */
126
135
  getObjectDatasource?: (objectName: string) => string | undefined;
127
136
  /**
@@ -407,6 +416,15 @@ interface AnalyticsServiceConfig {
407
416
  * datasources before any query is ever built. Absence keeps the pre-#5115
408
417
  * behaviour exactly ("cannot answer, do not block") — the query-time
409
418
  * diagnostic above stays as the backstop.
419
+ *
420
+ * [#5288] "Bound to" above is the whole contract, and it took until #5288 for
421
+ * the built-in host to honour it: `plugin.ts` answered with the object's
422
+ * DECLARED `datasource` — step 1 of the five `ObjectQL.getDriver` routes by —
423
+ * so an object placed by a `datasourceMapping` rule, by the ADR-0057 §3.6
424
+ * lifecycle split, or by its package's `defaultDatasource` reported
425
+ * `'default'` and sent the message above to the wrong database. It now asks
426
+ * `ObjectQL.resolveEffectiveDatasource`. A custom host owes the same answer:
427
+ * the datasource an object is BOUND to, `undefined` when nothing binds it.
410
428
  */
411
429
  getObjectDatasource?: (objectName: string) => string | undefined;
412
430
  /**
@@ -665,6 +683,13 @@ declare class AnalyticsService implements IAnalyticsService {
665
683
  * the data path's `resolveQueryFields`: they are engine-assigned rather than
666
684
  * declared, and a gate stricter than the engine it guards would reject
667
685
  * queries that used to work.
686
+ *
687
+ * [#5918] Its `stripPrefix` below is deliberately NOT narrowed the way the two
688
+ * MINTS were. This is a RESOLVER — it mirrors `lookupMember`'s tiers to answer
689
+ * "which Metric will the strategy read", and that tier order did not change.
690
+ * What changed is what can reach it: a dotted measure is now either a
691
+ * `<cube>.` qualifier or a key the cube itself declares, because every other
692
+ * dotted spelling is refused at the mint before this gate runs.
668
693
  */
669
694
  private assertMeasureFields;
670
695
  /**
@@ -1041,6 +1066,19 @@ declare class DatasetExecutor {
1041
1066
  * ISO strings chronologically, and bucket keys are minted sort-stable.)
1042
1067
  */
1043
1068
  private timeDimensionsOf;
1069
+ /**
1070
+ * The EFFECTIVE bucket size one dimension is grouped at for this selection,
1071
+ * or `undefined` when it is not a date dimension or nothing states a size (in
1072
+ * which case the runtime groups the raw column).
1073
+ *
1074
+ * One definition, two readers, deliberately: {@link buildQuery} uses it to
1075
+ * decide the `GROUP BY`, and {@link runCompare} uses it to realign the
1076
+ * comparison pass's bucket keys (#6007). Those two MUST agree — realigning
1077
+ * `month` keys a query grouped by `quarter` would move every comparison value
1078
+ * onto a bucket that does not exist — and the way to make them agree is to
1079
+ * have one of them, not two that look alike.
1080
+ */
1081
+ private granularityOf;
1044
1082
  private buildQuery;
1045
1083
  private runCompare;
1046
1084
  }
@@ -1464,6 +1502,14 @@ declare class ObjectQLStrategy implements AnalyticsStrategy {
1464
1502
  * string — `String(…)`, the same normalisation `like-pattern.ts` applies at the
1465
1503
  * two SQL emitters and `driver-sql`'s `applyLike` applies at the driver, so one
1466
1504
  * `$contains` means one thing on every face (#5567's invariant).
1505
+ *
1506
+ * [#5234] Those four `String(…)` calls now only ever see a value that renders
1507
+ * faithfully: `fieldLeaves` refuses an object comparand on this family before a
1508
+ * leaf exists. That ordering is load-bearing rather than incidental — this arm
1509
+ * is a PRODUCER for the engine, so stringifying an object here would have
1510
+ * laundered it into `'[object Object]'` and handed a driver a perfectly
1511
+ * well-typed string. A strict driver downstream could never have seen the shape
1512
+ * it was strict about, which is why the guard sits at the door and not here.
1467
1513
  */
1468
1514
  private convertFilter;
1469
1515
  private extractObjectName;