dasSQLITE chunk 14c: schema rebuild via [struct_convert]#2595
dasSQLITE chunk 14c: schema rebuild via [struct_convert]#2595
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends dasSQLITE migrations with a full “schema rebuild” path for changes that SQLite can’t express via in-place ALTER TABLE, centered around legacy structs, [struct_convert] auto-derived row translation, and convert_and_rename staging-table rebuilds. It also expands the hygiene toolchain with a rule to collapse consecutive blank lines and updates tutorial/docs plus adds targeted regression tests.
Changes:
- Add
[struct_convert]annotation +convert/convert_and_renamehelpers to support rebuild-style migrations. - Introduce
[sql_table(legacy=true)]read-only structs and runtimename:stringoverloads for staging-tablecreate_table/insert. - Add
rule_collapse_blank_linesto hygiene rules, apply it in the rule chain, and add tests/docs/tutorial updates.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| utils/hygiene/test_hygiene.das | Adds unit tests for collapsing blank lines and rule chaining. |
| utils/hygiene/rules.das | Chains collapse_blank_lines after trim_private_docstrings. |
| utils/hygiene/rule_collapse_blank_lines.das | New hygiene rule to collapse runs of blank/whitespace-only lines while preserving CRLF. |
| tutorials/sql/43-migrations.das | Tutorial expanded with legacy struct + [struct_convert] + rebuild migration example and gotchas. |
| tests/dasSQLITE/migrate_91_full_rebuild_end_to_end.das | End-to-end test for rebuild flow preserving rows and performing translation overrides. |
| tests/dasSQLITE/migrate_90_sql_table_legacy_marker.das | Tests legacy structs remain readable and can be dropped. |
| tests/dasSQLITE/migrate_89_insert_name_override.das | Tests insert(row, name) writes into a staging table. |
| tests/dasSQLITE/migrate_88_create_table_name_override.das | Tests create_table(type<T>, name) emits correct schema + index naming for staging tables. |
| tests/dasSQLITE/migrate_87_struct_convert_override_via_mention.das | Tests override suppression via any dst.X mention in converter body. |
| tests/dasSQLITE/migrate_81_struct_convert_option_flip.das | Tests auto-derivation for T -> Option<T> wrapping behavior. |
| tests/dasSQLITE/migrate_80_struct_convert_trivial.das | Trivial rebuild round-trip test using auto-derived field copies. |
| tests/dasSQLITE/failed_struct_convert_option_to_t.das | Negative compile test: rejects Option<T> -> T without explicit fallback. |
| tests/dasSQLITE/failed_struct_convert_new_field_no_default.das | Negative compile test: rejects new non-optional field with no default and no override. |
| modules/dasSQLITE/daslib/sqlite_migrate.das | Implements [struct_convert] macro + convert / convert_and_rename rebuild primitives. |
| modules/dasSQLITE/daslib/sqlite_linq.das | Comment-hygiene edits (no behavioral changes apparent in shown diff). |
| modules/dasSQLITE/daslib/sqlite_boost.das | Adds legacy marker behavior, staging-table name overload plumbing, and refactors helper SQL factories. |
| doc/source/reference/tutorials/sql_43_migrations.rst | Documents rebuild workflow and updates “what does not ship” section accordingly. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
090fdd6 to
b73fc96
Compare
b73fc96 to
5d81bf9
Compare
177ff38 to
203f2ab
Compare
203f2ab to
6d78c09
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
modules/dasSQLITE/daslib/sqlite_boost.das:2202
is_option_field_type(and the nearbyunwrap_option_payload_type) changed fromprivateto public in thesqlite_boostpublic module, which expands the public API surface with very generic names. If these are intended as internal macro helpers, consider keeping them private (and duplicating/moving the minimal logic intosqlite_migrate) or renaming/prefixing them to avoid future namespace/API collisions.
def is_option_field_type(td : TypeDeclPtr) : bool {
if (td == null) {
return false
}
// Pre-instantiation form: typeMacro `$Option<T>` — what [sql_table] sees during structure_macro apply().
6d78c09 to
f7cec29
Compare
Final piece of the migration trio (after 14a spine, 14b typed ALTER) - the rebuild path for schema changes SQLite's narrow ALTER vocabulary cannot express in place (PK/FK/CHECK changes, type narrowing). User-side surface collapses the SQLite 12-step recipe to three lines: keep the historical struct as [sql_table(legacy=true)], write a [struct_convert]-annotated converter, and call db |> convert_and_rename(type<S>, type<T>) from the migration body. Also: utils/hygiene gains a collapse-blank-lines rule chained after the private-docstring trim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f7cec29 to
384f974
Compare
Summary
Final piece of the migration trio (after 14a spine, 14b typed ALTER) — the rebuild path for schema changes SQLite's narrow
ALTERvocabulary cannot express in place (PK/FK/CHECK changes, type narrowing).User-side: SQLite's "12-step recipe" collapses to three lines.
What ships
[sql_table(legacy=true)]— emits read-side helpers only; writes (create_table/insert/update/delete) fail at compile time as unresolved overloads.[struct_convert]function annotation — auto-derives field-by-field translation (same-name same-type,T → Option<T>, scalar primitive casts,@sql_renamed_from). Walks the user body viaAstVisitor::preVisitExprFieldfor ANY mention ofdst.Xto suppress the auto-derived assignment when the user takes control.db |> convert(type<S>, type<T> [, name])— SELECT → converter → INSERT loop.db |> convert_and_rename(type<S>, type<T>)— full rebuild: CREATE staging, copy via converter, DROP original, RENAME.name : stringoverloads forcreate_tableandinsert—make_*_sql_fnfactories refactored to twin overloads (1-arg wrapper forwards to 2-arg with the struct's own[sql_table(name=...)]).Bonus: utils/hygiene
rule_collapse_blank_lines.daschained after the private-docstring trim — runs of 2+ blank lines collapse to one, CRLF round-trips, whitespace-only lines count as blank. 8 unit tests.sqlite_boost.das/sqlite_migrate.das/sqlite_linq.das(57 blank-line collapses + a handful of private//!strips).--comment-hygiene(STYLE014/STYLE015) cleanup on the three SQL files: trimmed multi-paragraph banner blocks and oversized private// ...comments to 1-line WHYs per CLAUDE.md.Test plan
dastest --test tests/dasSQLITE— 762/762 (interpreted)test_aot.exe -use-aotfull suite — 7321/7321 (AOT)daslang utils/lint/main.dasclean on all changed.dasfiles--comment-hygieneclean on the three SQL daslib filesformat_fileclean on every changed.das-Wclean (zero warnings, zero errors) on the doc tree🤖 Generated with Claude Code