You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
objectql + REST: a per-aggregation filter (and having) compares a temporal comparand type-blind, not by the column's storage rule — an ISO instant on a date field counts 1 where the where twin counts 3 #20176
packages/objectql/src/having-filter.ts: checkCondition, which is type-blind and shared by the per-aggregation filter and having.
Finding class (a). This is ONE class-closure card for a family: a temporal comparand at this position is compared type-blind, while where reads it by the declared column's storage rule (driver-memorycoerceTemporalValue, driver-sqltemporalFilterValue). reach: was measured at the public REST door (below).
The domain:engine execution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) filed this from its #20148 dev's report (os-dev-report 5852943342 on #20148, PR #20174): out-of-scope finding 1, plus open question 2's residual. The seat folded those two into this card (amendment 5852957006). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.
The enumeration (each one a row of the pin)
Measured by the #20148 dev on a real InMemoryDriver and a real SqlDriver (schema-synced; 6 rows in 3 groups), through the engine and through REST POST /api/v1/data/:object/query. Readings are identical at base 49144fccc8 and at PR #20174's head f22f0e875f, except rows 6–7, which PR #20174's instant lift created.
#
Shape, in aggregations[i].filter (or having)
Count now
The same condition as a where
reach:
1
{ placed_on: { $gte: '2026-02-01T00:00:00.000Z' } } on a date field
1
3
public: REST, both drivers
2
{ placed_on: { $eq: '2026-02-01T00:00:00.000Z' } } on a date field
0
2
public: REST
3
{ opened_at: { $lte: '2026-02-01' } }, a bare day as the upper bound on a datetime
2
3
public: REST
4
$between with a bare day as the max, on a datetime
2
3
public: REST
5
an epoch-ms bound on a datetime
0
3
public: REST
6
a Date carrying a time of day on a date field ($gte / $lt / $eq)
1 / 5 / 0
3 / 3 / 2
in-process only (a Date is not JSON)
7
a Date on a time field
0
3
in-process only
8
having on max(date) with an ISO bound
keeps c2
the date rule keeps c2, c3
public: REST
Control: a zone-naive datetime string counts 4, and so does the where twin.
Suggested shape (⛔ not a ruling)
Normalise every temporal comparand of a per-aggregation filter in ObjectQL.aggregate's loop by the object's declared field class. Use ONE storage-form function lifted out of the drivers into spec or core, so the drivers and this position read one rule, not a third copy.
Dedupe words: per-aggregation filter temporal string storage rule · aggregation filter ISO instant date field · aggregation filter bare day lte datetime · having-filter checkCondition temporal text comparison
Filing gate: ① a defect with a named landing site, the per-aggregation
filterposition andhaving:packages/objectql/src/engine.ts:ObjectQL.aggregate's per-aggregation loop;packages/objectql/src/having-filter.ts:checkCondition, which is type-blind and shared by the per-aggregationfilterandhaving.Finding class (a). This is ONE class-closure card for a family: a temporal comparand at this position is compared type-blind, while
wherereads it by the declared column's storage rule (driver-memorycoerceTemporalValue,driver-sqltemporalFilterValue).reach:was measured at the public REST door (below).The
domain:engineexecution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) filed this from its #20148 dev's report (os-dev-report5852943342 on #20148, PR #20174): out-of-scope finding 1, plus open question 2's residual. The seat folded those two into this card (amendment 5852957006). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.The enumeration (each one a row of the pin)
Measured by the #20148 dev on a real
InMemoryDriverand a realSqlDriver(schema-synced; 6 rows in 3 groups), through the engine and through RESTPOST /api/v1/data/:object/query. Readings are identical at base49144fccc8and at PR #20174's headf22f0e875f, except rows 6–7, which PR #20174's instant lift created.aggregations[i].filter(orhaving)wherereach:{ placed_on: { $gte: '2026-02-01T00:00:00.000Z' } }on adatefield{ placed_on: { $eq: '2026-02-01T00:00:00.000Z' } }on adatefield{ opened_at: { $lte: '2026-02-01' } }, a bare day as the upper bound on adatetime$betweenwith a bare day as the max, on adatetimedatetimeDatecarrying a time of day on adatefield ($gte/$lt/$eq)Dateis not JSON)Dateon atimefieldhavingonmax(date)with an ISO boundc2c2,c3Control: a zone-naive datetime string counts 4, and so does the
wheretwin.Suggested shape (⛔ not a ruling)
filterinObjectQL.aggregate's loop by the object's declared field class. Use ONE storage-form function lifted out of the drivers intospecorcore, so the drivers and this position read one rule, not a third copy.having, thread each aggregated column's temporal class intocheckCondition(the objectqlhaving: a{ $field }reference withaddDaysagainst a non-temporal aggregated column answers by epoch-ms coercion, where SQL push-down refuses the same pair onwhere— the aggregated row declares no temporal class to judge it by #20127 class rule already derives it foraddDayspairs).wheretwin as the control.Filing-gate answers
filterstill lacks four ofwhere's doors — a bad date, anaddDaysnumeric pair, an undeclared{ $field }and an unknown key answer200with every count 0 #20148 dev.domain:engine, the owner ofpackages/objectql). It is sequenced after PR fix(objectql,metadata-protocol)!: the per-aggregation filter takes where's remaining doors — a bad date, an addDays numeric pair, an undeclared { $field } and an unknown key are refused; a Date bound compares as an instant #20174 (objectql + REST: the per-aggregationfilterstill lacks four ofwhere's doors — a bad date, anaddDaysnumeric pair, an undeclared{ $field }and an unknown key answer200with every count 0 #20148), which edits the same loop andcheckCondition. That is a region order, not aBlocked-by:.closedincluded:aggregation filter temporal string compared as text ISO instant date field having checkCondition storage rule→ 1 hit: objectqlhaving: a{ $field }reference withaddDaysagainst a non-temporal aggregated column answers by epoch-ms coercion, where SQL push-down refuses the same pair onwhere— the aggregated row declares no temporal class to judge it by #20127 (closed), theaddDaysclass rule onhaving, a different row.where filter ISO datetime string against date field wrong count temporal comparand normalise storage form aggregate→ 7 hits, all read.filterstill lacks four ofwhere's doors — a bad date, anaddDaysnumeric pair, an undeclared{ $field }and an unknown key answer200with every count 0 #20148 (the family's parent, in flight) and objectqlhaving: a{ $field }reference withaddDaysagainst a non-temporal aggregated column answers by epoch-ms coercion, where SQL push-down refuses the same pair onwhere— the aggregated row declares no temporal class to judge it by #20127.whereskips the shared comparand-TYPE face, so a plain-object / Map / oversized-bigint comparand is bound as JSON text on the native path while the FilterArray spelling and the engine refuse 400 #20035: the analytics comparand-type face.where, fixed.{placeholder}is correctly rejected 400 (17.0.0 GA) #8690: an unparseable date onwhere.Dedupe words:
per-aggregation filter temporal string storage rule·aggregation filter ISO instant date field·aggregation filter bare day lte datetime·having-filter checkCondition temporal text comparison