joist-core 2.3.0-next.97 → 2.3.0-next.99
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/build/BaseEntity.cjs.map +1 -1
- package/build/BaseEntity.js.map +1 -1
- package/build/Entity.cjs.map +1 -1
- package/build/Entity.js.map +1 -1
- package/build/EntityManager.cjs +45 -46
- package/build/EntityManager.cjs.map +1 -1
- package/build/EntityManager.d.cts +7 -7
- package/build/EntityManager.d.cts.map +1 -1
- package/build/EntityManager.d.mts +7 -7
- package/build/EntityManager.d.mts.map +1 -1
- package/build/EntityManager.js +27 -28
- package/build/EntityManager.js.map +1 -1
- package/build/EntityMetadata.cjs +0 -2
- package/build/EntityMetadata.cjs.map +1 -1
- package/build/EntityMetadata.d.cts +3 -3
- package/build/EntityMetadata.d.mts +3 -3
- package/build/EntityMetadata.js +0 -2
- package/build/EntityMetadata.js.map +1 -1
- package/build/IndexManager.cjs +1 -1
- package/build/IndexManager.cjs.map +1 -1
- package/build/IndexManager.js +1 -1
- package/build/IndexManager.js.map +1 -1
- package/build/InstanceData.cjs.map +1 -1
- package/build/InstanceData.js.map +1 -1
- package/build/PluginManager.cjs +0 -1
- package/build/PluginManager.cjs.map +1 -1
- package/build/PluginManager.d.cts +1 -1
- package/build/PluginManager.d.mts +1 -1
- package/build/PluginManager.js +0 -1
- package/build/PluginManager.js.map +1 -1
- package/build/batchloaders/enumCollectionBatchLoader.cjs +1 -1
- package/build/batchloaders/enumCollectionBatchLoader.cjs.map +1 -1
- package/build/batchloaders/enumCollectionBatchLoader.d.cts +1 -1
- package/build/batchloaders/enumCollectionBatchLoader.d.mts +1 -1
- package/build/batchloaders/enumCollectionBatchLoader.js +1 -1
- package/build/batchloaders/enumCollectionBatchLoader.js.map +1 -1
- package/build/batchloaders/loadBatchLoader.cjs +3 -4
- package/build/batchloaders/loadBatchLoader.cjs.map +1 -1
- package/build/batchloaders/loadBatchLoader.d.cts +1 -1
- package/build/batchloaders/loadBatchLoader.d.mts +1 -1
- package/build/batchloaders/loadBatchLoader.js +2 -3
- package/build/batchloaders/loadBatchLoader.js.map +1 -1
- package/build/batchloaders/manyToManyBatchLoader.cjs +1 -1
- package/build/batchloaders/manyToManyBatchLoader.cjs.map +1 -1
- package/build/batchloaders/manyToManyBatchLoader.d.cts +1 -1
- package/build/batchloaders/manyToManyBatchLoader.d.mts +1 -1
- package/build/batchloaders/manyToManyBatchLoader.js +1 -1
- package/build/batchloaders/manyToManyBatchLoader.js.map +1 -1
- package/build/batchloaders/oneToManyBatchLoader.cjs +1 -1
- package/build/batchloaders/oneToManyBatchLoader.cjs.map +1 -1
- package/build/batchloaders/oneToManyBatchLoader.js +1 -1
- package/build/batchloaders/oneToManyBatchLoader.js.map +1 -1
- package/build/batchloaders/oneToOneBatchLoader.cjs +1 -1
- package/build/batchloaders/oneToOneBatchLoader.cjs.map +1 -1
- package/build/batchloaders/oneToOneBatchLoader.js +1 -1
- package/build/batchloaders/oneToOneBatchLoader.js.map +1 -1
- package/build/batchloaders/populateBatchLoader.cjs +11 -12
- package/build/batchloaders/populateBatchLoader.cjs.map +1 -1
- package/build/batchloaders/populateBatchLoader.d.cts +1 -1
- package/build/batchloaders/populateBatchLoader.d.mts +1 -1
- package/build/batchloaders/populateBatchLoader.js +7 -8
- package/build/batchloaders/populateBatchLoader.js.map +1 -1
- package/build/batchloaders/recursiveChildrenBatchLoader.cjs +2 -2
- package/build/batchloaders/recursiveChildrenBatchLoader.cjs.map +1 -1
- package/build/batchloaders/recursiveChildrenBatchLoader.js +2 -2
- package/build/batchloaders/recursiveChildrenBatchLoader.js.map +1 -1
- package/build/batchloaders/recursiveM2mBatchLoader.cjs +2 -2
- package/build/batchloaders/recursiveM2mBatchLoader.cjs.map +1 -1
- package/build/batchloaders/recursiveM2mBatchLoader.js +2 -2
- package/build/batchloaders/recursiveM2mBatchLoader.js.map +1 -1
- package/build/batchloaders/recursiveParentsBatchLoader.cjs +2 -2
- package/build/batchloaders/recursiveParentsBatchLoader.cjs.map +1 -1
- package/build/batchloaders/recursiveParentsBatchLoader.js +2 -2
- package/build/batchloaders/recursiveParentsBatchLoader.js.map +1 -1
- package/build/changes.cjs +2 -3
- package/build/changes.cjs.map +1 -1
- package/build/changes.js +2 -3
- package/build/changes.js.map +1 -1
- package/build/config.cjs +3 -3
- package/build/config.cjs.map +1 -1
- package/build/config.d.cts +2 -2
- package/build/config.d.mts +2 -2
- package/build/config.js +1 -1
- package/build/config.js.map +1 -1
- package/build/configure.cjs +10 -10
- package/build/configure.cjs.map +1 -1
- package/build/configure.js +5 -5
- package/build/configure.js.map +1 -1
- package/build/dataloaders/fastWhereFilterHash.cjs +8 -8
- package/build/dataloaders/fastWhereFilterHash.cjs.map +1 -1
- package/build/dataloaders/fastWhereFilterHash.d.cts.map +1 -1
- package/build/dataloaders/fastWhereFilterHash.d.mts.map +1 -1
- package/build/dataloaders/fastWhereFilterHash.js +3 -3
- package/build/dataloaders/fastWhereFilterHash.js.map +1 -1
- package/build/dataloaders/findByUniqueDataLoader.cjs.map +1 -1
- package/build/dataloaders/findByUniqueDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findByUniqueDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findByUniqueDataLoader.js.map +1 -1
- package/build/dataloaders/findCountDataLoader.cjs +2 -2
- package/build/dataloaders/findCountDataLoader.cjs.map +1 -1
- package/build/dataloaders/findCountDataLoader.js +1 -1
- package/build/dataloaders/findCountDataLoader.js.map +1 -1
- package/build/dataloaders/findDataLoader.cjs +6 -6
- package/build/dataloaders/findDataLoader.cjs.map +1 -1
- package/build/dataloaders/findDataLoader.d.cts +1 -1
- package/build/dataloaders/findDataLoader.d.mts +1 -1
- package/build/dataloaders/findDataLoader.js +3 -3
- package/build/dataloaders/findDataLoader.js.map +1 -1
- package/build/dataloaders/findIdsDataLoader.cjs +3 -3
- package/build/dataloaders/findIdsDataLoader.cjs.map +1 -1
- package/build/dataloaders/findIdsDataLoader.js +2 -2
- package/build/dataloaders/findIdsDataLoader.js.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.cjs +1 -1
- package/build/dataloaders/findOrCreateDataLoader.cjs.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findOrCreateDataLoader.js +1 -1
- package/build/dataloaders/findOrCreateDataLoader.js.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.cjs +6 -6
- package/build/dataloaders/findPaginatedDataLoader.cjs.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.d.cts +1 -1
- package/build/dataloaders/findPaginatedDataLoader.d.mts +1 -1
- package/build/dataloaders/findPaginatedDataLoader.js +3 -3
- package/build/dataloaders/findPaginatedDataLoader.js.map +1 -1
- package/build/dataloaders/lensDataLoader.cjs +3 -3
- package/build/dataloaders/lensDataLoader.cjs.map +1 -1
- package/build/dataloaders/lensDataLoader.d.cts.map +1 -1
- package/build/dataloaders/lensDataLoader.d.mts.map +1 -1
- package/build/dataloaders/lensDataLoader.js +2 -2
- package/build/dataloaders/lensDataLoader.js.map +1 -1
- package/build/dataloaders/manyToManyFindDataLoader.cjs +1 -1
- package/build/dataloaders/manyToManyFindDataLoader.cjs.map +1 -1
- package/build/dataloaders/manyToManyFindDataLoader.d.cts.map +1 -1
- package/build/dataloaders/manyToManyFindDataLoader.d.mts.map +1 -1
- package/build/dataloaders/manyToManyFindDataLoader.js +1 -1
- package/build/dataloaders/manyToManyFindDataLoader.js.map +1 -1
- package/build/dataloaders/oneToManyFindDataLoader.cjs +1 -1
- package/build/dataloaders/oneToManyFindDataLoader.cjs.map +1 -1
- package/build/dataloaders/oneToManyFindDataLoader.d.cts.map +1 -1
- package/build/dataloaders/oneToManyFindDataLoader.d.mts.map +1 -1
- package/build/dataloaders/oneToManyFindDataLoader.js +1 -1
- package/build/dataloaders/oneToManyFindDataLoader.js.map +1 -1
- package/build/defaults.cjs +5 -5
- package/build/defaults.cjs.map +1 -1
- package/build/defaults.d.cts +1 -1
- package/build/defaults.d.cts.map +1 -1
- package/build/defaults.d.mts +1 -1
- package/build/defaults.d.mts.map +1 -1
- package/build/defaults.js +4 -4
- package/build/defaults.js.map +1 -1
- package/build/drivers/Driver.cjs +0 -1
- package/build/drivers/Driver.d.cts +1 -1
- package/build/drivers/Driver.d.mts +1 -1
- package/build/drivers/Driver.js +0 -1
- package/build/drivers/EntityWriter.cjs +6 -7
- package/build/drivers/EntityWriter.cjs.map +1 -1
- package/build/drivers/EntityWriter.d.cts +1 -1
- package/build/drivers/EntityWriter.d.mts +1 -1
- package/build/drivers/EntityWriter.js +2 -3
- package/build/drivers/EntityWriter.js.map +1 -1
- package/build/drivers/IdAssigner.cjs +0 -1
- package/build/drivers/IdAssigner.cjs.map +1 -1
- package/build/drivers/IdAssigner.d.cts +1 -1
- package/build/drivers/IdAssigner.d.mts +1 -1
- package/build/drivers/IdAssigner.js +0 -1
- package/build/drivers/IdAssigner.js.map +1 -1
- package/build/drivers/driverApi.cjs +19 -0
- package/build/drivers/driverApi.cjs.map +1 -0
- package/build/drivers/driverApi.d.cts +22 -0
- package/build/drivers/driverApi.d.cts.map +1 -0
- package/build/drivers/driverApi.d.mts +22 -0
- package/build/drivers/driverApi.d.mts.map +1 -0
- package/build/drivers/driverApi.js +18 -0
- package/build/drivers/driverApi.js.map +1 -0
- package/build/fields.cjs +3 -3
- package/build/fields.cjs.map +1 -1
- package/build/fields.js +2 -2
- package/build/fields.js.map +1 -1
- package/build/{FlushLock.cjs → flush/FlushLock.cjs} +1 -1
- package/build/flush/FlushLock.cjs.map +1 -0
- package/build/{FlushLock.d.cts → flush/FlushLock.d.cts} +1 -1
- package/build/flush/FlushLock.d.cts.map +1 -0
- package/build/{FlushLock.d.mts → flush/FlushLock.d.mts} +1 -1
- package/build/flush/FlushLock.d.mts.map +1 -0
- package/build/{FlushLock.js → flush/FlushLock.js} +1 -1
- package/build/flush/FlushLock.js.map +1 -0
- package/build/{JoinRows.cjs → flush/JoinRows.cjs} +5 -8
- package/build/flush/JoinRows.cjs.map +1 -0
- package/build/{JoinRows.d.cts → flush/JoinRows.d.cts} +5 -5
- package/build/flush/JoinRows.d.cts.map +1 -0
- package/build/{JoinRows.d.mts → flush/JoinRows.d.mts} +5 -5
- package/build/flush/JoinRows.d.mts.map +1 -0
- package/build/{JoinRows.js → flush/JoinRows.js} +5 -8
- package/build/flush/JoinRows.js.map +1 -0
- package/build/{PendingChanges.cjs → flush/PendingChanges.cjs} +0 -1
- package/build/{PendingChanges.d.cts → flush/PendingChanges.d.cts} +2 -2
- package/build/flush/PendingChanges.d.cts.map +1 -0
- package/build/{PendingChanges.d.mts → flush/PendingChanges.d.mts} +2 -2
- package/build/flush/PendingChanges.d.mts.map +1 -0
- package/build/flush/PendingChanges.js +1 -0
- package/build/{Todo.cjs → flush/Todo.cjs} +4 -6
- package/build/flush/Todo.cjs.map +1 -0
- package/build/{Todo.d.cts → flush/Todo.d.cts} +3 -3
- package/build/flush/Todo.d.cts.map +1 -0
- package/build/{Todo.d.mts → flush/Todo.d.mts} +3 -3
- package/build/flush/Todo.d.mts.map +1 -0
- package/build/{Todo.js → flush/Todo.js} +4 -6
- package/build/flush/Todo.js.map +1 -0
- package/build/getProperties.cjs.map +1 -1
- package/build/getProperties.js.map +1 -1
- package/build/index.cjs +100 -100
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +15 -15
- package/build/index.d.mts +15 -15
- package/build/index.js +42 -42
- package/build/index.js.map +1 -1
- package/build/json.cjs +4 -4
- package/build/json.cjs.map +1 -1
- package/build/json.js +3 -3
- package/build/json.js.map +1 -1
- package/build/keys.cjs +1 -1
- package/build/keys.cjs.map +1 -1
- package/build/keys.js +1 -1
- package/build/keys.js.map +1 -1
- package/build/{HintTree.cjs → loading/HintTree.cjs} +2 -5
- package/build/loading/HintTree.cjs.map +1 -0
- package/build/{HintTree.d.cts → loading/HintTree.d.cts} +3 -3
- package/build/loading/HintTree.d.cts.map +1 -0
- package/build/{HintTree.d.mts → loading/HintTree.d.mts} +3 -3
- package/build/loading/HintTree.d.mts.map +1 -0
- package/build/{HintTree.js → loading/HintTree.js} +2 -5
- package/build/loading/HintTree.js.map +1 -0
- package/build/{IsLoadedCache.cjs → loading/IsLoadedCache.cjs} +2 -3
- package/build/loading/IsLoadedCache.cjs.map +1 -0
- package/build/{IsLoadedCache.d.cts → loading/IsLoadedCache.d.cts} +2 -2
- package/build/loading/IsLoadedCache.d.cts.map +1 -0
- package/build/{IsLoadedCache.d.mts → loading/IsLoadedCache.d.mts} +2 -2
- package/build/loading/IsLoadedCache.d.mts.map +1 -0
- package/build/{IsLoadedCache.js → loading/IsLoadedCache.js} +2 -3
- package/build/{IsLoadedCache.cjs.map → loading/IsLoadedCache.js.map} +1 -1
- package/build/{loadHints.cjs → loading/loadHints.cjs} +6 -11
- package/build/loading/loadHints.cjs.map +1 -0
- package/build/{loadHints.d.cts → loading/loadHints.d.cts} +14 -14
- package/build/loading/loadHints.d.cts.map +1 -0
- package/build/{loadHints.d.mts → loading/loadHints.d.mts} +14 -14
- package/build/loading/loadHints.d.mts.map +1 -0
- package/build/{loadHints.js → loading/loadHints.js} +3 -8
- package/build/loading/loadHints.js.map +1 -0
- package/build/{loadLens.cjs → loading/loadLens.cjs} +8 -9
- package/build/loading/loadLens.cjs.map +1 -0
- package/build/{loadLens.d.cts → loading/loadLens.d.cts} +3 -3
- package/build/loading/loadLens.d.cts.map +1 -0
- package/build/{loadLens.d.mts → loading/loadLens.d.mts} +3 -3
- package/build/loading/loadLens.d.mts.map +1 -0
- package/build/{loadLens.js → loading/loadLens.js} +8 -9
- package/build/loading/loadLens.js.map +1 -0
- package/build/{withLoaded.cjs → loading/withLoaded.cjs} +12 -13
- package/build/loading/withLoaded.cjs.map +1 -0
- package/build/{withLoaded.d.cts → loading/withLoaded.d.cts} +9 -9
- package/build/loading/withLoaded.d.cts.map +1 -0
- package/build/{withLoaded.d.mts → loading/withLoaded.d.mts} +9 -9
- package/build/loading/withLoaded.d.mts.map +1 -0
- package/build/{withLoaded.js → loading/withLoaded.js} +10 -11
- package/build/loading/withLoaded.js.map +1 -0
- package/build/logging/FactoryLogger.cjs.map +1 -1
- package/build/logging/FactoryLogger.d.cts.map +1 -1
- package/build/logging/FactoryLogger.d.mts.map +1 -1
- package/build/logging/FactoryLogger.js.map +1 -1
- package/build/logging/FieldLogger.cjs.map +1 -1
- package/build/logging/FieldLogger.d.cts.map +1 -1
- package/build/logging/FieldLogger.d.mts.map +1 -1
- package/build/logging/FieldLogger.js.map +1 -1
- package/build/logging/ReactionLogger.cjs +0 -2
- package/build/logging/ReactionLogger.cjs.map +1 -1
- package/build/logging/ReactionLogger.d.cts +2 -2
- package/build/logging/ReactionLogger.d.cts.map +1 -1
- package/build/logging/ReactionLogger.d.mts +2 -2
- package/build/logging/ReactionLogger.d.mts.map +1 -1
- package/build/logging/ReactionLogger.js +0 -2
- package/build/logging/ReactionLogger.js.map +1 -1
- package/build/newEntity.cjs.map +1 -1
- package/build/newEntity.js.map +1 -1
- package/build/newTestInstance.cjs +3 -3
- package/build/newTestInstance.cjs.map +1 -1
- package/build/newTestInstance.d.cts +1 -1
- package/build/newTestInstance.d.cts.map +1 -1
- package/build/newTestInstance.d.mts +1 -1
- package/build/newTestInstance.d.mts.map +1 -1
- package/build/newTestInstance.js +2 -2
- package/build/newTestInstance.js.map +1 -1
- package/build/normalizeHints.cjs +0 -2
- package/build/normalizeHints.cjs.map +1 -1
- package/build/normalizeHints.d.cts +2 -2
- package/build/normalizeHints.d.mts +2 -2
- package/build/normalizeHints.js +0 -2
- package/build/normalizeHints.js.map +1 -1
- package/build/nowUTC.cjs +2 -2
- package/build/nowUTC.cjs.map +1 -1
- package/build/nowUTC.d.cts +1 -1
- package/build/nowUTC.d.mts +1 -1
- package/build/nowUTC.js +1 -1
- package/build/nowUTC.js.map +1 -1
- package/build/plugins/ImmutableEntitiesPlugin.cjs.map +1 -1
- package/build/plugins/ImmutableEntitiesPlugin.js.map +1 -1
- package/build/plugins/PreloadPlugin.cjs +0 -2
- package/build/plugins/PreloadPlugin.d.cts +2 -2
- package/build/plugins/PreloadPlugin.d.mts +2 -2
- package/build/plugins/PreloadPlugin.js +0 -2
- package/build/preloading/JsonAggregatePreloader.cjs +1 -4
- package/build/preloading/JsonAggregatePreloader.cjs.map +1 -1
- package/build/preloading/JsonAggregatePreloader.d.cts +2 -2
- package/build/preloading/JsonAggregatePreloader.d.cts.map +1 -1
- package/build/preloading/JsonAggregatePreloader.d.mts +2 -2
- package/build/preloading/JsonAggregatePreloader.d.mts.map +1 -1
- package/build/preloading/JsonAggregatePreloader.js +1 -4
- package/build/preloading/JsonAggregatePreloader.js.map +1 -1
- package/build/preloading/canPreload.cjs.map +1 -1
- package/build/preloading/canPreload.js.map +1 -1
- package/build/preloading/partitionHint.cjs +2 -3
- package/build/preloading/partitionHint.cjs.map +1 -1
- package/build/preloading/partitionHint.d.cts +1 -1
- package/build/preloading/partitionHint.d.mts +1 -1
- package/build/preloading/partitionHint.js +2 -3
- package/build/preloading/partitionHint.js.map +1 -1
- package/build/queries/ConditionBuilder.cjs.map +1 -1
- package/build/queries/ConditionBuilder.d.cts +1 -1
- package/build/queries/ConditionBuilder.d.mts +1 -1
- package/build/queries/ConditionBuilder.js.map +1 -1
- package/build/queries/conditions.cjs.map +1 -1
- package/build/queries/conditions.js.map +1 -1
- package/build/queries/entityQueryUtils.cjs.map +1 -1
- package/build/queries/entityQueryUtils.js.map +1 -1
- package/build/queries/find/Aliases.cjs +1 -1
- package/build/queries/find/Aliases.cjs.map +1 -1
- package/build/queries/find/Aliases.d.cts.map +1 -1
- package/build/queries/find/Aliases.d.mts.map +1 -1
- package/build/queries/find/Aliases.js +1 -1
- package/build/queries/find/Aliases.js.map +1 -1
- package/build/queries/find/DeferredAlias.cjs.map +1 -1
- package/build/queries/find/DeferredAlias.js.map +1 -1
- package/build/queries/find/EntityFilter.cjs.map +1 -1
- package/build/queries/find/EntityFilter.js.map +1 -1
- package/build/queries/find/EntityGraphQLFilter.cjs.map +1 -1
- package/build/queries/find/EntityGraphQLFilter.js.map +1 -1
- package/build/queries/find/QueryParser.cjs +2 -2
- package/build/queries/find/QueryParser.cjs.map +1 -1
- package/build/queries/find/QueryParser.collectionJoins.cjs.map +1 -1
- package/build/queries/find/QueryParser.collectionJoins.js.map +1 -1
- package/build/queries/find/QueryParser.d.cts.map +1 -1
- package/build/queries/find/QueryParser.d.mts.map +1 -1
- package/build/queries/find/QueryParser.js +2 -2
- package/build/queries/find/QueryParser.js.map +1 -1
- package/build/queries/find/QueryParser.pruning.cjs.map +1 -1
- package/build/queries/find/QueryParser.pruning.js.map +1 -1
- package/build/queries/find/QueryVisitor.cjs.map +1 -1
- package/build/queries/find/QueryVisitor.js.map +1 -1
- package/build/queries/find/buildFindQuery.cjs.map +1 -1
- package/build/queries/find/buildFindQuery.js.map +1 -1
- package/build/queries/find/scopes.cjs.map +1 -1
- package/build/queries/find/scopes.d.cts +1 -1
- package/build/queries/find/scopes.d.mts +1 -1
- package/build/queries/find/scopes.js.map +1 -1
- package/build/queries/parsedConditions.cjs.map +1 -1
- package/build/queries/parsedConditions.js.map +1 -1
- package/build/queries/renderConditions.cjs.map +1 -1
- package/build/queries/renderConditions.js.map +1 -1
- package/build/queries/skipCondition.cjs.map +1 -1
- package/build/queries/skipCondition.js.map +1 -1
- package/build/queries/sql/AliasAssigner.cjs.map +1 -1
- package/build/queries/sql/AliasAssigner.js.map +1 -1
- package/build/queries/sql/Expr.cjs +2 -2
- package/build/queries/sql/Expr.cjs.map +1 -1
- package/build/queries/sql/Expr.d.cts +1 -1
- package/build/queries/sql/Expr.d.mts +1 -1
- package/build/queries/sql/Expr.js +1 -1
- package/build/queries/sql/Expr.js.map +1 -1
- package/build/queries/sql/Tables.cjs +1 -1
- package/build/queries/sql/Tables.cjs.map +1 -1
- package/build/queries/sql/Tables.d.cts.map +1 -1
- package/build/queries/sql/Tables.d.mts.map +1 -1
- package/build/queries/sql/Tables.js +1 -1
- package/build/queries/sql/Tables.js.map +1 -1
- package/build/queries/sql/execute.cjs +1 -1
- package/build/queries/sql/execute.cjs.map +1 -1
- package/build/queries/sql/execute.js +1 -1
- package/build/queries/sql/execute.js.map +1 -1
- package/build/queries/sql/expressions/arrayAgg.cjs.map +1 -1
- package/build/queries/sql/expressions/arrayAgg.js.map +1 -1
- package/build/queries/sql/expressions/case.cjs.map +1 -1
- package/build/queries/sql/expressions/case.js.map +1 -1
- package/build/queries/sql/expressions/coalesce.cjs.map +1 -1
- package/build/queries/sql/expressions/coalesce.js.map +1 -1
- package/build/queries/sql/expressions/codecs.cjs +2 -2
- package/build/queries/sql/expressions/codecs.cjs.map +1 -1
- package/build/queries/sql/expressions/codecs.js +1 -1
- package/build/queries/sql/expressions/codecs.js.map +1 -1
- package/build/queries/sql/expressions/expression.cjs.map +1 -1
- package/build/queries/sql/expressions/expression.d.cts.map +1 -1
- package/build/queries/sql/expressions/expression.d.mts.map +1 -1
- package/build/queries/sql/expressions/expression.js.map +1 -1
- package/build/queries/sql/expressions/greatest.cjs.map +1 -1
- package/build/queries/sql/expressions/greatest.js.map +1 -1
- package/build/queries/sql/expressions/least.cjs.map +1 -1
- package/build/queries/sql/expressions/least.js.map +1 -1
- package/build/queries/sql/expressions/nullIf.cjs.map +1 -1
- package/build/queries/sql/expressions/nullIf.js.map +1 -1
- package/build/queries/sql/expressions/parseExpression.cjs.map +1 -1
- package/build/queries/sql/expressions/parseExpression.js.map +1 -1
- package/build/queries/sql/expressions/types.d.cts.map +1 -1
- package/build/queries/sql/expressions/types.d.mts.map +1 -1
- package/build/queries/sql/query.cjs +1 -1
- package/build/queries/sql/query.cjs.map +1 -1
- package/build/queries/sql/query.d.cts +1 -1
- package/build/queries/sql/query.d.mts +1 -1
- package/build/queries/sql/query.js +1 -1
- package/build/queries/sql/query.js.map +1 -1
- package/build/{unnest.cjs → queries/unnest.cjs} +1 -2
- package/build/queries/unnest.cjs.map +1 -0
- package/build/{unnest.d.cts → queries/unnest.d.cts} +3 -3
- package/build/queries/unnest.d.cts.map +1 -0
- package/build/{unnest.d.mts → queries/unnest.d.mts} +3 -3
- package/build/queries/unnest.d.mts.map +1 -0
- package/build/{unnest.js → queries/unnest.js} +1 -2
- package/build/queries/unnest.js.map +1 -0
- package/build/queries/valueFilters.cjs.map +1 -1
- package/build/queries/valueFilters.d.cts +1 -1
- package/build/queries/valueFilters.d.cts.map +1 -1
- package/build/queries/valueFilters.d.mts +1 -1
- package/build/queries/valueFilters.d.mts.map +1 -1
- package/build/queries/valueFilters.js.map +1 -1
- package/build/{ReactionsManager.cjs → reactivity/ReactionsManager.cjs} +8 -10
- package/build/reactivity/ReactionsManager.cjs.map +1 -0
- package/build/{ReactionsManager.d.cts → reactivity/ReactionsManager.d.cts} +5 -6
- package/build/reactivity/ReactionsManager.d.cts.map +1 -0
- package/build/{ReactionsManager.d.mts → reactivity/ReactionsManager.d.mts} +5 -6
- package/build/reactivity/ReactionsManager.d.mts.map +1 -0
- package/build/{ReactionsManager.js → reactivity/ReactionsManager.js} +6 -8
- package/build/reactivity/ReactionsManager.js.map +1 -0
- package/build/{reactiveHints.cjs → reactivity/reactiveHints.cjs} +12 -16
- package/build/reactivity/reactiveHints.cjs.map +1 -0
- package/build/{reactiveHints.d.cts → reactivity/reactiveHints.d.cts} +17 -17
- package/build/reactivity/reactiveHints.d.cts.map +1 -0
- package/build/{reactiveHints.d.mts → reactivity/reactiveHints.d.mts} +17 -17
- package/build/reactivity/reactiveHints.d.mts.map +1 -0
- package/build/{reactiveHints.js → reactivity/reactiveHints.js} +12 -16
- package/build/reactivity/reactiveHints.js.map +1 -0
- package/build/relations/AbstractRelationImpl.cjs.map +1 -1
- package/build/relations/AbstractRelationImpl.js.map +1 -1
- package/build/relations/AsyncProperty.cjs.map +1 -1
- package/build/relations/AsyncProperty.js.map +1 -1
- package/build/relations/AsyncReactiveField.cjs +6 -6
- package/build/relations/AsyncReactiveField.cjs.map +1 -1
- package/build/relations/AsyncReactiveField.d.cts +1 -1
- package/build/relations/AsyncReactiveField.d.mts +1 -1
- package/build/relations/AsyncReactiveField.js +4 -4
- package/build/relations/AsyncReactiveField.js.map +1 -1
- package/build/relations/Collection.cjs +1 -1
- package/build/relations/Collection.cjs.map +1 -1
- package/build/relations/Collection.js +1 -1
- package/build/relations/Collection.js.map +1 -1
- package/build/relations/CustomCollection.cjs.map +1 -1
- package/build/relations/CustomCollection.d.cts +1 -1
- package/build/relations/CustomCollection.d.mts +1 -1
- package/build/relations/CustomCollection.js.map +1 -1
- package/build/relations/CustomReference.cjs +1 -1
- package/build/relations/CustomReference.cjs.map +1 -1
- package/build/relations/CustomReference.d.cts +1 -1
- package/build/relations/CustomReference.d.mts +1 -1
- package/build/relations/CustomReference.js +1 -1
- package/build/relations/CustomReference.js.map +1 -1
- package/build/relations/EnumCollection.cjs.map +1 -1
- package/build/relations/EnumCollection.d.cts +1 -1
- package/build/relations/EnumCollection.d.mts +1 -1
- package/build/relations/EnumCollection.js.map +1 -1
- package/build/relations/LazyField.cjs +4 -4
- package/build/relations/LazyField.cjs.map +1 -1
- package/build/relations/LazyField.js +4 -4
- package/build/relations/LazyField.js.map +1 -1
- package/build/relations/ManyToManyCollection.cjs +3 -3
- package/build/relations/ManyToManyCollection.cjs.map +1 -1
- package/build/relations/ManyToManyCollection.js +3 -3
- package/build/relations/ManyToManyCollection.js.map +1 -1
- package/build/relations/ManyToManyLargeCollection.cjs +3 -3
- package/build/relations/ManyToManyLargeCollection.cjs.map +1 -1
- package/build/relations/ManyToManyLargeCollection.js +3 -3
- package/build/relations/ManyToManyLargeCollection.js.map +1 -1
- package/build/relations/ManyToOneReference.cjs +4 -4
- package/build/relations/ManyToOneReference.cjs.map +1 -1
- package/build/relations/ManyToOneReference.js +4 -4
- package/build/relations/ManyToOneReference.js.map +1 -1
- package/build/relations/OneToManyCollection.cjs +1 -2
- package/build/relations/OneToManyCollection.cjs.map +1 -1
- package/build/relations/OneToManyCollection.d.cts +1 -1
- package/build/relations/OneToManyCollection.d.mts +1 -1
- package/build/relations/OneToManyCollection.js +1 -2
- package/build/relations/OneToManyCollection.js.map +1 -1
- package/build/relations/OneToManyLargeCollection.cjs +1 -1
- package/build/relations/OneToManyLargeCollection.cjs.map +1 -1
- package/build/relations/OneToManyLargeCollection.js +1 -1
- package/build/relations/OneToManyLargeCollection.js.map +1 -1
- package/build/relations/OneToOneReference.cjs +5 -5
- package/build/relations/OneToOneReference.cjs.map +1 -1
- package/build/relations/OneToOneReference.js +5 -5
- package/build/relations/OneToOneReference.js.map +1 -1
- package/build/relations/PolymorphicReference.cjs +3 -3
- package/build/relations/PolymorphicReference.cjs.map +1 -1
- package/build/relations/PolymorphicReference.js +3 -3
- package/build/relations/PolymorphicReference.js.map +1 -1
- package/build/relations/ReactiveField.cjs +5 -6
- package/build/relations/ReactiveField.cjs.map +1 -1
- package/build/relations/ReactiveField.d.cts +2 -2
- package/build/relations/ReactiveField.d.mts +2 -2
- package/build/relations/ReactiveField.js +3 -4
- package/build/relations/ReactiveField.js.map +1 -1
- package/build/relations/ReactiveGetter.cjs +0 -1
- package/build/relations/ReactiveGetter.cjs.map +1 -1
- package/build/relations/ReactiveGetter.d.cts +1 -1
- package/build/relations/ReactiveGetter.d.mts +1 -1
- package/build/relations/ReactiveGetter.js +0 -1
- package/build/relations/ReactiveGetter.js.map +1 -1
- package/build/relations/ReactiveManyToMany.cjs +5 -6
- package/build/relations/ReactiveManyToMany.cjs.map +1 -1
- package/build/relations/ReactiveManyToMany.d.cts +2 -2
- package/build/relations/ReactiveManyToMany.d.cts.map +1 -1
- package/build/relations/ReactiveManyToMany.d.mts +2 -2
- package/build/relations/ReactiveManyToMany.d.mts.map +1 -1
- package/build/relations/ReactiveManyToMany.js +3 -4
- package/build/relations/ReactiveManyToMany.js.map +1 -1
- package/build/relations/ReactiveManyToManyOtherSide.cjs +1 -3
- package/build/relations/ReactiveManyToManyOtherSide.cjs.map +1 -1
- package/build/relations/ReactiveManyToManyOtherSide.d.cts +2 -2
- package/build/relations/ReactiveManyToManyOtherSide.d.mts +2 -2
- package/build/relations/ReactiveManyToManyOtherSide.js +1 -3
- package/build/relations/ReactiveManyToManyOtherSide.js.map +1 -1
- package/build/relations/ReactiveReference.cjs +8 -9
- package/build/relations/ReactiveReference.cjs.map +1 -1
- package/build/relations/ReactiveReference.d.cts +2 -2
- package/build/relations/ReactiveReference.d.cts.map +1 -1
- package/build/relations/ReactiveReference.d.mts +2 -2
- package/build/relations/ReactiveReference.d.mts.map +1 -1
- package/build/relations/ReactiveReference.js +6 -7
- package/build/relations/ReactiveReference.js.map +1 -1
- package/build/relations/ReadOnlyCollection.cjs.map +1 -1
- package/build/relations/ReadOnlyCollection.js.map +1 -1
- package/build/relations/RecursiveCollection.cjs +3 -4
- package/build/relations/RecursiveCollection.cjs.map +1 -1
- package/build/relations/RecursiveCollection.d.cts +1 -1
- package/build/relations/RecursiveCollection.d.mts +1 -1
- package/build/relations/RecursiveCollection.js +3 -4
- package/build/relations/RecursiveCollection.js.map +1 -1
- package/build/relations/RecursiveCycleError.cjs.map +1 -1
- package/build/relations/RecursiveCycleError.js.map +1 -1
- package/build/relations/Reference.cjs +1 -1
- package/build/relations/Reference.cjs.map +1 -1
- package/build/relations/Reference.js +1 -1
- package/build/relations/Reference.js.map +1 -1
- package/build/relations/Relation.cjs.map +1 -1
- package/build/relations/Relation.js.map +1 -1
- package/build/relations/hasAsyncMethod.cjs +2 -2
- package/build/relations/hasAsyncMethod.cjs.map +1 -1
- package/build/relations/hasAsyncMethod.d.cts +1 -1
- package/build/relations/hasAsyncMethod.d.mts +1 -1
- package/build/relations/hasAsyncMethod.js +1 -1
- package/build/relations/hasAsyncMethod.js.map +1 -1
- package/build/relations/hasManyDerived.cjs +3 -3
- package/build/relations/hasManyDerived.cjs.map +1 -1
- package/build/relations/hasManyDerived.d.cts +1 -1
- package/build/relations/hasManyDerived.d.mts +1 -1
- package/build/relations/hasManyDerived.js +2 -2
- package/build/relations/hasManyDerived.js.map +1 -1
- package/build/relations/hasManyThrough.cjs +6 -6
- package/build/relations/hasManyThrough.cjs.map +1 -1
- package/build/relations/hasManyThrough.d.cts +1 -1
- package/build/relations/hasManyThrough.d.mts +1 -1
- package/build/relations/hasManyThrough.js +2 -2
- package/build/relations/hasManyThrough.js.map +1 -1
- package/build/relations/hasOneDerived.cjs +3 -3
- package/build/relations/hasOneDerived.cjs.map +1 -1
- package/build/relations/hasOneDerived.d.cts +1 -1
- package/build/relations/hasOneDerived.d.mts +1 -1
- package/build/relations/hasOneDerived.js +2 -2
- package/build/relations/hasOneDerived.js.map +1 -1
- package/build/relations/hasOneThrough.cjs +7 -7
- package/build/relations/hasOneThrough.cjs.map +1 -1
- package/build/relations/hasOneThrough.d.cts +1 -1
- package/build/relations/hasOneThrough.d.mts +1 -1
- package/build/relations/hasOneThrough.js +2 -2
- package/build/relations/hasOneThrough.js.map +1 -1
- package/build/relations/hasProperty.cjs +4 -4
- package/build/relations/hasProperty.cjs.map +1 -1
- package/build/relations/hasProperty.d.cts +2 -2
- package/build/relations/hasProperty.d.mts +2 -2
- package/build/relations/hasProperty.js +2 -2
- package/build/relations/hasProperty.js.map +1 -1
- package/build/relations/index.cjs +10 -10
- package/build/relations/index.js +10 -10
- package/build/relations/isCascadeDelete.cjs.map +1 -1
- package/build/relations/isCascadeDelete.js.map +1 -1
- package/build/resurrection.cjs.map +1 -1
- package/build/resurrection.js.map +1 -1
- package/build/rules.cjs +3 -4
- package/build/rules.cjs.map +1 -1
- package/build/rules.d.cts +1 -1
- package/build/rules.d.mts +1 -1
- package/build/rules.js +3 -4
- package/build/rules.js.map +1 -1
- package/build/runtimeConfig.cjs.map +1 -1
- package/build/runtimeConfig.js.map +1 -1
- package/build/{TypeInfo.cjs → serde/TypeInfo.cjs} +1 -1
- package/build/serde/TypeInfo.cjs.map +1 -0
- package/build/{TypeInfo.d.cts → serde/TypeInfo.d.cts} +2 -2
- package/build/serde/TypeInfo.d.cts.map +1 -0
- package/build/{TypeInfo.d.mts → serde/TypeInfo.d.mts} +2 -2
- package/build/serde/TypeInfo.d.mts.map +1 -0
- package/build/{TypeInfo.js → serde/TypeInfo.js} +1 -1
- package/build/serde/TypeInfo.js.map +1 -0
- package/build/{columns.cjs → serde/columns.cjs} +1 -1
- package/build/serde/columns.cjs.map +1 -0
- package/build/{columns.d.cts → serde/columns.d.cts} +2 -2
- package/build/serde/columns.d.cts.map +1 -0
- package/build/{columns.d.mts → serde/columns.d.mts} +2 -2
- package/build/serde/columns.d.mts.map +1 -0
- package/build/{columns.js → serde/columns.js} +1 -1
- package/build/serde/columns.js.map +1 -0
- package/build/{fieldSerde.cjs → serde/fieldSerde.cjs} +6 -6
- package/build/serde/fieldSerde.cjs.map +1 -0
- package/build/{fieldSerde.d.cts → serde/fieldSerde.d.cts} +5 -5
- package/build/serde/fieldSerde.d.cts.map +1 -0
- package/build/{fieldSerde.d.mts → serde/fieldSerde.d.mts} +5 -5
- package/build/serde/fieldSerde.d.mts.map +1 -0
- package/build/{fieldSerde.js → serde/fieldSerde.js} +6 -6
- package/build/serde/fieldSerde.js.map +1 -0
- package/build/{serde.cjs → serde/serde.cjs} +25 -26
- package/build/serde/serde.cjs.map +1 -0
- package/build/{serde.d.cts → serde/serde.d.cts} +1 -1
- package/build/serde/serde.d.cts.map +1 -0
- package/build/{serde.d.mts → serde/serde.d.mts} +1 -1
- package/build/serde/serde.d.mts.map +1 -0
- package/build/{serde.js → serde/serde.js} +4 -5
- package/build/serde/serde.js.map +1 -0
- package/build/{temporal.cjs → serde/temporal.cjs} +1 -1
- package/build/serde/temporal.cjs.map +1 -0
- package/build/{temporal.d.cts → serde/temporal.d.cts} +1 -1
- package/build/serde/temporal.d.cts.map +1 -0
- package/build/{temporal.d.mts → serde/temporal.d.mts} +1 -1
- package/build/serde/temporal.d.mts.map +1 -0
- package/build/{temporal.js → serde/temporal.js} +1 -1
- package/build/serde/temporal.js.map +1 -0
- package/build/{temporalMappers.cjs → serde/temporalMappers.cjs} +4 -5
- package/build/serde/temporalMappers.cjs.map +1 -0
- package/build/{temporalMappers.d.cts → serde/temporalMappers.d.cts} +1 -1
- package/build/serde/temporalMappers.d.cts.map +1 -0
- package/build/{temporalMappers.d.mts → serde/temporalMappers.d.mts} +1 -1
- package/build/serde/temporalMappers.d.mts.map +1 -0
- package/build/{temporalMappers.js → serde/temporalMappers.js} +2 -3
- package/build/serde/temporalMappers.js.map +1 -0
- package/build/upsert.cjs +1 -1
- package/build/upsert.cjs.map +1 -1
- package/build/upsert.d.cts.map +1 -1
- package/build/upsert.d.mts.map +1 -1
- package/build/upsert.js +1 -1
- package/build/upsert.js.map +1 -1
- package/build/utils.cjs +0 -1
- package/build/utils.cjs.map +1 -1
- package/build/utils.d.cts +1 -1
- package/build/utils.d.mts +1 -1
- package/build/utils.js +0 -1
- package/build/utils.js.map +1 -1
- package/package.json +2 -2
- package/build/FlushLock.cjs.map +0 -1
- package/build/FlushLock.d.cts.map +0 -1
- package/build/FlushLock.d.mts.map +0 -1
- package/build/FlushLock.js.map +0 -1
- package/build/HintTree.cjs.map +0 -1
- package/build/HintTree.d.cts.map +0 -1
- package/build/HintTree.d.mts.map +0 -1
- package/build/HintTree.js.map +0 -1
- package/build/IsLoadedCache.d.cts.map +0 -1
- package/build/IsLoadedCache.d.mts.map +0 -1
- package/build/IsLoadedCache.js.map +0 -1
- package/build/JoinRows.cjs.map +0 -1
- package/build/JoinRows.d.cts.map +0 -1
- package/build/JoinRows.d.mts.map +0 -1
- package/build/JoinRows.js.map +0 -1
- package/build/PendingChanges.d.cts.map +0 -1
- package/build/PendingChanges.d.mts.map +0 -1
- package/build/PendingChanges.js +0 -2
- package/build/ReactionsManager.cjs.map +0 -1
- package/build/ReactionsManager.d.cts.map +0 -1
- package/build/ReactionsManager.d.mts.map +0 -1
- package/build/ReactionsManager.js.map +0 -1
- package/build/Todo.cjs.map +0 -1
- package/build/Todo.d.cts.map +0 -1
- package/build/Todo.d.mts.map +0 -1
- package/build/Todo.js.map +0 -1
- package/build/TypeInfo.cjs.map +0 -1
- package/build/TypeInfo.d.cts.map +0 -1
- package/build/TypeInfo.d.mts.map +0 -1
- package/build/TypeInfo.js.map +0 -1
- package/build/columns.cjs.map +0 -1
- package/build/columns.d.cts.map +0 -1
- package/build/columns.d.mts.map +0 -1
- package/build/columns.js.map +0 -1
- package/build/driverApi.cjs +0 -18
- package/build/driverApi.cjs.map +0 -1
- package/build/driverApi.d.cts +0 -22
- package/build/driverApi.d.cts.map +0 -1
- package/build/driverApi.d.mts +0 -22
- package/build/driverApi.d.mts.map +0 -1
- package/build/driverApi.js +0 -18
- package/build/driverApi.js.map +0 -1
- package/build/fieldSerde.cjs.map +0 -1
- package/build/fieldSerde.d.cts.map +0 -1
- package/build/fieldSerde.d.mts.map +0 -1
- package/build/fieldSerde.js.map +0 -1
- package/build/loadHints.cjs.map +0 -1
- package/build/loadHints.d.cts.map +0 -1
- package/build/loadHints.d.mts.map +0 -1
- package/build/loadHints.js.map +0 -1
- package/build/loadLens.cjs.map +0 -1
- package/build/loadLens.d.cts.map +0 -1
- package/build/loadLens.d.mts.map +0 -1
- package/build/loadLens.js.map +0 -1
- package/build/reactiveHints.cjs.map +0 -1
- package/build/reactiveHints.d.cts.map +0 -1
- package/build/reactiveHints.d.mts.map +0 -1
- package/build/reactiveHints.js.map +0 -1
- package/build/serde.cjs.map +0 -1
- package/build/serde.d.cts.map +0 -1
- package/build/serde.d.mts.map +0 -1
- package/build/serde.js.map +0 -1
- package/build/temporal.cjs.map +0 -1
- package/build/temporal.d.cts.map +0 -1
- package/build/temporal.d.mts.map +0 -1
- package/build/temporal.js.map +0 -1
- package/build/temporalMappers.cjs.map +0 -1
- package/build/temporalMappers.d.cts.map +0 -1
- package/build/temporalMappers.d.mts.map +0 -1
- package/build/temporalMappers.js.map +0 -1
- package/build/unnest.cjs.map +0 -1
- package/build/unnest.d.cts.map +0 -1
- package/build/unnest.d.mts.map +0 -1
- package/build/unnest.js.map +0 -1
- package/build/withLoaded.cjs.map +0 -1
- package/build/withLoaded.d.cts.map +0 -1
- package/build/withLoaded.d.mts.map +0 -1
- package/build/withLoaded.js.map +0 -1
package/build/relations/index.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import { isCollection, isLoadedCollection } from "./Collection.js";
|
|
2
|
+
import { CustomCollection, hasCustomCollection } from "./CustomCollection.js";
|
|
2
3
|
import { EnumCollectionImpl, hasEnumCollection } from "./EnumCollection.js";
|
|
3
|
-
import {
|
|
4
|
-
import { PropertyImpl, hasProperty, hasReactiveProperty, isLoadedProperty, isProperty } from "./hasProperty.js";
|
|
5
|
-
import { LazyFieldImpl, hasLazyField, isLazyField, isLoadedLazyField } from "./LazyField.js";
|
|
6
|
-
import { OneToManyCollection, hasMany } from "./OneToManyCollection.js";
|
|
7
|
-
import { ManyToOneReferenceImpl, hasOne, isManyToOneReference } from "./ManyToOneReference.js";
|
|
8
|
-
import { isLoadedReference, isReference } from "./Reference.js";
|
|
9
|
-
import { ReactiveReferenceImpl, hasReactiveReference, isReactiveReference } from "./ReactiveReference.js";
|
|
10
|
-
import { OneToOneReferenceImpl, hasOneToOne, isLoadedOneToOneReference, isOneToOneReference } from "./OneToOneReference.js";
|
|
4
|
+
import { CustomReference, hasCustomReference } from "./CustomReference.js";
|
|
11
5
|
import { hasReactiveGetter, isReactiveGetter } from "./ReactiveGetter.js";
|
|
12
6
|
import { isRelation } from "./Relation.js";
|
|
13
7
|
import { isLoadedReadOnlyCollection, isReadOnlyCollection } from "./ReadOnlyCollection.js";
|
|
8
|
+
import { RecursiveCycleError } from "./RecursiveCycleError.js";
|
|
14
9
|
import { hasRecursiveChildren, hasRecursiveM2m, hasRecursiveParents } from "./RecursiveCollection.js";
|
|
15
|
-
import { CustomCollection, hasCustomCollection } from "./CustomCollection.js";
|
|
16
|
-
import { CustomReference, hasCustomReference } from "./CustomReference.js";
|
|
17
10
|
import { hasAsyncMethod } from "./hasAsyncMethod.js";
|
|
11
|
+
import { PropertyImpl, hasProperty, hasReactiveProperty, isLoadedProperty, isProperty } from "./hasProperty.js";
|
|
18
12
|
import { AsyncPropertyImpl, hasAsyncProperty, isAsyncProperty, isLoadedAsyncProperty } from "./AsyncProperty.js";
|
|
13
|
+
import { LazyFieldImpl, hasLazyField, isLazyField, isLoadedLazyField } from "./LazyField.js";
|
|
19
14
|
import { hasManyDerived } from "./hasManyDerived.js";
|
|
20
15
|
import { hasManyThrough } from "./hasManyThrough.js";
|
|
16
|
+
import { isLoadedReference, isReference } from "./Reference.js";
|
|
21
17
|
import { hasOneDerived } from "./hasOneDerived.js";
|
|
22
18
|
import { hasOneThrough } from "./hasOneThrough.js";
|
|
23
19
|
import { ManyToManyCollection, hasManyToMany } from "./ManyToManyCollection.js";
|
|
24
20
|
import { ManyToManyLargeCollection, hasLargeManyToMany } from "./ManyToManyLargeCollection.js";
|
|
21
|
+
import { OneToManyCollection, hasMany } from "./OneToManyCollection.js";
|
|
22
|
+
import { ManyToOneReferenceImpl, hasOne, isManyToOneReference } from "./ManyToOneReference.js";
|
|
25
23
|
import { OneToManyLargeCollection, hasLargeMany } from "./OneToManyLargeCollection.js";
|
|
24
|
+
import { ReactiveReferenceImpl, hasReactiveReference, isReactiveReference } from "./ReactiveReference.js";
|
|
25
|
+
import { OneToOneReferenceImpl, hasOneToOne, isLoadedOneToOneReference, isOneToOneReference } from "./OneToOneReference.js";
|
|
26
26
|
import { PolymorphicReferenceImpl, hasOnePolymorphic, isPolymorphicReference } from "./PolymorphicReference.js";
|
|
27
27
|
import { hasReactiveField, isReactiveField } from "./ReactiveField.js";
|
|
28
28
|
import { ReactiveManyToManyImpl, hasReactiveManyToMany, isReactiveManyToMany } from "./ReactiveManyToMany.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isCascadeDelete.cjs","names":["getBaseAndSelfMetas","getMetadata"],"sources":["../../src/relations/isCascadeDelete.ts"],"sourcesContent":["import { getBaseAndSelfMetas, getMetadata } from \"
|
|
1
|
+
{"version":3,"file":"isCascadeDelete.cjs","names":["getBaseAndSelfMetas","getMetadata"],"sources":["../../src/relations/isCascadeDelete.ts"],"sourcesContent":["import { getBaseAndSelfMetas, getMetadata } from \"src/EntityMetadata.ts\";\nimport type { AbstractRelationImpl } from \"src/relations/AbstractRelationImpl.ts\";\n\n// Keep metadata imports out of AbstractRelationImpl so query imports cannot evaluate a relation\n// subclass before its base class has initialized.\n/** Returns whether this relation is configured for cascade deletion on the entity or a base type. */\nexport function isCascadeDelete(relation: AbstractRelationImpl<any, any>, fieldName: string): boolean {\n return getBaseAndSelfMetas(getMetadata(relation.entity)).some((meta) =>\n meta.config.__data.cascadeDeleteFields.includes(fieldName as any),\n );\n}\n"],"mappings":";;;;AAMA,SAAgB,gBAAgB,UAA0C,WAA4B;CACpG,OAAOA,uBAAAA,oBAAoBC,uBAAAA,YAAY,SAAS,MAAM,CAAC,CAAC,CAAC,MAAM,SAC7D,KAAK,OAAO,OAAO,oBAAoB,SAAS,SAAgB,CAClE;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isCascadeDelete.js","names":[],"sources":["../../src/relations/isCascadeDelete.ts"],"sourcesContent":["import { getBaseAndSelfMetas, getMetadata } from \"
|
|
1
|
+
{"version":3,"file":"isCascadeDelete.js","names":[],"sources":["../../src/relations/isCascadeDelete.ts"],"sourcesContent":["import { getBaseAndSelfMetas, getMetadata } from \"src/EntityMetadata.ts\";\nimport type { AbstractRelationImpl } from \"src/relations/AbstractRelationImpl.ts\";\n\n// Keep metadata imports out of AbstractRelationImpl so query imports cannot evaluate a relation\n// subclass before its base class has initialized.\n/** Returns whether this relation is configured for cascade deletion on the entity or a base type. */\nexport function isCascadeDelete(relation: AbstractRelationImpl<any, any>, fieldName: string): boolean {\n return getBaseAndSelfMetas(getMetadata(relation.entity)).some((meta) =>\n meta.config.__data.cascadeDeleteFields.includes(fieldName as any),\n );\n}\n"],"mappings":";;;AAMA,SAAgB,gBAAgB,UAA0C,WAA4B;CACpG,OAAO,oBAAoB,YAAY,SAAS,MAAM,CAAC,CAAC,CAAC,MAAM,SAC7D,KAAK,OAAO,OAAO,oBAAoB,SAAS,SAAgB,CAClE;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resurrection.cjs","names":["getBaseMeta","getMetadata","TooManyError","isEntity"],"sources":["../src/resurrection.ts"],"sourcesContent":["import { type Entity, isEntity } from \"
|
|
1
|
+
{"version":3,"file":"resurrection.cjs","names":["getBaseMeta","getMetadata","TooManyError","isEntity"],"sources":["../src/resurrection.ts"],"sourcesContent":["import { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityManager, type MaybeAbstractEntityConstructor, TooManyError } from \"src/EntityManager.ts\";\nimport { type EntityMetadata, type Field, getBaseMeta, getMetadata } from \"src/EntityMetadata.ts\";\nimport { setField } from \"src/fields.ts\";\n\n/** Clears the soft-delete marker so a matched entity is updated instead of recreated. */\nexport function resurrectIfSoftDeleted(entity: Entity): void {\n const deletedAt = getBaseMeta(getMetadata(entity)).timestampFields?.deletedAt;\n if (deletedAt && (entity as any).isSoftDeletedEntity) {\n setField(entity, deletedAt, undefined);\n }\n}\n\n/**\n * Finds an existing entity when the input fully covers one configured `uniqueBy` candidate.\n * I.e. with `uniqueBy = [[\"email\"], [\"author\", \"title\"]]`, `{ email }` or `{ authorId, title }` can lookup an existing row.\n */\nexport async function findExistingIfUniqueBy<T extends Entity>(\n em: EntityManager<any, any, any>,\n constructor: MaybeAbstractEntityConstructor<T>,\n input: object,\n): Promise<T | undefined> {\n const meta = getMetadata(constructor);\n const candidates = getUniqueByCandidates(meta, input);\n for (const where of candidates) {\n const inMemory = onlySoftDeleted(em.filterEntities(constructor as any, where as any) as T[]);\n if (inMemory.length > 1) {\n throw new TooManyError(`Found more than one existing ${meta.type} with ${whereAsString(where)}`);\n } else if (inMemory.length === 1) {\n resurrectIfSoftDeleted(inMemory[0]);\n return inMemory[0];\n }\n\n // I.e. `{ publisher: newPublisherEntity }` cannot already exist in the database, so skip the `em.find`.\n const hasNewEntityParam = Object.values(where).some((value) => isEntity(value) && value.isNewEntity);\n if (hasNewEntityParam) continue;\n\n const entities = onlySoftDeleted(await (em as any).find(constructor, where, { softDeletes: \"include\" })) as T[];\n if (entities.length > 1) {\n throw new TooManyError(`Found more than one existing ${meta.type} with ${whereAsString(where)}`);\n } else if (entities.length === 1) {\n resurrectIfSoftDeleted(entities[0]);\n return entities[0];\n }\n }\n return undefined;\n}\n\n/** Returns soft-deleted entities that are safe for upsert to resurrect. */\nfunction onlySoftDeleted<T extends Entity>(entities: T[]): T[] {\n return entities.filter(\n (entity) => !entity.isDeletedEntity && (entity as T & { isSoftDeletedEntity?: boolean }).isSoftDeletedEntity,\n );\n}\n\n/** Builds pushdown-safe where clauses from configured identity fields. */\nfunction getUniqueByCandidates(meta: EntityMetadata, input: object): object[] {\n return (meta.uniqueBy ?? getBaseMeta(meta).uniqueBy ?? []).flatMap((fields) => {\n const where: Record<string, unknown> = {};\n for (const fieldName of fields) {\n const field = meta.allFields[fieldName];\n if (!field || !isQueryableIdentityField(field)) return [];\n const value = getIdentityValue(field, input);\n if (value === undefined || value === null) return [];\n where[field.fieldName] = value;\n }\n return [where];\n });\n}\n\n/** Returns the identity value from the input. */\nfunction getIdentityValue(field: Field, input: object): unknown {\n if (Object.hasOwn(input, field.fieldName)) {\n return normalizeIdentityValue((input as Record<string, unknown>)[field.fieldName]);\n }\n if (field.fieldIdName && Object.hasOwn(input, field.fieldIdName)) {\n return normalizeIdentityValue((input as Record<string, unknown>)[field.fieldIdName]);\n }\n return undefined;\n}\n\n/** Returns raw ids from relation inputs, i.e. `{ publisher: { id: \"p:1\" } }` becomes `{ publisher: \"p:1\" }`. */\nfunction normalizeIdentityValue(value: unknown): unknown {\n if (!isEntity(value) && value && typeof value === \"object\" && Object.hasOwn(value, \"id\")) {\n return (value as { id?: unknown }).id;\n }\n return value;\n}\n\n/** Returns true if Joist can push this identity field into a flat find clause. */\nfunction isQueryableIdentityField(field: Field): boolean {\n return field.kind === \"primitive\" || field.kind === \"enum\" || field.kind === \"m2o\" || field.kind === \"poly\";\n}\n\nfunction whereAsString(where: object): string {\n return Object.entries(where)\n .map(([key, value]) => `${key}=${value}`)\n .join(\", \");\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,uBAAuB,QAAsB;CAC3D,MAAM,YAAYA,uBAAAA,YAAYC,uBAAAA,YAAY,MAAM,CAAC,CAAC,CAAC,iBAAiB;CACpE,IAAI,aAAc,OAAe,qBAC/B,eAAA,SAAS,QAAQ,WAAW,KAAA,CAAS;AAEzC;;;;;AAMA,eAAsB,uBACpB,IACA,aACA,OACwB;CACxB,MAAM,OAAOA,uBAAAA,YAAY,WAAW;CACpC,MAAM,aAAa,sBAAsB,MAAM,KAAK;CACpD,KAAK,MAAM,SAAS,YAAY;EAC9B,MAAM,WAAW,gBAAgB,GAAG,eAAe,aAAoB,KAAY,CAAQ;EAC3F,IAAI,SAAS,SAAS,GACpB,MAAM,IAAIC,sBAAAA,aAAa,gCAAgC,KAAK,KAAK,QAAQ,cAAc,KAAK,GAAG;OAC1F,IAAI,SAAS,WAAW,GAAG;GAChC,uBAAuB,SAAS,EAAE;GAClC,OAAO,SAAS;EAClB;EAIA,IAD0B,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,UAAUC,eAAAA,SAAS,KAAK,KAAK,MAAM,WACpE,GAAG;EAEvB,MAAM,WAAW,gBAAgB,MAAO,GAAW,KAAK,aAAa,OAAO,EAAE,aAAa,UAAU,CAAC,CAAC;EACvG,IAAI,SAAS,SAAS,GACpB,MAAM,IAAID,sBAAAA,aAAa,gCAAgC,KAAK,KAAK,QAAQ,cAAc,KAAK,GAAG;OAC1F,IAAI,SAAS,WAAW,GAAG;GAChC,uBAAuB,SAAS,EAAE;GAClC,OAAO,SAAS;EAClB;CACF;AAEF;;AAGA,SAAS,gBAAkC,UAAoB;CAC7D,OAAO,SAAS,QACb,WAAW,CAAC,OAAO,mBAAoB,OAAiD,mBAC3F;AACF;;AAGA,SAAS,sBAAsB,MAAsB,OAAyB;CAC5E,QAAQ,KAAK,YAAYF,uBAAAA,YAAY,IAAI,CAAC,CAAC,YAAY,CAAC,EAAA,CAAG,SAAS,WAAW;EAC7E,MAAM,QAAiC,CAAC;EACxC,KAAK,MAAM,aAAa,QAAQ;GAC9B,MAAM,QAAQ,KAAK,UAAU;GAC7B,IAAI,CAAC,SAAS,CAAC,yBAAyB,KAAK,GAAG,OAAO,CAAC;GACxD,MAAM,QAAQ,iBAAiB,OAAO,KAAK;GAC3C,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,CAAC;GACnD,MAAM,MAAM,aAAa;EAC3B;EACA,OAAO,CAAC,KAAK;CACf,CAAC;AACH;;AAGA,SAAS,iBAAiB,OAAc,OAAwB;CAC9D,IAAI,OAAO,OAAO,OAAO,MAAM,SAAS,GACtC,OAAO,uBAAwB,MAAkC,MAAM,UAAU;CAEnF,IAAI,MAAM,eAAe,OAAO,OAAO,OAAO,MAAM,WAAW,GAC7D,OAAO,uBAAwB,MAAkC,MAAM,YAAY;AAGvF;;AAGA,SAAS,uBAAuB,OAAyB;CACvD,IAAI,CAACG,eAAAA,SAAS,KAAK,KAAK,SAAS,OAAO,UAAU,YAAY,OAAO,OAAO,OAAO,IAAI,GACrF,OAAQ,MAA2B;CAErC,OAAO;AACT;;AAGA,SAAS,yBAAyB,OAAuB;CACvD,OAAO,MAAM,SAAS,eAAe,MAAM,SAAS,UAAU,MAAM,SAAS,SAAS,MAAM,SAAS;AACvG;AAEA,SAAS,cAAc,OAAuB;CAC5C,OAAO,OAAO,QAAQ,KAAK,CAAC,CACzB,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,CACxC,KAAK,IAAI;AACd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resurrection.js","names":[],"sources":["../src/resurrection.ts"],"sourcesContent":["import { type Entity, isEntity } from \"
|
|
1
|
+
{"version":3,"file":"resurrection.js","names":[],"sources":["../src/resurrection.ts"],"sourcesContent":["import { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityManager, type MaybeAbstractEntityConstructor, TooManyError } from \"src/EntityManager.ts\";\nimport { type EntityMetadata, type Field, getBaseMeta, getMetadata } from \"src/EntityMetadata.ts\";\nimport { setField } from \"src/fields.ts\";\n\n/** Clears the soft-delete marker so a matched entity is updated instead of recreated. */\nexport function resurrectIfSoftDeleted(entity: Entity): void {\n const deletedAt = getBaseMeta(getMetadata(entity)).timestampFields?.deletedAt;\n if (deletedAt && (entity as any).isSoftDeletedEntity) {\n setField(entity, deletedAt, undefined);\n }\n}\n\n/**\n * Finds an existing entity when the input fully covers one configured `uniqueBy` candidate.\n * I.e. with `uniqueBy = [[\"email\"], [\"author\", \"title\"]]`, `{ email }` or `{ authorId, title }` can lookup an existing row.\n */\nexport async function findExistingIfUniqueBy<T extends Entity>(\n em: EntityManager<any, any, any>,\n constructor: MaybeAbstractEntityConstructor<T>,\n input: object,\n): Promise<T | undefined> {\n const meta = getMetadata(constructor);\n const candidates = getUniqueByCandidates(meta, input);\n for (const where of candidates) {\n const inMemory = onlySoftDeleted(em.filterEntities(constructor as any, where as any) as T[]);\n if (inMemory.length > 1) {\n throw new TooManyError(`Found more than one existing ${meta.type} with ${whereAsString(where)}`);\n } else if (inMemory.length === 1) {\n resurrectIfSoftDeleted(inMemory[0]);\n return inMemory[0];\n }\n\n // I.e. `{ publisher: newPublisherEntity }` cannot already exist in the database, so skip the `em.find`.\n const hasNewEntityParam = Object.values(where).some((value) => isEntity(value) && value.isNewEntity);\n if (hasNewEntityParam) continue;\n\n const entities = onlySoftDeleted(await (em as any).find(constructor, where, { softDeletes: \"include\" })) as T[];\n if (entities.length > 1) {\n throw new TooManyError(`Found more than one existing ${meta.type} with ${whereAsString(where)}`);\n } else if (entities.length === 1) {\n resurrectIfSoftDeleted(entities[0]);\n return entities[0];\n }\n }\n return undefined;\n}\n\n/** Returns soft-deleted entities that are safe for upsert to resurrect. */\nfunction onlySoftDeleted<T extends Entity>(entities: T[]): T[] {\n return entities.filter(\n (entity) => !entity.isDeletedEntity && (entity as T & { isSoftDeletedEntity?: boolean }).isSoftDeletedEntity,\n );\n}\n\n/** Builds pushdown-safe where clauses from configured identity fields. */\nfunction getUniqueByCandidates(meta: EntityMetadata, input: object): object[] {\n return (meta.uniqueBy ?? getBaseMeta(meta).uniqueBy ?? []).flatMap((fields) => {\n const where: Record<string, unknown> = {};\n for (const fieldName of fields) {\n const field = meta.allFields[fieldName];\n if (!field || !isQueryableIdentityField(field)) return [];\n const value = getIdentityValue(field, input);\n if (value === undefined || value === null) return [];\n where[field.fieldName] = value;\n }\n return [where];\n });\n}\n\n/** Returns the identity value from the input. */\nfunction getIdentityValue(field: Field, input: object): unknown {\n if (Object.hasOwn(input, field.fieldName)) {\n return normalizeIdentityValue((input as Record<string, unknown>)[field.fieldName]);\n }\n if (field.fieldIdName && Object.hasOwn(input, field.fieldIdName)) {\n return normalizeIdentityValue((input as Record<string, unknown>)[field.fieldIdName]);\n }\n return undefined;\n}\n\n/** Returns raw ids from relation inputs, i.e. `{ publisher: { id: \"p:1\" } }` becomes `{ publisher: \"p:1\" }`. */\nfunction normalizeIdentityValue(value: unknown): unknown {\n if (!isEntity(value) && value && typeof value === \"object\" && Object.hasOwn(value, \"id\")) {\n return (value as { id?: unknown }).id;\n }\n return value;\n}\n\n/** Returns true if Joist can push this identity field into a flat find clause. */\nfunction isQueryableIdentityField(field: Field): boolean {\n return field.kind === \"primitive\" || field.kind === \"enum\" || field.kind === \"m2o\" || field.kind === \"poly\";\n}\n\nfunction whereAsString(where: object): string {\n return Object.entries(where)\n .map(([key, value]) => `${key}=${value}`)\n .join(\", \");\n}\n"],"mappings":";;;;;;AAMA,SAAgB,uBAAuB,QAAsB;CAC3D,MAAM,YAAY,YAAY,YAAY,MAAM,CAAC,CAAC,CAAC,iBAAiB;CACpE,IAAI,aAAc,OAAe,qBAC/B,SAAS,QAAQ,WAAW,KAAA,CAAS;AAEzC;;;;;AAMA,eAAsB,uBACpB,IACA,aACA,OACwB;CACxB,MAAM,OAAO,YAAY,WAAW;CACpC,MAAM,aAAa,sBAAsB,MAAM,KAAK;CACpD,KAAK,MAAM,SAAS,YAAY;EAC9B,MAAM,WAAW,gBAAgB,GAAG,eAAe,aAAoB,KAAY,CAAQ;EAC3F,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,aAAa,gCAAgC,KAAK,KAAK,QAAQ,cAAc,KAAK,GAAG;OAC1F,IAAI,SAAS,WAAW,GAAG;GAChC,uBAAuB,SAAS,EAAE;GAClC,OAAO,SAAS;EAClB;EAIA,IAD0B,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,UAAU,SAAS,KAAK,KAAK,MAAM,WACpE,GAAG;EAEvB,MAAM,WAAW,gBAAgB,MAAO,GAAW,KAAK,aAAa,OAAO,EAAE,aAAa,UAAU,CAAC,CAAC;EACvG,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,aAAa,gCAAgC,KAAK,KAAK,QAAQ,cAAc,KAAK,GAAG;OAC1F,IAAI,SAAS,WAAW,GAAG;GAChC,uBAAuB,SAAS,EAAE;GAClC,OAAO,SAAS;EAClB;CACF;AAEF;;AAGA,SAAS,gBAAkC,UAAoB;CAC7D,OAAO,SAAS,QACb,WAAW,CAAC,OAAO,mBAAoB,OAAiD,mBAC3F;AACF;;AAGA,SAAS,sBAAsB,MAAsB,OAAyB;CAC5E,QAAQ,KAAK,YAAY,YAAY,IAAI,CAAC,CAAC,YAAY,CAAC,EAAA,CAAG,SAAS,WAAW;EAC7E,MAAM,QAAiC,CAAC;EACxC,KAAK,MAAM,aAAa,QAAQ;GAC9B,MAAM,QAAQ,KAAK,UAAU;GAC7B,IAAI,CAAC,SAAS,CAAC,yBAAyB,KAAK,GAAG,OAAO,CAAC;GACxD,MAAM,QAAQ,iBAAiB,OAAO,KAAK;GAC3C,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,CAAC;GACnD,MAAM,MAAM,aAAa;EAC3B;EACA,OAAO,CAAC,KAAK;CACf,CAAC;AACH;;AAGA,SAAS,iBAAiB,OAAc,OAAwB;CAC9D,IAAI,OAAO,OAAO,OAAO,MAAM,SAAS,GACtC,OAAO,uBAAwB,MAAkC,MAAM,UAAU;CAEnF,IAAI,MAAM,eAAe,OAAO,OAAO,OAAO,MAAM,WAAW,GAC7D,OAAO,uBAAwB,MAAkC,MAAM,YAAY;AAGvF;;AAGA,SAAS,uBAAuB,OAAyB;CACvD,IAAI,CAAC,SAAS,KAAK,KAAK,SAAS,OAAO,UAAU,YAAY,OAAO,OAAO,OAAO,IAAI,GACrF,OAAQ,MAA2B;CAErC,OAAO;AACT;;AAGA,SAAS,yBAAyB,OAAuB;CACvD,OAAO,MAAM,SAAS,eAAe,MAAM,SAAS,UAAU,MAAM,SAAS,SAAS,MAAM,SAAS;AACvG;AAEA,SAAS,cAAc,OAAuB;CAC5C,OAAO,OAAO,QAAQ,KAAK,CAAC,CACzB,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,CACxC,KAAK,IAAI;AACd"}
|
package/build/rules.cjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_fields = require("./fields.cjs");
|
|
3
|
-
require("./typeMap.cjs");
|
|
4
|
-
require("./changes.cjs");
|
|
5
3
|
const require_relations_Reference = require("./relations/Reference.cjs");
|
|
6
|
-
require("./reactiveHints.cjs");
|
|
7
|
-
const require_utils = require("./utils.cjs");
|
|
8
4
|
const require_relations_AsyncReactiveField = require("./relations/AsyncReactiveField.cjs");
|
|
9
5
|
require("./relations/index.cjs");
|
|
6
|
+
const require_utils = require("./utils.cjs");
|
|
7
|
+
require("./typeMap.cjs");
|
|
8
|
+
require("./changes.cjs");
|
|
10
9
|
const require_EntityManager = require("./EntityManager.cjs");
|
|
11
10
|
require("./Entity.cjs");
|
|
12
11
|
//#region src/rules.ts
|
package/build/rules.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.cjs","names":["groupBy","maybePromiseThen","getField","isAsyncReactiveField","isLoadedReference","getEmInternalApi"],"sources":["../src/rules.ts"],"sourcesContent":["import { type Changes, type EntityChanges } from \"./changes.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { getEmInternalApi } from \"./EntityManager.ts\";\nimport { getField } from \"./fields.ts\";\nimport { type ReactiveHint } from \"./reactiveHints.ts\";\nimport { type ManyToOneReferenceImpl, isAsyncReactiveField, isLoadedReference } from \"./relations/index.ts\";\nimport { type FieldsOf } from \"./typeMap.ts\";\nimport { type MaybePromise, groupBy, maybePromiseThen } from \"./utils.ts\";\n\nexport enum ValidationCode {\n required = \"required\",\n cannotBeUpdated = \"not-updatable\",\n cannotBeChanged = \"not-changeable\",\n numeric = \"not-numeric\",\n minValue = \"under-min\",\n maxValue = \"over-max\",\n}\n\n/**\n * The return type of `ValidationRule` lambdas.\n *\n * We're flexible and allow rules to return a variety of shapes, like just a string, string[], etc.\n *\n * Returning `undefined` means the rule passed.\n */\nexport type ValidationRuleResult = string | string[] | GenericError | GenericError[] | undefined | void;\n\n/** An entity validation rule. */\nexport type ValidationRule<T extends Entity> = (entity: T) => MaybePromise<ValidationRuleResult>;\n\n/** Internal metadata for an async/reactive validation rule. */\nexport type ValidationRuleInternal<T extends Entity> = {\n name: string;\n hint: ReactiveHint<T> | undefined;\n fn: ValidationRule<T>;\n};\n\n/** A generic error which contains a message, and optional field/codes. */\nexport type GenericError = { message: string; field?: string; code?: string };\n\n/** Combines the GenericError with the `entity` that caused it. */\nexport type ValidationError = { entity: Entity } & GenericError;\n\nexport type ValidationRuleOptsFn<T extends Entity> = (entity: T) => MaybePromise<boolean>;\nexport type ValidationRuleOpts<T extends Entity> = {\n unless?: ValidationRuleOptsFn<T>;\n if?: ValidationRuleOptsFn<T>;\n};\n\nfunction errorMessage(errors: ValidationError[]): string {\n if (errors.length === 1) {\n return `Validation error: ${errors[0].entity.toString()} ${errors[0].message}`;\n } else {\n const message = [...groupBy(errors, (e) => e.entity.toString()).entries()]\n .map(([entityToString, errors]) => `${entityToString} ${errors.map((e) => e.message).join(\", \")}`)\n .join(\", \");\n return `Validation errors (${errors.length}): ${message}`;\n }\n}\n\nexport class ValidationErrors extends Error {\n public errors: Array<GenericError | ValidationError>;\n public readonly toJSON: () => string;\n constructor(errors: ValidationError[]);\n constructor(message: string);\n constructor(messageOrErrors: ValidationError[] | string) {\n super(typeof messageOrErrors === \"string\" ? messageOrErrors : errorMessage(messageOrErrors));\n this.errors = typeof messageOrErrors === \"string\" ? [{ message: messageOrErrors }] : messageOrErrors;\n // Jest clones without prototype, so explictly setting this as a property rather than a class method\n // https://github.com/jestjs/jest/issues/11958\n this.toJSON = () => `ValidationErrors: ${this.message}`;\n }\n}\n\nfunction ruleWithOpts<T extends Entity>(\n opts: ValidationRuleOpts<T> | undefined,\n fn: (entity: T) => ValidationRuleResult,\n): ValidationRule<T> {\n return (entity) => {\n // Since all of our rules are sync, we run the rule first, then check if we should have run it second since this\n // may be an async operation. This way we can avoid running promises if we don't have to.\n const result = fn(entity);\n if (result === undefined) return;\n const { unless, if: _if } = opts ?? {};\n if (unless === undefined && _if === undefined) return result;\n const shouldRun = [unless ?? (() => false), _if ?? (() => true)].map((fn) => fn(entity));\n return maybePromiseThen(\n shouldRun.some((r) => r instanceof Promise) ? Promise.all(shouldRun) : (shouldRun as boolean[]),\n ([unless, _if]) => (!unless && _if ? result : undefined),\n );\n };\n}\n\n/**\n * The fields of `F` that have their own column, i.e. what a required rule can check.\n *\n * The filter is an allow-list (\"keep kinds primitive/enum/m2o/poly\"), not a deny-list (\"drop kind\n * o2o\"), because of how it degrades when `T` is generic/uninferred: `FieldsOf<T>` is then `never`,\n * and `never extends X` is true for any `X`, so an allow-list keeps every key (permissive, exactly\n * like the unfiltered `keyof FieldsOf<T>` before it) while a deny-list would drop every key and\n * break valid calls like `newRequiredRule(\"city\")`.\n */\ntype ColumnBackedFields<F> = {\n [K in keyof F as F[K] extends { kind: \"primitive\" | \"enum\" | \"m2o\" | \"poly\" } ? K : never]: F[K];\n};\n\n/**\n * Creates a validation rule for required fields.\n *\n * This is added automatically by codegen to entities based on FK not-nulls.\n */\nexport function newRequiredRule<T extends Entity>(\n key: keyof ColumnBackedFields<FieldsOf<T>> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Use getField so that we peer through relations\n if (getField(entity, key) === undefined) {\n // Sanity check for AsyncReactiveFields--this should be cheap to just always do; alternatively we could\n // have a RQF-specific `rqfRequiredRule` so that other `newRequiredRule` users don't pay the cost of these\n // two `if` checks`.\n if (entity.isNewEntity && isAsyncReactiveField((entity as any)[key])) {\n throw new Error(\n `AsyncReactiveField ${entity.constructor.name}.${key} must have a default value, either in the database or with config.setDefault (see the 4th step in https://joist-orm.io/modeling/reactive-fields/#async-reactive-fields.`,\n );\n }\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Like `newRequiredRule`, but for `lazy` columns (i.e. codegen only wires this up for `lazy` fields).\n *\n * On an already-persisted entity that hasn't loaded the column, we skip the check rather than force-load\n * (or falsely fail) a value that was required when the row was last saved. It still fires on create and\n * when the field is explicitly loaded-then-unset.\n */\nexport function newRequiredLazyFieldRule<T extends Entity>(\n key: keyof FieldsOf<T> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n if (!entity.isNewEntity && !(entity as any)[key].isLoaded) return;\n if (getField(entity, key) === undefined) {\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Creates a validation rule that a field cannot be updated; it can only be set on creation.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n unless?: ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n optsOrUnless?: ValidationRuleOpts<T> | ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T> {\n const opts = typeof optsOrUnless === \"function\" ? { unless: optsOrUnless } : (optsOrUnless ?? {});\n const fn = ruleWithOpts(opts, (entity: T) => {\n // For now putting the `EntityChanges` cast here to avoid breaking cannotBeUpdated rules\n // on base types, see Publisher.ts's `cannotBeUpdated(\"type\")` repro.\n if ((entity as any as EntityChanges<T>).changes[field].hasUpdated) {\n const value = (entity as any)[field];\n // If we're being changed b/c of an em.merge, that is okay\n if (isLoadedReference(value) && getEmInternalApi(entity.em).isMerging(value.get)) return;\n return { field, code: ValidationCode.cannotBeUpdated, message: `${field} cannot be updated` };\n }\n return;\n });\n return Object.assign(fn, { field, immutable: opts.unless === undefined && opts.if === undefined });\n}\n\n/**\n * Creates a validation rule that a field cannot be changed once set.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeChanged<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity: T) => {\n const changes = (entity as any as EntityChanges<T>).changes[field];\n if (changes.kind === \"m2m\" || changes.kind === \"o2m\" || changes.kind === \"m2mEnum\") {\n throw new Error(\"cannotBeChanged is only supported on primitive & m2o fields\");\n } else if (changes.hasUpdated) {\n const originalValue = changes.originalValue;\n if (originalValue === undefined) return;\n const value = getField(entity, field);\n if (getEmInternalApi(entity.em).isMerging(value)) return;\n return { field, code: ValidationCode.cannotBeChanged, message: `${field} cannot be changed` };\n }\n return;\n });\n}\n\ntype CannotBeUpdatedRule<T extends Entity> = ValidationRule<T> & { field: string; immutable: boolean };\n\nexport function isCannotBeUpdatedRule(rule: Function): rule is CannotBeUpdatedRule<any> {\n return \"field\" in rule && \"immutable\" in rule;\n}\n\n/** For STI, enforces subtype-specific relations/FKs at runtime. */\nexport function mustBeSubType<T extends Entity, K extends keyof Changes<T> & string>(\n relationName: K,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const m2o = (entity as any)[relationName] as ManyToOneReferenceImpl<any, any, any>;\n const other = m2o.get;\n const otherCstr = m2o.otherMeta.cstr;\n if (other && !(other instanceof otherCstr)) {\n return `${relationName} must be a ${otherCstr.name} not ${other}`;\n }\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be smaller than a\n * certain value.\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 range is [0, Infinity]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be smaller than 0\n * config.addRule(minValueRule(\"age\", 0));\n */\nexport function minValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value < minValue) {\n return {\n field,\n code: ValidationCode.minValue,\n message: `${field} must be greater than or equal to ${minValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be greater than a\n * certain value.\n *\n * @param field The field to validate\n * @param maxValue The include maximum value. e.g 10 range is [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be greater than 150\n * config.addRule(maxValueRule(\"age\", 150));\n */\nexport function maxValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value > maxValue) {\n return {\n field,\n code: ValidationCode.maxValue,\n message: `${field} must be smaller than or equal to ${maxValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value must be within a range of\n * certain values\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 [0, Infinity]\n * @param maxValue The include maximum value. e.g 10 [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation * @example\n *\n * // Age must be between 0 and 150\n * config.addRule(rangeValueRule(\"age\", 0, 150));\n */\nexport function rangeValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Check min and max value rules. Because these are called without opts, it should be safe to treat them as sync.\n const minValueResult = minValueRule<T, K>(field, minValue)(entity) as ValidationRuleResult;\n const maxValueResult = maxValueRule<T, K>(field, maxValue)(entity) as ValidationRuleResult;\n // Return any errors or nothing\n if (minValueResult) return minValueResult;\n if (maxValueResult) return maxValueResult;\n return;\n });\n}\n"],"mappings":";;;;;;;;;;;;AASA,IAAY,iBAAL,yBAAA,gBAAA;CACL,eAAA,cAAA;CACA,eAAA,qBAAA;CACA,eAAA,qBAAA;CACA,eAAA,aAAA;CACA,eAAA,cAAA;CACA,eAAA,cAAA;;AACF,EAAA,CAAA,CAAA;AAiCA,SAAS,aAAa,QAAmC;CACvD,IAAI,OAAO,WAAW,GACpB,OAAO,qBAAqB,OAAO,EAAE,CAAC,OAAO,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC;MAChE;EACL,MAAM,UAAU,CAAC,GAAGA,cAAAA,QAAQ,SAAS,MAAM,EAAE,OAAO,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CACvE,KAAK,CAAC,gBAAgB,YAAY,GAAG,eAAe,GAAG,OAAO,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CACjG,KAAK,IAAI;EACZ,OAAO,sBAAsB,OAAO,OAAO,KAAK;CAClD;AACF;AAEA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CACA;CAGA,YAAY,iBAA6C;EACvD,MAAM,OAAO,oBAAoB,WAAW,kBAAkB,aAAa,eAAe,CAAC;EAC3F,KAAK,SAAS,OAAO,oBAAoB,WAAW,CAAC,EAAE,SAAS,gBAAgB,CAAC,IAAI;EAGrF,KAAK,eAAe,qBAAqB,KAAK;CAChD;AACF;AAEA,SAAS,aACP,MACA,IACmB;CACnB,QAAQ,WAAW;EAGjB,MAAM,SAAS,GAAG,MAAM;EACxB,IAAI,WAAW,KAAA,GAAW;EAC1B,MAAM,EAAE,QAAQ,IAAI,QAAQ,QAAQ,CAAC;EACrC,IAAI,WAAW,KAAA,KAAa,QAAQ,KAAA,GAAW,OAAO;EACtD,MAAM,YAAY,CAAC,iBAAiB,QAAQ,cAAc,KAAK,CAAC,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC;EACvF,OAAOC,cAAAA,iBACL,UAAU,MAAM,MAAM,aAAa,OAAO,IAAI,QAAQ,IAAI,SAAS,IAAK,YACvE,CAAC,QAAQ,SAAU,CAAC,UAAU,MAAM,SAAS,KAAA,CAChD;CACF;AACF;;;;;;AAoBA,SAAgB,gBACd,KACA,OAA8B,CAAC,GACZ;CACnB,OAAO,aAAa,OAAO,WAAW;EAEpC,IAAIC,eAAAA,SAAS,QAAQ,GAAG,MAAM,KAAA,GAAW;GAIvC,IAAI,OAAO,eAAeC,qCAAAA,qBAAsB,OAAe,IAAI,GACjE,MAAM,IAAI,MACR,sBAAsB,OAAO,YAAY,KAAK,GAAG,IAAI,wKACvD;GAEF,OAAO;IAAE,OAAO;IAAK,MAAA;IAA+B,SAAS,GAAG,IAAI;GAAc;EACpF;CACF,CAAC;AACH;;;;;;;;AASA,SAAgB,yBACd,KACA,OAA8B,CAAC,GACZ;CACnB,OAAO,aAAa,OAAO,WAAW;EACpC,IAAI,CAAC,OAAO,eAAe,CAAE,OAAe,IAAI,CAAC,UAAU;EAC3D,IAAID,eAAAA,SAAS,QAAQ,GAAG,MAAM,KAAA,GAC5B,OAAO;GAAE,OAAO;GAAK,MAAA;GAA+B,SAAS,GAAG,IAAI;EAAc;CAEtF,CAAC;AACH;AAeA,SAAgB,gBACd,OACA,cACwB;CACxB,MAAM,OAAO,OAAO,iBAAiB,aAAa,EAAE,QAAQ,aAAa,IAAK,gBAAgB,CAAC;CAC/F,MAAM,KAAK,aAAa,OAAO,WAAc;EAG3C,IAAK,OAAmC,QAAQ,MAAM,CAAC,YAAY;GACjE,MAAM,QAAS,OAAe;GAE9B,IAAIE,4BAAAA,kBAAkB,KAAK,KAAKC,sBAAAA,iBAAiB,OAAO,EAAE,CAAC,CAAC,UAAU,MAAM,GAAG,GAAG;GAClF,OAAO;IAAE;IAAO,MAAA;IAAsC,SAAS,GAAG,MAAM;GAAoB;EAC9F;CAEF,CAAC;CACD,OAAO,OAAO,OAAO,IAAI;EAAE;EAAO,WAAW,KAAK,WAAW,KAAA,KAAa,KAAK,OAAO,KAAA;CAAU,CAAC;AACnG;;;;;;AAOA,SAAgB,gBACd,OACA,MACmB;CACnB,OAAO,aAAa,OAAO,WAAc;EACvC,MAAM,UAAW,OAAmC,QAAQ;EAC5D,IAAI,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAAQ,SAAS,WACvE,MAAM,IAAI,MAAM,6DAA6D;OACxE,IAAI,QAAQ,YAAY;GAE7B,IADsB,QAAQ,kBACR,KAAA,GAAW;GACjC,MAAM,QAAQH,eAAAA,SAAS,QAAQ,KAAK;GACpC,IAAIG,sBAAAA,iBAAiB,OAAO,EAAE,CAAC,CAAC,UAAU,KAAK,GAAG;GAClD,OAAO;IAAE;IAAO,MAAA;IAAsC,SAAS,GAAG,MAAM;GAAoB;EAC9F;CAEF,CAAC;AACH;AAIA,SAAgB,sBAAsB,MAAkD;CACtF,OAAO,WAAW,QAAQ,eAAe;AAC3C;;AAGA,SAAgB,cACd,cACA,OAA8B,CAAC,GACZ;CACnB,OAAO,aAAa,OAAO,WAAW;EACpC,MAAM,MAAO,OAAe;EAC5B,MAAM,QAAQ,IAAI;EAClB,MAAM,YAAY,IAAI,UAAU;EAChC,IAAI,SAAS,EAAE,iBAAiB,YAC9B,OAAO,GAAG,aAAa,aAAa,UAAU,KAAK,OAAO;CAE9D,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAgB,aACd,OACA,UACA,OAA8B,CAAC,GACZ;CACnB,OAAO,aAAa,OAAO,WAAW;EACpC,MAAM,QAAQ,OAAO;EAErB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM;EAE3C,IAAI,OAAO,UAAU,UACnB,OAAO;GAAE;GAAO,MAAA;GAA8B,SAAS,GAAG,MAAM;EAAmB;EAGrF,IAAI,QAAQ,UACV,OAAO;GACL;GACA,MAAA;GACA,SAAS,GAAG,MAAM,oCAAoC;EACxD;CAGJ,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAgB,aACd,OACA,UACA,OAA8B,CAAC,GACZ;CACnB,OAAO,aAAa,OAAO,WAAW;EACpC,MAAM,QAAQ,OAAO;EAErB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM;EAE3C,IAAI,OAAO,UAAU,UACnB,OAAO;GAAE;GAAO,MAAA;GAA8B,SAAS,GAAG,MAAM;EAAmB;EAGrF,IAAI,QAAQ,UACV,OAAO;GACL;GACA,MAAA;GACA,SAAS,GAAG,MAAM,oCAAoC;EACxD;CAGJ,CAAC;AACH;;;;;;;;;;;;;;;AAgBA,SAAgB,eACd,OACA,UACA,UACA,OAA8B,CAAC,GACZ;CACnB,OAAO,aAAa,OAAO,WAAW;EAEpC,MAAM,iBAAiB,aAAmB,OAAO,QAAQ,CAAC,CAAC,MAAM;EACjE,MAAM,iBAAiB,aAAmB,OAAO,QAAQ,CAAC,CAAC,MAAM;EAEjE,IAAI,gBAAgB,OAAO;EAC3B,IAAI,gBAAgB,OAAO;CAE7B,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"rules.cjs","names":["groupBy","maybePromiseThen","getField","isAsyncReactiveField","isLoadedReference","getEmInternalApi"],"sources":["../src/rules.ts"],"sourcesContent":["import { type Changes, type EntityChanges } from \"src/changes.ts\";\nimport { type Entity } from \"src/Entity.ts\";\nimport { getEmInternalApi } from \"src/EntityManager.ts\";\nimport { getField } from \"src/fields.ts\";\nimport type { ReactiveHint } from \"src/reactivity/reactiveHints.ts\";\nimport { type ManyToOneReferenceImpl, isAsyncReactiveField, isLoadedReference } from \"src/relations/index.ts\";\nimport { type FieldsOf } from \"src/typeMap.ts\";\nimport { type MaybePromise, groupBy, maybePromiseThen } from \"src/utils.ts\";\n\nexport enum ValidationCode {\n required = \"required\",\n cannotBeUpdated = \"not-updatable\",\n cannotBeChanged = \"not-changeable\",\n numeric = \"not-numeric\",\n minValue = \"under-min\",\n maxValue = \"over-max\",\n}\n\n/**\n * The return type of `ValidationRule` lambdas.\n *\n * We're flexible and allow rules to return a variety of shapes, like just a string, string[], etc.\n *\n * Returning `undefined` means the rule passed.\n */\nexport type ValidationRuleResult = string | string[] | GenericError | GenericError[] | undefined | void;\n\n/** An entity validation rule. */\nexport type ValidationRule<T extends Entity> = (entity: T) => MaybePromise<ValidationRuleResult>;\n\n/** Internal metadata for an async/reactive validation rule. */\nexport type ValidationRuleInternal<T extends Entity> = {\n name: string;\n hint: ReactiveHint<T> | undefined;\n fn: ValidationRule<T>;\n};\n\n/** A generic error which contains a message, and optional field/codes. */\nexport type GenericError = { message: string; field?: string; code?: string };\n\n/** Combines the GenericError with the `entity` that caused it. */\nexport type ValidationError = { entity: Entity } & GenericError;\n\nexport type ValidationRuleOptsFn<T extends Entity> = (entity: T) => MaybePromise<boolean>;\nexport type ValidationRuleOpts<T extends Entity> = {\n unless?: ValidationRuleOptsFn<T>;\n if?: ValidationRuleOptsFn<T>;\n};\n\nfunction errorMessage(errors: ValidationError[]): string {\n if (errors.length === 1) {\n return `Validation error: ${errors[0].entity.toString()} ${errors[0].message}`;\n } else {\n const message = [...groupBy(errors, (e) => e.entity.toString()).entries()]\n .map(([entityToString, errors]) => `${entityToString} ${errors.map((e) => e.message).join(\", \")}`)\n .join(\", \");\n return `Validation errors (${errors.length}): ${message}`;\n }\n}\n\nexport class ValidationErrors extends Error {\n public errors: Array<GenericError | ValidationError>;\n public readonly toJSON: () => string;\n constructor(errors: ValidationError[]);\n constructor(message: string);\n constructor(messageOrErrors: ValidationError[] | string) {\n super(typeof messageOrErrors === \"string\" ? messageOrErrors : errorMessage(messageOrErrors));\n this.errors = typeof messageOrErrors === \"string\" ? [{ message: messageOrErrors }] : messageOrErrors;\n // Jest clones without prototype, so explictly setting this as a property rather than a class method\n // https://github.com/jestjs/jest/issues/11958\n this.toJSON = () => `ValidationErrors: ${this.message}`;\n }\n}\n\nfunction ruleWithOpts<T extends Entity>(\n opts: ValidationRuleOpts<T> | undefined,\n fn: (entity: T) => ValidationRuleResult,\n): ValidationRule<T> {\n return (entity) => {\n // Since all of our rules are sync, we run the rule first, then check if we should have run it second since this\n // may be an async operation. This way we can avoid running promises if we don't have to.\n const result = fn(entity);\n if (result === undefined) return;\n const { unless, if: _if } = opts ?? {};\n if (unless === undefined && _if === undefined) return result;\n const shouldRun = [unless ?? (() => false), _if ?? (() => true)].map((fn) => fn(entity));\n return maybePromiseThen(\n shouldRun.some((r) => r instanceof Promise) ? Promise.all(shouldRun) : (shouldRun as boolean[]),\n ([unless, _if]) => (!unless && _if ? result : undefined),\n );\n };\n}\n\n/**\n * The fields of `F` that have their own column, i.e. what a required rule can check.\n *\n * The filter is an allow-list (\"keep kinds primitive/enum/m2o/poly\"), not a deny-list (\"drop kind\n * o2o\"), because of how it degrades when `T` is generic/uninferred: `FieldsOf<T>` is then `never`,\n * and `never extends X` is true for any `X`, so an allow-list keeps every key (permissive, exactly\n * like the unfiltered `keyof FieldsOf<T>` before it) while a deny-list would drop every key and\n * break valid calls like `newRequiredRule(\"city\")`.\n */\ntype ColumnBackedFields<F> = {\n [K in keyof F as F[K] extends { kind: \"primitive\" | \"enum\" | \"m2o\" | \"poly\" } ? K : never]: F[K];\n};\n\n/**\n * Creates a validation rule for required fields.\n *\n * This is added automatically by codegen to entities based on FK not-nulls.\n */\nexport function newRequiredRule<T extends Entity>(\n key: keyof ColumnBackedFields<FieldsOf<T>> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Use getField so that we peer through relations\n if (getField(entity, key) === undefined) {\n // Sanity check for AsyncReactiveFields--this should be cheap to just always do; alternatively we could\n // have a RQF-specific `rqfRequiredRule` so that other `newRequiredRule` users don't pay the cost of these\n // two `if` checks`.\n if (entity.isNewEntity && isAsyncReactiveField((entity as any)[key])) {\n throw new Error(\n `AsyncReactiveField ${entity.constructor.name}.${key} must have a default value, either in the database or with config.setDefault (see the 4th step in https://joist-orm.io/modeling/reactive-fields/#async-reactive-fields.`,\n );\n }\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Like `newRequiredRule`, but for `lazy` columns (i.e. codegen only wires this up for `lazy` fields).\n *\n * On an already-persisted entity that hasn't loaded the column, we skip the check rather than force-load\n * (or falsely fail) a value that was required when the row was last saved. It still fires on create and\n * when the field is explicitly loaded-then-unset.\n */\nexport function newRequiredLazyFieldRule<T extends Entity>(\n key: keyof FieldsOf<T> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n if (!entity.isNewEntity && !(entity as any)[key].isLoaded) return;\n if (getField(entity, key) === undefined) {\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Creates a validation rule that a field cannot be updated; it can only be set on creation.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n unless?: ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n optsOrUnless?: ValidationRuleOpts<T> | ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T> {\n const opts = typeof optsOrUnless === \"function\" ? { unless: optsOrUnless } : (optsOrUnless ?? {});\n const fn = ruleWithOpts(opts, (entity: T) => {\n // For now putting the `EntityChanges` cast here to avoid breaking cannotBeUpdated rules\n // on base types, see Publisher.ts's `cannotBeUpdated(\"type\")` repro.\n if ((entity as any as EntityChanges<T>).changes[field].hasUpdated) {\n const value = (entity as any)[field];\n // If we're being changed b/c of an em.merge, that is okay\n if (isLoadedReference(value) && getEmInternalApi(entity.em).isMerging(value.get)) return;\n return { field, code: ValidationCode.cannotBeUpdated, message: `${field} cannot be updated` };\n }\n return;\n });\n return Object.assign(fn, { field, immutable: opts.unless === undefined && opts.if === undefined });\n}\n\n/**\n * Creates a validation rule that a field cannot be changed once set.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeChanged<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity: T) => {\n const changes = (entity as any as EntityChanges<T>).changes[field];\n if (changes.kind === \"m2m\" || changes.kind === \"o2m\" || changes.kind === \"m2mEnum\") {\n throw new Error(\"cannotBeChanged is only supported on primitive & m2o fields\");\n } else if (changes.hasUpdated) {\n const originalValue = changes.originalValue;\n if (originalValue === undefined) return;\n const value = getField(entity, field);\n if (getEmInternalApi(entity.em).isMerging(value)) return;\n return { field, code: ValidationCode.cannotBeChanged, message: `${field} cannot be changed` };\n }\n return;\n });\n}\n\ntype CannotBeUpdatedRule<T extends Entity> = ValidationRule<T> & { field: string; immutable: boolean };\n\nexport function isCannotBeUpdatedRule(rule: Function): rule is CannotBeUpdatedRule<any> {\n return \"field\" in rule && \"immutable\" in rule;\n}\n\n/** For STI, enforces subtype-specific relations/FKs at runtime. */\nexport function mustBeSubType<T extends Entity, K extends keyof Changes<T> & string>(\n relationName: K,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const m2o = (entity as any)[relationName] as ManyToOneReferenceImpl<any, any, any>;\n const other = m2o.get;\n const otherCstr = m2o.otherMeta.cstr;\n if (other && !(other instanceof otherCstr)) {\n return `${relationName} must be a ${otherCstr.name} not ${other}`;\n }\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be smaller than a\n * certain value.\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 range is [0, Infinity]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be smaller than 0\n * config.addRule(minValueRule(\"age\", 0));\n */\nexport function minValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value < minValue) {\n return {\n field,\n code: ValidationCode.minValue,\n message: `${field} must be greater than or equal to ${minValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be greater than a\n * certain value.\n *\n * @param field The field to validate\n * @param maxValue The include maximum value. e.g 10 range is [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be greater than 150\n * config.addRule(maxValueRule(\"age\", 150));\n */\nexport function maxValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value > maxValue) {\n return {\n field,\n code: ValidationCode.maxValue,\n message: `${field} must be smaller than or equal to ${maxValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value must be within a range of\n * certain values\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 [0, Infinity]\n * @param maxValue The include maximum value. e.g 10 [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation * @example\n *\n * // Age must be between 0 and 150\n * config.addRule(rangeValueRule(\"age\", 0, 150));\n */\nexport function rangeValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Check min and max value rules. Because these are called without opts, it should be safe to treat them as sync.\n const minValueResult = minValueRule<T, K>(field, minValue)(entity) as ValidationRuleResult;\n const maxValueResult = maxValueRule<T, K>(field, maxValue)(entity) as ValidationRuleResult;\n // Return any errors or nothing\n if (minValueResult) return minValueResult;\n if (maxValueResult) return maxValueResult;\n return;\n });\n}\n"],"mappings":"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"}
|
package/build/rules.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FieldsOf } from "./typeMap.cjs";
|
|
2
2
|
import { Changes } from "./changes.cjs";
|
|
3
3
|
import { MaybePromise } from "./utils.cjs";
|
|
4
|
-
import { ReactiveHint } from "./reactiveHints.cjs";
|
|
4
|
+
import { ReactiveHint } from "./reactivity/reactiveHints.cjs";
|
|
5
5
|
import { Entity } from "./Entity.cjs";
|
|
6
6
|
//#region src/rules.d.ts
|
|
7
7
|
declare enum ValidationCode {
|
package/build/rules.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FieldsOf } from "./typeMap.mjs";
|
|
2
2
|
import { Changes } from "./changes.mjs";
|
|
3
3
|
import { MaybePromise } from "./utils.mjs";
|
|
4
|
-
import { ReactiveHint } from "./reactiveHints.mjs";
|
|
4
|
+
import { ReactiveHint } from "./reactivity/reactiveHints.mjs";
|
|
5
5
|
import { Entity } from "./Entity.mjs";
|
|
6
6
|
//#region src/rules.d.ts
|
|
7
7
|
declare enum ValidationCode {
|
package/build/rules.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { getField } from "./fields.js";
|
|
2
|
-
import "./typeMap.js";
|
|
3
|
-
import "./changes.js";
|
|
4
2
|
import { isLoadedReference } from "./relations/Reference.js";
|
|
5
|
-
import "./reactiveHints.js";
|
|
6
|
-
import { groupBy, maybePromiseThen } from "./utils.js";
|
|
7
3
|
import { isAsyncReactiveField } from "./relations/AsyncReactiveField.js";
|
|
8
4
|
import "./relations/index.js";
|
|
5
|
+
import { groupBy, maybePromiseThen } from "./utils.js";
|
|
6
|
+
import "./typeMap.js";
|
|
7
|
+
import "./changes.js";
|
|
9
8
|
import { getEmInternalApi } from "./EntityManager.js";
|
|
10
9
|
import "./Entity.js";
|
|
11
10
|
//#region src/rules.ts
|
package/build/rules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","names":[],"sources":["../src/rules.ts"],"sourcesContent":["import { type Changes, type EntityChanges } from \"./changes.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { getEmInternalApi } from \"./EntityManager.ts\";\nimport { getField } from \"./fields.ts\";\nimport { type ReactiveHint } from \"./reactiveHints.ts\";\nimport { type ManyToOneReferenceImpl, isAsyncReactiveField, isLoadedReference } from \"./relations/index.ts\";\nimport { type FieldsOf } from \"./typeMap.ts\";\nimport { type MaybePromise, groupBy, maybePromiseThen } from \"./utils.ts\";\n\nexport enum ValidationCode {\n required = \"required\",\n cannotBeUpdated = \"not-updatable\",\n cannotBeChanged = \"not-changeable\",\n numeric = \"not-numeric\",\n minValue = \"under-min\",\n maxValue = \"over-max\",\n}\n\n/**\n * The return type of `ValidationRule` lambdas.\n *\n * We're flexible and allow rules to return a variety of shapes, like just a string, string[], etc.\n *\n * Returning `undefined` means the rule passed.\n */\nexport type ValidationRuleResult = string | string[] | GenericError | GenericError[] | undefined | void;\n\n/** An entity validation rule. */\nexport type ValidationRule<T extends Entity> = (entity: T) => MaybePromise<ValidationRuleResult>;\n\n/** Internal metadata for an async/reactive validation rule. */\nexport type ValidationRuleInternal<T extends Entity> = {\n name: string;\n hint: ReactiveHint<T> | undefined;\n fn: ValidationRule<T>;\n};\n\n/** A generic error which contains a message, and optional field/codes. */\nexport type GenericError = { message: string; field?: string; code?: string };\n\n/** Combines the GenericError with the `entity` that caused it. */\nexport type ValidationError = { entity: Entity } & GenericError;\n\nexport type ValidationRuleOptsFn<T extends Entity> = (entity: T) => MaybePromise<boolean>;\nexport type ValidationRuleOpts<T extends Entity> = {\n unless?: ValidationRuleOptsFn<T>;\n if?: ValidationRuleOptsFn<T>;\n};\n\nfunction errorMessage(errors: ValidationError[]): string {\n if (errors.length === 1) {\n return `Validation error: ${errors[0].entity.toString()} ${errors[0].message}`;\n } else {\n const message = [...groupBy(errors, (e) => e.entity.toString()).entries()]\n .map(([entityToString, errors]) => `${entityToString} ${errors.map((e) => e.message).join(\", \")}`)\n .join(\", \");\n return `Validation errors (${errors.length}): ${message}`;\n }\n}\n\nexport class ValidationErrors extends Error {\n public errors: Array<GenericError | ValidationError>;\n public readonly toJSON: () => string;\n constructor(errors: ValidationError[]);\n constructor(message: string);\n constructor(messageOrErrors: ValidationError[] | string) {\n super(typeof messageOrErrors === \"string\" ? messageOrErrors : errorMessage(messageOrErrors));\n this.errors = typeof messageOrErrors === \"string\" ? [{ message: messageOrErrors }] : messageOrErrors;\n // Jest clones without prototype, so explictly setting this as a property rather than a class method\n // https://github.com/jestjs/jest/issues/11958\n this.toJSON = () => `ValidationErrors: ${this.message}`;\n }\n}\n\nfunction ruleWithOpts<T extends Entity>(\n opts: ValidationRuleOpts<T> | undefined,\n fn: (entity: T) => ValidationRuleResult,\n): ValidationRule<T> {\n return (entity) => {\n // Since all of our rules are sync, we run the rule first, then check if we should have run it second since this\n // may be an async operation. This way we can avoid running promises if we don't have to.\n const result = fn(entity);\n if (result === undefined) return;\n const { unless, if: _if } = opts ?? {};\n if (unless === undefined && _if === undefined) return result;\n const shouldRun = [unless ?? (() => false), _if ?? (() => true)].map((fn) => fn(entity));\n return maybePromiseThen(\n shouldRun.some((r) => r instanceof Promise) ? Promise.all(shouldRun) : (shouldRun as boolean[]),\n ([unless, _if]) => (!unless && _if ? result : undefined),\n );\n };\n}\n\n/**\n * The fields of `F` that have their own column, i.e. what a required rule can check.\n *\n * The filter is an allow-list (\"keep kinds primitive/enum/m2o/poly\"), not a deny-list (\"drop kind\n * o2o\"), because of how it degrades when `T` is generic/uninferred: `FieldsOf<T>` is then `never`,\n * and `never extends X` is true for any `X`, so an allow-list keeps every key (permissive, exactly\n * like the unfiltered `keyof FieldsOf<T>` before it) while a deny-list would drop every key and\n * break valid calls like `newRequiredRule(\"city\")`.\n */\ntype ColumnBackedFields<F> = {\n [K in keyof F as F[K] extends { kind: \"primitive\" | \"enum\" | \"m2o\" | \"poly\" } ? K : never]: F[K];\n};\n\n/**\n * Creates a validation rule for required fields.\n *\n * This is added automatically by codegen to entities based on FK not-nulls.\n */\nexport function newRequiredRule<T extends Entity>(\n key: keyof ColumnBackedFields<FieldsOf<T>> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Use getField so that we peer through relations\n if (getField(entity, key) === undefined) {\n // Sanity check for AsyncReactiveFields--this should be cheap to just always do; alternatively we could\n // have a RQF-specific `rqfRequiredRule` so that other `newRequiredRule` users don't pay the cost of these\n // two `if` checks`.\n if (entity.isNewEntity && isAsyncReactiveField((entity as any)[key])) {\n throw new Error(\n `AsyncReactiveField ${entity.constructor.name}.${key} must have a default value, either in the database or with config.setDefault (see the 4th step in https://joist-orm.io/modeling/reactive-fields/#async-reactive-fields.`,\n );\n }\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Like `newRequiredRule`, but for `lazy` columns (i.e. codegen only wires this up for `lazy` fields).\n *\n * On an already-persisted entity that hasn't loaded the column, we skip the check rather than force-load\n * (or falsely fail) a value that was required when the row was last saved. It still fires on create and\n * when the field is explicitly loaded-then-unset.\n */\nexport function newRequiredLazyFieldRule<T extends Entity>(\n key: keyof FieldsOf<T> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n if (!entity.isNewEntity && !(entity as any)[key].isLoaded) return;\n if (getField(entity, key) === undefined) {\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Creates a validation rule that a field cannot be updated; it can only be set on creation.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n unless?: ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n optsOrUnless?: ValidationRuleOpts<T> | ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T> {\n const opts = typeof optsOrUnless === \"function\" ? { unless: optsOrUnless } : (optsOrUnless ?? {});\n const fn = ruleWithOpts(opts, (entity: T) => {\n // For now putting the `EntityChanges` cast here to avoid breaking cannotBeUpdated rules\n // on base types, see Publisher.ts's `cannotBeUpdated(\"type\")` repro.\n if ((entity as any as EntityChanges<T>).changes[field].hasUpdated) {\n const value = (entity as any)[field];\n // If we're being changed b/c of an em.merge, that is okay\n if (isLoadedReference(value) && getEmInternalApi(entity.em).isMerging(value.get)) return;\n return { field, code: ValidationCode.cannotBeUpdated, message: `${field} cannot be updated` };\n }\n return;\n });\n return Object.assign(fn, { field, immutable: opts.unless === undefined && opts.if === undefined });\n}\n\n/**\n * Creates a validation rule that a field cannot be changed once set.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeChanged<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity: T) => {\n const changes = (entity as any as EntityChanges<T>).changes[field];\n if (changes.kind === \"m2m\" || changes.kind === \"o2m\" || changes.kind === \"m2mEnum\") {\n throw new Error(\"cannotBeChanged is only supported on primitive & m2o fields\");\n } else if (changes.hasUpdated) {\n const originalValue = changes.originalValue;\n if (originalValue === undefined) return;\n const value = getField(entity, field);\n if (getEmInternalApi(entity.em).isMerging(value)) return;\n return { field, code: ValidationCode.cannotBeChanged, message: `${field} cannot be changed` };\n }\n return;\n });\n}\n\ntype CannotBeUpdatedRule<T extends Entity> = ValidationRule<T> & { field: string; immutable: boolean };\n\nexport function isCannotBeUpdatedRule(rule: Function): rule is CannotBeUpdatedRule<any> {\n return \"field\" in rule && \"immutable\" in rule;\n}\n\n/** For STI, enforces subtype-specific relations/FKs at runtime. */\nexport function mustBeSubType<T extends Entity, K extends keyof Changes<T> & string>(\n relationName: K,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const m2o = (entity as any)[relationName] as ManyToOneReferenceImpl<any, any, any>;\n const other = m2o.get;\n const otherCstr = m2o.otherMeta.cstr;\n if (other && !(other instanceof otherCstr)) {\n return `${relationName} must be a ${otherCstr.name} not ${other}`;\n }\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be smaller than a\n * certain value.\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 range is [0, Infinity]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be smaller than 0\n * config.addRule(minValueRule(\"age\", 0));\n */\nexport function minValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value < minValue) {\n return {\n field,\n code: ValidationCode.minValue,\n message: `${field} must be greater than or equal to ${minValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be greater than a\n * certain value.\n *\n * @param field The field to validate\n * @param maxValue The include maximum value. e.g 10 range is [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be greater than 150\n * config.addRule(maxValueRule(\"age\", 150));\n */\nexport function maxValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value > maxValue) {\n return {\n field,\n code: ValidationCode.maxValue,\n message: `${field} must be smaller than or equal to ${maxValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value must be within a range of\n * certain values\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 [0, Infinity]\n * @param maxValue The include maximum value. e.g 10 [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation * @example\n *\n * // Age must be between 0 and 150\n * config.addRule(rangeValueRule(\"age\", 0, 150));\n */\nexport function rangeValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Check min and max value rules. Because these are called without opts, it should be safe to treat them as sync.\n const minValueResult = minValueRule<T, K>(field, minValue)(entity) as ValidationRuleResult;\n const maxValueResult = maxValueRule<T, K>(field, maxValue)(entity) as ValidationRuleResult;\n // Return any errors or nothing\n if (minValueResult) return minValueResult;\n if (maxValueResult) return maxValueResult;\n return;\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rules.js","names":[],"sources":["../src/rules.ts"],"sourcesContent":["import { type Changes, type EntityChanges } from \"src/changes.ts\";\nimport { type Entity } from \"src/Entity.ts\";\nimport { getEmInternalApi } from \"src/EntityManager.ts\";\nimport { getField } from \"src/fields.ts\";\nimport type { ReactiveHint } from \"src/reactivity/reactiveHints.ts\";\nimport { type ManyToOneReferenceImpl, isAsyncReactiveField, isLoadedReference } from \"src/relations/index.ts\";\nimport { type FieldsOf } from \"src/typeMap.ts\";\nimport { type MaybePromise, groupBy, maybePromiseThen } from \"src/utils.ts\";\n\nexport enum ValidationCode {\n required = \"required\",\n cannotBeUpdated = \"not-updatable\",\n cannotBeChanged = \"not-changeable\",\n numeric = \"not-numeric\",\n minValue = \"under-min\",\n maxValue = \"over-max\",\n}\n\n/**\n * The return type of `ValidationRule` lambdas.\n *\n * We're flexible and allow rules to return a variety of shapes, like just a string, string[], etc.\n *\n * Returning `undefined` means the rule passed.\n */\nexport type ValidationRuleResult = string | string[] | GenericError | GenericError[] | undefined | void;\n\n/** An entity validation rule. */\nexport type ValidationRule<T extends Entity> = (entity: T) => MaybePromise<ValidationRuleResult>;\n\n/** Internal metadata for an async/reactive validation rule. */\nexport type ValidationRuleInternal<T extends Entity> = {\n name: string;\n hint: ReactiveHint<T> | undefined;\n fn: ValidationRule<T>;\n};\n\n/** A generic error which contains a message, and optional field/codes. */\nexport type GenericError = { message: string; field?: string; code?: string };\n\n/** Combines the GenericError with the `entity` that caused it. */\nexport type ValidationError = { entity: Entity } & GenericError;\n\nexport type ValidationRuleOptsFn<T extends Entity> = (entity: T) => MaybePromise<boolean>;\nexport type ValidationRuleOpts<T extends Entity> = {\n unless?: ValidationRuleOptsFn<T>;\n if?: ValidationRuleOptsFn<T>;\n};\n\nfunction errorMessage(errors: ValidationError[]): string {\n if (errors.length === 1) {\n return `Validation error: ${errors[0].entity.toString()} ${errors[0].message}`;\n } else {\n const message = [...groupBy(errors, (e) => e.entity.toString()).entries()]\n .map(([entityToString, errors]) => `${entityToString} ${errors.map((e) => e.message).join(\", \")}`)\n .join(\", \");\n return `Validation errors (${errors.length}): ${message}`;\n }\n}\n\nexport class ValidationErrors extends Error {\n public errors: Array<GenericError | ValidationError>;\n public readonly toJSON: () => string;\n constructor(errors: ValidationError[]);\n constructor(message: string);\n constructor(messageOrErrors: ValidationError[] | string) {\n super(typeof messageOrErrors === \"string\" ? messageOrErrors : errorMessage(messageOrErrors));\n this.errors = typeof messageOrErrors === \"string\" ? [{ message: messageOrErrors }] : messageOrErrors;\n // Jest clones without prototype, so explictly setting this as a property rather than a class method\n // https://github.com/jestjs/jest/issues/11958\n this.toJSON = () => `ValidationErrors: ${this.message}`;\n }\n}\n\nfunction ruleWithOpts<T extends Entity>(\n opts: ValidationRuleOpts<T> | undefined,\n fn: (entity: T) => ValidationRuleResult,\n): ValidationRule<T> {\n return (entity) => {\n // Since all of our rules are sync, we run the rule first, then check if we should have run it second since this\n // may be an async operation. This way we can avoid running promises if we don't have to.\n const result = fn(entity);\n if (result === undefined) return;\n const { unless, if: _if } = opts ?? {};\n if (unless === undefined && _if === undefined) return result;\n const shouldRun = [unless ?? (() => false), _if ?? (() => true)].map((fn) => fn(entity));\n return maybePromiseThen(\n shouldRun.some((r) => r instanceof Promise) ? Promise.all(shouldRun) : (shouldRun as boolean[]),\n ([unless, _if]) => (!unless && _if ? result : undefined),\n );\n };\n}\n\n/**\n * The fields of `F` that have their own column, i.e. what a required rule can check.\n *\n * The filter is an allow-list (\"keep kinds primitive/enum/m2o/poly\"), not a deny-list (\"drop kind\n * o2o\"), because of how it degrades when `T` is generic/uninferred: `FieldsOf<T>` is then `never`,\n * and `never extends X` is true for any `X`, so an allow-list keeps every key (permissive, exactly\n * like the unfiltered `keyof FieldsOf<T>` before it) while a deny-list would drop every key and\n * break valid calls like `newRequiredRule(\"city\")`.\n */\ntype ColumnBackedFields<F> = {\n [K in keyof F as F[K] extends { kind: \"primitive\" | \"enum\" | \"m2o\" | \"poly\" } ? K : never]: F[K];\n};\n\n/**\n * Creates a validation rule for required fields.\n *\n * This is added automatically by codegen to entities based on FK not-nulls.\n */\nexport function newRequiredRule<T extends Entity>(\n key: keyof ColumnBackedFields<FieldsOf<T>> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Use getField so that we peer through relations\n if (getField(entity, key) === undefined) {\n // Sanity check for AsyncReactiveFields--this should be cheap to just always do; alternatively we could\n // have a RQF-specific `rqfRequiredRule` so that other `newRequiredRule` users don't pay the cost of these\n // two `if` checks`.\n if (entity.isNewEntity && isAsyncReactiveField((entity as any)[key])) {\n throw new Error(\n `AsyncReactiveField ${entity.constructor.name}.${key} must have a default value, either in the database or with config.setDefault (see the 4th step in https://joist-orm.io/modeling/reactive-fields/#async-reactive-fields.`,\n );\n }\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Like `newRequiredRule`, but for `lazy` columns (i.e. codegen only wires this up for `lazy` fields).\n *\n * On an already-persisted entity that hasn't loaded the column, we skip the check rather than force-load\n * (or falsely fail) a value that was required when the row was last saved. It still fires on create and\n * when the field is explicitly loaded-then-unset.\n */\nexport function newRequiredLazyFieldRule<T extends Entity>(\n key: keyof FieldsOf<T> & string,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n if (!entity.isNewEntity && !(entity as any)[key].isLoaded) return;\n if (getField(entity, key) === undefined) {\n return { field: key, code: ValidationCode.required, message: `${key} is required` };\n }\n });\n}\n\n/**\n * Creates a validation rule that a field cannot be updated; it can only be set on creation.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n unless?: ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T>;\nexport function cannotBeUpdated<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n optsOrUnless?: ValidationRuleOpts<T> | ValidationRuleOptsFn<T>,\n): CannotBeUpdatedRule<T> {\n const opts = typeof optsOrUnless === \"function\" ? { unless: optsOrUnless } : (optsOrUnless ?? {});\n const fn = ruleWithOpts(opts, (entity: T) => {\n // For now putting the `EntityChanges` cast here to avoid breaking cannotBeUpdated rules\n // on base types, see Publisher.ts's `cannotBeUpdated(\"type\")` repro.\n if ((entity as any as EntityChanges<T>).changes[field].hasUpdated) {\n const value = (entity as any)[field];\n // If we're being changed b/c of an em.merge, that is okay\n if (isLoadedReference(value) && getEmInternalApi(entity.em).isMerging(value.get)) return;\n return { field, code: ValidationCode.cannotBeUpdated, message: `${field} cannot be updated` };\n }\n return;\n });\n return Object.assign(fn, { field, immutable: opts.unless === undefined && opts.if === undefined });\n}\n\n/**\n * Creates a validation rule that a field cannot be changed once set.\n *\n * If the optional `unless` function returns true, then the update is allowed.\n */\nexport function cannotBeChanged<T extends Entity, K extends keyof Changes<T> & string>(\n field: K,\n opts?: ValidationRuleOpts<T>,\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity: T) => {\n const changes = (entity as any as EntityChanges<T>).changes[field];\n if (changes.kind === \"m2m\" || changes.kind === \"o2m\" || changes.kind === \"m2mEnum\") {\n throw new Error(\"cannotBeChanged is only supported on primitive & m2o fields\");\n } else if (changes.hasUpdated) {\n const originalValue = changes.originalValue;\n if (originalValue === undefined) return;\n const value = getField(entity, field);\n if (getEmInternalApi(entity.em).isMerging(value)) return;\n return { field, code: ValidationCode.cannotBeChanged, message: `${field} cannot be changed` };\n }\n return;\n });\n}\n\ntype CannotBeUpdatedRule<T extends Entity> = ValidationRule<T> & { field: string; immutable: boolean };\n\nexport function isCannotBeUpdatedRule(rule: Function): rule is CannotBeUpdatedRule<any> {\n return \"field\" in rule && \"immutable\" in rule;\n}\n\n/** For STI, enforces subtype-specific relations/FKs at runtime. */\nexport function mustBeSubType<T extends Entity, K extends keyof Changes<T> & string>(\n relationName: K,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const m2o = (entity as any)[relationName] as ManyToOneReferenceImpl<any, any, any>;\n const other = m2o.get;\n const otherCstr = m2o.otherMeta.cstr;\n if (other && !(other instanceof otherCstr)) {\n return `${relationName} must be a ${otherCstr.name} not ${other}`;\n }\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be smaller than a\n * certain value.\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 range is [0, Infinity]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be smaller than 0\n * config.addRule(minValueRule(\"age\", 0));\n */\nexport function minValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value < minValue) {\n return {\n field,\n code: ValidationCode.minValue,\n message: `${field} must be greater than or equal to ${minValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value cannot be greater than a\n * certain value.\n *\n * @param field The field to validate\n * @param maxValue The include maximum value. e.g 10 range is [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation\n *\n * @example\n * // Age cannot be greater than 150\n * config.addRule(maxValueRule(\"age\", 150));\n */\nexport function maxValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n const value = entity[field];\n // Ignore undefined and null values. These should be handled by required rules\n if (value === undefined || value === null) return;\n // Show an error when the value type is not a number\n if (typeof value !== \"number\") {\n return { field, code: ValidationCode.numeric, message: `${field} must be a number` };\n }\n // Show an error when the value is smaller than the minimum value\n if (value > maxValue) {\n return {\n field,\n code: ValidationCode.maxValue,\n message: `${field} must be smaller than or equal to ${maxValue}`,\n };\n }\n return;\n });\n}\n\n/**\n * Creates a validation rule that a field value must be within a range of\n * certain values\n *\n * @param field The field to validate\n * @param minValue The inclusive minimum value. e.g 0 [0, Infinity]\n * @param maxValue The include maximum value. e.g 10 [-Infinity, 10]\n * @param opts Optional validation rule options that control when the rule should run:\n * - unless: Function that returns true to skip validation\n * - if: Function that returns true to run validation * @example\n *\n * // Age must be between 0 and 150\n * config.addRule(rangeValueRule(\"age\", 0, 150));\n */\nexport function rangeValueRule<T extends Entity, K extends keyof T & string>(\n field: K,\n minValue: number,\n maxValue: number,\n opts: ValidationRuleOpts<T> = {},\n): ValidationRule<T> {\n return ruleWithOpts(opts, (entity) => {\n // Check min and max value rules. Because these are called without opts, it should be safe to treat them as sync.\n const minValueResult = minValueRule<T, K>(field, minValue)(entity) as ValidationRuleResult;\n const maxValueResult = maxValueRule<T, K>(field, maxValue)(entity) as ValidationRuleResult;\n // Return any errors or nothing\n if (minValueResult) return minValueResult;\n if (maxValueResult) return maxValueResult;\n return;\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeConfig.cjs","names":["fail"],"sources":["../src/runtimeConfig.ts"],"sourcesContent":["import { fail } from \"
|
|
1
|
+
{"version":3,"file":"runtimeConfig.cjs","names":["fail"],"sources":["../src/runtimeConfig.ts"],"sourcesContent":["import { fail } from \"src/utils.ts\";\n\nlet runtimeConfig: RuntimeConfig | undefined = undefined;\n\nexport function getRuntimeConfig(): RuntimeConfig {\n return runtimeConfig ?? fail(\"setRuntimeConfig in metadata.ts has not been invoked yet\");\n}\n\n/** Returns the runtime config if generated metadata has initialized it. */\nexport function maybeGetRuntimeConfig(): RuntimeConfig | undefined {\n return runtimeConfig;\n}\n\n/**\n * Holds any `joist-config.json` values that we want to access at runtime.\n */\nexport type RuntimeConfig = {\n /** The process-wide tagged-id separator; explicit `undefined` means no separator, while omission defaults to `:`. */\n tagDelimiter?: string | undefined;\n temporal:\n | false\n | {\n /** The application's default time zone, i.e. when we say \"now\", and store it as yyyy-MM-dd, what time zone should we use? */\n timeZone: string;\n };\n};\n\n/**\n * Called by the code-generated `metadata.ts` to pass along `joist-config.json` values.\n *\n * This avoids having to load/parse/ship the `joist-config.json` file at runtime.\n */\nexport function setRuntimeConfig(config: RuntimeConfig) {\n runtimeConfig = config;\n}\n"],"mappings":";;;AAEA,IAAI,gBAA2C,KAAA;AAE/C,SAAgB,mBAAkC;CAChD,OAAO,iBAAiBA,cAAAA,KAAK,0DAA0D;AACzF;;AAGA,SAAgB,wBAAmD;CACjE,OAAO;AACT;;;;;;AAqBA,SAAgB,iBAAiB,QAAuB;CACtD,gBAAgB;AAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeConfig.js","names":[],"sources":["../src/runtimeConfig.ts"],"sourcesContent":["import { fail } from \"
|
|
1
|
+
{"version":3,"file":"runtimeConfig.js","names":[],"sources":["../src/runtimeConfig.ts"],"sourcesContent":["import { fail } from \"src/utils.ts\";\n\nlet runtimeConfig: RuntimeConfig | undefined = undefined;\n\nexport function getRuntimeConfig(): RuntimeConfig {\n return runtimeConfig ?? fail(\"setRuntimeConfig in metadata.ts has not been invoked yet\");\n}\n\n/** Returns the runtime config if generated metadata has initialized it. */\nexport function maybeGetRuntimeConfig(): RuntimeConfig | undefined {\n return runtimeConfig;\n}\n\n/**\n * Holds any `joist-config.json` values that we want to access at runtime.\n */\nexport type RuntimeConfig = {\n /** The process-wide tagged-id separator; explicit `undefined` means no separator, while omission defaults to `:`. */\n tagDelimiter?: string | undefined;\n temporal:\n | false\n | {\n /** The application's default time zone, i.e. when we say \"now\", and store it as yyyy-MM-dd, what time zone should we use? */\n timeZone: string;\n };\n};\n\n/**\n * Called by the code-generated `metadata.ts` to pass along `joist-config.json` values.\n *\n * This avoids having to load/parse/ship the `joist-config.json` file at runtime.\n */\nexport function setRuntimeConfig(config: RuntimeConfig) {\n runtimeConfig = config;\n}\n"],"mappings":";;AAEA,IAAI,gBAA2C,KAAA;AAE/C,SAAgB,mBAAkC;CAChD,OAAO,iBAAiB,KAAK,0DAA0D;AACzF;;AAGA,SAAgB,wBAAmD;CACjE,OAAO;AACT;;;;;;AAqBA,SAAgB,iBAAiB,QAAuB;CACtD,gBAAgB;AAClB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
//#region src/TypeInfo.ts
|
|
2
|
+
//#region src/serde/TypeInfo.ts
|
|
3
3
|
/**
|
|
4
4
|
* Normalizes known PostgreSQL type synonyms without treating coercible types or user types as equal.
|
|
5
5
|
* The output compatibility checks compare these names, so normalize only spellings of the same type.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeInfo.cjs","names":[],"sources":["../../src/serde/TypeInfo.ts"],"sourcesContent":["// Keep compatibility metadata a runtime leaf in both CJS and ESM builds.\nimport type { EntityMetadata } from \"src/EntityMetadata.ts\";\n\n/**\n * Runtime proof that values can share scalar conversions.\n *\n * PostgreSQL compares projected SQL rows and chooses a common SQL type before Joist decodes them.\n * A compound uses one decoder per output column and retains an encoder for later comparisons and\n * coalesce fallbacks. TypeScript result types are erased, and equal SQL storage types do not imply\n * equal logical domains.\n *\n * I.e. Author.id and Book.author_id are compatible Author IDs despite having separate serdes, while\n * Book.id must not decode as an Author ID just because both use int4. Author.age and Author.age.sum()\n * both expose TypeScript numbers but produce int4 and int8 driver values. Enum, custom-mapper, and\n * JSON-schema domain tokens also prevent unrelated conversions from mixing.\n *\n * Compatibility requires exact equality of canonical `dbType`, `domain`, and `idMeta`. An absent\n * descriptor is unknown, not an identity codec. `idMeta` identifies scalar IDs only; arrays retain\n * their element domain separately so they cannot select a polymorphic IN component. Raw `sql<R>`\n * annotations supply no runtime evidence. This descriptor does not implement conversions.\n */\nexport interface TypeInfo {\n dbType: string;\n domain: unknown;\n idMeta?: EntityMetadata;\n /** Internal conversion proof, consistent for equal dbType/domain/idMeta; not another compatibility key. */\n arrayElementSafe?: boolean;\n}\n\n/**\n * Normalizes known PostgreSQL type synonyms without treating coercible types or user types as equal.\n * The output compatibility checks compare these names, so normalize only spellings of the same type.\n *\n * I.e. `integer` and `int` both mean `int4`; `integer[]` and `int4[]` also describe the same SQL type.\n * Keeping these spellings distinct would reject compatible outputs just because their serdes use\n * different names for the same representation.\n *\n * I.e. `int4` can be promoted to `int8`, but they are not synonyms: classic pg returns int4 as a number\n * and int8 as a string. Treating them as equal could admit a compound whose first operand's decoder\n * cannot handle the common SQL type. This function does not choose or apply a conversion.\n *\n * I.e. `citext` must stay distinct from `text`: they disagree on whether 'Alice' and 'alice' are equal,\n * which matters when a set operation compares rows. A user-defined `app.email` domain over text can\n * also impose constraints that text does not. Unknown names remain unchanged, including their schema\n * and quoting; neither coercibility nor a shared base type proves that their outputs are compatible.\n */\nexport function canonicalDbType(dbType: string): string {\n if (dbType.endsWith(\"[]\")) return `${canonicalDbType(dbType.slice(0, -2))}[]`;\n switch (dbType) {\n case \"smallint\":\n return \"int2\";\n case \"int\":\n case \"integer\":\n return \"int4\";\n case \"bigint\":\n return \"int8\";\n case \"decimal\":\n return \"numeric\";\n case \"real\":\n return \"float4\";\n case \"double precision\":\n return \"float8\";\n case \"boolean\":\n return \"bool\";\n case \"character varying\":\n return \"varchar\";\n case \"character\":\n return \"bpchar\";\n case \"timestamp without time zone\":\n return \"timestamp\";\n case \"timestamp with time zone\":\n return \"timestamptz\";\n case \"time without time zone\":\n return \"time\";\n case \"time with time zone\":\n return \"timetz\";\n default:\n return dbType;\n }\n}\n\nconst arrayDomains = new Map<unknown, Map<EntityMetadata | undefined, symbol>>();\n\n// Both classic pg and lazy binary reads decode these physical arrays, not an unparsed array string.\nconst arrayElementDbTypes = new Set([\n \"bool\",\n \"bytea\",\n \"int2\",\n \"int4\",\n \"int8\",\n \"float4\",\n \"float8\",\n \"numeric\",\n \"text\",\n \"varchar\",\n \"bpchar\",\n \"uuid\",\n \"json\",\n \"jsonb\",\n]);\n\n/**\n * Describes elementwise conversion only for known physical array parsers and stable domain conversion.\n *\n * I.e. `a.id.arrayAgg()` wraps Author's tag and `idMeta` in its domain token, but has no scalar\n * `idMeta` of its own. Repeated expressions share the token; IDs of subtypes with a shared tag do not.\n * Native enum/citext, date/time, and nested SQL arrays remain unknown. Numeric elements can be numbers\n * in classic pg and strings in lazy binary reads, so a scalar string-only mapper is not sufficient.\n */\nexport function arrayOutputType(outputType: TypeInfo | undefined): TypeInfo | undefined {\n if (!outputType?.arrayElementSafe || !arrayElementDbTypes.has(outputType.dbType)) return undefined;\n let domains = arrayDomains.get(outputType.domain);\n if (!domains) arrayDomains.set(outputType.domain, (domains = new Map()));\n let domain = domains.get(outputType.idMeta);\n if (!domain) domains.set(outputType.idMeta, (domain = Symbol(\"joist.arrayOutput\")));\n return { dbType: `${outputType.dbType}[]`, domain };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8CA,SAAgB,gBAAgB,QAAwB;CACtD,IAAI,OAAO,SAAS,IAAI,GAAG,OAAO,GAAG,gBAAgB,OAAO,MAAM,GAAG,EAAE,CAAC,EAAE;CAC1E,QAAQ,QAAR;EACE,KAAK,YACH,OAAO;EACT,KAAK;EACL,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,oBACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,qBACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,+BACH,OAAO;EACT,KAAK,4BACH,OAAO;EACT,KAAK,0BACH,OAAO;EACT,KAAK,uBACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,MAAM,+BAAe,IAAI,IAAsD;AAG/E,MAAM,sCAAsB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;AAUD,SAAgB,gBAAgB,YAAwD;CACtF,IAAI,CAAC,YAAY,oBAAoB,CAAC,oBAAoB,IAAI,WAAW,MAAM,GAAG,OAAO,KAAA;CACzF,IAAI,UAAU,aAAa,IAAI,WAAW,MAAM;CAChD,IAAI,CAAC,SAAS,aAAa,IAAI,WAAW,QAAS,0BAAU,IAAI,IAAI,CAAE;CACvE,IAAI,SAAS,QAAQ,IAAI,WAAW,MAAM;CAC1C,IAAI,CAAC,QAAQ,QAAQ,IAAI,WAAW,QAAS,SAAS,OAAO,mBAAmB,CAAE;CAClF,OAAO;EAAE,QAAQ,GAAG,WAAW,OAAO;EAAK;CAAO;AACpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeInfo.d.cts","names":[],"sources":["../../src/serde/TypeInfo.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;UAqBiB;EACf;EACA;EACA,SAAS;;EAET;;;;;;;;;;;;;;;;;;;iBAoBc,gBAAgB;;;;;;;;;iBA+DhB,gBAAgB,YAAY,uBAAuB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeInfo.d.mts","names":[],"sources":["../../src/serde/TypeInfo.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;UAqBiB;EACf;EACA;EACA,SAAS;;EAET;;;;;;;;;;;;;;;;;;;iBAoBc,gBAAgB;;;;;;;;;iBA+DhB,gBAAgB,YAAY,uBAAuB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeInfo.js","names":[],"sources":["../../src/serde/TypeInfo.ts"],"sourcesContent":["// Keep compatibility metadata a runtime leaf in both CJS and ESM builds.\nimport type { EntityMetadata } from \"src/EntityMetadata.ts\";\n\n/**\n * Runtime proof that values can share scalar conversions.\n *\n * PostgreSQL compares projected SQL rows and chooses a common SQL type before Joist decodes them.\n * A compound uses one decoder per output column and retains an encoder for later comparisons and\n * coalesce fallbacks. TypeScript result types are erased, and equal SQL storage types do not imply\n * equal logical domains.\n *\n * I.e. Author.id and Book.author_id are compatible Author IDs despite having separate serdes, while\n * Book.id must not decode as an Author ID just because both use int4. Author.age and Author.age.sum()\n * both expose TypeScript numbers but produce int4 and int8 driver values. Enum, custom-mapper, and\n * JSON-schema domain tokens also prevent unrelated conversions from mixing.\n *\n * Compatibility requires exact equality of canonical `dbType`, `domain`, and `idMeta`. An absent\n * descriptor is unknown, not an identity codec. `idMeta` identifies scalar IDs only; arrays retain\n * their element domain separately so they cannot select a polymorphic IN component. Raw `sql<R>`\n * annotations supply no runtime evidence. This descriptor does not implement conversions.\n */\nexport interface TypeInfo {\n dbType: string;\n domain: unknown;\n idMeta?: EntityMetadata;\n /** Internal conversion proof, consistent for equal dbType/domain/idMeta; not another compatibility key. */\n arrayElementSafe?: boolean;\n}\n\n/**\n * Normalizes known PostgreSQL type synonyms without treating coercible types or user types as equal.\n * The output compatibility checks compare these names, so normalize only spellings of the same type.\n *\n * I.e. `integer` and `int` both mean `int4`; `integer[]` and `int4[]` also describe the same SQL type.\n * Keeping these spellings distinct would reject compatible outputs just because their serdes use\n * different names for the same representation.\n *\n * I.e. `int4` can be promoted to `int8`, but they are not synonyms: classic pg returns int4 as a number\n * and int8 as a string. Treating them as equal could admit a compound whose first operand's decoder\n * cannot handle the common SQL type. This function does not choose or apply a conversion.\n *\n * I.e. `citext` must stay distinct from `text`: they disagree on whether 'Alice' and 'alice' are equal,\n * which matters when a set operation compares rows. A user-defined `app.email` domain over text can\n * also impose constraints that text does not. Unknown names remain unchanged, including their schema\n * and quoting; neither coercibility nor a shared base type proves that their outputs are compatible.\n */\nexport function canonicalDbType(dbType: string): string {\n if (dbType.endsWith(\"[]\")) return `${canonicalDbType(dbType.slice(0, -2))}[]`;\n switch (dbType) {\n case \"smallint\":\n return \"int2\";\n case \"int\":\n case \"integer\":\n return \"int4\";\n case \"bigint\":\n return \"int8\";\n case \"decimal\":\n return \"numeric\";\n case \"real\":\n return \"float4\";\n case \"double precision\":\n return \"float8\";\n case \"boolean\":\n return \"bool\";\n case \"character varying\":\n return \"varchar\";\n case \"character\":\n return \"bpchar\";\n case \"timestamp without time zone\":\n return \"timestamp\";\n case \"timestamp with time zone\":\n return \"timestamptz\";\n case \"time without time zone\":\n return \"time\";\n case \"time with time zone\":\n return \"timetz\";\n default:\n return dbType;\n }\n}\n\nconst arrayDomains = new Map<unknown, Map<EntityMetadata | undefined, symbol>>();\n\n// Both classic pg and lazy binary reads decode these physical arrays, not an unparsed array string.\nconst arrayElementDbTypes = new Set([\n \"bool\",\n \"bytea\",\n \"int2\",\n \"int4\",\n \"int8\",\n \"float4\",\n \"float8\",\n \"numeric\",\n \"text\",\n \"varchar\",\n \"bpchar\",\n \"uuid\",\n \"json\",\n \"jsonb\",\n]);\n\n/**\n * Describes elementwise conversion only for known physical array parsers and stable domain conversion.\n *\n * I.e. `a.id.arrayAgg()` wraps Author's tag and `idMeta` in its domain token, but has no scalar\n * `idMeta` of its own. Repeated expressions share the token; IDs of subtypes with a shared tag do not.\n * Native enum/citext, date/time, and nested SQL arrays remain unknown. Numeric elements can be numbers\n * in classic pg and strings in lazy binary reads, so a scalar string-only mapper is not sufficient.\n */\nexport function arrayOutputType(outputType: TypeInfo | undefined): TypeInfo | undefined {\n if (!outputType?.arrayElementSafe || !arrayElementDbTypes.has(outputType.dbType)) return undefined;\n let domains = arrayDomains.get(outputType.domain);\n if (!domains) arrayDomains.set(outputType.domain, (domains = new Map()));\n let domain = domains.get(outputType.idMeta);\n if (!domain) domains.set(outputType.idMeta, (domain = Symbol(\"joist.arrayOutput\")));\n return { dbType: `${outputType.dbType}[]`, domain };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA8CA,SAAgB,gBAAgB,QAAwB;CACtD,IAAI,OAAO,SAAS,IAAI,GAAG,OAAO,GAAG,gBAAgB,OAAO,MAAM,GAAG,EAAE,CAAC,EAAE;CAC1E,QAAQ,QAAR;EACE,KAAK,YACH,OAAO;EACT,KAAK;EACL,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,oBACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,qBACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,+BACH,OAAO;EACT,KAAK,4BACH,OAAO;EACT,KAAK,0BACH,OAAO;EACT,KAAK,uBACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,MAAM,+BAAe,IAAI,IAAsD;AAG/E,MAAM,sCAAsB,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;AAUD,SAAgB,gBAAgB,YAAwD;CACtF,IAAI,CAAC,YAAY,oBAAoB,CAAC,oBAAoB,IAAI,WAAW,MAAM,GAAG,OAAO,KAAA;CACzF,IAAI,UAAU,aAAa,IAAI,WAAW,MAAM;CAChD,IAAI,CAAC,SAAS,aAAa,IAAI,WAAW,QAAS,0BAAU,IAAI,IAAI,CAAE;CACvE,IAAI,SAAS,QAAQ,IAAI,WAAW,MAAM;CAC1C,IAAI,CAAC,QAAQ,QAAQ,IAAI,WAAW,QAAS,SAAS,OAAO,mBAAmB,CAAE;CAClF,OAAO;EAAE,QAAQ,GAAG,WAAW,OAAO;EAAK;CAAO;AACpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.cjs","names":[],"sources":["../../src/serde/columns.ts"],"sourcesContent":["// These must be erased imports: descriptors are loaded before entity metadata and relation classes.\nimport type { EntityMetadata } from \"src/EntityMetadata.ts\";\nimport type { ScalarCodec } from \"src/serde/serde.ts\";\nimport type { TypeInfo } from \"src/serde/TypeInfo.ts\";\n\n/** A physical column owns one scalar codec, shared with every field binding for that column. */\nexport class Column {\n readonly insert: \"required\" | \"optional\" | \"never\";\n readonly update: boolean;\n /** Physical storage and SQL write policy, independent of domain field requiredness and defaults. */\n constructor(\n readonly columnName: string,\n readonly sqlNullable: boolean,\n readonly hasDefault: boolean,\n readonly isGenerated: boolean,\n /** ORM-maintained timestamps can be omitted by the SQL API as well. */\n readonly insertOptional: boolean,\n /** Polymorphic components are readable, but direct mutations remain unsupported. */\n readonly writable: boolean,\n readonly idMetadata: (() => EntityMetadata) | undefined,\n readonly codec: ScalarCodec,\n ) {\n const primaryKey = columnName === \"id\";\n this.insert =\n isGenerated || writable === false\n ? \"never\"\n : sqlNullable || hasDefault || insertOptional || (primaryKey && [\"int\", \"bigint\"].includes(codec.dbType))\n ? \"optional\"\n : \"required\";\n this.update = !primaryKey && !isGenerated && writable !== false;\n }\n\n get dbType(): string {\n return this.codec.dbType;\n }\n get isArray(): boolean {\n return this.codec.isArray;\n }\n get isNullableArray(): boolean {\n return this.codec.isArray && this.sqlNullable;\n }\n\n /** Resolve ID metadata only after all generated entity modules have initialized. */\n get outputType(): TypeInfo | undefined {\n const output = this.codec.outputType;\n if (!this.idMetadata) return output;\n // Scalar ID evidence must never be attached to an array domain or an unknown replacement codec.\n return output && !this.codec.isArray && !output.dbType.endsWith(\"[]\")\n ? { ...output, idMeta: this.idMetadata() }\n : undefined;\n }\n\n mapToDb(value: any): any {\n return this.codec.mapToDb(value);\n }\n mapToDbValue(value: unknown): unknown {\n return this.codec.mapToDbValue!(value);\n }\n mapFromDb(value: unknown): unknown {\n return this.codec.mapFromDb(value);\n }\n mapFromJsonAgg(value: any): any {\n return this.codec.mapFromJsonAgg(value);\n }\n}\n\nexport type ColumnDescriptors = Record<string, Column>;\n"],"mappings":";;;AAMA,IAAa,SAAb,MAAoB;CAKP;CACA;CACA;CACA;CAEA;CAEA;CACA;CACA;CAbX;CACA;;CAEA,YACE,YACA,aACA,YACA,aAEA,gBAEA,UACA,YACA,OACA;EAVS,KAAA,aAAA;EACA,KAAA,cAAA;EACA,KAAA,aAAA;EACA,KAAA,cAAA;EAEA,KAAA,iBAAA;EAEA,KAAA,WAAA;EACA,KAAA,aAAA;EACA,KAAA,QAAA;EAET,MAAM,aAAa,eAAe;EAClC,KAAK,SACH,eAAe,aAAa,QACxB,UACA,eAAe,cAAc,kBAAmB,cAAc,CAAC,OAAO,QAAQ,CAAC,CAAC,SAAS,MAAM,MAAM,IACnG,aACA;EACR,KAAK,SAAS,CAAC,cAAc,CAAC,eAAe,aAAa;CAC5D;CAEA,IAAI,SAAiB;EACnB,OAAO,KAAK,MAAM;CACpB;CACA,IAAI,UAAmB;EACrB,OAAO,KAAK,MAAM;CACpB;CACA,IAAI,kBAA2B;EAC7B,OAAO,KAAK,MAAM,WAAW,KAAK;CACpC;;CAGA,IAAI,aAAmC;EACrC,MAAM,SAAS,KAAK,MAAM;EAC1B,IAAI,CAAC,KAAK,YAAY,OAAO;EAE7B,OAAO,UAAU,CAAC,KAAK,MAAM,WAAW,CAAC,OAAO,OAAO,SAAS,IAAI,IAChE;GAAE,GAAG;GAAQ,QAAQ,KAAK,WAAW;EAAE,IACvC,KAAA;CACN;CAEA,QAAQ,OAAiB;EACvB,OAAO,KAAK,MAAM,QAAQ,KAAK;CACjC;CACA,aAAa,OAAyB;EACpC,OAAO,KAAK,MAAM,aAAc,KAAK;CACvC;CACA,UAAU,OAAyB;EACjC,OAAO,KAAK,MAAM,UAAU,KAAK;CACnC;CACA,eAAe,OAAiB;EAC9B,OAAO,KAAK,MAAM,eAAe,KAAK;CACxC;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TypeInfo } from "./TypeInfo.cjs";
|
|
2
2
|
import { ScalarCodec } from "./serde.cjs";
|
|
3
|
-
import { EntityMetadata } from "
|
|
4
|
-
//#region src/columns.d.ts
|
|
3
|
+
import { EntityMetadata } from "../EntityMetadata.cjs";
|
|
4
|
+
//#region src/serde/columns.d.ts
|
|
5
5
|
/** A physical column owns one scalar codec, shared with every field binding for that column. */
|
|
6
6
|
declare class Column {
|
|
7
7
|
readonly columnName: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.d.cts","names":[],"sources":["../../src/serde/columns.ts"],"mappings":";;;;;cAMa;WAKA;WACA;WACA;WACA;;WAEA;;WAEA;WACA,mBAAmB;WACnB,OAAO;WAbT;WACA;;EAET,YACW,oBACA,sBACA,qBACA,sBAEA;;EAAA,yBAEA;;EAAA,mBACA,mBAAmB,6BACnB,OAAO;MAYd;MAGA;MAGA;;MAKA,cAAc;EASlB,QAAQ;EAGR,aAAa;EAGb,UAAU;EAGV,eAAe;;KAKL,oBAAoB,eAAe"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TypeInfo } from "./TypeInfo.mjs";
|
|
2
2
|
import { ScalarCodec } from "./serde.mjs";
|
|
3
|
-
import { EntityMetadata } from "
|
|
4
|
-
//#region src/columns.d.ts
|
|
3
|
+
import { EntityMetadata } from "../EntityMetadata.mjs";
|
|
4
|
+
//#region src/serde/columns.d.ts
|
|
5
5
|
/** A physical column owns one scalar codec, shared with every field binding for that column. */
|
|
6
6
|
declare class Column {
|
|
7
7
|
readonly columnName: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.d.mts","names":[],"sources":["../../src/serde/columns.ts"],"mappings":";;;;;cAMa;WAKA;WACA;WACA;WACA;;WAEA;;WAEA;WACA,mBAAmB;WACnB,OAAO;WAbT;WACA;;EAET,YACW,oBACA,sBACA,qBACA,sBAEA;;EAAA,yBAEA;;EAAA,mBACA,mBAAmB,6BACnB,OAAO;MAYd;MAGA;MAGA;;MAKA,cAAc;EASlB,QAAQ;EAGR,aAAa;EAGb,UAAU;EAGV,eAAe;;KAKL,oBAAoB,eAAe"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.js","names":[],"sources":["../../src/serde/columns.ts"],"sourcesContent":["// These must be erased imports: descriptors are loaded before entity metadata and relation classes.\nimport type { EntityMetadata } from \"src/EntityMetadata.ts\";\nimport type { ScalarCodec } from \"src/serde/serde.ts\";\nimport type { TypeInfo } from \"src/serde/TypeInfo.ts\";\n\n/** A physical column owns one scalar codec, shared with every field binding for that column. */\nexport class Column {\n readonly insert: \"required\" | \"optional\" | \"never\";\n readonly update: boolean;\n /** Physical storage and SQL write policy, independent of domain field requiredness and defaults. */\n constructor(\n readonly columnName: string,\n readonly sqlNullable: boolean,\n readonly hasDefault: boolean,\n readonly isGenerated: boolean,\n /** ORM-maintained timestamps can be omitted by the SQL API as well. */\n readonly insertOptional: boolean,\n /** Polymorphic components are readable, but direct mutations remain unsupported. */\n readonly writable: boolean,\n readonly idMetadata: (() => EntityMetadata) | undefined,\n readonly codec: ScalarCodec,\n ) {\n const primaryKey = columnName === \"id\";\n this.insert =\n isGenerated || writable === false\n ? \"never\"\n : sqlNullable || hasDefault || insertOptional || (primaryKey && [\"int\", \"bigint\"].includes(codec.dbType))\n ? \"optional\"\n : \"required\";\n this.update = !primaryKey && !isGenerated && writable !== false;\n }\n\n get dbType(): string {\n return this.codec.dbType;\n }\n get isArray(): boolean {\n return this.codec.isArray;\n }\n get isNullableArray(): boolean {\n return this.codec.isArray && this.sqlNullable;\n }\n\n /** Resolve ID metadata only after all generated entity modules have initialized. */\n get outputType(): TypeInfo | undefined {\n const output = this.codec.outputType;\n if (!this.idMetadata) return output;\n // Scalar ID evidence must never be attached to an array domain or an unknown replacement codec.\n return output && !this.codec.isArray && !output.dbType.endsWith(\"[]\")\n ? { ...output, idMeta: this.idMetadata() }\n : undefined;\n }\n\n mapToDb(value: any): any {\n return this.codec.mapToDb(value);\n }\n mapToDbValue(value: unknown): unknown {\n return this.codec.mapToDbValue!(value);\n }\n mapFromDb(value: unknown): unknown {\n return this.codec.mapFromDb(value);\n }\n mapFromJsonAgg(value: any): any {\n return this.codec.mapFromJsonAgg(value);\n }\n}\n\nexport type ColumnDescriptors = Record<string, Column>;\n"],"mappings":";;AAMA,IAAa,SAAb,MAAoB;CAKP;CACA;CACA;CACA;CAEA;CAEA;CACA;CACA;CAbX;CACA;;CAEA,YACE,YACA,aACA,YACA,aAEA,gBAEA,UACA,YACA,OACA;EAVS,KAAA,aAAA;EACA,KAAA,cAAA;EACA,KAAA,aAAA;EACA,KAAA,cAAA;EAEA,KAAA,iBAAA;EAEA,KAAA,WAAA;EACA,KAAA,aAAA;EACA,KAAA,QAAA;EAET,MAAM,aAAa,eAAe;EAClC,KAAK,SACH,eAAe,aAAa,QACxB,UACA,eAAe,cAAc,kBAAmB,cAAc,CAAC,OAAO,QAAQ,CAAC,CAAC,SAAS,MAAM,MAAM,IACnG,aACA;EACR,KAAK,SAAS,CAAC,cAAc,CAAC,eAAe,aAAa;CAC5D;CAEA,IAAI,SAAiB;EACnB,OAAO,KAAK,MAAM;CACpB;CACA,IAAI,UAAmB;EACrB,OAAO,KAAK,MAAM;CACpB;CACA,IAAI,kBAA2B;EAC7B,OAAO,KAAK,MAAM,WAAW,KAAK;CACpC;;CAGA,IAAI,aAAmC;EACrC,MAAM,SAAS,KAAK,MAAM;EAC1B,IAAI,CAAC,KAAK,YAAY,OAAO;EAE7B,OAAO,UAAU,CAAC,KAAK,MAAM,WAAW,CAAC,OAAO,OAAO,SAAS,IAAI,IAChE;GAAE,GAAG;GAAQ,QAAQ,KAAK,WAAW;EAAE,IACvC,KAAA;CACN;CAEA,QAAQ,OAAiB;EACvB,OAAO,KAAK,MAAM,QAAQ,KAAK;CACjC;CACA,aAAa,OAAyB;EACpC,OAAO,KAAK,MAAM,aAAc,KAAK;CACvC;CACA,UAAU,OAAyB;EACjC,OAAO,KAAK,MAAM,UAAU,KAAK;CACnC;CACA,eAAe,OAAiB;EAC9B,OAAO,KAAK,MAAM,eAAe,KAAK;CACxC;AACF"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const require_configure = require("
|
|
5
|
-
const require_EntityMetadata = require("
|
|
6
|
-
const require_Entity = require("
|
|
7
|
-
//#region src/fieldSerde.ts
|
|
2
|
+
const require_keys = require("../keys.cjs");
|
|
3
|
+
const require_utils = require("../utils.cjs");
|
|
4
|
+
const require_configure = require("../configure.cjs");
|
|
5
|
+
const require_EntityMetadata = require("../EntityMetadata.cjs");
|
|
6
|
+
const require_Entity = require("../Entity.cjs");
|
|
7
|
+
//#region src/serde/fieldSerde.ts
|
|
8
8
|
function hasSerde(field) {
|
|
9
9
|
return !!field.serde;
|
|
10
10
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fieldSerde.cjs","names":["isEntity","getMetadata","maybeResolveReferenceToId","getConstructorFromTaggedId","groupBy","getBaseMeta"],"sources":["../../src/serde/fieldSerde.ts"],"sourcesContent":["import { getConstructorFromTaggedId } from \"src/configure.ts\";\nimport type { InsertFixup } from \"src/drivers/EntityWriter.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n type SerdeField,\n getBaseMeta,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"src/keys.ts\";\nimport type { RowData } from \"src/RowData.ts\";\nimport type { Column } from \"src/serde/columns.ts\";\nimport type { TimestampCodec } from \"src/serde/serde.ts\";\nimport { groupBy } from \"src/utils.ts\";\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/** Entity hydration and flush bindings; a polymorphic relationship spans several physical columns. */\nexport interface FieldSerde {\n columns: FieldColumn[];\n /** Decode one domain value from accessed cells; callers own entity assignment and caching. */\n fromRow(rowData: RowData, rowIndex: number): unknown;\n}\n\nexport interface TimestampSerde<T> extends FieldSerde {\n mapFromNow(now: Date): T;\n dbValue(data: any): any;\n}\n\n/** Binds a physical column to entity data without adding a second codec or storage declaration. */\nexport class FieldColumn {\n constructor(\n readonly fieldName: string,\n readonly column: Column,\n ) {}\n get codec() {\n return this.column.codec;\n }\n get insertOptional() {\n return this.column.insertOptional;\n }\n get writable() {\n return this.column.writable;\n }\n get insert() {\n return this.column.insert;\n }\n get update() {\n return this.column.update;\n }\n get idMetadata() {\n return this.column.idMetadata;\n }\n get columnName(): string {\n return this.column.columnName;\n }\n get dbType(): string {\n return this.column.dbType;\n }\n get isArray(): boolean {\n return this.column.isArray;\n }\n get isNullableArray(): boolean {\n return this.column.isNullableArray;\n }\n get sqlNullable(): boolean {\n return this.column.sqlNullable;\n }\n get hasDefault(): boolean {\n return this.column.hasDefault;\n }\n get isGenerated(): boolean {\n return this.column.isGenerated;\n }\n get outputType() {\n return this.column.outputType;\n }\n mapToDb(value: any): any {\n return this.column.mapToDb(value);\n }\n mapToDbValue(value: unknown): unknown {\n return this.column.mapToDbValue(value);\n }\n mapFromDb(value: unknown): unknown {\n return this.column.mapFromDb(value);\n }\n mapFromJsonAgg(value: any): any {\n return this.column.mapFromJsonAgg(value);\n }\n\n /** Defers FK writes whose new target must be inserted after this entity. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any {\n const value = data[this.fieldName];\n if (\n this.column.idMetadata &&\n fixups &&\n isEntity(value) &&\n value.isNewEntity &&\n getMetadata(value).nonDeferredFkOrder &&\n getMetadata(entity).nonDeferredFkOrder &&\n getMetadata(value).nonDeferredFkOrder! >= getMetadata(entity).nonDeferredFkOrder!\n ) {\n fixups.push({ entity, tableName, column: this, value: this.mapToDbValue(maybeResolveReferenceToId(value)) });\n return null;\n }\n return this.mapToDbValue(value);\n }\n\n /** Reconstruct the driver's row representation, which can differ from write bindings for Date and JSON. */\n rowValue(data: any): any {\n return this.column.codec.mapToRow(data[this.fieldName]);\n }\n}\n\n/** Binds one entity field to its physical column. */\nexport class SimpleFieldSerde extends FieldColumn implements FieldSerde {\n readonly columns: FieldColumn[] = [this];\n /** Decode this field's physical column without changing entity data. */\n fromRow(rowData: RowData, rowIndex: number): unknown {\n return this.column.mapFromDb(rowData.get(rowIndex, this.column.columnName));\n }\n mapFromNow(now: Date): unknown {\n return (this.column.codec as TimestampCodec<unknown>).mapFromNow(now);\n }\n}\n\n/** A polymorphic field selects exactly one component while each physical column retains a scalar ID codec. */\nexport class PolymorphicKeySerde implements FieldSerde {\n readonly columns: PolymorphicFieldColumn[];\n constructor(\n readonly fieldName: string,\n components: PolymorphicFieldComponent[],\n ) {\n this.columns = components.map((component) => new PolymorphicFieldColumn(fieldName, component, components));\n }\n /** Select the first truthy component whose decoded ID is not nullish. */\n fromRow(rowData: RowData, rowIndex: number): unknown {\n let decoded: unknown;\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) {\n decoded = column.mapFromDb(value);\n if (decoded != null) return decoded;\n }\n }\n return decoded;\n }\n}\n\n/** Shares domain components between relationship traversal and entity write selection. */\nexport function polymorphicField(\n fieldName: string,\n required: boolean,\n components: PolymorphicFieldComponent[],\n): PolymorphicField {\n return {\n kind: \"poly\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required,\n components,\n serde: new PolymorphicKeySerde(fieldName, components),\n immutable: false,\n };\n}\n\n/** A domain relationship component references storage and only overrides a specialized domain target. */\nexport class PolyComponent implements PolymorphicFieldComponent {\n constructor(\n readonly column: Column,\n readonly otherFieldName: string,\n private readonly target?: () => EntityMetadata,\n ) {}\n get columnName(): string {\n return this.column.columnName;\n }\n get otherMetadata(): () => EntityMetadata {\n return this.target ?? this.column.idMetadata!;\n }\n}\n\n/** Selects a relationship component for entity writes only; direct SQL writes use its scalar column codec. */\nclass PolymorphicFieldColumn extends FieldColumn {\n constructor(\n fieldName: string,\n private readonly component: PolymorphicFieldComponent,\n private readonly components: PolymorphicFieldComponent[],\n ) {\n super(fieldName, component.column);\n }\n get otherMetadata() {\n return this.component.otherMetadata;\n }\n\n /** Preserve exact subtype selection when multiple components share a base type. */\n mapToDbValue(value: unknown): unknown {\n const id = maybeResolveReferenceToId(value as Parameters<typeof maybeResolveReferenceToId>[0]);\n const cstr = isEntity(value) ? getMetadata(value).cstr : id ? getConstructorFromTaggedId(id) : undefined;\n // If our poly has multiple components from the same base type, i.e.\n // `parent_small_publisher_id` and `parent_large_publisher_id`, then we\n // need slightly different logic...\n const hasMultipleComponentsWithSameBaseType = [\n ...groupBy(this.components, (component) => getBaseMeta(component.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n const otherMeta = this.otherMetadata();\n // We'll have multiple columns, i.e. [parent_author_id, parent_book_id], and each column\n // will only return a value if the `id` matches its type, i.e. `parent_author_id=a:1` will\n // return 1, but `parent_book_id` will return null.\n const applies = hasMultipleComponentsWithSameBaseType\n ? cstr === otherMeta.cstr\n : cstr === otherMeta.cstr ||\n cstr === getBaseMeta(otherMeta).cstr ||\n otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr);\n return applies ? this.column.mapToDbValue(id) : undefined;\n }\n // Polymorphic writes historically do not schedule non-deferred FK fixups.\n dbValue(data: any): any {\n return this.mapToDbValue(data[this.fieldName]);\n }\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n}\n"],"mappings":"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"}
|