@rvoh/dream 2.5.8 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/dist/cjs/src/Dream.js +12 -56
  2. package/dist/cjs/src/dream/LoadBuilder.js +55 -0
  3. package/dist/cjs/src/dream/Query.js +4 -5
  4. package/dist/cjs/src/dream/constants.js +2 -0
  5. package/dist/cjs/src/dream/internal/buildAssociationPaths.js +33 -0
  6. package/dist/cjs/src/dream/internal/buildDependentDestroyPreloadPaths.js +43 -0
  7. package/dist/cjs/src/dream/internal/buildSerializerPreloadPaths.js +38 -0
  8. package/dist/cjs/src/dream/internal/destroyAssociatedRecords.js +14 -6
  9. package/dist/cjs/src/dream/internal/destroyDream.js +7 -1
  10. package/dist/cjs/src/dream/internal/loadDependentDestroyTree.js +35 -0
  11. package/dist/cjs/src/dream/internal/resolveSerializerAssociationEdges.js +53 -0
  12. package/dist/cjs/src/serializer/SerializerRenderer.js +1 -1
  13. package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +4 -0
  14. package/dist/cjs/src/types/recursiveSerialization.js +1 -0
  15. package/dist/esm/src/Dream.js +12 -56
  16. package/dist/esm/src/dream/LoadBuilder.js +55 -0
  17. package/dist/esm/src/dream/Query.js +4 -5
  18. package/dist/esm/src/dream/constants.js +2 -0
  19. package/dist/esm/src/dream/internal/buildAssociationPaths.js +33 -0
  20. package/dist/esm/src/dream/internal/buildDependentDestroyPreloadPaths.js +43 -0
  21. package/dist/esm/src/dream/internal/buildSerializerPreloadPaths.js +38 -0
  22. package/dist/esm/src/dream/internal/destroyAssociatedRecords.js +14 -6
  23. package/dist/esm/src/dream/internal/destroyDream.js +7 -1
  24. package/dist/esm/src/dream/internal/loadDependentDestroyTree.js +35 -0
  25. package/dist/esm/src/dream/internal/resolveSerializerAssociationEdges.js +53 -0
  26. package/dist/esm/src/serializer/SerializerRenderer.js +1 -1
  27. package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +4 -0
  28. package/dist/esm/src/types/recursiveSerialization.js +1 -0
  29. package/dist/types/src/dream/LoadBuilder.d.ts +48 -1
  30. package/dist/types/src/dream/constants.d.ts +2 -0
  31. package/dist/types/src/dream/internal/buildAssociationPaths.d.ts +12 -0
  32. package/dist/types/src/dream/internal/buildDependentDestroyPreloadPaths.d.ts +17 -0
  33. package/dist/types/src/dream/internal/buildSerializerPreloadPaths.d.ts +3 -0
  34. package/dist/types/src/dream/internal/convertDreamClassAndAssociationNameTupleArrayToPreloadArgs.d.ts +1 -1
  35. package/dist/types/src/dream/internal/destroyAssociatedRecords.d.ts +5 -1
  36. package/dist/types/src/dream/internal/loadDependentDestroyTree.d.ts +17 -0
  37. package/dist/types/src/dream/internal/resolveSerializerAssociationEdges.d.ts +13 -0
  38. package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +13 -4
  39. package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +3 -2
  40. package/dist/types/src/types/recursiveSerialization.d.ts +8 -0
  41. package/dist/types/src/types/recursiveSerialization.ts +10 -0
  42. package/dist/types/src/types/serializer.d.ts +8 -1
  43. package/dist/types/src/types/serializer.ts +8 -1
  44. package/docs/classes/db.DreamMigrationHelpers.html +9 -9
  45. package/docs/classes/db.KyselyQueryDriver.html +32 -32
  46. package/docs/classes/db.PostgresQueryDriver.html +33 -33
  47. package/docs/classes/db.QueryDriverBase.html +31 -31
  48. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  49. package/docs/classes/errors.ColumnOverflow.html +3 -3
  50. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  51. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  52. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  53. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  54. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  55. package/docs/classes/errors.InvalidClockTime.html +2 -2
  56. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  57. package/docs/classes/errors.InvalidDateTime.html +2 -2
  58. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  59. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  60. package/docs/classes/errors.NotNullViolation.html +3 -3
  61. package/docs/classes/errors.RecordNotFound.html +3 -3
  62. package/docs/classes/errors.ValidationError.html +3 -3
  63. package/docs/classes/index.CalendarDate.html +33 -33
  64. package/docs/classes/index.ClockTime.html +32 -32
  65. package/docs/classes/index.ClockTimeTz.html +35 -35
  66. package/docs/classes/index.DateTime.html +86 -86
  67. package/docs/classes/index.Decorators.html +19 -19
  68. package/docs/classes/index.Dream.html +118 -118
  69. package/docs/classes/index.DreamApp.html +5 -5
  70. package/docs/classes/index.DreamTransaction.html +2 -2
  71. package/docs/classes/index.Env.html +2 -2
  72. package/docs/classes/index.Query.html +56 -56
  73. package/docs/classes/system.CliFileWriter.html +4 -4
  74. package/docs/classes/system.DreamBin.html +2 -2
  75. package/docs/classes/system.DreamCLI.html +6 -6
  76. package/docs/classes/system.DreamImporter.html +2 -2
  77. package/docs/classes/system.DreamLogos.html +2 -2
  78. package/docs/classes/system.DreamSerializerBuilder.html +19 -15
  79. package/docs/classes/system.ObjectSerializerBuilder.html +10 -10
  80. package/docs/classes/system.PathHelpers.html +3 -3
  81. package/docs/classes/utils.Encrypt.html +2 -2
  82. package/docs/classes/utils.Range.html +2 -2
  83. package/docs/functions/db.closeAllDbConnections.html +1 -1
  84. package/docs/functions/db.dreamDbConnections.html +1 -1
  85. package/docs/functions/db.untypedDb.html +1 -1
  86. package/docs/functions/db.validateColumn.html +1 -1
  87. package/docs/functions/db.validateTable.html +1 -1
  88. package/docs/functions/errors.pgErrorType.html +1 -1
  89. package/docs/functions/index.DreamSerializer.html +1 -1
  90. package/docs/functions/index.ObjectSerializer.html +1 -1
  91. package/docs/functions/index.ReplicaSafe.html +1 -1
  92. package/docs/functions/index.STI.html +1 -1
  93. package/docs/functions/index.SoftDelete.html +1 -1
  94. package/docs/functions/utils.camelize.html +1 -1
  95. package/docs/functions/utils.capitalize.html +1 -1
  96. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  97. package/docs/functions/utils.compact.html +1 -1
  98. package/docs/functions/utils.groupBy.html +1 -1
  99. package/docs/functions/utils.hyphenize.html +1 -1
  100. package/docs/functions/utils.intersection.html +1 -1
  101. package/docs/functions/utils.isEmpty.html +1 -1
  102. package/docs/functions/utils.normalizeUnicode.html +1 -1
  103. package/docs/functions/utils.pascalize.html +1 -1
  104. package/docs/functions/utils.percent.html +1 -1
  105. package/docs/functions/utils.range.html +1 -1
  106. package/docs/functions/utils.round.html +1 -1
  107. package/docs/functions/utils.sanitizeString.html +1 -1
  108. package/docs/functions/utils.snakeify.html +1 -1
  109. package/docs/functions/utils.sort.html +1 -1
  110. package/docs/functions/utils.sortBy.html +1 -1
  111. package/docs/functions/utils.sortObjectByKey.html +1 -1
  112. package/docs/functions/utils.sortObjectByValue.html +1 -1
  113. package/docs/functions/utils.uncapitalize.html +1 -1
  114. package/docs/functions/utils.uniq.html +1 -1
  115. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  116. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  117. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  118. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  119. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  120. package/docs/interfaces/types.DecoratorContext.html +2 -2
  121. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  122. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  123. package/docs/interfaces/types.DurationObject.html +2 -2
  124. package/docs/interfaces/types.EncryptOptions.html +2 -2
  125. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  126. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  127. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  128. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  129. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  130. package/docs/types/openapi.OpenapiFormats.html +1 -1
  131. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  132. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  133. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  134. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  135. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  136. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  137. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  138. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  139. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  140. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
  141. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
  142. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
  143. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  144. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  145. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  146. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  147. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  153. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  154. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  155. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  156. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  157. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  158. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  159. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
  160. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
  161. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
  162. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  163. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  164. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  165. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  166. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  167. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  168. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  169. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  170. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  171. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  172. package/docs/types/types.CalendarDateObject.html +1 -1
  173. package/docs/types/types.Camelized.html +1 -1
  174. package/docs/types/types.ClockTimeObject.html +1 -1
  175. package/docs/types/types.DbConnectionType.html +1 -1
  176. package/docs/types/types.DbTypes.html +1 -1
  177. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  178. package/docs/types/types.DreamAttributes.html +1 -1
  179. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  180. package/docs/types/types.DreamClassColumn.html +1 -1
  181. package/docs/types/types.DreamColumn.html +1 -1
  182. package/docs/types/types.DreamColumnNames.html +1 -1
  183. package/docs/types/types.DreamLogLevel.html +1 -1
  184. package/docs/types/types.DreamLogger.html +2 -2
  185. package/docs/types/types.DreamModelSerializerType.html +1 -1
  186. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  187. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  188. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  189. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  190. package/docs/types/types.DreamSerializable.html +1 -1
  191. package/docs/types/types.DreamSerializableArray.html +1 -1
  192. package/docs/types/types.DreamSerializerKey.html +1 -1
  193. package/docs/types/types.DreamSerializers.html +1 -1
  194. package/docs/types/types.DreamVirtualColumns.html +1 -1
  195. package/docs/types/types.DurationUnit.html +1 -1
  196. package/docs/types/types.EncryptAlgorithm.html +1 -1
  197. package/docs/types/types.HasManyStatement.html +1 -1
  198. package/docs/types/types.HasOneStatement.html +1 -1
  199. package/docs/types/types.Hyphenized.html +1 -1
  200. package/docs/types/types.Pascalized.html +1 -1
  201. package/docs/types/types.PrimaryKeyType.html +1 -1
  202. package/docs/types/types.RoundingPrecision.html +1 -1
  203. package/docs/types/types.SerializerCasing.html +1 -1
  204. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  205. package/docs/types/types.Snakeified.html +1 -1
  206. package/docs/types/types.StrictInterface.html +1 -1
  207. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  208. package/docs/types/types.UpdateableProperties.html +1 -1
  209. package/docs/types/types.ValidationType.html +1 -1
  210. package/docs/types/types.ViewModel.html +2 -2
  211. package/docs/types/types.ViewModelClass.html +1 -1
  212. package/docs/types/types.WeekdayName.html +1 -1
  213. package/docs/types/types.WhereStatementForDream.html +1 -1
  214. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  215. package/docs/variables/index.DreamConst.html +1 -1
  216. package/docs/variables/index.ops.html +1 -1
  217. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  218. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  219. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  220. package/docs/variables/system.primaryKeyTypes.html +1 -1
  221. package/package.json +1 -1
  222. package/dist/cjs/src/dream/internal/extractNestedPaths.js +0 -34
  223. package/dist/esm/src/dream/internal/extractNestedPaths.js +0 -34
  224. package/dist/types/src/dream/internal/extractNestedPaths.d.ts +0 -21
