@rvoh/dream 2.30.1 → 2.32.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.
Files changed (251) hide show
  1. package/dist/cjs/src/Dream.js +9 -5
  2. package/dist/cjs/src/db/errors.js +2 -0
  3. package/dist/cjs/src/decorators/Decorators.js +121 -6
  4. package/dist/cjs/src/decorators/field/sortable/Sortable.js +4 -31
  5. package/dist/cjs/src/decorators/field/sortable/helpers/cascadeReachesEveryRowInSortScope.js +51 -0
  6. package/dist/cjs/src/decorators/field/sortable/helpers/performSortableDestroyWork.js +5 -2
  7. package/dist/cjs/src/decorators/field/sortable/helpers/prepareSortableFieldsForDestroy.js +39 -25
  8. package/dist/cjs/src/decorators/field/sortable/helpers/sortableCascadeEdge.js +32 -0
  9. package/dist/cjs/src/dream/Query.js +37 -13
  10. package/dist/cjs/src/dream/QueryDriver/Base.js +26 -0
  11. package/dist/cjs/src/dream/QueryDriver/Kysely.js +4 -1
  12. package/dist/cjs/src/dream/QueryDriver/Postgres.js +7 -1
  13. package/dist/cjs/src/dream/internal/destroyAssociatedRecords.js +7 -0
  14. package/dist/cjs/src/dream/internal/destroyDream.js +25 -14
  15. package/dist/cjs/src/dream/internal/saveDream.js +9 -0
  16. package/dist/cjs/src/dream/internal/undestroyDream.js +55 -32
  17. package/dist/cjs/src/dream/internal/withConcurrentWriterRetry.js +64 -0
  18. package/dist/cjs/src/errors/CannotSaveMissingDream.js +24 -0
  19. package/dist/cjs/src/errors/SortableBatchRequiresTooManyScopeLocks.js +7 -0
  20. package/dist/cjs/src/errors/associations/MissingRequiredBelongsToAssociation.js +8 -3
  21. package/dist/cjs/src/package-exports/errors.js +10 -1
  22. package/dist/esm/src/Dream.js +9 -5
  23. package/dist/esm/src/db/errors.js +2 -0
  24. package/dist/esm/src/decorators/Decorators.js +121 -6
  25. package/dist/esm/src/decorators/field/sortable/Sortable.js +4 -31
  26. package/dist/esm/src/decorators/field/sortable/helpers/cascadeReachesEveryRowInSortScope.js +51 -0
  27. package/dist/esm/src/decorators/field/sortable/helpers/performSortableDestroyWork.js +5 -2
  28. package/dist/esm/src/decorators/field/sortable/helpers/prepareSortableFieldsForDestroy.js +39 -25
  29. package/dist/esm/src/decorators/field/sortable/helpers/sortableCascadeEdge.js +32 -0
  30. package/dist/esm/src/dream/Query.js +37 -13
  31. package/dist/esm/src/dream/QueryDriver/Base.js +26 -0
  32. package/dist/esm/src/dream/QueryDriver/Kysely.js +4 -1
  33. package/dist/esm/src/dream/QueryDriver/Postgres.js +7 -1
  34. package/dist/esm/src/dream/internal/destroyAssociatedRecords.js +7 -0
  35. package/dist/esm/src/dream/internal/destroyDream.js +25 -14
  36. package/dist/esm/src/dream/internal/saveDream.js +9 -0
  37. package/dist/esm/src/dream/internal/undestroyDream.js +55 -32
  38. package/dist/esm/src/dream/internal/withConcurrentWriterRetry.js +64 -0
  39. package/dist/esm/src/errors/CannotSaveMissingDream.js +24 -0
  40. package/dist/esm/src/errors/SortableBatchRequiresTooManyScopeLocks.js +7 -0
  41. package/dist/esm/src/errors/associations/MissingRequiredBelongsToAssociation.js +8 -3
  42. package/dist/esm/src/package-exports/errors.js +10 -1
  43. package/dist/types/src/Dream.d.ts +9 -5
  44. package/dist/types/src/db/errors.d.ts +2 -0
  45. package/dist/types/src/decorators/Decorators.d.ts +121 -6
  46. package/dist/types/src/decorators/field/sortable/Sortable.d.ts +4 -31
  47. package/dist/types/src/decorators/field/sortable/helpers/cascadeReachesEveryRowInSortScope.d.ts +39 -0
  48. package/dist/types/src/decorators/field/sortable/helpers/performSortableDestroyWork.d.ts +6 -1
  49. package/dist/types/src/decorators/field/sortable/helpers/prepareSortableFieldsForDestroy.d.ts +37 -20
  50. package/dist/types/src/decorators/field/sortable/helpers/sortableCascadeEdge.d.ts +20 -0
  51. package/dist/types/src/dream/Query.d.ts +37 -13
  52. package/dist/types/src/dream/QueryDriver/Base.d.ts +20 -0
  53. package/dist/types/src/dream/QueryDriver/Postgres.d.ts +2 -0
  54. package/dist/types/src/dream/internal/destroyDream.d.ts +3 -1
  55. package/dist/types/src/dream/internal/undestroyDream.d.ts +6 -4
  56. package/dist/types/src/dream/internal/withConcurrentWriterRetry.d.ts +47 -0
  57. package/dist/types/src/errors/CannotSaveMissingDream.d.ts +23 -0
  58. package/dist/types/src/errors/SortableBatchRequiresTooManyScopeLocks.d.ts +7 -0
  59. package/dist/types/src/errors/associations/MissingRequiredBelongsToAssociation.d.ts +1 -0
  60. package/dist/types/src/package-exports/errors.d.ts +1 -1
  61. package/docs/assets/hierarchy.js +1 -1
  62. package/docs/assets/navigation.js +1 -1
  63. package/docs/assets/search.js +1 -1
  64. package/docs/classes/db.DreamMigrationHelpers.html +11 -11
  65. package/docs/classes/db.KyselyQueryDriver.html +55 -43
  66. package/docs/classes/db.PostgresQueryDriver.html +56 -44
  67. package/docs/classes/db.QueryDriverBase.html +54 -42
  68. package/docs/classes/errors.CannotSaveMissingDream.html +47 -0
  69. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  70. package/docs/classes/errors.ColumnOverflow.html +3 -3
  71. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  72. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  73. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  74. package/docs/classes/errors.DecryptionError.html +2 -2
  75. package/docs/classes/errors.DecryptionParseError.html +2 -2
  76. package/docs/classes/errors.DecryptionRotationError.html +3 -3
  77. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  78. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  79. package/docs/classes/errors.InvalidClockTime.html +2 -2
  80. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  81. package/docs/classes/errors.InvalidDateTime.html +2 -2
  82. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  83. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  84. package/docs/classes/errors.NotNullViolation.html +3 -3
  85. package/docs/classes/errors.RecordNotFound.html +3 -3
  86. package/docs/classes/errors.SortableScopeDidNotStabilize.html +3 -3
  87. package/docs/classes/errors.SortableScopeLockWaitTimedOut.html +3 -3
  88. package/docs/classes/errors.ValidationError.html +3 -3
  89. package/docs/classes/index.CalendarDate.html +33 -33
  90. package/docs/classes/index.ClockTime.html +32 -32
  91. package/docs/classes/index.ClockTimeTz.html +35 -35
  92. package/docs/classes/index.DateTime.html +86 -86
  93. package/docs/classes/index.Decorators.html +101 -22
  94. package/docs/classes/index.Dream.html +133 -129
  95. package/docs/classes/index.DreamApp.html +10 -10
  96. package/docs/classes/index.DreamTransaction.html +2 -2
  97. package/docs/classes/index.Env.html +2 -2
  98. package/docs/classes/index.Query.html +88 -67
  99. package/docs/classes/system.CliFileWriter.html +4 -4
  100. package/docs/classes/system.DreamBin.html +2 -2
  101. package/docs/classes/system.DreamCLI.html +7 -7
  102. package/docs/classes/system.DreamImporter.html +2 -2
  103. package/docs/classes/system.DreamLogos.html +2 -2
  104. package/docs/classes/system.DreamSerializerBuilder.html +11 -11
  105. package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
  106. package/docs/classes/system.PathHelpers.html +3 -3
  107. package/docs/classes/utils.Encrypt.html +3 -3
  108. package/docs/classes/utils.Range.html +2 -2
  109. package/docs/functions/db.closeAllDbConnections.html +1 -1
  110. package/docs/functions/db.dreamDbConnections.html +1 -1
  111. package/docs/functions/db.untypedDb.html +1 -1
  112. package/docs/functions/db.validateColumn.html +1 -1
  113. package/docs/functions/db.validateTable.html +1 -1
  114. package/docs/functions/errors.pgErrorType.html +1 -1
  115. package/docs/functions/index.DreamSerializer.html +1 -1
  116. package/docs/functions/index.ObjectSerializer.html +1 -1
  117. package/docs/functions/index.ReplicaSafe.html +1 -1
  118. package/docs/functions/index.STI.html +1 -1
  119. package/docs/functions/index.SoftDelete.html +1 -1
  120. package/docs/functions/utils.camelize.html +1 -1
  121. package/docs/functions/utils.capitalize.html +1 -1
  122. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  123. package/docs/functions/utils.compact.html +1 -1
  124. package/docs/functions/utils.groupBy.html +1 -1
  125. package/docs/functions/utils.hyphenize.html +1 -1
  126. package/docs/functions/utils.intersection.html +1 -1
  127. package/docs/functions/utils.isEmpty.html +1 -1
  128. package/docs/functions/utils.normalizeUnicode.html +1 -1
  129. package/docs/functions/utils.pascalize.html +1 -1
  130. package/docs/functions/utils.percent.html +1 -1
  131. package/docs/functions/utils.range.html +1 -1
  132. package/docs/functions/utils.round.html +1 -1
  133. package/docs/functions/utils.sanitizeString.html +1 -1
  134. package/docs/functions/utils.snakeify.html +1 -1
  135. package/docs/functions/utils.sort.html +1 -1
  136. package/docs/functions/utils.sortBy.html +1 -1
  137. package/docs/functions/utils.sortObjectByKey.html +1 -1
  138. package/docs/functions/utils.sortObjectByValue.html +1 -1
  139. package/docs/functions/utils.uncapitalize.html +1 -1
  140. package/docs/functions/utils.uniq.html +1 -1
  141. package/docs/hierarchy.html +1 -1
  142. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  143. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  144. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  145. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  146. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  147. package/docs/interfaces/types.DecoratorContext.html +2 -2
  148. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  149. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  150. package/docs/interfaces/types.DreamDbConfig.html +5 -5
  151. package/docs/interfaces/types.DurationObject.html +2 -2
  152. package/docs/interfaces/types.EncryptOptions.html +2 -2
  153. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  154. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  155. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  156. package/docs/modules/errors.html +1 -1
  157. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  158. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  159. package/docs/types/openapi.OpenapiFormats.html +1 -1
  160. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  161. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  162. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  163. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  164. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  165. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  166. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  167. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  168. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  169. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
  170. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
  171. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
  172. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  173. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  174. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  175. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  176. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  177. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  178. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  179. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  180. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  181. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  182. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  183. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  184. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  185. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  186. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  187. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  188. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
  189. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
  190. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
  191. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  192. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  193. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  194. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  195. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  196. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  197. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  198. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  199. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  200. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  201. package/docs/types/types.CalendarDateObject.html +1 -1
  202. package/docs/types/types.Camelized.html +1 -1
  203. package/docs/types/types.ClockTimeObject.html +1 -1
  204. package/docs/types/types.DbConnectionType.html +1 -1
  205. package/docs/types/types.DbTypes.html +1 -1
  206. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  207. package/docs/types/types.DreamAttributes.html +1 -1
  208. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  209. package/docs/types/types.DreamClassColumn.html +1 -1
  210. package/docs/types/types.DreamColumn.html +1 -1
  211. package/docs/types/types.DreamColumnNames.html +1 -1
  212. package/docs/types/types.DreamLogLevel.html +1 -1
  213. package/docs/types/types.DreamLogger.html +2 -2
  214. package/docs/types/types.DreamModelSerializerType.html +1 -1
  215. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  216. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  217. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  218. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  219. package/docs/types/types.DreamSerializable.html +1 -1
  220. package/docs/types/types.DreamSerializableArray.html +1 -1
  221. package/docs/types/types.DreamSerializerKey.html +1 -1
  222. package/docs/types/types.DreamSerializers.html +1 -1
  223. package/docs/types/types.DreamVirtualColumns.html +1 -1
  224. package/docs/types/types.DurationUnit.html +1 -1
  225. package/docs/types/types.EncryptAlgorithm.html +1 -1
  226. package/docs/types/types.HasManyStatement.html +1 -1
  227. package/docs/types/types.HasOneStatement.html +1 -1
  228. package/docs/types/types.Hyphenized.html +1 -1
  229. package/docs/types/types.Pascalized.html +1 -1
  230. package/docs/types/types.PrimaryKeyType.html +1 -1
  231. package/docs/types/types.RoundingPrecision.html +1 -1
  232. package/docs/types/types.SerializerCasing.html +1 -1
  233. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  234. package/docs/types/types.Snakeified.html +1 -1
  235. package/docs/types/types.StrictInterface.html +1 -1
  236. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  237. package/docs/types/types.UpdateableProperties.html +1 -1
  238. package/docs/types/types.ValidationType.html +1 -1
  239. package/docs/types/types.ViewModel.html +2 -2
  240. package/docs/types/types.ViewModelClass.html +1 -1
  241. package/docs/types/types.WeekdayName.html +1 -1
  242. package/docs/types/types.WhereStatementForDream.html +1 -1
  243. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  244. package/docs/variables/index.DreamConst.html +1 -1
  245. package/docs/variables/index.ops.html +1 -1
  246. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  247. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  248. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  249. package/docs/variables/system.primaryKeyTypes.html +1 -1
  250. package/package.json +2 -2
  251. package/docs/classes/errors.SortableBatchRequiresTooManyScopeLocks.html +0 -61
