Skip to content

Commit 6643ba1

Browse files
docs(spec): $exists asks whether a field has a value, not whether a key is present (#14050)
* docs(spec): $exists asks for a value, not a present key (#13709) The JSDoc on `SpecialOperatorSchema.$exists` read "Field exists check (primarily for NoSQL)", which describes key-presence. `$exists` stopped meaning key-presence when the has-value alignment landed (PR #13529 / 9dac1ae); the line was false, not merely stale, and it was the last of six sites still carrying the old claim. Replaced with the wording recorded on #13539 and already shipped on the other five sites, adapted to this file's JSDoc idiom (the sibling `$null` line annotates which boolean maps to which lowering, so this one does too). Direction verified against all three evaluators before rewriting. Prose only: `$exists` is `z.boolean().optional()` before and after, and the comment is not a `.describe()`, so no generated artifact moves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1 * docs(changeset): state the measured surfaces, not the assumed one (#13709) The first draft claimed the corrected JSDoc reaches consumers as `.d.ts` hover text. Measured on a freshly built dist: zero `.d.ts`/`.d.mts` carry it (the property's type is inferred from Zod, so no declaration comment is emitted) — it appears in `dist` only inside `.js.map` sourcemaps. The surface that does carry it is published SOURCE: this package's `files` array ships `src/**/*.zod.ts`, so `filter.zod.ts` itself is in the tarball. Recorded alongside the two negative results, since a PR correcting a false claim must not ship one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent ada3834 commit 6643ba1

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
docs(spec): `$exists` JSDoc said key-presence, which has been false since protocol alignment (#13709)
6+
7+
`SpecialOperatorSchema.$exists` carried `Field exists check (primarily for NoSQL) -
8+
MongoDB: $exists`. That describes key-presence, and key-presence stopped being what
9+
`$exists` means when the has-value alignment landed (PR #13529 / `9dac1ae017`). The
10+
line was not stale phrasing — it was false, and it is the last of the six sites that
11+
carried the old claim; the other five were corrected by PR #13581 / PR #13577.
12+
13+
The corrected wording is the one recorded on #13539 and already shipped on those five
14+
sites: `$exists` asks whether the field HAS A VALUE (`!= null`), the exact inverse of
15+
`$null`, never key presence — lowered to `IS NOT NULL` / `IS NULL` on SQL and to
16+
`{$ne: null}` / `{$eq: null}` on MongoDB. Verified against all three evaluators before
17+
rewriting: `formula`'s `matchesFilterCondition` (`v === true ? actual != null : actual == null`),
18+
`objectql`'s `having` face, and the `filter-logic-conformance.ts` table, which enrolls
19+
`$exists` in both directions.
20+
21+
Prose only. No accept/reject change: `$exists` was and stays `z.boolean().optional()`,
22+
and the JSDoc is a comment, not a `.describe()` — the schema, its JSON-Schema
23+
projection and all 15 generated artifacts are byte-identical (`check:generated` green
24+
on a freshly built `dist`).
25+
26+
Where the corrected line does and does not surface, measured rather than assumed:
27+
28+
- **Published source — yes.** This package's `files` array ships `src/**/*.zod.ts`, so
29+
`filter.zod.ts` is in the npm tarball and the comment reaches consumers verbatim.
30+
That is the surface this patch is for.
31+
- **Emitted `.d.ts` — no.** Zero of the emitted `.d.ts`/`.d.mts` carry the text; the
32+
property's type is inferred from Zod, so no declaration comment is written. It
33+
appears in `dist` only inside `.js.map` sourcemaps.
34+
- **Generated reference page — no.** `content/docs/references/data/filter.mdx` renders
35+
its Description column from `prop.description`, i.e. a Zod `.describe()`; `$exists`
36+
carries none, so that cell is empty before and after. Regenerating all 230 pages
37+
produces no diff. See #13709 for the follow-up on that empty cell.

packages/spec/src/data/filter.zod.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,11 @@ export const SpecialOperatorSchema = lazySchema(() => z.object({
994994
/** Is null check - SQL: IS NULL (true) / IS NOT NULL (false) | MongoDB: field: null */
995995
$null: z.boolean().optional(),
996996

997-
/** Field exists check (primarily for NoSQL) - MongoDB: $exists */
997+
/**
998+
* Field HAS A VALUE (`!= null`) — the inverse of `$null`, never key presence.
999+
* Lowered to `IS NOT NULL` (true) / `IS NULL` (false) on SQL and to
1000+
* `{$ne: null}` / `{$eq: null}` on MongoDB.
1001+
*/
9981002
$exists: z.boolean().optional(),
9991003
}));
10001004

0 commit comments

Comments
 (0)