@@ -24,6 +24,61 @@ export default class LoadBuilder {
24
24
  this.query = this.query.passthrough(passthroughWhereStatement);
25
25
  return this;
26
26
  }
27
+ /**
28
+ * Prevents a specific default scope from applying when
29
+ * loading associations
30
+ *
31
+ * ```ts
32
+ * const user = await User.firstOrFail()
33
+ * const loaded = await user
34
+ * .load('posts')
35
+ * .removeDefaultScope('dream:SoftDelete')
36
+ * .execute()
37
+ * ```
38
+ *
39
+ * @param scopeName - The default scope to bypass
40
+ * @returns The LoadBuilder instance for chaining
41
+ */
42
+ removeDefaultScope(scopeName) {
43
+ this.query = this.query.removeDefaultScope(scopeName);
44
+ return this;
45
+ }
46
+ /**
47
+ * Prevents all default scopes from applying when
48
+ * loading associations
49
+ *
50
+ * ```ts
51
+ * const user = await User.firstOrFail()
52
+ * const loaded = await user
53
+ * .load('posts')
54
+ * .removeAllDefaultScopes()
55
+ * .execute()
56
+ * ```
57
+ *
58
+ * @returns The LoadBuilder instance for chaining
59
+ */
60
+ removeAllDefaultScopes() {
61
+ this.query = this.query.removeAllDefaultScopes();
62
+ return this;
63
+ }
64
+ /**
65
+ * Sets the database connection to use when loading associations
66
+ *
67
+ * ```ts
68
+ * const user = await User.firstOrFail()
69
+ * const loaded = await user
70
+ * .load('posts')
71
+ * .connection('replica')
72
+ * .execute()
73
+ * ```
74
+ *
75
+ * @param connection - The connection type ('primary' or 'replica')
76
+ * @returns The LoadBuilder instance for chaining
77
+ */
78
+ connection(connection) {
79
+ this.query = this.query.connection(connection);
80
+ return this;
81
+ }
27
82
  /**
28
83
  * Attaches a load statement to the load builder
29
84
  *
@@ -17,10 +17,10 @@ import namespaceColumn from '../helpers/namespaceColumn.js';
17
17
  import protectAgainstPollutingAssignment from '../helpers/protectAgainstPollutingAssignment.js';
18
18
  import { toSafeObject } from '../helpers/toSafeObject.js';
19
19
  import ops from '../ops/index.js';
20
+ import buildSerializerPreloadPaths from './internal/buildSerializerPreloadPaths.js';
20
21
  import computedPaginatePage from './internal/computedPaginatePage.js';
21
22
  import convertDreamClassAndAssociationNameTupleArrayToPreloadArgs from './internal/convertDreamClassAndAssociationNameTupleArrayToPreloadArgs.js';
22
- import extractNestedPaths from './internal/extractNestedPaths.js';
23
- // Cache for extractNestedPaths results, keyed by "${sanitizedName}:${serializerKey}"
23
+ // Cache for serializer preload-path results, keyed by "${globalName}:${serializerKey}"
24
24
  const extractedNestedPathsCache = new Map();
25
25
  export default class Query {
26
26
  /**
@@ -526,11 +526,10 @@ export default class Query {
526
526
  * @returns A Query with all serialization associations preloaded
527
527
  */
