@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 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 updateOperations = { $set: { [deletedAtColumn]: /* @__PURE__ */ new Date() } };
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