@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.
- package/dist/cjs/src/Dream.js +25 -10
- package/dist/cjs/src/decorators/class/STI.js +2 -2
- package/dist/cjs/src/dream/LeftJoinLoadBuilder.js +16 -10
- package/dist/cjs/src/dream/LoadBuilder.js +15 -9
- package/dist/cjs/src/dream/Query.js +1 -1
- package/dist/cjs/src/dream/internal/similarity/SimilarityBuilder.js +3 -1
- package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +110 -52
- package/dist/cjs/src/serializer/builders/ObjectSerializerBuilder.js +111 -41
- package/dist/esm/src/Dream.js +25 -10
- package/dist/esm/src/decorators/class/STI.js +2 -2
- package/dist/esm/src/dream/LeftJoinLoadBuilder.js +16 -10
- package/dist/esm/src/dream/LoadBuilder.js +15 -9
- package/dist/esm/src/dream/Query.js +1 -1
- package/dist/esm/src/dream/internal/similarity/SimilarityBuilder.js +3 -1
- package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +110 -52
- package/dist/esm/src/serializer/builders/ObjectSerializerBuilder.js +111 -41
- package/dist/types/src/Dream.d.ts +25 -10
- package/dist/types/src/decorators/Decorators.d.ts +8 -0
- package/dist/types/src/decorators/class/STI.d.ts +1 -3
- package/dist/types/src/decorators/field/sortable/Sortable.d.ts +9 -0
- package/dist/types/src/decorators/field/validation/Validates.d.ts +4 -0
- package/dist/types/src/decorators/static-method/Scope.d.ts +4 -0
- package/dist/types/src/dream/LeftJoinLoadBuilder.d.ts +16 -10
- package/dist/types/src/dream/LoadBuilder.d.ts +15 -9
- package/dist/types/src/dream/Query.d.ts +1 -1
- package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +151 -59
- package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +123 -41
- package/dist/types/src/types/associations/belongsTo.d.ts +34 -0
- package/dist/types/src/types/associations/belongsTo.ts +41 -0
- package/dist/types/src/types/associations/hasMany.d.ts +18 -0
- package/dist/types/src/types/associations/hasMany.ts +18 -0
- package/dist/types/src/types/associations/shared.d.ts +71 -0
- package/dist/types/src/types/associations/shared.ts +74 -0
- package/dist/types/src/types/dream.d.ts +16 -0
- package/dist/types/src/types/dream.ts +18 -0
- package/dist/types/src/types/lifecycle.d.ts +18 -0
- package/dist/types/src/types/lifecycle.ts +18 -0
- package/dist/types/src/types/query.d.ts +3 -0
- package/dist/types/src/types/query.ts +3 -0
- package/docs/classes/db.DreamMigrationHelpers.html +9 -9
- package/docs/classes/db.KyselyQueryDriver.html +32 -32
- package/docs/classes/db.PostgresQueryDriver.html +33 -33
- package/docs/classes/db.QueryDriverBase.html +31 -31
- package/docs/classes/errors.CheckConstraintViolation.html +3 -3
- package/docs/classes/errors.ColumnOverflow.html +3 -3
- package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
- package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
- package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
- package/docs/classes/errors.GlobalNameNotSet.html +3 -3
- package/docs/classes/errors.InvalidCalendarDate.html +2 -2
- package/docs/classes/errors.InvalidClockTime.html +2 -2
- package/docs/classes/errors.InvalidClockTimeTz.html +2 -2
- package/docs/classes/errors.InvalidDateTime.html +2 -2
- package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
- package/docs/classes/errors.NonLoadedAssociation.html +3 -3
- package/docs/classes/errors.NotNullViolation.html +3 -3
- package/docs/classes/errors.RecordNotFound.html +3 -3
- package/docs/classes/errors.ValidationError.html +3 -3
- package/docs/classes/index.CalendarDate.html +33 -33
- package/docs/classes/index.ClockTime.html +32 -32
- package/docs/classes/index.ClockTimeTz.html +35 -35
- package/docs/classes/index.DateTime.html +86 -86
- package/docs/classes/index.Decorators.html +21 -20
- package/docs/classes/index.Dream.html +133 -126
- package/docs/classes/index.DreamApp.html +5 -5
- package/docs/classes/index.DreamTransaction.html +2 -2
- package/docs/classes/index.Env.html +2 -2
- package/docs/classes/index.Query.html +57 -57
- package/docs/classes/system.CliFileWriter.html +4 -4
- package/docs/classes/system.DreamBin.html +2 -2
- package/docs/classes/system.DreamCLI.html +6 -6
- package/docs/classes/system.DreamImporter.html +2 -2
- package/docs/classes/system.DreamLogos.html +2 -2
- package/docs/classes/system.DreamSerializerBuilder.html +172 -58
- package/docs/classes/system.ObjectSerializerBuilder.html +109 -33
- package/docs/classes/system.PathHelpers.html +3 -3
- package/docs/classes/utils.Encrypt.html +2 -2
- package/docs/classes/utils.Range.html +2 -2
- package/docs/functions/db.closeAllDbConnections.html +1 -1
- package/docs/functions/db.dreamDbConnections.html +1 -1
- package/docs/functions/db.untypedDb.html +1 -1
- package/docs/functions/db.validateColumn.html +1 -1
- package/docs/functions/db.validateTable.html +1 -1
- package/docs/functions/errors.pgErrorType.html +1 -1
- package/docs/functions/index.DreamSerializer.html +1 -1
- package/docs/functions/index.ObjectSerializer.html +1 -1
- package/docs/functions/index.ReplicaSafe.html +1 -1
- package/docs/functions/index.STI.html +1 -1
- package/docs/functions/index.SoftDelete.html +1 -1
- package/docs/functions/utils.camelize.html +1 -1
- package/docs/functions/utils.capitalize.html +1 -1
- package/docs/functions/utils.cloneDeepSafe.html +1 -1
- package/docs/functions/utils.compact.html +1 -1
- package/docs/functions/utils.groupBy.html +1 -1
- package/docs/functions/utils.hyphenize.html +1 -1
- package/docs/functions/utils.intersection.html +1 -1
- package/docs/functions/utils.isEmpty.html +1 -1
- package/docs/functions/utils.normalizeUnicode.html +1 -1
- package/docs/functions/utils.pascalize.html +1 -1
- package/docs/functions/utils.percent.html +1 -1
- package/docs/functions/utils.range.html +1 -1
- package/docs/functions/utils.round.html +1 -1
- package/docs/functions/utils.sanitizeString.html +1 -1
- package/docs/functions/utils.snakeify.html +1 -1
- package/docs/functions/utils.sort.html +1 -1
- package/docs/functions/utils.sortBy.html +1 -1
- package/docs/functions/utils.sortObjectByKey.html +1 -1
- package/docs/functions/utils.sortObjectByValue.html +1 -1
- package/docs/functions/utils.uncapitalize.html +1 -1
- package/docs/functions/utils.uniq.html +1 -1
- package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
- package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
- package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
- package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
- package/docs/interfaces/types.BelongsToStatement.html +2 -2
- package/docs/interfaces/types.DecoratorContext.html +2 -2
- package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
- package/docs/interfaces/types.DreamAppOpts.html +2 -2
- package/docs/interfaces/types.DurationObject.html +2 -2
- package/docs/interfaces/types.EncryptOptions.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
- package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
- package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
- package/docs/types/openapi.OpenapiAllTypes.html +1 -1
- package/docs/types/openapi.OpenapiFormats.html +1 -1
- package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
- package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
- package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
- package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
- package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +2 -2
- package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +2 -2
- package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +2 -2
- package/docs/types/openapi.OpenapiSchemaExpressionRef.html +2 -2
- package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +2 -2
- package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
- package/docs/types/openapi.OpenapiSchemaNull.html +2 -2
- package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +2 -2
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +2 -2
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +2 -2
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +2 -2
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +2 -2
- package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
- package/docs/types/openapi.OpenapiSchemaString.html +1 -1
- package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
- package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
- package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
- package/docs/types/openapi.OpenapiTypeField.html +1 -1
- package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
- package/docs/types/types.CalendarDateDurationUnit.html +1 -1
- package/docs/types/types.CalendarDateObject.html +1 -1
- package/docs/types/types.Camelized.html +1 -1
- package/docs/types/types.ClockTimeObject.html +1 -1
- package/docs/types/types.DbConnectionType.html +1 -1
- package/docs/types/types.DbTypes.html +1 -1
- package/docs/types/types.DreamAssociationMetadata.html +1 -1
- package/docs/types/types.DreamAttributes.html +1 -1
- package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
- package/docs/types/types.DreamClassColumn.html +1 -1
- package/docs/types/types.DreamColumn.html +1 -1
- package/docs/types/types.DreamColumnNames.html +1 -1
- package/docs/types/types.DreamLogLevel.html +1 -1
- package/docs/types/types.DreamLogger.html +2 -2
- package/docs/types/types.DreamModelSerializerType.html +1 -1
- package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
- package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
- package/docs/types/types.DreamParamSafeAttributes.html +1 -1
- package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
- package/docs/types/types.DreamSerializable.html +1 -1
- package/docs/types/types.DreamSerializableArray.html +1 -1
- package/docs/types/types.DreamSerializerKey.html +1 -1
- package/docs/types/types.DreamSerializers.html +1 -1
- package/docs/types/types.DreamVirtualColumns.html +1 -1
- package/docs/types/types.DurationUnit.html +1 -1
- package/docs/types/types.EncryptAlgorithm.html +1 -1
- package/docs/types/types.HasManyStatement.html +1 -1
- package/docs/types/types.HasOneStatement.html +1 -1
- package/docs/types/types.Hyphenized.html +1 -1
- package/docs/types/types.Pascalized.html +1 -1
- package/docs/types/types.PrimaryKeyType.html +1 -1
- package/docs/types/types.RoundingPrecision.html +1 -1
- package/docs/types/types.SerializerCasing.html +1 -1
- package/docs/types/types.SimpleObjectSerializerType.html +1 -1
- package/docs/types/types.Snakeified.html +1 -1
- package/docs/types/types.StrictInterface.html +1 -1
- package/docs/types/types.UpdateableAssociationProperties.html +1 -1
- package/docs/types/types.UpdateableProperties.html +1 -1
- package/docs/types/types.ValidationType.html +1 -1
- package/docs/types/types.ViewModel.html +2 -2
- package/docs/types/types.ViewModelClass.html +1 -1
- package/docs/types/types.WeekdayName.html +1 -1
- package/docs/types/types.WhereStatementForDream.html +1 -1
- package/docs/types/types.WhereStatementForDreamClass.html +1 -1
- package/docs/variables/index.DreamConst.html +1 -1
- package/docs/variables/index.ops.html +1 -1
- package/docs/variables/openapi.openapiPrimitiveTypes.html +1 -1
- package/docs/variables/openapi.openapiShorthandPrimitiveTypes.html +1 -1
- package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
- package/docs/variables/system.primaryKeyTypes.html +1 -1
- package/package.json +1 -1
package/dist/cjs/src/Dream.js
CHANGED
|
@@ -3238,13 +3238,28 @@ export default class Dream {
|
|
|
3238
3238
|
return new LoadBuilder(this).passthrough(passthroughWhereStatement);
|
|
3239
3239
|
}
|
|
3240
3240
|
/**
|
|
3241
|
-
* Loads the requested associations upon execution
|
|
3241
|
+
* Loads the requested associations upon execution.
|
|
3242
|
+
*
|
|
3243
|
+
* **IMPORTANT:** `load().execute()` returns a **new clone** of the model with the
|
|
3244
|
+
* associations loaded. It does NOT modify the original instance. You must use the
|
|
3245
|
+
* returned value:
|
|
3246
|
+
*
|
|
3247
|
+
* ```ts
|
|
3248
|
+
* // CORRECT — use the returned clone:
|
|
3249
|
+
* const loaded = await user.load('posts').execute()
|
|
3250
|
+
* loaded.posts // works
|
|
3251
|
+
*
|
|
3252
|
+
* // WRONG — original is not modified:
|
|
3253
|
+
* await user.load('posts').execute()
|
|
3254
|
+
* user.posts // association not loaded!
|
|
3255
|
+
* ```
|
|
3242
3256
|
*
|
|
3243
3257
|
* NOTE: {@link Dream.preload} is often a preferrable way of achieving the
|
|
3244
|
-
* same goal.
|
|
3258
|
+
* same goal. Alternatively, `await model.association('posts')` loads only
|
|
3259
|
+
* if the association is not already loaded.
|
|
3245
3260
|
*
|
|
3246
3261
|
* ```ts
|
|
3247
|
-
* await user
|
|
3262
|
+
* const user = await user
|
|
3248
3263
|
* .load('posts', { body: ops.ilike('%hello world%') }, 'comments', 'replies')
|
|
3249
3264
|
* .load('images')
|
|
3250
3265
|
* .execute()
|
|
@@ -3257,7 +3272,7 @@ export default class Dream {
|
|
|
3257
3272
|
* ```
|
|
3258
3273
|
*
|
|
3259
3274
|
* @param args - A list of associations (and optional where clauses) to load
|
|
3260
|
-
* @returns A chainable LoadBuilder instance
|
|
3275
|
+
* @returns A chainable LoadBuilder instance. Call `.execute()` to get the cloned model with associations loaded.
|
|
3261
3276
|
*/
|
|
3262
3277
|
load(...args) {
|
|
3263
3278
|
return new LoadBuilder(this).load(...args);
|
|
@@ -3326,19 +3341,19 @@ export default class Dream {
|
|
|
3326
3341
|
* Load each specified association using a single SQL query.
|
|
3327
3342
|
* See {@link Dream.load} for loading in separate queries.
|
|
3328
3343
|
*
|
|
3344
|
+
* **IMPORTANT:** Like `load()`, `leftJoinLoad().execute()` returns a **new clone** of the
|
|
3345
|
+
* model with associations loaded. It does NOT modify the original instance.
|
|
3346
|
+
*
|
|
3329
3347
|
* Note: since leftJoinLoad loads via single query, it has
|
|
3330
|
-
* some downsides
|
|
3348
|
+
* some downsides that may be avoided using {@link Dream.load}:
|
|
3331
3349
|
* 1. `limit` and `offset` will be automatically removed
|
|
3332
3350
|
* 2. `through` associations will bring additional namespaces into the query that can conflict with through associations from other associations, creating an invalid query
|
|
3333
3351
|
* 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.
|
|
3334
3352
|
* 4. the individual query becomes more complex the more associations are included
|
|
3335
3353
|
* 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
|
|
3336
3354
|
*
|
|
3337
|
-
* Note: Left join loading loads all data in a single SQL query but has trade-offs compared
|
|
3338
|
-
* to regular preloading. See {@link Dream.leftJoinPreload} for details about limitations.
|
|
3339
|
-
*
|
|
3340
3355
|
* ```ts
|
|
3341
|
-
* await user
|
|
3356
|
+
* const user = await user
|
|
3342
3357
|
* .leftJoinLoad('posts', { body: ops.ilike('%hello world%') }, 'comments', 'replies')
|
|
3343
3358
|
* .leftJoinLoad('images')
|
|
3344
3359
|
* .execute()
|
|
@@ -3351,7 +3366,7 @@ export default class Dream {
|
|
|
3351
3366
|
* ```
|
|
3352
3367
|
*
|
|
3353
3368
|
* @param args - A list of associations (and optional where clauses) to load
|
|
3354
|
-
* @returns A chainable LeftJoinLoadBuilder instance
|
|
3369
|
+
* @returns A chainable LeftJoinLoadBuilder instance. Call `.execute()` to get the cloned model with associations loaded.
|
|
3355
3370
|
*/
|
|
3356
3371
|
leftJoinLoad(...args) {
|
|
3357
3372
|
return new LeftJoinLoadBuilder(this).leftJoinLoad(...args);
|
|
@@ -3,7 +3,7 @@ import StiChildIncompatibleWithReplicaSafeDecorator from '../../errors/sti/StiCh
|
|
|
3
3
|
import StiChildIncompatibleWithSoftDeleteDecorator from '../../errors/sti/StiChildIncompatibleWithSoftDeleteDecorator.js';
|
|
4
4
|
import { scopeImplementation } from '../static-method/Scope.js';
|
|
5
5
|
export const STI_SCOPE_NAME = 'dream:STI';
|
|
6
|
-
export default function STI(dreamClass
|
|
6
|
+
export default function STI(dreamClass) {
|
|
7
7
|
return function (target) {
|
|
8
8
|
const stiChildClass = target;
|
|
9
9
|
const baseClass = dreamClass['sti'].baseClass || dreamClass;
|
|
@@ -21,7 +21,7 @@ export default function STI(dreamClass, { value } = {}) {
|
|
|
21
21
|
stiChildClass['sti'] = {
|
|
22
22
|
active: true,
|
|
23
23
|
baseClass,
|
|
24
|
-
value:
|
|
24
|
+
value: stiChildClass.sanitizedName,
|
|
25
25
|
};
|
|
26
26
|
stiChildClass[STI_SCOPE_NAME] = function (query) {
|
|
27
27
|
return query.where({ type: stiChildClass['sti'].value });
|
|
@@ -5,13 +5,16 @@ export default class LeftJoinLoadBuilder {
|
|
|
5
5
|
dream;
|
|
6
6
|
query;
|
|
7
7
|
/**
|
|
8
|
-
* An intermediate
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* An intermediate builder for loading associations onto a Dream model
|
|
9
|
+
* via a single left-join SQL query. Accessed via `#leftJoinLoad`.
|
|
10
|
+
*
|
|
11
|
+
* **Note:** The LeftJoinLoadBuilder works on a clone of the original model.
|
|
12
|
+
* Call `.execute()` to get the clone with associations loaded.
|
|
11
13
|
*
|
|
12
14
|
* ```ts
|
|
13
15
|
* const user = await User.firstOrFail()
|
|
14
|
-
* await user.
|
|
16
|
+
* const loaded = await user.leftJoinLoad('settings').execute()
|
|
17
|
+
* loaded.settings // association is loaded on the returned clone
|
|
15
18
|
* ```
|
|
16
19
|
*/
|
|
17
20
|
constructor(dream, dreamTransaction) {
|
|
@@ -39,17 +42,20 @@ export default class LeftJoinLoadBuilder {
|
|
|
39
42
|
return this;
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
42
|
-
*
|
|
43
|
-
* all associations
|
|
44
|
-
* instances.
|
|
45
|
+
* Executes the left-join load query, returning a **clone** of the original model
|
|
46
|
+
* with all requested associations loaded. The original instance is not modified.
|
|
45
47
|
*
|
|
46
48
|
* ```ts
|
|
47
49
|
* const user = await User.firstOrFail()
|
|
48
|
-
* await user
|
|
49
|
-
* .
|
|
50
|
-
* .
|
|
50
|
+
* const loaded = await user
|
|
51
|
+
* .leftJoinLoad('settings')
|
|
52
|
+
* .leftJoinLoad('posts', 'comments', 'replies')
|
|
51
53
|
* .execute()
|
|
54
|
+
*
|
|
55
|
+
* loaded.settings // works — associations are on the returned clone
|
|
52
56
|
* ```
|
|
57
|
+
*
|
|
58
|
+
* @returns A clone of the Dream instance with all requested associations loaded
|
|
53
59
|
*/
|
|
54
60
|
async execute() {
|
|
55
61
|
if (this.dreamTransaction) {
|
|
@@ -3,13 +3,16 @@ export default class LoadBuilder {
|
|
|
3
3
|
dream;
|
|
4
4
|
query;
|
|
5
5
|
/**
|
|
6
|
-
* An intermediate
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* An intermediate builder for loading associations onto a Dream model.
|
|
7
|
+
* Accessed via the `#load` method on a Dream instance.
|
|
8
|
+
*
|
|
9
|
+
* **Note:** The LoadBuilder works on a clone of the original model.
|
|
10
|
+
* Call `.execute()` to get the clone with associations loaded.
|
|
9
11
|
*
|
|
10
12
|
* ```ts
|
|
11
13
|
* const user = await User.firstOrFail()
|
|
12
|
-
* await user.load('settings').execute()
|
|
14
|
+
* const loaded = await user.load('settings').execute()
|
|
15
|
+
* loaded.settings // association is loaded on the returned clone
|
|
13
16
|
* ```
|
|
14
17
|
*/
|
|
15
18
|
constructor(dream, dreamTransaction) {
|
|
@@ -89,19 +92,22 @@ export default class LoadBuilder {
|
|
|
89
92
|
return this;
|
|
90
93
|
}
|
|
91
94
|
/**
|
|
92
|
-
* Executes
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
+
* Executes the load query, binding all associations to a **clone** of the
|
|
96
|
+
* original model instance. The original instance is not modified.
|
|
97
|
+
*
|
|
98
|
+
* You must use the returned value to access the loaded associations:
|
|
95
99
|
*
|
|
96
100
|
* ```ts
|
|
97
101
|
* const user = await User.firstOrFail()
|
|
98
|
-
* await user
|
|
102
|
+
* const loaded = await user
|
|
99
103
|
* .load('settings')
|
|
100
104
|
* .load('posts', 'comments', 'replies', ['image', 'localizedText'])
|
|
101
105
|
* .execute()
|
|
106
|
+
*
|
|
107
|
+
* loaded.settings // works — associations are on the returned clone
|
|
102
108
|
* ```
|
|
103
109
|
*
|
|
104
|
-
* @returns
|
|
110
|
+
* @returns A clone of the Dream instance with all requested associations loaded
|
|
105
111
|
*/
|
|
106
112
|
async execute() {
|
|
107
113
|
if (this.dreamTransaction) {
|
|
@@ -1698,7 +1698,7 @@ export default class Query {
|
|
|
1698
1698
|
* Updates all records matching the Query
|
|
1699
1699
|
*
|
|
1700
1700
|
* ```ts
|
|
1701
|
-
* await User.where({ email: ops.ilike('%burpcollaborator%') }).
|
|
1701
|
+
* await User.where({ email: ops.ilike('%burpcollaborator%') }).update({ email: null })
|
|
1702
1702
|
* // 12
|
|
1703
1703
|
* ```
|
|
1704
1704
|
* @param attributes - The attributes used to update the records
|
|
@@ -323,7 +323,9 @@ function removeJoinAndFromObjectHierarchy(obj) {
|
|
|
323
323
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
324
324
|
// Only recurse into plain data objects. Class instances (Dream models, DateTime, etc.)
|
|
325
325
|
// may contain circular loaded-association references, which would cause infinite recursion.
|
|
326
|
-
|
|
326
|
+
// Guard against null/undefined before calling Object.getPrototypeOf, since
|
|
327
|
+
// Object.getPrototypeOf(null) throws "TypeError: Cannot convert undefined or null to object".
|
|
328
|
+
const proto = obj[key] != null ? Object.getPrototypeOf(obj[key]) : null;
|
|
327
329
|
if (isObject(obj[key]) && (proto === Object.prototype || proto === null)) {
|
|
328
330
|
result[key] = removeJoinAndFromObjectHierarchy(obj[key].and || obj[key]);
|
|
329
331
|
}
|
|
@@ -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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
35
|
-
* .delegatedAttribute('
|
|
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
|
-
*
|
|
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
|
|
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('
|
|
103
|
+
* .customAttribute('coordinates', () => ({ lat: 40.7, lng: -74.0 }), {
|
|
78
104
|
* flatten: true,
|
|
79
105
|
* openapi: {
|
|
80
|
-
*
|
|
81
|
-
*
|
|
106
|
+
* lat: { type: 'number' },
|
|
107
|
+
* lng: { type: 'number' }
|
|
82
108
|
* }
|
|
83
109
|
* })
|
|
84
|
-
* ```
|
|
85
110
|
*
|
|
86
|
-
*
|
|
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
|
|
101
|
-
* inferred from that associated Dream's
|
|
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
|
|
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
|
-
* //
|
|
110
|
-
* .rendersOne('
|
|
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
|
-
* //
|
|
116
|
-
* .rendersOne('
|
|
117
|
-
* openapi: { $ref: '#/components/schemas/User' }
|
|
118
|
-
* })
|
|
119
|
-
* ```
|
|
165
|
+
* // Allow null association
|
|
166
|
+
* .rendersOne('approver', { optional: true })
|
|
120
167
|
*
|
|
121
|
-
*
|
|
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
|
|
135
|
-
* inferred from that associated Dream's
|
|
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
|
-
*
|
|
138
|
-
*
|
|
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
|
-
* //
|
|
144
|
-
* .rendersMany('
|
|
207
|
+
* // Auto-infer serializer from Dream association
|
|
208
|
+
* .rendersMany('rooms')
|
|
145
209
|
*
|
|
146
|
-
* // With specific serializer
|
|
147
|
-
* .rendersMany('
|
|
210
|
+
* // With specific serializer key
|
|
211
|
+
* .rendersMany('rooms', { serializerKey: 'summary' })
|
|
148
212
|
*
|
|
149
|
-
* //
|
|
150
|
-
* .rendersMany('
|
|
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
|
-
*
|
|
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
|
-
*
|
|
172
|
-
* and associations to produce the final serialized object.
|
|
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();
|