528
528
  preloadFor(serializerKey, modifierFn) {
529
- const cacheKey = `${this.dreamClass.sanitizedName}:${serializerKey ?? 'default'}`;
529
+ const cacheKey = `${this.dreamClass.globalName}:${serializerKey ?? 'default'}`;
530
530
  let preloadArgs = extractedNestedPathsCache.get(cacheKey);
531
531
  if (!preloadArgs) {
532
- // Cache miss - compute and store
533
- preloadArgs = extractNestedPaths(this.dreamClass['serializationMap'](serializerKey));
532
+ preloadArgs = buildSerializerPreloadPaths(this.dreamClass, serializerKey);
534
533
  extractedNestedPathsCache.set(cacheKey, preloadArgs);
535
534
  }
536
535
  let query = this;
@@ -1,5 +1,7 @@
1
1
  export const primaryKeyTypes = ['uuid7', 'uuid4', 'bigserial', 'bigint', 'integer'];
2
2
  export const TRIGRAM_OPERATORS = ['%', '<%', '<<%'];
3
+ export const RECURSIVE_SERIALIZATION_MAX_REPEATS = 4;
4
+ export const RECURSIVE_DESTROY_PRELOAD_MAX_REPEATS = RECURSIVE_SERIALIZATION_MAX_REPEATS;
3
5
  class RequiredAttribute {
4
6
  constructor() { }
5
7
  }
@@ -0,0 +1,33 @@
1
+ export default function buildAssociationPaths(rootNode, opts) {
2
+ const paths = [];
3
+ traverseAssociationPaths(rootNode, [], {}, paths, opts);
4
+ return paths;
5
+ }
6
+ function traverseAssociationPaths(node, currentPath, depthTracker, paths, opts) {
7
+ const trackerId = opts.getKey(node);
8
+ depthTracker[trackerId] ??= 0;
9
+ if (depthTracker[trackerId] + 1 > opts.maxRepeats) {
10
+ if (currentPath.length > 0) {
11
+ paths.push([...currentPath]);
12
+ }
13
+ return;
14
+ }
15
+ depthTracker[trackerId]++;
16
+ const edges = opts.getEdges(node);
17
+ if (edges.length === 0) {
18
+ if (currentPath.length > 0) {
19
+ paths.push([...currentPath]);
20
+ }
21
+ depthTracker[trackerId]--;
22
+ return;
23
+ }
24
+ for (const edge of edges) {
25
+ const newPath = [...currentPath, edge.tuple];
26
+ if (!edge.nextNode) {
27
+ paths.push(newPath);
28
+ continue;
29
+ }
30
+ traverseAssociationPaths(edge.nextNode, newPath, depthTracker, paths, opts);
31
+ }
32
+ depthTracker[trackerId]--;
33
+ }
@@ -0,0 +1,43 @@
1
+ import { RECURSIVE_DESTROY_PRELOAD_MAX_REPEATS } from '../constants.js';
2
+ import buildAssociationPaths from './buildAssociationPaths.js';
3
+ const dependentDestroyPreloadPathsCache = new Map();
4
+ /**
5
+ * @internal
6
+ *
7
+ * Recursively walks `dependent: 'destroy'` associations starting from the given
8
+ * Dream class, producing an array of preload paths. Each path is an array of
9
+ * [DreamClass, associationName] tuples representing a chain from root to leaf.
10
+ *
11
+ * Allows the same Dream class to appear up to MAX_REPEATS times in a single
12
+ * path to support tree structures (e.g. a Category with `dependent: 'destroy'`
13
+ * on its children, which are also Categories).
14
+ *
15
+ * Used to build a preload tree so that all records in the cascade can be loaded
16
+ * upfront, eliminating N+1 queries during destroy.
17
+ */
18
+ export default function buildDependentDestroyPreloadPaths(dreamClass) {
19
+ const cacheKey = dreamClass.globalName;
20
+ const cached = dependentDestroyPreloadPathsCache.get(cacheKey);
21
+ if (cached)
22
+ return cached;
23
+ const paths = [];
24
+ paths.push(...buildAssociationPaths(dreamClass, {
25
+ getKey: currentDreamClass => currentDreamClass.globalName,
26
+ getEdges: currentDreamClass => {
27
+ const associationMap = currentDreamClass['associationMetadataMap']();
28
+ const dependentDestroyNames = Object.keys(associationMap).filter(key => associationMap[key].dependent === 'destroy');
29
+ return dependentDestroyNames.flatMap(associationName => {
30
+ const association = associationMap[associationName];
31
+ const modelCBResult = association.modelCB();
32
+ const targetClasses = Array.isArray(modelCBResult) ? modelCBResult : [modelCBResult];
33
+ return targetClasses.map(targetClass => ({
34
+ nextNode: targetClass,
35
+ tuple: [currentDreamClass, associationName],
36
+ }));
37
+ });
38
+ },
39
+ maxRepeats: RECURSIVE_DESTROY_PRELOAD_MAX_REPEATS,
40
+ }));
41
+ dependentDestroyPreloadPathsCache.set(cacheKey, paths);
42
+ return paths;
43
+ }
@@ -0,0 +1,38 @@
1
+ import { inferSerializersFromDreamClassOrViewModelClass } from '../../serializer/helpers/inferSerializerFromDreamOrViewModel.js';
2
+ import { RECURSIVE_SERIALIZATION_MAX_REPEATS } from '../constants.js';
3
+ import buildAssociationPaths from './buildAssociationPaths.js';
4
+ import resolveSerializerAssociationEdges from './resolveSerializerAssociationEdges.js';
5
+ export default function buildSerializerPreloadPaths(dreamClass, serializerKey) {
6
+ const key = serializerKey || 'default';
7
+ const serializer = inferSerializersFromDreamClassOrViewModelClass(dreamClass, key)[0] ?? null;
8
+ if (!serializer)
9
+ throw new Error(`unable to find serializer with key: ${key}`);
10
+ const paths = buildAssociationPaths({
11
+ dreamClass,
12
+ serializer,
13
+ }, {
14
+ getKey: node => node.dreamClass.globalName,
15
+ getEdges: serializerNodeToEdges,
16
+ maxRepeats: RECURSIVE_SERIALIZATION_MAX_REPEATS,
17
+ });
18
+ const dedupedPaths = new Map();
19
+ for (const path of paths) {
20
+ dedupedPaths.set(path
21
+ .map(([pathDreamClass, associationName]) => `${pathDreamClass.globalName}:${associationName}`)
22
+ .join('|'), path);
23
+ }
24
+ return [...dedupedPaths.values()];
25
+ }
26
+ function serializerNodeToEdges({ dreamClass, serializer, }) {
27
+ const edges = resolveSerializerAssociationEdges(dreamClass, serializer);
28
+ return edges.flatMap(edge => {
29
+ const tuple = [dreamClass, edge.associationAs];
30
+ if (edge.type === 'delegatedAttribute' || edge.targets.length === 0) {
31
+ return [{ nextNode: null, tuple }];
32
+ }
33
+ return edge.targets.map(target => ({
34
+ nextNode: target,
35
+ tuple,
36
+ }));
37
+ });
38
+ }
@@ -2,17 +2,25 @@
2
2
  * @internal
3
3
  *
4
4
  * Destroys all HasOne/HasMany associations on this
5
- * dream that are marked as `dependent: 'destroy'`
5
+ * dream that are marked as `dependent: 'destroy'`.
6
+ *
7
+ * Expects associations to be preloaded onto the dream instance
8
+ * via `loadDependentDestroyTree`. Iterates loaded associations
9
+ * directly instead of querying the database.
6
10
  */
7
11
  export default async function destroyAssociatedRecords(dream, txn, options) {
8
12
  const dreamClass = dream.constructor;
9
13
  const { reallyDestroy } = options;
10
14
  for (const associationName of dreamClass['dependentDestroyAssociationNames']()) {
11
- if (reallyDestroy) {
12
- await dream.txn(txn).reallyDestroyAssociation(associationName, options);
13
- }
14
- else {
15
- await dream.txn(txn).destroyAssociation(associationName, options);
15
+ const loaded = dream[associationName];
16
+ const records = Array.isArray(loaded) ? loaded : loaded ? [loaded] : [];
17
+ for (const record of records) {
18
+ if (reallyDestroy) {
19
+ await record.txn(txn).reallyDestroy(options);
20
+ }
21
+ else {
22
+ await record.txn(txn).destroy(options);
23
+ }
16
24
  }
17
25
  }
18
26
  }
@@ -1,5 +1,6 @@
1
1
  import DreamApp from '../../dream-app/index.js';
2
2
  import destroyAssociatedRecords from './destroyAssociatedRecords.js';
3
+ import loadDependentDestroyTree from './loadDependentDestroyTree.js';
3
4
  import runHooksFor from './runHooksFor.js';
4
5
  /**
5
6
  * @internal
@@ -30,7 +31,12 @@ export default async function destroyDream(dream, txn = null, options) {
30
31
  async function destroyDreamWithTransaction(dream, txn, options) {
31
32
  const { cascade, reallyDestroy, skipHooks } = options;
32
33
  if (cascade) {
33
- await destroyAssociatedRecords(dream, txn, options);
34
+ const dreamWithAssociations = await loadDependentDestroyTree(dream, txn, {
35
+ reallyDestroy,
36
+ bypassAllDefaultScopes: options.bypassAllDefaultScopes ?? false,
37
+ defaultScopesToBypass: options.defaultScopesToBypass ?? [],
38
+ });
39
+ await destroyAssociatedRecords(dreamWithAssociations, txn, options);
34
40
  }
35
41
  if (!skipHooks) {
36
42
  await runHooksFor('beforeDestroy', dream, true, null, txn);
@@ -0,0 +1,35 @@
1
+ import LoadBuilder from '../LoadBuilder.js';
2
+ import buildDependentDestroyPreloadPaths from './buildDependentDestroyPreloadPaths.js';
3
+ import convertDreamClassAndAssociationNameTupleArrayToPreloadArgs from './convertDreamClassAndAssociationNameTupleArrayToPreloadArgs.js';
4
+ /**
5
+ * @internal
6
+ *
7
+ * Loads all `dependent: 'destroy'` associations onto the dream instance
8
+ * upfront, eliminating N+1 queries during cascade destruction.
9
+ *
10
+ * Returns a clone of the dream with all associations loaded.
11
+ * If there are no dependent-destroy associations, returns the original dream.
12
+ */
13
+ export default async function loadDependentDestroyTree(dream, txn, { reallyDestroy, bypassAllDefaultScopes, defaultScopesToBypass, }) {
14
+ const dreamClass = dream.constructor;
15
+ const paths = buildDependentDestroyPreloadPaths(dreamClass);
16
+ if (paths.length === 0)
17
+ return dream;
18
+ let loadBuilder = new LoadBuilder(dream, txn);
19
+ for (const path of paths) {
20
+ const args = convertDreamClassAndAssociationNameTupleArrayToPreloadArgs(path);
21
+ loadBuilder = loadBuilder.load(...args);
22
+ }
23
+ if (bypassAllDefaultScopes) {
24
+ loadBuilder = loadBuilder.removeAllDefaultScopes();
25
+ }
26
+ else {
27
+ for (const scopeName of defaultScopesToBypass) {
28
+ loadBuilder = loadBuilder.removeDefaultScope(scopeName);
29
+ }
30
+ }
31
+ if (reallyDestroy) {
32
+ loadBuilder = loadBuilder.removeDefaultScope('dream:SoftDelete');
33
+ }
34
+ return await loadBuilder.execute();
35
+ }
@@ -0,0 +1,53 @@
1
+ import MissingSerializersDefinition from '../../errors/serializers/MissingSerializersDefinition.js';
2
+ import compact from '../../helpers/compact.js';
3
+ import { inferSerializersFromDreamClassOrViewModelClass } from '../../serializer/helpers/inferSerializerFromDreamOrViewModel.js';
4
+ export default function resolveSerializerAssociationEdges(dreamClass, serializer) {
5
+ const serializerBuilder = serializer(undefined, undefined);
6
+ const serializerAssociations = serializerBuilder['attributes'].filter(attribute => ['rendersOne', 'rendersMany', 'delegatedAttribute'].includes(attribute.type));
7
+ return compact(serializerAssociations.map(serializerAssociation => {
8
+ const serializerAssociationName = serializerAssociation.targetName ??
9
+ serializerAssociation.name;
10
+ const association = dreamClass['getAssociationMetadata'](serializerAssociationName);
11
+ if (!association)
12
+ return null;
13
+ if (serializerAssociation.type === 'delegatedAttribute') {
14
+ return {
15
+ associationAs: association.as,
16
+ sourceDreamClass: dreamClass,
17
+ type: serializerAssociation.type,
18
+ serializerAssociationName,
19
+ targets: [],
20
+ };
21
+ }
22
+ const maybeAssociatedClasses = association.modelCB();
23
+ if (!maybeAssociatedClasses)
24
+ throw new Error(`No class defined on ${serializerAssociationName} association on ${dreamClass.sanitizedName}`);
25
+ const associatedClasses = Array.isArray(maybeAssociatedClasses)
26
+ ? maybeAssociatedClasses
27
+ : [maybeAssociatedClasses];
28
+ const targets = associatedClasses.flatMap(associatedClass => {
29
+ let serializers = [];
30
+ try {
31
+ serializers = serializerAssociation.options.serializer
32
+ ? compact([serializerAssociation.options.serializer])
33
+ : compact(inferSerializersFromDreamClassOrViewModelClass(associatedClass, serializerAssociation.options.serializerKey));
34
+ }
35
+ catch (error) {
36
+ if (!(error instanceof MissingSerializersDefinition))
37
+ throw error;
38
+ serializers = [];
39
+ }
40
+ return serializers.map(associatedSerializer => ({
41
+ dreamClass: associatedClass,
42
+ serializer: associatedSerializer,
43
+ }));
44
+ });
45
+ return {
46
+ associationAs: association.as,
47
+ sourceDreamClass: dreamClass,
48
+ type: serializerAssociation.type,
49
+ serializerAssociationName,
50
+ targets,
51
+ };
52
+ }));
53
+ }
@@ -158,7 +158,7 @@ export default class SerializerRenderer {
158
158
  // does not pass it into the call to DreamSerializer/ObjectSerializer,
159
159
  // then it would be lost to serializers rendered via rendersOne/Many, and SerializerRenderer
160
160
  // handles passing its passthrough data into those
161
- .render(passthroughData));
161
+ .render(passthroughData, this.renderOpts));
162
162
  });
