Skip to content

Commit 0010797

Browse files
os-warrenclaude
andauthored
feat(driver-sql,objectql): qualify cross-schema foreign keys with referencedSchema; refuse to wire the bare name (#11906)
* feat(driver-sql): qualify a cross-schema foreign key with referencedSchema (#11377) IntrospectedForeignKey gains an optional referencedSchema, present when - and only when - the referenced parent lives outside the session's own resolution scope (PG: the parent's schema vs current_schemas(false); MySQL: REFERENCED_TABLE_SCHEMA vs DATABASE(), null-safe). referencedTable stays a bare name unconditionally. SQLite never sets the key - no schemas, and a foreign key cannot cross an ATTACHed database. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rxnd8cyFnoU8V5y21PaTsy * feat(objectql): refuse to wire a lookup to a foreign key carrying referencedSchema (#11377) convertIntrospectedSchemaToObjects reads the driver's new qualification: a foreign key whose target carries referencedSchema is loudly skipped and flagged through options.logger (default console) - never wired to the bare name - and the column converts as a plain field so the data stays visible. Resolvable foreign keys keep wiring byte-identically. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rxnd8cyFnoU8V5y21PaTsy * test(driver-sql): expect the #11377 qualification in #11324's cross-schema pins; add changeset The #11324 fixture IS the cross-schema shape #11377 qualifies, so its two cross-schema assertions now carry referencedSchema; presence/absence semantics stay pinned in the #11377 file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rxnd8cyFnoU8V5y21PaTsy --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent bb62d4d commit 0010797

6 files changed

Lines changed: 718 additions & 5 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/driver-sql': minor
3+
'@objectstack/objectql': minor
4+
---
5+
6+
Cross-schema foreign keys are now qualified instead of shipping an unusable bare name (#11377).
7+
8+
`IntrospectedForeignKey` (driver-sql) gains an optional `referencedSchema`, present when — and
9+
only when — the referenced parent table lives outside the introspecting session's resolution
10+
scope (Postgres: the parent's schema is not on `current_schemas(false)`; MySQL: the parent's
11+
database differs from `DATABASE()`; SQLite never sets it — no schemas, and a foreign key cannot
12+
cross an ATTACHed database). `referencedTable` stays a bare name always — the qualification is a
13+
separate key, never a conditional spelling.
14+
15+
`convertIntrospectedSchemaToObjects` (objectql) reads the new key: a foreign key whose target
16+
carries `referencedSchema` is loudly skipped and flagged through the new `options.logger`
17+
(default `console`) instead of being wired to the bare name — which either resolved to nothing
18+
or to a same-named table in the current schema, silently. The column is kept as a plain field so
19+
its data stays visible. Foreign keys with in-scope targets keep producing identical lookup
20+
fields.

packages/drivers/driver-sql/src/sql-driver-11324-introspect-fk-join-correlations.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ function declareJoinCorrelationSuite(cell: DialectCell): void {
229229
it('returns a foreign key whose target lives in ANOTHER schema', async () => {
230230
const foreignKeys = await driver.foreignKeys(CROSS_CHILD);
231231

232+
// `referencedSchema` is #11377's half of this answer: the parent is off
233+
// the session's `search_path`, so the (still bare) name arrives
234+
// qualified. Presence/absence semantics and their own controls are
235+
// pinned in `sql-driver-11377-introspect-fk-cross-schema-qualification`;
236+
// this file keeps owning the #11324 fact — the key is RETURNED at all.
232237
expect(
233238
foreignKeys,
234239
`${cell.label}: ${CROSS_CHILD} has a declared foreign key into ${far} and must not be ` +
@@ -239,6 +244,7 @@ function declareJoinCorrelationSuite(cell: DialectCell): void {
239244
referencedTable: REMOTE_PARENT,
240245
referencedColumn: 'id',
241246
constraintName: FK_CROSS,
247+
referencedSchema: far,
242248
},
243249
]);
244250
});
@@ -256,6 +262,8 @@ function declareJoinCorrelationSuite(cell: DialectCell): void {
256262
referencedTable: REMOTE_PARENT,
257263
referencedColumn: 'id',
258264
constraintName: FK_CROSS,
265+
// #11377: the off-path parent arrives qualified — see above.
266+
referencedSchema: far,
259267
},
260268
]);
261269
});

0 commit comments

Comments
 (0)