@objectstack/service-analytics 10.0.0 → 10.3.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/dist/index.cjs CHANGED
@@ -359,6 +359,17 @@ var NativeSQLStrategy = class {
359
359
  canHandle(query, ctx) {
360
360
  if (!query.cube) return false;
361
361
  if (query.timeDimensions?.some((td) => !!td.granularity)) return false;
362
+ if (typeof ctx.isExternalObject === "function") {
363
+ const cube = ctx.getCube(query.cube);
364
+ if (cube) {
365
+ if (ctx.isExternalObject(this.extractObjectName(cube))) return false;
366
+ const joinTargets = cube.joins ? Object.values(cube.joins) : [];
367
+ for (const j of joinTargets) {
368
+ const joinedObject = j?.name;
369
+ if (joinedObject && ctx.isExternalObject(joinedObject)) return false;
370
+ }
371
+ }
372
+ }
362
373
  const caps = ctx.queryCapabilities(query.cube);
363
374
  return caps.nativeSql && typeof ctx.executeRawSql === "function";
364
375
  }
@@ -1516,7 +1527,8 @@ var AnalyticsService = class {
1516
1527
  // Prefer a compiled dataset's declared relationships (D-C join allowlist);
1517
1528
  // fall back to any explicitly-configured provider for legacy cubes.
1518
1529
  getAllowedRelationships: (cubeName) => this.datasetRegistry.get(cubeName)?.allowedRelationships ?? config.getAllowedRelationships?.(cubeName),
1519
- coerceTemporalFilterValue: config.coerceTemporalFilterValue
1530
+ coerceTemporalFilterValue: config.coerceTemporalFilterValue,
1531
+ isExternalObject: config.isExternalObject
1520
1532
  };
1521
1533
  const builtIn = [
1522
1534
  new NativeSQLStrategy(),
@@ -1784,9 +1796,10 @@ var AnalyticsService = class {
1784
1796
  if (!cube) {
1785
1797
  cube = this.inferCubeFromQuery(query);
1786
1798
  this.cubeRegistry.register(cube);
1787
- this.logger.warn(
1788
- `[Analytics] No cube registered for "${name}"; auto-inferred a minimal cube (sql="${name}", measures=${Object.keys(cube.measures).join(",") || "(none)"}, dimensions=${Object.keys(cube.dimensions).join(",") || "(none)"}). Define an explicit Cube in your stack for full control.`
1789
- );
1799
+ const isScalarMetric = (query.dimensions?.length ?? 0) === 0 && (query.timeDimensions?.length ?? 0) === 0;
1800
+ const message = `[Analytics] No cube registered for "${name}"; auto-inferred a minimal cube (sql="${name}", measures=${Object.keys(cube.measures).join(",") || "(none)"}, dimensions=${Object.keys(cube.dimensions).join(",") || "(none)"}). Define an explicit Cube in your stack for full control.`;
1801
+ if (isScalarMetric) this.logger.debug(message);
1802
+ else this.logger.warn(message);
1790
1803
  return;
1791
1804
  }
1792
1805
  const stripPrefix = (m) => m.includes(".") ? m.split(".").slice(1).join(".") : m;
@@ -2121,6 +2134,13 @@ var AnalyticsServicePlugin = class {
2121
2134
  const f = dataEngine()?.getObject?.(object)?.fields?.[field];
2122
2135
  return f ? { type: f.type, defaultCurrency: f.currencyConfig?.defaultCurrency } : void 0;
2123
2136
  },
2137
+ // ADR-0062 D6 — a federated object carries an `external` block (ADR-0015).
2138
+ // Reported so NativeSQLStrategy declines it (its hand-compiled FROM would
2139
+ // hit the wrong physical table) and the driver-correct ObjectQL path runs.
2140
+ isExternalObject: (objectName) => {
2141
+ const obj = dataEngine()?.getObject?.(objectName);
2142
+ return !!(obj && obj.external != null);
2143
+ },
2124
2144
  draftRowsResolver
2125
2145
  };
2126
2146
  if (autoBridgedReadScope) {