@zerotal/orm 1.6.3 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,97 @@ follows the Zerotal monorepo's unified versioning.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ### Fixed
12
+
13
+ - **A seeder that failed partway left its rows behind.** `Seeder.call()` has always wrapped
14
+ *composed* seeders in a transaction, so a `DatabaseSeeder` that delegates was atomic and one that
15
+ does its work inline — which is most of them — was not. A failure on the fourth table committed
16
+ the first three, so the obvious next move, running it again, died on a unique constraint, and the
17
+ only way out was `migrate:fresh`. Migrations became transactional in 1.7.0; this closes the
18
+ asymmetry.
19
+
20
+ `db:seed` now wraps the whole run. Nesting is safe — `DB.transaction` opens a `SAVEPOINT` when one
21
+ is already open, so an inner `call()` still rolls back independently. The wrapper is skipped when
22
+ no connection is bound, because a seeder is not obliged to touch the database and an app that has
23
+ not configured one should not fail to seed over a transaction it never needed.
24
+
25
+
26
+ ### Fixed
27
+
28
+ - **`DatabaseProvider` now runs in `worker`, so `zt queue:work` can boot.** It did not, and the
29
+ consequence was total rather than partial: `QueueProvider` _does_ run in `worker`, the
30
+ queue's own default driver is `sqlite`, and so the worker asked for a connection this
31
+ provider had not made and died on startup —
32
+
33
+ ```
34
+ error: [Zerotal ORM] No database connection. Is DatabaseProvider registered?
35
+ ```
36
+
37
+ — while it plainly was registered.
38
+
39
+ It was never only the queue. Nine providers run in `worker` — notifications, audit, media,
40
+ tenancy, scheduler among them — and a job exists to do work with models. `AuthProvider` and
41
+ `SessionProvider` are absent from `worker` correctly, having neither a request nor a
42
+ session; the ORM being absent was an oversight, dating to 1.0.2.
43
+
44
+ Found building the first cookbook app, whose first queued job could not run.
45
+
46
+ - **Relation keys now accept the JS spelling, like every other identifier.** The convention is
47
+ camelCase in the application and snake_case in the database, converted on the way through —
48
+ and relation keys were the one place it did not happen. `@hasMany(() => Issue, { foreignKey:
49
+ "projectId" })` type-checked and then emitted `no such column: issues.projectId`, with the
50
+ error naming a column rather than the relation that produced it.
51
+
52
+ `_relationSubquery()` builds its subquery with a plain `QueryBuilder`, and the `_column()`
53
+ hook that converts is an override on `ModelQueryBuilder`, so nothing was converting these.
54
+ The keys are now converted where they are qualified, which covers `withCount`, `withSum`,
55
+ `has`/`whereHas` and `withExists` for `hasMany`, `belongsTo`, `manyToMany` and the morph
56
+ relations. Both spellings resolve to the column, so apps already passing `project_id` are
57
+ unaffected.
58
+
59
+ Found building the first cookbook app, where a project list would not count its issues.
60
+
61
+ ## [1.7.0] — 2026-08-16
62
+
63
+ ### Fixed
64
+
65
+ - **Migrations are now actually transactional.** The runner wrapped each `up()` in
66
+ `begin()` and the docblock promised all-or-nothing, but the wrapper governed nothing:
67
+ `Schema` resolved the _global_ connection, so the migration's DDL ran on a pooled
68
+ connection and committed independently of the transaction around it. On PostgreSQL a
69
+ migration that failed on its third statement left the first two behind, and the enclosing
70
+ `ROLLBACK` had nothing to undo.
71
+
72
+ Three changes close it. `Schema` resolves the enclosing transaction when there is one
73
+ (new `_getScopedDbConnection`), so DDL issued inside `DB.transaction()` joins it —
74
+ migrations included. The tracking-table insert moved _inside_ the transaction, because
75
+ recording after the commit leaves a window where the schema has moved and nothing says so,
76
+ and the next deploy re-runs the migration against a schema it already changed. And
77
+ rollback got the same treatment: a `down()` that fails part-way now undoes nothing rather
78
+ than leaving the schema and the tracking table disagreeing.
79
+
80
+ This was invisible to the test suite by construction — `new SQL(":memory:")` is a single
81
+ handle, so the "global" and transaction connections are the same object and DDL joined the
82
+ transaction by accident. The new tests use a fake that keeps them distinguishable.
83
+
84
+ ### Added
85
+
86
+ - **`MigrationRunner.willRollBackOnFailure`** and `SqlDialect.supportsTransactionalDdl`.
87
+ MySQL and MariaDB implicitly commit on every DDL statement, so a transaction around a
88
+ migration there is a promise that cannot be kept — the runner no longer opens one, and
89
+ `bun zt migrate` warns before it starts rather than after something breaks. PostgreSQL
90
+ and SQLite report `true`.
91
+
92
+ - **Two DevTools tabs the ORM already had the data for.** `ModelChanged`,
93
+ `TransactionCommitted` and `TransactionRolledBack` were on the framework event bus and went
94
+ nowhere: a request that wrote four rows and one that wrote none looked identical in the
95
+ panel, and a transaction that rolled back showed only as queries that appeared to succeed.
96
+
97
+ The observability bridge now declares a **Models** channel (grouped per model) and a
98
+ **Transactions** channel (marking a rollback as a warning, with its reason). Both are
99
+ declared as data, so DevTools ships no ORM-specific code — and both are skipped entirely
100
+ when DevTools is not installed, as every other bridge here is.
101
+
11
102
  ## [1.6.0] — 2026-08-15
12
103
 
13
104
  ### Fixed