Skip to content

Latest commit

 

History

History
698 lines (477 loc) · 22.2 KB

File metadata and controls

698 lines (477 loc) · 22.2 KB

Changelog — @objectstack/service-analytics

10.3.0

Patch Changes

  • f73d40a: fix(analytics): log scalar auto-inferred cubes at debug, not warn

    Scalar metric queries (measures only, no dimensions/timeDimensions) over an unregistered cube — the first-class object-metric "metric over an object" path — auto-infer a trivial count/sum cube by design. That auto-infer now logs at debug instead of warn, so boot/render no longer spams No cube registered for "..." for a non-problem. Grouped queries (explicit dimension / time bucket) over an unregistered cube keep the warn, where a forgotten cube registration is a real mistake.

    • @objectstack/spec@10.3.0
    • @objectstack/core@10.3.0

10.2.0

Patch Changes

  • Updated dependencies [b496498]
    • @objectstack/spec@10.2.0
    • @objectstack/core@10.2.0

10.1.0

Minor Changes

  • 49da36e: feat(analytics): correct analytics over federated objects (ADR-0062 Phase 3, D6)

    Analytics over an external (federated) object now aggregates against the correct remote table instead of silently querying the wrong one. The NativeSQLStrategy hand-compiles FROM "<object>" and bare column references, which bypass the driver's physical-table resolution (external.remoteName / remoteSchema / columnMap). It now declines any query whose base or joined object is federated, routing it to the ObjectQLStrategy — whose engine.aggregate() goes through the driver's getBuilder and already honours remoteName/remoteSchema (#2138/#2149). This "reuses the driver's resolution" (D6) rather than re-implementing it.

    Adds an optional StrategyContext.isExternalObject(objectName) hook (reported by the analytics plugin from the object's external block). Purely additive — with no hook, behavior is unchanged for managed objects.

Patch Changes

  • Updated dependencies [49da36e]
  • Updated dependencies [ac79f16]
    • @objectstack/spec@10.1.0
    • @objectstack/core@10.1.0

10.0.0

Minor Changes

  • 70609af: Resolve a monetary measure's display currency via the field→tenant chain.

    A dataset measure-currency now resolves through: explicit measure currency → source-field currencyConfig.defaultCurrency → tenant default (ctx.currency). A measure is monetary iff it declares a currency or aggregates a currency-type field, so count/avg-of-number measures never receive a code. Wires a measureCurrency field-metadata resolver from the data engine's object schema.

  • 3187952: Dataset analytics enrich dimension result fields with their display label (so report/dashboard table headers read "Status" instead of the raw field name) and expose drill-through metadata on the dataset query result: the base object, a drillable dimension→field map, and a parallel drillRawRows array of each row's raw grouped values (captured before label resolution). This lets a host drill a grouped bucket back to its underlying records with an exact-match filter built from the stored value, not the display label. Date dimensions are excluded (a humanized bucket can't be exact-matched).

  • a581385: Propagate a dataset measure's declared currency to the analytics result field.

    Adds an optional DatasetMeasure.currency (ISO 4217) on the semantic layer and carries it onto each measure result field alongside label/format, so a currency-aware client (Intl symbol) can render ¥1,234 / $616,000 from a real currency code instead of a plain number or a $ baked into format. Additive and optional — existing datasets are unaffected.

Patch Changes

  • Updated dependencies [d7ff626]
  • Updated dependencies [2a1b16b]
  • Updated dependencies [e16f2a8]
  • Updated dependencies [e411a82]
  • Updated dependencies [a581385]
  • Updated dependencies [d5f6d29]
  • Updated dependencies [220ce5b]
  • Updated dependencies [3efe334]
  • Updated dependencies [feead7e]
  • Updated dependencies [6ca20b3]
  • Updated dependencies [5f875fe]
  • Updated dependencies [b469950]
    • @objectstack/spec@10.0.0
    • @objectstack/core@10.0.0

9.11.0

Patch Changes

  • Updated dependencies [e7f6539]
  • Updated dependencies [2365d07]
  • Updated dependencies [6595b53]
  • Updated dependencies [fa8964d]
  • Updated dependencies [36138c7]
  • Updated dependencies [a8e4f3b]
  • Updated dependencies [4c213c2]
  • Updated dependencies [2afb612]
    • @objectstack/spec@9.11.0
    • @objectstack/core@9.11.0

9.10.0

Patch Changes

  • db02bd5: Fix dashboard time-series charts / "last N months" KPIs that filter or group by a Field.datetime column silently returning "No rows".

    The analytics NativeSQLStrategy compiles dashboard relative-date tokens ({12_months_ago}, {today}, …) to ISO date strings and binds them directly into raw SQL, bypassing the driver's own filter coercion. Under better-sqlite3 a Field.datetime column is stored as an INTEGER epoch (ms), so assessed_at >= '2025-06-18' became a TEXT-vs-INTEGER affinity compare that is always false — an empty result even though the rows exist. Field.date columns store ISO TEXT and were unaffected.

    The strategy now coerces a temporal comparand to the column's on-disk storage form via a new optional StrategyContext.coerceTemporalFilterValue hook, wired to the driver's public SqlDriver.temporalFilterValue (the single source of truth for the storage convention). Coercion is dialect-correct: SQLite Field.datetime → epoch ms; Field.date text and native-timestamp dialects (Postgres/MySQL) are left unchanged, so Postgres is never handed an epoch integer. Applied to gte/lte/gt/lt/equals, in/notIn, and the dateRange/timeDimension BETWEEN path.

  • fd07027: fix(analytics): make organization timezone actually drive date-dimension bucketing (ADR-0053 Phase 2, #1982)

    Date-bucketed analytics silently ignored the reference timezone end-to-end. Three independent seams were broken:

    • service-analyticsNativeSQLStrategy (priority 10) won every cube/dataset query on a SQL driver, but it groups by the raw column (no date_trunc) and ignores timezone, so a date dimension never bucketed (one row per raw timestamp) and a non-UTC zone was dropped. It now declines queries that carry a timeDimensions[].granularity, handing them to ObjectQLStrategyengine.aggregate (native bucketing when UTC-safe, uniform in-memory bucketing when non-UTC).
    • objectql — the in-memory count aggregation treated the * count-all sentinel (the Cube count measure / a fieldless dataset count, both compiled to sql: '*') as a column name, counting non-null of a non-existent property → 0 for every bucket. The driver's COUNT(*) masked it; the in-memory path (non-UTC date buckets, driver-rest/driver-memory) returned zeros. * is now counted as all rows.
    • restresolveExecCtx never resolved the localization timezone/locale, so /analytics/dataset/query always ran with timezone: 'UTC'. It now resolves them through the settings service (honouring the 4-tier cascade incl. the OS_LOCALIZATION_TIMEZONE env override), mirroring the dispatcher path.
  • Updated dependencies [db02bd5]

  • Updated dependencies [641675d]

  • Updated dependencies [94e9040]

  • Updated dependencies [1f88fd9]

  • Updated dependencies [1f88fd9]

    • @objectstack/spec@9.10.0
    • @objectstack/core@9.10.0

9.9.1

Patch Changes

  • @objectstack/spec@9.9.1
  • @objectstack/core@9.9.1

9.9.0

Minor Changes

  • 9afeb2d: feat(settings): localization settings — platform default timezone, language & formats (ADR-0053 Phase 2)

    Adds a localization SettingsManifest, the missing keystone that makes the Phase 2 reference-timezone actually configurable end-to-end. One declaration gives the full settings stack for free: platform built-in default → globaltenant cascade, a permission-gated settings page, and i18n.

    Keys (organization-level; per-user overrides intentionally out of scope for v1): timezone (UTC), locale (en-US), default_country, date_format, time_format, number_format, first_day_of_week, currency (USD), fiscal_year_start. Benchmarked against Salesforce/Workday "Company Information + Locale".

    Resolver 收编resolveExecutionContext now resolves timezone and locale from the localization settings via the settings service (canonical 4-tier cascade), falling back to a direct tenant-scoped sys_setting read, then UTC / en-US. This replaces the hand-rolled sys_user_preference + tenant-only sys_setting path from #1978 (which bypassed the settings abstraction and is dropped along with the per-user tier). New ExecutionContext.locale.

    Consumer wiring — analytics date bucketing now picks up the resolved org timezone: DatasetExecutor threads ExecutionContext.timezone into the query (precedence: explicit selection tz → request tz → UTC), so #1982's tz-aware buckets fire for a configured org without callers passing a zone. Formula today()/datetime were already wired (#1979/#1980).

    Email datetime rendering (SendTemplateInput.timezone, shipped in #1981) is intentionally not wired here: the only current sendTemplate callers are pre-session auth emails with no org context; business-notification callers can pass the zone when they appear.

  • 601cc11: feat(analytics): timezone-aware date bucketing (ADR-0053 Phase 2)

    Analytics day/week/month/quarter/year buckets now resolve on a reference timezone's calendar days, so a row near a tz day-boundary lands in the bucket a user in that zone would expect — identically on SQLite and Postgres.

    Per ADR-0053 decision D2, bucketing is done in-memory, uniformly for non-UTC zones rather than emitting dialect-specific date_trunc … AT TIME ZONE (SQLite has no tz database and MySQL needs tz tables loaded, so splitting by dialect would shift bucket boundaries for the same data). engine.aggregate({ timezone }) therefore forces the in-memory aggregation path when a non-UTC reference tz is set — the date-range where still goes to the driver, so only matching rows are fetched. UTC / unset keeps the native driver fast path unchanged.

    • New shared calendarPartsInTz / calendarPartsInTzOrUtc util in @objectstack/core (DST-safe via Intl.DateTimeFormat, never hand-rolled offset math; falls back to UTC for an unset/'UTC'/invalid zone).
    • EngineAggregateOptions and the analytics executeAggregate bridge / ObjectQLStrategy thread the reference timezone (sourced from the dataset selection / ExecutionContext) through to applyInMemoryAggregationbucketDateValue, and the draft-preview evaluator's bucketDate.
    • formatDateBucket (dimension labels) stays UTC-only by design: it re-labels values that were already bucketed upstream, so re-applying a timezone there would shift a correct bucket by a day.

Patch Changes

  • Updated dependencies [84249a4]
  • Updated dependencies [11af299]
  • Updated dependencies [d5774b5]
  • Updated dependencies [134043a]
  • Updated dependencies [90108e0]
  • Updated dependencies [9afeb2d]
  • Updated dependencies [6bec07e]
  • Updated dependencies [601cc11]
  • Updated dependencies [575448d]
    • @objectstack/spec@9.9.0
    • @objectstack/core@9.9.0

9.8.0

Patch Changes

  • Updated dependencies [97c55b3]
  • Updated dependencies [1b1f490]
    • @objectstack/spec@9.8.0
    • @objectstack/core@9.8.0

9.7.0

Patch Changes

  • @objectstack/spec@9.7.0
  • @objectstack/core@9.7.0

9.6.0

Patch Changes

  • Updated dependencies [d1e930a]
  • Updated dependencies [71578f2]
  • Updated dependencies [5e3a301]
  • Updated dependencies [5db2742]
    • @objectstack/spec@9.6.0
    • @objectstack/core@9.6.0

9.5.1

Patch Changes

  • Updated dependencies [ee72aae]
    • @objectstack/spec@9.5.1
    • @objectstack/core@9.5.1

9.5.0

Patch Changes

  • Updated dependencies [d08551c]
  • Updated dependencies [707aeed]
  • Updated dependencies [7a103d4]
  • Updated dependencies [4b01250]
    • @objectstack/spec@9.5.0
    • @objectstack/core@9.5.0

9.4.0

Patch Changes

  • Updated dependencies [060467a]
  • Updated dependencies [0856476]
  • Updated dependencies [b678d8c]
  • Updated dependencies [b678d8c]
  • Updated dependencies [b678d8c]
    • @objectstack/spec@9.4.0
    • @objectstack/core@9.4.0

9.3.0

Minor Changes

  • b4765be: Server-side totals for matrix reports (#1753). queryDataset selections accept totals: { groupings: string[][] } — each grouping a subset of selection.dimensions to additionally aggregate by ([] = grand total); the marginal rows come back on AnalyticsResult.totals in request order. Each subtotal/grand total re-runs the full executor pipeline (measure-scoped filters, derived measures, compareTo) grouped only by that subset, so totals use each measure's true aggregate over the underlying rows — an avg total is the average of all rows, never an average of bucket averages (the ADR-0021 line that forbids client-side re-aggregation). Dimension display labels resolve on totals rows the same as the primary grid. A matrix report renderer asks for { groupings: [rowDims, columnDims, []] } and renders the supplied totals row/column.

Patch Changes

  • Updated dependencies [1ada658]
  • Updated dependencies [3219191]
  • Updated dependencies [290f631]
  • Updated dependencies [50b7b47]
  • Updated dependencies [f15d6f6]
  • Updated dependencies [f8684ea]
  • Updated dependencies [b4765be]
    • @objectstack/spec@9.3.0
    • @objectstack/core@9.3.0

9.2.0

Patch Changes

  • Updated dependencies [2f57b75]
  • Updated dependencies [2f57b75]
    • @objectstack/spec@9.2.0
    • @objectstack/core@9.2.0

9.1.0

Patch Changes

  • Updated dependencies [b9062c9]
    • @objectstack/spec@9.1.0
    • @objectstack/core@9.1.0

9.0.1

Patch Changes

  • Updated dependencies [1817845]
    • @objectstack/spec@9.0.1
    • @objectstack/core@9.0.1

9.0.0

Minor Changes

  • 4a0736b: Analytics now renders date dimensions as human bucket labels instead of raw epoch millis, and buckets them by their declared granularity.

    • A date dimension with an explicit dateGranularity is now grouped by that bucket (the executor promotes it to a time dimension), so a "monthly" trend chart shows one point per month rather than one per raw timestamp.
    • Grouped date values are formatted to a sort-stable label per granularity (year2026, quarter2026-Q2, month2026-04, day/week2026-04-15), so charts no longer show 1777632968596.

    Pairs with the dimension display-label resolution (select option labels / lookup names) shipped previously.

  • 2c6864f: Analytics dimensions now render human display labels instead of raw stored values. A select dimension shows its option label (e.g. Backlog rather than backlog), and a lookup/master_detail dimension shows the related record's display name (e.g. an account's name rather than its FK id). queryDataset resolves these server-side, so every dashboard/report chart benefits with no frontend change. Date/number/string dimensions are unaffected, and unresolved values are left as-is.

  • 0bf39f1: queryDataset now carries each measure's display label and format on the result fields, so presentations can show "Tasks" / "$616,000" instead of the raw measure name "task_count" / "616000".

    • AnalyticsResult.fields[] gains optional label? and format?.
    • The dataset executor enriches measure columns from the dataset's measure definitions (matching <name> and <name>__compare).

    The format can't be baked into the numeric row value (charts need the raw number), so the renderer applies it at display time.

Patch Changes

  • Updated dependencies [4c3f693]
  • Updated dependencies [0bf39f1]
  • Updated dependencies [f533f42]
  • Updated dependencies [1c83ee8]
    • @objectstack/spec@9.0.0
    • @objectstack/core@9.0.0

8.0.1

Patch Changes

  • @objectstack/spec@8.0.1
  • @objectstack/core@8.0.1

8.0.0

Patch Changes

  • Updated dependencies [a46c017]
  • Updated dependencies [b990b89]
  • Updated dependencies [99111ec]
  • Updated dependencies [d5a8161]
  • Updated dependencies [5cf1f1b]
  • Updated dependencies [9ef89d4]
  • Updated dependencies [3306d2f]
  • Updated dependencies [c262301]
  • Updated dependencies [bc44195]
  • Updated dependencies [9e2e229]
    • @objectstack/spec@8.0.0
    • @objectstack/core@8.0.0

7.9.0

Patch Changes

  • @objectstack/spec@7.9.0
  • @objectstack/core@7.9.0

7.8.0

Patch Changes

  • Updated dependencies [06f2bbb]
  • Updated dependencies [36719db]
  • Updated dependencies [424ab26]
    • @objectstack/spec@7.8.0
    • @objectstack/core@7.8.0

7.7.0

Patch Changes

  • Updated dependencies [b391955]
  • Updated dependencies [f06b64e]
  • Updated dependencies [023bf93]
    • @objectstack/spec@7.7.0
    • @objectstack/core@7.7.0

7.6.0

Patch Changes

  • Updated dependencies [955d4c8]
  • Updated dependencies [c4a4cbd]
  • Updated dependencies [b046ec2]
  • Updated dependencies [2170ad9]
  • Updated dependencies [02d6359]
  • Updated dependencies [7648242]
  • Updated dependencies [8fa1e7f]
  • Updated dependencies [55866f5]
  • Updated dependencies [60f9c45]
    • @objectstack/spec@7.6.0
    • @objectstack/core@7.6.0

7.5.0

Patch Changes

  • @objectstack/spec@7.5.0
  • @objectstack/core@7.5.0

7.4.1

Patch Changes

  • @objectstack/spec@7.4.1
  • @objectstack/core@7.4.1

7.4.0

Patch Changes

  • Updated dependencies [23c7107]
  • Updated dependencies [c72daad]
  • Updated dependencies [f115182]
  • Updated dependencies [2faf9f2]
  • Updated dependencies [2faf9f2]
  • Updated dependencies [2faf9f2]
  • Updated dependencies [58b450b]
  • Updated dependencies [82eb6cf]
  • Updated dependencies [13d8653]
  • Updated dependencies [ff3d006]
  • Updated dependencies [5e831de]
    • @objectstack/spec@7.4.0
    • @objectstack/core@7.4.0

7.3.0

Patch Changes

  • Updated dependencies [5e7c554]
    • @objectstack/spec@7.3.0
    • @objectstack/core@7.3.0

7.2.1

Patch Changes

  • @objectstack/spec@7.2.1
  • @objectstack/core@7.2.1

7.2.0

Patch Changes

  • @objectstack/spec@7.2.0
  • @objectstack/core@7.2.0

7.1.0

Patch Changes

  • Updated dependencies [47a92f4]
    • @objectstack/spec@7.1.0
    • @objectstack/core@7.1.0

7.0.0

Patch Changes

  • Updated dependencies [74470ad]
  • Updated dependencies [d29617e]
  • Updated dependencies [dc72172]
    • @objectstack/spec@7.0.0
    • @objectstack/core@7.0.0

6.9.0

Patch Changes

  • @objectstack/spec@6.9.0
  • @objectstack/core@6.9.0

6.8.1

Patch Changes

  • @objectstack/spec@6.8.1
  • @objectstack/core@6.8.1

6.8.0

Patch Changes

  • Updated dependencies [6e88f77]
  • Updated dependencies [c8b9f57]
    • @objectstack/spec@6.8.0
    • @objectstack/core@6.8.0

6.7.1

Patch Changes

  • @objectstack/spec@6.7.1
  • @objectstack/core@6.7.1

6.7.0

Patch Changes

  • Updated dependencies [430067b]
  • Updated dependencies [4f9e9d4]
    • @objectstack/spec@6.7.0
    • @objectstack/core@6.7.0

6.6.0

Patch Changes

  • Updated dependencies [a49cfc2]
    • @objectstack/spec@6.6.0
    • @objectstack/core@6.6.0

6.5.1

Patch Changes

  • @objectstack/spec@6.5.1
  • @objectstack/core@6.5.1

6.5.0

Patch Changes

  • @objectstack/spec@6.5.0
  • @objectstack/core@6.5.0

6.4.0

Patch Changes

  • Updated dependencies [f8651cc]
  • Updated dependencies [f8651cc]
  • Updated dependencies [0bf6f9a]
    • @objectstack/spec@6.4.0
    • @objectstack/core@6.4.0

6.3.0

Patch Changes

  • @objectstack/spec@6.3.0
  • @objectstack/core@6.3.0

6.2.0

Patch Changes

  • Updated dependencies [b4c74a9]
    • @objectstack/spec@6.2.0
    • @objectstack/core@6.2.0

6.1.1

Patch Changes

  • @objectstack/spec@6.1.1
  • @objectstack/core@6.1.1

6.1.0

Patch Changes

  • Updated dependencies [93c0589]
    • @objectstack/spec@6.1.0
    • @objectstack/core@6.1.0

6.0.0

Patch Changes

  • Updated dependencies [629a716]
  • Updated dependencies [dbc4f7d]
  • Updated dependencies [944f187]
    • @objectstack/spec@6.0.0
    • @objectstack/core@6.0.0

5.2.0

Patch Changes

  • Updated dependencies [bab2b20]
  • Updated dependencies [fa011d8]
  • Updated dependencies [b806f58]
    • @objectstack/spec@5.2.0
    • @objectstack/core@5.2.0

5.1.0

Patch Changes

  • Updated dependencies [75f4ee6]
  • Updated dependencies [823d559]
    • @objectstack/spec@5.1.0
    • @objectstack/core@5.1.0

5.0.0

Patch Changes

  • Updated dependencies [2f9073a]
    • @objectstack/spec@5.0.0
    • @objectstack/core@5.0.0

4.2.0

Patch Changes

  • Updated dependencies [2869891]
    • @objectstack/spec@4.2.0
    • @objectstack/core@4.2.0

4.1.1

Patch Changes

  • @objectstack/spec@4.1.1
  • @objectstack/core@4.1.1

4.1.0

Patch Changes

  • Updated dependencies [2108c30]
  • Updated dependencies [23db640]
    • @objectstack/spec@4.1.0
    • @objectstack/core@4.1.0

4.0.5

Patch Changes

  • 15e0df6: chore: unify all package versions to a single patch release
  • Updated dependencies [15e0df6]
    • @objectstack/spec@4.0.5
    • @objectstack/core@4.0.5

4.0.4

Patch Changes

  • Updated dependencies [326b66b]
    • @objectstack/spec@4.0.4
    • @objectstack/core@4.0.4

4.0.3

Patch Changes

  • @objectstack/spec@4.0.3
  • @objectstack/core@4.0.3

4.0.2

Patch Changes

  • Updated dependencies [5f659e9]
    • @objectstack/spec@4.0.2
    • @objectstack/core@4.0.2

4.0.0

Patch Changes

  • Updated dependencies [f08ffc3]
  • Updated dependencies [e0b0a78]
    • @objectstack/spec@4.0.0
    • @objectstack/core@4.0.0

3.3.1

Patch Changes

  • @objectstack/spec@3.3.1
  • @objectstack/core@3.3.1

3.2.10

Patch Changes

  • @objectstack/spec@3.3.0
  • @objectstack/core@3.3.0

All notable changes to this package will be documented in this file.

[3.2.9] — 2026-03-22

Added

  • Initial implementation of @objectstack/service-analytics
  • AnalyticsService orchestrator implementing IAnalyticsService
  • Strategy pattern with priority chain:
    • P1 — NativeSQLStrategy: Pushes queries as native SQL to SQL-capable drivers (Postgres, MySQL, etc.)
    • P2 — ObjectQLStrategy: Translates analytics queries into ObjectQL engine.aggregate() calls
    • P3 — InMemoryStrategy: Delegates to any registered IAnalyticsService (e.g., MemoryAnalyticsService)
  • CubeRegistry for auto-discovery and registration of cubes from manifest definitions and object schema inference
  • AnalyticsServicePlugin for kernel plugin lifecycle integration
  • queryCapabilities() driver capability probing for strategy selection
  • generateSql() dry-run SQL generation across all strategies
  • Unit tests covering all strategy branches