ADR-015: <table> accepts extraConfig prop mirroring Drizzle's third callback argument for composite unique constraints and other column-reference-based features. ADR-016: Adapter accepts Type.Module compiled bundle (not individual schemas). M.Import() handles ref resolution automatically, eliminating potential complications with separate schema wiring. Update FromDbTypeConfig interface to use module instead of schema, update element types table with extraConfig prop.
11 KiB
11 KiB
status, last_updated
| status | last_updated |
|---|---|
| stable | 2026-05-23 |
Open Questions Tracker
Architectural questions for dbtype, organized by theme. Resolved questions reference their ADR.
Schema & Module
OQ-01: Should relation entries use a naming convention?
- Origin: schema.md
- Status: Resolved
- Priority:
MediumResolved - Context: Currently
UsersRelations/TasksRelations. Is this naming convention sufficient, or should relations be structured differently? Arelationsfield on the table entry would couple relations to table definitions. - Resolution: Keep the
FooRelationsnaming convention. Separate module entries for relations align with Drizzle's naming convention, stay within Type.Module's flat namespace, and are independently addressable viaM.Import. Arelationsfield on the table entry would break the TypeBox schema model. See ADR-009. - Cross-references: OQ-03
OQ-02: Should derived schemas live in the module or be extracted separately?
- Origin: schema.md
- Status: Resolved
- Priority:
LowResolved - Context: Insert/update schemas can be added as module entries (
InsertUsers,UpdateUsers) or extracted by walking the module. Adding them to the module increases size but makes everything accessible viaImport. Extracting separately is more flexible but requires separate code paths. - Resolution: Include all derived schemas (insert, update, filter) in the module by default. A
repo_frominterface will generate CRUD operation specs from the module using the operations system, and needs access to all derived schemas. The decision isn't hard to reverse — anincludeDerived: falseopt-out can be added later. See ADR-010. - Cross-references: OQ-03
OQ-03: Should the module support multiple database namespaces?
- Origin: schema.md
- Status: Resolved
- Priority:
LowResolved - Context: One module per database, or one module with all tables across all databases? Probably one per database namespace, but this needs confirmation from real use cases.
- Resolution: One module per database namespace. This keeps the module's flat namespace clean, avoids table name collisions across databases, and aligns with how Drizzle organizes schemas. See ADR-010.
Element & Host
OQ-04: Should column elements support nested TypeBox schemas?
- Origin: elements.md
- Status: Resolved
- Priority:
HighResolved - Context: The research docs proposed
DbType.String({ notNull: true, inner: Type.String({ format: 'email', maxLength: 255 }) }). With UJSX elements, this would be<column name="email" type="string" notNull format="email" maxLength={255} />. The flat props model works for common cases, but custom validation constraints (patterns, ranges, custom checks) may need a nestedinnerprop. - Resolution: Yes — flat props for common cases,
inneras escape hatch for custom validation. Wheninneris provided,extractTable()uses it directly instead of callingcolToTypeBox(). The host ignoresinner— it's purely for the TypeBox schema. See ADR-007.
OQ-05: How to handle PG enum pre-declaration?
- Origin: hosts.md
- Status: Resolved
- Priority:
HighResolved - Context: PG requires
pgEnum()at module scope before tables that reference it. Options: (A) return both enums and tables from render, (B) start with text for all enums, (C) per-column opt-in withpostgres: { nativeEnum: true }. - Resolution: Option A — the PG host accumulates enums in
ctx.enumsduring the render walk. The consumer includes bothctx.enumsandctx.tablesin their Drizzle schema. Enum names follow thetable_columnconvention. See ADR-008.
OQ-06: Should hosts return rendered tables or store them in context?
- Origin: hosts.md
- Status: Resolved
- Priority:
MediumResolved - Context: The probe scripts use
ctx.tablesto collect rendered tables. A more functional approach would haverender()return the rendered table directly. Need to resolve this before implementation. - Resolution: render() accumulates results in root.ctx (tables, enums). The context shape varies by dialect — SQLite has ctx.tables, PG has ctx.tables and ctx.enums. This is a design clarification confirmed by implementation, not a significant architectural decision requiring its own ADR. See hosts.md Rendering Pipeline.
OQ-07: Should we support JSX file extensions?
- Origin: elements.md
- Status: Resolved
- Priority:
LowResolved - Context: JSX syntax (
.tsxwithjsxImportSource: '@alkdev/ujsx') would be more ergonomic thanh()calls. This requires build configuration (TSConfigjsx, bundler support). Theh()API works universally; JSX is a convenience layer. - Resolution: Yes — support JSX/TSX as an ergonomic authoring layer. JSX desugars to
h()calls viajsxImportSource: '@alkdev/ujsx', so the runtime representation is identical. Theh()API remains the universal fallback. See ADR-011.
Repo Adapter
OQ-08: Per-dialect handler differences?
- Origin: repo-adapter.md
- Status: Resolved
- Priority:
MediumResolved - Context: PG has
.returning()on all mutations, MySQL often doesn't. Should the adapter handle this transparently (always try.returning(), fall back gracefully), or should it be explicit in the config? - Resolution: Always use
.returning()and gracefully fall back. For dialects that support it (PG, SQLite), return the full result rows. For dialects that don't (MySQL), fall back to returning validated input data (for inserts) or affected row count (for updates/deletes). This keeps the operations API uniform across dialects. See ADR-012.
OQ-09: Relation rendering responsibility?
- Origin: repo-adapter.md
- Status: Resolved
- Priority:
MediumResolved - Context: Should the host render relations (new element type
<relation>), or should the adapter generate them from the module's relation entries? The adapter knows the rendered table objects; the module knows the relation structure. Leaning toward the adapter generating them. - Resolution: The adapter generates relation objects from the module's relation entries and the rendered table objects. No new
<relation>element type is needed. The adapter readsFooRelationsentries from the module, maps them to Drizzlerelations()calls using the rendered table objects inctx.tables. See ADR-013.
Migration & Diffing
OQ-10: How far should migration diffing go in phase 1?
- Origin: module.md
- Status: Resolved
- Priority:
LowResolved - Context:
Value.Diffon serialized schemas produces structural edit lists (insert/delete/update property). Translating these toALTER TABLEstatements is straightforward for additive changes (new column) but complex for destructive ones (drop column, change type). Phase 1 likely skips migration generation entirely (rely ondrizzle-kit), but the module structure should not prevent it later. - Resolution: Leverage
drizzle-kitfor migrations. dbtype renders to Drizzle table definitions, anddrizzle-kit generatealready handles migration generation from those. No dbtype-native migration generator in phase 1 or the foreseeable future. The module'sValue.Diffcapability remains available as a foundation for future use. See ADR-014.
OQ-11: Should <table> accept extraConfig props?
- Origin: elements.md
- Status: Resolved
- Priority:
LowResolved - Context: Drizzle tables accept a third callback argument for indexes and unique constraints defined in terms of column references (e.g.,
t => ({ uniqueEmail: unique().on(t.email) })). The<index>element handles most index cases, but composite unique constraints using the Drizzle callback style may not be expressible via<index unique>. How should this map to element props, or is it needed at all? - Resolution: Yes — the
<table>element accepts anextraConfigprop that mirrors Drizzle's third callback argument. It receives the rendered column builders and returns an object for indexes, unique constraints, and other column-reference-based features. This is the escape hatch pattern, consistent withinneron<column>. See ADR-015.
OQ-12: Should the adapter accept the Type.Module bundle or individual schemas?
- Origin: repo-adapter.md
- Status: Resolved
- Priority:
LowResolved - Context: The adapter needs access to select, insert, update, and filter schemas. Accepting the
Type.Modulecompiled bundle is convenient (everything in one place, accessible viaM.Import()) but couples the adapter to TypeBox's module format. Accepting individual schemas is more flexible but requires more config. With ADR-010 resolving that derived schemas are included in the module, the module bundle approach is the natural default, but the adapter could expose both interfaces. - Resolution: Accept the Type.Module compiled bundle.
M.Import()handles ref resolution and recursion automatically, which eliminates potential complications with separate schema wiring. Consistent with ADR-010 (derived schemas in the module) and requires less configuration. See ADR-016.
Summary Table
| ID | Question | Origin | Priority | Status |
|---|---|---|---|---|
| OQ-01 | Relation naming convention | schema.md | Resolved — ADR-009 | |
| OQ-02 | Derived schemas in module or separate | schema.md | Resolved — ADR-010 | |
| OQ-03 | Multiple database namespaces | schema.md | Resolved — ADR-010 | |
| OQ-04 | Nested TypeBox schemas in column props | elements.md | Resolved — ADR-007 | |
| OQ-05 | PG enum pre-declaration | hosts.md | Resolved — ADR-008 | |
| OQ-06 | Host render return value vs context | hosts.md | Resolved — design clarification | |
| OQ-07 | JSX file extensions | elements.md | Resolved — ADR-011 | |
| OQ-08 | Per-dialect handler differences | repo-adapter.md | Resolved — ADR-012 | |
| OQ-09 | Relation rendering responsibility | repo-adapter.md | Resolved — ADR-013 | |
| OQ-10 | Migration diffing scope | module.md | Resolved — ADR-014 | |
| OQ-11 | Table extraConfig props | elements.md | Resolved — ADR-015 | |
| OQ-12 | Module bundle vs. individual schemas | repo-adapter.md | Resolved — ADR-016 |