@@ -1,33 +1,50 @@
1
1
  import Dream from '../../../../Dream.js';
2
2
  import DreamTransaction from '../../../../dream/DreamTransaction.js';
3
+ import { SortableFieldConfig } from '../Sortable.js';
4
+ import { SortableCascadeEdge } from './sortableCascadeEdge.js';
5
+ export interface SortableDestroyPreparation {
6
+ /**
7
+ * False when the snapshot read found no row: this destroy has nothing to
8
+ * vacate, and compacting from the instance's remembered position would shift
9
+ * a scope some other writer has already closed. The delete's own affected-row
10
+ * count is the stronger signal (a writer outside the sortable path can remove
11
+ * the row after this read), so the caller checks both.
12
+ */
13
+ rowExists: boolean;
14
+ /**
15
+ * The sortable fields whose scope this destroy compacts, for
16
+ * `performSortableDestroyWork`.
17
+ */
18
+ sortableFields: SortableFieldConfig[];
19
+ }
3
20
  /**
4
21
  * @internal
5
22
  *
6
23
  * The sortable preparation phase of a destroy. Called from `destroyDream` after
7
24
  * every user `beforeDestroy` hook has run and before the delete — a phase, not
8
- * a hook among them — so the operation's whole advisory key set, across every
9
- * sortable field, is taken in one sorted stabilized acquisition, with one
10
- * snapshot SELECT covering all fields. Per-field acquisition would take
11
- * multi-field keys in declaration order, which deadlocks against the paths
12
- * that acquire sorted.
25
+ * a hook among them — so the row's real position and scope values are read in
26
+ * one snapshot SELECT covering every field while the row still exists.
27
+ * Pre-delete is the only seat for that read: on a hard destroy the row is gone
28
+ * afterwards, and a soft destroy nulls the position columns in the same UPDATE
29
+ * as `deletedAt`. The per-field compactions (`performSortableDestroyWork`)
30
+ * consume the cached snapshots.
13
31
  *
14
- * Pre-delete is the only seat available for the snapshot read: on a hard
15
- * destroy the row is gone afterwards, and a soft destroy nulls the position
16
- * columns in the same UPDATE as `deletedAt`. The lock is taken around the read
17
- * so the snapshot cannot be invalidated between the read and the compaction;
18
- * it is transaction-scoped, and `destroyDream` opens a transaction that spans
19
- * the delete and the after-destroy hooks, so one acquisition covers both.
32
+ * A direct destroy takes the operation's whole advisory key set — every
33
+ * sortable field — in one sorted stabilized acquisition around that read, so
34
+ * the snapshot cannot be invalidated before the compaction; per-field
35
+ * acquisition would take multi-field keys in declaration order and deadlock
36
+ * against the paths that acquire sorted. The lock is transaction-scoped, and
37
+ * `destroyDream` opens a transaction spanning the delete and the after-destroy
38
+ * hooks, so one acquisition covers both.
20
39
  *
21
- * The per-field compactions (`performSortableDestroyWork`) consume the cached
22
- * snapshots.
23
- *
24
- * @returns false when the snapshot read found no row — this destroy has nothing
25
- * to vacate, and compacting from the instance's remembered position would
26
- * shift a scope some other writer has already closed. The delete's own
27
- * affected-row count is the stronger signal (a writer outside the sortable
28
- * path can remove the row after this read), so the caller checks both.
40
+ * A cascaded destroy — one reached through a `dependent: 'destroy'` association,
41
+ * which passes the edge it arrived by — takes no scope lock: a cascade would
42
+ * otherwise hold one per distinct sort scope it touches until the root
43
+ * transaction commits. It reads the same snapshot unlocked and compacts from
44
+ * it, and skips both for a field whose whole sort scope the cascade is
45
+ * destroying, since nothing survives there to observe a compaction.
29
46
  */
