fix(sql): browse-commit states a topByTimestamp row selector (#552)
`RawBrowseCommitMapper.BuildSqlTagConfig` emitted a WideRow blob carrying only table + columnName. A wide-row tag must also say WHICH row it reads, so both `SqlEquipmentTagParser` (the runtime authority) and `SqlTagConfigModel.Validate` (the authoring gate) refused it — a browse-committed Sql tag was never readable, first silently as BadNodeIdUnknown and, since #551 put the gate on the import, loudly at commit. `SqlBrowseSession` now states a fourth address field: the table's preferred date/time-typed column, computed from the columns its attributes call ALREADY read (no extra catalog round-trip). Candidacy is decided by `ISqlDialect.MapColumnType` reporting `DriverDataType.DateTime` — never by column name, which would order a wide-row read by a string column that merely looks like a timestamp. Multiple candidates tie-break on FIRST IN CATALOG ORDER (every dialect's column SQL orders by ordinal position), so the pick is stable across calls and servers; it is a visible, editable default the typed editor round-trips. No candidate (a table with no date/time column) is an operator-actionable refusal, not an invented selector: the only remaining selector is a whereColumn/whereValue pair whose value is data, not schema, so `DescribeUncommittableLeaf` refuses that leaf by name, names the table, and points at the tag editor. The session and the mapper now agree via `SqlBrowseAddressFields` constants rather than two independently spelled string literals — a disagreement there is silent, and is exactly the shape this defect had. `RawTagConfigGateTests`' Sql leg flips from "records the gap" to "browse-commit output passes the gate", with the no-candidate case pinned as its own test.
This commit is contained in:
@@ -169,6 +169,33 @@ Browse works against all three constructed providers; the catalog query is the d
|
||||
(`INFORMATION_SCHEMA` on SQL Server and Postgres — with `pg_catalog` / `information_schema`
|
||||
themselves excluded — and the `ALL_*` views on Oracle).
|
||||
|
||||
### The committed row selector (Gitea #552)
|
||||
|
||||
A browse-committed column becomes a **WideRow** tag, and a wide-row tag must say *which row* it reads
|
||||
— the table and column alone are not a binding. The browse session therefore states a fourth address
|
||||
field alongside schema/table/column: the table's preferred **date/time-typed** column, which the
|
||||
commit writes as `rowSelector.topByTimestamp` ("read the newest row"). Before this the commit emitted
|
||||
a selector-less blob that `SqlEquipmentTagParser` and the authoring gate both refuse, so no
|
||||
browse-committed Sql tag was ever readable.
|
||||
|
||||
Two properties of the choice are deliberate:
|
||||
|
||||
- **Candidacy is by declared TYPE, never by column name.** The session asks
|
||||
`ISqlDialect.MapColumnType` for `DriverDataType.DateTime` — the same metadata the browse tree already
|
||||
renders per column. A name heuristic (`*_ts`, `*time*`) would happily order a wide-row read by a
|
||||
*string* column called `timestamp`, binding the tag to whichever row sorts last lexically.
|
||||
- **The tie-break is first in catalog order** (every dialect's column query orders by ordinal
|
||||
position), so the pick is stable across calls, connections and servers. On a
|
||||
`CreatedUtc`/`ModifiedUtc` pair it takes the earlier-declared one. It is a **visible, editable
|
||||
default**: the typed editor shows the selector and the operator can change it — to the other
|
||||
timestamp, or to a `whereColumn`/`whereValue` pair entirely.
|
||||
|
||||
**A table with no date/time column cannot be bound by browse, and the commit says so.** The remaining
|
||||
selector is a `whereColumn`/`whereValue` pair whose value is *data*, not schema, so nothing in a
|
||||
catalog can supply it. `RawBrowseCommitMapper.DescribeUncommittableLeaf` refuses that leaf by name,
|
||||
names the table, and points at the tag editor; no selector is invented, and the mapper's blob stays
|
||||
selector-less rather than dropping to a generic `{"address": …}` the typed editor cannot read.
|
||||
|
||||
## Authoring in the AdminUI
|
||||
|
||||
- **Driver config** — `/raw` → driver node → *Configure*. Sql is a **single-connection** driver: the
|
||||
|
||||
Reference in New Issue
Block a user