Chages - #3
Merged
Merged
Chages#3
Conversation
- Microsoft SQL Server as a first-class dialect (mssql v12): T-SQL query generation (OUTPUT INSERTED.*, OFFSET/FETCH pagination, MERGE upserts), schema generation via OBJECT_ID and sys.indexes probes in place of the CREATE IF NOT EXISTS forms SQL Server lacks, and automatic rewriting of the library's ? placeholders to @param0. - Model relationships: OneToOne, ManyToOne, OneToMany and ManyToMany, declared in the model config and eager-loaded in batched follow-up queries rather than per row. attach/detach/sync edit a join table without loading either side. - Column encryption: marking a column encrypted encrypts on write and decrypts on read with AES-256-GCM, including for rows served from cache. The key is read from ORM_ENCRYPTION_KEY with no fallback, so a missing key fails loudly instead of silently protecting nothing. - auto-migrate.ts: additive AutoMigrate that creates missing tables, adds missing columns and adds missing indexes. It never drops a column and never changes a column type. - validateAll, findOrFail/firstOrFail, raw clause builders, and connection retry with exponential backoff and jitter for read-only statements. Fixed: - after* hooks and both delete hooks never ran: getHooks() resolved the model through proto.constructor, but reads return plain rows, so the prototype was Object and the metadata lookup found nothing. - getRepository() opened a new, unclosed Redis connection on every call. - Cached find() results were written without their relations, so a cache hit returned a different shape than a miss. Adds test coverage for all of the above, plus integration suites for sqlite, mysql, mariadb, postgres, mssql, models, relations and the write paths, which skip themselves when no server answers. The docs move to their own repository (ElectronSz/stabilize-docs) and are now ignored here.
Brings in the validation metadata mapping fix from origin/chages. The only
conflict was the column mapping in repository.ts, where both sides had added
different fields to the same object: origin/chages added minLength, maxLength,
pattern and customValidator, and this branch added required, unique, encrypted,
softDelete and optimisticLock. Resolved as the union of both.
Two defects in the incoming tests/migrations.test.ts, both of which broke the
suite:
- The file was missing a closing brace. describe("generateMigration") opened at
line 31 and never closed, so describe("runMigrations") was nested inside it and
the file ended one brace short — 38 opening against 37 closing. It failed to
parse, which took the whole file's tests out of the run.
- It called vi.mock("../client"). Under Bun's test runner a module mock is
process-wide, not file-scoped, so the mock replaced DBClient for every other
test file in the run. Those files then failed with "db.migrationQuery is not a
function" against a mock that never had that method, and the suite went from
262 passing to 239. The mock is gone; runMigrations is now driven against a
real file-backed SQLite database and the result read back through a second
connection, which covers the same ground and also asserts that a recorded
migration is not applied twice.
…chema MongoDB joins the four SQL dialects as a full backend rather than a side-car. The work is staged M0-M4 of the approved plan, each milestone green before the next began. M0 - connection lifecycle. The driver is an optional dependency and is imported lazily, so a project that only uses SQLite never needs it. A connect-time probe warns when the server is a standalone, because the ORM wraps every write in a transaction and a standalone rejects startTransaction - so the failure would otherwise appear only on the first create, with a driver message that names the rule but not the remedy. The Mongo handles are structural interfaces, so no driver type reaches an emitted .d.ts. M1 - mongo-query.ts, the pure translation layer. Structured predicates are recorded alongside the SQL fragments the existing methods already render, so the four SQL backends are untouched. Clauses that have no MongoDB equivalent (joins, CTEs, raw SQL) record a blocker and throw at execute() naming every offending method. M2 - the repository's ~24 raw where() calls became structured ones, so no SQL parsing is needed on the Mongo path. This surfaced four bugs where a lookup rendered the property key into SQL instead of the column name; only a renamed column could expose them, which is why tests/renamed-columns.test.ts builds models that have one and asserts each fix, with a companion assertion that the property-named column is genuinely absent so the test cannot pass for the wrong reason. M3 - the read path and integer auto-increment keys. Ids come from a stabilize_counters collection; one $inc reserves a whole bulkCreate batch, and a caller-supplied id advances the counter with $max so a later generated id cannot collide. Documents are keyed by _id. M4 - schema and migrations. Collections are created with a $jsonSchema validator and indexes. Two rules are load-bearing and are asserted against a real server: validationLevel "moderate", without which an update to a document lacking a newly declared required field is rejected, and sparse: true on unique indexes, without which the second document that omits a unique column collides where SQL would allow it. Migrations are data rather than closures, so a generated one is assertable without a server. Also fixes a bug the M4 tests found in shared code: the transaction error classifier rewrote every error as TX_ERROR, including errors the ORM raised itself, so a validation failure pointed the reader at the server's replica-set configuration. The four SQL branches all let their original error through; MongoDB now does too, while still recognising a standalone's rejection when the executor has already wrapped it. 380 pass / 0 fail, typecheck clean, build clean, no mongodb reference in dist/*.d.ts.
…atches Completes the backend begun in 681e341. The four SQL backends are untouched: every MongoDB body sits behind an early return in repository.ts, and the shared code above it — validation, hooks, timestamps, optimistic locking, cache invalidation, relation algorithms, encryption — is reused, not duplicated. Write path: create/bulkCreate, update/bulkUpdate, upsert, delete/bulkDelete, recover, plus updateBy/deleteBy/restoreBy, increment/decrement/toggle, aggregate, countDistinct, paginate, random and the findMany cursor. Relations: attach/fetch/sync for many-to-many, with the link collection keyed by a compound {parent, child} _id so attach is idempotent at the storage layer rather than by pre-read. Link reads are explicitly sorted, because MongoDB's to-many order is unspecified and not stable between two reads of unchanged data. Versioning: asOf/history/rollback/writeHistory against a history collection with native Date validity windows, so the range comparisons stay index-backed. A delete now records max(sent, newestRecorded + 1): on MongoDB the version is half the compound _id, so recording the row's current version collided with the row it was journalling and failed the delete it was meant to record. Escape hatches: the 22 clauses with no MongoDB equivalent throw MONGO_UNSUPPORTED naming every offending method, and an inverse table proves an allowed clause is not refused. lock()/forUpdate() is a no-op that Repository.lockForUpdate now warns about, since the read it returns is indistinguishable from a locked one. Also fixes aggregate() on an empty collection, where $group over no input produces no document at all and the count came back undefined rather than 0. Flagged, not fixed: processForLoad reads processed[key] while rows arrive keyed by column name, so an encrypted column that declares name: is not decrypted on read. This affects all five backends and is left for a separate change.
Major version for the MongoDB backend, which is a new supported database rather than a change to the existing four. The version number is the only purely mechanical part: no SQL behaviour changed in this release, so a 2.x consumer that does not opt into MongoDB has no migration to perform. The bump signals that defineModel and the Repository API now carry a backend whose guarantees differ in documented ways — raw SQL is refused, transactions require a replica set, and DECIMAL is stored as a double. The description now names SQL Server and MongoDB, neither of which it mentioned despite both being supported.
It was recorded as a bare gitlink with no .gitmodules, so a fresh clone produced an empty stabilize-cli directory with nothing to tell git where the contents should come from. The recorded pointer was also stale: it named 6a92aa13 while the nested repo's HEAD was ac5e810. That commit is a descendant, so the pointer was simply behind rather than pointing at something that never existed — and ac5e810 is already on origin/main, so nothing needed pushing to make it reachable. Adds the missing .gitmodules and advances the pointer. The nested repo's working tree is left as it is: it has uncommitted changes of its own, which belong to its own history rather than to this pointer.
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.
No description provided.