163
163
  return accumulator;
164
164
  }
@@ -37,6 +37,10 @@ export default class DreamSerializerBuilder {
37
37
  * - `default` - Value to use when the target object or its attribute is null/undefined
38
38
  * - `openapi` - OpenAPI schema definition; required for non-Dream targets and json/jsonb
39
39
  * columns, optional for standard Dream columns (where types are inferred)
40
+ * - `optional` - Set to `true` to indicate the value can be null in the OpenAPI schema
41
+ * (wraps the type in `anyOf: [schema, { type: 'null' }]`). For Dream models, this is
42
+ * auto-inferred from optional BelongsTo associations. Use this when delegating through
43
+ * a HasOne or other nullable association.
40
44
  * - `precision` - Round decimal values to the specified number of decimal places (0–9)
41
45
  * during rendering; does not affect the OpenAPI shape
42
46
  * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import Dream from '../Dream.js';
2
2
  import { PassthroughOnClause } from '../types/associations/shared.js';
3
- import { DreamSerializerKey, PassthroughColumnNames } from '../types/dream.js';
3
+ import { DbConnectionType } from '../types/db.js';
4
+ import { AllDefaultScopeNames, DreamSerializerKey, PassthroughColumnNames } from '../types/dream.js';
4
5
  import { LoadForModifierFn } from '../types/query.js';
5
6
  import { VariadicLoadArgs } from '../types/variadic.js';
6
7
  import DreamTransaction from './DreamTransaction.js';
@@ -23,6 +24,52 @@ export default class LoadBuilder<DreamInstance extends Dream> {
23
24
  */
24
25
  constructor(dream: Dream, dreamTransaction?: (DreamTransaction<any> | null) | undefined);
25
26
  passthrough<I extends LoadBuilder<DreamInstance>, PassthroughColumns extends PassthroughColumnNames<DreamInstance>>(this: I, passthroughWhereStatement: PassthroughOnClause<PassthroughColumns>): I;
27
+ /**
28
+ * Prevents a specific default scope from applying when
29
+ * loading associations
30
+ *
31
+ * ```ts
32
+ * const user = await User.firstOrFail()
33
+ * const loaded = await user
34
+ * .load('posts')
35
+ * .removeDefaultScope('dream:SoftDelete')
36
+ * .execute()
37
+ * ```
38
+ *
39
+ * @param scopeName - The default scope to bypass
40
+ * @returns The LoadBuilder instance for chaining
41
+ */
42
+ removeDefaultScope<I extends LoadBuilder<DreamInstance>>(this: I, scopeName: AllDefaultScopeNames<DreamInstance>): I;
43
+ /**
44
+ * Prevents all default scopes from applying when
45
+ * loading associations
46
+ *
47
+ * ```ts
48
+ * const user = await User.firstOrFail()
49
+ * const loaded = await user
50
+ * .load('posts')
51
+ * .removeAllDefaultScopes()
52
+ * .execute()
53
+ * ```
54
+ *
55
+ * @returns The LoadBuilder instance for chaining
56
+ */
57
+ removeAllDefaultScopes<I extends LoadBuilder<DreamInstance>>(this: I): I;
58
+ /**
59
+ * Sets the database connection to use when loading associations
60
+ *
61
+ * ```ts
62
+ * const user = await User.firstOrFail()
63
+ * const loaded = await user
64
+ * .load('posts')
65
+ * .connection('replica')
66
+ * .execute()
67
+ * ```
68
+ *
69
+ * @param connection - The connection type ('primary' or 'replica')
70
+ * @returns The LoadBuilder instance for chaining
71
+ */
72
+ connection<I extends LoadBuilder<DreamInstance>>(this: I, connection: DbConnectionType): I;
26
73
  /**
27
74
  * Attaches a load statement to the load builder
28
75
  *
@@ -1,5 +1,7 @@
1
1
  export declare const primaryKeyTypes: readonly ["uuid7", "uuid4", "bigserial", "bigint", "integer"];
2
2
  export declare const TRIGRAM_OPERATORS: readonly ["%", "<%", "<<%"];
3
+ export declare const RECURSIVE_SERIALIZATION_MAX_REPEATS = 4;
4
+ export declare const RECURSIVE_DESTROY_PRELOAD_MAX_REPEATS = 4;
3
5
  declare class RequiredAttribute {
4
6
  constructor();
5
7
  }
@@ -0,0 +1,12 @@
1
+ import { DreamClassAndAssociationNameTuple } from '../../types/recursiveSerialization.js';
2
+ export interface AssociationPathEdge<NodeType> {
3
+ nextNode: NodeType | null;
4
+ tuple: DreamClassAndAssociationNameTuple;
5
+ }
6
+ export default function buildAssociationPaths<NodeType>(rootNode: NodeType, opts: BuildAssociationPathsOptions<NodeType>): DreamClassAndAssociationNameTuple[][];
7
+ type BuildAssociationPathsOptions<NodeType> = {
8
+ getKey: (node: NodeType) => string;
9
+ getEdges: (node: NodeType) => AssociationPathEdge<NodeType>[];
10
+ maxRepeats: number;
11
+ };
12
+ export {};
@@ -0,0 +1,17 @@
1
+ import Dream from '../../Dream.js';
2
+ import { DreamClassAndAssociationNameTuple } from '../../types/recursiveSerialization.js';
3
+ /**
4
+ * @internal
5
+ *
6
+ * Recursively walks `dependent: 'destroy'` associations starting from the given
7
+ * Dream class, producing an array of preload paths. Each path is an array of
8
+ * [DreamClass, associationName] tuples representing a chain from root to leaf.
9
+ *
10
+ * Allows the same Dream class to appear up to MAX_REPEATS times in a single
11
+ * path to support tree structures (e.g. a Category with `dependent: 'destroy'`
12
+ * on its children, which are also Categories).
13
+ *
14
+ * Used to build a preload tree so that all records in the cascade can be loaded
15
+ * upfront, eliminating N+1 queries during destroy.
16
+ */
17
+ export default function buildDependentDestroyPreloadPaths(dreamClass: typeof Dream): DreamClassAndAssociationNameTuple[][];
@@ -0,0 +1,3 @@
1
+ import Dream from '../../Dream.js';
2
+ import { DreamClassAndAssociationNameTuple } from '../../types/recursiveSerialization.js';
3
+ export default function buildSerializerPreloadPaths(dreamClass: typeof Dream, serializerKey?: string): DreamClassAndAssociationNameTuple[][];
@@ -1,5 +1,5 @@
1
1
  import { LoadForModifierFn } from '../../types/query.js';
2
- import { DreamClassAndAssociationNameTuple } from './extractNestedPaths.js';
2
+ import { DreamClassAndAssociationNameTuple } from '../../types/recursiveSerialization.js';
3
3
  export default function convertDreamClassAndAssociationNameTupleArrayToPreloadArgs(dreamClassAndAssociationNameTupleArray: DreamClassAndAssociationNameTuple[], modifierFn?: LoadForModifierFn, counter?: {
4
4
  count: number;
5
5
  }): (string | {
@@ -5,6 +5,10 @@ import { ReallyDestroyOptions } from './destroyDream.js';
5
5
  * @internal
6
6
  *
7
7
  * Destroys all HasOne/HasMany associations on this
8
- * dream that are marked as `dependent: 'destroy'`
8
+ * dream that are marked as `dependent: 'destroy'`.
9
+ *
10
+ * Expects associations to be preloaded onto the dream instance
11
+ * via `loadDependentDestroyTree`. Iterates loaded associations
12
+ * directly instead of querying the database.
9
13
  */
10
14
  export default function destroyAssociatedRecords<I extends Dream>(dream: I, txn: DreamTransaction<I>, options: ReallyDestroyOptions<I>): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import Dream from '../../Dream.js';
2
+ import { AllDefaultScopeNames } from '../../types/dream.js';
3
+ import DreamTransaction from '../DreamTransaction.js';
4
+ /**
5
+ * @internal
6
+ *
7
+ * Loads all `dependent: 'destroy'` associations onto the dream instance
8
+ * upfront, eliminating N+1 queries during cascade destruction.
9
+ *
10
+ * Returns a clone of the dream with all associations loaded.
11
+ * If there are no dependent-destroy associations, returns the original dream.
12
+ */
13
+ export default function loadDependentDestroyTree<I extends Dream>(dream: I, txn: DreamTransaction<I>, { reallyDestroy, bypassAllDefaultScopes, defaultScopesToBypass, }: {
14
+ reallyDestroy: boolean;
15
+ bypassAllDefaultScopes: boolean;
16
+ defaultScopesToBypass: AllDefaultScopeNames<I>[];
17
+ }): Promise<I>;
@@ -0,0 +1,13 @@
1
+ import Dream from '../../Dream.js';
2
+ import { DreamModelSerializerType, SimpleObjectSerializerType } from '../../types/serializer.js';
3
+ export interface ResolvedSerializerAssociationEdge {
4
+ associationAs: string;
5
+ sourceDreamClass: typeof Dream;
6
+ type: 'rendersOne' | 'rendersMany' | 'delegatedAttribute';
7
+ serializerAssociationName: string;
8
+ targets: {
9
+ dreamClass: typeof Dream;
10
+ serializer: DreamModelSerializerType | SimpleObjectSerializerType;
11
+ }[];
12
+ }
13
+ export default function resolveSerializerAssociationEdges(dreamClass: typeof Dream, serializer: DreamModelSerializerType | SimpleObjectSerializerType): ResolvedSerializerAssociationEdge[];
@@ -2,6 +2,7 @@ import Dream from '../../Dream.js';
2
2
  import { DreamOrViewModelSerializerKey, DreamVirtualColumns, NonJsonDreamColumnNames, ViewModel, ViewModelClass } from '../../types/dream.js';
3
3
  import { AutomaticSerializerAttributeOptions, AutomaticSerializerAttributeOptionsForType, InternalAnyTypedSerializerAttribute, InternalAnyTypedSerializerCustomAttribute, InternalAnyTypedSerializerDelegatedAttribute, InternalAnyTypedSerializerRendersMany, InternalAnyTypedSerializerRendersOne, NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption, SerializerAttributeOptionsForVirtualColumn, SerializerType } from '../../types/serializer.js';
4
4
  import { SerializerRendererOpts } from '../SerializerRenderer.js';
5
+ export type DreamPropertiesToExclude = keyof Dream | 'serializers';
5
6
  export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dream, MaybeNullDataType extends Dream | null, PassthroughDataType = any, DataType extends Exclude<MaybeNullDataType, null> = Exclude<MaybeNullDataType, null>> {
6
7
  protected $typeForOpenapi: DataTypeForOpenapi;
7
8
  protected data: MaybeNullDataType;
@@ -53,7 +54,7 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
53
54
  */
54
55
  attribute(name: NonJsonDreamColumnNames<DataType> & keyof DataType & 'type', options?: AutomaticSerializerAttributeOptionsForType): DreamSerializerBuilder<DataTypeForOpenapi, MaybeNullDataType, PassthroughDataType, DataType>;
55
56
  attribute(name: DreamVirtualColumns<DataType>[number], options?: SerializerAttributeOptionsForVirtualColumn): DreamSerializerBuilder<DataTypeForOpenapi, MaybeNullDataType, PassthroughDataType, DataType>;
56
- attribute<MaybeAttributeName extends NonJsonDreamColumnNames<DataType> | (keyof DataType & string), AttributeName extends MaybeAttributeName extends NonJsonDreamColumnNames<DataType> ? never : Exclude<keyof DataType, keyof Dream> & string>(name: AttributeName, options: NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption): DreamSerializerBuilder<DataTypeForOpenapi, MaybeNullDataType, PassthroughDataType, DataType>;
57
+ attribute<MaybeAttributeName extends NonJsonDreamColumnNames<DataType> | (keyof DataType & string), AttributeName extends MaybeAttributeName extends NonJsonDreamColumnNames<DataType> ? never : Exclude<keyof DataType, DreamPropertiesToExclude> & string>(name: AttributeName, options: NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption): DreamSerializerBuilder<DataTypeForOpenapi, MaybeNullDataType, PassthroughDataType, DataType>;
57
58
  attribute<AttributeName extends NonJsonDreamColumnNames<DataType> & keyof DataType & string>(name: AttributeName, options?: AutomaticSerializerAttributeOptions): DreamSerializerBuilder<DataTypeForOpenapi, MaybeNullDataType, PassthroughDataType, DataType>;
58
59
  /**
59
60
  * Includes an attribute from a nested object in the serialized output.
@@ -75,6 +76,10 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
75
76
  * - `default` - Value to use when the target object or its attribute is null/undefined
76
77
  * - `openapi` - OpenAPI schema definition; required for non-Dream targets and json/jsonb
77
78
  * columns, optional for standard Dream columns (where types are inferred)
79
+ * - `optional` - Set to `true` to indicate the value can be null in the OpenAPI schema
80
+ * (wraps the type in `anyOf: [schema, { type: 'null' }]`). For Dream models, this is
81
+ * auto-inferred from optional BelongsTo associations. Use this when delegating through
82
+ * a HasOne or other nullable association.
78
83
  * - `precision` - Round decimal values to the specified number of decimal places (0–9)
79
84
  * during rendering; does not affect the OpenAPI shape
80
85
  * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
@@ -99,7 +104,11 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
99
104
  * })
100
105
  * ```
101
106
  */
102
- delegatedAttribute<ProvidedModelType = undefined, ProvidedTargetName extends ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, keyof Dream> = ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, keyof Dream>, ActualDataType extends ProvidedModelType extends undefined ? DataType : ProvidedModelType = ProvidedModelType extends undefined ? DataType : ProvidedModelType, TargetName extends ProvidedTargetName extends undefined ? Exclude<keyof ActualDataType, keyof Dream> : ProvidedTargetName & keyof ActualDataType = ProvidedTargetName extends undefined ? Exclude<keyof ActualDataType, keyof Dream> : ProvidedTargetName & keyof ActualDataType, AssociatedModelType = Exclude<ActualDataType[TargetName], null>, TargetAttributeName extends AssociatedModelType extends object ? Exclude<keyof AssociatedModelType, keyof Dream> & string : never = AssociatedModelType extends object ? Exclude<keyof AssociatedModelType, keyof Dream> & string : never>(targetName: TargetName, name: TargetAttributeName, options?: AssociatedModelType extends Dream ? TargetAttributeName extends NonJsonDreamColumnNames<AssociatedModelType> & keyof AssociatedModelType & 'type' ? AutomaticSerializerAttributeOptionsForType : TargetAttributeName extends DreamVirtualColumns<AssociatedModelType>[number] ? SerializerAttributeOptionsForVirtualColumn : TargetAttributeName extends AssociatedModelType & keyof AssociatedModelType & string ? AutomaticSerializerAttributeOptions | NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption : NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption : NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption): this;
107
+ delegatedAttribute<ProvidedModelType = undefined, ProvidedTargetName extends ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, DreamPropertiesToExclude> = ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, DreamPropertiesToExclude>, ActualDataType extends ProvidedModelType extends undefined ? InstanceType<DataTypeForOpenapi> : ProvidedModelType = ProvidedModelType extends undefined ? InstanceType<DataTypeForOpenapi> : ProvidedModelType, TargetName extends ProvidedTargetName extends undefined ? Exclude<keyof ActualDataType, DreamPropertiesToExclude> : ProvidedTargetName & keyof ActualDataType = ProvidedTargetName extends undefined ? Exclude<keyof ActualDataType, DreamPropertiesToExclude> : ProvidedTargetName & keyof ActualDataType, AssociatedModelType = Exclude<ActualDataType[TargetName], null>, TargetAttributeName extends AssociatedModelType extends object ? Exclude<keyof AssociatedModelType, DreamPropertiesToExclude> & string : never = AssociatedModelType extends object ? Exclude<keyof AssociatedModelType, DreamPropertiesToExclude> & string : never>(targetName: TargetName, name: TargetAttributeName, options?: AssociatedModelType extends Dream ? TargetAttributeName extends NonJsonDreamColumnNames<AssociatedModelType> & keyof AssociatedModelType & 'type' ? AutomaticSerializerAttributeOptionsForType & {
108
+ optional?: boolean;
109
+ } : TargetAttributeName extends DreamVirtualColumns<AssociatedModelType>[number] ? SerializerAttributeOptionsForVirtualColumn : TargetAttributeName extends NonJsonDreamColumnNames<AssociatedModelType> & keyof AssociatedModelType & string ? (AutomaticSerializerAttributeOptions & {
110
+ optional?: boolean;
111
+ }) | NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption : NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption : NonAutomaticSerializerAttributeOptionsWithPossibleDecimalRenderOption): this;
103
112
  /**
104
113
  * Includes a computed value in the serialized output.
105
114
  *
@@ -196,7 +205,7 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
196
205
  * .rendersOne('owner', { serializer: CustomOwnerSerializer })
197
206
  * ```
198
207
  */
199
- rendersOne<ProvidedModelType = undefined, ProvidedAttributeName extends ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, keyof Dream> = ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, keyof Dream>, ActualDataType extends ProvidedModelType extends undefined ? DataType : ProvidedModelType = ProvidedModelType extends undefined ? DataType : ProvidedModelType, AttributeName extends ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, keyof Dream> : ProvidedAttributeName & keyof ActualDataType = ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, keyof Dream> : ProvidedAttributeName & keyof ActualDataType, AssociatedModelType = Exclude<ActualDataType[AttributeName], null>, SerializerOptions = AssociatedModelType extends Dream ? {
208
+ rendersOne<ProvidedModelType = undefined, ProvidedAttributeName extends ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, DreamPropertiesToExclude> = ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, DreamPropertiesToExclude>, ActualDataType extends ProvidedModelType extends undefined ? InstanceType<DataTypeForOpenapi> : ProvidedModelType = ProvidedModelType extends undefined ? InstanceType<DataTypeForOpenapi> : ProvidedModelType, AttributeName extends ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, DreamPropertiesToExclude> : ProvidedAttributeName & keyof ActualDataType = ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, DreamPropertiesToExclude> : ProvidedAttributeName & keyof ActualDataType, AssociatedModelType = Exclude<ActualDataType[AttributeName], null>, SerializerOptions = AssociatedModelType extends Dream ? {
200
209
  serializerKey?: DreamOrViewModelSerializerKey<AssociatedModelType>;
201
210
  } | {
202
211
  serializer?: SerializerType;
@@ -267,7 +276,7 @@ export default class DreamSerializerBuilder<DataTypeForOpenapi extends typeof Dr
267
276
  * .rendersMany('rooms', { serializerKey: 'forGuests', as: 'guestRooms' })
268
277
  * ```
269
278
  */
270
- rendersMany<ProvidedModelType = undefined, ProvidedAttributeName extends ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, keyof Dream> = ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, keyof Dream>, ActualDataType extends ProvidedModelType extends undefined ? DataType : ProvidedModelType = ProvidedModelType extends undefined ? DataType : ProvidedModelType, AttributeName extends ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, keyof Dream> : ProvidedAttributeName & keyof ActualDataType = ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, keyof Dream> : ProvidedAttributeName & keyof ActualDataType, AssociatedModelType = ActualDataType[AttributeName] extends (Dream | ViewModel)[] ? ActualDataType[AttributeName] extends (infer U)[] ? U : object : object, SerializerOptions = AssociatedModelType extends Dream ? {
279
+ rendersMany<ProvidedModelType = undefined, ProvidedAttributeName extends ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, DreamPropertiesToExclude> = ProvidedModelType extends undefined ? undefined : Exclude<keyof ProvidedModelType, DreamPropertiesToExclude>, ActualDataType extends ProvidedModelType extends undefined ? InstanceType<DataTypeForOpenapi> : ProvidedModelType = ProvidedModelType extends undefined ? InstanceType<DataTypeForOpenapi> : ProvidedModelType, AttributeName extends ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, DreamPropertiesToExclude> : ProvidedAttributeName & keyof ActualDataType = ProvidedAttributeName extends undefined ? Exclude<keyof ActualDataType, DreamPropertiesToExclude> : ProvidedAttributeName & keyof ActualDataType, AssociatedModelType = ActualDataType[AttributeName] extends (Dream | ViewModel)[] ? ActualDataType[AttributeName] extends (infer U)[] ? U : object : object, SerializerOptions = AssociatedModelType extends Dream ? {
271
280
  serializerKey?: DreamOrViewModelSerializerKey<AssociatedModelType>;
272
281
  } | {
273
282
  serializer?: SerializerType;