Skip to content

fix(analytics): timeDimensions 分桶维度回到结果的 rows 与 fields (#4033) - #4069

Merged
os-zhuang merged 1 commit into
mainfrom
claude/sqlite-datetime-filter-empty-hradlv
Jul 30, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/sqlite-datetime-filter-empty-hradlv

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4033。

问题

只用 timeDimensions 分桶的 analytics 查询,分组是对的 —— 回显的 SQL 就是 date_trunc('month', due_date) AS "due_date" —— 但结果里没有这个维度:

rows:   [{ "count": 2 }, { "count": 8 }]
fields: [{ "name": "count", "type": "number" }]

趋势图因此拿到 N 个数值却没有 x 轴标签。数值全对,所以下游没有任何报错,只是标签没了;把同一个查询写成 dimensions: ['due_date'] 又完全正常 —— 这就是它一直没被发现的原因。是 dogfood 真实跑 showcase app 时发现的,不是静态审出来的。

根因

ObjectQLStrategy 里三处对「哪些维度被投影」各有一套判断:

  • groupBy(3 处,主路径 / generateSql / cross-object):dimensions + 带 granularity 的 timeDimensions ✅
  • 主路径行映射:只枚举 query.dimensions ❌
  • buildFieldMeta:只枚举 query.dimensions ❌
  • cross-object 行映射:自己另写了一份正确的循环 ✅(但与上面两处平行维护)

引擎按时间桶分了组、行里也带着它,映射这一步把它丢了。

修法

三方(分组、行映射、字段元数据)统一由一个 projectedDimensions() 推导:dimensions 加上所有带 granularity 且不重复的 timeDimensions。

以 granularity 为闸门是因为那正是三处 groupBy 的判据 —— 不带 granularity 的条目只贡献 dateRange 谓词,把它投影出去会声明一个引擎从没分组过的列。cross-object 那份「正确但平行」的循环也并入同一定义,不再是第二个需要同步的地方。

验证

新增 objectql-timedimension-projection.test.ts(5 例)。先验证它能抓到 bug:在未修复的代码上跑 → 3 失败 2 通过(通过的那 2 个是负向断言,本就该过);修复后 5/5。

覆盖:桶进 rows、桶进 fields、timeDimensions 写法与 dimensions 写法结果一致、同时出现时不重复、不带 granularity 的条目不得被投影。

  • service-analytics 329/329
  • driver-sql 508 passed / 38 skipped
  • objectql 1179/1179

过程说明:首轮跑出 10 个失败(涉及 #3777/#3912/#3650),我先在未改动的 main 上复跑确认同样失败,再定位到是本工作树 dist 过期(#4041 新增的 nextUtcCalendarDay 尚未构建进 @objectstack/core)。全量重建后归零,与本 PR 无关。

🤖 Generated with Claude Code

https://claude.ai/code/session_01TPxNwPnjcn599ujXpU3ibJ


Generated by Claude Code

…and fields

A query bucketing by `timeDimensions` alone grouped correctly — the echoed SQL
read `date_trunc('month', due_date) AS "due_date"` — but the row mapper and
buildFieldMeta both enumerated `query.dimensions` only, so the bucket was
dropped on the way out:

  rows:   [{ count: 2 }, { count: 8 }]
  fields: [{ name: 'count', type: 'number' }]

A trend chart therefore got N values and no x-axis. Found by driving a live
showcase app, not by static review: the numbers were right, so nothing
downstream errored — only the labels were gone. Writing the same query as
`dimensions: ['due_date']` was always fine, which is why it survived.

Grouping, row mapping (both the direct and cross-object paths) and field
metadata now derive their projected set from one `projectedDimensions()`
helper: `dimensions` plus every GRANULAR `timeDimensions` entry not already
among them. Granularity is the right gate because it is exactly what the three
groupBy sites key on — an entry without one contributes only a `dateRange`
predicate, and projecting it would declare a column the engine never grouped
by. The cross-object path already had its own correct-but-parallel loop; it now
shares the single definition rather than being a second place to keep in sync.

Closes #4033

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPxNwPnjcn599ujXpU3ibJ
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 7:58am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): packages/services.

6 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/webhooks.mdx (via packages/services)
  • content/docs/kernel/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/index.mdx (via packages/services)
  • content/docs/kernel/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/plugins/packages.mdx (via packages/services)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/services)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Analytics: a timeDimensions-bucketed query drops the bucket label from rows and fields — trend charts get counts with no x-axis

2 participants