json-rest-api 1.0.13 → 1.0.15
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/connectors_ideas/fastify.js +66 -68
- package/connectors_ideas/koa-plugin.js +50 -51
- package/eslint.config.js +13 -0
- package/examples/url-override-example.js +63 -63
- package/index.js +13 -13
- package/lib/enhanced-logger.js +51 -51
- package/lib/error-formatter.js +61 -61
- package/lib/rest-api-errors.js +28 -28
- package/package.json +9 -5
- package/plugins/core/bulk-operations-plugin.js +142 -145
- package/plugins/core/connectors/express-plugin.js +210 -217
- package/plugins/core/connectors/lib/busboy-detector.js +84 -84
- package/plugins/core/connectors/lib/formidable-detector.js +50 -50
- package/plugins/core/connectors/lib/request-helpers.js +74 -74
- package/plugins/core/file-handling-plugin.js +125 -125
- package/plugins/core/lib/anyapi/anyapi-registry.js +254 -254
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +287 -287
- package/plugins/core/lib/anyapi/schema-utils.js +101 -101
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +41 -41
- package/plugins/core/lib/dbTablesOperations.js +134 -135
- package/plugins/core/lib/fractional-positioning.js +74 -76
- package/plugins/core/lib/querying/knex-cross-table-search.js +320 -320
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +144 -144
- package/plugins/core/lib/querying/knex-pagination-helpers.js +164 -164
- package/plugins/core/lib/querying/knex-process-includes.js +50 -50
- package/plugins/core/lib/querying/knex-query-helpers-base.js +31 -31
- package/plugins/core/lib/querying/knex-query-helpers.js +451 -452
- package/plugins/core/lib/querying/knex-relationship-includes.js +1160 -1170
- package/plugins/core/lib/querying/knex-window-queries.js +89 -89
- package/plugins/core/lib/querying/url-helpers.js +35 -35
- package/plugins/core/lib/querying-writing/compile-schemas.js +97 -98
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +31 -31
- package/plugins/core/lib/querying-writing/database-capabilities.js +94 -94
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +76 -76
- package/plugins/core/lib/querying-writing/default-data-helpers.js +27 -27
- package/plugins/core/lib/querying-writing/field-utils.js +44 -42
- package/plugins/core/lib/querying-writing/knex-constants.js +15 -16
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +117 -115
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +41 -41
- package/plugins/core/lib/querying-writing/payload-validators.js +275 -275
- package/plugins/core/lib/querying-writing/schema-helpers.js +129 -129
- package/plugins/core/lib/querying-writing/scope-validations.js +143 -146
- package/plugins/core/lib/querying-writing/simplified-helpers.js +133 -129
- package/plugins/core/lib/storage/storage-adapter.js +68 -68
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +31 -31
- package/plugins/core/lib/writing/many-to-many-manipulations.js +81 -81
- package/plugins/core/lib/writing/relationship-processor.js +58 -58
- package/plugins/core/rest-api-access.js +8 -8
- package/plugins/core/rest-api-anyapi-knex-plugin.js +920 -920
- package/plugins/core/rest-api-cors-plugin.js +170 -171
- package/plugins/core/rest-api-knex-plugin.js +482 -493
- package/plugins/core/rest-api-multihome-plugin.js +247 -251
- package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +20 -21
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +44 -44
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +23 -23
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +15 -15
- package/plugins/core/rest-api-plugin-methods/add-route.js +9 -9
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +5 -6
- package/plugins/core/rest-api-plugin-methods/common.js +295 -297
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +35 -37
- package/plugins/core/rest-api-plugin-methods/delete.js +57 -59
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +172 -171
- package/plugins/core/rest-api-plugin-methods/get-related.js +96 -96
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +16 -18
- package/plugins/core/rest-api-plugin-methods/get.js +86 -86
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +16 -17
- package/plugins/core/rest-api-plugin-methods/patch.js +63 -64
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +54 -55
- package/plugins/core/rest-api-plugin-methods/post.js +61 -62
- package/plugins/core/rest-api-plugin-methods/put.js +86 -87
- package/plugins/core/rest-api-plugin-methods/query.js +88 -88
- package/plugins/core/rest-api-plugin-methods/release.js +5 -6
- package/plugins/core/rest-api-plugin.js +76 -78
- package/plugins/core/rest-api-positioning-plugin.js +251 -252
- package/plugins/core/socketio-plugin.js +240 -236
- package/plugins/storage/local-storage.js +103 -103
- package/plugins/storage/s3-storage.js +41 -42
- package/quickTest.js +37 -37
- package/scripts/debug-anyapi-review-filter.mjs +18 -18
- package/scripts/inspect-anyapi-descriptor-country.mjs +10 -10
- package/scripts/inspect-anyapi-descriptor.mjs +10 -10
- package/scripts/run-docs.js +112 -113
- package/test-debug.js +28 -28
- package/tests/TEST_TEMPLATE.test.js +51 -51
- package/tests/anyapi-basic.test.js +42 -42
- package/tests/anyapi-cursor-pagination.test.js +48 -48
- package/tests/bulk-operations.test.js +208 -208
- package/tests/computed-fields.test.js +204 -204
- package/tests/cors.test.js +412 -413
- package/tests/curl.test.js +275 -276
- package/tests/custom-idproperty-relationships.test.js +266 -266
- package/tests/field-getters.test.js +132 -132
- package/tests/field-setters.test.js +110 -110
- package/tests/fixtures/api-configs.js +699 -699
- package/tests/helpers/storage-mode.js +32 -32
- package/tests/helpers/test-utils.js +76 -76
- package/tests/include-depth-validation.test.js +76 -76
- package/tests/includes.test.js +145 -145
- package/tests/multihome.test.js +175 -175
- package/tests/nested-includes.test.js +255 -255
- package/tests/pagination-cursor-multifield.test.js +164 -164
- package/tests/pagination-enhanced.test.js +225 -225
- package/tests/polymorphic-relationships.test.js +96 -96
- package/tests/polymorphic-simple.test.js +44 -44
- package/tests/positioning-advanced.test.js +226 -226
- package/tests/positioning-extended.test.js +399 -399
- package/tests/positioning-multifilter.test.js +204 -204
- package/tests/positioning.test.js +266 -266
- package/tests/queries.test.js +184 -184
- package/tests/query-limits.test.js +154 -155
- package/tests/relationship-endpoints.test.js +127 -127
- package/tests/relationships.test.js +178 -179
- package/tests/rest-api-access.test.js +86 -86
- package/tests/rest-api.test.js +103 -103
- package/tests/searchschema-merge.test.js +93 -93
- package/tests/socketio.test.js +326 -326
- package/tests/virtual-fields.test.js +164 -164
|
@@ -1,62 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { findRelationshipDefinition, handleWriteMethodError } from "./common.js";
|
|
1
|
+
import { RestApiResourceError, RestApiValidationError, RestApiPayloadError } from '../../../lib/rest-api-errors.js'
|
|
2
|
+
import { findRelationshipDefinition, handleWriteMethodError } from './common.js'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* DELETE RELATIONSHIP
|
|
7
6
|
* Removes specific members from a to-many relationship
|
|
8
7
|
* DELETE /api/articles/1/relationships/tags
|
|
9
|
-
*
|
|
8
|
+
*
|
|
10
9
|
* @param {string} id - The ID of the resource
|
|
11
10
|
* @param {string} relationshipName - The name of the relationship
|
|
12
11
|
* @param {array} relationshipData - Array of resource identifiers to remove
|
|
13
12
|
* @returns {Promise<void>} 204 No Content
|
|
14
13
|
*/
|
|
15
|
-
export default async function deleteRelationshipMethod({ params, context, vars, helpers, scope, scopes, runHooks, scopeName, api, log }) {
|
|
16
|
-
context.method = 'deleteRelationship'
|
|
17
|
-
context.id = params.id
|
|
18
|
-
context.relationshipName = params.relationshipName
|
|
19
|
-
context.schemaInfo = scopes[scopeName].vars.schemaInfo
|
|
14
|
+
export default async function deleteRelationshipMethod ({ params, context, vars, helpers, scope, scopes, runHooks, scopeName, api, log }) {
|
|
15
|
+
context.method = 'deleteRelationship'
|
|
16
|
+
context.id = params.id
|
|
17
|
+
context.relationshipName = params.relationshipName
|
|
18
|
+
context.schemaInfo = scopes[scopeName].vars.schemaInfo
|
|
20
19
|
|
|
21
20
|
// Transaction handling
|
|
22
|
-
context.transaction = params.transaction ||
|
|
23
|
-
(helpers.newTransaction && !params.transaction ? await helpers.newTransaction() : null)
|
|
24
|
-
context.shouldCommit = !params.transaction && !!context.transaction
|
|
21
|
+
context.transaction = params.transaction ||
|
|
22
|
+
(helpers.newTransaction && !params.transaction ? await helpers.newTransaction() : null)
|
|
23
|
+
context.shouldCommit = !params.transaction && !!context.transaction
|
|
25
24
|
context.db = context.transaction || api.knex.instance
|
|
26
25
|
|
|
27
26
|
try {
|
|
28
27
|
// Validate
|
|
29
|
-
const relDef = findRelationshipDefinition(context.schemaInfo, context.relationshipName)
|
|
28
|
+
const relDef = findRelationshipDefinition(context.schemaInfo, context.relationshipName)
|
|
30
29
|
if (!relDef) {
|
|
31
30
|
throw new RestApiResourceError(
|
|
32
31
|
`Relationship '${context.relationshipName}' not found on resource '${scopeName}'`,
|
|
33
32
|
{ subtype: 'relationship_not_found' }
|
|
34
|
-
)
|
|
33
|
+
)
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
if (relDef.type !== 'hasMany' && relDef.type !== 'manyToMany') {
|
|
38
37
|
throw new RestApiValidationError(
|
|
39
38
|
`Cannot DELETE from to-one relationship '${context.relationshipName}'`,
|
|
40
39
|
{ fields: ['data'] }
|
|
41
|
-
)
|
|
40
|
+
)
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
if (!Array.isArray(params.relationshipData)) {
|
|
45
|
-
throw new RestApiPayloadError('DELETE from relationship requires array of resource identifiers')
|
|
44
|
+
throw new RestApiPayloadError('DELETE from relationship requires array of resource identifiers')
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
// Check permissions
|
|
49
|
-
await runHooks('checkPermissions')
|
|
50
|
-
await runHooks('checkPermissionsDeleteRelationship')
|
|
48
|
+
await runHooks('checkPermissions')
|
|
49
|
+
await runHooks('checkPermissionsDeleteRelationship')
|
|
51
50
|
|
|
52
51
|
// Verify parent exists
|
|
53
52
|
const exists = await helpers.dataExists({
|
|
54
53
|
scopeName,
|
|
55
|
-
context: {
|
|
56
|
-
})
|
|
54
|
+
context: { db: context.db, id: context.id, schemaInfo: context.schemaInfo }
|
|
55
|
+
})
|
|
57
56
|
|
|
58
57
|
if (!exists) {
|
|
59
|
-
throw new RestApiResourceError('Resource not found', { subtype: 'not_found' })
|
|
58
|
+
throw new RestApiResourceError('Resource not found', { subtype: 'not_found' })
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
// Remove relationships
|
|
@@ -68,26 +67,26 @@ export default async function deleteRelationshipMethod({ params, context, vars,
|
|
|
68
67
|
relName: context.relationshipName,
|
|
69
68
|
relDef,
|
|
70
69
|
relData: params.relationshipData,
|
|
71
|
-
})
|
|
70
|
+
})
|
|
72
71
|
} else {
|
|
73
|
-
const knex = api.knex?.instance || helpers.db
|
|
74
|
-
const pivotResource = relDef.through
|
|
75
|
-
const pivotScope = api.resources[pivotResource]
|
|
76
|
-
const pivotTable = pivotScope?.vars?.schemaInfo?.tableName || pivotResource
|
|
77
|
-
const localKey = relDef.foreignKey
|
|
78
|
-
const foreignKey = relDef.otherKey
|
|
72
|
+
const knex = api.knex?.instance || helpers.db
|
|
73
|
+
const pivotResource = relDef.through
|
|
74
|
+
const pivotScope = api.resources[pivotResource]
|
|
75
|
+
const pivotTable = pivotScope?.vars?.schemaInfo?.tableName || pivotResource
|
|
76
|
+
const localKey = relDef.foreignKey
|
|
77
|
+
const foreignKey = relDef.otherKey
|
|
79
78
|
|
|
80
79
|
for (const identifier of params.relationshipData) {
|
|
81
80
|
await knex(pivotTable)
|
|
82
81
|
.where(localKey, context.id)
|
|
83
82
|
.where(foreignKey, identifier.id)
|
|
84
83
|
.delete()
|
|
85
|
-
.transacting(context.transaction)
|
|
84
|
+
.transacting(context.transaction)
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
} else {
|
|
89
88
|
// Null out foreign keys for hasMany
|
|
90
|
-
const targetType = relDef.target
|
|
89
|
+
const targetType = relDef.target
|
|
91
90
|
for (const identifier of params.relationshipData) {
|
|
92
91
|
await api.resources[targetType].patch({
|
|
93
92
|
id: identifier.id,
|
|
@@ -100,20 +99,19 @@ export default async function deleteRelationshipMethod({ params, context, vars,
|
|
|
100
99
|
},
|
|
101
100
|
transaction: context.transaction,
|
|
102
101
|
simplified: false
|
|
103
|
-
})
|
|
102
|
+
})
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
await runHooks('finish')
|
|
108
|
-
await runHooks('finishDeleteRelationship')
|
|
106
|
+
await runHooks('finish')
|
|
107
|
+
await runHooks('finishDeleteRelationship')
|
|
109
108
|
|
|
110
109
|
if (context.shouldCommit) {
|
|
111
|
-
await context.transaction.commit()
|
|
110
|
+
await context.transaction.commit()
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
// 204 No Content
|
|
116
114
|
} catch (error) {
|
|
117
|
-
await handleWriteMethodError(error, context, 'DELETE_RELATIONSHIP', scopeName, log, runHooks)
|
|
115
|
+
await handleWriteMethodError(error, context, 'DELETE_RELATIONSHIP', scopeName, log, runHooks)
|
|
118
116
|
}
|
|
119
117
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RestApiResourceError } from '../../../lib/rest-api-errors.js'
|
|
2
|
-
import { handleWriteMethodError } from './common.js'
|
|
1
|
+
import { RestApiResourceError } from '../../../lib/rest-api-errors.js'
|
|
2
|
+
import { handleWriteMethodError } from './common.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* DELETE
|
|
@@ -7,100 +7,98 @@ import { handleWriteMethodError } from './common.js';
|
|
|
7
7
|
* Returns 204 No Content on success, indicating the resource has been removed.
|
|
8
8
|
* This method does not return the deleted resource.
|
|
9
9
|
*/
|
|
10
|
-
export default async function deleteMethod({
|
|
11
|
-
params,
|
|
12
|
-
context,
|
|
13
|
-
vars,
|
|
14
|
-
helpers,
|
|
15
|
-
scope,
|
|
16
|
-
scopes,
|
|
17
|
-
runHooks,
|
|
18
|
-
apiOptions,
|
|
19
|
-
pluginOptions,
|
|
20
|
-
scopeOptions,
|
|
10
|
+
export default async function deleteMethod ({
|
|
11
|
+
params,
|
|
12
|
+
context,
|
|
13
|
+
vars,
|
|
14
|
+
helpers,
|
|
15
|
+
scope,
|
|
16
|
+
scopes,
|
|
17
|
+
runHooks,
|
|
18
|
+
apiOptions,
|
|
19
|
+
pluginOptions,
|
|
20
|
+
scopeOptions,
|
|
21
21
|
scopeName,
|
|
22
22
|
api,
|
|
23
23
|
log
|
|
24
24
|
}) {
|
|
25
25
|
// Make the method available to all hooks
|
|
26
|
-
context.method = 'delete'
|
|
27
|
-
|
|
26
|
+
context.method = 'delete'
|
|
27
|
+
|
|
28
28
|
// Set the ID in context
|
|
29
|
-
context.id = params.id
|
|
30
|
-
|
|
29
|
+
context.id = params.id
|
|
30
|
+
|
|
31
31
|
// Set scopeName in context (needed for broadcasting)
|
|
32
|
-
context.scopeName = scopeName
|
|
33
|
-
|
|
32
|
+
context.scopeName = scopeName
|
|
33
|
+
|
|
34
34
|
// Set schema info even for DELETE (needed by storage layer)
|
|
35
|
-
context.schemaInfo = scopes[scopeName].vars.schemaInfo
|
|
36
|
-
|
|
35
|
+
context.schemaInfo = scopes[scopeName].vars.schemaInfo
|
|
36
|
+
|
|
37
37
|
// Transaction handling
|
|
38
|
-
context.transaction = params.transaction ||
|
|
39
|
-
(helpers.newTransaction && !params.transaction ? await helpers.newTransaction() : null)
|
|
40
|
-
context.shouldCommit = !params.transaction && !!context.transaction
|
|
41
|
-
context.db = context.transaction || api.knex.instance
|
|
42
|
-
|
|
38
|
+
context.transaction = params.transaction ||
|
|
39
|
+
(helpers.newTransaction && !params.transaction ? await helpers.newTransaction() : null)
|
|
40
|
+
context.shouldCommit = !params.transaction && !!context.transaction
|
|
41
|
+
context.db = context.transaction || api.knex.instance
|
|
42
|
+
|
|
43
43
|
try {
|
|
44
44
|
// No payload validation needed for DELETE
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
// Fetch minimal record for authorization and logging
|
|
47
47
|
const minimalRecord = await helpers.dataGetMinimal({
|
|
48
48
|
scopeName,
|
|
49
49
|
context,
|
|
50
50
|
runHooks
|
|
51
|
-
})
|
|
52
|
-
|
|
51
|
+
})
|
|
52
|
+
|
|
53
53
|
if (!minimalRecord) {
|
|
54
54
|
throw new RestApiResourceError(
|
|
55
|
-
|
|
56
|
-
{
|
|
55
|
+
'Resource not found',
|
|
56
|
+
{
|
|
57
57
|
subtype: 'not_found',
|
|
58
58
|
resourceType: scopeName,
|
|
59
59
|
resourceId: context.id
|
|
60
60
|
}
|
|
61
|
-
)
|
|
61
|
+
)
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
context.originalMinimalRecord = minimalRecord
|
|
65
|
-
context.minimalRecord = minimalRecord
|
|
66
|
-
|
|
63
|
+
|
|
64
|
+
context.originalMinimalRecord = minimalRecord
|
|
65
|
+
context.minimalRecord = minimalRecord
|
|
66
|
+
|
|
67
67
|
// Centralised checkPermissions function
|
|
68
68
|
await scope.checkPermissions({
|
|
69
69
|
method: 'delete',
|
|
70
70
|
originalContext: context,
|
|
71
|
-
})
|
|
72
|
-
|
|
71
|
+
})
|
|
72
|
+
|
|
73
73
|
// Before data operations
|
|
74
|
-
await runHooks('beforeDataCall')
|
|
75
|
-
await runHooks('beforeDataCallDelete')
|
|
76
|
-
|
|
74
|
+
await runHooks('beforeDataCall')
|
|
75
|
+
await runHooks('beforeDataCallDelete')
|
|
76
|
+
|
|
77
77
|
// Initialize record context for hooks
|
|
78
|
-
context.record = {}
|
|
79
|
-
|
|
78
|
+
context.record = {}
|
|
79
|
+
|
|
80
80
|
// Call the storage helper
|
|
81
81
|
await helpers.dataDelete({
|
|
82
82
|
scopeName,
|
|
83
83
|
context
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
await runHooks('afterDataCallDelete')
|
|
87
|
-
await runHooks('afterDataCall')
|
|
88
|
-
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
await runHooks('afterDataCallDelete')
|
|
87
|
+
await runHooks('afterDataCall')
|
|
88
|
+
|
|
89
89
|
// No return record for DELETE (204 No Content)
|
|
90
|
-
|
|
91
|
-
await runHooks('finish')
|
|
92
|
-
await runHooks('finishDelete')
|
|
93
|
-
|
|
90
|
+
|
|
91
|
+
await runHooks('finish')
|
|
92
|
+
await runHooks('finishDelete')
|
|
93
|
+
|
|
94
94
|
// Commit transaction if we created it
|
|
95
95
|
if (context.shouldCommit) {
|
|
96
|
-
await context.transaction.commit()
|
|
97
|
-
await runHooks('afterCommit')
|
|
96
|
+
await context.transaction.commit()
|
|
97
|
+
await runHooks('afterCommit')
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
// DELETE typically returns void/undefined (204 No Content)
|
|
101
|
-
return;
|
|
102
|
-
|
|
103
101
|
} catch (error) {
|
|
104
|
-
await handleWriteMethodError(error, context, 'DELETE', scopeName, log, runHooks)
|
|
102
|
+
await handleWriteMethodError(error, context, 'DELETE', scopeName, log, runHooks)
|
|
105
103
|
}
|
|
106
|
-
}
|
|
104
|
+
}
|