@rvoh/dream 2.5.6 → 2.5.8

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 (217) hide show
  1. package/dist/cjs/src/Dream.js +25 -10
  2. package/dist/cjs/src/decorators/class/STI.js +2 -2
  3. package/dist/cjs/src/dream/LeftJoinLoadBuilder.js +16 -10
  4. package/dist/cjs/src/dream/LoadBuilder.js +15 -9
  5. package/dist/cjs/src/dream/Query.js +1 -1
  6. package/dist/cjs/src/dream/internal/similarity/SimilarityBuilder.js +3 -1
  7. package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +110 -52
  8. package/dist/cjs/src/serializer/builders/ObjectSerializerBuilder.js +111 -41
  9. package/dist/esm/src/Dream.js +25 -10
  10. package/dist/esm/src/decorators/class/STI.js +2 -2
  11. package/dist/esm/src/dream/LeftJoinLoadBuilder.js +16 -10
  12. package/dist/esm/src/dream/LoadBuilder.js +15 -9
  13. package/dist/esm/src/dream/Query.js +1 -1
  14. package/dist/esm/src/dream/internal/similarity/SimilarityBuilder.js +3 -1
  15. package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +110 -52
  16. package/dist/esm/src/serializer/builders/ObjectSerializerBuilder.js +111 -41
  17. package/dist/types/src/Dream.d.ts +25 -10
  18. package/dist/types/src/decorators/Decorators.d.ts +8 -0
  19. package/dist/types/src/decorators/class/STI.d.ts +1 -3
  20. package/dist/types/src/decorators/field/sortable/Sortable.d.ts +9 -0
  21. package/dist/types/src/decorators/field/validation/Validates.d.ts +4 -0
  22. package/dist/types/src/decorators/static-method/Scope.d.ts +4 -0
  23. package/dist/types/src/dream/LeftJoinLoadBuilder.d.ts +16 -10
  24. package/dist/types/src/dream/LoadBuilder.d.ts +15 -9
  25. package/dist/types/src/dream/Query.d.ts +1 -1
  26. package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +151 -59
  27. package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +123 -41
  28. package/dist/types/src/types/associations/belongsTo.d.ts +34 -0
  29. package/dist/types/src/types/associations/belongsTo.ts +41 -0
  30. package/dist/types/src/types/associations/hasMany.d.ts +18 -0
  31. package/dist/types/src/types/associations/hasMany.ts +18 -0
  32. package/dist/types/src/types/associations/shared.d.ts +71 -0
  33. package/dist/types/src/types/associations/shared.ts +74 -0
  34. package/dist/types/src/types/dream.d.ts +16 -0
  35. package/dist/types/src/types/dream.ts +18 -0
  36. package/dist/types/src/types/lifecycle.d.ts +18 -0
  37. package/dist/types/src/types/lifecycle.ts +18 -0
  38. package/dist/types/src/types/query.d.ts +3 -0
  39. package/dist/types/src/types/query.ts +3 -0
  40. package/docs/classes/db.DreamMigrationHelpers.html +9 -9
  41. package/docs/classes/db.KyselyQueryDriver.html +32 -32
  42. package/docs/classes/db.PostgresQueryDriver.html +33 -33
  43. package/docs/classes/db.QueryDriverBase.html +31 -31
  44. package/docs/classes/errors.CheckConstraintViolation.html +3 -3
  45. package/docs/classes/errors.ColumnOverflow.html +3 -3
  46. package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
  47. package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
  48. package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
  49. package/docs/classes/errors.GlobalNameNotSet.html +3 -3
  50. package/docs/classes/errors.InvalidCalendarDate.html +2 -2
  51. package/docs/classes/errors.InvalidClockTime.html +2 -2
  52. package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
  53. package/docs/classes/errors.InvalidDateTime.html +2 -2
  54. package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
  55. package/docs/classes/errors.NonLoadedAssociation.html +3 -3
  56. package/docs/classes/errors.NotNullViolation.html +3 -3
  57. package/docs/classes/errors.RecordNotFound.html +3 -3
  58. package/docs/classes/errors.ValidationError.html +3 -3
  59. package/docs/classes/index.CalendarDate.html +33 -33
  60. package/docs/classes/index.ClockTime.html +32 -32
  61. package/docs/classes/index.ClockTimeTz.html +35 -35
  62. package/docs/classes/index.DateTime.html +86 -86
  63. package/docs/classes/index.Decorators.html +21 -20
  64. package/docs/classes/index.Dream.html +133 -126
  65. package/docs/classes/index.DreamApp.html +5 -5
  66. package/docs/classes/index.DreamTransaction.html +2 -2
  67. package/docs/classes/index.Env.html +2 -2
  68. package/docs/classes/index.Query.html +57 -57
  69. package/docs/classes/system.CliFileWriter.html +4 -4
  70. package/docs/classes/system.DreamBin.html +2 -2
  71. package/docs/classes/system.DreamCLI.html +6 -6
  72. package/docs/classes/system.DreamImporter.html +2 -2
  73. package/docs/classes/system.DreamLogos.html +2 -2
  74. package/docs/classes/system.DreamSerializerBuilder.html +172 -58
  75. package/docs/classes/system.ObjectSerializerBuilder.html +109 -33
  76. package/docs/classes/system.PathHelpers.html +3 -3
  77. package/docs/classes/utils.Encrypt.html +2 -2
  78. package/docs/classes/utils.Range.html +2 -2
  79. package/docs/functions/db.closeAllDbConnections.html +1 -1
  80. package/docs/functions/db.dreamDbConnections.html +1 -1
  81. package/docs/functions/db.untypedDb.html +1 -1
  82. package/docs/functions/db.validateColumn.html +1 -1
  83. package/docs/functions/db.validateTable.html +1 -1
  84. package/docs/functions/errors.pgErrorType.html +1 -1
  85. package/docs/functions/index.DreamSerializer.html +1 -1
  86. package/docs/functions/index.ObjectSerializer.html +1 -1
  87. package/docs/functions/index.ReplicaSafe.html +1 -1
  88. package/docs/functions/index.STI.html +1 -1
  89. package/docs/functions/index.SoftDelete.html +1 -1
  90. package/docs/functions/utils.camelize.html +1 -1
  91. package/docs/functions/utils.capitalize.html +1 -1
  92. package/docs/functions/utils.cloneDeepSafe.html +1 -1
  93. package/docs/functions/utils.compact.html +1 -1
  94. package/docs/functions/utils.groupBy.html +1 -1
  95. package/docs/functions/utils.hyphenize.html +1 -1
  96. package/docs/functions/utils.intersection.html +1 -1
  97. package/docs/functions/utils.isEmpty.html +1 -1
  98. package/docs/functions/utils.normalizeUnicode.html +1 -1
  99. package/docs/functions/utils.pascalize.html +1 -1
  100. package/docs/functions/utils.percent.html +1 -1
  101. package/docs/functions/utils.range.html +1 -1
  102. package/docs/functions/utils.round.html +1 -1
  103. package/docs/functions/utils.sanitizeString.html +1 -1
  104. package/docs/functions/utils.snakeify.html +1 -1
  105. package/docs/functions/utils.sort.html +1 -1
  106. package/docs/functions/utils.sortBy.html +1 -1
  107. package/docs/functions/utils.sortObjectByKey.html +1 -1
  108. package/docs/functions/utils.sortObjectByValue.html +1 -1
  109. package/docs/functions/utils.uncapitalize.html +1 -1
  110. package/docs/functions/utils.uniq.html +1 -1
  111. package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
  112. package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
  113. package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
  114. package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
  115. package/docs/interfaces/types.BelongsToStatement.html +2 -2
  116. package/docs/interfaces/types.DecoratorContext.html +2 -2
  117. package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
  118. package/docs/interfaces/types.DreamAppOpts.html +2 -2
  119. package/docs/interfaces/types.DurationObject.html +2 -2
  120. package/docs/interfaces/types.EncryptOptions.html +2 -2
  121. package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
  122. package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
  123. package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
  124. package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
  125. package/docs/types/openapi.OpenapiAllTypes.html +1 -1
  126. package/docs/types/openapi.OpenapiFormats.html +1 -1
  127. package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
  128. package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
  129. package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
  130. package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
  131. package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
  132. package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
  133. package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
  134. package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
  135. package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
  136. package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
  137. package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
  138. package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
  139. package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
  140. package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
  141. package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
  142. package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
  143. package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
  144. package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
  145. package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
  146. package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
  147. package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
  148. package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
  149. package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
  150. package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
  151. package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
  152. package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
  153. package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
  154. package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
  155. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
  156. package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
  157. package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
  158. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
  159. package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
  160. package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
  161. package/docs/types/openapi.OpenapiSchemaString.html +1 -1
  162. package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
  163. package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
  164. package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
  165. package/docs/types/openapi.OpenapiTypeField.html +1 -1
  166. package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
  167. package/docs/types/types.CalendarDateDurationUnit.html +1 -1
  168. package/docs/types/types.CalendarDateObject.html +1 -1
  169. package/docs/types/types.Camelized.html +1 -1
  170. package/docs/types/types.ClockTimeObject.html +1 -1
  171. package/docs/types/types.DbConnectionType.html +1 -1
  172. package/docs/types/types.DbTypes.html +1 -1
  173. package/docs/types/types.DreamAssociationMetadata.html +1 -1
  174. package/docs/types/types.DreamAttributes.html +1 -1
  175. package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
  176. package/docs/types/types.DreamClassColumn.html +1 -1
  177. package/docs/types/types.DreamColumn.html +1 -1
  178. package/docs/types/types.DreamColumnNames.html +1 -1
  179. package/docs/types/types.DreamLogLevel.html +1 -1
  180. package/docs/types/types.DreamLogger.html +2 -2
  181. package/docs/types/types.DreamModelSerializerType.html +1 -1
  182. package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
  183. package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
  184. package/docs/types/types.DreamParamSafeAttributes.html +1 -1
  185. package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
  186. package/docs/types/types.DreamSerializable.html +1 -1
  187. package/docs/types/types.DreamSerializableArray.html +1 -1
  188. package/docs/types/types.DreamSerializerKey.html +1 -1
  189. package/docs/types/types.DreamSerializers.html +1 -1
  190. package/docs/types/types.DreamVirtualColumns.html +1 -1
  191. package/docs/types/types.DurationUnit.html +1 -1
  192. package/docs/types/types.EncryptAlgorithm.html +1 -1
  193. package/docs/types/types.HasManyStatement.html +1 -1
  194. package/docs/types/types.HasOneStatement.html +1 -1
  195. package/docs/types/types.Hyphenized.html +1 -1
  196. package/docs/types/types.Pascalized.html +1 -1
  197. package/docs/types/types.PrimaryKeyType.html +1 -1
  198. package/docs/types/types.RoundingPrecision.html +1 -1
  199. package/docs/types/types.SerializerCasing.html +1 -1
  200. package/docs/types/types.SimpleObjectSerializerType.html +1 -1
  201. package/docs/types/types.Snakeified.html +1 -1
  202. package/docs/types/types.StrictInterface.html +1 -1
  203. package/docs/types/types.UpdateableAssociationProperties.html +1 -1
  204. package/docs/types/types.UpdateableProperties.html +1 -1
  205. package/docs/types/types.ValidationType.html +1 -1
  206. package/docs/types/types.ViewModel.html +2 -2
  207. package/docs/types/types.ViewModelClass.html +1 -1
  208. package/docs/types/types.WeekdayName.html +1 -1
  209. package/docs/types/types.WhereStatementForDream.html +1 -1
  210. package/docs/types/types.WhereStatementForDreamClass.html +1 -1
  211. package/docs/variables/index.DreamConst.html +1 -1
  212. package/docs/variables/index.ops.html +1 -1
  213. package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
  214. package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
  215. package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
  216. package/docs/variables/system.primaryKeyTypes.html +1 -1
  217. package/package.json +1 -1
