@rvoh/dream 0.34.0 → 0.35.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 (219) hide show
  1. package/dist/cjs/src/Dream.js +25 -10
  2. package/dist/cjs/src/dream/DreamInstanceTransactionBuilder.js +14 -0
  3. package/dist/cjs/src/dream/internal/destroyDream.js +1 -2
  4. package/dist/cjs/src/dream/internal/runHooksFor.js +66 -28
  5. package/dist/cjs/src/dream/internal/saveDream.js +2 -4
  6. package/dist/cjs/src/dream/internal/undestroyDream.js +1 -2
  7. package/dist/cjs/src/errors/associations/CannotAssociationQueryOnUnpersistedDream.js +18 -0
  8. package/dist/cjs/src/errors/associations/CannotCreateAssociationOnUnpersistedDream.js +18 -0
  9. package/dist/cjs/src/errors/associations/CannotDestroyAssociationOnUnpersistedDream.js +18 -0
  10. package/dist/cjs/src/errors/associations/CannotUpdateAssociationOnUnpersistedDream.js +18 -0
  11. package/dist/cjs/src/helpers/DreamLogos/DreamLogos.js +12 -0
  12. package/dist/cjs/src/helpers/{DreamGlam/howyadoins/whaaaaaaaaaaok.js → DreamLogos/logos.js} +2 -2
  13. package/dist/cjs/src/helpers/areEqual.js +29 -0
  14. package/dist/cjs/src/helpers/cli/autoGeneratedFileDisclaimer.js +2 -2
  15. package/dist/cjs/src/helpers/cli/generateDreamContent.js +2 -2
  16. package/dist/cjs/src/helpers/cli/generateSerializerContent.js +14 -6
  17. package/dist/cjs/src/helpers/notEqual.js +7 -0
  18. package/dist/cjs/src/helpers/uniq.js +3 -4
  19. package/dist/cjs/src/index.js +3 -3
  20. package/dist/esm/src/Dream.js +25 -10
  21. package/dist/esm/src/dream/DreamInstanceTransactionBuilder.js +14 -0
  22. package/dist/esm/src/dream/internal/destroyDream.js +1 -2
  23. package/dist/esm/src/dream/internal/runHooksFor.js +66 -28
  24. package/dist/esm/src/dream/internal/saveDream.js +2 -4
  25. package/dist/esm/src/dream/internal/undestroyDream.js +1 -2
  26. package/dist/esm/src/errors/associations/CannotAssociationQueryOnUnpersistedDream.js +15 -0
  27. package/dist/esm/src/errors/associations/CannotCreateAssociationOnUnpersistedDream.js +15 -0
  28. package/dist/esm/src/errors/associations/CannotDestroyAssociationOnUnpersistedDream.js +15 -0
  29. package/dist/esm/src/errors/associations/CannotUpdateAssociationOnUnpersistedDream.js +15 -0
  30. package/dist/esm/src/helpers/DreamLogos/DreamLogos.js +9 -0
  31. package/dist/esm/src/helpers/{DreamGlam/howyadoins/whaaaaaaaaaaok.js → DreamLogos/logos.js} +1 -1
  32. package/dist/esm/src/helpers/areEqual.js +26 -0
  33. package/dist/esm/src/helpers/cli/autoGeneratedFileDisclaimer.js +2 -2
  34. package/dist/esm/src/helpers/cli/generateDreamContent.js +2 -2
  35. package/dist/esm/src/helpers/cli/generateSerializerContent.js +14 -6
  36. package/dist/esm/src/helpers/notEqual.js +4 -0
  37. package/dist/esm/src/helpers/uniq.js +3 -4
  38. package/dist/esm/src/index.js +1 -1
  39. package/dist/types/src/Dream.d.ts +1 -0
  40. package/dist/types/src/decorators/Decorators.d.ts +27 -27
  41. package/dist/types/src/errors/associations/CannotAssociationQueryOnUnpersistedDream.d.ts +7 -0
  42. package/dist/types/src/errors/associations/CannotCreateAssociationOnUnpersistedDream.d.ts +7 -0
  43. package/dist/types/src/errors/associations/CannotDestroyAssociationOnUnpersistedDream.d.ts +7 -0
  44. package/dist/types/src/errors/associations/CannotUpdateAssociationOnUnpersistedDream.d.ts +7 -0
  45. package/dist/types/src/helpers/DreamLogos/DreamLogos.d.ts +4 -0
  46. package/dist/types/src/helpers/DreamLogos/logos.d.ts +2 -0
  47. package/dist/types/src/helpers/areEqual.d.ts +1 -0
  48. package/dist/types/src/helpers/notEqual.d.ts +1 -0
  49. package/dist/types/src/index.d.ts +1 -1
  50. package/docs/assets/icons.js +1 -1
  51. package/docs/assets/icons.svg +1 -1
  52. package/docs/assets/main.js +1 -1
  53. package/docs/assets/navigation.js +1 -1
  54. package/docs/assets/search.js +1 -1
  55. package/docs/assets/style.css +21 -66
  56. package/docs/classes/Benchmark.html +2 -2
  57. package/docs/classes/CalendarDate.html +2 -2
  58. package/docs/classes/CreateOrFindByFailedToCreateAndFind.html +5 -6
  59. package/docs/classes/Decorators.html +38 -38
  60. package/docs/classes/Dream.html +131 -130
  61. package/docs/classes/DreamApplication.html +4 -4
  62. package/docs/classes/DreamBin.html +2 -2
  63. package/docs/classes/DreamCLI.html +4 -4
  64. package/docs/classes/DreamImporter.html +2 -2
  65. package/docs/classes/DreamLogos.html +4 -0
  66. package/docs/classes/DreamMigrationHelpers.html +7 -7
  67. package/docs/classes/DreamSerializer.html +2 -2
  68. package/docs/classes/DreamTransaction.html +2 -2
  69. package/docs/classes/Encrypt.html +2 -2
  70. package/docs/classes/Env.html +2 -2
  71. package/docs/classes/GlobalNameNotSet.html +5 -6
  72. package/docs/classes/NonLoadedAssociation.html +5 -6
  73. package/docs/classes/Query.html +50 -50
  74. package/docs/classes/Range.html +2 -2
  75. package/docs/classes/RecordNotFound.html +5 -6
  76. package/docs/classes/ValidationError.html +5 -6
  77. package/docs/functions/Attribute.html +1 -1
  78. package/docs/functions/RendersMany.html +1 -1
  79. package/docs/functions/RendersOne.html +1 -1
  80. package/docs/functions/ReplicaSafe.html +1 -1
  81. package/docs/functions/STI.html +1 -1
  82. package/docs/functions/SoftDelete.html +1 -1
  83. package/docs/functions/camelize.html +1 -1
  84. package/docs/functions/capitalize.html +1 -1
  85. package/docs/functions/closeAllDbConnections.html +1 -1
  86. package/docs/functions/compact.html +1 -1
  87. package/docs/functions/debug.html +1 -1
  88. package/docs/functions/dreamDbConnections.html +1 -1
  89. package/docs/functions/dreamPath.html +1 -1
  90. package/docs/functions/generateDream.html +1 -1
  91. package/docs/functions/globalClassNameFromFullyQualifiedModelName.html +1 -1
  92. package/docs/functions/hyphenize.html +1 -1
  93. package/docs/functions/inferSerializerFromDreamClassOrViewModelClass.html +1 -1
  94. package/docs/functions/inferSerializerFromDreamOrViewModel.html +1 -1
  95. package/docs/functions/isEmpty.html +1 -1
  96. package/docs/functions/loadRepl.html +1 -1
  97. package/docs/functions/lookupClassByGlobalName.html +1 -1
  98. package/docs/functions/pascalize.html +1 -1
  99. package/docs/functions/pgErrorType.html +1 -1
  100. package/docs/functions/range-1.html +1 -1
  101. package/docs/functions/relativeDreamPath.html +1 -1
  102. package/docs/functions/round.html +1 -1
  103. package/docs/functions/serializerNameFromFullyQualifiedModelName.html +1 -1
  104. package/docs/functions/sharedPathPrefix.html +1 -1
  105. package/docs/functions/snakeify.html +1 -1
  106. package/docs/functions/sort.html +1 -1
  107. package/docs/functions/sortBy.html +1 -1
  108. package/docs/functions/standardizeFullyQualifiedModelName.html +1 -1
  109. package/docs/functions/uncapitalize.html +1 -1
  110. package/docs/functions/uniq.html +1 -1
  111. package/docs/functions/untypedDb.html +1 -1
  112. package/docs/functions/validateColumn.html +1 -1
  113. package/docs/functions/validateTable.html +1 -1
  114. package/docs/index.html +7 -7
  115. package/docs/interfaces/AttributeStatement.html +2 -2
  116. package/docs/interfaces/DecoratorContext.html +2 -2
  117. package/docs/interfaces/DreamApplicationInitOptions.html +2 -2
  118. package/docs/interfaces/DreamApplicationOpts.html +2 -2
  119. package/docs/interfaces/DreamSerializerAssociationStatement.html +2 -2
  120. package/docs/interfaces/EncryptOptions.html +2 -2
  121. package/docs/interfaces/OpenapiSchemaProperties.html +1 -1
  122. package/docs/interfaces/OpenapiSchemaPropertiesShorthand.html +1 -1
  123. package/docs/interfaces/OpenapiTypeFieldObject.html +1 -1
  124. package/docs/modules.html +9 -9
  125. package/docs/types/Camelized.html +1 -1
  126. package/docs/types/CommonOpenapiSchemaObjectFields.html +1 -1
  127. package/docs/types/DateTime.html +1 -1
  128. package/docs/types/DbConnectionType.html +1 -1
  129. package/docs/types/DreamAssociationMetadata.html +1 -1
  130. package/docs/types/DreamAttributes.html +1 -1
  131. package/docs/types/DreamClassColumn.html +1 -1
  132. package/docs/types/DreamColumn.html +1 -1
  133. package/docs/types/DreamColumnNames.html +1 -1
  134. package/docs/types/DreamLogLevel.html +1 -1
  135. package/docs/types/DreamLogger.html +1 -1
  136. package/docs/types/DreamOrViewModelSerializerKey.html +1 -1
  137. package/docs/types/DreamParamSafeAttributes.html +1 -1
  138. package/docs/types/DreamParamSafeColumnNames.html +1 -1
  139. package/docs/types/DreamSerializerKey.html +1 -1
  140. package/docs/types/DreamSerializers.html +1 -1
  141. package/docs/types/DreamTableSchema.html +1 -1
  142. package/docs/types/DreamVirtualColumns.html +1 -1
  143. package/docs/types/EncryptAlgorithm.html +1 -1
  144. package/docs/types/Hyphenized.html +1 -1
  145. package/docs/types/IdType.html +1 -1
  146. package/docs/types/OpenapiAllTypes.html +1 -1
  147. package/docs/types/OpenapiFormats.html +1 -1
  148. package/docs/types/OpenapiNumberFormats.html +1 -1
  149. package/docs/types/OpenapiPrimitiveTypes.html +1 -1
  150. package/docs/types/OpenapiSchemaArray.html +1 -1
  151. package/docs/types/OpenapiSchemaArrayShorthand.html +1 -1
  152. package/docs/types/OpenapiSchemaBase.html +1 -1
  153. package/docs/types/OpenapiSchemaBody.html +1 -1
  154. package/docs/types/OpenapiSchemaBodyShorthand.html +1 -1
  155. package/docs/types/OpenapiSchemaCommonFields.html +1 -1
  156. package/docs/types/OpenapiSchemaExpressionAllOf.html +1 -1
  157. package/docs/types/OpenapiSchemaExpressionAnyOf.html +1 -1
  158. package/docs/types/OpenapiSchemaExpressionOneOf.html +1 -1
  159. package/docs/types/OpenapiSchemaExpressionRef.html +1 -1
  160. package/docs/types/OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
  161. package/docs/types/OpenapiSchemaInteger.html +1 -1
  162. package/docs/types/OpenapiSchemaNull.html +1 -1
  163. package/docs/types/OpenapiSchemaNumber.html +1 -1
  164. package/docs/types/OpenapiSchemaObject.html +1 -1
  165. package/docs/types/OpenapiSchemaObjectAllOf.html +1 -1
  166. package/docs/types/OpenapiSchemaObjectAllOfShorthand.html +1 -1
  167. package/docs/types/OpenapiSchemaObjectAnyOf.html +1 -1
  168. package/docs/types/OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  169. package/docs/types/OpenapiSchemaObjectBase.html +1 -1
  170. package/docs/types/OpenapiSchemaObjectBaseShorthand.html +1 -1
  171. package/docs/types/OpenapiSchemaObjectOneOf.html +1 -1
  172. package/docs/types/OpenapiSchemaObjectOneOfShorthand.html +1 -1
  173. package/docs/types/OpenapiSchemaObjectShorthand.html +1 -1
  174. package/docs/types/OpenapiSchemaPartialSegment.html +1 -1
  175. package/docs/types/OpenapiSchemaPrimitiveGeneric.html +1 -1
  176. package/docs/types/OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  177. package/docs/types/OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  178. package/docs/types/OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  179. package/docs/types/OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
  180. package/docs/types/OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
  181. package/docs/types/OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  182. package/docs/types/OpenapiSchemaString.html +1 -1
  183. package/docs/types/OpenapiShorthandAllTypes.html +1 -1
  184. package/docs/types/OpenapiShorthandPrimitiveTypes.html +1 -1
  185. package/docs/types/OpenapiTypeField.html +1 -1
  186. package/docs/types/Pascalized.html +1 -1
  187. package/docs/types/PrimaryKeyType.html +1 -1
  188. package/docs/types/RoundingPrecision.html +1 -1
  189. package/docs/types/SerializableClassOrSerializerCallback.html +1 -1
  190. package/docs/types/SerializableDreamClassOrViewModelClass.html +1 -1
  191. package/docs/types/SerializableDreamOrViewModel.html +1 -1
  192. package/docs/types/SerializableTypes.html +1 -1
  193. package/docs/types/Snakeified.html +1 -1
  194. package/docs/types/Timestamp.html +1 -1
  195. package/docs/types/UpdateableAssociationProperties.html +1 -1
  196. package/docs/types/UpdateableProperties.html +1 -1
  197. package/docs/types/ValidationType.html +1 -1
  198. package/docs/types/ViewModelSerializerKey.html +1 -1
  199. package/docs/types/WhereStatementForDream.html +1 -1
  200. package/docs/types/WhereStatementForDreamClass.html +1 -1
  201. package/docs/variables/DateTime-1.html +1 -1
  202. package/docs/variables/DreamConst.html +1 -1
  203. package/docs/variables/TRIGRAM_OPERATORS.html +1 -1
  204. package/docs/variables/openapiPrimitiveTypes-1.html +1 -1
  205. package/docs/variables/openapiShorthandPrimitiveTypes-1.html +1 -1
  206. package/docs/variables/ops.html +1 -1
  207. package/docs/variables/primaryKeyTypes.html +1 -1
  208. package/package.json +4 -4
  209. package/dist/cjs/src/dream/internal/safelyRunCommitHooks.js +0 -15
  210. package/dist/cjs/src/helpers/DreamGlam/DreamGlam.js +0 -16
  211. package/dist/cjs/src/helpers/DreamGlam/howyadoins/fluffstopherwalkin.js +0 -42
  212. package/dist/esm/src/dream/internal/safelyRunCommitHooks.js +0 -12
  213. package/dist/esm/src/helpers/DreamGlam/DreamGlam.js +0 -13
  214. package/dist/esm/src/helpers/DreamGlam/howyadoins/fluffstopherwalkin.js +0 -39
  215. package/dist/types/src/dream/internal/safelyRunCommitHooks.d.ts +0 -7
  216. package/dist/types/src/helpers/DreamGlam/DreamGlam.d.ts +0 -5
  217. package/dist/types/src/helpers/DreamGlam/howyadoins/fluffstopherwalkin.d.ts +0 -1
  218. package/dist/types/src/helpers/DreamGlam/howyadoins/whaaaaaaaaaaok.d.ts +0 -2
  219. package/docs/classes/DreamGlam.html +0 -5
