Handle dal.IsNullCondition (isNull / isNotNull) in chat joins, access policies and compare-facts

未关闭
#316 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
55/100
Issue 类型
功能
描述清晰度
描述清楚
活跃度
活跃
技术栈
go

调研方向

Start with the listed switches in pkg/chat/join.go, pkg/accesspolicies/fields.go, pkg/accesspolicies/run.go, and pkg/server/endpoints/compare_facts.go, then review the nearby tests and the dalgo release containing dal-go/dalgo#193. Check the optional dbcopy filter files separately. Done means null-test queries qualify joins, respect field policies and parameter checks, remain eligible for compare-facts when safe, and adapters do not silently ignore them.

由索引模型根据 Issue 内容生成。

描述

Background

dal-go/dalgo#193 (with its TypeScript counterpart dal-go/dalgo-js#10) adds an explicit null test to the dalgo condition model and to DTQL:

  • Go: dal.IsNullCondition, built with dal.NewIsNullCondition(expr) / dal.NewIsNotNullCondition(expr) / FieldRef.IsNull() / FieldRef.IsNotNull(); read with Operand() dal.Expression and Negated() bool; String() renders x IS NULL / x IS NOT NULL.
  • DTQL: isNull: <expression> / isNotNull: <expression> anywhere a condition is allowed (where, having, inside and/or, nested queries); never in a join on list.
  • Meaning: TRUE or FALSE for every input, never UNKNOWN. A field absent from a record, an explicit null and a nil pointer (dal.IsNullValue) all count as NULL. The operand is a field, a literal, arithmetic or a scalar subquery; values, star, param and a WHERE aggregate are rejected at parse.
  • Why it exists: x == null is UNKNOWN in the WHERE of a joined, nested or federated-aggregate query (matches no row) but means IS NULL when a single-source query is pushed down to an adapter, so a filter that matched 49 rows alone matched 0 once joined. isNull has one meaning everywhere. (HAVING is two-valued, HAVING g == null returns the null group; that pre-existing WHERE/HAVING difference is documented in dal-go/dalgo dtql/README.md and left unchanged.)
  • Rule for adapters (dal-go/dalgo docs/queries.md, "Testing for NULL"): an adapter that evaluates a query itself and cannot translate or evaluate a null test must fail the query rather than ignore the condition. Today the default arms listed below already do, so nothing is silently dropped; this issue is about supporting it.
  • Not in scope: access-policy predicates (access.DocumentCondition, condeval) keep rejecting null tests on purpose (layered-ACL acceptance V02: a missing field never matches).

Line numbers below are for the default branch at the commit named in each section.

Sites (datatug/datatug-cli @ 2b6df4c0e5cec84965bf855cb5fa10ab4a1ba446, depends on dalgo v0.88.0)

  1. pkg/chat/join.go:586 qualifyJoinCondition (switch :590; Comparison :591, GroupCondition :601). Prefixes unqualified FieldRefs with the root alias in the chat JOIN builder. Default errors unsupported condition %T, so a derived chat JOIN over a query with a null test fails. Add a case that qualifies Operand() with the existing qualifyJoinExpression (:622) and rebuilds with dal.NewIsNullCondition / dal.NewIsNotNullCondition (keep Negated()).
  2. pkg/accesspolicies/fields.go:36-37 walkCondition, a closure inside referencedFields (:16; switch :38 with Comparison/*Comparison :41/:43 and GroupCondition/*GroupCondition :45/:47). Default errors unsupported condition %T (intentional fail-closed). referencedFields is called by hiddenReferences (:171) from pkg/accesspolicies/run.go:79, which runs only when a field allow-list policy applies, where the walker error becomes access.ErrAccessDenied: cannot verify the query against field-restricted policies. So today every query with an isNull/isNotNull is denied under a field-restricted policy. Add a case that walks Operand() with walkExpression (value and pointer forms, like Comparison) so a null test on a hidden field is reported as a hidden reference and one on an allowed field passes. Tests next to accesspolicies_test.go:268.
  3. pkg/accesspolicies/run.go:154 walkParams (switch :155; Comparison :156/:161, GroupCondition :166/:170, no default). An unknown type is silently ignored, so a Param inside a null-test operand would escape the "params only on the right of a comparison" check used by misplacedParams (:121) / paramsIn (:142) and substituteParams (~:108). Visit Operand() and treat a Param there as misplaced. (DTQL no longer parses a param operand; this closes the programmatic path.)
  4. pkg/server/endpoints/compare_facts.go:167 countNativeInBindings (switch :168; Comparison :169, *Comparison :179, GroupCondition :183, *GroupCondition :196; helper comparisonMentionsCohortBinding :204). An unknown type falls through to return 0, false ("not safe"), so a saved query containing a null test becomes ineligible for compare-facts. Add a case returning 0, true when the operand does not mention the cohort field/parameter and 0, false when it does.
  5. Optional: pkg/dbcopy/filter/operator.go (:11-14, :38-45) lists is_null / is_not_null as deferred because dalgo lacked them; pkg/dbcopy/filter/compile.go:42 builds conditions through dal.WhereField. These can now map to dal.NewIsNullCondition / NewIsNotNullCondition.
  6. Safe, no change: pkg/chat/join.go:818 and apps/datatugapp/commands/cmd_query_run_saved.go:434 only inspect join ON conditions.

Expected behavior

A saved query / chat result using isNull / isNotNull can be joined, runs under field-restricted policies exactly like the equivalent comparison would (hidden fields stay hidden), and stays eligible for compare-facts when the null test does not involve the cohort binding. Bump github.com/dal-go/dalgo to the release containing dal-go/dalgo#193 first.

Context for the chat UI: when a derived join copies the parent's filter, == null / != null should be written as isNull / isNotNull (see datatug-apps) because a joined WHERE evaluates == null as UNKNOWN.

🤖 Generated with Claude Code

主要语言
Go
星标
1
派生
0
平均合并
7 小时 18 分钟
30 天内合并 PR
181

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

datatug/datatug-cli 的其他 Issue

查看 datatug/datatug-cli 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。