30
- export default function prepareSortableFieldsForDestroy(dream: Dream, txn: DreamTransaction<any>): Promise<boolean>;
47
+ export default function prepareSortableFieldsForDestroy(dream: Dream, txn: DreamTransaction<any>, cascadeEdge: SortableCascadeEdge | null): Promise<SortableDestroyPreparation>;
31
48
  /**
32
49
  * @internal
33
50
  *
@@ -0,0 +1,20 @@
1
+ import Dream from '../../../../Dream.js';
2
+ import { HasStatement } from '../../../../types/associations/shared.js';
3
+ export type SortableCascadeEdge = HasStatement<any, any, any, any, 'HasOne' | 'HasMany'>;
4
+ /**
5
+ * @internal
6
+ *
7
+ * Marks a record a `dependent: 'destroy'` cascade is about to destroy or
8
+ * undestroy, with the association the cascade reached it through. The record's
9
+ * own destroy or undestroy consumes the mark and does its sortable work without
10
+ * the scope lock a direct operation takes.
11
+ */
12
+ export declare function markSortableCascadeEdge(dream: Dream, association: SortableCascadeEdge): void;
13
+ /**
14
+ * @internal
15
+ *
16
+ * The association a cascade reached this record through, or null on a direct
17
+ * destroy or undestroy. Consuming removes the mark, so a later direct operation
18
+ * on the same instance cannot inherit a cascade's optimism.
19
+ */
20
+ export declare function consumeSortableCascadeEdge(dream: Dream): SortableCascadeEdge | null;
@@ -1356,13 +1356,15 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1356
1356
  * {@link Query.delete | delete} (a single statement, no hooks or cascade)
