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(analytics)!: `AnalyticsServiceConfig.sqlDialect` declares its three-name accept set, and a host that answers outside it is told once (#16206)
6
+
7
+
<!-- adr-0087: not-required (runtime-interface-only packages/services/service-analytics/src/analytics-service.ts#AnalyticsServiceConfig) The narrowed member is one hook on a service CONSTRUCTOR CONFIG — a published runtime TypeScript interface with no metadata surface. It has no Zod schema, no `packages/spec` declaration and no stored representation, so `objectstack migrate meta`, `spec-changes.json` and the generated upgrade guide have nothing to rewrite; the affected party is a TypeScript host and the channel that reaches every one of them is the compiler at their own composition site. No metadata key is added, removed, renamed or re-shaped, and `packages/spec` is untouched by this diff. -->
8
+
9
+
**BREAKING** for a TypeScript host that declares its `sqlDialect` hook as returning
10
+
`string`: the hook's declared return is now the three canonical dialect names or
11
+
`undefined`, so such a composition stops compiling until the host's own annotation
12
+
says which names it can answer. Shipped as `minor` under the repo's launch-window
13
+
convention, in which breaking-ness is carried by this banner and the disposition
14
+
above rather than by the bump level. Runtime behaviour for every host is unchanged:
15
+
the same three names were the only ones that ever did anything.
16
+
17
+
## What was wrong
18
+
19
+
`AnalyticsServiceConfig.sqlDialect` — the hook a host answers to say which SQL
20
+
dialect backs an object — was typed as free `string`, while `normalizeSqlDialect`
21
+
has only ever recognised `sqlite`, `postgres` and `mysql`. Nothing said so, and
22
+
nothing told a host that answered otherwise.
23
+
24
+
So a host that owns a SQLite datasource and answers the spelling its own stack uses
25
+
— knex's canonical `sqlite3`, or `better-sqlite3`, both of which `driver-sql` itself
26
+
lists in `SQLITE_EMIT_CLIENTS` — was read as `unknown`. And because `sqlDialectFor`
27
+
is tiered "cannot answer, do not block", **a wrong answer and no answer were the
28
+
same answer**: the host that tried hardest to help got the residue arm, silently.
29
+
30
+
## What it does now
31
+
32
+
-**The vocabulary is declared**, on the type and in the docblock, as
33
+
`AcceptedSqlDialect` — `sqlite` | `postgres` | `mysql` — so a host reading the
34
+
config learns the accept set without running anything. The type and the runtime
35
+
membership set are generated from one `const` tuple, so a future widening cannot
36
+
land in one and miss the other.
37
+
-**A non-empty answer outside the set is diagnosed**: one `warn` naming the object,
38
+
the answer and the accepted set. It is emitted **once per distinct unrecognised
39
+
spelling** — the failure's identity — so the line count is bounded by the host's
40
+
own hook and never grows with query volume.
41
+
-**`undefined` stays silent and legal.** The hook is optional and "cannot answer,
42
+
do not block" is a supported composition, not a misconfiguration. A pin holds both
43
+
halves, because a diagnostic that also shouted at hosts who wired nothing would be
44
+
a worse defect than the one being fixed.
45
+
-**The accept set is NOT widened.** Teaching this package `driver-sql`'s knex
46
+
aliases would be a second copy of that driver's table, and an unrecognised
47
+
spelling is sometimes deliberate (`mariadb`, #11756). The answer is still read as
48
+
`unknown`; only the silence changed.
49
+
-**The plugin bridge translates the driver's own residue.**`SqlDriver.dialectName`
50
+
carries a fourth name, `unknown`, meaning "I cannot say"; handed on verbatim it
51
+
would have presented a correctly-behaving driver as a host answering out of
52
+
contract. It now arrives as `undefined`, this hook's own spelling for the same
53
+
thing. The dialect the compilers end up with is unchanged either way.
54
+
55
+
## Measured, and worth reading before relying on the residue arm
56
+
57
+
Driven on sql.js through a host answering `sqlite3`, against the shared
58
+
`FILTER_TEXT_CASES` fixture, with a host answering `sqlite` as the control: **five of
59
+
the six case-EXACT cases come back with the wrong rows** — every case that
0 commit comments