@rvoh/dream 2.27.0 → 2.28.1

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 (330) hide show
  1. package/dist/cjs/src/Dream.js +63 -1
  2. package/dist/cjs/src/db/errors.js +4 -0
  3. package/dist/cjs/src/decorators/field/Encrypted.js +12 -0
  4. package/dist/cjs/src/decorators/field/sortable/Sortable.js +43 -118
  5. package/dist/cjs/src/decorators/field/sortable/helpers/acquireSortableScopeLocks.js +38 -0
  6. package/dist/cjs/src/decorators/field/sortable/helpers/acquireStabilizedSortableBatchLocks.js +183 -0
  7. package/dist/cjs/src/decorators/field/sortable/helpers/acquireStabilizedSortableScopeLocks.js +40 -0
  8. package/dist/cjs/src/decorators/field/sortable/helpers/canonicalScopeValue.js +194 -0
  9. package/dist/cjs/src/decorators/field/sortable/helpers/clearCachedSortableValues.js +18 -0
  10. package/dist/cjs/src/decorators/field/sortable/helpers/decrementScopedRecordsGreaterThanPosition.js +9 -9
  11. package/dist/cjs/src/decorators/field/sortable/helpers/filterQueryToInstanceScope.js +20 -0
  12. package/dist/cjs/src/decorators/field/sortable/helpers/filterQueryToScopeValues.js +32 -0
  13. package/dist/cjs/src/decorators/field/sortable/helpers/heldSortableScopeLockKeys.js +34 -0
  14. package/dist/cjs/src/decorators/field/sortable/helpers/performSortableDestroyWork.js +21 -0
  15. package/dist/cjs/src/decorators/field/sortable/helpers/performSortablePositionWork.js +36 -0
  16. package/dist/cjs/src/decorators/field/sortable/helpers/prepareSortableFieldsForDestroy.js +56 -0
  17. package/dist/cjs/src/decorators/field/sortable/helpers/prepareSortableFieldsForSave.js +84 -0
  18. package/dist/cjs/src/decorators/field/sortable/helpers/resortAllRecords.js +186 -29
  19. package/dist/cjs/src/decorators/field/sortable/helpers/setPosition.js +90 -46
  20. package/dist/cjs/src/decorators/field/sortable/helpers/sortableRowCache.js +73 -0
  21. package/dist/cjs/src/decorators/field/sortable/helpers/sortableScopeColumns.js +42 -0
  22. package/dist/cjs/src/decorators/field/sortable/helpers/sortableScopeLockKey.js +99 -0
  23. package/dist/cjs/src/decorators/field/sortable/helpers/sortableScopeLockKeys.js +72 -0
  24. package/dist/cjs/src/decorators/field/sortable/helpers/sortableSnapshot.js +101 -0
  25. package/dist/cjs/src/decorators/field/sortable/helpers/stabilizeSortableScopeLocks.js +86 -0
  26. package/dist/cjs/src/decorators/field/sortable/helpers/validPosition.js +21 -4
  27. package/dist/cjs/src/decorators/field/sortable/hooks/afterSortableDestroy.js +24 -7
  28. package/dist/cjs/src/decorators/field/sortable/hooks/afterSortableUpdate.js +10 -0
  29. package/dist/cjs/src/dream/Query.js +73 -11
  30. package/dist/cjs/src/dream/QueryDriver/Base.js +75 -2
  31. package/dist/cjs/src/dream/QueryDriver/Kysely.js +11 -4
  32. package/dist/cjs/src/dream/QueryDriver/Postgres.js +74 -0
  33. package/dist/cjs/src/dream/internal/destroyDream.js +60 -6
  34. package/dist/cjs/src/dream/internal/saveDream.js +109 -7
  35. package/dist/cjs/src/dream/internal/similarity/SimilarityBuilder.js +19 -4
  36. package/dist/cjs/src/dream/internal/softDeleteDream.js +13 -1
  37. package/dist/cjs/src/dream/internal/undestroyDream.js +56 -8
  38. package/dist/cjs/src/dream-app/index.js +21 -0
  39. package/dist/cjs/src/encrypt/assertNoEncryptedColumnWrites.js +62 -0
  40. package/dist/cjs/src/errors/SortableBatchRequiresTooManyScopeLocks.js +57 -0
  41. package/dist/cjs/src/errors/SortableRequiresAdvisoryTransactionLocks.js +26 -0
  42. package/dist/cjs/src/errors/SortableScopeDidNotStabilize.js +39 -0
  43. package/dist/cjs/src/errors/SortableScopeLockWaitTimedOut.js +50 -0
  44. package/dist/cjs/src/errors/encrypt/CannotSetEncryptedColumnInQueryUpdate.js +31 -0
  45. package/dist/cjs/src/package-exports/errors.js +3 -0
  46. package/dist/esm/src/Dream.js +63 -1
  47. package/dist/esm/src/db/errors.js +4 -0
  48. package/dist/esm/src/decorators/field/Encrypted.js +12 -0
  49. package/dist/esm/src/decorators/field/sortable/Sortable.js +43 -118
  50. package/dist/esm/src/decorators/field/sortable/helpers/acquireSortableScopeLocks.js +38 -0
  51. package/dist/esm/src/decorators/field/sortable/helpers/acquireStabilizedSortableBatchLocks.js +183 -0
  52. package/dist/esm/src/decorators/field/sortable/helpers/acquireStabilizedSortableScopeLocks.js +40 -0
  53. package/dist/esm/src/decorators/field/sortable/helpers/canonicalScopeValue.js +194 -0
  54. package/dist/esm/src/decorators/field/sortable/helpers/clearCachedSortableValues.js +18 -0
  55. package/dist/esm/src/decorators/field/sortable/helpers/decrementScopedRecordsGreaterThanPosition.js +9 -9
  56. package/dist/esm/src/decorators/field/sortable/helpers/filterQueryToInstanceScope.js +20 -0
  57. package/dist/esm/src/decorators/field/sortable/helpers/filterQueryToScopeValues.js +32 -0
  58. package/dist/esm/src/decorators/field/sortable/helpers/heldSortableScopeLockKeys.js +34 -0
  59. package/dist/esm/src/decorators/field/sortable/helpers/performSortableDestroyWork.js +21 -0
  60. package/dist/esm/src/decorators/field/sortable/helpers/performSortablePositionWork.js +36 -0
  61. package/dist/esm/src/decorators/field/sortable/helpers/prepareSortableFieldsForDestroy.js +56 -0
  62. package/dist/esm/src/decorators/field/sortable/helpers/prepareSortableFieldsForSave.js +84 -0
  63. package/dist/esm/src/decorators/field/sortable/helpers/resortAllRecords.js +186 -29
  64. package/dist/esm/src/decorators/field/sortable/helpers/setPosition.js +90 -46
  65. package/dist/esm/src/decorators/field/sortable/helpers/sortableRowCache.js +73 -0
  66. package/dist/esm/src/decorators/field/sortable/helpers/sortableScopeColumns.js +42 -0
  67. package/dist/esm/src/decorators/field/sortable/helpers/sortableScopeLockKey.js +99 -0
  68. package/dist/esm/src/decorators/field/sortable/helpers/sortableScopeLockKeys.js +72 -0
  69. package/dist/esm/src/decorators/field/sortable/helpers/sortableSnapshot.js +101 -0
  70. package/dist/esm/src/decorators/field/sortable/helpers/stabilizeSortableScopeLocks.js +86 -0
  71. package/dist/esm/src/decorators/field/sortable/helpers/validPosition.js +21 -4
  72. package/dist/esm/src/decorators/field/sortable/hooks/afterSortableDestroy.js +24 -7
  73. package/dist/esm/src/decorators/field/sortable/hooks/afterSortableUpdate.js +10 -0
  74. package/dist/esm/src/dream/Query.js +73 -11
  75. package/dist/esm/src/dream/QueryDriver/Base.js +75 -2
  76. package/dist/esm/src/dream/QueryDriver/Kysely.js +11 -4
  77. package/dist/esm/src/dream/QueryDriver/Postgres.js +74 -0
  78. package/dist/esm/src/dream/internal/destroyDream.js +60 -6
  79. package/dist/esm/src/dream/internal/saveDream.js +109 -7
  80. package/dist/esm/src/dream/internal/similarity/SimilarityBuilder.js +19 -4
  81. package/dist/esm/src/dream/internal/softDeleteDream.js +13 -1
  82. package/dist/esm/src/dream/internal/undestroyDream.js +56 -8
  83. package/dist/esm/src/dream-app/index.js +21 -0
  84. package/dist/esm/src/encrypt/assertNoEncryptedColumnWrites.js +62 -0
  85. package/dist/esm/src/errors/SortableBatchRequiresTooManyScopeLocks.js +57 -0
  86. package/dist/esm/src/errors/SortableRequiresAdvisoryTransactionLocks.js +26 -0
  87. package/dist/esm/src/errors/SortableScopeDidNotStabilize.js +39 -0
  88. package/dist/esm/src/errors/SortableScopeLockWaitTimedOut.js +50 -0
  89. package/dist/esm/src/errors/encrypt/CannotSetEncryptedColumnInQueryUpdate.js +31 -0
  90. package/dist/esm/src/package-exports/errors.js +3 -0
  91. package/dist/types/src/Dream.d.ts +56 -0
  92. package/dist/types/src/db/errors.d.ts +2 -0
  93. package/dist/types/src/decorators/field/sortable/Sortable.d.ts +33 -0
  94. package/dist/types/src/decorators/field/sortable/helpers/acquireSortableScopeLocks.d.ts +25 -0
  95. package/dist/types/src/decorators/field/sortable/helpers/acquireStabilizedSortableBatchLocks.d.ts +91 -0
  96. package/dist/types/src/decorators/field/sortable/helpers/acquireStabilizedSortableScopeLocks.d.ts +31 -0
  97. package/dist/types/src/decorators/field/sortable/helpers/canonicalScopeValue.d.ts +85 -0
  98. package/dist/types/src/decorators/field/sortable/helpers/clearCachedSortableValues.d.ts +13 -0
  99. package/dist/types/src/decorators/field/sortable/helpers/decrementScopedRecordsGreaterThanPosition.d.ts +8 -1
  100. package/dist/types/src/decorators/field/sortable/helpers/filterQueryToInstanceScope.d.ts +24 -0
  101. package/dist/types/src/decorators/field/sortable/helpers/filterQueryToScopeValues.d.ts +22 -0
  102. package/dist/types/src/decorators/field/sortable/helpers/heldSortableScopeLockKeys.d.ts +27 -0
  103. package/dist/types/src/decorators/field/sortable/helpers/performSortableDestroyWork.d.ts +14 -0
  104. package/dist/types/src/decorators/field/sortable/helpers/performSortablePositionWork.d.ts +15 -0
  105. package/dist/types/src/decorators/field/sortable/helpers/prepareSortableFieldsForDestroy.d.ts +41 -0
  106. package/dist/types/src/decorators/field/sortable/helpers/prepareSortableFieldsForSave.d.ts +35 -0
  107. package/dist/types/src/decorators/field/sortable/helpers/resortAllRecords.d.ts +32 -0
  108. package/dist/types/src/decorators/field/sortable/helpers/setPosition.d.ts +27 -11
  109. package/dist/types/src/decorators/field/sortable/helpers/sortableRowCache.d.ts +48 -0
  110. package/dist/types/src/decorators/field/sortable/helpers/sortableScopeColumns.d.ts +30 -0
  111. package/dist/types/src/decorators/field/sortable/helpers/sortableScopeLockKey.d.ts +44 -0
  112. package/dist/types/src/decorators/field/sortable/helpers/sortableScopeLockKeys.d.ts +51 -0
  113. package/dist/types/src/decorators/field/sortable/helpers/sortableSnapshot.d.ts +92 -0
  114. package/dist/types/src/decorators/field/sortable/helpers/stabilizeSortableScopeLocks.d.ts +59 -0
  115. package/dist/types/src/decorators/field/sortable/helpers/validPosition.d.ts +14 -2
  116. package/dist/types/src/decorators/field/sortable/hooks/afterSortableCreate.d.ts +1 -1
  117. package/dist/types/src/decorators/field/sortable/hooks/afterSortableDestroy.d.ts +3 -1
  118. package/dist/types/src/decorators/field/sortable/hooks/afterSortableUpdate.d.ts +1 -1
  119. package/dist/types/src/dream/Query.d.ts +47 -9
  120. package/dist/types/src/dream/QueryDriver/Base.d.ts +61 -1
  121. package/dist/types/src/dream/QueryDriver/Kysely.d.ts +6 -2
  122. package/dist/types/src/dream/QueryDriver/Postgres.d.ts +40 -0
  123. package/dist/types/src/dream/internal/softDeleteDream.d.ts +7 -1
  124. package/dist/types/src/dream-app/index.d.ts +18 -2
  125. package/dist/types/src/encrypt/assertNoEncryptedColumnWrites.d.ts +27 -0
  126. package/dist/types/src/errors/SortableBatchRequiresTooManyScopeLocks.d.ts +37 -0
  127. package/dist/types/src/errors/SortableRequiresAdvisoryTransactionLocks.d.ts +13 -0
  128. package/dist/types/src/errors/SortableScopeDidNotStabilize.d.ts +23 -0
  129. package/dist/types/src/errors/SortableScopeLockWaitTimedOut.d.ts +34 -0
  130. package/dist/types/src/errors/encrypt/CannotSetEncryptedColumnInQueryUpdate.d.ts +8 -0
  131. package/dist/types/src/package-exports/errors.d.ts +3 -0
  132. package/docs/assets/hierarchy.js +1 -1
  133. package/docs/assets/navigation.js +1 -1
  134. package/docs/assets/search.js +1 -1
  135. package/docs/classes/db.DreamMigrationHelpers.html +11 -11
  136. package/docs/classes/db.KyselyQueryDriver.html +88 -41
  137. package/docs/classes/db.PostgresQueryDriver.html +82 -42
  138. package/docs/classes/db.QueryDriverBase.html +86 -39
  139. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  140. package/docs/classes/errors.ColumnOverflow.html +3 -3
  141. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  142. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  143. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  144. package/docs/classes/errors.DecryptionError.html +2 -2
  145. package/docs/classes/errors.DecryptionParseError.html +2 -2
  146. package/docs/classes/errors.DecryptionRotationError.html +3 -3
  147. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  148. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  149. package/docs/classes/errors.InvalidClockTime.html +2 -2
  150. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  151. package/docs/classes/errors.InvalidDateTime.html +2 -2
  152. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  153. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  154. package/docs/classes/errors.NotNullViolation.html +3 -3
  155. package/docs/classes/errors.RecordNotFound.html +3 -3
  156. package/docs/classes/errors.SortableBatchRequiresTooManyScopeLocks.html +61 -0
  157. package/docs/classes/errors.SortableScopeDidNotStabilize.html +48 -0
  158. package/docs/classes/errors.SortableScopeLockWaitTimedOut.html +58 -0
  159. package/docs/classes/errors.ValidationError.html +3 -3
  160. package/docs/classes/index.CalendarDate.html +33 -33
  161. package/docs/classes/index.ClockTime.html +32 -32
  162. package/docs/classes/index.ClockTimeTz.html +35 -35
  163. package/docs/classes/index.DateTime.html +86 -86
  164. package/docs/classes/index.Decorators.html +19 -19
  165. package/docs/classes/index.Dream.html +151 -124
  166. package/docs/classes/index.DreamApp.html +11 -10
  167. package/docs/classes/index.DreamTransaction.html +2 -2
  168. package/docs/classes/index.Env.html +2 -2
  169. package/docs/classes/index.Query.html +124 -98
  170. package/docs/classes/system.CliFileWriter.html +4 -4
  171. package/docs/classes/system.DreamBin.html +2 -2
  172. package/docs/classes/system.DreamCLI.html +7 -7
  173. package/docs/classes/system.DreamImporter.html +2 -2
  174. package/docs/classes/system.DreamLogos.html +2 -2
  175. package/docs/classes/system.DreamSerializerBuilder.html +11 -11
  176. package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
  177. package/docs/classes/system.PathHelpers.html +3 -3
  178. package/docs/classes/utils.Encrypt.html +3 -3
  179. package/docs/classes/utils.Range.html +2 -2
  180. package/docs/functions/db.closeAllDbConnections.html +1 -1
  181. package/docs/functions/db.dreamDbConnections.html +1 -1
  182. package/docs/functions/db.untypedDb.html +1 -1
  183. package/docs/functions/db.validateColumn.html +1 -1
  184. package/docs/functions/db.validateTable.html +1 -1
  185. package/docs/functions/errors.pgErrorType.html +1 -1
  186. package/docs/functions/index.DreamSerializer.html +1 -1
  187. package/docs/functions/index.ObjectSerializer.html +1 -1
  188. package/docs/functions/index.ReplicaSafe.html +1 -1
  189. package/docs/functions/index.STI.html +1 -1
  190. package/docs/functions/index.SoftDelete.html +1 -1
  191. package/docs/functions/utils.camelize.html +1 -1
  192. package/docs/functions/utils.capitalize.html +1 -1
  193. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  194. package/docs/functions/utils.compact.html +1 -1
  195. package/docs/functions/utils.groupBy.html +1 -1
  196. package/docs/functions/utils.hyphenize.html +1 -1
  197. package/docs/functions/utils.intersection.html +1 -1
  198. package/docs/functions/utils.isEmpty.html +1 -1
  199. package/docs/functions/utils.normalizeUnicode.html +1 -1
  200. package/docs/functions/utils.pascalize.html +1 -1
  201. package/docs/functions/utils.percent.html +1 -1
  202. package/docs/functions/utils.range.html +1 -1
  203. package/docs/functions/utils.round.html +1 -1
  204. package/docs/functions/utils.sanitizeString.html +1 -1
  205. package/docs/functions/utils.snakeify.html +1 -1
  206. package/docs/functions/utils.sort.html +2 -2
  207. package/docs/functions/utils.sortBy.html +1 -1
  208. package/docs/functions/utils.sortObjectByKey.html +1 -1
  209. package/docs/functions/utils.sortObjectByValue.html +1 -1
  210. package/docs/functions/utils.uncapitalize.html +1 -1
  211. package/docs/functions/utils.uniq.html +1 -1
  212. package/docs/hierarchy.html +1 -1
  213. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  214. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  215. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  216. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  217. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  218. package/docs/interfaces/types.DecoratorContext.html +2 -2
  219. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  220. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  221. package/docs/interfaces/types.DreamDbConfig.html +5 -5
  222. package/docs/interfaces/types.DurationObject.html +2 -2
  223. package/docs/interfaces/types.EncryptOptions.html +2 -2
  224. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  225. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  226. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  227. package/docs/modules/errors.html +1 -1
  228. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  229. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  230. package/docs/types/openapi.OpenapiFormats.html +1 -1
  231. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  232. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  233. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  234. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  235. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  236. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  237. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  238. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  239. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  240. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
  241. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
  242. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
  243. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  244. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  245. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  246. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  247. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  248. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  249. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  250. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  251. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  252. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  253. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  254. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  255. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  256. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  257. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  258. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  259. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
  260. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
  261. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
  262. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  263. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  264. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  265. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  266. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  267. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  268. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  269. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  270. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  271. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  272. package/docs/types/types.CalendarDateObject.html +1 -1
  273. package/docs/types/types.Camelized.html +1 -1
  274. package/docs/types/types.ClockTimeObject.html +1 -1
  275. package/docs/types/types.DbConnectionType.html +1 -1
  276. package/docs/types/types.DbTypes.html +1 -1
  277. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  278. package/docs/types/types.DreamAttributes.html +1 -1
  279. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  280. package/docs/types/types.DreamClassColumn.html +1 -1
  281. package/docs/types/types.DreamColumn.html +1 -1
  282. package/docs/types/types.DreamColumnNames.html +1 -1
  283. package/docs/types/types.DreamLogLevel.html +1 -1
  284. package/docs/types/types.DreamLogger.html +2 -2
  285. package/docs/types/types.DreamModelSerializerType.html +1 -1
  286. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  287. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  288. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  289. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  290. package/docs/types/types.DreamSerializable.html +1 -1
  291. package/docs/types/types.DreamSerializableArray.html +1 -1
  292. package/docs/types/types.DreamSerializerKey.html +1 -1
  293. package/docs/types/types.DreamSerializers.html +1 -1
  294. package/docs/types/types.DreamVirtualColumns.html +1 -1
  295. package/docs/types/types.DurationUnit.html +1 -1
  296. package/docs/types/types.EncryptAlgorithm.html +1 -1
  297. package/docs/types/types.HasManyStatement.html +1 -1
  298. package/docs/types/types.HasOneStatement.html +1 -1
  299. package/docs/types/types.Hyphenized.html +1 -1
  300. package/docs/types/types.Pascalized.html +1 -1
  301. package/docs/types/types.PrimaryKeyType.html +1 -1
  302. package/docs/types/types.RoundingPrecision.html +1 -1
  303. package/docs/types/types.SerializerCasing.html +1 -1
  304. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  305. package/docs/types/types.Snakeified.html +1 -1
  306. package/docs/types/types.StrictInterface.html +1 -1
  307. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  308. package/docs/types/types.UpdateableProperties.html +1 -1
  309. package/docs/types/types.ValidationType.html +1 -1
  310. package/docs/types/types.ViewModel.html +2 -2
  311. package/docs/types/types.ViewModelClass.html +1 -1
  312. package/docs/types/types.WeekdayName.html +1 -1
  313. package/docs/types/types.WhereStatementForDream.html +1 -1
  314. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  315. package/docs/variables/index.DreamConst.html +1 -1
  316. package/docs/variables/index.ops.html +1 -1
  317. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  318. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  319. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  320. package/docs/variables/system.primaryKeyTypes.html +1 -1
  321. package/package.json +1 -1
  322. package/dist/cjs/src/decorators/field/sortable/helpers/applySortableScopeToQuery.js +0 -13
  323. package/dist/cjs/src/decorators/field/sortable/helpers/sortableQueryExcludingDream.js +0 -7
  324. package/dist/cjs/src/decorators/field/sortable/hooks/beforeSortableSave.js +0 -41
  325. package/dist/esm/src/decorators/field/sortable/helpers/applySortableScopeToQuery.js +0 -13
  326. package/dist/esm/src/decorators/field/sortable/helpers/sortableQueryExcludingDream.js +0 -7
  327. package/dist/esm/src/decorators/field/sortable/hooks/beforeSortableSave.js +0 -41
  328. package/dist/types/src/decorators/field/sortable/helpers/applySortableScopeToQuery.d.ts +0 -12
  329. package/dist/types/src/decorators/field/sortable/helpers/sortableQueryExcludingDream.d.ts +0 -12
  330. package/dist/types/src/decorators/field/sortable/hooks/beforeSortableSave.d.ts +0 -12