1357
1357
  * are the right tools for bulk removal.
1358
1358
  *
1359
+ * To bypass a default scope, chain `removeDefaultScope` onto the Query
1360
+ * before calling this method; it is Query state, not an option, and it
1361
+ * carries through to the cascade.
1362
+ *
1359
1363
  * @param options - Options for destroying the instance
1360
1364
  * @param options.skipHooks - If true, skips applying model hooks during the destroy operation. Defaults to false
1361
1365
  * @param options.cascade - If false, skips destroying associations marked `dependent: 'destroy'`. Defaults to true
1362
1366
  * @param options.lock - If true, each batch is re-selected with an exclusive row lock inside its own transaction before being destroyed, making the destroy a compare-and-set. Defaults to false
1363
1367
  * @param options.batchSize - The number of records to process per batch. Must be a positive integer. Defaults to 10 when `lock` is true, and to 1000 otherwise
1364
- * @param options.bypassAllDefaultScopes - If true, bypasses user-removable default scopes when cascade destroying; an STI child's reserved discriminator remains enforced, including when associations are loaded. Defaults to false
1365
- * @param options.defaultScopesToBypass - An array of default scope names to bypass when cascade destroying. Defaults to an empty array
1366
1368
  * @returns The number of records that were removed
1367
1369
  * @throws InvalidBatchSize if `batchSize` is not a positive integer
1368
1370
  * @throws BatchingIncompatibleWithLimitOrOffset if the query carries a `limit` or `offset`
@@ -1433,11 +1435,12 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1433
1435
  * transaction ends, so every batch's scope keys are still held when the
1434
1436
  * next one preflights. That accumulation is bounded — the preflight counts
1435
1437
  * the keys the transaction already holds along with the ones the batch
1436
- * would add, and refuses with `SortableBatchRequiresTooManyScopeLocks`
1437
- * rather than letting a long run over a high-cardinality sort scope exhaust
1438
- * `max_locks_per_transaction` for the whole cluster — so a run long enough
1439
- * raises instead of completing. Letting Dream open a transaction per batch
1440
- * releases the keys as it goes and gives each batch the whole budget.
1438
+ * would add, and raises rather than letting a long run over a
1439
+ * high-cardinality sort scope exhaust `max_locks_per_transaction` for the
1440
+ * whole cluster — so a run long enough raises instead of completing. That
1441
+ * refusal is a sizing failure to fix, not a condition to catch: letting
1442
+ * Dream open a transaction per batch releases the keys as it goes and gives
1443
+ * each batch the whole budget, and a smaller `batchSize` takes fewer.
1441
1444
  * - the preflight covers **the claimed rows' own scopes only**. A
1442
1445
  * `dependent: 'destroy'` cascade under `destroy({ lock: true })` destroys
1443
1446
  * child records of other tables, and a sortable child takes its own table's
@@ -1454,8 +1457,18 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1454
1457
  private lockedBatches;
1455
1458
  /**
1456
1459
  * Destroys all records matching the Query,
1457
- * ignoring the SoftDelete decorator and
1458
- * permanently removing records from the database.
1460
+ * permanently removing each matched record from
1461
+ * the database instead of soft deleting it.
1462
+ *
1463
+ * The SoftDelete decorator is bypassed when
1464
+ * deleting each matched record, not when
1465
+ * matching: the Query selects under its default
1466
+ * scopes, `dream:SoftDelete` among them, so on a
1467
+ * SoftDelete model it matches only records that
1468
+ * have not already been soft deleted. Reaching
1469
+ * soft deleted records takes
1470
+ * `removeDefaultScope('dream:SoftDelete')` on
1471
+ * the Query.
1459
1472
  *
1460
1473
  * Calls model hooks and applies cascade destroy
1461
1474
  * to associations with `dependent: 'destroy'`,
@@ -1470,17 +1483,26 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1470
1483
  * // 12
1471
1484
  * ```
1472
1485
  *
1486
+ * ```ts
1487
+ * await User.removeDefaultScope('dream:SoftDelete')
1488
+ * .where({ email: ops.ilike('%burpcollaborator%') })
1489
+ * .reallyDestroy()
1490
+ * // 12
1491
+ * ```
1492
+ *
1473
1493
  * A `limit` or `offset` on the Query is incompatible with `reallyDestroy`,
1474
1494
  * exactly as it is with {@link Query.destroy}: a limit- or offset-carrying
1475
1495
  * Query throws at runtime.
1476
1496
  *
1497
+ * To bypass a default scope, chain `removeDefaultScope` onto the Query
1498
+ * before calling this method; it is Query state, not an option, and it
1499
+ * carries through to the cascade.
1500
+ *
1477
1501
  * @param options - Options for destroying the instance
1478
1502
  * @param options.skipHooks - If true, skips applying model hooks during the destroy operation. Defaults to false
1479
1503
  * @param options.cascade - If false, skips destroying associations marked `dependent: 'destroy'`. Defaults to true
1480
1504
  * @param options.lock - If true, each batch is re-selected with an exclusive row lock inside its own transaction before being destroyed, making the destroy a compare-and-set. See {@link Query.destroy} for the full semantics. Defaults to false
1481
1505
  * @param options.batchSize - The number of records to process per batch. Must be a positive integer. Defaults to 10 when `lock` is true, and to 1000 otherwise
1482
- * @param options.bypassAllDefaultScopes - If true, bypasses user-removable default scopes when cascade destroying; an STI child's reserved discriminator remains enforced, including when associations are loaded. Defaults to false
1483
- * @param options.defaultScopesToBypass - An array of default scope names to bypass when cascade destroying. Defaults to an empty array
1484
1506
  * @returns The number of records that were removed
1485
1507
  * @throws InvalidBatchSize if `batchSize` is not a positive integer
1486
1508
  * @throws BatchingIncompatibleWithLimitOrOffset if the query carries a `limit` or `offset`
@@ -1509,11 +1531,13 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1509
1531
  * re-applied to every window — so a limit- or offset-carrying Query throws
1510
1532
  * at runtime.
1511
1533
  *
1534
+ * To bypass a default scope, chain `removeDefaultScope` onto the Query
1535
+ * before calling this method; it is Query state, not an option, and it
1536
+ * carries through to the cascade. The SoftDelete scope is always bypassed.
1537
+ *
1512
1538
  * @param options - Options for undestroying the instance
1513
1539
  * @param options.skipHooks - If true, skips applying model hooks during the undestroy operation. Defaults to false
1514
1540
  * @param options.cascade - If false, skips undestroying associations marked `dependent: 'destroy'`. Defaults to true
1515
- * @param options.bypassAllDefaultScopes - If true, bypasses user-removable default scopes when cascade undestroying; an STI child's reserved discriminator remains enforced, including when associations are loaded. Defaults to false
1516
- * @param options.defaultScopesToBypass - An array of default scope names to bypass when cascade undestroying (soft delete is always bypassed). Defaults to an empty array
1517
1541
  * @returns The number of records that were removed
1518
1542
  * @throws BatchingIncompatibleWithLimitOrOffset if the query carries a `limit` or `offset`
1519
1543
  */
@@ -162,6 +162,26 @@ export default class QueryDriverBase<DreamInstance extends Dream> {
162
162
  * than silently racing on position values.
163
163
  */
164
164
  static supportsAdvisoryTransactionLocks: boolean;
165
+ /**
166
+ * @internal
167
+ *
168
+ * Whether `error` is the database refusing a write for violating a unique
169
+ * constraint. `withConcurrentWriterRetry` asks this of an error raised at
170
+ * COMMIT, which is where a `DEFERRABLE INITIALLY DEFERRED` constraint — the
171
+ * one `DreamMigrationHelpers.addDeferrableUniqueConstraint` declares — reports
172
+ * a collision. A driver that does not recognize one reports false, and nothing
173
+ * is retried.
174
+ */
175
+ static isUniqueConstraintViolation(error: unknown): boolean;
176
+ /**
177
+ * @internal
178
+ *
179
+ * Whether `error` is the database aborting a transaction to break a deadlock
180
+ * with another. `withConcurrentWriterRetry` reruns a transaction of Dream's
181
+ * own that was aborted this way. A driver that does not recognize one reports
182
+ * false, and nothing is retried.
183
+ */
184
+ static isDeadlock(error: unknown): boolean;
165
185
  /**
166
186
  * @internal
167
187
  *
@@ -56,6 +56,8 @@ export default class PostgresQueryDriver<DreamInstance extends Dream> extends Ky
56
56
  */
57
57
  applyRowLock(kyselyQuery: SelectQueryBuilder<any, any, any>, tableAlias: string): SelectQueryBuilder<any, any, any>;
58
58
  static supportsAdvisoryTransactionLocks: boolean;
59
+ static isUniqueConstraintViolation(error: unknown): boolean;
60
+ static isDeadlock(error: unknown): boolean;
59
61
  /**
60
62
  * @internal
61
63
  *
@@ -10,7 +10,9 @@ export interface ReallyDestroyOptions<DreamInstance extends Dream> extends Destr
10
10
  *
11
11
  * Destroys the Dream and any `dependent: 'destroy'` associations
12
12
  * within a transaction. If a transaction is passed, it will be used.
13
- * Otherwise, a new transaction will be created automatically.
13
+ * Otherwise, a new transaction will be created automatically, and the
14
+ * whole destroy is run again if that transaction is undone by a concurrent
15
+ * writer (see `withConcurrentWriterRetry`).
14
16
  * If any of the nested associations fails to destroy, then this
15
17
  * record will also fail to destroy. If skipHooks is true, model hooks
16
18
  * will be bypassed.
@@ -5,11 +5,13 @@ type UndestroyOptions<DreamInstance extends Dream> = Required<OptionalDestroyOpt
5
5
  /**
6
6
  * @internal
7
7
  *
8
- * Destroys the Dream and any `dependent: 'destroy'` associations
8
+ * Undestroys the Dream and any `dependent: 'destroy'` associations
9
9
  * within a transaction. If a transaction is passed, it will be used.
10
- * Otherwise, a new transaction will be created automatically.
11
- * If any of the nested associations fails to destroy, then this
12
- * record will also fail to destroy. If skipHooks is true, model hooks
10
+ * Otherwise, a new transaction will be created automatically, and the
11
+ * whole undestroy is run again if that transaction is undone by a
12
+ * concurrent writer (see `withConcurrentWriterRetry`).
13
+ * If any of the nested associations fails to undestroy, then this
14
+ * record will also fail to undestroy. If skipHooks is true, model hooks
13
15
  * will be bypassed.
14
16
  */
15
17
  export default function undestroyDream<I extends Dream>(dream: I, txn: (DreamTransaction<I> | null) | undefined, options: UndestroyOptions<I>): Promise<I>;
@@ -0,0 +1,47 @@
1
+ import Dream from '../../Dream.js';
2
+ import DreamTransaction from '../DreamTransaction.js';
3
+ /**
4
+ * How many times a destroy or undestroy that opened its own transaction runs
5
+ * before a failure caused by a concurrent writer escapes. One such failure
6
+ * needs another writer of the same rows or sort scope during the operation;
7
+ * three in a row is contention past the point of retrying.
8
+ */
9
+ export declare const MAX_CONCURRENT_WRITER_ATTEMPTS = 3;
10
+ /**
11
+ * @internal
12
+ *
13
+ * Runs `callback` in a transaction of the model's own, and runs it again when
14
+ * that transaction is undone by a concurrent writer: a deadlock, or a unique
15
+ * constraint refusing the COMMIT.
16
+ *
17
+ * A cascaded destroy or undestroy does its sortable position work without the
18
+ * scope lock a direct one takes (see `@deco.Sortable`), so a concurrent writer
19
+ * of the same sort scope can leave two live rows sharing a position, which the
20
+ * scope's deferrable unique constraint refuses at COMMIT — or, when both
21
+ * writers reach COMMIT together, as a deadlock between their two checks. A
22
+ * cascade holding row locks can deadlock against another writer of the same
23
+ * rows mid-statement as well. Either way the database has undone the whole
24
+ * transaction, nothing has committed and no commit hook has run, so running
25
+ * the operation again reads the rows as the other writer left them. The last
26
+ * attempt's error is the adapter's own.
27
+ *
28
+ * A unique violation raised by a statement inside the callback is not a
29
+ * collision but a write that violates a constraint outright, and is not
30
+ * retried; only a refusal of the COMMIT itself is, which is why the callback
31
+ * having resolved is part of the test.
32
+ *
33
+ * Only a transaction Dream opens is retried. Inside a caller's transaction the
34
+ * failure is the caller's, and the caller retries the whole transaction.
35
+ *
36
+ * Saves are deliberately not run through this. When a direct save and a
37
+ * cascade collide, the loser is whichever transaction waits first at COMMIT,
38
+ * and that is usually the save, which is short and reaches COMMIT while the
39
+ * cascade is still working: it fails with the adapter's deadlock error after
40
+ * `deadlock_timeout`. That bounded, occasional failure is the accepted price of
41
+ * cascades holding no scope locks, and the save path's state restore
42
+ * (`saveDream`) already makes calling `save` again correct. The collision needs
43
+ * a position write into the same sort scope inside the cascade's window that
44
+ * picks the same position, which a cascade destroying a scope's owner never
45
+ * exposes since it writes no position at all.
46
+ */
47
+ export default function withConcurrentWriterRetry<R>(dreamClass: typeof Dream, callback: (txn: DreamTransaction<any>) => Promise<R>): Promise<R>;
@@ -0,0 +1,23 @@
1
+ import Dream from '../Dream.js';
2
+ /**
3
+ * Raised when saving a persisted instance whose database row no longer exists —
4
+ * the row was deleted between the moment the instance was loaded and the moment
5
+ * the save reached the database.
6
+ *
7
+ * This is the write-side counterpart of `RecordNotFound`, and applications catch
8
+ * it for the same reasons: a request updating a record another request has since
9
+ * deleted should answer 404 or 409 rather than 500, and a background job holding
10
+ * a stale instance should usually drop the work rather than fail loudly. Nothing
11
+ * is written when it is raised.
12
+ *
13
+ * It does not mean the save was rejected — a save that fails validation raises
14
+ * `ValidationError`, and a constraint violation raises its own error. It means
15
+ * the row that the instance stands for is gone.
16
+ *
17
+ * Dream raises it from the query driver, so a custom driver overriding
18
+ * `saveDream` translates its own adapter's empty-result error the same way, as
19
+ * the test-app MySQL driver does.
20
+ */
21
+ export default class CannotSaveMissingDream extends Error {
22
+ constructor(dream: Dream);
23
+ }
@@ -1,4 +1,6 @@
1
1
  /**
2
+ * @internal
3
+ *
2
4
  * Raised when a batch of a locked `Query#destroy` or `Query#update` on a
3
5
  * sortable model would carry its transaction past the number of advisory
4
6
  * sort-scope locks Dream is willing to hold at once.
@@ -27,6 +29,11 @@
27
29
  * — a long multi-batch run inside a transaction you opened — either let Dream
28
30
  * open a transaction per batch (do not pass a transaction of your own) or
29
31
  * commit between runs, which is what releases the locks as it goes.
32
+ *
33
+ * Not exported from `@rvoh/dream/errors`. Exceeding the bound is a sizing
34
+ * mistake in the calling code, not a runtime condition an application can
35
+ * recover from, so there is nothing for a consumer to catch: the fix is a
36
+ * smaller batch or a narrower transaction, never a retry.
30
37
  */
31
38
  export default class SortableBatchRequiresTooManyScopeLocks extends Error {
32
39
  dreamClassName: string;
@@ -44,6 +44,7 @@ export default class MissingRequiredBelongsToAssociation extends Error {
44
44
  polymorphic: boolean;
45
45
  });
46
46
  get message(): string;
47
+ private get populatedForeignKeyDiagnosticMessage();
47
48
  private get foreignKeyMessage();
48
49
  private formatValue;
49
50
  }
@@ -1,5 +1,6 @@
1
1
  export { pgErrorType } from '../db/errors.js';
2
2
  export { default as NonLoadedAssociation } from '../errors/associations/NonLoadedAssociation.js';
3
+ export { default as CannotSaveMissingDream } from '../errors/CannotSaveMissingDream.js';
3
4
  export { default as CreateOrFindByFailedToCreateAndFind } from '../errors/CreateOrFindByFailedToCreateAndFind.js';
4
5
  export { default as CheckConstraintViolation } from '../errors/db/CheckConstraintViolation.js';
5
6
  export { default as ColumnOverflow } from '../errors/db/ColumnOverflow.js';
@@ -12,7 +13,6 @@ export { default as DecryptionParseError } from '../errors/encrypt/DecryptionPar
12
13
  export { default as DecryptionRotationError } from '../errors/encrypt/DecryptionRotationError.js';
13
14
  export { default as RecordNotFound } from '../errors/RecordNotFound.js';
14
15
  export { default as MissingSerializersDefinition } from '../errors/serializers/MissingSerializersDefinition.js';
15
- export { default as SortableBatchRequiresTooManyScopeLocks } from '../errors/SortableBatchRequiresTooManyScopeLocks.js';
16
16
  export { default as SortableScopeDidNotStabilize } from '../errors/SortableScopeDidNotStabilize.js';