@@ -24,7 +24,11 @@ import undestroyDream from './dream/internal/undestroyDream.js';
24
24
  import LeftJoinLoadBuilder from './dream/LeftJoinLoadBuilder.js';
25
25
  import LoadBuilder from './dream/LoadBuilder.js';
26
26
  import Query from './dream/Query.js';
27
+ import CannotAssociationQueryOnUnpersistedDream from './errors/associations/CannotAssociationQueryOnUnpersistedDream.js';
28
+ import CannotCreateAssociationOnUnpersistedDream from './errors/associations/CannotCreateAssociationOnUnpersistedDream.js';
29
+ import CannotDestroyAssociationOnUnpersistedDream from './errors/associations/CannotDestroyAssociationOnUnpersistedDream.js';
27
30
  import CannotPassNullOrUndefinedToRequiredBelongsTo from './errors/associations/CannotPassNullOrUndefinedToRequiredBelongsTo.js';
31
+ import CannotUpdateAssociationOnUnpersistedDream from './errors/associations/CannotUpdateAssociationOnUnpersistedDream.js';
28
32
  import CanOnlyPassBelongsToModelParam from './errors/associations/CanOnlyPassBelongsToModelParam.js';
29
33
  import NonLoadedAssociation from './errors/associations/NonLoadedAssociation.js';
