@objectstack/service-analytics 9.11.0 → 10.2.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
  }
@@ -1495,6 +1506,7 @@ var AnalyticsService = class {
1495
1506
  }
1496
1507
  this.readScopeProvider = config.getReadScope;
1497
1508
  this.relationshipResolver = config.relationshipResolver;
1509
+ this.measureCurrency = config.measureCurrency;
1498
1510
  this.labelResolver = config.labelResolver;
1499
1511
  this.draftRowsResolver = config.draftRowsResolver;
1500
1512
  if (config.datasets) {
@@ -1515,7 +1527,8 @@ var AnalyticsService = class {
1515
1527
  // Prefer a compiled dataset's declared relationships (D-C join allowlist);
1516
1528
  // fall back to any explicitly-configured provider for legacy cubes.
1517
1529
  getAllowedRelationships: (cubeName) => this.datasetRegistry.get(cubeName)?.allowedRelationships ?? config.getAllowedRelationships?.(cubeName),
1518
- coerceTemporalFilterValue: config.coerceTemporalFilterValue
1530
+ coerceTemporalFilterValue: config.coerceTemporalFilterValue,
1531
+ isExternalObject: config.isExternalObject
1519
1532
  };
1520
1533
  const builtIn = [
1521
1534
  new NativeSQLStrategy(),
@@ -1672,8 +1685,21 @@ var AnalyticsService = class {
1672
1685
  }
1673
1686
  throw err;
1674
1687
  }
1675
- if (this.labelResolver && selection.dimensions?.length) {
1676
- const dims = selection.dimensions.map((name) => dataset.dimensions?.find((d) => d.name === name)).filter((d) => !!d?.field).map((d) => ({ name: d.name, field: d.field, type: d.type, dateGranularity: d.dateGranularity }));
1688
+ const selectedDims = (selection.dimensions ?? []).map((name) => dataset.dimensions?.find((d) => d.name === name)).filter((d) => !!d);
1689
+ const drillDims = selectedDims.filter((d) => !!d.field && d.type !== "date");
1690
+ if (drillDims.length && result.rows.length) {
1691
+ result.object = dataset.object;
1692
+ result.dimensionFields = Object.fromEntries(
1693
+ drillDims.map((d) => [d.name, d.field])
1694
+ );
1695
+ result.drillRawRows = result.rows.map((row) => {
1696
+ const raw = {};
1697
+ for (const d of drillDims) raw[d.name] = row[d.name];
1698
+ return raw;
1699
+ });
1700
+ }
1701
+ if (this.labelResolver && selectedDims.length) {
1702
+ const dims = selectedDims.filter((d) => !!d.field).map((d) => ({ name: d.name, field: d.field, type: d.type, dateGranularity: d.dateGranularity }));
1677
1703
  if (dims.length) {
1678
1704
  try {
1679
1705
  await resolveDimensionLabels(dataset.object, dims, result.rows, this.labelResolver);
@@ -1695,6 +1721,25 @@ var AnalyticsService = class {
1695
1721
  if (!m) continue;
1696
1722
  if (f.label == null && typeof m.label === "string") f.label = m.label;
1697
1723
  if (f.format == null && m.format) f.format = m.format;
1724
+ const fc = f;
1725
+ const mc = m;
1726
+ if (fc.currency == null) {
1727
+ const meta = m.field ? this.measureCurrency?.(dataset.object, m.field) : void 0;
1728
+ const monetary = !!mc.currency || meta?.type === "currency";
1729
+ if (monetary) {
1730
+ const resolved = mc.currency ?? meta?.defaultCurrency ?? context?.currency;
1731
+ if (resolved) fc.currency = resolved;
1732
+ }
1733
+ }
1734
+ }
1735
+ }
1736
+ if (result.fields?.length && selectedDims.length) {
1737
+ const dimByName = new Map(selectedDims.map((d) => [d.name, d]));
1738
+ const dimByField = new Map(selectedDims.filter((d) => !!d.field).map((d) => [d.field, d]));
1739
+ for (const f of result.fields) {
1740
+ if (f.label != null) continue;
1741
+ const d = dimByName.get(f.name) ?? dimByField.get(f.name);
1742
+ if (d && typeof d.label === "string") f.label = d.label;
1698
1743
  }
1699
1744
  }
1700
1745
  return result;
@@ -2083,6 +2128,18 @@ var AnalyticsServicePlugin = class {
2083
2128
  coerceTemporalFilterValue,
2084
2129
  relationshipResolver,
2085
2130
  labelResolver,
2131
+ // ADR-0053 — source-field currency metadata for the measure currency chain.
2132
+ measureCurrency: (object, field) => {
2133
+ const f = dataEngine()?.getObject?.(object)?.fields?.[field];
2134
+ return f ? { type: f.type, defaultCurrency: f.currencyConfig?.defaultCurrency } : void 0;
2135
+ },
2136
+ // ADR-0062 D6 — a federated object carries an `external` block (ADR-0015).
2137
+ // Reported so NativeSQLStrategy declines it (its hand-compiled FROM would
2138
+ // hit the wrong physical table) and the driver-correct ObjectQL path runs.
2139
+ isExternalObject: (objectName) => {
2140
+ const obj = dataEngine()?.getObject?.(objectName);
2141
+ return !!(obj && obj.external != null);
2142
+ },
2086
2143
  draftRowsResolver
2087
2144
  };
2088
2145
  if (autoBridgedReadScope) {