@@ -0,0 +1,92 @@
1
+ import Dream from '../../../../Dream.js';
2
+ import DreamTransaction from '../../../../dream/DreamTransaction.js';
3
+ import { SortableFieldConfig } from '../Sortable.js';
4
+ /**
5
+ * @internal
6
+ *
7
+ * What a sortable position-mutating path knows about the row as it physically
8
+ * exists, rather than as the in-memory instance remembers it.
9
+ *
10
+ * `position` is the row's real position; `scopeValues` are the row's real sort
11
+ * scope column values, keyed by column. An instance loaded before another
12
+ * writer moved the row carries neither.
13
+ */
14
+ export interface SortableSnapshot {
15
+ position: number | null;
16
+ scopeValues: Map<string, unknown>;
17
+ }
18
+ /**
19
+ * @internal
20
+ *
21
+ * Snapshots keyed by position field — a model may declare several sortable
22
+ * fields, each with its own scope and its own position space.
23
+ */
24
+ export type SortableSnapshots = Map<string, SortableSnapshot>;
25
+ /**
26
+ * @internal
27
+ *
28
+ * The outcome of a snapshot read: the snapshots themselves, plus whether the
29
+ * row was physically there to read.
30
+ *
31
+ * The two are deliberately separate. An empty `snapshots` map means only "no
32
+ * snapshot is available", which the model having no sortable fields produces
33
+ * just as readily as a row another writer has already deleted — and a caller
34
+ * that reads absence out of the empty map compacts a scope this operation never
35
+ * vacated.
36
+ */
37
+ export interface SortableSnapshotRead {
38
+ /**
39
+ * False only when a read positively found no row. A read that never had to
40
+ * run — a model with no sortable fields — reports true, since it observed
41
+ * nothing.
42
+ */
43
+ rowExists: boolean;
44
+ snapshots: SortableSnapshots;
45
+ }
46
+ /**
47
+ * @internal
48
+ *
49
+ * Reads the record's real position and sort scope column values straight from
50
+ * the row, inside the given transaction.
51
+ *
52
+ * The read deliberately bypasses Dream's default scopes and goes to the table
53
+ * by primary key: soft-deleted rows have to be readable here (undestroy reads
54
+ * one), and an STI child's row is the same physical row whatever scope the
55
+ * class carries.
56
+ *
57
+ * When the row is not there the snapshots are empty and `rowExists` is false;
58
+ * a caller that goes on to compute a shift falls back to the instance, which is
59
+ * the pre-existing behavior.
60
+ *
61
+ * @param dream - the record to snapshot
62
+ * @param txn - the transaction the read runs in; the read must be protected by
63
+ * whatever scope lock the caller holds in that transaction
64
+ * @param configs - the sortable fields whose position and scope columns to read
65
+ */
66
+ export declare function readSortableSnapshots(dream: Dream, txn: DreamTransaction<any>, configs: SortableFieldConfig[]): Promise<SortableSnapshotRead>;
67
+ /**
68
+ * @internal
69
+ *
70
+ * Stashes snapshots on the instance so the phase that computes the shift can
71
+ * reach the read the earlier phase made. The read and the shift are separate
72
+ * calls on every path — `prepareSortableFieldsForDestroy` to
73
+ * `performSortableDestroyWork`, the `saveDream` lock acquisition to
74
+ * `performSortablePositionWork` — and the instance is what crosses between
75
+ * them.
76
+ */
77
+ export declare function cacheSortableSnapshots(dream: Dream, snapshots: SortableSnapshots): void;
78
+ /**
79
+ * @internal
80
+ */
81
+ export declare function sortableSnapshotFor(dream: Dream, positionField: string): SortableSnapshot | undefined;
82
+ /**
83
+ * @internal
84
+ */
85
+ export declare function clearSortableSnapshot(dream: Dream, positionField: string): void;
86
+ /**
87
+ * @internal
88
+ *
89
+ * The value to filter a sort scope column by: the row's real value when a
90
+ * snapshot is available, and the caller's own fallback when it is not.
91
+ */
92
+ export declare function snapshotScopeValue(snapshot: SortableSnapshot | undefined, column: string, fallback: () => unknown): unknown;
@@ -0,0 +1,59 @@
1
+ import Dream from '../../../../Dream.js';
2
+ import DreamTransaction from '../../../../dream/DreamTransaction.js';
3
+ /**
4
+ * How many acquisition passes a position-mutating operation will make while
5
+ * following a record that has been moved to another sort scope, before giving
6
+ * up. One pass is the ordinary case (lock what the caller says, read, agree); a
7
+ * second covers a competitor that moved the row between the two; a third exists
8
+ * so that a single unlucky retry is not fatal. Beyond that the row is being
9
+ * moved faster than it can be read, and raising is better than compacting a
10
+ * scope it no longer occupies.
11
+ *
12
+ * The bound counts acquisitions, and every one of them counts: the convergence
13
+ * check runs after the last acquisition and the read taken under it, so an
14
+ * operation that settles on its final pass settles rather than raising.
15
+ */
16
+ export declare const MAX_SCOPE_STABILIZATION_ROUNDS = 3;
17
+ /**
18
+ * @internal
19
+ *
20
+ * The stabilization protocol every sortable lock acquisition follows, in one
21
+ * place: acquire the keys the current knowledge implies, read again under those
22
+ * locks, and take whatever additional key the read reveals — until a pass
23
+ * reveals nothing new, or the bound above is exhausted.
24
+ *
25
+ * The bootstrapping problem it solves: a sort scope's lock key is derived from
26
+ * the record's *physical* scope columns, and those cannot be read safely until
27
+ * that scope is locked. So the first pass locks what the caller can know without
28
+ * reading — an instance's own values, or an unprotected candidate read — and
29
+ * every later pass locks what the read taken under those locks reveals.
30
+ *
31
+ * Nothing here is ever unwound: the locks are transaction-scoped advisory locks,
32
+ * which are additive and are released only when the transaction ends. A pass
33
+ * that discovers a new key simply also takes it, holding at worst one lock too
34
+ * many for the rest of the transaction — which costs contention and never
35
+ * correctness. That is what lets this run inside a caller-owned transaction
36
+ * unchanged; no path here restarts or rolls back a transaction it did not open.
37
+ *
38
+ * Keys the transaction already holds — taken by an earlier phase of the same
39
+ * operation, or by the preflight of the locked batch this record is being
40
+ * walked in — are not taken again; they are held to the end of the transaction
41
+ * regardless. Convergence is judged on that same set, so a pass whose read
42
+ * reveals only keys already held is a pass that agrees.
43
+ *
44
+ * Keys are taken in sorted order within a pass, so that two operations touching
45
+ * the same set of scopes cannot deadlock against each other. Across passes the
46
+ * order is discovery-driven and therefore unsortable in principle, which is the
47
+ * named fallback: two operations moving records in opposite directions between
48
+ * the same two scopes can raise Postgres's `40P01` deadlock error, a visible
49
+ * retryable failure.
50
+ *
51
+ * @param dream - a record of the model being locked; supplies the connection
52
+ * and, when this fails, the class name in the error
53
+ * @param txn - the transaction the locks are scoped to
54
+ * @param keysForRound - reads whatever this pass can see — the caller's own
55
+ * snapshot or candidate read — and returns every lock key it implies. Called
56
+ * once per pass with the number of acquisitions made so far, so a caller whose
57
+ * first pass needs no read can skip it on round 0
58
+ */
59
+ export default function stabilizeSortableScopeLocks(dream: Dream, txn: DreamTransaction<any>, keysForRound: (round: number) => Promise<Iterable<bigint>>): Promise<void>;
@@ -1,2 +1,14 @@
1
- import { SortableCacheWithRequiredTransaction } from './setPosition.js';
2
- export default function validPosition({ changingScope, dream, position, positionField, query, scope, wasNewRecord, previousPosition, txn, }: SortableCacheWithRequiredTransaction): Promise<number>;
1
+ import { SortablePositionWrite } from './setPosition.js';
2
+ /**
3
+ * @internal
4
+ *
5
+ * The position the record will be written at: the caller's, clamped to the
6
+ * scope the record now occupies.
7
+ *
8
+ * The scope is read off the instance rather than off the snapshot because the
9
+ * scope in question is the one being *entered*, which is the instance's — the
10
+ * snapshot holds the scope the row was in before the driver write. On every
11
+ * path into here the driver write has already landed the instance's scope
12
+ * values on the row.
13
+ */
14
+ export default function validPosition({ changingScope, dream, position, positionField, positionUnderSentinel, query, scope, wasNewRecord, previousPosition, txn, }: SortablePositionWrite): Promise<number>;
@@ -5,6 +5,6 @@ export default function afterSortableCreate({ positionField, dream, query, txn,
5
5
  positionField: string;
6
6
  dream: Dream;
7
7
  query: Query<Dream>;
8
- txn?: DreamTransaction<any> | undefined;
8
+ txn: DreamTransaction<any>;
9
9
  scope: string | string[] | undefined;
10
10
  }): Promise<void>;
