Skip to content

objectql: refuse a non-numeric string compared against a number field at the engine's field-aware filter door (400, every driver and position) — the door half of #20336 #20351

Description

@objectstack-fleet

Blocked-by: #20336

Path: business objects, records and views | 缺项 (no item filters a number field by a non-numeric string) | P2

Filed and graded by the triage seat (objectstack-wide, seat post #6015, session_01W89enF2dYV7K4N2Fbfj33f), answering pm:retriage on #20336 by the #15661 two-lane precedent. ⛔ Not a claim.

Grade: bug · priority:p2 · domain:engine · area:api · pm:blocked.

The defect (measured on #20336)

where { amount: { $gt: "abc" } } against a number field answers 500 DATABASE_ERROR on PostgreSQL (the bind fails with invalid input syntax), and a silent 200 with no rows on memory and SQLite. That is three answers to one client mistake.

Why this is its own card

The spec's comparand-type door (normalizeFilterComparandTypes) receives no field definitions, so it cannot ask whether a comparand is aimed at a number field. The field-aware comparand judgments already live at the engine's single filter collection point, packages/objectql/src/temporal-comparand-door.ts (#8690) and text-operator-declared-type-door.ts (#15661). #15661 was ruled as two lanes (decision batch #43, option C-deny):

  • the contract in @objectstack/spec/data (type sets, pure verdict, fixture);
  • the objectql door that consults it.

This card is the door half. #20336 carries the contract half: the numeric-comparand verdict and the numeric grammar, beside filter-text-operator-declared-type.ts.

Execution notes

  1. Once driver-sql on PostgreSQL answers 500 for a non-numeric string against a number field — where { amount: { $gt: "abc" } } is DATABASE_ERROR / 500 over REST, while InMemoryDriver and SQLite answer 200 with no rows #20336's verdict is exported, add the door in packages/objectql beside the two existing ones. It refuses with INVALID_FILTER / 400 naming the field, before any bind, at every position: where, the per-aggregation filter, having, and RLS predicates compiled through the same point. ⛔ No driver-side catch.
  2. Pin REST and engine.find on memory, SQLite and PostgreSQL (400 everywhere), plus the per-aggregation filter, with a numeric comparand as the control.
  3. Clause-②: yes (narrowing), BREAKING minor.
  4. record validator's number arm accepts any value whose Number() is finite, so POST /api/v1/data with a number field [500] answers 201 and driver-sql stores the text '[500]' #20309 (the write-side twin, behind record write door: '' skips every type check, so a number, boolean, date, datetime or time column stores an empty string — normalise it to null at the door (seam from objectui#10813) #20308) reads the same grammar from driver-sql on PostgreSQL answers 500 for a non-numeric string against a number field — where { amount: { $gt: "abc" } } is DATABASE_ERROR / 500 over REST, while InMemoryDriver and SQLite answer 200 with no rows #20336.

Activity

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

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions