@rvoh/dream 0.44.9 → 0.45.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 (207) hide show
  1. package/dist/cjs/src/Dream.js +246 -23
  2. package/dist/cjs/src/cli/index.js +16 -0
  3. package/dist/cjs/src/db/migration-helpers/DreamMigrationHelpers.js +18 -14
  4. package/dist/cjs/src/decorators/Decorators.js +2 -1
  5. package/dist/cjs/src/dream/Query.js +162 -24
  6. package/dist/cjs/src/dream/internal/extractNestedPaths.js +37 -0
  7. package/dist/cjs/src/helpers/indent.js +18 -0
  8. package/dist/cjs/src/serializer/SerializerRenderer.js +2 -17
  9. package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +139 -3
  10. package/dist/cjs/src/serializer/builders/ObjectSerializerBuilder.js +176 -3
  11. package/dist/cjs/src/serializer/helpers/serializerForAssociatedClass.js +20 -0
  12. package/dist/esm/src/Dream.js +246 -23
  13. package/dist/esm/src/cli/index.js +16 -0
  14. package/dist/esm/src/db/migration-helpers/DreamMigrationHelpers.js +18 -14
  15. package/dist/esm/src/decorators/Decorators.js +2 -1
  16. package/dist/esm/src/dream/Query.js +162 -24
  17. package/dist/esm/src/dream/internal/extractNestedPaths.js +34 -0
  18. package/dist/esm/src/helpers/indent.js +15 -0
  19. package/dist/esm/src/serializer/SerializerRenderer.js +2 -17
  20. package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +139 -3
  21. package/dist/esm/src/serializer/builders/ObjectSerializerBuilder.js +176 -3
  22. package/dist/esm/src/serializer/helpers/serializerForAssociatedClass.js +17 -0
  23. package/dist/types/src/Dream.d.ts +218 -24
  24. package/dist/types/src/db/migration-helpers/DreamMigrationHelpers.d.ts +18 -14
  25. package/dist/types/src/decorators/Decorators.d.ts +2 -1
  26. package/dist/types/src/dream/Query.d.ts +154 -25
  27. package/dist/types/src/dream/internal/extractNestedPaths.d.ts +21 -0
  28. package/dist/types/src/helpers/indent.d.ts +3 -0
  29. package/dist/types/src/index.d.ts +1 -1
  30. package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +176 -5
  31. package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +176 -3
  32. package/dist/types/src/serializer/helpers/serializerForAssociatedClass.d.ts +9 -0
  33. package/dist/types/src/types/dream.d.ts +2 -1
  34. package/dist/types/src/types/dream.ts +26 -1
  35. package/docs/assets/highlight.css +7 -0
  36. package/docs/assets/navigation.js +1 -1
  37. package/docs/assets/search.js +1 -1
  38. package/docs/classes/Benchmark.html +2 -2
  39. package/docs/classes/CalendarDate.html +2 -2
  40. package/docs/classes/CreateOrFindByFailedToCreateAndFind.html +3 -3
  41. package/docs/classes/Decorators.html +21 -20
  42. package/docs/classes/Dream.html +288 -209
  43. package/docs/classes/DreamApp.html +4 -4
  44. package/docs/classes/DreamBin.html +2 -2
  45. package/docs/classes/DreamCLI.html +4 -4
  46. package/docs/classes/DreamImporter.html +2 -2
  47. package/docs/classes/DreamLogos.html +2 -2
  48. package/docs/classes/DreamMigrationHelpers.html +21 -8
  49. package/docs/classes/DreamSerializerBuilder.html +66 -2
  50. package/docs/classes/DreamTransaction.html +2 -2
  51. package/docs/classes/Encrypt.html +2 -2
  52. package/docs/classes/Env.html +2 -2
  53. package/docs/classes/GlobalNameNotSet.html +3 -3
  54. package/docs/classes/NonLoadedAssociation.html +3 -3
  55. package/docs/classes/ObjectSerializerBuilder.html +66 -2
  56. package/docs/classes/Query.html +118 -78
  57. package/docs/classes/Range.html +2 -2
  58. package/docs/classes/RecordNotFound.html +3 -3
  59. package/docs/classes/ValidationError.html +3 -3
  60. package/docs/functions/DreamSerializer.html +1 -1
  61. package/docs/functions/ObjectSerializer.html +1 -1
  62. package/docs/functions/ReplicaSafe.html +1 -1
  63. package/docs/functions/STI.html +1 -1
  64. package/docs/functions/SoftDelete.html +1 -1
  65. package/docs/functions/camelize.html +1 -1
  66. package/docs/functions/capitalize.html +1 -1
  67. package/docs/functions/cloneDeepSafe.html +1 -1
  68. package/docs/functions/closeAllDbConnections.html +1 -1
  69. package/docs/functions/compact.html +1 -1
  70. package/docs/functions/dreamDbConnections.html +1 -1
  71. package/docs/functions/dreamPath.html +1 -1
  72. package/docs/functions/expandStiClasses.html +1 -1
  73. package/docs/functions/generateDream.html +1 -1
  74. package/docs/functions/globalClassNameFromFullyQualifiedModelName.html +1 -1
  75. package/docs/functions/groupBy.html +1 -1
  76. package/docs/functions/hyphenize.html +1 -1
  77. package/docs/functions/inferSerializerFromDreamOrViewModel.html +1 -1
  78. package/docs/functions/inferSerializersFromDreamClassOrViewModelClass.html +1 -1
  79. package/docs/functions/intersection.html +1 -1
  80. package/docs/functions/isDreamSerializer.html +1 -1
  81. package/docs/functions/isEmpty.html +1 -1
  82. package/docs/functions/loadRepl.html +1 -1
  83. package/docs/functions/lookupClassByGlobalName.html +1 -1
  84. package/docs/functions/normalizeUnicode.html +1 -1
  85. package/docs/functions/pascalize.html +1 -1
  86. package/docs/functions/pgErrorType.html +1 -1
  87. package/docs/functions/range-1.html +1 -1
  88. package/docs/functions/relativeDreamPath.html +1 -1
  89. package/docs/functions/round.html +1 -1
  90. package/docs/functions/serializerNameFromFullyQualifiedModelName.html +1 -1
  91. package/docs/functions/sharedPathPrefix.html +1 -1
  92. package/docs/functions/snakeify.html +1 -1
  93. package/docs/functions/sort.html +1 -1
  94. package/docs/functions/sortBy.html +1 -1
  95. package/docs/functions/sortObjectByKey.html +1 -1
  96. package/docs/functions/sortObjectByValue.html +1 -1
  97. package/docs/functions/standardizeFullyQualifiedModelName.html +1 -1
  98. package/docs/functions/uncapitalize.html +1 -1
  99. package/docs/functions/uniq.html +1 -1
  100. package/docs/functions/untypedDb.html +1 -1
  101. package/docs/functions/validateColumn.html +1 -1
  102. package/docs/functions/validateTable.html +1 -1
  103. package/docs/interfaces/BelongsToStatement.html +2 -2
  104. package/docs/interfaces/DecoratorContext.html +2 -2
  105. package/docs/interfaces/DreamAppInitOptions.html +2 -2
  106. package/docs/interfaces/DreamAppOpts.html +2 -2
  107. package/docs/interfaces/EncryptOptions.html +2 -2
  108. package/docs/interfaces/InternalAnyTypedSerializerRendersMany.html +2 -2
  109. package/docs/interfaces/InternalAnyTypedSerializerRendersOne.html +2 -2
  110. package/docs/interfaces/OpenapiDescription.html +2 -2
  111. package/docs/interfaces/OpenapiSchemaProperties.html +1 -1
  112. package/docs/interfaces/OpenapiSchemaPropertiesShorthand.html +1 -1
  113. package/docs/interfaces/OpenapiTypeFieldObject.html +1 -1
  114. package/docs/interfaces/SerializerRendererOpts.html +2 -2
  115. package/docs/modules.html +1 -0
  116. package/docs/types/Camelized.html +1 -1
  117. package/docs/types/CommonOpenapiSchemaObjectFields.html +1 -1
  118. package/docs/types/DateTime.html +1 -1
  119. package/docs/types/DbConnectionType.html +1 -1
  120. package/docs/types/DbTypes.html +1 -1
  121. package/docs/types/DreamAssociationMetadata.html +1 -1
  122. package/docs/types/DreamAttributes.html +1 -1
  123. package/docs/types/DreamClassAssociationAndStatement.html +1 -0
  124. package/docs/types/DreamClassColumn.html +1 -1
  125. package/docs/types/DreamColumn.html +1 -1
  126. package/docs/types/DreamColumnNames.html +1 -1
  127. package/docs/types/DreamLogLevel.html +1 -1
  128. package/docs/types/DreamLogger.html +1 -1
  129. package/docs/types/DreamModelSerializerType.html +1 -1
  130. package/docs/types/DreamOrViewModelClassSerializerKey.html +1 -1
  131. package/docs/types/DreamOrViewModelSerializerKey.html +1 -1
  132. package/docs/types/DreamParamSafeAttributes.html +1 -1
  133. package/docs/types/DreamParamSafeColumnNames.html +1 -1
  134. package/docs/types/DreamSerializable.html +1 -1
  135. package/docs/types/DreamSerializableArray.html +1 -1
  136. package/docs/types/DreamSerializerKey.html +1 -1
  137. package/docs/types/DreamSerializers.html +1 -1
  138. package/docs/types/DreamTableSchema.html +1 -1
  139. package/docs/types/DreamVirtualColumns.html +1 -1
  140. package/docs/types/EncryptAlgorithm.html +1 -1
  141. package/docs/types/HasManyStatement.html +1 -1
  142. package/docs/types/HasOneStatement.html +1 -1
  143. package/docs/types/Hyphenized.html +1 -1
  144. package/docs/types/IdType.html +1 -1
  145. package/docs/types/OpenapiAllTypes.html +1 -1
  146. package/docs/types/OpenapiFormats.html +1 -1
  147. package/docs/types/OpenapiNumberFormats.html +1 -1
  148. package/docs/types/OpenapiPrimitiveBaseTypes.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/OpenapiSchemaPrimitiveGeneric.html +1 -1
  175. package/docs/types/OpenapiSchemaShorthandExpressionAllOf.html +1 -1
  176. package/docs/types/OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
  177. package/docs/types/OpenapiSchemaShorthandExpressionOneOf.html +1 -1
  178. package/docs/types/OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
  179. package/docs/types/OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
  180. package/docs/types/OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  181. package/docs/types/OpenapiSchemaString.html +1 -1
  182. package/docs/types/OpenapiShorthandAllTypes.html +1 -1
  183. package/docs/types/OpenapiShorthandPrimitiveBaseTypes.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/SerializerCasing.html +1 -1
  190. package/docs/types/SimpleObjectSerializerType.html +1 -1
  191. package/docs/types/Snakeified.html +1 -1
  192. package/docs/types/Timestamp.html +1 -1
  193. package/docs/types/UpdateableAssociationProperties.html +1 -1
  194. package/docs/types/UpdateableProperties.html +1 -1
  195. package/docs/types/ValidationType.html +1 -1
  196. package/docs/types/ViewModel.html +1 -1
  197. package/docs/types/ViewModelClass.html +1 -1
  198. package/docs/types/WhereStatementForDream.html +1 -1
  199. package/docs/types/WhereStatementForDreamClass.html +1 -1
  200. package/docs/variables/DateTime-1.html +1 -1
  201. package/docs/variables/DreamConst.html +1 -1
  202. package/docs/variables/TRIGRAM_OPERATORS.html +1 -1
  203. package/docs/variables/openapiPrimitiveTypes-1.html +1 -1
  204. package/docs/variables/openapiShorthandPrimitiveTypes-1.html +1 -1
  205. package/docs/variables/ops.html +1 -1
  206. package/docs/variables/primaryKeyTypes.html +1 -1
  207. package/package.json +2 -2
@@ -13,11 +13,13 @@ const CannotPaginateWithLimit_js_1 = require("../errors/pagination/CannotPaginat
13
13
  const CannotPaginateWithOffset_js_1 = require("../errors/pagination/CannotPaginateWithOffset.js");
14
14
  const RecordNotFound_js_1 = require("../errors/RecordNotFound.js");
15
15
  const cloneDeepSafe_js_1 = require("../helpers/cloneDeepSafe.js");
16
+ const compact_js_1 = require("../helpers/compact.js");
16
17
  const isObject_js_1 = require("../helpers/isObject.js");
17
18
  const namespaceColumn_js_1 = require("../helpers/namespaceColumn.js");
18
19
  const protectAgainstPollutingAssignment_js_1 = require("../helpers/protectAgainstPollutingAssignment.js");
19
20
  const index_js_2 = require("../ops/index.js");
20
21
  const computedPaginatePage_js_1 = require("./internal/computedPaginatePage.js");
22
+ const extractNestedPaths_js_1 = require("./internal/extractNestedPaths.js");
21
23
  const Postgres_js_1 = require("./QueryDriver/Postgres.js");
22
24
  class Query {
23
25
  /**
@@ -398,8 +400,8 @@ class Query {
398
400
  * ```
399
401
  *
400
402
  * @param cb - The callback to call for each found record
401
- * @param options - Options for destroying the instance
402
- * @param options.batchSize - The batch size you wish to collect records in. If not provided, it will default to 1000
403
+ * @param __namedParameters - Options for batch processing
404
+ * @param __namedParameters.batchSize - The batch size you wish to collect records in. If not provided, it will default to 1000
403
405
  * @returns void
404
406
  */
405
407
  async findEach(cb, { batchSize = Query.BATCH_SIZES.FIND_EACH } = {}) {
@@ -423,10 +425,10 @@ class Query {
423
425
  }
424
426
  /**
425
427
  * Load each specified association using a single SQL query.
426
- * See {@link #preload} for preloading in separate queries.
428
+ * See {@link Query.preload} for preloading in separate queries.
427
429
  *
428
430
  * Note: since leftJoinPreload loads via single query, it has
429
- * some downsides and that may be avoided using {@link #preload}:
431
+ * some downsides and that may be avoided using {@link Query.preload}:
430
432
  * 1. `limit` and `offset` will be automatically removed
431
433
  * 2. `through` associations will bring additional namespaces into the query that can conflict with through associations from other associations, creating an invalid query
432
434
  * 3. each nested association will result in an additional record which duplicates data from the outer record. E.g., given `.leftJoinPreload('a', 'b', 'c')`, if each `a` has 10 `b` and each `b` has 10 `c`, then for one `a`, 100 records will be returned, each of which has all of the columns of `a`. `.preload('a', 'b', 'c')` would perform three separate SQL queries, but the data for a single `a` would only be returned once.
@@ -454,7 +456,7 @@ class Query {
454
456
  }
455
457
  /**
456
458
  * Load each specified association using a separate SQL query.
457
- * See {@link #leftJoinPreload} for preloading in a single query.
459
+ * See {@link Query.leftJoinPreload} for preloading in a single query.
458
460
  *
459
461
  * ```ts
460
462
  * const user = await User.query().preload('posts', 'comments', { visibilty: 'public' }, 'replies').first()
@@ -471,6 +473,141 @@ class Query {
471
473
  this.fleshOutJoinStatements([], preloadStatements, preloadOnStatements, null, [...args]);
472
474
  return this.clone({ preloadStatements, preloadOnStatements: preloadOnStatements });
473
475
  }
476
+ /**
477
+ * Recursively preloads all Dream associations referenced by `rendersOne` and `rendersMany`
478
+ * in a DreamSerializer. This traverses the entire content tree of serializers to automatically
479
+ * load all necessary associations, eliminating N+1 query problems and removing the need to
480
+ * manually remember which associations to preload for serialization.
481
+ *
482
+ * This method decouples data loading code from data rendering code by having the serializer
483
+ * (rendering code) inform the query (loading code) about which associations are needed.
484
+ * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
485
+ * modifying existing ones - the loading code automatically adapts without requiring
486
+ * corresponding modifications to preload statements.
487
+ *
488
+ * This method analyzes the serializer (specified by `serializerKey` or 'default') and
489
+ * automatically preloads all associations that will be needed during serialization.
490
+ *
491
+ * ```ts
492
+ * // Instead of manually specifying all associations:
493
+ * await User.preload('posts', 'comments', 'replies').all()
494
+ *
495
+ * // Automatically preload everything needed for serialization:
496
+ * await User.preloadForSerialization({ serializerKey: 'summary' }).all()
497
+ *
498
+ * // Add where conditions to specific associations during preloading:
499
+ * await User.preloadForSerialization({
500
+ * serializerKey: 'detailed',
501
+ * modifierFn: (dreamClass, associationName) => {
502
+ * if (dreamClass.typeof(Post) && associationName === 'comments') {
503
+ * return { and: { published: true } }
504
+ * }
505
+ * }
506
+ * }).all()
507
+ *
508
+ * // Skip preloading specific associations to handle them manually:
509
+ * await User.preloadForSerialization({
510
+ * serializerKey: 'summary',
511
+ * modifierFn: (dreamClass, associationName) => {
512
+ * if (dreamClass.typeof(User) && associationName === 'posts') {
513
+ * return 'omit' // Handle posts preloading separately with custom logic
514
+ * }
515
+ * }
516
+ * })
517
+ * .preload('posts', { and: { featured: true } }) // Custom preloading
518
+ * .all()
519
+ * ```
520
+ *
521
+ * @param opts - Configuration options for serialization preloading
522
+ * @param opts.serializerKey - The serializer key to use for determining which associations to preload. Defaults to 'default'
523
+ * @param opts.modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
524
+ * @returns A Query with all serialization associations preloaded
525
+ */
526
+ preloadForSerialization({ serializerKey, modifierFn, } = {}) {
527
+ const preloadArgs = (0, extractNestedPaths_js_1.default)(this.dreamClass['serializationMap'](serializerKey));
528
+ let query = this;
529
+ preloadArgs.forEach(dreamClassAndAssociationNameTupleArray => {
530
+ query = query.preload(...this.convertDreamClassAndAssociationNameTupleArrayToPreloadArgs(dreamClassAndAssociationNameTupleArray, modifierFn));
531
+ });
532
+ return query;
533
+ }
534
+ /**
535
+ * Recursively preloads all Dream associations referenced by `rendersOne` and `rendersMany`
536
+ * in a DreamSerializer using left join preloading. This traverses the entire content tree
537
+ * of serializers to automatically load all necessary associations in a single query,
538
+ * eliminating N+1 query problems and removing the need to manually remember which
539
+ * associations to preload for serialization.
540
+ *
541
+ * This method decouples data loading code from data rendering code by having the serializer
542
+ * (rendering code) inform the query (loading code) about which associations are needed.
543
+ * As serializers evolve over time - adding new `rendersOne` and `rendersMany` calls or
544
+ * modifying existing ones - the loading code automatically adapts without requiring
545
+ * corresponding modifications to left join preload statements.
546
+ *
547
+ * This method analyzes the serializer (specified by `serializerKey` or 'default') and
548
+ * automatically left join preloads all associations that will be needed during serialization.
549
+ *
550
+ * Note: Left join preloading loads all data in a single SQL query but has trade-offs compared
551
+ * to regular preloading. See {@link Dream.leftJoinPreload} for details about limitations.
552
+ *
553
+ * ```ts
554
+ * // Instead of manually specifying all associations:
555
+ * await User.leftJoinPreload('posts', 'comments', 'replies').all()
556
+ *
557
+ * // Automatically left join preload everything needed for serialization:
558
+ * await User.leftJoinPreloadForSerialization({ serializerKey: 'summary' }).all()
559
+ *
560
+ * // Add where conditions to specific associations during left join preloading:
561
+ * await User.leftJoinPreloadForSerialization({
562
+ * serializerKey: 'detailed',
563
+ * modifierFn: (dreamClass, associationName) => {
564
+ * if (dreamClass.typeof(Post) && associationName === 'comments') {
565
+ * return { and: { published: true } }
566
+ * }
567
+ * }
568
+ * }).all()
569
+ *
570
+ * // Skip left join preloading specific associations to handle them manually:
571
+ * await User.leftJoinPreloadForSerialization({
572
+ * serializerKey: 'summary',
573
+ * modifierFn: (dreamClass, associationName) => {
574
+ * if (dreamClass.typeof(User) && associationName === 'posts') {
575
+ * return 'omit' // Handle posts preloading separately with custom logic
576
+ * }
577
+ * }
578
+ * })
579
+ * .preload('posts', { and: { featured: true } }) // Custom preloading instead
580
+ * .all()
581
+ * ```
582
+ *
583
+ * @param opts - Configuration options for serialization preloading
584
+ * @param opts.serializerKey - The serializer key to use for determining which associations to preload. Defaults to 'default'
585
+ * @param opts.modifierFn - Optional callback function to modify or omit specific associations during preloading. Called for each association with the Dream class and association name. Return an object with `and`, `andAny`, or `andNot` properties to add where conditions, return 'omit' to skip preloading that association (useful when you want to handle it manually), or return undefined to use default preloading
586
+ * @returns A Query with all serialization associations left join preloaded
587
+ */
588
+ leftJoinPreloadForSerialization({ serializerKey, modifierFn, } = {}) {
589
+ const preloadArgs = (0, extractNestedPaths_js_1.default)(this.dreamClass['serializationMap'](serializerKey));
590
+ let query = this;
591
+ const counter = { count: 0 };
592
+ preloadArgs.forEach(dreamClassAndAssociationNameTupleArray => {
593
+ query = query.leftJoinPreload(...this.convertDreamClassAndAssociationNameTupleArrayToPreloadArgs(dreamClassAndAssociationNameTupleArray, modifierFn, counter));
594
+ });
595
+ return query;
596
+ }
597
+ convertDreamClassAndAssociationNameTupleArrayToPreloadArgs(dreamClassAndAssociationNameTupleArray, modifierFn, counter) {
598
+ return (0, compact_js_1.default)(dreamClassAndAssociationNameTupleArray.flatMap(dreamClassAndAssociationNameTuple => {
599
+ const associationName = dreamClassAndAssociationNameTuple[1];
600
+ const aliasedAssociationName = counter
601
+ ? `${dreamClassAndAssociationNameTuple[1]} as drsz${counter.count++}`
602
+ : dreamClassAndAssociationNameTuple[1];
603
+ if (!modifierFn)
604
+ return aliasedAssociationName;
605
+ const modifier = modifierFn(dreamClassAndAssociationNameTuple[0], associationName);
606
+ if (modifier === 'omit')
607
+ return undefined;
608
+ return [aliasedAssociationName, modifier];
609
+ }));
610
+ }
474
611
  /**
475
612
  * Returns a new Query instance, with the provided
476
613
  * joins statement attached
@@ -785,7 +922,7 @@ class Query {
785
922
  * // [User{name: 'a', id: 99}, User{name: 'a', id: 97}, User{ name: 'b', id: 98 } ...]
786
923
  * ```
787
924
  *
788
- * @param orderStatement - Either a string or an object specifying order. If a string, the order is implicitly ascending. If the orderStatement is an object, statements will be provided in the order of the keys set in the object
925
+ * @param arg - Either a string or an object specifying order. If a string, the order is implicitly ascending. If the orderStatement is an object, statements will be provided in the order of the keys set in the object
789
926
  * @returns A cloned Query with the order clause applied
790
927
  */
791
928
  order(arg) {
@@ -887,7 +1024,7 @@ class Query {
887
1024
  * })
888
1025
  * ```
889
1026
  *
890
- * @param txn - A DreamTransaction instance (usually collected by calling `ApplicationModel.transaction`)
1027
+ * @param dreamTransaction - A DreamTransaction instance (usually collected by calling `ApplicationModel.transaction`)
891
1028
  * @returns A cloned Query with the transaction applied
892
1029
  *
893
1030
  */
@@ -1084,6 +1221,7 @@ class Query {
1084
1221
  * // 2
1085
1222
  * ```
1086
1223
  *
1224
+ * @param opts - Pagination options
1087
1225
  * @param opts.page - the page number that you want to fetch results for
1088
1226
  * @param opts.pageSize - the number of results per page (optional)
1089
1227
  * @returns results.recordCount - A number representing the total number of records matching your query
@@ -1247,11 +1385,11 @@ class Query {
1247
1385
  * // 12
1248
1386
  * ```
1249
1387
  *
1250
- * @param options - Options for destroying the instance
1251
- * @param options.skipHooks - If true, skips applying model hooks during the destroy operation. Defaults to false
1252
- * @param options.cascade - If false, skips destroying associations marked `dependent: 'destroy'`. Defaults to true
1253
- * @param options.bypassAllDefaultScopes - If true, bypasses all default scopes when cascade destroying. Defaults to false
1254
- * @param options.defaultScopesToBypass - An array of default scope names to bypass when cascade destroying. Defaults to an empty array
1388
+ * @param __namedParameters - Options for destroying the instance
1389
+ * @param __namedParameters.skipHooks - If true, skips applying model hooks during the destroy operation. Defaults to false
1390
+ * @param __namedParameters.cascade - If false, skips destroying associations marked `dependent: 'destroy'`. Defaults to true
1391
+ * @param __namedParameters.bypassAllDefaultScopes - If true, bypasses all default scopes when cascade destroying. Defaults to false
1392
+ * @param __namedParameters.defaultScopesToBypass - An array of default scope names to bypass when cascade destroying. Defaults to an empty array
1255
1393
  * @returns The number of records that were removed
1256
1394
  */
1257
1395
  async destroy({ skipHooks, cascade, } = {}) {
@@ -1287,18 +1425,18 @@ class Query {
1287
1425
  * were destroyed.
1288
1426
  *
1289
1427
  * To destroy without bypassing the SoftDelete
1290
- * decorator, use {@link Query.(destroy:instance) | destroy} instead.
1428
+ * decorator, use {@link Query.destroy} instead.
1291
1429
  *
1292
1430
  * ```ts
1293
1431
  * await User.where({ email: ops.ilike('%burpcollaborator%') }).reallyDestroy()
1294
1432
  * // 12
1295
1433
  * ```
1296
1434
  *
1297
- * @param options - Options for destroying the instance
1298
- * @param options.skipHooks - If true, skips applying model hooks during the destroy operation. Defaults to false
1299
- * @param options.cascade - If false, skips destroying associations marked `dependent: 'destroy'`. Defaults to true
1300
- * @param options.bypassAllDefaultScopes - If true, bypasses all default scopes when cascade destroying. Defaults to false
1301
- * @param options.defaultScopesToBypass - An array of default scope names to bypass when cascade destroying. Defaults to an empty array
1435
+ * @param __namedParameters - Options for destroying the instance
1436
+ * @param __namedParameters.skipHooks - If true, skips applying model hooks during the destroy operation. Defaults to false
1437
+ * @param __namedParameters.cascade - If false, skips destroying associations marked `dependent: 'destroy'`. Defaults to true
1438
+ * @param __namedParameters.bypassAllDefaultScopes - If true, bypasses all default scopes when cascade destroying. Defaults to false
1439
+ * @param __namedParameters.defaultScopesToBypass - An array of default scope names to bypass when cascade destroying. Defaults to an empty array
1302
1440
  * @returns The number of records that were removed
1303
1441
  */
1304
1442
  async reallyDestroy({ skipHooks, cascade, } = {}) {
@@ -1316,11 +1454,11 @@ class Query {
1316
1454
  * // 12
1317
1455
  * ```
1318
1456
  *
1319
- * @param options - Options for undestroying the instance
1320
- * @param options.skipHooks - If true, skips applying model hooks during the undestroy operation. Defaults to false
1321
- * @param options.cascade - If false, skips undestroying associations marked `dependent: 'destroy'`. Defaults to true
1322
- * @param options.bypassAllDefaultScopes - If true, bypasses all default scopes when cascade undestroying. Defaults to false
1323
- * @param options.defaultScopesToBypass - An array of default scope names to bypass when cascade undestroying (soft delete is always bypassed). Defaults to an empty array
1457
+ * @param __namedParameters - Options for undestroying the instance
1458
+ * @param __namedParameters.skipHooks - If true, skips applying model hooks during the undestroy operation. Defaults to false
1459
+ * @param __namedParameters.cascade - If false, skips undestroying associations marked `dependent: 'destroy'`. Defaults to true
1460
+ * @param __namedParameters.bypassAllDefaultScopes - If true, bypasses all default scopes when cascade undestroying. Defaults to false
1461
+ * @param __namedParameters.defaultScopesToBypass - An array of default scope names to bypass when cascade undestroying (soft delete is always bypassed). Defaults to an empty array
1324
1462
  * @returns The number of records that were removed
1325
1463
  */
1326
1464
  async undestroy({ cascade, skipHooks, } = {}) {
@@ -1348,7 +1486,7 @@ class Query {
1348
1486
  * though cascading may still happen at the database level.
1349
1487
  *
1350
1488
  * To apply model hooks and association dependent destroy,
1351
- * use {@link Query.(destroy:instance) | destroy} instead.
1489
+ * use {@link Query.destroy} instead.
1352
1490
  *
1353
1491
  * ```ts
1354
1492
  * await User.where({ email: ops.ilike('%burpcollaborator%').delete() })
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = extractNestedPaths;
4
+ /**
5
+ * Turns RecursiveSerializerInfo into an array of arrays of tuples,
6
+ * each tuple including a Dream class and an association name
7
+ *
8
+ * E.g., returns the following:
9
+ * ```ts
10
+ * [
11
+ * [[Post, 'a'], [Pet, 'b']],
12
+ * [[Post, 'a'], [Balloon, 'd'], [BalloonLine, 'e']]
13
+ * ]
14
+ * ```
15
+ */
16
+ function extractNestedPaths(obj) {
17
+ const paths = [];
18
+ function traverse(current, currentPath) {
19
+ const associationNames = Object.keys(current);
20
+ if (associationNames.length === 0) {
21
+ paths.push([...currentPath]);
22
+ return;
23
+ }
24
+ for (const associationName of associationNames) {
25
+ const serializerInfo = current[associationName];
26
+ if (serializerInfo === undefined)
27
+ throw new Error('shouldn’t be undefined');
28
+ const dreamClass = serializerInfo.parentDreamClass;
29
+ const nestedSerializerInfo = serializerInfo.nestedSerializerInfo;
30
+ const tuple = [dreamClass, associationName];
31
+ const newPath = [...currentPath, tuple];
32
+ traverse(nestedSerializerInfo, newPath);
33
+ }
34
+ }
35
+ traverse(obj, []);
36
+ return paths;
37
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.indent = indent;
4
+ function indent(number, { tabWidth = 2 } = {}) {
5
+ let spacesString = '';
6
+ const indentationUnit = indentationUnitString(tabWidth);
7
+ for (let i = 0; i < number; i++) {
8
+ spacesString += indentationUnit;
9
+ }
10
+ return spacesString;
11
+ }
12
+ function indentationUnitString(number) {
13
+ let spacesString = '';
14
+ for (let i = 0; i < number; i++) {
15
+ spacesString += ' ';
16
+ }
17
+ return spacesString;
18
+ }
@@ -9,6 +9,7 @@ const snakeify_js_1 = require("../helpers/snakeify.js");
9
9
  const DreamSerializerBuilder_js_1 = require("./builders/DreamSerializerBuilder.js");
10
10
  const ObjectSerializerBuilder_js_1 = require("./builders/ObjectSerializerBuilder.js");
11
11
  const inferSerializerFromDreamOrViewModel_js_1 = require("./helpers/inferSerializerFromDreamOrViewModel.js");
12
+ const serializerForAssociatedClass_js_1 = require("./helpers/serializerForAssociatedClass.js");
12
13
  class SerializerRenderer {
13
14
  serializerBuilder;
14
15
  passthroughData;
@@ -98,7 +99,7 @@ class SerializerRenderer {
98
99
  * we need something to determine the keys that will be flattened into the
99
100
  * rendering serializer
100
101
  */
101
- serializer = serializerForAssociatedClass(data, attribute.name, attribute.options);
102
+ serializer = (0, serializerForAssociatedClass_js_1.serializerForAssociatedClass)(data, attribute.name, attribute.options);
102
103
  }
103
104
  const serializerBuilder = serializer?.(attribute.options.flatten ? (associatedObject ?? {}) : associatedObject,
104
105
  // passthrough data going into the serializer is the argument that gets
@@ -204,19 +205,3 @@ function serializerForAssociatedObject(associatedObject, options) {
204
205
  return options.serializer;
205
206
  return (0, inferSerializerFromDreamOrViewModel_js_1.default)(associatedObject, options.serializerKey);
206
207
  }
207
- /**
208
- * Only used when flatten: true, and the associated model is null, in which case,
209
- * we need something to determine the keys that will be flattened into the
210
- * rendering serializer
211
- */
212
- function serializerForAssociatedClass(object, associationName, options) {
213
- if (options.serializer)
214
- return options.serializer;
215
- if (!object.isDreamInstance)
216
- return null;
217
- const dream = object;
218
- const association = dream['getAssociationMetadata'](associationName);
219
- const associatedClasses = association.modelCB();
220
- const associatedClass = Array.isArray(associatedClasses) ? associatedClasses[0] : associatedClasses;
221
- return (0, inferSerializerFromDreamOrViewModel_js_1.inferSerializersFromDreamClassOrViewModelClass)(associatedClass, options.serializerKey)[0] ?? null;
222
- }
@@ -22,15 +22,74 @@ class DreamSerializerBuilder {
22
22
  });
23
23
  return this;
24
24
  }
25
+ /**
26
+ * Includes an attribute from a nested object in the serialized output.
27
+ *
28
+ * Serializes an attribute from a target object. If the target object or
29
+ * the delegated attribute is null/undefined, the `default` option value
30
+ * will be used if provided.
31
+ *
32
+ * @param targetName - The property name containing the target object
33
+ * @param name - The attribute name within the target object
34
+ * @param options - Configuration options including OpenAPI schema, default value, and output customization
35
+ * @returns The serializer builder for method chaining
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * // Delegate to user.email
40
+ * .delegatedAttribute('user', 'email', {
41
+ * openapi: { type: 'string', format: 'email' }
42
+ * })
43
+ *
44
+ * // With default value for null target or attribute
45
+ * .delegatedAttribute('user', 'displayName', {
46
+ * openapi: { type: 'string' },
47
+ * default: 'Unknown User'
48
+ * })
49
+ * ```
50
+ *
51
+ * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
52
+ */
25
53
  delegatedAttribute(targetName, name, options) {
26
54
  this.attributes.push({
27
55
  type: 'delegatedAttribute',
28
- targetName,
56
+ targetName: targetName,
29
57
  name: name,
30
58
  options: options ?? {},
31
59
  });
32
60
  return this;
33
61
  }
62
+ /**
63
+ * Includes a computed value in the serialized output.
64
+ *
65
+ * Executes a callback function to generate a custom attribute value.
66
+ * The `openapi` option is always required since the return type cannot be inferred.
67
+ *
68
+ * @param name - The attribute name for the computed value
69
+ * @param fn - Callback function that returns the computed value
70
+ * @param options - Configuration options including required OpenAPI schema and optional flattening
71
+ * @returns The serializer builder for method chaining
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * // Simple computed value
76
+ * .customAttribute('initials', () =>
77
+ * `${user.firstName?.[0]}${user.lastName?.[0]}`.toUpperCase(),
78
+ * { openapi: { type: 'string' } }
79
+ * )
80
+ *
81
+ * // Flattened object properties
82
+ * .customAttribute('metadata', () => ({ age: 30, city: 'NYC' }), {
83
+ * flatten: true,
84
+ * openapi: {
85
+ * age: { type: 'integer' },
86
+ * city: { type: 'string' }
87
+ * }
88
+ * })
89
+ * ```
90
+ *
91
+ * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
92
+ */
34
93
  customAttribute(name, fn, options) {
35
94
  this.attributes.push({
36
95
  type: 'customAttribute',
@@ -40,22 +99,99 @@ class DreamSerializerBuilder {
40
99
  });
41
100
  return this;
42
101
  }
102
+ /**
103
+ * Includes a single associated object in the serialized output.
104
+ *
105
+ * When rendering a Dream association, the OpenAPI shape is automatically
106
+ * inferred from that associated Dream's serializer.
107
+ *
108
+ * @param name - The association property name
109
+ * @param options - Configuration options for serialization and schema definition
110
+ * @returns The serializer builder for method chaining
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // DreamSerializer with inference
115
+ * .rendersOne('user') // Infers from Dream association
116
+ *
117
+ * // With specific serializer
118
+ * .rendersOne('user', { serializerKey: 'summary' })
119
+ *
120
+ * // ObjectSerializer (explicit configuration required)
121
+ * .rendersOne('owner', UserSerializer, {
122
+ * openapi: { $ref: '#/components/schemas/User' }
123
+ * })
124
+ * ```
125
+ *
126
+ * See: {@link https://your-docs-url.com/docs/serializers/associations | Serializer Associations Documentation}
127
+ */
43
128
  rendersOne(name, options) {
44
129
  this.attributes.push({
45
130
  type: 'rendersOne',
46
- name,
131
+ name: name,
47
132
  options: options ?? {},
48
133
  });
49
134
  return this;
50
135
  }
136
+ /**
137
+ * Includes an array of associated objects in the serialized output.
138
+ *
139
+ * When rendering a Dream association, the OpenAPI shape is automatically
140
+ * inferred from that associated Dream's serializer.
141
+ *
142
+ * @param name - The association property name (should be an array)
143
+ * @param options - Configuration options for serialization and schema definition
144
+ * @returns The serializer builder for method chaining
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * // DreamSerializer with inference
149
+ * .rendersMany('posts') // Infers from Dream association
150
+ *
151
+ * // With specific serializer
152
+ * .rendersMany('posts', { serializerKey: 'summary' })
153
+ *
154
+ * // ObjectSerializer (explicit configuration required)
155
+ * .rendersMany('articles', ArticleSerializer, {
156
+ * openapi: {
157
+ * type: 'array',
158
+ * items: { $ref: '#/components/schemas/Article' }
159
+ * }
160
+ * })
161
+ * ```
162
+ *
163
+ * See: {@link https://your-docs-url.com/docs/serializers/associations | Serializer Associations Documentation}
164
+ */
51
165
  rendersMany(name, options) {
52
166
  this.attributes.push({
53
167
  type: 'rendersMany',
54
- name,
168
+ name: name,
55
169
  options: options ?? {},
56
170
  });
57
171
  return this;
58
172
  }
173
+ /**
174
+ * Executes the serializer and returns the serialized output.
175
+ *
176
+ * This method processes all defined attributes, custom attributes, delegated attributes,
177
+ * and associations to produce the final serialized object. The result is suitable for
178
+ * JSON.stringify() and API responses.
179
+ *
180
+ * @param passthrough - Additional data to pass through to nested serializers
181
+ * @param opts - Rendering options for customizing the serialization process
182
+ * @returns The serialized object
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * const result = UserSerializer(user).render()
187
+ * // Returns: { id: 1, email: 'user@example.com', ... }
188
+ *
189
+ * // With passthrough data
190
+ * const result = UserSerializer(user).render({ currentUserId: 123 })
191
+ * ```
192
+ *
193
+ * See: {@link https://your-docs-url.com/docs/serializers/render | Serializer Rendering Documentation}
194
+ */
59
195
  render(passthrough = {}, opts = {}) {
60
196
  return new SerializerRenderer_js_1.default(this, passthrough, opts).render();
61
197
  }