Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/spec/src/data/filter-comparand-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Money {
constructor(readonly v: number) {}
}

describe('the accepted set (#7872 ruling)', () => {
describe('the accepted set — one set, defined at the shared door for every driver', () => {
it('is exactly the measured superset — string | number | bigint | boolean | null | Date', () => {
expect([...ACCEPTED_FILTER_COMPARAND_TYPES]).toEqual([
'string', 'number', 'bigint', 'boolean', 'null', 'Date',
Expand Down Expand Up @@ -118,7 +118,7 @@ describe('refusals — the measured divergence rows die at the door', () => {
expect(err?.message).toContain('where.qty');
});

it.each(refused)('refuses %s as an $in member — each member is a comparand in its own right (#5234)', (_name, value) => {
it.each(refused)('refuses %s as an $in member — each member is a comparand in its own right', (_name, value) => {
const err = refusalOf(() => normalizeFilterComparandTypes({ qty: { $in: [100, value] } }));
expect(err?.code).toBe('INVALID_FILTER');
expect(err?.message).toContain('where.qty.$in[1]');
Expand All @@ -131,7 +131,7 @@ describe('refusals — the measured divergence rows die at the door', () => {
expect(err?.message).toMatch(/omit/);
});

it('the undefined prescription is position-safe: it names the null predicate by its ruled spellings, at every position it is emitted at (#14426)', () => {
it('the undefined prescription is position-safe: it names the null predicate by its ruled spellings, at every position it is emitted at', () => {
// "Write null for the null predicate" was position-agnostic advice: followed
// at `$gt: undefined` it produced `$gt: null`, refused one door over since
// the 2026-09-01 ruling; at an `$in` member it produced `$in: [null]`,
Expand Down Expand Up @@ -183,7 +183,7 @@ describe('refusals — the measured divergence rows die at the door', () => {
});
});

describe('bigint — accepted, and NARROWED copy-on-write (#7872; the memory crash cell dies here)', () => {
describe('bigint — accepted, and NARROWED copy-on-write (the memory crash cell dies here)', () => {
it('narrows an exact-range bigint to its number, without touching the caller’s object', () => {
const original = { qty: { $eq: BigInt(100) } };
const out = normalizeFilterComparandTypes(original);
Expand Down Expand Up @@ -222,7 +222,7 @@ describe('bigint — accepted, and NARROWED copy-on-write (#7872; the memory cra
});

describe('boundaries the door deliberately does not cross', () => {
it('leaves a FieldReference alone at every position — #5222/scalar comparison/#7597 own its fate', () => {
it('leaves a FieldReference alone at every position — cross-field push-down, scalar comparison and the `$eq` lowering own its fate', () => {
for (const filter of [
{ amount: { $gt: { $field: 'budget' } } },
{ amount: { $eq: { $field: 'budget' } } },
Expand All @@ -233,7 +233,7 @@ describe('boundaries the door deliberately does not cross', () => {
}
});

it('does not descend into a no-$-key plain object — nested-relation / deep-equality structure (#5869 boundary)', () => {
it('does not descend into a no-$-key plain object — nested-relation / deep-equality structure', () => {
const filter = { author: { name: 'x' } };
expect(normalizeFilterComparandTypes(filter)).toBe(filter);
});
Expand All @@ -252,18 +252,18 @@ describe('boundaries the door deliberately does not cross', () => {
expect(normalizeFilterComparandTypes(retired)).toBe(retired);
});

it('does not judge a non-array list-operator comparand — that SHAPE belongs to the engine’s #5869 gate', () => {
it('does not judge a non-array list-operator comparand — that SHAPE is refused 400 by the engine’s shape gate', () => {
const filter = { stage: { $in: 'won' } };
expect(normalizeFilterComparandTypes(filter)).toBe(filter);
});

it('keeps the zero-operator constraint for the driver refusal that names it (#5240)', () => {
it('keeps the zero-operator constraint for the driver refusal that names it', () => {
const filter = { qty: {} };
expect(normalizeFilterComparandTypes(filter)).toBe(filter);
});
});

describe('parseFilterAST is the compile face that runs the door (#7872)', () => {
describe('parseFilterAST is the compile face that runs the door', () => {
it('judges the OBJECT passthrough — the form that used to leave unexamined', () => {
const err = refusalOf(() => parseFilterAST({ qty: { $eq: Symbol('x') } }));
expect(err?.code).toBe('INVALID_FILTER');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const union = (...sets: ReadonlySet<string>[]) => new Set(sets.flatMap((s) => [.
const cls = (c: string): CrossFieldColumnVerdict => ({ kind: 'class', class: c } as CrossFieldColumnVerdict);
const none = (r: string): CrossFieldColumnVerdict => ({ kind: 'no-class', reason: r } as CrossFieldColumnVerdict);

describe('[#20347] the class table', () => {
describe('the class table — one classification, read by every judge', () => {
it('classifies every FieldType member exactly once — rows pairwise disjoint, union exactly FieldType', () => {
const seen = new Map<string, string>();
for (const row of CROSS_FIELD_COMPARISON_TYPE_CLASSES) {
Expand Down Expand Up @@ -107,7 +107,7 @@ describe('[#20347] the class table', () => {
});
});

describe('[#20347] crossFieldColumnVerdict — one declared column', () => {
describe('crossFieldColumnVerdict — one declared column', () => {
it('answers each FieldType member its row\'s verdict when declared single-valued', () => {
for (const row of CROSS_FIELD_COMPARISON_TYPE_CLASSES) {
for (const type of row.types) {
Expand Down Expand Up @@ -140,7 +140,7 @@ describe('[#20347] crossFieldColumnVerdict — one declared column', () => {
});
});

describe('[#20347] crossFieldComparisonVerdict — the measured cells', () => {
describe('crossFieldComparisonVerdict — the measured cells', () => {
it('text vs number is cross-class, in both orders', () => {
expect(crossFieldComparisonVerdict({ type: 'text' }, { type: 'number' }))
.toEqual({ verdict: 'cross-class', left: 'text', right: 'numeric' });
Expand Down Expand Up @@ -183,7 +183,7 @@ describe('[#20347] crossFieldComparisonVerdict — the measured cells', () => {
});
});

describe('[#20347] crossFieldComparisonVerdict — every pair of declared columns', () => {
describe('crossFieldComparisonVerdict — every pair of declared columns', () => {
// Every FieldType member single-valued, plus every multi-capable member
// flagged `multiple: true`.
const columns = [
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/src/data/filter-dotted-head.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { SEARCH_VIRTUAL_TYPES } from './search-fields';
// DELIBERATELY unjudged (structured/JSON — live on two of three backends, the
// carve-out the maintainer ruling names with a ⛔).
// ---------------------------------------------------------------------------
describe('[#8371] classifyDottedFilterHead — the FILTER axis dotted verdict', () => {
describe('classifyDottedFilterHead — the FILTER axis dotted verdict, by the type of the head segment', () => {
it('a relation head is refused: the stored value is a scalar id, not an embedded document', () => {
expect(classifyDottedFilterHead({ type: 'lookup' })).toBe('relation');
expect(classifyDottedFilterHead({ type: 'master_detail' })).toBe('relation');
Expand All @@ -37,7 +37,7 @@ describe('[#8371] classifyDottedFilterHead — the FILTER axis dotted verdict',
}
});

it('a virtual head is refused: the #8296 verdict finally reaching the dotted spelling', () => {
it('a virtual head is refused: the unmaterializable-field verdict finally reaching the dotted spelling', () => {
for (const type of SEARCH_VIRTUAL_TYPES) {
expect(classifyDottedFilterHead({ type }), `'${type}' must classify as virtual`).toBe('virtual');
}
Expand Down
10 changes: 5 additions & 5 deletions packages/spec/src/data/filter-empty-operator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function descriptionOf(shape: Record<string, unknown>, key: string): string | un
// §1 The description IS the ruled table
// ---------------------------------------------------------------------------

describe('#20311 §1 — the $empty description is the ruled per-type table', () => {
describe('§1 — the $empty description is the ruled per-type table', () => {
/** The ruled table, verbatim as the operator describes it. */
const RULED_TABLE =
'Is-empty check by the field\'s DECLARED type. `true` matches rows whose field is empty, '
Expand Down Expand Up @@ -118,7 +118,7 @@ describe('#20311 §1 — the $empty description is the ruled per-type table', ()
// §2 The schema door: $empty parses; the empty list is still refused
// ---------------------------------------------------------------------------

describe('#20311 §2 — { tags: { $empty: true } } parses; { tags: [] } is still refused', () => {
describe('§2 — { tags: { $empty: true } } parses; { tags: [] } is still refused', () => {
it('the enforced operator slot keeps a boolean $empty rather than stripping it', () => {
// An undeclared key on this non-strict object is STRIPPED on parse; a
// declared one survives. `toEqual` holding both values is the difference.
Expand All @@ -145,7 +145,7 @@ describe('#20311 §2 — { tags: { $empty: true } } parses; { tags: [] } is stil
expect(NormalizedFilterSchema.safeParse({ $and: [{ tags: { $empty: 'yes' } }] }).success).toBe(false);
});

it('the empty list stays refused in the equality slot — ruling 乙 on #19757 is untouched', () => {
it('the empty list stays refused in the equality slot — the ruled refusal of an array there is untouched', () => {
for (const [where, path] of [
[{ tags: [] }, 'tags'],
[{ tags: { $eq: [] } }, 'tags.$eq'],
Expand Down Expand Up @@ -178,7 +178,7 @@ describe('#20311 §2 — { tags: { $empty: true } } parses; { tags: [] } is stil
// §3 The expansion: three arms for the three field kinds, and the value test
// ---------------------------------------------------------------------------

describe('#20311 §3 — expandEmptyOperator answers the ruled arm per field definition', () => {
describe('§3 — expandEmptyOperator answers the ruled arm per field definition', () => {
it('is published on the data entry — the one function every compile surface imports', () => {
expect(dataBarrel.expandEmptyOperator).toBe(expandEmptyOperator);
expect(dataBarrel.isEmptyFilterValue).toBe(isEmptyFilterValue);
Expand Down Expand Up @@ -249,7 +249,7 @@ describe('#20311 §3 — expandEmptyOperator answers the ruled arm per field def
// §4 The flip: in FILTER_OPERATORS, and the view operators lower to it
// ---------------------------------------------------------------------------

describe('#20446 §4 — $empty is IN FILTER_OPERATORS and is_empty / is_not_empty lower to it', () => {
describe('§4 — $empty is IN FILTER_OPERATORS and is_empty / is_not_empty lower to it', () => {
it('is in FILTER_OPERATORS, beside the other value-presence flags', () => {
// Inverted from #20311's staging pin (the maintainer's amendment, record
// 5868169573): every compile face answers `$empty` now (#20444, #20445),
Expand Down
10 changes: 5 additions & 5 deletions packages/spec/src/data/filter-equality-array-schema-door.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const REFUSED: ReadonlyArray<readonly [label: string, where: unknown, issuePath:
// §1 FilterConditionSchema refuses both spellings, at the slot's own path
// ---------------------------------------------------------------------------

describe('#19889 §1 — FilterConditionSchema refuses an array in the equality slot', () => {
describe('§1 — FilterConditionSchema refuses an array in the equality slot', () => {
it.each(REFUSED)('refuses %s', (_label, where, issuePath) => {
const issue = issueAt(FilterConditionSchema.safeParse(where), issuePath);
expect(issue.message).toMatch(/requires a single comparable value, but received an array/);
Expand All @@ -104,7 +104,7 @@ describe('#19889 §1 — FilterConditionSchema refuses an array in the equality
// §2 FieldOperatorsSchema.$eq refuses — the enforced copy and the documented one
// ---------------------------------------------------------------------------

describe('#19889 §2 — the $eq operator slot refuses an array', () => {
describe('§2 — the $eq operator slot refuses an array', () => {
it.each([
['FieldOperatorsSchema (the enforced copy)', FieldOperatorsSchema],
['EqualityOperatorSchema (the documentation copy)', EqualityOperatorSchema],
Expand All @@ -125,7 +125,7 @@ describe('#19889 §2 — the $eq operator slot refuses an array', () => {
// §3 The parse-door message IS the compile-face message
// ---------------------------------------------------------------------------

describe('#19889 §3 — one text, two doors', () => {
describe('§3 — one text, two doors', () => {
it.each(REFUSED)('%s — the schema door prints the face\'s sentence', (_label, where, issuePath, facePath) => {
const face = faceRefusal(where);
// The face is the ADR-0112 class-1 refusal it has been since #19757.
Expand Down Expand Up @@ -174,7 +174,7 @@ describe('#19889 §3 — one text, two doors', () => {
// §4 CONTROLS — both doors accept, so the arm is exactly the face's
// ---------------------------------------------------------------------------

describe('#19889 §4 — what stays accepted, at BOTH doors', () => {
describe('§4 — what stays accepted, at BOTH doors', () => {
const day = new Date('2026-07-01T00:00:00.000Z');
it.each([
['a string', { stage: 'won' }],
Expand Down Expand Up @@ -244,7 +244,7 @@ describe('#19889 §4 — what stays accepted, at BOTH doors', () => {
// §5 The stored carriers refuse on save, naming the path
// ---------------------------------------------------------------------------

describe('#19889 §5 — a stored filter carrier refuses the shape on save', () => {
describe('§5 — a stored filter carrier refuses the shape on save', () => {
const dataset = (extra: Record<string, unknown>) => ({
name: 'deals_ds',
label: 'Deals',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const EQUALITY_SPELLINGS = ['=', '==', 'equals', 'eq'] as const;

const REF = { $field: 'budget' } as const;

describe('[#7597] equality triples with a `{ $field }` comparand', () => {
describe('equality triples with a `{ $field }` comparand — lowered to `$eq`, never a bare field spec', () => {
// ── The fix ───────────────────────────────────────────────────────────────

for (const op of EQUALITY_SPELLINGS) {
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/src/data/filter-icontains-parse-door.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ function issueAt(
// §1 the `$` dialect door — FilterConditionSchema
// ---------------------------------------------------------------------------

describe('#19514 §1 — the $ dialect refuses what the table declares refused', () => {
describe('§1 — the $ dialect refuses what the table declares refused', () => {
it.each([
['the EMPTY comparand', '', 'EMPTY STRING'],
['a NUMBER comparand', 42, 'not a string'],
Expand Down Expand Up @@ -156,7 +156,7 @@ describe('#19514 §1 — the $ dialect refuses what the table declares refused',
// §2 the infix/view dialect door — ViewFilterRuleSchema
// ---------------------------------------------------------------------------

describe('#19514 §2 — the view vocabulary refuses the same two comparands', () => {
describe('§2 — the view vocabulary refuses the same two comparands', () => {
const rule = (value?: unknown) =>
ViewFilterRuleSchema.safeParse(
value === undefined
Expand Down Expand Up @@ -241,7 +241,7 @@ describe('#19514 §2 — the view vocabulary refuses the same two comparands', (
// §3 both doors are DRIVEN BY the table, not by a copy of it
// ---------------------------------------------------------------------------

describe('#19514 §3 — a row added to FILTER_TEXT_CASES reaches both doors', () => {
describe('§3 — a row added to FILTER_TEXT_CASES reaches both doors', () => {
it('the table still carries rows for this operator, so this suite is not vacuous', () => {
expect(TABLE_ROWS.length).toBeGreaterThan(0);
});
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/src/data/filter-like-code-point.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const FAMILY: ReadonlyArray<readonly ['$like' | '$ilike', string, readonly strin
const answer = (match: (v: string) => boolean): string[] =>
Object.entries(ROWS).filter(([, v]) => match(v)).map(([label]) => label).sort();

describe('[#20143] matchesLikePattern — `_` is one code point', () => {
describe('matchesLikePattern — `_` is one code point', () => {
for (const [op, pattern, codePoint] of FAMILY) {
it(`${op} ${JSON.stringify(pattern)} answers the code-point rows`, () => {
expect(answer((v) => matchesLikePattern(v, pattern, op === '$ilike'))).toEqual([...codePoint]);
Expand Down Expand Up @@ -90,7 +90,7 @@ describe('[#20143] matchesLikePattern — `_` is one code point', () => {
});
});

describe('[#20143] likePatternToRegExp — the one compilation', () => {
describe('likePatternToRegExp — the one compilation', () => {
it('carries the `u` flag and nothing else (no `i`: the $ilike fold is in the source)', () => {
expect(likePatternToRegExp('a_b').flags).toBe('u');
expect(likePatternToRegExp('a_b', true).flags).toBe('u');
Expand All @@ -111,7 +111,7 @@ describe('[#20143] likePatternToRegExp — the one compilation', () => {
});
});

describe('[#20143] every ASCII punctuation character is `u`-legal, bare and escaped', () => {
describe('every ASCII punctuation character is `u`-legal, bare and escaped', () => {
/** Printable ASCII that is neither a letter nor a digit, space included: 33 characters. */
const PUNCTUATION = Array.from({ length: 0x7f - 0x20 }, (_, i) => String.fromCharCode(0x20 + i))
.filter((c) => !/[A-Za-z0-9]/.test(c));
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/data/filter-like-nul-pattern.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {

const NUL = String.fromCharCode(0x00);

describe('[#20041] hasNulInLikePattern', () => {
describe('hasNulInLikePattern — one predicate, so every door refuses a pattern holding U+0000', () => {
it('finds U+0000 at the start, in the middle, at the end, and alone', () => {
expect(hasNulInLikePattern(NUL + '%')).toBe(true);
expect(hasNulInLikePattern('a' + NUL + 'b')).toBe(true);
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/src/data/filter-like-wire-lowering.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
matchesLikePattern,
} from './filter.zod';

describe('[#7536] the wire lowering of `like` / `ilike`', () => {
describe('the wire lowering of `like` / `ilike` — its own operator, never folded onto `$contains`', () => {
// ── The card's repro table, as pins ───────────────────────────────────────

it('keeps a wildcard pattern INTACT — the `%` is the caller\'s, not a literal', () => {
Expand Down Expand Up @@ -153,7 +153,7 @@ describe('[#7536] the wire lowering of `like` / `ilike`', () => {
});
});

describe('[#7536] the `$like` pattern language', () => {
describe('the `$like` pattern language', () => {
// One definition, shared by every face — so these cases are the contract the
// SQL emitters and the JS evaluator are BOTH held to.

Expand Down Expand Up @@ -220,7 +220,7 @@ describe('[#7536] the `$like` pattern language', () => {
});
});

describe('[#7536] the LIKE → GLOB translation the SQLite dialects need', () => {
describe('the LIKE → GLOB translation the SQLite dialects need', () => {
// SQLite's `LIKE` folds ASCII case and cannot be told not to per statement,
// so a case-exact pattern match has to use `GLOB` — which speaks a DIFFERENT
// pattern language. These cases are what stops the two from being confused.
Expand Down
Loading
Loading