@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.
- package/dist/cjs/src/Dream.js +246 -23
- package/dist/cjs/src/cli/index.js +16 -0
- package/dist/cjs/src/db/migration-helpers/DreamMigrationHelpers.js +18 -14
- package/dist/cjs/src/decorators/Decorators.js +2 -1
- package/dist/cjs/src/dream/Query.js +162 -24
- package/dist/cjs/src/dream/internal/extractNestedPaths.js +37 -0
- package/dist/cjs/src/helpers/indent.js +18 -0
- package/dist/cjs/src/serializer/SerializerRenderer.js +2 -17
- package/dist/cjs/src/serializer/builders/DreamSerializerBuilder.js +139 -3
- package/dist/cjs/src/serializer/builders/ObjectSerializerBuilder.js +176 -3
- package/dist/cjs/src/serializer/helpers/serializerForAssociatedClass.js +20 -0
- package/dist/esm/src/Dream.js +246 -23
- package/dist/esm/src/cli/index.js +16 -0
- package/dist/esm/src/db/migration-helpers/DreamMigrationHelpers.js +18 -14
- package/dist/esm/src/decorators/Decorators.js +2 -1
- package/dist/esm/src/dream/Query.js +162 -24
- package/dist/esm/src/dream/internal/extractNestedPaths.js +34 -0
- package/dist/esm/src/helpers/indent.js +15 -0
- package/dist/esm/src/serializer/SerializerRenderer.js +2 -17
- package/dist/esm/src/serializer/builders/DreamSerializerBuilder.js +139 -3
- package/dist/esm/src/serializer/builders/ObjectSerializerBuilder.js +176 -3
- package/dist/esm/src/serializer/helpers/serializerForAssociatedClass.js +17 -0
- package/dist/types/src/Dream.d.ts +218 -24
- package/dist/types/src/db/migration-helpers/DreamMigrationHelpers.d.ts +18 -14
- package/dist/types/src/decorators/Decorators.d.ts +2 -1
- package/dist/types/src/dream/Query.d.ts +154 -25
- package/dist/types/src/dream/internal/extractNestedPaths.d.ts +21 -0
- package/dist/types/src/helpers/indent.d.ts +3 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/serializer/builders/DreamSerializerBuilder.d.ts +176 -5
- package/dist/types/src/serializer/builders/ObjectSerializerBuilder.d.ts +176 -3
- package/dist/types/src/serializer/helpers/serializerForAssociatedClass.d.ts +9 -0
- package/dist/types/src/types/dream.d.ts +2 -1
- package/dist/types/src/types/dream.ts +26 -1
- package/docs/assets/highlight.css +7 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/Benchmark.html +2 -2
- package/docs/classes/CalendarDate.html +2 -2
- package/docs/classes/CreateOrFindByFailedToCreateAndFind.html +3 -3
- package/docs/classes/Decorators.html +21 -20
- package/docs/classes/Dream.html +288 -209
- package/docs/classes/DreamApp.html +4 -4
- package/docs/classes/DreamBin.html +2 -2
- package/docs/classes/DreamCLI.html +4 -4
- package/docs/classes/DreamImporter.html +2 -2
- package/docs/classes/DreamLogos.html +2 -2
- package/docs/classes/DreamMigrationHelpers.html +21 -8
- package/docs/classes/DreamSerializerBuilder.html +66 -2
- package/docs/classes/DreamTransaction.html +2 -2
- package/docs/classes/Encrypt.html +2 -2
- package/docs/classes/Env.html +2 -2
- package/docs/classes/GlobalNameNotSet.html +3 -3
- package/docs/classes/NonLoadedAssociation.html +3 -3
- package/docs/classes/ObjectSerializerBuilder.html +66 -2
- package/docs/classes/Query.html +118 -78
- package/docs/classes/Range.html +2 -2
- package/docs/classes/RecordNotFound.html +3 -3
- package/docs/classes/ValidationError.html +3 -3
- package/docs/functions/DreamSerializer.html +1 -1
- package/docs/functions/ObjectSerializer.html +1 -1
- package/docs/functions/ReplicaSafe.html +1 -1
- package/docs/functions/STI.html +1 -1
- package/docs/functions/SoftDelete.html +1 -1
- package/docs/functions/camelize.html +1 -1
- package/docs/functions/capitalize.html +1 -1
- package/docs/functions/cloneDeepSafe.html +1 -1
- package/docs/functions/closeAllDbConnections.html +1 -1
- package/docs/functions/compact.html +1 -1
- package/docs/functions/dreamDbConnections.html +1 -1
- package/docs/functions/dreamPath.html +1 -1
- package/docs/functions/expandStiClasses.html +1 -1
- package/docs/functions/generateDream.html +1 -1
- package/docs/functions/globalClassNameFromFullyQualifiedModelName.html +1 -1
- package/docs/functions/groupBy.html +1 -1
- package/docs/functions/hyphenize.html +1 -1
- package/docs/functions/inferSerializerFromDreamOrViewModel.html +1 -1
- package/docs/functions/inferSerializersFromDreamClassOrViewModelClass.html +1 -1
- package/docs/functions/intersection.html +1 -1
- package/docs/functions/isDreamSerializer.html +1 -1
- package/docs/functions/isEmpty.html +1 -1
- package/docs/functions/loadRepl.html +1 -1
- package/docs/functions/lookupClassByGlobalName.html +1 -1
- package/docs/functions/normalizeUnicode.html +1 -1
- package/docs/functions/pascalize.html +1 -1
- package/docs/functions/pgErrorType.html +1 -1
- package/docs/functions/range-1.html +1 -1
- package/docs/functions/relativeDreamPath.html +1 -1
- package/docs/functions/round.html +1 -1
- package/docs/functions/serializerNameFromFullyQualifiedModelName.html +1 -1
- package/docs/functions/sharedPathPrefix.html +1 -1
- package/docs/functions/snakeify.html +1 -1
- package/docs/functions/sort.html +1 -1
- package/docs/functions/sortBy.html +1 -1
- package/docs/functions/sortObjectByKey.html +1 -1
- package/docs/functions/sortObjectByValue.html +1 -1
- package/docs/functions/standardizeFullyQualifiedModelName.html +1 -1
- package/docs/functions/uncapitalize.html +1 -1
- package/docs/functions/uniq.html +1 -1
- package/docs/functions/untypedDb.html +1 -1
- package/docs/functions/validateColumn.html +1 -1
- package/docs/functions/validateTable.html +1 -1
- package/docs/interfaces/BelongsToStatement.html +2 -2
- package/docs/interfaces/DecoratorContext.html +2 -2
- package/docs/interfaces/DreamAppInitOptions.html +2 -2
- package/docs/interfaces/DreamAppOpts.html +2 -2
- package/docs/interfaces/EncryptOptions.html +2 -2
- package/docs/interfaces/InternalAnyTypedSerializerRendersMany.html +2 -2
- package/docs/interfaces/InternalAnyTypedSerializerRendersOne.html +2 -2
- package/docs/interfaces/OpenapiDescription.html +2 -2
- package/docs/interfaces/OpenapiSchemaProperties.html +1 -1
- package/docs/interfaces/OpenapiSchemaPropertiesShorthand.html +1 -1
- package/docs/interfaces/OpenapiTypeFieldObject.html +1 -1
- package/docs/interfaces/SerializerRendererOpts.html +2 -2
- package/docs/modules.html +1 -0
- package/docs/types/Camelized.html +1 -1
- package/docs/types/CommonOpenapiSchemaObjectFields.html +1 -1
- package/docs/types/DateTime.html +1 -1
- package/docs/types/DbConnectionType.html +1 -1
- package/docs/types/DbTypes.html +1 -1
- package/docs/types/DreamAssociationMetadata.html +1 -1
- package/docs/types/DreamAttributes.html +1 -1
- package/docs/types/DreamClassAssociationAndStatement.html +1 -0
- package/docs/types/DreamClassColumn.html +1 -1
- package/docs/types/DreamColumn.html +1 -1
- package/docs/types/DreamColumnNames.html +1 -1
- package/docs/types/DreamLogLevel.html +1 -1
- package/docs/types/DreamLogger.html +1 -1
- package/docs/types/DreamModelSerializerType.html +1 -1
- package/docs/types/DreamOrViewModelClassSerializerKey.html +1 -1
- package/docs/types/DreamOrViewModelSerializerKey.html +1 -1
- package/docs/types/DreamParamSafeAttributes.html +1 -1
- package/docs/types/DreamParamSafeColumnNames.html +1 -1
- package/docs/types/DreamSerializable.html +1 -1
- package/docs/types/DreamSerializableArray.html +1 -1
- package/docs/types/DreamSerializerKey.html +1 -1
- package/docs/types/DreamSerializers.html +1 -1
- package/docs/types/DreamTableSchema.html +1 -1
- package/docs/types/DreamVirtualColumns.html +1 -1
- package/docs/types/EncryptAlgorithm.html +1 -1
- package/docs/types/HasManyStatement.html +1 -1
- package/docs/types/HasOneStatement.html +1 -1
- package/docs/types/Hyphenized.html +1 -1
- package/docs/types/IdType.html +1 -1
- package/docs/types/OpenapiAllTypes.html +1 -1
- package/docs/types/OpenapiFormats.html +1 -1
- package/docs/types/OpenapiNumberFormats.html +1 -1
- package/docs/types/OpenapiPrimitiveBaseTypes.html +1 -1
- package/docs/types/OpenapiPrimitiveTypes.html +1 -1
- package/docs/types/OpenapiSchemaArray.html +1 -1
- package/docs/types/OpenapiSchemaArrayShorthand.html +1 -1
- package/docs/types/OpenapiSchemaBase.html +1 -1
- package/docs/types/OpenapiSchemaBody.html +1 -1
- package/docs/types/OpenapiSchemaBodyShorthand.html +1 -1
- package/docs/types/OpenapiSchemaCommonFields.html +1 -1
- package/docs/types/OpenapiSchemaExpressionAllOf.html +1 -1
- package/docs/types/OpenapiSchemaExpressionAnyOf.html +1 -1
- package/docs/types/OpenapiSchemaExpressionOneOf.html +1 -1
- package/docs/types/OpenapiSchemaExpressionRef.html +1 -1
- package/docs/types/OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
- package/docs/types/OpenapiSchemaInteger.html +1 -1
- package/docs/types/OpenapiSchemaNull.html +1 -1
- package/docs/types/OpenapiSchemaNumber.html +1 -1
- package/docs/types/OpenapiSchemaObject.html +1 -1
- package/docs/types/OpenapiSchemaObjectAllOf.html +1 -1
- package/docs/types/OpenapiSchemaObjectAllOfShorthand.html +1 -1
- package/docs/types/OpenapiSchemaObjectAnyOf.html +1 -1
- package/docs/types/OpenapiSchemaObjectAnyOfShorthand.html +1 -1
- package/docs/types/OpenapiSchemaObjectBase.html +1 -1
- package/docs/types/OpenapiSchemaObjectBaseShorthand.html +1 -1
- package/docs/types/OpenapiSchemaObjectOneOf.html +1 -1
- package/docs/types/OpenapiSchemaObjectOneOfShorthand.html +1 -1
- package/docs/types/OpenapiSchemaObjectShorthand.html +1 -1
- package/docs/types/OpenapiSchemaPrimitiveGeneric.html +1 -1
- package/docs/types/OpenapiSchemaShorthandExpressionAllOf.html +1 -1
- package/docs/types/OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
- package/docs/types/OpenapiSchemaShorthandExpressionOneOf.html +1 -1
- package/docs/types/OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
- package/docs/types/OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
- package/docs/types/OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
- package/docs/types/OpenapiSchemaString.html +1 -1
- package/docs/types/OpenapiShorthandAllTypes.html +1 -1
- package/docs/types/OpenapiShorthandPrimitiveBaseTypes.html +1 -1
- package/docs/types/OpenapiShorthandPrimitiveTypes.html +1 -1
- package/docs/types/OpenapiTypeField.html +1 -1
- package/docs/types/Pascalized.html +1 -1
- package/docs/types/PrimaryKeyType.html +1 -1
- package/docs/types/RoundingPrecision.html +1 -1
- package/docs/types/SerializerCasing.html +1 -1
- package/docs/types/SimpleObjectSerializerType.html +1 -1
- package/docs/types/Snakeified.html +1 -1
- package/docs/types/Timestamp.html +1 -1
- package/docs/types/UpdateableAssociationProperties.html +1 -1
- package/docs/types/UpdateableProperties.html +1 -1
- package/docs/types/ValidationType.html +1 -1
- package/docs/types/ViewModel.html +1 -1
- package/docs/types/ViewModelClass.html +1 -1
- package/docs/types/WhereStatementForDream.html +1 -1
- package/docs/types/WhereStatementForDreamClass.html +1 -1
- package/docs/variables/DateTime-1.html +1 -1
- package/docs/variables/DreamConst.html +1 -1
- package/docs/variables/TRIGRAM_OPERATORS.html +1 -1
- package/docs/variables/openapiPrimitiveTypes-1.html +1 -1
- package/docs/variables/openapiShorthandPrimitiveTypes-1.html +1 -1
- package/docs/variables/ops.html +1 -1
- package/docs/variables/primaryKeyTypes.html +1 -1
- 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
|
|
402
|
-
* @param
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1251
|
-
* @param
|
|
1252
|
-
* @param
|
|
1253
|
-
* @param
|
|
1254
|
-
* @param
|
|
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.
|
|
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
|
|
1298
|
-
* @param
|
|
1299
|
-
* @param
|
|
1300
|
-
* @param
|
|
1301
|
-
* @param
|
|
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
|
|
1320
|
-
* @param
|
|
1321
|
-
* @param
|
|
1322
|
-
* @param
|
|
1323
|
-
* @param
|
|
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.
|
|
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
|
}
|