Add Weasel 8 → 9 migration guide#276
Merged
Merged
Conversation
…Weasel 9.0) (#271) * Bump JasperFx 2.0.0-alpha.1 → 2.0.0-alpha.8, JasperFx.Events → 2.0.0-alpha.3 Pulls in the latest pre-release alphas of JasperFx 2.0 ahead of #270 implementation work. Verified clean build across the solution and all non-Docker test suites pass: - Weasel.Core.Tests: 6/6 - Weasel.Sqlite.Tests: 361/361 - Weasel.CommandLine.Tests: 23/23 (with Postgres container) Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 1: SchemaObjectBase + SequenceBase, refactor all 4 Sequence providers Adds two new base classes in Weasel.Core that consolidate the boilerplate every schema object reimplements today: - SchemaObjectBase: implements ISchemaObject with default AllNames() (yield Identifier), default "single COUNT(*) row" CreateDeltaAsync, and the standard FindDeltaAsync(DbConnection) pattern that builds a query command, executes it, resolves the delta, and closes the reader. ReadExistsCountAsync is a virtual hook that converts the count to long via Convert.ToInt64 — handles the int / long / decimal variation across SQL Server / MySQL / Oracle so no provider needs to override the delta logic anymore. - SequenceBase: extends SchemaObjectBase with the cross-provider sequence properties: nullable StartWith, plus Owner / OwnerColumn for providers that support OWNED BY. Refactors the 4 provider Sequence subclasses to inherit from SequenceBase: - Postgresql.Sequence: 84 → 55 LOC - SqlServer.Sequence: 86 → 55 LOC - Oracle.Sequence: 104 → 76 LOC (Oracle keeps its provider-specific OracleConnection FindDeltaAsync overload and its PL/SQL DROP wrapper) - MySql.Sequence: 65 → 58 LOC (gains the standard IInheritance, keeps its table-based emulation override) Each provider's concrete subclass now only contains the 3 things that genuinely vary per database — WriteCreateStatement, WriteDropStatement, ConfigureQueryCommand — plus a strongly-typed FindDeltaAsync overload (e.g. NpgsqlConnection) where the original surface had one. No behavioural change. All 15 Postgresql Sequence tests pass; all 6 SqlServer Sequence tests pass. Sets the foundation for FunctionBase, ViewBase, and other ISchemaObject implementations in subsequent commits. Refs #270. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 2: FunctionBase, refactor PostgreSQL + SQL Server Function Lifts the ISchemaObject boilerplate that both Function implementations were duplicating: - Constructor pattern (DbObjectName, body, optional drop statements) - IsRemoved flag with protected setter - Body(Migrator?) — routes through the provider's WriteCreateStatement - DropStatements() — returns pre-supplied drops, empty for IsRemoved, or ComputeDefaultDropStatements() (abstract per provider) - WriteDropStatement — iterates DropStatements() and writes each line - CreateDeltaAsync — reads existing function via ReadExistingFromReaderAsync (abstract per provider) and routes through CreateFunctionDelta (abstract) - AllNames, Identifier — inherited from SchemaObjectBase Each provider's concrete Function now only contains: - WriteCreateStatement (PG writes RawBody directly; SS wraps in EXEC sp_executesql) - ConfigureQueryCommand (pg_proc + pg_namespace vs. sys.sql_modules) - ReadExistingFromReaderAsync (PG reads 2 result sets; SS reads 1) - ComputeDefaultDropStatements (PG parses function signature; SS uses identifier) - GetDefaultMigrator (provider's migrator type) - ParseIdentifier / ParseSignature (PG has the signature parser; SS uses identifier-only) - FetchExistingAsync / FindDeltaAsync (strongly-typed connection overloads) - ForSql / ForRemoval static factories - PG-only: BuildTemplate / WriteTemplate (template-based function generation) Result: - Postgresql.Functions.Function: 230 → 185 LOC (-45) - SqlServer.Functions.Function: 155 → 109 LOC (-46) - Weasel.Core.FunctionBase: 0 → 133 LOC (new shared base) Net: 91 LOC removed from per-provider Function files, 133 LOC of new reusable infrastructure. All 32 Postgresql Function tests pass; all 20 SqlServer Function tests pass. Refs #270. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 3: ViewBase, refactor PostgreSQL + SQLite View, SQLite ViewDelta Add Weasel.Core/ViewBase (extends SchemaObjectBase) owning the SELECT body (ViewSql), the MoveToSchema/WithSchema template-method pair, and the ToBasicCreateViewSql helper. Both PostgreSQL.View and SQLite.View now inherit from it and only carry the provider-specific DDL. PostgreSQL View keeps its protected virtual ViewType/ViewKind/GetCreationOptions hooks so MaterializedView continues to override "VIEW"→"MATERIALIZED VIEW", 'v'→'m', and USING <access_method>. SQLite ViewDelta now inherits from SchemaObjectDelta<View> instead of hand-rolling ISchemaObjectDelta. To preserve its "no previous state to restore" no-op semantics when Actual is null, SchemaObjectDelta<T>. WriteRestorationOfPreviousState is now virtual (it was concrete and would NRE on a null Actual). No existing override conflicts — grep across src shows the new SQLite ViewDelta override is the only one. Tests pass with no behaviour change: - SQLite view tests: 38/38 (net10.0) - PostgreSQL view tests: 11/11 (net10.0) - PostgreSQL sequence + function + materialized-view tests: 47/47 - SQL Server sequence + function tests: 26/26 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 4: pull ForeignKey shared methods into ForeignKeyBase The five provider ForeignKey classes (PG, SQL Server, Oracle, MySQL, SQLite) were carrying ~120 LOC of near-identical boilerplate each. This commit consolidates the cross-provider parts into ForeignKeyBase: - Parse(string definition[, string? defaultSchema]) — fully shared; subclasses only supply ParseLinkedTable(string) to wrap the parsed table name in the provider-specific DbObjectName subclass. ParseCascadeClause helper reads ON DELETE / ON UPDATE clauses (PG keeps a `new` overload defaulting schema to "public" for catalog rows that hand back unqualified names). - LinkColumns(columnName, referencedName) — append a (dependent, principal) pair to ColumnNames/LinkedNames. MySQL's setter-driven List<string> still works correctly through the base because the setters re-marshal. - ReadReferentialActions(onDelete, onUpdate) — translates catalog cascade text via a virtual ReadAction default that handles every spelling used across the five providers (CASCADE / RESTRICT / NO_ACTION / NO ACTION / SET_NULL / SET NULL / SET_DEFAULT / SET DEFAULT). The static *Provider.ReadAction methods stay in place for external callers. - Equals / GetHashCode — structural across same-provider FKs (name + column lists + LinkedTable + both cascades). Parametrised on virtual NameComparer/ColumnComparer so case-folding providers (Oracle, SQLite, MySQL) just override the comparers. Hash drops the buggy array-reference hashing the per-provider versions had — array identity hashing gave different hashes to structurally-equal FKs, breaking HashSet/Dictionary; omitting the arrays gives more collisions but keeps semantics correct. Equality is widened from the previous strict same-type to "same provider root" — Equals(object?) walks up the inheritance chain to find the immediate subclass of ForeignKeyBase (the provider's concrete ForeignKey class) and uses IsAssignableFrom, so consumer-supplied marker subclasses (Marten ships one as `ForeignKeyTest` in PG tests) still compare equal to plain provider FKs as they did pre-9.0, while cross-provider comparison still returns false. This restores a regression a strict GetType()==GetType() check would have introduced. MisconfiguredForeignKeyException was defined identically and unused in four providers; the canonical type now lives in Weasel.Core and the provider duplicates are removed. (The PG-specific InvalidForeignKeyException and TryToCorrectForLink stay where they are.) MySQL's IsEquivalentTo is kept as a forwarder to the new EqualsCore for backward compatibility. Not consolidated (deferred): WriteAddStatement / WriteDropStatement / ToDDL all take a provider-specific Table parameter, blocked on TableBase (step 9). The obsolete OnDelete/OnUpdate shim properties stay in the subclasses since their per-provider local CascadeAction enums are already marked [Obsolete] and scheduled for removal. Net diff: -189 LOC across the FK files. All tests pass: - PostgreSQL: 29/29 FK + 181/182 detecting_table_deltas (1 unrelated skip) - SQL Server: 22/22 FK + 31/31 detecting_table_deltas - SQLite: 24/24 FK + 361/361 full suite - Weasel.Core: 6/6 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 5: MySQL TableDelta now inherits SchemaObjectDelta<Table> MySQL.TableDelta was the only provider TableDelta still implementing ISchemaObjectDelta by hand (PG, SQL Server, Oracle, SQLite all inherit from SchemaObjectDelta<Table>). This commit brings MySQL onto the same pattern so the five deltas now compose uniformly: - Constructor forwards (expected, actual) to base - Differencing happens in the protected compare(expected, actual) override (the base ctor calls it and stores the SchemaPatchDifference on Difference); side-effect-populates Columns/Indexes/ForeignKeys/ PrimaryKeyDifference as before - WriteUpdate / WriteRollback overrides preserve the MySQL-specific DDL (MODIFY COLUMN, backtick quoting, DROP FOREIGN KEY syntax, PartitionStrategy = SchemaPatchDifference.Invalid path) - WriteRestorationOfPreviousState overridden because MySQL has historically no-op'd when Actual is null (the base default would NRE) - Expected/Actual properties drop from this file — inherited from SchemaObjectDelta<T> The public surface stays compatible: Columns / Indexes / ForeignKeys / PrimaryKeyDifference / HasChanges are still public (HasChanges is no longer required by ISchemaObjectDelta but is kept for callers that ask "anything to do?" without unpacking the Difference enum). All MySQL tests pass: 188/188 (33 integration tests against MySQL 8.0 container, 155 unit tests). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 7: extract DatabaseProvider memo-lookup helpers The five provider ResolveDatabaseType + ResolveXxxDbType methods were all carrying the same memo-lookup prologue: try DatabaseTypeMemo / ParameterTypeMemo; if absent and the type is Nullable<T>, look up T instead, copy the result to the nullable's slot for next-time, and return. Only the fallback after that miss differs per provider (PG → Npgsql plugin type map; SS/Oracle/MySQL → NotSupportedException; SQLite → null/Text). Move the lookup-with-nullable-promote into DatabaseProvider as two shared protected helpers — ResolveDatabaseTypeFromMemo and ResolveParameterTypeFromMemo — and rewrite each provider's two Resolve* methods as one-or-two-liners that combine the helper with the provider- specific fallback. The audit also suggested templating determineParameterType but I held back: in SS/Oracle/MySQL/SQLite the post-Resolve branches (IsEnum, IsArray, DBNull, IsConstructedGenericType) are largely unreachable because their Resolve always returns a sentinel fallback rather than null. Removing that dead code would technically preserve behaviour but risks edge cases that aren't covered by the current tests, so I left those bodies alone. Net diff: -97 LOC across the five provider files. No behaviour change. Tests pass: - PostgreSQL: 69/69 (Provider + TypeMapping + ToParameterType filter) - SQL Server: 8/8 (+8 pre-existing skips) - SQLite: 45/45 - MySQL: 37/37 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 8: prototype IDdlSyntaxStrategy on PostgreSQL + SQLite Introduces IDdlSyntaxStrategy in Weasel.Core — the pluggable strategy object the #270 plan calls out for owning provider-specific DDL syntax decisions. Step 8 deliberately covers only the parts of CREATE / DROP that genuinely differ between PostgreSQL and SQLite (the two providers at opposite ends of the feature spectrum, per the audit's "prototype against the extremes" guidance). If the shape holds for those two, step 9 will extend it across the remaining three providers when the full CREATE algorithm moves into TableBase. Strategy surface (intentionally minimal for the prototype): QuoteIdentifier(name) — provider quoting rules WriteDropTable(writer, identifier) — PG appends CASCADE, SQLite doesn't WriteCreateTableHeader(writer, id, style) — CREATE TABLE [IF NOT EXISTS] x ( InlineForeignKeyConstraints — true for SQLite (no ALTER ADD FK) AutoIncrementToken — SERIAL / AUTOINCREMENT / ... StatementTerminator — ";", or "/" for Oracle PostgresqlDdlSyntax (singleton) implements the PG side; SqliteDdlSyntax the SQLite side. Both Table classes expose Syntax => instance and route WriteDropStatement plus the CREATE-header part of WriteCreateStatement through it. The remaining CREATE body (columns / PK / inline FKs / indexes) is unchanged for now — it'll move into TableBase in step 9 once we've validated the strategy shape is workable. This is a behaviour-preserving change: the emitted SQL is byte-for-byte identical to before. Tests pass: - PostgreSQL: 185/188 (3 pre-existing concurrent-index skips) - SQLite: 361/361 (full suite) Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 9: TableBase, refactor all five provider Tables Introduces Weasel.Core.TableBase<TColumn, TIndex, TForeignKey> — the cross-provider base for the five concrete Table classes that the audit predicted would absorb ~600-700 LOC of duplication. This commit lifts the high-confidence shared boilerplate; the full CREATE algorithm body is still per-provider for now (step 8's IDdlSyntaxStrategy will absorb that incrementally once the strategy shape has settled). TableBase owns: - _columns field + Columns getter (generic over TColumn : ITableColumn) - ForeignKeys + Indexes + IgnoredIndexes - MaxIdentifierLength + TruncatedNameIdentifier - ColumnFor / HasColumn / IndexFor / HasIndex / HasIgnoredIndex / IgnoreIndex - RemoveColumn (always case-insensitive — matches every provider's pre-existing impl, distinct from the per-provider NameComparison) - PrimaryKeyName with DefaultPrimaryKeyName() hook (PG/SS use pkey_{name}_{cols}, Oracle/MySQL use pk_{name}_{cols}, SQLite uses pk_{name}) - NameComparison virtual (Ordinal default — PG only; SS/Oracle/MySQL/ SQLite override to OrdinalIgnoreCase to match their pre-existing ColumnFor/HasColumn behaviour) - ToString() returning $"Table: {Identifier}" (PG/SQLite had this override; SS/Oracle/MySQL inherit it now) - ToBasicCreateTableSql() template via GetDefaultMigratorForBasicSql() hook - All ITable explicit interface implementations (AddColumn(string,string), AddColumn(string,Type), AddPrimaryKeyColumn variants, ForeignKeys, AddForeignKey) — providers supply just three abstract hooks: CreateForeignKey(name), AddColumnAndReturn(name,type), AddPrimaryKeyColumnAndReturn(name,type), and GetDatabaseTypeFor(Type). PrimaryKeyColumns stays abstract per provider — PG / SQLite store an explicit _primaryKeyColumns field, SS / Oracle / MySQL derive from Columns.Where(IsPrimaryKey). Both shapes preserved. Provider-specific items retained: - Constructor (provider wraps Identifier in its DbObjectName subclass) - WriteCreateStatement / WriteDropStatement (step 8 strategy partially consumes; rest stays per-provider until follow-up) - AllNames() override (provider-specific DbObjectName wrapping for indexes and FKs) - ColumnExpression nested class - AddColumn fluent overloads returning ColumnExpression - PrimaryKeyDeclaration() (provider-specific quoting / formatting) - Partition properties / Engine / Charset / WithoutRowId / StrictTypes / etc. SQLite's TableDelta touched _columns directly via internal access; swapped those to call the public AddColumn(TableColumn) factory which properly sets Parent and adds via the base list. IgnoredIndexes was previously a PG- and SQLite-only feature; now uniform across all providers via TableBase. Empty set on SS / Oracle / MySQL is a no-op until those providers wire it up. Diff: -398 LOC net across the five Table.cs files (-565 deletions, +167 insertions excluding the new TableBase.cs). All tests pass: - PostgreSQL: 653/656 (3 pre-existing skips) - SQL Server: 244/252 (8 pre-existing skips) - SQLite: 361/361 - MySQL: 188/188 - Weasel.Core: 6/6 - Oracle: build-only (no container available locally) Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> * #270 step 10: canonical AutoIncrement() across providers, doc trait matrix Standardises the identity / auto-increment fluent spelling. Before 9.0 the same conceptual operation was spelled four different ways across providers: PostgreSQL: .Serial() / .BigSerial() / .SmallSerial() SQL Server: .AutoNumber() Oracle: .AutoNumber() MySQL: .AutoNumber() SQLite: .AutoIncrement() In 9.0 every provider's ColumnExpression exposes a canonical .AutoIncrement() (plus .BigAutoIncrement() / .SmallAutoIncrement() on PostgreSQL for the 64-bit and 16-bit variants). The historical names are kept as [Obsolete] aliases for one major-version cycle, with deprecation messages pointing at the canonical name. Polymorphic schema-building code now works without provider-specific casts: table.AddColumn<int>("id").AsPrimaryKey().AutoIncrement(); // works on all 5 SQL emitted is unchanged per provider — only the C# spelling on the caller side is normalised. Also adds docs/core/provider-trait-matrix.md (linked in the sidebar) that explicitly documents the per-provider differences the audit catalogued: quoting, case-folding, ALTER TABLE limitations, partitioning, JSON storage, identity spelling, primary-key name defaults, the new TableBase / ForeignKeyBase / SequenceBase / FunctionBase / ViewBase / IDdlSyntaxStrategy class hierarchy, and the constructor pattern. End users can now answer "what works on every provider vs what's provider-specific" without reading source. DocSamples updated to use the canonical AutoIncrement() spelling. Test code still uses the old names (Serial() / AutoNumber()) for now to validate the [Obsolete] forwarders work — those warnings will surface in CI as a gentle nudge to migrate but they're not failures. This completes the #270 work plan. Sequence of commits on this branch: 83cf822 JasperFx 2.0.0-alpha.8 upgrade 5ea60f3 step 1: SchemaObjectBase + SequenceBase 639628f step 2: FunctionBase 2967556 step 3: ViewBase + SQLite ViewDelta e7afae8 step 4: ForeignKeyBase (-174 LOC net) 02a6440 step 5: MySQL TableDelta ( +5 LOC net) 9c49c1e step 7: DatabaseProvider memo helpers ( -37 LOC net) 1319cf4 step 8: IDdlSyntaxStrategy prototype 99485c1 step 9: TableBase (-154 LOC net) <this> step 10: AutoIncrement + trait matrix Step 6 (TableDeltaBase shared helpers) was absorbed into step 9 since the helpers needed TableBase to exist before they could decompose cleanly. All tests pass: - PostgreSQL: 653/656 (3 pre-existing skips) - SQL Server: 244/252 (8 pre-existing skips) - SQLite: 361/361 - MySQL: 188/188 - Weasel.Core: 6/6 - Oracle: build-clean (no container locally) Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
…ions (#272) #261 — Postgres/SqlServer CascadeAction obsolete PG and SqlServer ColumnExpression.ForeignKeyTo overloads took the local [Obsolete] CascadeAction enum, with no Weasel.Core.CascadeAction overload. Users wanting to opt out of the obsolete enum had no fluent path. (Oracle and MySQL already used Core.CascadeAction directly via the using directive — verified by grep; no local CascadeAction enum exists in those projects.) Adds Core.CascadeAction sibling overloads on PG and SS ColumnExpression for ForeignKeyTo(string,...), ForeignKeyTo(Table,...), ForeignKeyTo(DbObjectName,...) and (PG only) ForeignKeyTo(PostgresqlObjectName,...). The new overloads have no defaults to avoid call-site ambiguity with the existing overloads, so .ForeignKeyTo("x", "y") binds unchanged. Callers opt into Core by passing the enum values explicitly: // before — obsolete enum .ForeignKeyTo("tbl", "id", onDelete: Weasel.Postgresql.CascadeAction.Cascade) // after — canonical .ForeignKeyTo("tbl", "id", fkName: null, onDelete: Weasel.Core.CascadeAction.Cascade, onUpdate: Weasel.Core.CascadeAction.NoAction) Defaults can be restored when the local CascadeAction enums are removed in a future major (currently scheduled per #263). #265 — AOT IL3050 on AnsiConsole.WriteException in AssertCommand Annotates AssertCommand.Execute with [RequiresDynamicCode] so the IL3050 diagnostic propagates to AOT-publishing consumers as a precise warning instead of getting swallowed inside Weasel.Core. The xmldoc explains why: db-assert is a dev-time CLI tool, so the minimum-blast-radius fix is to let consumers see the warning at the entry point rather than chase Spectre.Console's ExceptionFormatter. #266 — AOT IL2075 on CommandBuilderBase.AddParameters reflection Annotates the parameters argument of AddParameters(object) with [DynamicallyAccessedMembers(PublicProperties)] so callers carry the runtime contract through the type system, plus an [UnconditionalSuppressMessage("Trimming", "IL2075", ...)] that documents why the warning at the GetType().GetProperties() call site is expected — the trimmer's flow analysis doesn't currently propagate the DAM annotation through object.GetType(), but the runtime contract holds. xmldoc points at the longer-term source-generator path as path 2 from the issue. All existing tests pass: PG 653/656 (3 pre-existing skips), SS 244/252 (8 pre-existing), SQLite 361/361, MySQL 188/188, Core 6/6. Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
New docs/migration-guide.md walks consumers through the Critter Stack 2026 upgrade path for Weasel: - Foundation pin bumps (JasperFx 2.0 alphas) + dropping net8.0 - Dedup-audit relocations (CascadeAction, BulkInsertMode, MisconfiguredForeignKeyException → Weasel.Core) with before/after snippets - Canonical AutoIncrement() fluent rename + the [Obsolete] alias table (Serial / BigSerial / SmallSerial / AutoNumber) - SchemaObjectDelta<T>.WriteRestorationOfPreviousState now virtual, including the no-op-on-null-Actual override pattern that SQLite ViewDelta uses - ForeignKey.Equals widening — restores the Marten/consumer marker-subclass pattern that strict GetType() comparison broke - Behaviour fixes worth flagging (SQL Server column casing, SQLite composite PK) - New surface (no migration impact): TableBase / ForeignKeyBase / SequenceBase / FunctionBase / ViewBase / IDdlSyntaxStrategy, with links out to the trait matrix - AOT posture summary + link to the cross-stack publishing guide - Lockstep dependency table for the 2026 wave Sidebar gets a "Migrating from 8.x to 9.0" entry under Getting Started. Drive-by fix: docs/core/provider-trait-matrix.md had a dead link to src/Weasel.Core/IDdlSyntaxStrategy.cs via a relative path VitePress can't resolve. Replaced with the GitHub URL on the 9.0 branch so the docs build passes again. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
docs/migration-guide.mdto walk consumers through the Critter Stack 2026 upgrade path. Sits alongside Polecat 3→4 and the (in-flight) Marten 8→9 guides; cross-linked from all three.The doc covers, in order:
net8.0, current TFMs.Weasel.Postgresql.CascadeAction/Weasel.SqlServer.CascadeAction→Weasel.Core.CascadeAction(sibling overloads, no defaults to avoid call-site ambiguity)Polecat.BulkInsertMode→Weasel.Core.BulkInsertMode(gainedOverwriteIfVersionMatches)Weasel.*.MisconfiguredForeignKeyException→Weasel.Core.MisconfiguredForeignKeyExceptionAutoIncrement()fluent rename (Serial/BigSerial/SmallSerial/AutoNumberare[Obsolete]one cycle)SchemaObjectDelta<T>.WriteRestorationOfPreviousStatenowvirtual— with the no-op-on-null-Actualoverride pattern SQLiteViewDeltausesForeignKey.Equalswidening to "same provider root" — restores the consumer marker-subclass pattern Marten and similar libraries rely onTableColumncasing preserved (Resolve #261, #265, #266 — Core.CascadeAction overloads + AOT annotations #272)TableBase/ForeignKeyBase/SequenceBase/FunctionBase/ViewBase/SchemaObjectBase— links out to the Provider Trait MatrixIDdlSyntaxStrategyprototype scope (PG + SQLite for now, opt-in for customTablesubclasses)IsAotCompatible=true+ reflective-surface annotation summaryThe migration guide is added to the VitePress sidebar under Getting Started:
Drive-by fix
docs/core/provider-trait-matrix.mdhad a dead relative-path link tosrc/Weasel.Core/IDdlSyntaxStrategy.csthat brokenpm run build— VitePress can't resolve cross-tree file links. Replaced with the GitHub URL on the9.0branch.Test plan
cd docs && npm install && npm run build— passesRefs #270, #272, jasperfx#217 (Critter Stack 2026 umbrella), jasperfx#213 (AOT pillar).
🤖 Generated with Claude Code