@@ -20,30 +20,46 @@ export default class DreamSerializerBuilder {
20
20
  /**
21
21
  * Includes an attribute from a nested object in the serialized output.
22
22
  *
23
- * Serializes an attribute from a target object. If the target object or
24
- * the delegated attribute is null/undefined, the `default` option value
23
+ * Accesses `targetName.name` on the data object. If the target object
24
+ * or the delegated attribute is null/undefined, the `default` option value
25
25
  * will be used if provided.
26
26
  *
27
- * @param targetName - The property name containing the target object
27
+ * When the target is a Dream model, OpenAPI types may be automatically inferred
28
+ * for standard database columns. For json/jsonb columns or non-Dream targets,
29
+ * the `openapi` option is required.
30
+ *
31
+ * @param targetName - The property name containing the target object (e.g., an association name)
28
32
  * @param name - The attribute name within the target object
29
- * @param options - Configuration options including OpenAPI schema, default value, and output customization
33
+ * @param options - Configuration options:
34
+ * - `as` - Rename the attribute key in the serialized output and OpenAPI shape
35
+ * (e.g., delegating `'user', 'email'` with `as: 'userEmail'` outputs the value
36
+ * under `userEmail`)
37
+ * - `default` - Value to use when the target object or its attribute is null/undefined
38
+ * - `openapi` - OpenAPI schema definition; required for non-Dream targets and json/jsonb
39
+ * columns, optional for standard Dream columns (where types are inferred)
40
+ * - `precision` - Round decimal values to the specified number of decimal places (0–9)
41
+ * during rendering; does not affect the OpenAPI shape
42
+ * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
43
+ * when omitted, attributes are required by default
30
44
  * @returns The serializer builder for method chaining
31
45
  *
32
46
  * @example
33
47
  * ```typescript
34
- * // Delegate to user.email
35
- * .delegatedAttribute('user', 'email', {
36
- * openapi: { type: 'string', format: 'email' }
37
- * })
48
+ * // Delegate to a Dream association's column (type inferred)
49
+ * .delegatedAttribute('currentLocalizedText', 'title', { openapi: 'string' })
38
50
  *
39
51
  * // With default value for null target or attribute
40
52
  * .delegatedAttribute('user', 'displayName', {
41
53
  * openapi: { type: 'string' },
42
54
  * default: 'Unknown User'
43
55
  * })
44
- * ```
45
56
  *
46
- * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
57
+ * // Rename the output key
58
+ * .delegatedAttribute('profile', 'avatarUrl', {
59
+ * openapi: 'string',
60
+ * as: 'avatar'
61
+ * })
62
+ * ```
47
63
  */
48
64
  delegatedAttribute(targetName, name, options) {
49
65
  this.attributes.push({
@@ -62,7 +78,17 @@ export default class DreamSerializerBuilder {
62
78
  *
63
79
  * @param name - The attribute name for the computed value
64
80
  * @param fn - Callback function that returns the computed value
65
- * @param options - Configuration options including required OpenAPI schema and optional flattening
81
+ * @param options - Configuration options:
82
+ * - `openapi` - (required) OpenAPI schema definition for the computed value
83
+ * - `as` - Rename the attribute key in the serialized output and OpenAPI shape
84
+ * - `default` - Value to use when the callback returns undefined
85
+ * - `flatten` - When `true`, spreads the returned object's properties directly into the
86
+ * parent serialized output instead of nesting them under `name`; the `openapi` option
87
+ * should then define each flattened property individually
88
+ * - `precision` - Round decimal values to the specified number of decimal places (0–9)
89
+ * during rendering; does not affect the OpenAPI shape
90
+ * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
91
+ * when omitted, attributes are required by default
66
92
  * @returns The serializer builder for method chaining
67
93
  *
68
94
  * @example
@@ -74,16 +100,20 @@ export default class DreamSerializerBuilder {
74
100
  * )
75
101
  *
76
102
  * // Flattened object properties
77
- * .customAttribute('metadata', () => ({ age: 30, city: 'NYC' }), {
103
+ * .customAttribute('coordinates', () => ({ lat: 40.7, lng: -74.0 }), {
78
104
  * flatten: true,
79
105
  * openapi: {
80
- * age: { type: 'integer' },
81
- * city: { type: 'string' }
106
+ * lat: { type: 'number' },
107
+ * lng: { type: 'number' }
82
108
  * }
83
109
  * })
84
- * ```
85
110
  *
86
- * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
111
+ * // With decimal precision
112
+ * .customAttribute('averageRating', () => calculateAverage(ratings), {
113
+ * openapi: 'decimal',
114
+ * precision: 2
115
+ * })
116
+ * ```
87
117
  */
88
118
  customAttribute(name, fn, options) {
89
119
  this.attributes.push({
@@ -97,28 +127,50 @@ export default class DreamSerializerBuilder {
97
127
  /**
98
128
  * Includes a single associated object in the serialized output.
99
129
  *
100
- * When rendering a Dream association, the OpenAPI shape is automatically
101
- * inferred from that associated Dream's serializer.
130
+ * When rendering a Dream association, the serializer and OpenAPI shape are automatically
131
+ * inferred from that associated Dream model's registered serializers.
102
132
  *
103
133
  * @param name - The association property name
104
- * @param options - Configuration options for serialization and schema definition
134
+ * @param options - Configuration options:
135
+ * - `as` - Rename the association key in the serialized output
136
+ * - `flatten` - When `true`, spreads the rendered association's attributes directly into
137
+ * the parent serialized output instead of nesting them under `name`. Be aware of
138
+ * attribute shadowing: if the parent and flattened association share attribute names
139
+ * (e.g., `id`), the flattened association's values overwrite the parent's
140
+ * - `optional` - When `true`, allows the association to be null/missing without causing
141
+ * an `OpenapiResponseValidationFailure` during Psychic controller unit specs. By default,
142
+ * `rendersOne` expects the association to be present (mirroring the `optional` option on
143
+ * `@deco.BelongsTo`). Set this to `true` when the association is genuinely nullable
144
+ * - `serializerKey` - Use a specific serializer key from the associated Dream model's
145
+ * registered serializers (e.g., `'summary'`)
146
+ * - `serializer` - Provide an explicit serializer function instead of using the
147
+ * associated model's registered serializers
148
+ *
149
+ * For ViewModel associations, one of these is required:
150
+ * - `viewModelClass` + optional `serializerKey`
151
+ * - `serializer`
152
+ *
153
+ * For non-Dream/non-ViewModel associations:
154
+ * - `serializer` is required
105
155
  * @returns The serializer builder for method chaining
106
156
  *
107
157
  * @example
108
158
  * ```typescript
109
- * // DreamSerializer with inference
110
- * .rendersOne('user') // Infers from Dream association
159
+ * // Auto-infer serializer from Dream association
160
+ * .rendersOne('profile')
111
161
  *
112
- * // With specific serializer
162
+ * // With specific serializer key
113
163
  * .rendersOne('user', { serializerKey: 'summary' })
114
164
  *
115
- * // ObjectSerializer (explicit configuration required)
116
- * .rendersOne('owner', UserSerializer, {
117
- * openapi: { $ref: '#/components/schemas/User' }
118
- * })
119
- * ```
165
+ * // Allow null association
166
+ * .rendersOne('approver', { optional: true })
120
167
  *
121
- * See: {@link https://your-docs-url.com/docs/serializers/associations | Serializer Associations Documentation}
168
+ * // Flatten into parent object
169
+ * .rendersOne('candidate', { serializerKey: 'summary', flatten: true })
170
+ *
171
+ * // Explicit serializer function
172
+ * .rendersOne('owner', { serializer: CustomOwnerSerializer })
173
+ * ```
122
174
  */
123
175
  rendersOne(name, options) {
124
176
  this.attributes.push({
@@ -131,31 +183,39 @@ export default class DreamSerializerBuilder {
131
183
  /**
132
184
  * Includes an array of associated objects in the serialized output.
133
185
  *
134
- * When rendering a Dream association, the OpenAPI shape is automatically
135
- * inferred from that associated Dream's serializer.
186
+ * When rendering a Dream association, the serializer and OpenAPI shape are automatically
187
+ * inferred from that associated Dream model's registered serializers.
188
+ *
189
+ * @param name - The association property name (should resolve to an array)
190
+ * @param options - Configuration options:
191
+ * - `as` - Rename the association key in the serialized output
192
+ * - `serializerKey` - Use a specific serializer key from the associated Dream model's
193
+ * registered serializers (e.g., `'summary'`)
194
+ * - `serializer` - Provide an explicit serializer function instead of using the
195
+ * associated model's registered serializers
136
196
  *
137
- * @param name - The association property name (should be an array)
138
- * @param options - Configuration options for serialization and schema definition
197
+ * For ViewModel associations, one of these is required:
198
+ * - `viewModelClass` + optional `serializerKey`
199
+ * - `serializer`
200
+ *
201
+ * For non-Dream/non-ViewModel associations:
202
+ * - `serializer` is required
139
203
  * @returns The serializer builder for method chaining
140
204
  *
141
205
  * @example
142
206
  * ```typescript
143
- * // DreamSerializer with inference
144
- * .rendersMany('posts') // Infers from Dream association
207
+ * // Auto-infer serializer from Dream association
208
+ * .rendersMany('rooms')
145
209
  *
146
- * // With specific serializer
147
- * .rendersMany('posts', { serializerKey: 'summary' })
210
+ * // With specific serializer key
211
+ * .rendersMany('rooms', { serializerKey: 'summary' })
148
212
  *
149
- * // ObjectSerializer (explicit configuration required)
150
- * .rendersMany('articles', ArticleSerializer, {
151
- * openapi: {
152
- * type: 'array',
153
- * items: { $ref: '#/components/schemas/Article' }
154
- * }
155
- * })
156
- * ```
213
+ * // Explicit serializer function (for non-Dream objects)
214
+ * .rendersMany('bedTypes', { serializer: BedTypeSerializer })
157
215
  *
158
- * See: {@link https://your-docs-url.com/docs/serializers/associations | Serializer Associations Documentation}
216
+ * // Rename output key
217
+ * .rendersMany('rooms', { serializerKey: 'forGuests', as: 'guestRooms' })
218
+ * ```
159
219
  */
160
220
  rendersMany(name, options) {
161
221
  this.attributes.push({
@@ -168,24 +228,22 @@ export default class DreamSerializerBuilder {
168
228
  /**
169
229
  * Executes the serializer and returns the serialized output.
170
230
  *
171
- * This method processes all defined attributes, custom attributes, delegated attributes,
172
- * and associations to produce the final serialized object. The result is suitable for
173
- * JSON.stringify() and API responses.
231
+ * Processes all defined attributes, custom attributes, delegated attributes,
232
+ * and associations to produce the final serialized object.
174
233
  *
175
234
  * @param passthrough - Additional data to pass through to nested serializers
235
+ * (e.g., locale, current user context)
176
236
  * @param opts - Rendering options for customizing the serialization process
177
- * @returns The serialized object
237
+ * @returns The serialized object, suitable for JSON responses
178
238
  *
179
239
  * @example
180
240
  * ```typescript
181
241
  * const result = UserSerializer(user).render()
182
242
  * // Returns: { id: 1, email: 'user@example.com', ... }
183
243
  *
184
- * // With passthrough data
244
+ * // With passthrough data for nested serializers
185
245
  * const result = UserSerializer(user).render({ currentUserId: 123 })
186
246
  * ```
187
- *
188
- * See: {@link https://your-docs-url.com/docs/serializers/render | Serializer Rendering Documentation}
189
247
  */
190
248
  render(passthrough = {}, opts = {}) {
191
249
  return new SerializerRenderer(this, passthrough, opts).render();
@@ -14,7 +14,15 @@ export default class ObjectSerializerBuilder {
14
14
  * inference is not available for plain objects or ViewModels.
15
15
  *
16
16
  * @param name - The attribute name from the data object
17
- * @param options - Configuration options including required OpenAPI schema, default value, and output customization
17
+ * @param options - Configuration options:
18
+ * - `openapi` - (required) OpenAPI schema definition for the attribute
19
+ * - `as` - Rename the attribute key in the serialized output and OpenAPI shape
20
+ * - `default` - Value to use when the attribute is undefined
21
+ * - `precision` - Round decimal values to the specified number of decimal places (0–9)
22
+ * during rendering; does not affect the OpenAPI shape
23
+ * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
24
+ * when omitted, attributes are required by default, meaning `undefined` values will
25
+ * serialize as `null`
18
26
  * @returns The serializer builder for method chaining
19
27
  *
20
28
  * @example
@@ -35,9 +43,19 @@ export default class ObjectSerializerBuilder {
35
43
  * openapi: { type: 'string' },
36
44
  * as: 'userEmail'
37
45
  * })
38
- * ```
39
46
  *
40
- * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
47
+ * // Round decimal to 2 places
48
+ * .attribute('price', {
49
+ * openapi: 'decimal',
50
+ * precision: 2
51
+ * })
52
+ *
53
+ * // Mark as optional in OpenAPI (omitted from response when undefined)
54
+ * .attribute('nickname', {
55
+ * openapi: 'string',
56
+ * required: false
57
+ * })
58
+ * ```
41
59
  */
42
60
  attribute(name, options) {
43
61
  this.attributes.push({
@@ -50,13 +68,22 @@ export default class ObjectSerializerBuilder {
50
68
  /**
51
69
  * Includes an attribute from a nested object in the serialized output.
52
70
  *
53
- * Pulls up an attribute from a target object property. The `openapi` option
54
- * is always required. If the target object or the delegated attribute
55
- * is null/undefined, the `default` option value will be used if provided.
71
+ * Accesses `targetName.name` on the data object. The `openapi` option is always
72
+ * required. If the target object or the delegated attribute is null/undefined,
73
+ * the `default` option value will be used if provided.
56
74
  *
57
75
  * @param targetName - The property name containing the target object
58
76
  * @param name - The attribute name within the target object
59
- * @param options - Configuration options including required OpenAPI schema, default value, and output customization
77
+ * @param options - Configuration options:
78
+ * - `openapi` - (required) OpenAPI schema definition for the attribute
79
+ * - `as` - Rename the attribute key in the serialized output and OpenAPI shape
80
+ * (e.g., delegating `'profile', 'avatarUrl'` with `as: 'avatar'` outputs the value
81
+ * under `avatar`)
82
+ * - `default` - Value to use when the target object or its attribute is null/undefined
83
+ * - `precision` - Round decimal values to the specified number of decimal places (0–9)
84
+ * during rendering; does not affect the OpenAPI shape
85
+ * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
86
+ * when omitted, attributes are required by default
60
87
  * @returns The serializer builder for method chaining
61
88
  *
62
89
  * @example
@@ -71,9 +98,13 @@ export default class ObjectSerializerBuilder {
71
98
  * openapi: { type: 'string' },
72
99
  * default: 'Anonymous User'
73
100
  * })
74
- * ```
75
101
  *
76
- * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
102
+ * // Rename the output key
103
+ * .delegatedAttribute('profile', 'avatarUrl', {
104
+ * openapi: 'string',
105
+ * as: 'avatar'
106
+ * })
107
+ * ```
77
108
  */
78
109
  delegatedAttribute(targetName, name, options) {
79
110
  this.attributes.push({
@@ -90,9 +121,19 @@ export default class ObjectSerializerBuilder {
90
121
  * Executes a callback function to generate a custom attribute value.
91
122
  * The `openapi` option is always required since the return type cannot be inferred.
92
123
  *
124
+ * Unlike DreamSerializerBuilder's `customAttribute`, this version does not support `as`
125
+ * or `precision`.
126
+ *
93
127
  * @param name - The attribute name for the computed value
94
128
  * @param fn - Callback function that returns the computed value
95
- * @param options - Configuration options including required OpenAPI schema and optional flattening
129
+ * @param options - Configuration options:
130
+ * - `openapi` - (required) OpenAPI schema definition for the computed value
131
+ * - `default` - Value to use when the callback returns undefined
132
+ * - `flatten` - When `true`, spreads the returned object's properties directly into the
133
+ * parent serialized output instead of nesting them under `name`; the `openapi` option
134
+ * should then define each flattened property individually
135
+ * - `required` - Set to `false` to mark the attribute as optional in the OpenAPI schema;
136
+ * when omitted, attributes are required by default
96
137
  * @returns The serializer builder for method chaining
97
138
  *
98
139
  * @example
@@ -112,8 +153,6 @@ export default class ObjectSerializerBuilder {
112
153
  * }
113
154
  * })
114
155
  * ```
115
- *
116
- * See: {@link https://your-docs-url.com/docs/serializers/attributes | Serializer Attributes Documentation}
117
156
  */
118
157
  customAttribute(name, fn, options) {
119
158
  this.attributes.push({
@@ -131,25 +170,47 @@ export default class ObjectSerializerBuilder {
131
170
  * since association schemas cannot be inferred from plain objects.
132
171
  *
133
172
  * @param name - The association property name
134
- * @param options - Configuration options including required serializer and OpenAPI schema
173
+ * @param options - Configuration options:
174
+ * - `as` - Rename the association key in the serialized output
175
+ * - `flatten` - When `true`, spreads the rendered association's attributes directly into
176
+ * the parent serialized output instead of nesting them under `name`. Be aware of
177
+ * attribute shadowing: if the parent and flattened association share attribute names
178
+ * (e.g., `id`), the flattened association's values overwrite the parent's
179
+ * - `optional` - When `true`, allows the association to be null/missing without causing
180
+ * an `OpenapiResponseValidationFailure` during Psychic controller unit specs. By default,
181
+ * `rendersOne` expects the association to be present (mirroring the `optional` option on
182
+ * `@deco.BelongsTo`). Set this to `true` when the association is genuinely nullable
183
+ *
184
+ * For Dream associations:
185
+ * - `dreamClass` - The Dream model class, enabling serializer inference; when specified,
186
+ * `serializerKey` may also be provided to select a specific registered serializer
187
+ * - `serializer` - Provide an explicit serializer function
188
+ *
189
+ * For ViewModel associations:
190
+ * - `viewModelClass` + optional `serializerKey`
191
+ * - `serializer`
192
+ *
193
+ * For non-Dream/non-ViewModel associations:
194
+ * - `serializer` is required
135
195
  * @returns The serializer builder for method chaining
136
196
  *
137
197
  * @example
138
198
  * ```typescript
139
199
  * // With explicit serializer function
140
- * .rendersOne('owner', UserSerializer, {
141
- * openapi: { $ref: '#/components/schemas/User' }
142
- * })
200
+ * .rendersOne('owner', { serializer: CustomOwnerSerializer })
143
201
  *
144
- * // With Dream class reference
202
+ * // With Dream class reference and serializer key
145
203
  * .rendersOne('creator', {
146
204
  * dreamClass: User,
147
- * serializerKey: 'summary',
148
- * openapi: { $ref: '#/components/schemas/UserSummary' }
205
+ * serializerKey: 'summary'
149
206
  * })
150
- * ```
151
207
  *
152
- * See: {@link https://your-docs-url.com/docs/serializers/associations | Serializer Associations Documentation}
208
+ * // Allow null association
209
+ * .rendersOne('approver', { serializer: UserSerializer, optional: true })
210
+ *
211
+ * // Flatten into parent object
212
+ * .rendersOne('profile', { serializer: ProfileSerializer, flatten: true })
213
+ * ```
153
214
  */
154
215
  rendersOne(name, options) {
155
216
  this.attributes.push({
@@ -165,32 +226,43 @@ export default class ObjectSerializerBuilder {
165
226
  * For ObjectSerializer, explicit serializer configuration is always required
166
227
  * since association schemas cannot be inferred from plain objects.
167
228
  *
168
- * @param name - The association property name (should be an array)
169
- * @param options - Configuration options including required serializer and OpenAPI schema
229
+ * @param name - The association property name (should resolve to an array)
230
+ * @param options - Configuration options:
231
+ * - `as` - Rename the association key in the serialized output
232
+ *
233
+ * For Dream associations:
234
+ * - `dreamClass` - The Dream model class, enabling serializer inference; when specified,
235
+ * `serializerKey` may also be provided to select a specific registered serializer
236
+ * - `serializer` - Provide an explicit serializer function
237
+ *
238
+ * For ViewModel associations:
239
+ * - `viewModelClass` + optional `serializerKey`
240
+ * - `serializer`
241
+ *
242
+ * For non-Dream/non-ViewModel associations:
243
+ * - `serializer` is required
170
244
  * @returns The serializer builder for method chaining
171
245
  *
172
246
  * @example
173
247
  * ```typescript
174
248
  * // With explicit serializer function
175
- * .rendersMany('articles', ArticleSerializer, {
176
- * openapi: {
177
- * type: 'array',
178
- * items: { $ref: '#/components/schemas/Article' }
179
- * }
249
+ * .rendersMany('articles', { serializer: ArticleSerializer })
250
+ *
251
+ * // With Dream class reference and serializer key
252
+ * .rendersMany('posts', {
253
+ * dreamClass: Post,
254
+ * serializerKey: 'summary'
180
255
  * })
181
256
  *
182
257
  * // With ViewModel class reference
183
258
  * .rendersMany('comments', {
184
259
  * viewModelClass: CommentViewModel,
185
- * serializer: CommentViewModelSerializer,
186
- * openapi: {
187
- * type: 'array',
188
- * items: { $ref: '#/components/schemas/Comment' }
189
- * }
260
+ * serializer: CommentViewModelSerializer
190
261
  * })
191
- * ```
192
262
  *
193
- * See: {@link https://your-docs-url.com/docs/serializers/associations | Serializer Associations Documentation}
263
+ * // Rename output key
264
+ * .rendersMany('articles', { serializer: ArticleSerializer, as: 'posts' })
265
+ * ```
194
266
  */
195
267
  rendersMany(name, options) {
196
268
  this.attributes.push({
@@ -203,13 +275,13 @@ export default class ObjectSerializerBuilder {
203
275
  /**
204
276
  * Executes the serializer and returns the serialized output.
205
277
  *
206
- * This method processes all defined attributes, custom attributes, delegated attributes,
207
- * and associations to produce the final serialized object. The result is suitable for
208
- * JSON.stringify() and API responses.
278
+ * Processes all defined attributes, custom attributes, delegated attributes,
279
+ * and associations to produce the final serialized object.
209
280
  *
210
281
  * @param passthrough - Additional data to pass through to nested serializers
282
+ * (e.g., locale, current user context)
211
283
  * @param opts - Rendering options for customizing the serialization process
212
- * @returns The serialized object
284
+ * @returns The serialized object, suitable for JSON responses
213
285
  *
214
286
  * @example
215
287
  * ```typescript
@@ -219,8 +291,6 @@ export default class ObjectSerializerBuilder {
219
291
  * // With passthrough data for nested serializers
220
292
  * const result = UserViewModelSerializer(userVm).render({ currentUserId: '456' })
221
293
  * ```
222
- *
223
- * See: {@link https://your-docs-url.com/docs/serializers/render | Serializer Rendering Documentation}
224
294
  */
225
295
  render(passthrough = {}, opts = {}) {
226
296
  return new SerializerRenderer(this, passthrough, opts).render();
@@ -2368,13 +2368,28 @@ export default class Dream {
2368
2368
  */
2369
2369
  passthrough<I extends Dream, PassthroughColumns extends PassthroughColumnNames<I>>(this: I, passthroughWhereStatement: PassthroughOnClause<PassthroughColumns>): LoadBuilder<I>;
2370
2370
  /**
2371
- * Loads the requested associations upon execution
2371
+ * Loads the requested associations upon execution.
2372
+ *
2373
+ * **IMPORTANT:** `load().execute()` returns a **new clone** of the model with the
2374
+ * associations loaded. It does NOT modify the original instance. You must use the
2375
+ * returned value:
2376
+ *
2377
+ * ```ts
2378
+ * // CORRECT — use the returned clone:
2379
+ * const loaded = await user.load('posts').execute()
2380
+ * loaded.posts // works
2381
+ *
2382
+ * // WRONG — original is not modified:
2383
+ * await user.load('posts').execute()
2384
+ * user.posts // association not loaded!
2385
+ * ```
2372
2386
  *
2373
2387
  * NOTE: {@link Dream.preload} is often a preferrable way of achieving the
2374
- * same goal.
2388
+ * same goal. Alternatively, `await model.association('posts')` loads only
2389
+ * if the association is not already loaded.
2375
2390
  *
2376
2391
  * ```ts
2377
- * await user
2392
+ * const user = await user
2378
2393
  * .load('posts', { body: ops.ilike('%hello world%') }, 'comments', 'replies')
2379
2394
  * .load('images')
2380
2395
  * .execute()
@@ -2387,7 +2402,7 @@ export default class Dream {
2387
2402
  * ```
2388
2403
  *
2389
2404
  * @param args - A list of associations (and optional where clauses) to load
2390
- * @returns A chainable LoadBuilder instance
2405
+ * @returns A chainable LoadBuilder instance. Call `.execute()` to get the cloned model with associations loaded.
2391
2406
  */
2392
2407
  load<I extends Dream, DB extends I['DB'], TableName extends I['table'], Schema extends I['schema'], const Arr extends readonly unknown[]>(this: I, ...args: [...Arr, VariadicLoadArgs<I, DB, Schema, TableName, Arr>]): LoadBuilder<I>;
2393
2408
  /**
@@ -2557,19 +2572,19 @@ export default class Dream {
2557
2572
  * Load each specified association using a single SQL query.
2558
2573
  * See {@link Dream.load} for loading in separate queries.
2559
2574
  *
2575
+ * **IMPORTANT:** Like `load()`, `leftJoinLoad().execute()` returns a **new clone** of the
2576
+ * model with associations loaded. It does NOT modify the original instance.
2577
+ *
2560
2578
  * Note: since leftJoinLoad loads via single query, it has
2561
- * some downsides and that may be avoided using {@link Dream.load}:
2579
+ * some downsides that may be avoided using {@link Dream.load}:
2562
2580
  * 1. `limit` and `offset` will be automatically removed
2563
2581
  * 2. `through` associations will bring additional namespaces into the query that can conflict with through associations from other associations, creating an invalid query
2564
2582
  * 3. each nested association will result in an additional record which duplicates data from the outer record. E.g., given `.leftJoinLoad('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`. `.load('a', 'b', 'c')` would perform three separate SQL queries, but the data for a single `a` would only be returned once.
2565
2583
  * 4. the individual query becomes more complex the more associations are included
2566
2584
  * 5. associations loading associations loading associations could result in exponential amounts of data; in those cases, `.load(...).findEach(...)` avoids instantiating massive amounts of data at once
2567
2585
  *
2568
- * Note: Left join loading loads all data in a single SQL query but has trade-offs compared
2569
- * to regular preloading. See {@link Dream.leftJoinPreload} for details about limitations.
2570
- *
2571
2586
  * ```ts
2572
- * await user
2587
+ * const user = await user
2573
2588
  * .leftJoinLoad('posts', { body: ops.ilike('%hello world%') }, 'comments', 'replies')
2574
2589
  * .leftJoinLoad('images')
2575
2590
  * .execute()
@@ -2582,7 +2597,7 @@ export default class Dream {
2582
2597
  * ```
2583
2598
  *
2584
2599
  * @param args - A list of associations (and optional where clauses) to load
2585
- * @returns A chainable LeftJoinLoadBuilder instance
2600
+ * @returns A chainable LeftJoinLoadBuilder instance. Call `.execute()` to get the cloned model with associations loaded.
2586
2601
  */
2587
2602
  leftJoinLoad<I extends Dream, DB extends I['DB'], TableName extends I['table'], Schema extends I['schema'], const Arr extends readonly unknown[]>(this: I, ...args: [...Arr, VariadicLeftJoinLoadArgs<I, DB, Schema, TableName, Arr>]): LeftJoinLoadBuilder<I>;
2588
2603
  /**
@@ -56,6 +56,10 @@ export default class Decorators<TD extends typeof Dream, T extends Dream = Insta
56
56
  * @returns A Scope decorator
57
57
  */
58
58
  Scope(this: Decorators<TD>, opts?: {
59
+ /**
60
+ * If `true`, this scope will be applied automatically to all queries involving this model.
61
+ * Defaults to `false`.
62
+ */
59
63
  default?: boolean;
60
64
  }): any;
61
65
  /**
@@ -116,10 +120,14 @@ export default class Decorators<TD extends typeof Dream, T extends Dream = Insta
116
120
  * @returns A Validates decorator
117
121
  */
118
122
  Validates<VT extends ValidationType, VTArgs extends VT extends 'numericality' ? {
123
+ /** The minimum allowed value (inclusive). */
119
124
  min?: number;
125
+ /** The maximum allowed value (inclusive). */
120
126
  max?: number;
121
127
  } : VT extends 'length' ? {
128
+ /** The minimum allowed length (inclusive). */
122
129
  min: number;
130
+ /** The maximum allowed length (inclusive). */
123
131
  max?: number;
124
132
  } : VT extends 'contains' ? string | RegExp : never>(this: Decorators<TD>, type: VT, args?: VTArgs): any;
125
133
  /**
@@ -1,5 +1,3 @@
1
1
  import Dream from '../../Dream.js';
2
2
  export declare const STI_SCOPE_NAME = "dream:STI";
3
- export default function STI(dreamClass: typeof Dream, { value }?: {
4
- value?: string;
5
- }): ClassDecorator;
3
+ export default function STI(dreamClass: typeof Dream): ClassDecorator;
@@ -1,5 +1,14 @@
1
1
  export default function Sortable(opts?: SortableOpts): any;
2
2
  interface SortableOpts {
3
+ /**
4
+ * A column name or array of column names that define the scope within which
5
+ * position values are unique. Records are sorted independently within each scope.
6
+ *
7
+ * ```ts
8
+ * @deco.Sortable({ scope: 'species' })
9
+ * public positionWithinSpecies: number
10
+ * ```
11
+ */
3
12
  scope?: string | string[];
4
13
  }
5
14
  export interface SortableFieldConfig {
@@ -1,10 +1,14 @@
1
1
  import Dream from '../../../Dream.js';
2
2
  import { ValidationType } from '../../../types/validation.js';
3
3
  export default function Validates<VT extends ValidationType, VTArgs extends VT extends 'numericality' ? {
4
+ /** The minimum allowed value (inclusive). */
4
5
  min?: number;
6
+ /** The maximum allowed value (inclusive). */
5
7
  max?: number;
6
8
  } : VT extends 'length' ? {
9
+ /** The minimum allowed length (inclusive). */
7
10
  min: number;
11
+ /** The maximum allowed length (inclusive). */
8
12
  max?: number;
9
13
  } : VT extends 'contains' ? string | RegExp : never>(type: VT, args?: VTArgs): any;
10
14
  export declare function validatesImplementation<VT extends ValidationType, VTArgs extends VT extends 'numericality' ? {
@@ -1,5 +1,9 @@
1
1
  import Dream from '../../Dream.js';
2
2
  export default function Scope(opts?: {
3
+ /**
4
+ * If `true`, this scope will be applied automatically to all queries involving this model.
5
+ * Defaults to `false`.
6
+ */
3
7
  default?: boolean;
4
8
  }): any;
5
9
  export declare function scopeImplementation(t: typeof Dream, key: string, opts?: {