17
17
  export { default as SortableScopeLockWaitTimedOut } from '../errors/SortableScopeLockWaitTimedOut.js';
18
18
  export { default as ValidationError } from '../errors/ValidationError.js';
@@ -1 +1 @@
1
- window.hierarchyData = "eJyVkkFPwjAUx7/LOxekY3SsRyEmxoiaGD0QDmV7uIauJW2HWQjf3VQuFdGNU5vm/fv79fUdwBrjHfAlZaOMUEpXBCxuFBZeGu2AH4BSGhYtagQOLw3adm7lHu2tcAgEtlKXwGkyJdBYBRwKJZxDd1Ouh2fVw8rXCsipAjh4Vw5CfHA6IFBUUpUWNfBlko9XRwJJPo7oD61D1Ua3dvB/1V9jQMeUBYWwRg7PxvkPi66/xYVEh0egTrK477MKi+3MaOetkNq/SaNE+KL/0GitsW74V7SPwzSPHYxqav20R7tR5rMP+UegB4+Nsog3F17c68LUO+HlWuG79FU4WwuHdxJV2UOh846rJmKSURKaQihLGKEsTb8HhCXsTPu13eHp9WH3KF0tfFH19L0c7tO+NI08FsYvGqWuGZXzSBfzePwC4ktvDw=="
1
+ window.hierarchyData = "eJyVk0FPwyAUx7/LO+McuLCVo1tMjHFqYvSw7MDaN0tGYQE60yz77gZ3wTktO0HJ+/P7Aa97cNYGD2JB+YgRSumSgMO1xjIoazyIPVBK42BkgyDgpUXXzZzaobuVHoHARpkKBGUTAq3TIKDU0nv019VqcFI9qEOjgRwrQEDw1VWMXx0XCJS10pVDA2LBimJ5IMCKIqE/dB51l+zaw/9Vf4kBvWGTqBDHxOHZ+vDh0OdbnEn0eEQqH/KEOq2x3Eyt8cFJZcKbslrGJ/oPjc5Z5wd/RXMc2Ch1sLptzNMO3Vrbzxzyj0AOb8QS3kwGeW9K22xlUCuN7yrUcW0lPd4p1FWGQu8eF3UEH3ISL4VQzimhfPzdo/HjRPu12+Lx9HH2qHwjQ1ln+p4P51zfOP1Z5jbMW60vaZXTSB/zcPgCAPBvFw=="
@@ -1 +1 @@
1
- window.navigationData = "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"
1
+ window.navigationData = "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"