@@ -1,8 +1,10 @@
1
1
  import Dream from '../../../../Dream.js';
2
+ import DreamTransaction from '../../../../dream/DreamTransaction.js';
2
3
  import Query from '../../../../dream/Query.js';
3
- export default function afterSortableDestroy({ positionField, dream, query, scope, }: {
4
+ export default function afterSortableDestroy({ positionField, dream, query, scope, txn, }: {
4
5
  positionField: string;
5
6
  dream: Dream;
6
7
  query: Query<Dream>;
7
8
  scope: string | string[] | undefined;
9
+ txn: DreamTransaction<any>;
8
10
  }): Promise<void>;
@@ -5,6 +5,6 @@ export default function afterUpdateSortable({ positionField, dream, query, txn,
5
5
  positionField: string;
6
6
  dream: Dream;
7
7
  query: Query<Dream>;
8
- txn?: DreamTransaction<any> | undefined;
8
+ txn: DreamTransaction<any>;
9
9
  scope: string | string[] | undefined;
10
10
  }): Promise<void>;
@@ -1328,9 +1328,11 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1328
1328
  * read is a plain `FOR UPDATE`: if another transaction already holds a lock
1329
1329
  * on one of the batch's rows, this call blocks until that transaction ends,
1330
1330
  * holding its own transaction and its pooled connection open the whole
1331
- * time. Dream sets no `lock_timeout` or `statement_timeout`, so a
1332
- * long-running writer on the other side stalls the run indefinitely and, at
1333
- * scale, ties up connections. If that is a risk in your application, set a
1331
+ * time. Dream sets no `lock_timeout` or `statement_timeout` on a row-lock
1332
+ * wait — the one it does set, around a sortable model's scope-lock
1333
+ * acquisition, is restored before the rows are claimed — so a long-running
1334
+ * writer on the other side stalls the run indefinitely and, at scale, ties
1335
+ * up connections. If that is a risk in your application, set a
1334
1336
  * `lock_timeout` on the connection so a stuck batch fails instead of
1335
1337
  * hanging.
1336
1338
  * - **A `limit` or `offset` on the Query is incompatible with `destroy` on
@@ -1408,6 +1410,36 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1408
1410
  * When the Query already carries a transaction, that transaction is used for
1409
1411
  * every batch rather than opening one per batch, so the caller's transaction
1410
1412
  * boundary wins and the locks are held until the caller commits.
1413
+ *
1414
+ * On a sortable model, the advisory scope keys this batch needs are acquired
1415
+ * before the claim (see `acquireStabilizedSortableBatchLocks`), which removes
1416
+ * the row-lock/advisory-lock inversion for the rows the batch itself claims.
1417
+ * Two things stay outside that guarantee and are fallbacks rather than
1418
+ * guarantees, with Postgres's `40P01` as the residual failure in both:
1419
+ *
1420
+ * - the ordering is **per batch**. A multi-batch run inside a caller-owned
1421
+ * transaction keeps batch N-1's row locks while batch N preflights. The
1422
+ * same shape accumulates *advisory* locks: they are released only when the
1423
+ * transaction ends, so every batch's scope keys are still held when the
1424
+ * next one preflights. That accumulation is bounded — the preflight counts
1425
+ * the keys the transaction already holds along with the ones the batch
1426
+ * would add, and refuses with `SortableBatchRequiresTooManyScopeLocks`
1427
+ * rather than letting a long run over a high-cardinality sort scope exhaust
1428
+ * `max_locks_per_transaction` for the whole cluster — so a run long enough
1429
+ * raises instead of completing. Letting Dream open a transaction per batch
1430
+ * releases the keys as it goes and gives each batch the whole budget.
1431
+ * - the preflight covers **the claimed rows' own scopes only**. A
1432
+ * `dependent: 'destroy'` cascade under `destroy({ lock: true })` destroys
1433
+ * child records of other tables, and a sortable child takes its own table's
1434
+ * advisory key inside `perBatch` — after this transaction is already
1435
+ * holding the root rows' row locks. Walking
1436
+ * `dependentDestroyAssociationNames()` to fold those keys into the sorted
1437
+ * pass is deliberately not done: the cascade's shape is only knowable per
1438
+ * record, and the deadlock it leaves is detected and retryable. The keys
1439
+ * the preflight *did* take are held across the whole batch, cascade
1440
+ * included — a per-record destroy holds its scope lock across one delete
1441
+ * and one compaction, while here the hold spans batch size × cascade depth.
1442
+ * A smaller `batchSize` shortens it (the default is 10).
1411
1443
  */
1412
1444
  private lockedBatches;
1413
1445
  /**
@@ -1489,7 +1521,7 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1489
1521
  * use {@link Query.destroy} instead.
1490
1522
  *
1491
1523
  * ```ts
1492
- * await User.where({ email: ops.ilike('%burpcollaborator%').delete() })
1524
+ * await User.where({ email: ops.ilike('%burpcollaborator%') }).delete()
1493
1525
  * // 12
1494
1526
  * ```
1495
1527
  *
@@ -1651,14 +1683,19 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1651
1683
  * read is a plain `FOR UPDATE`: if another transaction already holds a
1652
1684
  * lock on one of the batch's rows, this call blocks until that transaction
1653
1685
  * ends, holding its own transaction and its pooled connection open the
1654
- * whole time. Dream sets no `lock_timeout` or `statement_timeout`, so a
1655
- * long-running writer on the other side stalls the run indefinitely and,
1656
- * at scale, ties up connections. If that is a risk in your application,
1657
- * set a `lock_timeout` on the connection so a stuck batch fails instead of
1686
+ * whole time. Dream sets no `lock_timeout` or `statement_timeout` on a
1687
+ * row-lock wait — the one it does set, around a sortable model's scope-lock
1688
+ * acquisition, is restored before the rows are claimed — so a long-running
1689
+ * writer on the other side stalls the run indefinitely and, at scale, ties
1690
+ * up connections. If that is a risk in your application, set a
1691
+ * `lock_timeout` on the connection so a stuck batch fails instead of
1658
1692
  * hanging.
1659
1693
  * - **`skipHooks` composes with `lock`, but stays on the per-instance
1660
1694
  * path.** With an attributes object and no `lock`, `skipHooks: true`
1661
- * issues a single `UPDATE ... WHERE` statement that writes raw columns.
1695
+ * issues a single `UPDATE ... WHERE` statement that writes raw columns —
1696
+ * with one refusal: it will not write a non-null value into an
1697
+ * `@Encrypted` backing column, since nothing on that path encrypts it, and
1698
+ * throws instead; `null`, which clears the column, is permitted.
1662
1699
  * With `lock: true`, `skipHooks: true` skips the model hooks on each
1663
1700
  * claimed record but still writes through the instance, so custom setters
1664
1701
  * — including the setters encrypted attributes encrypt through — run as
@@ -1681,6 +1718,7 @@ export default class Query<DreamInstance extends Dream, QueryTypeOpts extends Re
1681
1718
  * @throws InvalidBatchSize if `batchSize` is not a positive integer
1682
1719
  * @throws MissingRequiredLockOptionForUpdateCallback if a callback is passed without an options object carrying a boolean `lock`
1683
1720
  * @throws BatchingIncompatibleWithLimitOrOffset if the query carries a `limit` or `offset`
1721
+ * @throws CannotSetEncryptedColumnInQueryUpdate if the single-statement `skipHooks` form's attributes name an `@Encrypted` backing column with anything other than `null`
1684
1722
  */
1685
1723
  update(cb: (record: DreamInstance) => UpdateableProperties<DreamInstance> | undefined | Promise<UpdateableProperties<DreamInstance> | undefined>, options: {
1686
1724
  lock: boolean;
@@ -145,6 +145,62 @@ export default class QueryDriverBase<DreamInstance extends Dream> {
145
145
  * worker's lifetime.
146
146
  */
147
147
  static openTestDatabaseLockSession(connectionName: string): Promise<TestDatabaseLockSession>;
148
+ /**
149
+ * @internal
150
+ *
151
+ * Whether this driver implements the transaction-scoped advisory lock seam
152
+ * ({@link acquireAdvisoryTransactionLocks}). Adapters that can hold a
153
+ * key-addressed lock for the life of a transaction override this to `true`.
154
+ * It defaults to `false` so that a driver without the primitive fails loud
155
+ * for features that depend on it (today, the `Sortable` decorator) rather
156
+ * than silently racing on position values.
157
+ */
158
+ static supportsAdvisoryTransactionLocks: boolean;
159
+ /**
160
+ * @internal
161
+ *
162
+ * Acquire exclusive, transaction-scoped locks on arbitrary keys, waiting
163
+ * until any other transaction holding one of them finishes. The locks are
164
+ * released when the enclosing transaction commits or rolls back — never by an
165
+ * explicit unlock — so callers only ever have to acquire (Postgres:
166
+ * `pg_advisory_xact_lock(bigint)`).
167
+ *
168
+ * Unlike {@link applyRowLock}, this does not depend on rows existing: it is
169
+ * the only way to serialize writers that are about to insert into the same
170
+ * logical group. The `Sortable` decorator uses it to make each sort scope's
171
+ * position computation exclusive, keyed on the physical database, table,
172
+ * position field and scope values.
173
+ *
174
+ * The seam takes the whole key set rather than one key at a time so that a
175
+ * driver able to express it can take them in a single round trip — the
176
+ * batched, row-locking query APIs can need one key per candidate record per
177
+ * sortable field. **Keys must be acquired in the order given**: callers sort
178
+ * them, and that shared order is what keeps two operations over the same
179
+ * scopes from deadlocking. A driver that has no bulk form implements this by
180
+ * looping over the keys in order.
181
+ *
182
+ * **The wait must be bounded.** A caller that finds a key held waits for the
183
+ * holder's transaction, and an implementation that waits forever turns an
184
+ * ordinary mistake — a sortable operation issued without the enclosing
185
+ * transaction, so that it waits on a key that transaction itself holds — into
186
+ * a permanently wedged connection that no deadlock detector can see, because
187
+ * only one side is waiting. So an implementation applies the
188
+ * `sortableScopeLockTimeout` DreamApp option (milliseconds) to the
189
+ * acquisition and raises `SortableScopeLockWaitTimedOut` when it elapses. A
190
+ * configured `0` means no bound, and is applied just as literally: the
191
+ * acquisition waits without bound even where the connection carries a
192
+ * wait bound of its own. The bound belongs to
193
+ * the acquisition alone: whatever lock-wait behavior the connection was
194
+ * configured with has to be in force again by the time this returns, so that
195
+ * the row locks {@link applyRowLock} takes are unaffected.
196
+ *
197
+ * Only ever called when {@link supportsAdvisoryTransactionLocks} is `true`;
198
+ * the base default throws.
199
+ *
200
+ * @param txn - the transaction the locks are scoped to
201
+ * @param keys - the 64-bit signed lock keys, in acquisition order
202
+ */
203
+ static acquireAdvisoryTransactionLocks(txn: DreamTransaction<Dream>, keys: bigint[]): Promise<void>;
148
204
  static getColumnData(connectionName: string, tableName: string, allTableAssociationData: {
149
205
  [key: string]: SchemaBuilderAssociationData;
150
206
  }): Promise<{
@@ -391,8 +447,12 @@ export default class QueryDriverBase<DreamInstance extends Dream> {
391
447
  * @param dream - the dream instance you wish to destroy
392
448
  * @param txn - a transaction to encapsulate, consistently provided by underlying dream mechanisms
393
449
  * @param reallyDestroy - whether or not to reallyDestroy. If false, soft delete will be attempted when relevant
450
+ * @returns the number of rows this call removed (or soft deleted). Zero means
451
+ * the row was already gone, or that a `preventDeletion` veto stopped the
452
+ * write — callers distinguish the two by the veto flag, and use the count to
453
+ * decide whether there is anything for the after-destroy hooks to act on.
394
454
  */
395
- static destroyDream(dream: Dream, txn: DreamTransaction<Dream>, reallyDestroy: boolean): Promise<void>;
455
+ static destroyDream(dream: Dream, txn: DreamTransaction<Dream>, reallyDestroy: boolean): Promise<number>;
396
456
  static get syncDialect(): string;
397
457
  /**
398
458
  * Returns the sql that would be executed by this Query
@@ -60,13 +60,17 @@ export default class KyselyQueryDriver<DreamInstance extends Dream> extends Quer
60
60
  static primaryKeyType(): LegacyCompatiblePrimaryKeyType;
61
61
  /**
62
62
  * destroys a dream, possibly implementing soft delete if reallyDestroy is false
63
- * and the record being deleted implements soft delete.
63
+ * and the record being deleted implements soft delete. Does nothing at all when a
64
+ * beforeDestroy hook called `preventDeletion`.
64
65
  *
65
66
  * @param dream - the dream instance you wish to destroy
66
67
  * @param txn - a transaction to encapsulate, consistently provided by underlying dream mechanisms
67
68
  * @param reallyDestroy - whether or not to reallyDestroy. If false, soft delete will be attempted when relevant
69
+ * @returns the number of rows removed — zero when a `preventDeletion` veto
70
+ * stopped the write, and zero when the row was already gone, which on the
71
+ * soft delete path includes a row that is already soft deleted
68
72
  */
69
- static destroyDream(dream: Dream, txn: DreamTransaction<Dream>, reallyDestroy: boolean): Promise<void>;
73
+ static destroyDream(dream: Dream, txn: DreamTransaction<Dream>, reallyDestroy: boolean): Promise<number>;
70
74
  /**
71
75
  * Converts the given dream class into a Kysely query, enabling
72
76
  * you to build custom queries using the Kysely API
@@ -1,6 +1,7 @@
1
1
  import { type SelectQueryBuilder } from 'kysely';
2
2
  import Dream from '../../Dream.js';
3
3
  import { SchemaBuilderAssociationData, SchemaBuilderColumnData } from '../../helpers/cli/ASTBuilder.js';
4
+ import DreamTransaction from '../DreamTransaction.js';
4
5
  import KyselyQueryDriver from './Kysely.js';
5
6
  import type { TestDatabaseLockSession } from './Base.js';
6
7
  export default class PostgresQueryDriver<DreamInstance extends Dream> extends KyselyQueryDriver<DreamInstance> {
@@ -54,6 +55,45 @@ export default class PostgresQueryDriver<DreamInstance extends Dream> extends Ky
54
55
  * `Query#destroy`.
55
56
  */
56
57
  applyRowLock(kyselyQuery: SelectQueryBuilder<any, any, any>, tableAlias: string): SelectQueryBuilder<any, any, any>;
58
+ static supportsAdvisoryTransactionLocks: boolean;
59
+ /**
60
+ * @internal
61
+ *
62
+ * Postgres implementation of the transaction-scoped advisory lock seam.
63
+ *
64
+ * Uses the single-`bigint` form `pg_advisory_xact_lock(bigint)`, whose lock
65
+ * space is distinct from the two-`int4` form the test-database pool claims
66
+ * with (see {@link openTestDatabaseLockSession}), so an application lock can
67
+ * never collide with a pool claim.
68
+ *
69
+ * Every key is taken in one statement, over `unnest` of the key array: a
70
+ * function scan yields its rows in array order, so the caller's sorted
71
+ * acquisition order — the thing that keeps two operations over the same
72
+ * scopes from deadlocking — is preserved, while a batch that needs one key
73
+ * per candidate record costs one round trip rather than N.
74
+ *
75
+ * The locks are held until the enclosing transaction ends, and are waiting
76
+ * (no `NOWAIT`): a second transaction asking for the same key blocks at that
77
+ * key's row until the holder commits or rolls back. Because they are
78
+ * transaction-scoped there is nothing to release, and re-acquiring a key
79
+ * within one transaction is a no-op rather than an error.
80
+ *
81
+ * The wait is bounded by `lock_timeout`, taken from
82
+ * {@link DreamApp.sortableScopeLockTimeout} and applied to the acquisition
83
+ * statement alone: the prior value is read in the same statement that sets
84
+ * the bound and restored in the next one, so the transaction's row-lock waits
85
+ * keep whatever the application configured. Postgres cancels the statement
86
+ * with `55P03` when the bound elapses, and that is translated here into
87
+ * {@link SortableScopeLockWaitTimedOut} so no Postgres error code escapes the
88
+ * driver.
89
+ *
90
+ * A timeout of `0` means "no bound", which is what `lock_timeout` itself
91
+ * means by it, and is sent as the bound rather than skipped: an application
92
+ * whose connection carries a `lock_timeout` of its own would otherwise have
93
+ * its acquisition cancelled by that bound, which is neither the unbounded
94
+ * wait `0` asks for nor a cancellation this driver could translate.
95
+ */
96
+ static acquireAdvisoryTransactionLocks(txn: DreamTransaction<Dream>, keys: bigint[]): Promise<void>;
57
97
  static supportsParallelTestDatabases: boolean;
58
98
  /**
59
99
  * @internal
@@ -1,3 +1,9 @@
1
1
  import Dream from '../../Dream.js';
2
2
  import DreamTransaction from '../DreamTransaction.js';
3
- export default function softDeleteDream(dream: Dream, txn: DreamTransaction<any>): Promise<void>;
3
+ /**
4
+ * @internal
5
+ *
6
+ * @returns the number of rows soft deleted — zero when the row is already gone,
7
+ * and zero when it is already soft deleted
8
+ */
9
+ export default function softDeleteDream(dream: Dream, txn: DreamTransaction<any>): Promise<number>;
@@ -120,6 +120,22 @@ export default class DreamApp {
120
120
  get paginationPageSize(): number;
121
121
  private _paginationMaxPageSize;
122
122
  get paginationMaxPageSize(): number;
123
+ /**
124
+ * How long, in milliseconds, a position-mutating operation on a
125
+ * `@deco.Sortable` model will wait for another transaction to release the
126
+ * sort scope it needs before giving up with
127
+ * `SortableScopeLockWaitTimedOut`. Applied to the lock acquisition statement
128
+ * alone — the transaction's other lock waits keep whatever `lock_timeout`
129
+ * the application has configured.
130
+ *
131
+ * `0` waits without bound, which is what Postgres's `lock_timeout` means by
132
+ * it, and holds even on a connection configured with a `lock_timeout` of its
133
+ * own: the acquisition disables the bound for the duration of the statement.
134
+ *
135
+ * Set it with `dreamApp.set('sortableScopeLockTimeout', milliseconds)`.
136
+ */
137
+ private _sortableScopeLockTimeout;
138
+ get sortableScopeLockTimeout(): number;
123
139
  private _primaryKeyType;
124
140
  get primaryKeyType(): LegacyCompatiblePrimaryKeyType;
125
141
  private _projectRoot;
@@ -221,7 +237,7 @@ export default class DreamApp {
221
237
  private requireTestDatabaseClaimSupport;
222
238
  load<RT extends 'models' | 'serializers'>(resourceType: RT, resourcePath: string, importCb: (path: string) => Promise<any>): Promise<void>;
223
239
  plugin(cb: (app: DreamApp) => void | Promise<void>): void;
224
- set<ApplyOpt extends DreamAppSetOption>(applyOption: ApplyOpt, options: ApplyOpt extends 'bypassDeprecationChecks' ? boolean : ApplyOpt extends 'db' ? DreamDbCredentialOptions | string : ApplyOpt extends 'encryption' ? DreamAppEncryptionOptions : ApplyOpt extends 'primaryKeyType' ? LegacyCompatiblePrimaryKeyType : ApplyOpt extends 'importExtension' ? GeneratorImportStyle : ApplyOpt extends 'logger' ? DreamLogger : ApplyOpt extends 'projectRoot' ? string : ApplyOpt extends 'inflections' ? () => void | Promise<void> : ApplyOpt extends 'packageManager' ? DreamAppAllowedPackageManagersEnum : ApplyOpt extends 'paths' ? DreamDirectoryPaths : ApplyOpt extends 'parallelTests' ? number : ApplyOpt extends 'unicodeNormalization' ? UnicodeNormalizationForm : ApplyOpt extends 'paginationPageSize' ? number : ApplyOpt extends 'paginationMaxPageSize' ? number : never, secondaryOptions?: ApplyOpt extends 'db' ? DreamDbCredentialOptions : never): void;
240
+ set<ApplyOpt extends DreamAppSetOption>(applyOption: ApplyOpt, options: ApplyOpt extends 'bypassDeprecationChecks' ? boolean : ApplyOpt extends 'db' ? DreamDbCredentialOptions | string : ApplyOpt extends 'encryption' ? DreamAppEncryptionOptions : ApplyOpt extends 'primaryKeyType' ? LegacyCompatiblePrimaryKeyType : ApplyOpt extends 'importExtension' ? GeneratorImportStyle : ApplyOpt extends 'logger' ? DreamLogger : ApplyOpt extends 'projectRoot' ? string : ApplyOpt extends 'inflections' ? () => void | Promise<void> : ApplyOpt extends 'packageManager' ? DreamAppAllowedPackageManagersEnum : ApplyOpt extends 'paths' ? DreamDirectoryPaths : ApplyOpt extends 'parallelTests' ? number : ApplyOpt extends 'unicodeNormalization' ? UnicodeNormalizationForm : ApplyOpt extends 'paginationPageSize' ? number : ApplyOpt extends 'paginationMaxPageSize' ? number : ApplyOpt extends 'sortableScopeLockTimeout' ? number : never, secondaryOptions?: ApplyOpt extends 'db' ? DreamDbCredentialOptions : never): void;
225
241
  on<T extends DreamHookEventType>(hookEventType: T, cb: T extends 'db:log' ? (event: KyselyLogEvent) => void : T extends 'repl:start' ? (context: Context) => void | Promise<void> : never): void;
226
242
  }
227
243
  export type DreamHookEventType = 'db:log' | 'repl:start';
@@ -234,7 +250,7 @@ export interface DreamAppOpts {
234
250
  serializerCasing?: DreamSerializerCasing;
235
251
  parallelTests: number | undefined;
236
252
  }
237
- export type DreamAppSetOption = 'bypassDeprecationChecks' | 'db' | 'encryption' | 'inflections' | 'importExtension' | 'logger' | 'paths' | 'primaryKeyType' | 'projectRoot' | 'serializerCasing' | 'parallelTests' | 'unicodeNormalization' | 'paginationPageSize' | 'paginationMaxPageSize' | 'packageManager';
253
+ export type DreamAppSetOption = 'bypassDeprecationChecks' | 'db' | 'encryption' | 'inflections' | 'importExtension' | 'logger' | 'paths' | 'primaryKeyType' | 'projectRoot' | 'serializerCasing' | 'parallelTests' | 'unicodeNormalization' | 'paginationPageSize' | 'paginationMaxPageSize' | 'sortableScopeLockTimeout' | 'packageManager';
238
254
  export interface DreamDirectoryPaths {
239
255
  models?: string;
240
256
  serializers?: string;
@@ -0,0 +1,27 @@
1
+ import Dream from '../Dream.js';
2
+ /**
3
+ * @internal
4
+ *
5
+ * Throws when `attributes` names an @Encrypted backing column with anything other
6
+ * than null. Guards the write paths that never instantiate a model, and so never
7
+ * reach the throwing setter the Encrypted decorator installs for that column.
8
+ *
9
+ * `encryptedAttributes` is class-scoped, but a query rooted at an STI base reaches
10
+ * every one of its children's rows on the shared table, so `dreamClass` and every STI
11
+ * class below it are searched for backing columns.
12
+ *
13
+ * The search deliberately stops there rather than covering the whole hierarchy. A query
14
+ * rooted at an STI child matches only that child's rows, and a backing column only a
15
+ * sibling declares holds nothing meaningful for them: writing plaintext into it corrupts
16
+ * no ciphertext, because there is none to corrupt. Converting such a row to the sibling
17
+ * type is what has to clear that column, and it has to clear it whatever this guard did.
18
+ * Widening the walk to the siblings therefore buys no protection, and this guard runs on
19
+ * every single-statement update, so keep it narrow.
20
+ *
21
+ * Keys are matched in their snakeified form, since Kysely's CamelCasePlugin
22
+ * resolves both the camelCase and the snake_case spelling of a key to the same
23
+ * physical column.
24
+ *
25
+ * null is permitted: it clears the column, and there is no plaintext to mangle.
26
+ */
27
+ export default function assertNoEncryptedColumnWrites(dreamClass: typeof Dream, attributes: Record<string, unknown>): void;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Raised when a batch of a locked `Query#destroy` or `Query#update` on a
3
+ * sortable model would carry its transaction past the number of advisory
4
+ * sort-scope locks Dream is willing to hold at once.
5
+ *
6
+ * The batched, row-locking query APIs take every advisory scope key the batch
7
+ * needs before they claim a single row — one key per sort scope the batch's
8
+ * candidate records occupy, per sortable field the model declares. Advisory
9
+ * locks live in Postgres's cluster-wide shared lock table, whose size is fixed
10
+ * at startup (`max_locks_per_transaction` × `max_connections`), and they are
11
+ * held until the transaction ends. A batch over a table whose sort scope has
12
+ * very high cardinality can therefore consume a meaningful fraction of a
13
+ * resource every other connection in the cluster shares, and exhausting it
14
+ * fails unrelated transactions rather than only this one.
15
+ *
16
+ * So the preflight counts first and refuses, before claiming any row. The count
17
+ * is the whole transaction's: the keys it already holds plus the keys the
18
+ * refused batch would add, since advisory locks are released only when the
19
+ * transaction ends. Inside a transaction Dream opens for the batch that is the
20
+ * batch's own key set and nothing has been locked when this is raised; inside a
21
+ * transaction you own, it also counts every key the run's earlier batches took,
22
+ * and those stay held.
23
+ *
24
+ * The fix is almost always a smaller `batchSize`: the keys one batch needs are
25
+ * bounded by how many distinct sort scopes its records span, so halving the
26
+ * batch size halves the worst case. If the run itself is what accumulates them
27
+ * — a long multi-batch run inside a transaction you opened — either let Dream
28
+ * open a transaction per batch (do not pass a transaction of your own) or
29
+ * commit between runs, which is what releases the locks as it goes.
30
+ */
31
+ export default class SortableBatchRequiresTooManyScopeLocks extends Error {
32
+ dreamClassName: string;
33
+ keyCount: number;
34
+ maxKeyCount: number;
35
+ constructor(dreamClassName: string, keyCount: number, maxKeyCount: number);
36
+ get message(): string;
37
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Raised when a model declaring sortable fields is used on a query driver that
3
+ * cannot take transaction-scoped advisory locks.
4
+ *
5
+ * Sortable computes position values under a lock on the sort scope, without
6
+ * which concurrent writers collide on the same position. A driver that cannot
7
+ * provide that lock fails loudly here rather than racing silently.
8
+ */
9
+ export default class SortableRequiresAdvisoryTransactionLocks extends Error {
10
+ private queryDriverClassName;
11
+ constructor(queryDriverClassName: string);
12
+ get message(): string;
13
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Raised when a position-mutating operation cannot settle on the sort scope its
3
+ * record actually occupies.
4
+ *
5
+ * A save, destroy, undestroy or locked batch operation locks the sort scopes it
6
+ * believes it is touching, then reads the rows to find out which scopes they
7
+ * physically occupy. When another writer has moved a row in between, the
8
+ * operation takes the additional scope's lock and reads again. A row that keeps
9
+ * moving exhausts that bound, and the operation raises rather than compacting a
10
+ * scope the row has already left.
11
+ *
12
+ * This is a retryable condition: retrying the operation is the intended
13
+ * response. One caveat for saves the caller did not wrap in a transaction: the
14
+ * model's before-hooks run before the transaction this error aborts, so any
15
+ * effects those hooks had outside the record's own row — writes to other
16
+ * tables, enqueued work — are not rolled back, and run again on retry.
17
+ */
18
+ export default class SortableScopeDidNotStabilize extends Error {
19
+ dreamClassName: string;
20
+ rounds: number;
21
+ constructor(dreamClassName: string, rounds: number);
22
+ get message(): string;
23
+ }