30
34
  import CannotCallUndestroyOnANonSoftDeleteModel from './errors/CannotCallUndestroyOnANonSoftDeleteModel.js';
@@ -40,6 +44,7 @@ import { DateTime } from './helpers/DateTime.js';
40
44
  import cachedTypeForAttribute from './helpers/db/cachedTypeForAttribute.js';
41
45
  import isJsonColumn from './helpers/db/types/isJsonColumn.js';
42
46
  import inferSerializerFromDreamOrViewModel from './helpers/inferSerializerFromDreamOrViewModel.js';
47
+ import notEqual from './helpers/notEqual.js';
43
48
  import { isString } from './helpers/typechecks.js';
44
49
  export default class Dream {
45
50
  DB;
@@ -2243,13 +2248,8 @@ export default class Dream {
2243
2248
  this.constructor.columns().forEach(column => {
2244
2249
  const was = this.previousValueForAttribute(column);
2245
2250
  const now = this[column];
2246
- if (was !== now) {
2247
- ;
2248
- obj[column] = {
2249
- was,
2250
- now,
2251
- };
2252
- }
2251
+ if (notEqual(was, now))
2252
+ obj[column] = { was, now };
2253
2253
  });
2254
2254
  return obj;
2255
2255
  }
@@ -2283,7 +2283,7 @@ export default class Dream {
2283
2283
  * @returns Returns the previous value for an attribute
2284
2284
  */
2285
2285
  previousValueForAttribute(columnName) {
2286
- if (this.frozenAttributes[columnName] !== this[columnName])
2286
+ if (notEqual(this.frozenAttributes[columnName], this[columnName]))
2287
2287
  return this.frozenAttributes[columnName];
2288
2288
  return this.attributesFromBeforeLastSave[columnName];
2289
2289
  }
@@ -2299,7 +2299,7 @@ export default class Dream {
2299
2299
  const changes = this.changes();
2300
2300
  const now = changes?.[columnName]?.now;
2301
2301
  const was = changes?.[columnName]?.was;
2302
- return this.isPersisted && now !== was;
2302
+ return this.isPersisted && notEqual(now, was);
2303
2303
  }
2304
2304
  /**
2305
2305
  * Returns true if the columnName provided has
@@ -2482,7 +2482,12 @@ export default class Dream {
2482
2482
  * @returns A boolean
2483
2483
  */
2484
2484
  equals(other) {
2485
- return other?.constructor === this.constructor && other.primaryKeyValue === this.primaryKeyValue;
2485
+ if (!other?.isDreamInstance)
2486
+ return false;
2487
+ return this.comparisonKey === other.comparisonKey;
2488
+ }
2489
+ get comparisonKey() {
2490
+ return `${this.constructor.globalName}:${this.primaryKeyValue}`;
2486
2491
  }
2487
2492
  /**
2488
2493
  * @internal
@@ -2545,6 +2550,8 @@ export default class Dream {
2545
2550
  * @returns The created association
2546
2551
  */
2547
2552
  async createAssociation(associationName, attributes = {}) {
2553
+ if (this.isNewRecord)
2554
+ throw new CannotCreateAssociationOnUnpersistedDream(this, associationName);
2548
2555
  return createAssociation(this, null, associationName, attributes);
2549
2556
  }
2550
2557
  /**
@@ -2565,6 +2572,8 @@ export default class Dream {
2565
2572
  * @returns The number of records deleted
2566
2573
  */
2567
2574
  async destroyAssociation(associationName, options) {
2575
+ if (this.isNewRecord)
2576
+ throw new CannotDestroyAssociationOnUnpersistedDream(this, associationName);
2568
2577
  return await destroyAssociation(this, null, associationName, {
2569
2578
  ...destroyOptions(options),
2570
2579
  joinOnStatements: {
@@ -2597,6 +2606,8 @@ export default class Dream {
2597
2606
  * @returns The number of records deleted
2598
2607
  */
2599
2608
  async reallyDestroyAssociation(associationName, options) {
2609
+ if (this.isNewRecord)
2610
+ throw new CannotDestroyAssociationOnUnpersistedDream(this, associationName);
2600
2611
  return await destroyAssociation(this, null, associationName, {
2601
2612
  ...reallyDestroyOptions(options),
2602
2613
  joinOnStatements: {
@@ -2648,6 +2659,8 @@ export default class Dream {
2648
2659
  *
2649
2660
  */
2650
2661
  associationQuery(associationName, joinOnStatements) {
2662
+ if (this.isNewRecord)
2663
+ throw new CannotAssociationQueryOnUnpersistedDream(this, associationName);
2651
2664
  return associationQuery(this, null, associationName, {
2652
2665
  joinOnStatements: joinOnStatements,
2653
2666
  bypassAllDefaultScopes: DEFAULT_BYPASS_ALL_DEFAULT_SCOPES,
@@ -2677,6 +2690,8 @@ export default class Dream {
2677
2690
  * @returns The number of updated records
2678
2691
  */
2679
2692
  async updateAssociation(associationName, attributes, updateAssociationOptions) {
2693
+ if (this.isNewRecord)
2694
+ throw new CannotUpdateAssociationOnUnpersistedDream(this, associationName);
2680
2695
  return associationUpdateQuery(this, null, associationName, {
2681
2696
  joinOnStatements: {
2682
2697
  on: updateAssociationOptions?.on,
@@ -1,3 +1,7 @@
1
+ import CannotAssociationQueryOnUnpersistedDream from '../errors/associations/CannotAssociationQueryOnUnpersistedDream.js';
2
+ import CannotCreateAssociationOnUnpersistedDream from '../errors/associations/CannotCreateAssociationOnUnpersistedDream.js';
3
+ import CannotDestroyAssociationOnUnpersistedDream from '../errors/associations/CannotDestroyAssociationOnUnpersistedDream.js';
4
+ import CannotUpdateAssociationOnUnpersistedDream from '../errors/associations/CannotUpdateAssociationOnUnpersistedDream.js';
1
5
  import associationQuery from './internal/associations/associationQuery.js';
2
6
  import associationUpdateQuery from './internal/associations/associationUpdateQuery.js';
3
7
  import createAssociation from './internal/associations/createAssociation.js';
@@ -308,6 +312,8 @@ export default class DreamInstanceTransactionBuilder {
308
312
  * @returns A Query scoped to the specified association on the current instance
309
313
  */
310
314
  associationQuery(associationName, joinOnStatements) {
315
+ if (this.dreamInstance.isNewRecord)
316
+ throw new CannotAssociationQueryOnUnpersistedDream(this.dreamInstance, associationName);
311
317
  return associationQuery(this.dreamInstance, this.dreamTransaction, associationName, {
312
318
  joinOnStatements: joinOnStatements,
313
319
  bypassAllDefaultScopes: DEFAULT_BYPASS_ALL_DEFAULT_SCOPES,
@@ -339,6 +345,8 @@ export default class DreamInstanceTransactionBuilder {
339
345
  * @returns The number of updated records
340
346
  */
341
347
  async updateAssociation(associationName, attributes, updateAssociationOptions) {
348
+ if (this.dreamInstance.isNewRecord)
349
+ throw new CannotUpdateAssociationOnUnpersistedDream(this.dreamInstance, associationName);
342
350
  return await associationUpdateQuery(this.dreamInstance, this.dreamTransaction, associationName, {
343
351
  joinOnStatements: {
344
352
  on: updateAssociationOptions?.on,
@@ -365,6 +373,8 @@ export default class DreamInstanceTransactionBuilder {
365
373
  * @returns The created association
366
374
  */
367
375
  async createAssociation(associationName, opts = {}) {
376
+ if (this.dreamInstance.isNewRecord)
377
+ throw new CannotCreateAssociationOnUnpersistedDream(this.dreamInstance, associationName);
368
378
  return await createAssociation(this.dreamInstance, this.dreamTransaction, associationName, opts);
369
379
  }
370
380
  /**
@@ -387,6 +397,8 @@ export default class DreamInstanceTransactionBuilder {
387
397
  * @returns The number of records deleted
388
398
  */
389
399
  async destroyAssociation(associationName, options) {
400
+ if (this.dreamInstance.isNewRecord)
401
+ throw new CannotDestroyAssociationOnUnpersistedDream(this.dreamInstance, associationName);
390
402
  return await destroyAssociation(this.dreamInstance, this.dreamTransaction, associationName, {
391
403
  ...destroyOptions(options),
392
404
  joinOnStatements: {
@@ -421,6 +433,8 @@ export default class DreamInstanceTransactionBuilder {
421
433
  * @returns The number of records deleted
422
434
  */
423
435
  async reallyDestroyAssociation(associationName, options) {
436
+ if (this.dreamInstance.isNewRecord)
437
+ throw new CannotDestroyAssociationOnUnpersistedDream(this.dreamInstance, associationName);
424
438
  return await destroyAssociation(this.dreamInstance, this.dreamTransaction, associationName, {
425
439
  ...reallyDestroyOptions(options),
426
440
  joinOnStatements: {
@@ -1,6 +1,5 @@
1
1
  import destroyAssociatedRecords from './destroyAssociatedRecords.js';
2
2
  import runHooksFor from './runHooksFor.js';
3
- import safelyRunCommitHooks from './safelyRunCommitHooks.js';
4
3
  import softDeleteDream from './softDeleteDream.js';
5
4
  /**
6
5
  * @internal
@@ -39,7 +38,7 @@ async function destroyDreamWithTransaction(dream, txn, options) {
39
38
  await maybeDestroyDream(dream, txn, reallyDestroy);
40
39
  if (!skipHooks) {
41
40
  await runHooksFor('afterDestroy', dream, true, null, txn || undefined);
42
- await safelyRunCommitHooks(dream, 'afterDestroyCommit', true, null, txn);
41
+ await runHooksFor('afterDestroyCommit', dream, true, null, txn);
43
42
  }
44
43
  if (shouldSoftDelete(dream, reallyDestroy)) {
45
44
  await dream.txn(txn).reload();
@@ -1,47 +1,89 @@
1
1
  export default async function runHooksFor(key, dream, alreadyPersisted, beforeSaveChanges, txn) {
2
2
  const Base = dream.constructor;
3
- for (const statement of Base['hooks'][key]) {
4
- if (statement.ifChanging?.length) {
3
+ for (const hook of Base['hooks'][key]) {
4
+ if (hook.ifChanging?.length) {
5
5
  switch (key) {
6
6
  case 'beforeCreate':
7
- await runConditionalBeforeHooksForCreate(dream, statement, txn);
7
+ if (shouldRunBeforeCreateHook(dream, hook)) {
8
+ await runHook(hook, dream, txn);
9
+ }
8
10
  break;
9
11
  case 'beforeSave':
10
- if (alreadyPersisted)
11
- await runConditionalBeforeHooksForUpdate(dream, statement, txn);
12
- else
13
- await runConditionalBeforeHooksForCreate(dream, statement, txn);
12
+ if ((alreadyPersisted && shouldRunBeforeUpdateHook(dream, hook)) ||
13
+ (!alreadyPersisted && shouldRunBeforeCreateHook(dream, hook))) {
14
+ await runHook(hook, dream, txn);
15
+ }
14
16
  break;
15
17
  case 'beforeUpdate':
16
- await runConditionalBeforeHooksForUpdate(dream, statement, txn);
18
+ if (shouldRunBeforeUpdateHook(dream, hook)) {
19
+ await runHook(hook, dream, txn);
20
+ }
17
21
  break;
18
22
  default:
19
23
  throw new Error(`Unexpected statement key detected with ifChanging clause: ${key}`);
20
24
  }
21
25
  }
22
- else if (statement.ifChanged?.length) {
26
+ else if (hook.ifChanged?.length) {
23
27
  switch (key) {
24
28
  case 'afterCreate':
29
+ if (shouldRunAfterCreateHook(dream, hook, beforeSaveChanges)) {
30
+ await runHook(hook, dream, txn);
31
+ }
32
+ break;
25
33
  case 'afterCreateCommit':
26
- await runConditionalAfterHooksForCreate(dream, statement, beforeSaveChanges, txn);
34
+ if (shouldRunAfterCreateHook(dream, hook, beforeSaveChanges)) {
35
+ if (txn)
36
+ txn.addCommitHook(hook, dream);
37
+ else
38
+ await runHook(hook, dream);
39
+ }
27
40
  break;
28
41
  case 'afterSave':
42
+ if ((alreadyPersisted && shouldRunAfterUpdateHook(dream, hook)) ||
43
+ (!alreadyPersisted && shouldRunAfterCreateHook(dream, hook, beforeSaveChanges))) {
44
+ await runHook(hook, dream, txn);
45
+ }
46
+ break;
29
47
  case 'afterSaveCommit':
30
- if (alreadyPersisted)
31
- await runConditionalAfterHooksForUpdate(dream, statement, txn);
32
- else
33
- await runConditionalAfterHooksForCreate(dream, statement, beforeSaveChanges, txn);
48
+ if ((alreadyPersisted && shouldRunAfterUpdateHook(dream, hook)) ||
49
+ (!alreadyPersisted && shouldRunAfterCreateHook(dream, hook, beforeSaveChanges))) {
50
+ if (txn)
51
+ txn.addCommitHook(hook, dream);
52
+ else
53
+ await runHook(hook, dream);
54
+ }
34
55
  break;
35
56
  case 'afterUpdate':
57
+ if (shouldRunAfterUpdateHook(dream, hook)) {
58
+ await runHook(hook, dream, txn);
59
+ }
60
+ break;
36
61
  case 'afterUpdateCommit':
37
- await runConditionalAfterHooksForUpdate(dream, statement, txn);
62
+ if (shouldRunAfterUpdateHook(dream, hook)) {
63
+ if (txn)
64
+ txn.addCommitHook(hook, dream);
65
+ else
66
+ await runHook(hook, dream);
67
+ }
38
68
  break;
39
69
  default:
40
70
  throw new Error(`Unexpected statement key detected with ifChanged clause: ${key}`);
41
71
  }
42
72
  }
43
73
  else {
44
- await runHook(statement, dream, txn);
74
+ switch (key) {
75
+ case 'afterCreateCommit':
76
+ case 'afterSaveCommit':
77
+ case 'afterUpdateCommit':
78
+ case 'afterDestroyCommit':
79
+ if (txn)
80
+ txn.addCommitHook(hook, dream);
81
+ else
82
+ await runHook(hook, dream);
83
+ break;
84
+ default:
85
+ await runHook(hook, dream, txn);
86
+ }
45
87
  }
46
88
  }
47
89
  }
@@ -56,40 +98,36 @@ Please make sure "${statement.method}" is defined on ${dream['sanitizedConstruct
56
98
  }
57
99
  await dream[statement.method](txn);
58
100
  }
59
- async function runConditionalBeforeHooksForCreate(dream, statement, txn) {
101
+ function shouldRunBeforeCreateHook(dream, statement) {
60
102
  let shouldRun = false;
61
103
  for (const attribute of statement.ifChanging) {
62
104
  if (dream[attribute] !== undefined)
63
105
  shouldRun = true;
64
106
  }
65
- if (shouldRun)
66
- await runHook(statement, dream, txn);
107
+ return shouldRun;
67
108
  }
68
- async function runConditionalAfterHooksForCreate(dream, statement, beforeSaveChanges, txn) {
109
+ function shouldRunAfterCreateHook(dream, statement, beforeSaveChanges) {
69
110
  let shouldRun = false;
70
111
  for (const attribute of statement.ifChanged) {
71
112
  if (beforeSaveChanges?.[attribute] &&
72
113
  beforeSaveChanges[attribute].was !== beforeSaveChanges[attribute].now)
73
114
  shouldRun = true;
74
115
  }
75
- if (shouldRun)
76
- await runHook(statement, dream, txn);
116
+ return shouldRun;
77
117
  }
78
- async function runConditionalBeforeHooksForUpdate(dream, statement, txn) {
118
+ function shouldRunBeforeUpdateHook(dream, statement) {
79
119
  let shouldRun = false;
80
120
  for (const attribute of statement.ifChanging) {
81
121
  if (dream.willSaveChangeToAttribute(attribute))
82
122
  shouldRun = true;
83
123
  }
84
- if (shouldRun)
85
- await runHook(statement, dream, txn);
124
+ return shouldRun;
86
125
  }
87
- async function runConditionalAfterHooksForUpdate(dream, statement, txn) {
126
+ function shouldRunAfterUpdateHook(dream, statement) {
88
127
  let shouldRun = false;
89
128
  for (const attribute of statement.ifChanged) {
90
129
  if (dream.savedChangeToAttribute(attribute))
91
130
  shouldRun = true;
92
131
  }
93
- if (shouldRun)
94
- await runHook(statement, dream, txn);
132
+ return shouldRun;
95
133
  }
@@ -5,7 +5,6 @@ import namespaceColumn from '../../helpers/namespaceColumn.js';
5
5
  import sqlAttributes from '../../helpers/sqlAttributes.js';
6
6
  import executeDatabaseQuery from './executeDatabaseQuery.js';
7
7
  import runHooksFor from './runHooksFor.js';
8
- import safelyRunCommitHooks from './safelyRunCommitHooks.js';
9
8
  export default async function saveDream(dream, txn = null, { skipHooks = false } = {}) {
10
9
  const db = txn?.kyselyTransaction || _db('primary');
11
10
  const alreadyPersisted = dream.isPersisted;
@@ -56,9 +55,8 @@ export default async function saveDream(dream, txn = null, { skipHooks = false }
56
55
  await runHooksFor('afterUpdate', dream, alreadyPersisted, beforeSaveChanges, txn);
57
56
  else
58
57
  await runHooksFor('afterCreate', dream, alreadyPersisted, beforeSaveChanges, txn);
59
- const commitHookType = alreadyPersisted ? 'afterUpdateCommit' : 'afterCreateCommit';
60
- await safelyRunCommitHooks(dream, commitHookType, alreadyPersisted, beforeSaveChanges, txn);
61
- await safelyRunCommitHooks(dream, 'afterSaveCommit', alreadyPersisted, beforeSaveChanges, txn);
58
+ await runHooksFor(alreadyPersisted ? 'afterUpdateCommit' : 'afterCreateCommit', dream, alreadyPersisted, beforeSaveChanges, txn);
59
+ await runHooksFor('afterSaveCommit', dream, alreadyPersisted, beforeSaveChanges, txn);
62
60
  }
63
61
  return dream;
64
62
  }
@@ -1,6 +1,5 @@
1
1
  import { applySortableScopesToQuery } from '../../decorators/field/sortable/helpers/setPosition.js';
2
2
  import runHooksFor from './runHooksFor.js';
3
- import safelyRunCommitHooks from './safelyRunCommitHooks.js';
4
3
  /**
5
4
  * @internal
6
5
  *
@@ -38,7 +37,7 @@ async function undestroyDreamWithTransaction(dream, txn, options) {
38
37
  }
39
38
  if (!skipHooks) {
40
39
  await runHooksFor('afterUpdate', dream, true, null, txn);
41
- await safelyRunCommitHooks(dream, 'afterUpdateCommit', true, null, txn);
40
+ await runHooksFor('afterUpdateCommit', dream, true, null, txn);
42
41
  }
43
42
  await dream.txn(txn).reload();
44
43
  return dream;
@@ -0,0 +1,15 @@
1
+ export default class CannotAssociationQueryOnUnpersistedDream extends Error {
2
+ dream;
3
+ associationName;
4
+ constructor(dream, associationName) {
5
+ super();
6
+ this.dream = dream;
7
+ this.associationName = associationName;
8
+ }
9
+ get message() {
10
+ return `Cannot perform associationQuery on an unpersisted Dream.
11
+ Dream class: ${this.dream.sanitizedConstructorName}
12
+ Association: ${this.associationName.toString()}
13
+ `;
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ export default class CannotCreateAssociationOnUnpersistedDream extends Error {
2
+ dream;
3
+ associationName;
4
+ constructor(dream, associationName) {
5
+ super();
6
+ this.dream = dream;
7
+ this.associationName = associationName;
8
+ }
9
+ get message() {
10
+ return `Cannot perform createAssociation on an unpersisted Dream.
11
+ Dream class: ${this.dream.sanitizedConstructorName}
12
+ Association: ${this.associationName.toString()}
13
+ `;
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ export default class CannotDestroyAssociationOnUnpersistedDream extends Error {
2
+ dream;
3
+ associationName;
4
+ constructor(dream, associationName) {
5
+ super();
6
+ this.dream = dream;
7
+ this.associationName = associationName;
8
+ }
9
+ get message() {
10
+ return `Cannot perform destroyAssociation on an unpersisted Dream.
11
+ Dream class: ${this.dream.sanitizedConstructorName}
12
+ Association: ${this.associationName.toString()}
13
+ `;
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ export default class CannotUpdateAssociationOnUnpersistedDream extends Error {
2
+ dream;
3
+ associationName;
4
+ constructor(dream, associationName) {
5
+ super();
6
+ this.dream = dream;
7
+ this.associationName = associationName;
8
+ }
9
+ get message() {
10
+ return `Cannot perform updateAssociation on an unpersisted Dream.
11
+ Dream class: ${this.dream.sanitizedConstructorName}
12
+ Association: ${this.associationName.toString()}
13
+ `;
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ import colorfulLogo, { monochromeLogo } from './logos.js';
2
+ export default class DreamLogos {
3
+ static colorful() {
4
+ return colorfulLogo();
5
+ }
6
+ static monochrome() {
7
+ return monochromeLogo();
8
+ }
9
+ }
@@ -41,7 +41,7 @@ export default function whaaaaaaaaaaok() {
41
41
 
42
42
  `)));
43
43
  }
44
- export function whaaaaaaaaaaokBasic() {
44
+ export function monochromeLogo() {
45
45
  return `
46
46
  ,▄█▄
47
47
  ]█▄▄ ╓█████▌
@@ -0,0 +1,26 @@
1
+ import CalendarDate from './CalendarDate.js';
2
+ import { DateTime } from './DateTime.js';
3
+ export default function areEqual(a, b) {
4
+ return areEqualOrUndefined(a, b) ?? areEqualOrUndefined(b, a) ?? JSON.stringify(a) === JSON.stringify(b);
5
+ }
6
+ function areEqualOrUndefined(a, b) {
7
+ if (a === null)
8
+ return b === null;
9
+ if (a === undefined)
10
+ return b === undefined;
11
+ if (typeof a === 'boolean')
12
+ return a === b;
13
+ if (typeof a === 'number')
14
+ return a === b;
15
+ if (typeof a === 'string')
16
+ return a === b;
17
+ if (a instanceof DateTime)
18
+ return b instanceof DateTime && a.equals(b);
19
+ if (a instanceof CalendarDate)
20
+ return b instanceof CalendarDate && a.equals(b);
21
+ if (Array.isArray(a))
22
+ return Array.isArray(b) && a.length === b.length && !a.find((value, index) => !areEqual(value, b[index]));
23
+ if (a?.isDreamInstance)
24
+ return a.equals(b);
25
+ return undefined;
26
+ }
@@ -1,8 +1,8 @@
1
- import DreamGlam from '../DreamGlam/DreamGlam.js';
1
+ import DreamLogos from '../DreamLogos/DreamLogos.js';
2
2
  export default function autogeneratedFileDisclaimer(startComment = '\n/*', endComment = '\n*/') {
3
3
  return `\
4
4
  ${startComment}
5
- ${DreamGlam.whaaaaaaaaaaokBasic()}
5
+ ${DreamLogos.monochrome()}
6
6
 
7
7
  This file was automatically generated by my cat, Aster.
8
8
  He does not want you mucking about with his files,
@@ -75,7 +75,7 @@ public ${camelize(attributeName)}: ${getAttributeType(attribute, modelClassName)
75
75
  return `\
76
76
  import { ${uniq(dreamImports).join(', ')} } from '@rvoh/dream'${uniq(modelImportStatements).join('')}
77
77
 
78
- const deco = new Decorators<InstanceType<typeof ${modelClassName}>>()
78
+ const deco = new Decorators<typeof ${modelClassName}>()
79
79
 
80
80
  ${isSTI ? `\n@STI(${parentModelClassName})` : ''}
81
81
  export default class ${modelClassName} extends ${isSTI ? parentModelClassName : 'ApplicationModel'} {
@@ -86,7 +86,7 @@ ${isSTI
86
86
  }
87
87
 
88
88
  `}${serializer
89
- ? ` public get serializers(): DreamSerializers<${modelClassName}> {
89
+ ? ` public ${isSTI ? 'override ' : ''}get serializers(): DreamSerializers<${modelClassName}> {
90
90
  return {
91
91
  default: '${serializerNameFromFullyQualifiedModelName(fullyQualifiedModelName)}',
92
92
  summary: '${serializerNameFromFullyQualifiedModelName(fullyQualifiedModelName, 'summary')}',
@@ -29,13 +29,13 @@ export default function generateSerializerContent({ fullyQualifiedModelName, col
29
29
  Passthrough extends object,
30
30
  >`;
31
31
  dreamSerializerTypeArgs = `<DataType, Passthrough>`;
32
- const defaultSerialzerClassName = globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(fullyQualifiedModelName));
33
- const summarySerialzerClassName = globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(fullyQualifiedModelName, 'summary'));
32
+ const defaultSerialzerClassName = serializerNameFromFullyQualifiedModelName(fullyQualifiedModelNameToSerializerBaseName(fullyQualifiedModelName));
33
+ const summarySerialzerClassName = serializerNameFromFullyQualifiedModelName(fullyQualifiedModelNameToSerializerBaseName(fullyQualifiedModelName), 'summary');
34
34
  const defaultSerialzerExtends = isSTI
35
- ? globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(fullyQualifiedParentName))
35
+ ? serializerNameFromFullyQualifiedModelName(fullyQualifiedModelNameToSerializerBaseName(fullyQualifiedParentName))
36
36
  : summarySerialzerClassName;
37
37
  const summarySerialzerExtends = isSTI
38
- ? globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(fullyQualifiedParentName, 'summary'))
38
+ ? serializerNameFromFullyQualifiedModelName(fullyQualifiedModelNameToSerializerBaseName(fullyQualifiedParentName), 'summary')
39
39
  : 'DreamSerializer';
40
40
  const additionalModelImports = [];
41
41
  columnsWithTypes.forEach(attr => {
@@ -98,8 +98,16 @@ function attributeOptionsSpecifier(type, attr) {
98
98
  }
99
99
  }
100
100
  function importStatementForSerializer(originModelName, destinationModelName) {
101
- return `\nimport ${globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(destinationModelName))}, { ${globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(destinationModelName, 'summary'))} } from '${relativeDreamPath('serializers', 'serializers', originModelName, destinationModelName)}'`;
101
+ const defaultSerializer = globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(fullyQualifiedModelNameToSerializerBaseName(destinationModelName)));
102
+ const summarySerializer = globalClassNameFromFullyQualifiedModelName(serializerNameFromFullyQualifiedModelName(fullyQualifiedModelNameToSerializerBaseName(destinationModelName), 'summary'));
103
+ const importFrom = relativeDreamPath('serializers', 'serializers', originModelName, destinationModelName);
104
+ return `\nimport ${defaultSerializer}, { ${summarySerializer} } from '${importFrom}'`;
102
105
  }
103
106
  function importStatementForModel(originModelName, destinationModelName = originModelName) {
104
- return `\nimport ${globalClassNameFromFullyQualifiedModelName(destinationModelName)} from '${relativeDreamPath('serializers', 'models', originModelName, destinationModelName)}'`;
107
+ const modelName = globalClassNameFromFullyQualifiedModelName(destinationModelName);
108
+ const importFrom = relativeDreamPath('serializers', 'models', originModelName, destinationModelName);
109
+ return `\nimport ${modelName} from '${importFrom}'`;
110
+ }
111
+ function fullyQualifiedModelNameToSerializerBaseName(fullyQualifiedModelName) {
112
+ return fullyQualifiedModelName.split('/').pop() ?? '';
105
113
  }
@@ -0,0 +1,4 @@
1
+ import areEqual from './areEqual.js';
2
+ export default function (a, b) {
3
+ return !areEqual(a, b);
4
+ }
@@ -3,15 +3,14 @@ export default function uniq(arr, toKey = undefined) {
3
3
  return uniqWith(arr, toKey);
4
4
  return uniqWith(arr, a => String(a));
5
5
  }
6
- function dreamKey(dream) {
7
- return `${dream.constructor.globalName}:${dream.primaryKeyValue}`;
8
- }
9
6
  function uniqWith(arr, toKey) {
10
7
  const map = arr.reduce((acc, val) => {
11
8
  // Prefix with underscore to ensure that the values cannot be interpreted as integers.
12
9
  // If they can be interpreted as integers, then the keys are ordered not by the
13
10
  // order in which they were added, but in ascending numerical order.
14
- const key = val?.isDreamInstance ? dreamKey(val) : `_${toKey(val)}`;
11
+ const key = val?.isDreamInstance
12
+ ? val.comparisonKey
13
+ : `_${toKey(val)}`;
15
14
  acc[key] ||= val;
16
15
  return acc;
17
16
  }, {});
@@ -31,7 +31,7 @@ export { default as generateDream } from './helpers/cli/generateDream.js';
31
31
  export { default as compact } from './helpers/compact.js';
32
32
  export { DateTime } from './helpers/DateTime.js';
33
33
  export { default as debug } from './helpers/debug.js';
34
- export { default as DreamGlam } from './helpers/DreamGlam/DreamGlam.js';
34
+ export { default as DreamLogos } from './helpers/DreamLogos/DreamLogos.js';
35
35
  export { default as Env } from './helpers/Env.js';
36
36
  export { default as globalClassNameFromFullyQualifiedModelName } from './helpers/globalClassNameFromFullyQualifiedModelName.js';
37
37
  export { default as hyphenize } from './helpers/hyphenize.js';
@@ -1892,6 +1892,7 @@ export default class Dream {
1892
1892
  * @returns A boolean
1893
1893
  */
1894
1894
  equals(other: any): boolean;
1895
+ get comparisonKey(): string;
1895
1896
  /**
1896
1897
  * @internal
1897
1898
  *