json-rest-api 1.0.29 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +10 -670
- package/LICENSE-GPL-3.0 +674 -0
- package/LICENSE-MIT +21 -0
- package/README.md +39 -30
- package/docs/API.md +744 -1273
- package/docs/GUIDE/01-getting-started.md +338 -0
- package/docs/GUIDE/02-resources-and-relationships.md +33 -0
- package/docs/GUIDE/03-running-example.md +87 -0
- package/docs/GUIDE/04-creating-and-querying.md +181 -0
- package/docs/GUIDE/05-belongs-to.md +177 -0
- package/docs/GUIDE/06-has-many.md +184 -0
- package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
- package/docs/GUIDE/08-many-to-many.md +184 -0
- package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
- package/docs/GUIDE/10-put-and-patch.md +174 -0
- package/docs/GUIDE/11-relationship-endpoints.md +174 -0
- package/docs/GUIDE/12-field-transformations.md +287 -0
- package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
- package/docs/GUIDE/14-custom-resource-methods.md +125 -0
- package/docs/GUIDE/15-query-projections.md +266 -0
- package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
- package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
- package/docs/GUIDE/18-labels.md +86 -0
- package/docs/GUIDE/19-managed-transactions.md +179 -0
- package/docs/GUIDE/20-transaction-outcomes.md +207 -0
- package/docs/GUIDE/21-schema-and-migrations.md +733 -0
- package/docs/GUIDE/22-version-field-migrations.md +208 -0
- package/docs/GUIDE/23-fastify.md +179 -0
- package/docs/GUIDE/24-cors.md +172 -0
- package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
- package/docs/GUIDE/26-file-uploads.md +278 -0
- package/docs/GUIDE/27-bulk-operations.md +277 -0
- package/docs/GUIDE/28-socketio.md +325 -0
- package/docs/GUIDE/29-writing-plugins.md +278 -0
- package/docs/GUIDE/30-backend-capabilities.md +103 -0
- package/docs/GUIDE/31-positioning.md +181 -0
- package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +74 -30
- package/docs/GUIDE/33-migrating-to-v2.md +3838 -0
- package/docs/GUIDE/index.md +51 -59
- package/docs/QUICKSTART.md +120 -287
- package/docs/architecture.md +75 -0
- package/docs/contributing.md +178 -0
- package/index.d.ts +37 -0
- package/index.js +3 -22
- package/lib/enhanced-logger.js +91 -85
- package/lib/error-context.js +445 -5
- package/lib/error-formatter.js +219 -59
- package/lib/knex-transaction.js +70 -0
- package/lib/logger-types.d.ts +22 -0
- package/lib/missing-package.js +4 -0
- package/lib/rest-api-errors.js +103 -8
- package/lib/runtime/json-rest-api.js +172 -0
- package/lib/transaction-types.d.ts +59 -0
- package/package.json +97 -27
- package/plugins/core/bulk-operations-plugin.js +191 -184
- package/plugins/core/connectors/express-plugin.js +148 -219
- package/plugins/core/connectors/fastify-plugin.js +125 -82
- package/plugins/core/connectors/lib/busboy-detector.js +74 -156
- package/plugins/core/connectors/lib/connector-core.js +144 -20
- package/plugins/core/connectors/lib/formidable-detector.js +63 -120
- package/plugins/core/connectors/lib/http-validators.js +77 -0
- package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
- package/plugins/core/connectors/lib/request-helpers.js +10 -1
- package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
- package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
- package/plugins/core/file-handling-plugin.js +87 -177
- package/plugins/core/lib/anyapi/anyapi-registry.js +586 -418
- package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
- package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
- package/plugins/core/lib/anyapi/schema-utils.js +120 -56
- package/plugins/core/lib/anyapi/stored-definition.js +109 -0
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
- package/plugins/core/lib/dbIntrospection.js +228 -21
- package/plugins/core/lib/dbTablesOperations.js +409 -92
- package/plugins/core/lib/fractional-positioning.js +12 -48
- package/plugins/core/lib/querying/identifier-query.js +19 -0
- package/plugins/core/lib/querying/include-query-helpers.js +364 -0
- package/plugins/core/lib/querying/include-to-many.js +428 -0
- package/plugins/core/lib/querying/include-to-one.js +579 -0
- package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
- package/plugins/core/lib/querying/knex-pagination-helpers.js +48 -317
- package/plugins/core/lib/querying/knex-process-includes.js +5 -110
- package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
- package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
- package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
- package/plugins/core/lib/querying/knex-window-queries.js +62 -253
- package/plugins/core/lib/querying/query-builder-utils.js +44 -4
- package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
- package/plugins/core/lib/querying/query-constraint.js +27 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +134 -37
- package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
- package/plugins/core/lib/querying/sort-helpers.js +13 -1
- package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
- package/plugins/core/lib/querying/url-helpers.js +11 -4
- package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
- package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +179 -194
- package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
- package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
- package/plugins/core/lib/querying-writing/field-utils.js +113 -92
- package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
- package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +100 -290
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
- package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
- package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
- package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
- package/plugins/core/lib/querying-writing/request-contracts.js +93 -38
- package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
- package/plugins/core/lib/querying-writing/response-options.js +35 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
- package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
- package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
- package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
- package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
- package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
- package/plugins/core/lib/storage/storage-adapter.js +128 -62
- package/plugins/core/lib/storage/storage-mapping.js +78 -28
- package/plugins/core/lib/storage/storage-types.d.ts +502 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
- package/plugins/core/lib/writing/relationship-processor.js +94 -158
- package/plugins/core/lib/writing/resource-version.js +172 -0
- package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
- package/plugins/core/rest-api-anyapi-knex-plugin.js +290 -2475
- package/plugins/core/rest-api-autofilter-plugin.js +17 -19
- package/plugins/core/rest-api-cors-plugin.js +52 -205
- package/plugins/core/rest-api-knex-plugin.js +45 -1077
- package/plugins/core/rest-api-label-plugin.js +25 -38
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
- package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
- package/plugins/core/rest-api-plugin-methods/common.js +291 -395
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
- package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -148
- package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
- package/plugins/core/rest-api-plugin-methods/get.js +36 -68
- package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
- package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
- package/plugins/core/rest-api-plugin-methods/post.js +51 -51
- package/plugins/core/rest-api-plugin-methods/put.js +69 -148
- package/plugins/core/rest-api-plugin-methods/query.js +37 -81
- package/plugins/core/rest-api-plugin-methods/release.js +2 -1
- package/plugins/core/rest-api-plugin.js +32 -46
- package/plugins/core/rest-api-positioning-plugin.js +183 -628
- package/plugins/core/rest-api-query-projections-plugin.js +19 -102
- package/plugins/core/rest-api-row-policy-plugin.js +3 -3
- package/plugins/core/socketio-plugin.js +364 -344
- package/plugins/storage/local-storage.js +40 -36
- package/types/anyapi.d.ts +30 -0
- package/types/autofilter.d.ts +57 -0
- package/types/bulk-methods.d.ts +63 -0
- package/types/errors.d.ts +118 -0
- package/types/fastify-options.d.ts +19 -0
- package/types/file-detectors.d.ts +33 -0
- package/types/file-storage.d.ts +48 -0
- package/types/hook-context.d.ts +180 -0
- package/types/plugin-options.d.ts +65 -0
- package/types/relationship-methods.d.ts +74 -0
- package/types/representations.d.ts +50 -0
- package/types/resource-methods.d.ts +95 -0
- package/types/resource-schema.d.ts +157 -0
- package/types/row-policy.d.ts +31 -0
- package/types/runtime.d.ts +132 -0
- package/types/transactions.d.ts +21 -0
- package/.claude/agents/library-guide-expert.md +0 -30
- package/.claude/agents/rest-api-internals-expert.md +0 -54
- package/.claude/settings.local.json +0 -70
- package/AGENTS.md +0 -34
- package/CLAUDE.md +0 -160
- package/CRUSH.md +0 -55
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
- package/TODO.todo +0 -13
- package/connectors_ideas/fastify.js +0 -217
- package/connectors_ideas/koa-plugin.js +0 -112
- package/docs/.bundle/config +0 -2
- package/docs/COMPARISON.md +0 -433
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
- package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
- package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
- package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
- package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
- package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1247
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
- package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
- package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
- package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
- package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
- package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
- package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
- package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
- package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
- package/docs/Gemfile +0 -6
- package/docs/Gemfile.lock +0 -308
- package/docs/ONBOARDING.md +0 -315
- package/docs/_config.yml +0 -36
- package/docs/_layouts/default.html +0 -123
- package/docs/apple-touch-icon.svg +0 -4
- package/docs/assets/css/style.scss +0 -392
- package/docs/favicon.svg +0 -4
- package/docs/index.md +0 -164
- package/docs/mini-guides/file-uploads-complete.md +0 -161
- package/eslint.config.js +0 -13
- package/examples/url-override-example.js +0 -137
- package/fixing_plan.md +0 -112
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
- package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
- package/plugins/storage/s3-storage.js +0 -93
- package/quickTest.js +0 -136
- package/scripts/debug-anyapi-review-filter.mjs +0 -63
- package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
- package/scripts/inspect-anyapi-descriptor.mjs +0 -19
- package/scripts/run-docs.js +0 -133
- package/test-debug.js +0 -59
- package/tests/README.md +0 -202
- package/tests/TEST_TEMPLATE.test.js +0 -178
- package/tests/anyapi-basic.test.js +0 -105
- package/tests/anyapi-cursor-pagination.test.js +0 -148
- package/tests/anyapi-custom-idproperty.test.js +0 -163
- package/tests/autofilter.test.js +0 -463
- package/tests/bulk-operations.test.js +0 -657
- package/tests/computed-fields.test.js +0 -586
- package/tests/cors.test.js +0 -834
- package/tests/curl.test.js +0 -467
- package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
- package/tests/custom-id-simplified-post.test.js +0 -75
- package/tests/custom-idproperty-relationships.test.js +0 -932
- package/tests/db-introspection.test.js +0 -521
- package/tests/db-table-operations.test.js +0 -798
- package/tests/fastify-plugin.test.js +0 -184
- package/tests/field-getters.test.js +0 -370
- package/tests/field-setters.test.js +0 -306
- package/tests/file-handling.test.js +0 -155
- package/tests/fixtures/api-configs.js +0 -2566
- package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
- package/tests/helpers/fake-fastify.js +0 -99
- package/tests/helpers/storage-mode.js +0 -65
- package/tests/helpers/test-utils.js +0 -203
- package/tests/http-connectors-parity.test.js +0 -395
- package/tests/id-normalization.test.js +0 -444
- package/tests/include-depth-validation.test.js +0 -331
- package/tests/includes.test.js +0 -427
- package/tests/local-storage.test.js +0 -96
- package/tests/logical-id-write-validation.test.js +0 -151
- package/tests/nested-includes.test.js +0 -617
- package/tests/pagination-boundaries.test.js +0 -154
- package/tests/pagination-contract.test.js +0 -122
- package/tests/pagination-cursor-multifield.test.js +0 -641
- package/tests/pagination-enhanced.test.js +0 -563
- package/tests/polymorphic-relationships.test.js +0 -347
- package/tests/polymorphic-simple.test.js +0 -148
- package/tests/positioning-advanced.test.js +0 -692
- package/tests/positioning-extended.test.js +0 -915
- package/tests/positioning-multifilter.test.js +0 -699
- package/tests/positioning.test.js +0 -560
- package/tests/post-commit-hooks.test.js +0 -120
- package/tests/projected-fields.test.js +0 -319
- package/tests/public-exports.test.js +0 -15
- package/tests/put-create-parity.test.js +0 -216
- package/tests/queries.test.js +0 -521
- package/tests/query-limits.test.js +0 -584
- package/tests/relationship-endpoints.test.js +0 -620
- package/tests/relationship-include-storage-adapter.test.js +0 -56
- package/tests/relationships.test.js +0 -681
- package/tests/rest-api.test.js +0 -337
- package/tests/return-record-settings.test.js +0 -184
- package/tests/row-policy.test.js +0 -489
- package/tests/s3-storage.test.js +0 -38
- package/tests/searchschema-knex-behavior.test.js +0 -187
- package/tests/searchschema-merge.test.js +0 -151
- package/tests/socketio.test.js +0 -860
- package/tests/storage-mapping.test.js +0 -362
- package/tests/temporal-boundaries.test.js +0 -208
- package/tests/test-development-guide.md +0 -370
- package/tests/virtual-fields.test.js +0 -404
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @import {
|
|
3
|
+
* CompletedWriteContext, LifecycleArguments
|
|
4
|
+
* } from './lifecycle-types.js' */
|
|
5
|
+
import { applyResourceVersion, captureInverseVersions, invalidateInverseVersions } from '../lib/writing/resource-version.js'
|
|
6
|
+
import { RestApiResourceError } from '../../../lib/rest-api-errors.js'
|
|
7
|
+
import { lockRelationshipParent, lockRelationshipTargets, processRelationships } from '../lib/writing/relationship-processor.js'
|
|
8
|
+
import { updateReverseRelationship } from '../lib/writing/reverse-relationship-manipulations.js'
|
|
3
9
|
import { updateManyToManyRelationship } from '../lib/writing/many-to-many-manipulations.js'
|
|
4
10
|
import { ERROR_SUBTYPES } from '../lib/querying-writing/knex-constants.js'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
requireDocumentResourceId,
|
|
8
|
-
requireExistingResourceId
|
|
9
|
-
} from '../lib/querying-writing/resource-id-normalization.js'
|
|
11
|
+
import { validateUpdateRequest } from '../lib/querying-writing/request-contracts.js'
|
|
10
12
|
import {
|
|
11
13
|
setupCommonRequest,
|
|
14
|
+
writePrecondition,
|
|
12
15
|
validateResourceAttributesBeforeWrite,
|
|
13
16
|
validateRelationshipAccess,
|
|
14
17
|
applyFieldSetters,
|
|
@@ -19,103 +22,46 @@ import {
|
|
|
19
22
|
} from './common.js'
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* For relationships, only the ones explicitly provided will be updated.
|
|
27
|
-
* Just like PUT, it CANNOT have the `included` array in data.
|
|
25
|
+
* Update only supplied attributes and relationships on an existing resource.
|
|
26
|
+
* Input normalization, selected write response and transaction ownership use
|
|
27
|
+
* the same contracts as POST/PUT; omitted fields remain unchanged.
|
|
28
|
+
* @param {LifecycleArguments} args
|
|
28
29
|
*/
|
|
29
30
|
export default async function patchMethod ({
|
|
30
31
|
params,
|
|
31
|
-
context,
|
|
32
|
+
context: callerContext,
|
|
32
33
|
vars,
|
|
33
34
|
helpers,
|
|
34
35
|
scope,
|
|
35
36
|
scopes,
|
|
36
37
|
runHooks,
|
|
37
|
-
apiOptions,
|
|
38
|
-
pluginOptions,
|
|
39
38
|
scopeOptions,
|
|
40
39
|
scopeName,
|
|
41
40
|
api,
|
|
42
41
|
log
|
|
43
42
|
}) {
|
|
44
|
-
|
|
43
|
+
callerContext.method = 'patch'
|
|
45
44
|
|
|
46
45
|
try {
|
|
47
|
-
const { schema,
|
|
46
|
+
const { schema, versionState, context: preparedContext } = await setupCommonRequest({
|
|
48
47
|
params,
|
|
49
|
-
context,
|
|
48
|
+
context: callerContext,
|
|
50
49
|
vars,
|
|
51
50
|
scopes,
|
|
52
|
-
scopeOptions,
|
|
53
51
|
scopeName,
|
|
54
52
|
api,
|
|
55
|
-
helpers
|
|
53
|
+
helpers,
|
|
54
|
+
runHooks
|
|
56
55
|
})
|
|
57
|
-
// Run early hooks for pre-processing (e.g., file handling)
|
|
58
56
|
await runHooks('beforeProcessing')
|
|
59
57
|
await runHooks('beforeProcessingPatch')
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
schemaInfo: context.schemaInfo,
|
|
64
|
-
includeDepthLimit: vars.includeDepthLimit,
|
|
65
|
-
sortableFields: vars.sortableFields
|
|
66
|
-
})
|
|
67
|
-
const normalizedPathId = params.id === undefined
|
|
68
|
-
? null
|
|
69
|
-
: requireExistingResourceId(params.id, {
|
|
70
|
-
scopeOptions,
|
|
71
|
-
vars,
|
|
72
|
-
scopeName
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
if (normalizedPathId && !context.inputRecord?.data?.id) {
|
|
76
|
-
context.inputRecord = {
|
|
77
|
-
...context.inputRecord,
|
|
78
|
-
data: {
|
|
79
|
-
...(context.inputRecord?.data || {}),
|
|
80
|
-
id: normalizedPathId
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
context.inputRecord = validateRequestContractOrThrow(
|
|
86
|
-
requestContracts.patch,
|
|
87
|
-
context.inputRecord,
|
|
88
|
-
'PATCH request body is invalid'
|
|
89
|
-
)
|
|
90
|
-
const normalizedBodyId = requireDocumentResourceId(context.inputRecord.data.id, {
|
|
91
|
-
scopeOptions,
|
|
92
|
-
vars
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
if (normalizedPathId && normalizedPathId !== normalizedBodyId) {
|
|
96
|
-
throw new RestApiValidationError(
|
|
97
|
-
`ID mismatch. URL path ID '${normalizedPathId}' does not match request body ID '${normalizedBodyId}'`,
|
|
98
|
-
{
|
|
99
|
-
fields: ['data.id'],
|
|
100
|
-
violations: [{
|
|
101
|
-
field: 'data.id',
|
|
102
|
-
rule: 'id_consistency',
|
|
103
|
-
message: 'Request body ID must match URL path ID when both are provided'
|
|
104
|
-
}]
|
|
105
|
-
}
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
context.inputRecord.data.id = normalizedBodyId
|
|
109
|
-
context.id = normalizedPathId || normalizedBodyId
|
|
59
|
+
validateUpdateRequest({ method: 'patch', params, context: preparedContext, vars, scopeOptions, scopeName })
|
|
60
|
+
const context = /** @type {CompletedWriteContext} */ (preparedContext)
|
|
110
61
|
|
|
111
|
-
// Validate that user has read access to all related resources
|
|
112
|
-
// This ensures users can only create relationships to resources they can access
|
|
113
62
|
await validateRelationshipAccess(context, context.inputRecord, helpers, api)
|
|
114
63
|
|
|
115
|
-
|
|
116
|
-
// Example: relationships.author -> author_id: '123' for storage
|
|
117
|
-
// Example: relationships.tags -> array of pivot records to create later (only for provided relationships in PATCH)
|
|
118
|
-
const { belongsToUpdates, manyToManyRelationships } = processRelationships(
|
|
64
|
+
const { belongsToUpdates, belongsToTargets, manyToManyRelationships, reverseRelationships } = processRelationships(
|
|
119
65
|
scope,
|
|
120
66
|
{ context }
|
|
121
67
|
)
|
|
@@ -138,18 +84,19 @@ export default async function patchMethod ({
|
|
|
138
84
|
if (!minimalRecord) {
|
|
139
85
|
throw new RestApiResourceError(
|
|
140
86
|
`Resource not found: ${scopeName}/${context.id}`,
|
|
141
|
-
ERROR_SUBTYPES.NOT_FOUND
|
|
87
|
+
{ subtype: ERROR_SUBTYPES.NOT_FOUND }
|
|
142
88
|
)
|
|
143
89
|
}
|
|
144
90
|
|
|
145
91
|
context.minimalRecord = minimalRecord
|
|
146
92
|
|
|
147
|
-
// Centralised checkPermissions function
|
|
148
93
|
await scope.checkPermissions({
|
|
149
94
|
method: 'patch',
|
|
150
95
|
originalContext: context,
|
|
151
96
|
})
|
|
152
97
|
|
|
98
|
+
await params[writePrecondition]?.()
|
|
99
|
+
|
|
153
100
|
// Merge belongsTo updates into attributes before patching the record
|
|
154
101
|
if (Object.keys(belongsToUpdates).length > 0) {
|
|
155
102
|
context.inputRecord.data.attributes = {
|
|
@@ -161,23 +108,23 @@ export default async function patchMethod ({
|
|
|
161
108
|
await runHooks('beforeDataCall')
|
|
162
109
|
await runHooks('beforeDataCallPatch')
|
|
163
110
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
context.schemaInfo,
|
|
169
|
-
context,
|
|
170
|
-
api,
|
|
171
|
-
helpers
|
|
172
|
-
)
|
|
111
|
+
await lockRelationshipTargets(api, context.transaction, belongsToTargets)
|
|
112
|
+
|
|
113
|
+
if (manyToManyRelationships.length || reverseRelationships.length) {
|
|
114
|
+
await lockRelationshipParent({ context, helpers, scopeName })
|
|
173
115
|
}
|
|
174
116
|
|
|
175
|
-
|
|
117
|
+
await applyFieldSetters(context, api, helpers)
|
|
118
|
+
const inverseVersions = await captureInverseVersions({ api, helpers, context, scopeName })
|
|
119
|
+
await applyResourceVersion({ state: versionState, context, helpers, scopeName })
|
|
120
|
+
|
|
176
121
|
await helpers.dataPatch({
|
|
177
122
|
scopeName,
|
|
178
123
|
context
|
|
179
124
|
})
|
|
180
125
|
|
|
126
|
+
await invalidateInverseVersions({ state: inverseVersions, context, helpers, api })
|
|
127
|
+
|
|
181
128
|
await runHooks('afterDataCallPatch')
|
|
182
129
|
await runHooks('afterDataCall')
|
|
183
130
|
|
|
@@ -201,6 +148,7 @@ export default async function patchMethod ({
|
|
|
201
148
|
await updateManyToManyRelationship(null, {
|
|
202
149
|
api,
|
|
203
150
|
context: {
|
|
151
|
+
...context,
|
|
204
152
|
resourceId: context.id,
|
|
205
153
|
relDef,
|
|
206
154
|
relData,
|
|
@@ -209,24 +157,23 @@ export default async function patchMethod ({
|
|
|
209
157
|
})
|
|
210
158
|
}
|
|
211
159
|
|
|
212
|
-
const
|
|
160
|
+
for (const { relDef, relData } of reverseRelationships) {
|
|
161
|
+
await updateReverseRelationship({ api, helpers, context, scopeName, relDef, relData })
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const response = await handleRecordReturnAfterWrite({
|
|
213
165
|
context,
|
|
214
166
|
scopeName,
|
|
215
167
|
api,
|
|
216
168
|
scopes,
|
|
217
|
-
schemaStructure,
|
|
218
|
-
schemaRelationships,
|
|
219
|
-
scopeOptions,
|
|
220
|
-
vars,
|
|
221
169
|
runHooks,
|
|
222
|
-
helpers
|
|
223
|
-
log
|
|
170
|
+
helpers
|
|
224
171
|
})
|
|
225
172
|
|
|
226
|
-
await commitOwnedTransaction(context
|
|
173
|
+
await commitOwnedTransaction(context)
|
|
227
174
|
|
|
228
|
-
return
|
|
175
|
+
return response
|
|
229
176
|
} catch (error) {
|
|
230
|
-
await handleWriteMethodError(error,
|
|
177
|
+
await handleWriteMethodError(error, callerContext, 'PATCH', scopeName, log)
|
|
231
178
|
}
|
|
232
179
|
}
|
|
@@ -1,58 +1,63 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @import {
|
|
3
|
+
* Identifier, RelationshipWriteArguments, WriteRelationshipContext
|
|
4
|
+
* } from './lifecycle-types.js' */
|
|
5
|
+
import { lockRelationshipParent } from '../lib/writing/relationship-processor.js'
|
|
6
|
+
import { advanceResourceVersion } from '../lib/writing/resource-version.js'
|
|
7
|
+
import { beginWriteTransaction } from '../../../lib/error-context.js'
|
|
8
|
+
import { rejectRemovedOptions, resolveFormat } from '../lib/querying-writing/response-options.js'
|
|
1
9
|
import { RestApiResourceError, RestApiValidationError } from '../../../lib/rest-api-errors.js'
|
|
2
10
|
import {
|
|
3
11
|
commitOwnedTransaction,
|
|
4
|
-
findRelationshipDefinition,
|
|
5
12
|
getVisibleRelationshipParent,
|
|
6
13
|
handleWriteMethodError,
|
|
14
|
+
validateRelationshipAccess,
|
|
7
15
|
validateRelationshipRoutePayload
|
|
8
16
|
} from './common.js'
|
|
9
17
|
import { createPivotRecords } from '../lib/writing/many-to-many-manipulations.js'
|
|
18
|
+
import { updateReverseRelationship } from '../lib/writing/reverse-relationship-manipulations.js'
|
|
19
|
+
import { findRelationshipDefinition } from '../lib/querying-writing/relationship-contracts.js'
|
|
10
20
|
import {
|
|
11
21
|
normalizeRelationshipIdentifiers,
|
|
12
22
|
requireExistingResourceId
|
|
13
23
|
} from '../lib/querying-writing/resource-id-normalization.js'
|
|
14
24
|
|
|
15
25
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
context.id = requireExistingResourceId(params.id, {
|
|
26
|
+
* Add the identifiers in params.relationshipData to a to-many relationship.
|
|
27
|
+
* Authorization and parent/version locking precede mutation. The method
|
|
28
|
+
* returns no resource and completes only an owned transaction.
|
|
29
|
+
* @param {RelationshipWriteArguments<Identifier[]>} args
|
|
30
|
+
*/
|
|
31
|
+
export default async function postRelationshipMethod ({ params, context: callerContext, vars, helpers, scope, scopes, runHooks, scopeOptions, scopeName, api, log }) {
|
|
32
|
+
rejectRemovedOptions(params)
|
|
33
|
+
if (params.format !== undefined) resolveFormat(params.format)
|
|
34
|
+
callerContext.method = 'postRelationship'
|
|
35
|
+
callerContext.scopeName = scopeName
|
|
36
|
+
callerContext.id = requireExistingResourceId(params.id, {
|
|
28
37
|
scopeOptions,
|
|
29
38
|
vars,
|
|
30
39
|
scopeName
|
|
31
40
|
})
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
callerContext.relationshipName = params.relationshipName
|
|
42
|
+
callerContext.schemaInfo = scope.vars.schemaInfo
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
context.shouldCommit = !params.transaction && !!context.transaction
|
|
39
|
-
|
|
40
|
-
context.db = context.transaction || api.knex.instance
|
|
44
|
+
await beginWriteTransaction(callerContext, params.transaction, helpers.newTransaction, runHooks)
|
|
45
|
+
callerContext.db = callerContext.transaction || api.knex.instance
|
|
46
|
+
const context = /** @type {WriteRelationshipContext} */ (callerContext)
|
|
41
47
|
|
|
42
48
|
try {
|
|
43
|
-
// Validate
|
|
44
49
|
const relDef = findRelationshipDefinition(context.schemaInfo, context.relationshipName)
|
|
45
50
|
if (!relDef) {
|
|
46
51
|
throw new RestApiResourceError(
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
`Relationship '${context.relationshipName}' not found on resource '${scopeName}'`,
|
|
53
|
+
{ subtype: 'relationship_not_found' }
|
|
49
54
|
)
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
if (relDef.type !== 'hasMany' && relDef.type !== 'manyToMany') {
|
|
53
58
|
throw new RestApiValidationError(
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
`Cannot POST to to-one relationship '${context.relationshipName}'. Use PATCH instead.`,
|
|
60
|
+
{ fields: ['data'] }
|
|
56
61
|
)
|
|
57
62
|
}
|
|
58
63
|
|
|
@@ -63,7 +68,7 @@ export default async function postRelationshipMethod ({ params, context, vars, h
|
|
|
63
68
|
operation: 'postRelationship',
|
|
64
69
|
relationshipData: params.relationshipData
|
|
65
70
|
})
|
|
66
|
-
params.relationshipData = normalizeRelationshipIdentifiers(params.relationshipData, { api })
|
|
71
|
+
params.relationshipData = /** @type {Identifier[]} */ (normalizeRelationshipIdentifiers(params.relationshipData, { api }))
|
|
67
72
|
|
|
68
73
|
// Check permissions
|
|
69
74
|
await runHooks('checkPermissions')
|
|
@@ -80,6 +85,18 @@ export default async function postRelationshipMethod ({ params, context, vars, h
|
|
|
80
85
|
if (!parentRecord) {
|
|
81
86
|
throw new RestApiResourceError('Resource not found', { subtype: 'not_found' })
|
|
82
87
|
}
|
|
88
|
+
context.minimalRecord = parentRecord
|
|
89
|
+
context.originalMinimalRecord = parentRecord
|
|
90
|
+
|
|
91
|
+
await runHooks('beforeDataCall')
|
|
92
|
+
await runHooks('beforeDataCallPostRelationship')
|
|
93
|
+
|
|
94
|
+
const revision = await advanceResourceVersion({ scopeName, context, helpers, expectedVersion: params.expectedVersion })
|
|
95
|
+
if (revision === undefined) await lockRelationshipParent({ context, helpers, scopeName })
|
|
96
|
+
|
|
97
|
+
await validateRelationshipAccess(context, {
|
|
98
|
+
data: { relationships: { [context.relationshipName]: { data: params.relationshipData } } }
|
|
99
|
+
}, helpers, api)
|
|
83
100
|
|
|
84
101
|
// Add relationships
|
|
85
102
|
if (relDef?.through) {
|
|
@@ -92,38 +109,17 @@ export default async function postRelationshipMethod ({ params, context, vars, h
|
|
|
92
109
|
relData: params.relationshipData,
|
|
93
110
|
})
|
|
94
111
|
} else {
|
|
95
|
-
await createPivotRecords(api, context.id,
|
|
96
|
-
through: relDef.through,
|
|
97
|
-
foreignKey: relDef.foreignKey,
|
|
98
|
-
otherKey: relDef.otherKey
|
|
99
|
-
}, params.relationshipData, context.transaction, context)
|
|
112
|
+
await createPivotRecords(api, context.id, relDef, params.relationshipData, context.transaction)
|
|
100
113
|
}
|
|
101
114
|
} else if (relDef.type === 'hasMany') {
|
|
102
|
-
|
|
103
|
-
const targetType = relDef.target
|
|
104
|
-
for (const identifier of params.relationshipData) {
|
|
105
|
-
await api.resources[targetType].patch({
|
|
106
|
-
id: identifier.id,
|
|
107
|
-
inputRecord: {
|
|
108
|
-
data: {
|
|
109
|
-
type: targetType,
|
|
110
|
-
id: identifier.id,
|
|
111
|
-
attributes: { [relDef.foreignKey]: context.id }
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
transaction: context.transaction,
|
|
115
|
-
simplified: false
|
|
116
|
-
}, { ...context })
|
|
117
|
-
}
|
|
115
|
+
await updateReverseRelationship({ api, helpers, context, scopeName, relDef, relData: params.relationshipData, operation: 'add' })
|
|
118
116
|
}
|
|
119
117
|
|
|
120
118
|
await runHooks('finish')
|
|
121
119
|
await runHooks('finishPostRelationship')
|
|
122
120
|
|
|
123
|
-
await commitOwnedTransaction(context
|
|
124
|
-
|
|
125
|
-
// 204 No Content
|
|
121
|
+
await commitOwnedTransaction(context)
|
|
126
122
|
} catch (error) {
|
|
127
|
-
await handleWriteMethodError(error, context, 'POST_RELATIONSHIP', scopeName, log
|
|
123
|
+
await handleWriteMethodError(error, context, 'POST_RELATIONSHIP', scopeName, log)
|
|
128
124
|
}
|
|
129
|
-
}
|
|
125
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @import {
|
|
3
|
+
* CompletedWriteContext, LifecycleArguments, WriteContext
|
|
4
|
+
* } from './lifecycle-types.js' */
|
|
5
|
+
import { applyResourceVersion, captureInverseVersions, invalidateInverseVersions } from '../lib/writing/resource-version.js'
|
|
6
|
+
import { lockRelationshipTargets, processRelationships } from '../lib/writing/relationship-processor.js'
|
|
7
|
+
import { updateReverseRelationship } from '../lib/writing/reverse-relationship-manipulations.js'
|
|
2
8
|
import { getRequestContracts, validateRequestContractOrThrow } from '../lib/querying-writing/request-contracts.js'
|
|
3
9
|
import { createPivotRecords } from '../lib/writing/many-to-many-manipulations.js'
|
|
4
|
-
import { requireDocumentResourceId } from '../lib/querying-writing/resource-id-normalization.js'
|
|
10
|
+
import { defaultNormalizeResourceId, requireDocumentResourceId } from '../lib/querying-writing/resource-id-normalization.js'
|
|
5
11
|
import {
|
|
6
12
|
setupCommonRequest,
|
|
7
13
|
validateResourceAttributesBeforeWrite,
|
|
@@ -14,55 +20,53 @@ import {
|
|
|
14
20
|
} from './common.js'
|
|
15
21
|
|
|
16
22
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
23
|
+
* Create a resource from plain data or a JSON:API document.
|
|
24
|
+
* Supplied IDs and existing-resource linkage are validated before writing.
|
|
25
|
+
* Prepare the selected returning result before completing an owned transaction.
|
|
26
|
+
* @param {LifecycleArguments} args
|
|
21
27
|
*/
|
|
22
28
|
export default async function postMethod ({
|
|
23
29
|
params,
|
|
24
|
-
context,
|
|
30
|
+
context: callerContext,
|
|
25
31
|
vars,
|
|
26
32
|
helpers,
|
|
27
33
|
scope,
|
|
28
34
|
scopes,
|
|
29
35
|
runHooks,
|
|
30
|
-
apiOptions,
|
|
31
|
-
pluginOptions,
|
|
32
36
|
scopeOptions,
|
|
33
37
|
scopeName,
|
|
34
38
|
api,
|
|
35
39
|
log
|
|
36
40
|
}) {
|
|
37
|
-
|
|
41
|
+
callerContext.method = 'post'
|
|
38
42
|
|
|
39
43
|
try {
|
|
40
|
-
const { schema,
|
|
44
|
+
const { schema, versionState, context: preparedContext } = await setupCommonRequest({
|
|
41
45
|
params,
|
|
42
|
-
context,
|
|
46
|
+
context: callerContext,
|
|
43
47
|
vars,
|
|
44
48
|
scopes,
|
|
45
|
-
scopeOptions,
|
|
46
49
|
scopeName,
|
|
47
50
|
api,
|
|
48
|
-
helpers
|
|
51
|
+
helpers,
|
|
52
|
+
runHooks
|
|
49
53
|
})
|
|
50
54
|
|
|
51
|
-
// Run early hooks for pre-processing (e.g., file handling)
|
|
52
55
|
await runHooks('beforeProcessing')
|
|
53
56
|
await runHooks('beforeProcessingPost')
|
|
54
57
|
|
|
55
58
|
const requestContracts = getRequestContracts({
|
|
56
59
|
scopeName,
|
|
57
|
-
schemaInfo:
|
|
60
|
+
schemaInfo: preparedContext.schemaInfo,
|
|
58
61
|
includeDepthLimit: vars.includeDepthLimit,
|
|
59
62
|
sortableFields: vars.sortableFields
|
|
60
63
|
})
|
|
61
|
-
|
|
64
|
+
preparedContext.inputRecord = validateRequestContractOrThrow(
|
|
62
65
|
requestContracts.post,
|
|
63
|
-
|
|
66
|
+
preparedContext.inputRecord,
|
|
64
67
|
'POST request body is invalid'
|
|
65
68
|
)
|
|
69
|
+
const context = /** @type {WriteContext} */ (preparedContext)
|
|
66
70
|
|
|
67
71
|
if (context.inputRecord?.data?.id !== undefined) {
|
|
68
72
|
context.inputRecord.data.id = requireDocumentResourceId(context.inputRecord.data.id, {
|
|
@@ -71,14 +75,9 @@ export default async function postMethod ({
|
|
|
71
75
|
})
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
// Validate that user has read access to all related resources
|
|
75
|
-
// This ensures users can only create relationships to resources they can access
|
|
76
78
|
await validateRelationshipAccess(context, context.inputRecord, helpers, api)
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
// Example: relationships.author -> author_id: '123' for storage
|
|
80
|
-
// Example: relationships.tags -> array of pivot records to create later
|
|
81
|
-
const { belongsToUpdates, manyToManyRelationships } = await processRelationships(
|
|
80
|
+
const { belongsToUpdates, belongsToTargets, manyToManyRelationships, reverseRelationships } = await processRelationships(
|
|
82
81
|
scope,
|
|
83
82
|
{ context }
|
|
84
83
|
)
|
|
@@ -108,7 +107,6 @@ export default async function postMethod ({
|
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
// Centralised checkPermissions function
|
|
112
110
|
await scope.checkPermissions({
|
|
113
111
|
method: 'post',
|
|
114
112
|
originalContext: context,
|
|
@@ -117,23 +115,27 @@ export default async function postMethod ({
|
|
|
117
115
|
await runHooks('beforeDataCall')
|
|
118
116
|
await runHooks('beforeDataCallPost')
|
|
119
117
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
context,
|
|
126
|
-
api,
|
|
127
|
-
helpers
|
|
128
|
-
)
|
|
129
|
-
}
|
|
118
|
+
await lockRelationshipTargets(api, context.transaction, belongsToTargets)
|
|
119
|
+
|
|
120
|
+
await applyFieldSetters(context, api, helpers)
|
|
121
|
+
const inverseVersions = await captureInverseVersions({ api, helpers, context, scopeName, isCreate: true })
|
|
122
|
+
await applyResourceVersion({ state: versionState, context, helpers, scopeName, isCreate: true })
|
|
130
123
|
|
|
131
|
-
// Create the main record
|
|
132
|
-
|
|
124
|
+
// Create the main record and retain the logical ID returned by storage.
|
|
125
|
+
const storedId = await helpers.dataPost({
|
|
133
126
|
scopeName,
|
|
134
127
|
context
|
|
135
128
|
})
|
|
136
129
|
|
|
130
|
+
const resourceId = typeof storedId === 'bigint' ? String(storedId) : storedId
|
|
131
|
+
if ((typeof resourceId !== 'string' && typeof resourceId !== 'number') || !defaultNormalizeResourceId(resourceId)) {
|
|
132
|
+
throw new Error('Storage POST did not return a valid resource ID')
|
|
133
|
+
}
|
|
134
|
+
context.id = resourceId
|
|
135
|
+
const completedContext = /** @type {CompletedWriteContext} */ (context)
|
|
136
|
+
|
|
137
|
+
await invalidateInverseVersions({ state: inverseVersions, context, helpers, api })
|
|
138
|
+
|
|
137
139
|
await runHooks('afterDataCallPost')
|
|
138
140
|
await runHooks('afterDataCall')
|
|
139
141
|
|
|
@@ -141,7 +143,7 @@ export default async function postMethod ({
|
|
|
141
143
|
for (const { relName, relDef, relData } of manyToManyRelationships) {
|
|
142
144
|
if (api.anyapi?.links?.attachMany && relDef?.through) {
|
|
143
145
|
await api.anyapi.links.attachMany({
|
|
144
|
-
context,
|
|
146
|
+
context: completedContext,
|
|
145
147
|
scopeName,
|
|
146
148
|
relName,
|
|
147
149
|
relDef,
|
|
@@ -150,29 +152,27 @@ export default async function postMethod ({
|
|
|
150
152
|
continue
|
|
151
153
|
}
|
|
152
154
|
|
|
153
|
-
// Validate pivot resource exists
|
|
154
155
|
validatePivotResource(scopes, relDef, relName)
|
|
155
|
-
await createPivotRecords(api, context.id, relDef, relData, context.transaction
|
|
156
|
+
await createPivotRecords(api, context.id, relDef, relData, context.transaction)
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
const
|
|
159
|
-
context,
|
|
159
|
+
for (const { relDef, relData } of reverseRelationships) {
|
|
160
|
+
await updateReverseRelationship({ api, helpers, context, scopeName, relDef, relData })
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const response = await handleRecordReturnAfterWrite({
|
|
164
|
+
context: completedContext,
|
|
160
165
|
scopeName,
|
|
161
166
|
api,
|
|
162
167
|
scopes,
|
|
163
|
-
schemaStructure,
|
|
164
|
-
schemaRelationships,
|
|
165
|
-
scopeOptions,
|
|
166
|
-
vars,
|
|
167
168
|
runHooks,
|
|
168
|
-
helpers
|
|
169
|
-
log
|
|
169
|
+
helpers
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
-
await commitOwnedTransaction(context
|
|
172
|
+
await commitOwnedTransaction(context)
|
|
173
173
|
|
|
174
|
-
return
|
|
174
|
+
return response
|
|
175
175
|
} catch (error) {
|
|
176
|
-
await handleWriteMethodError(error,
|
|
176
|
+
await handleWriteMethodError(error, callerContext, 'POST', scopeName, log)
|
|
177
177
|
}
|
|
178
178
|
}
|