@warlock.js/cascade 4.2.10 → 4.2.11
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 +15 -0
- package/cjs/index.cjs +40 -3
- package/cjs/index.cjs.map +1 -1
- package/esm/migration/migration.d.mts +20 -0
- package/esm/migration/migration.d.mts.map +1 -1
- package/esm/migration/migration.mjs +34 -0
- package/esm/migration/migration.mjs.map +1 -1
- package/esm/remover/database-remover.d.mts.map +1 -1
- package/esm/remover/database-remover.mjs +3 -1
- package/esm/remover/database-remover.mjs.map +1 -1
- package/esm/writer/database-writer.d.mts.map +1 -1
- package/esm/writer/database-writer.mjs +4 -2
- package/esm/writer/database-writer.mjs.map +1 -1
- package/llms-full.txt +24 -1
- package/package.json +5 -5
- package/skills/configure-delete-strategy/SKILL.md +4 -0
- package/skills/write-migration/SKILL.md +20 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## 4.2.11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `Migration.create` auto-wires the `deletedAt` column when the model's delete strategy is `"soft"` (opt out with `{ softDeletes: false }`)
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Require `@mongez/reinforcements` ≥ 3.3.0 — the update validator now uses its new `when` helper for conditional schema fields
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Soft `destroy()` now sets `deletedAt` on the in-memory model — the instance was left stale before
|
|
22
|
+
- Update validation no longer strips or rejects the `deletedAt` column under strict mode (now whitelisted like the timestamps)
|
|
23
|
+
|
|
9
24
|
## 4.2.1
|
|
10
25
|
|
|
11
26
|
### Fixed
|
package/cjs/index.cjs
CHANGED
|
@@ -3152,8 +3152,10 @@ var DatabaseRemover = class {
|
|
|
3152
3152
|
case "soft": {
|
|
3153
3153
|
const deletedAtColumn = this.ctor.deletedAtColumn;
|
|
3154
3154
|
if (deletedAtColumn === false || deletedAtColumn === void 0) throw new Error(`Cannot perform soft delete on ${this.ctor.name}: deletedAtColumn is not configured. Set a column name or use a different delete strategy.`);
|
|
3155
|
-
const
|
|
3155
|
+
const deletedAt = /* @__PURE__ */ new Date();
|
|
3156
|
+
const updateOperations = { $set: { [deletedAtColumn]: deletedAt } };
|
|
3156
3157
|
deletedCount = (await this.driver.update(this.table, filter, updateOperations)).modifiedCount > 0 ? 1 : 0;
|
|
3158
|
+
if (deletedCount > 0) this.model.set(deletedAtColumn, deletedAt);
|
|
3157
3159
|
break;
|
|
3158
3160
|
}
|
|
3159
3161
|
}
|
|
@@ -3863,8 +3865,9 @@ var DatabaseWriter = class {
|
|
|
3863
3865
|
const validationSchema = isInsert ? this.schema.clone() : this.schema.clone(Object.keys(this.model.data)).extend({
|
|
3864
3866
|
id: _warlock_js_seal.v.scalar().optional(),
|
|
3865
3867
|
_id: _warlock_js_seal.v.any().optional(),
|
|
3866
|
-
[this.ctor.createdAtColumn]: _warlock_js_seal.v.date().optional(),
|
|
3867
|
-
[this.ctor.updatedAtColumn]: _warlock_js_seal.v.date().optional()
|
|
3868
|
+
...(0, _mongez_reinforcements.when)(this.ctor.createdAtColumn, () => ({ [this.ctor.createdAtColumn]: _warlock_js_seal.v.date().optional() })),
|
|
3869
|
+
...(0, _mongez_reinforcements.when)(this.ctor.updatedAtColumn, () => ({ [this.ctor.updatedAtColumn]: _warlock_js_seal.v.date().optional() })),
|
|
3870
|
+
...(0, _mongez_reinforcements.when)(this.ctor.deletedAtColumn, () => ({ [this.ctor.deletedAtColumn]: _warlock_js_seal.v.date().optional() }))
|
|
3868
3871
|
});
|
|
3869
3872
|
if (this.strictMode === "strip") validationSchema.stripUnknown();
|
|
3870
3873
|
else if (this.strictMode === "fail") validationSchema.allowUnknown(false);
|
|
@@ -20218,6 +20221,34 @@ function migrate(model, options) {
|
|
|
20218
20221
|
};
|
|
20219
20222
|
}
|
|
20220
20223
|
/**
|
|
20224
|
+
* Resolve the soft-delete column to auto-wire for a declarative `Migration.create`.
|
|
20225
|
+
*
|
|
20226
|
+
* Mirrors the runtime strategy resolution used by `destroy()`
|
|
20227
|
+
* (`model.deleteStrategy` → DataSource `defaultDeleteStrategy` → `"permanent"`)
|
|
20228
|
+
* and returns the model's resolved `deletedAtColumn` only when the column should
|
|
20229
|
+
* be added — otherwise `undefined`.
|
|
20230
|
+
*
|
|
20231
|
+
* @param model - Model the migration is bound to
|
|
20232
|
+
* @param force - The `softDeletes` option: `true` forces the column on;
|
|
20233
|
+
* `undefined` follows the resolved strategy. (`false` is short-circuited by
|
|
20234
|
+
* the caller and never reaches here.)
|
|
20235
|
+
* @returns The column name to add, or `undefined` to skip
|
|
20236
|
+
* @internal
|
|
20237
|
+
*/
|
|
20238
|
+
function resolveSoftDeleteColumn(model, force) {
|
|
20239
|
+
let defaultStrategy;
|
|
20240
|
+
try {
|
|
20241
|
+
defaultStrategy = model.getDataSource().defaultDeleteStrategy;
|
|
20242
|
+
} catch {
|
|
20243
|
+
defaultStrategy = void 0;
|
|
20244
|
+
}
|
|
20245
|
+
const deletedAtColumn = model.deletedAtColumn;
|
|
20246
|
+
if (deletedAtColumn === false) return;
|
|
20247
|
+
const column = deletedAtColumn || "deletedAt";
|
|
20248
|
+
if (force === true) return column;
|
|
20249
|
+
return (model.deleteStrategy ?? defaultStrategy ?? "permanent") === "soft" ? column : void 0;
|
|
20250
|
+
}
|
|
20251
|
+
/**
|
|
20221
20252
|
* Wire a `ColumnMap` onto an active migration instance.
|
|
20222
20253
|
*
|
|
20223
20254
|
* Fixes up the placeholder column name in each `DetachedColumnBuilder`,
|
|
@@ -20255,6 +20286,8 @@ function wireColumns(migration, columns) {
|
|
|
20255
20286
|
* - `createTableIfNotExists()`
|
|
20256
20287
|
* - Primary key (type resolved from `migrationDefaults.primaryKey` → options → `"int"`)
|
|
20257
20288
|
* - `timestamps()`
|
|
20289
|
+
* - Soft-delete column when the model's delete strategy resolves to `"soft"`
|
|
20290
|
+
* (opt out with `{ softDeletes: false }`, force on with `true`)
|
|
20258
20291
|
* - `down()` → `dropTableIfExists()`
|
|
20259
20292
|
*
|
|
20260
20293
|
* The class-based API remains available for complex migrations (raw SQL,
|
|
@@ -20295,6 +20328,10 @@ Migration.create = function createMigration(model, columns, options = {}) {
|
|
|
20295
20328
|
else if (pkType === "int") this.id();
|
|
20296
20329
|
wireColumns(this, columns);
|
|
20297
20330
|
if (withTimestamps) this.timestamps();
|
|
20331
|
+
if (options.softDeletes !== false) {
|
|
20332
|
+
const deletedAtColumn = resolveSoftDeleteColumn(model, options.softDeletes);
|
|
20333
|
+
if (deletedAtColumn && !Object.prototype.hasOwnProperty.call(columns, deletedAtColumn)) this.softDeletes(deletedAtColumn);
|
|
20334
|
+
}
|
|
20298
20335
|
if (options.index) for (const entry of options.index) this.index(entry.columns, entry.name, {
|
|
20299
20336
|
include: entry.include,
|
|
20300
20337
|
concurrently: entry.concurrently
|