@voltro/database 0.62.3 → 0.64.0

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/dist/sql.d.ts CHANGED
@@ -419,6 +419,14 @@ declare interface ColumnDefinition<TsType, Type extends ColumnType = ColumnType,
419
419
  * has nothing to do with FK semantics.
420
420
  */
421
421
  readonly refOnUpdate?: 'cascade' | 'restrict' | 'setNull' | 'noAction';
422
+ /**
423
+ * What the RUNTIME does to this column's rows when the referenced row is
424
+ * SOFT-deleted (`deletedAt` set) — set by `reference(…, { onSoftDelete })`.
425
+ * A foreign key never sees a soft delete (it is an UPDATE), so `onDelete`
426
+ * cannot express it; the store's post-commit change channel enforces this
427
+ * one instead, the way `pluginRef` orphan rules are enforced.
428
+ */
429
+ readonly refOnSoftDelete?: 'cascade' | 'setNull';
422
430
  /**
423
431
  * Auto-create a B-tree index on this FK column. Default `true` — FK
424
432
  * columns are nearly always read-by, and the lookup cost of a missing
@@ -522,12 +530,16 @@ declare interface ColumnDefinition<TsType, Type extends ColumnType = ColumnType,
522
530
  /**
523
531
  * Field-level encryption flag, set by `.encrypted()`. When `true`
524
532
  * the runtime's store middleware encrypts the value on write and
525
- * decrypts on read via the registered field cipher (AES-256-GCM,
526
- * keyed from the Secrets-Resolver — see `@voltro/plugin-governance`).
527
- * The stored column is an opaque `enc:v1:…` string, so the DB type
528
- * stays `text`. A row written while encryption is active can't be
533
+ * decrypts on read via the registered field cipher (AES-256-GCM, keyed
534
+ * from `VOLTRO_FIELD_ENCRYPTION_KEY` through the Secrets-Resolver — the
535
+ * framework registers it on both boot paths; `voltro dev` mints the key).
536
+ * The stored column is an opaque `enc:v2:…` string bound by GCM's
537
+ * additional authenticated data to its table, column and row
538
+ * (`FieldBinding`), so a ciphertext copied into another row or column
539
+ * does not decrypt there — and the DB type stays `text`. A row written
540
+ * while encryption is active can't be
529
541
  * read back without the key — losing the key loses the data, by
530
- * design. Boot fails loud if an `.encrypted()` column is present but
542
+ * design. Boot refuses if an `.encrypted()` column is declared but
531
543
  * no cipher is registered.
532
544
  */
533
545
  readonly encrypted?: boolean;
@@ -2091,6 +2103,15 @@ declare interface QueryDescriptor<R = Row> {
2091
2103
  * rows (an admin view, a grace-period check). Same shape and same posture as
2092
2104
  * `includeDeleted`. */
2093
2105
  readonly includeExpired?: boolean;
2106
+ /**
2107
+ * Lock the matched rows for the rest of the enclosing transaction — set by
2108
+ * `.forUpdate()`. `SELECT … FOR UPDATE` on postgres / mysql / mariadb,
2109
+ * `WITH (UPDLOCK, ROWLOCK)` on mssql; sqlite serialises writers already and
2110
+ * emits nothing. Outside a transaction the lock is released as the statement
2111
+ * ends, which is harmless and useless — the point is a read-modify-write
2112
+ * whose read and write share one transaction.
2113
+ */
2114
+ readonly lock?: 'update';
2094
2115
  /**
2095
2116
  * Opt OUT of the runtime's automatic tenant scope on `tenant()` tables.
2096
2117
  * Set by `.unscoped()`. Honored by the runtime, same as `includeDeleted`.
@@ -2677,6 +2698,9 @@ export declare interface RunPlannedMigrationsCtx {
2677
2698
  readonly environment: BootEnvironment;
2678
2699
  /** Pretty-name dialect used for log lines. */
2679
2700
  readonly dialectId: string;
2701
+ /** How long a soft-drop snapshot may sit before the boot warns about it
2702
+ * (`database.softDropRetentionDays`; default 7). */
2703
+ readonly softDropRetentionDays?: number;
2680
2704
  }
2681
2705
 
2682
2706
  /**
@@ -3112,10 +3136,11 @@ declare interface Table<Name extends string, Fields extends Record<string, Colum
3112
3136
  * row with the same key is allowed — no hand-written
3113
3137
  * `generatedAs("CASE WHEN …")` column, no resurrection footgun.
3114
3138
  *
3115
- * **mysql / mariadb:** these engines have no partial-index support, so
3116
- * `.uniqueActive()` FAILS LOUDLY at migrate time (a full unique index would
3117
- * silently forbid re-creating a soft-deleted row). Use a generated STORED
3118
- * column + `.unique()` there until the framework lowers it for you.
3139
+ * **mysql / mariadb:** these engines have no partial-index support, so the
3140
+ * migrator LOWERS `.uniqueActive()` to a generated STORED column holding the
3141
+ * key while the predicate holds (NULL otherwise, and NULLs never collide) plus
3142
+ * a UNIQUE index on it the same guarantee, on the dialects that cannot
3143
+ * spell it directly. See `lowerUniqueActive` in `migrate.ts`.
3119
3144
  */
3120
3145
  uniqueActive: {
3121
3146
  <const F extends readonly [keyof Fields & string, ...Array<keyof Fields & string>]>(fields: F, options?: {
@@ -3378,8 +3403,9 @@ declare interface TableIndex {
3378
3403
  * declarative planner is predicate-blind, these are emitted by the
3379
3404
  * fresh-schema DDL path (like every partial predicate) and kept OUT of the
3380
3405
  * declarative index snapshot. mysql/mariadb have no partial-index support —
3381
- * `.uniqueActive()` fails loudly there (use a generated column) rather than
3382
- * silently dropping the predicate into a full unique index.
3406
+ * `.uniqueActive()` is lowered there to a generated STORED column + UNIQUE
3407
+ * (`migrate.ts`) rather than silently dropping the predicate into a full
3408
+ * unique index.
3383
3409
  */
3384
3410
  readonly unique?: boolean;
3385
3411
  }