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
fix(driver-sql,service-analytics): bare-day upper bounds cover the whole day on Field.datetime (#3777) (#4041)
* fix(driver-sql,service-analytics): bare-day upper bounds cover the whole day on Field.datetime (#3777)
A bare YYYY-MM-DD comparand anchors to midnight UTC — right for a lower
bound, silently wrong for an upper one: the dashboard date-range filter
compiles { $gte: from, $lte: to } with bare-day bounds, so on a datetime
column every row created after 00:00 of the final day vanished. The
default configuration hit it: the filter's default field is created_at
(a system-injected Field.datetime) and 7 of 13 presets end "today".
The translation is operator-sensitive and half-open ([gte, lt) — the
drill ranges' shape, never an inclusive 23:59:59.999), applied at the
emitters that own an operator, while temporalFilterValue stays form-only:
- SqlDriver (SqliteWasmDriver inherits): $lte/<= bare-day on datetime ->
< next-day-midnight in storage form; $between [min, max] with a
bare-day max decomposes to >= min AND < next-day(max). Covers the
plain and the legacy-repair (mixed-storage) column paths and both
where spellings.
- NativeSQLStrategy: dateRange windows and lte filters bind < next-day.
- ObjectQLStrategy: execution keeps bare bounds (the driver rewrite is
the single authority); /analytics/sql renders half-open so the echoed
SQL reproduces execution.
- Preview evaluator: the same rule in memory, replacing the '~' hack.
One shared primitive: nextUtcCalendarDay (@objectstack/core) — rejects
instants, Dates and impossible days rather than inventing a bound.
Unchanged per the #3777 semantics table: date/time columns,
full-ISO/Date comparands, $gte/$gt/$lt.
Tests: the issue repro verbatim as the acceptance gate (row results),
operator x field-type x storage-form matrix incl. un-backfilled mixed
storage, dialect physical forms, boundary rollovers, a wasm inheritance
pin, strategy SQL shapes, preview parity. ADR-0053 gains the D-D
addendum; D-A3's matrix gains the bound-semantics axis.
Closes#3777
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EkL3RGJrzjLEGURsLxfS2f
* docs(objectql): state the calendar-day bound semantics where date filters are documented (#3777)
The Date Filters section demos the exact shape whose upper-bound semantics
#3777 fixed, without saying what the bounds mean. Now it does: bare-day
lower bound = start of day, bare-day upper bound = the whole day (compiled
half-open on datetime columns), full ISO timestamp = exact instant.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EkL3RGJrzjLEGURsLxfS2f
---------
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments