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
package/tests/includes.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { describe, it, before, beforeEach, after } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import knexLib from 'knex'
|
|
4
|
-
import { createBasicApi, createExtendedApi } from './fixtures/api-configs.js'
|
|
1
|
+
import { describe, it, before, beforeEach, after } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import knexLib from 'knex'
|
|
4
|
+
import { createBasicApi, createExtendedApi } from './fixtures/api-configs.js'
|
|
5
5
|
import {
|
|
6
6
|
validateJsonApiStructure,
|
|
7
7
|
resourceIdentifier,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
createToManyRelationship,
|
|
13
13
|
assertResourceAttributes,
|
|
14
14
|
assertResourceRelationship
|
|
15
|
-
} from './helpers/test-utils.js'
|
|
15
|
+
} from './helpers/test-utils.js'
|
|
16
16
|
|
|
17
17
|
// Create Knex instance for tests
|
|
18
18
|
const knex = knexLib({
|
|
@@ -21,62 +21,62 @@ const knex = knexLib({
|
|
|
21
21
|
filename: ':memory:'
|
|
22
22
|
},
|
|
23
23
|
useNullAsDefault: true
|
|
24
|
-
})
|
|
24
|
+
})
|
|
25
25
|
|
|
26
26
|
// API instances that persist across tests
|
|
27
|
-
let basicApi
|
|
28
|
-
let extendedApi
|
|
27
|
+
let basicApi
|
|
28
|
+
let extendedApi
|
|
29
29
|
|
|
30
30
|
describe('Include/Sideloading Operations', () => {
|
|
31
31
|
before(async () => {
|
|
32
32
|
// Initialize APIs once
|
|
33
|
-
basicApi = await createBasicApi(knex)
|
|
34
|
-
extendedApi = await createExtendedApi(knex)
|
|
35
|
-
})
|
|
33
|
+
basicApi = await createBasicApi(knex)
|
|
34
|
+
extendedApi = await createExtendedApi(knex)
|
|
35
|
+
})
|
|
36
36
|
|
|
37
37
|
after(async () => {
|
|
38
38
|
// Close database connection to allow tests to exit
|
|
39
|
-
await knex.destroy()
|
|
40
|
-
})
|
|
39
|
+
await knex.destroy()
|
|
40
|
+
})
|
|
41
41
|
|
|
42
42
|
describe('Single-Level Includes', () => {
|
|
43
|
-
|
|
43
|
+
const testData = {}
|
|
44
44
|
|
|
45
45
|
beforeEach(async () => {
|
|
46
46
|
// Clean all tables
|
|
47
47
|
await cleanTables(knex, [
|
|
48
48
|
'basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'
|
|
49
|
-
])
|
|
49
|
+
])
|
|
50
50
|
|
|
51
51
|
// Create test data
|
|
52
|
-
const countryDoc = createJsonApiDocument('countries', { name: 'Test Country', code: 'TC' })
|
|
52
|
+
const countryDoc = createJsonApiDocument('countries', { name: 'Test Country', code: 'TC' })
|
|
53
53
|
const countryResult = await basicApi.resources.countries.post({
|
|
54
54
|
inputRecord: countryDoc,
|
|
55
55
|
simplified: false
|
|
56
|
-
})
|
|
57
|
-
testData.country = countryResult.data
|
|
56
|
+
})
|
|
57
|
+
testData.country = countryResult.data
|
|
58
58
|
|
|
59
59
|
const publisherDoc = createJsonApiDocument('publishers',
|
|
60
60
|
{ name: 'Test Publisher' },
|
|
61
61
|
{ country: createRelationship(resourceIdentifier('countries', testData.country.id)) }
|
|
62
|
-
)
|
|
62
|
+
)
|
|
63
63
|
const publisherResult = await basicApi.resources.publishers.post({
|
|
64
64
|
inputRecord: publisherDoc,
|
|
65
65
|
simplified: false
|
|
66
|
-
})
|
|
67
|
-
testData.publisher = publisherResult.data
|
|
66
|
+
})
|
|
67
|
+
testData.publisher = publisherResult.data
|
|
68
68
|
|
|
69
|
-
const author1Doc = createJsonApiDocument('authors', { name: 'Author One' })
|
|
70
|
-
const author2Doc = createJsonApiDocument('authors', { name: 'Author Two' })
|
|
69
|
+
const author1Doc = createJsonApiDocument('authors', { name: 'Author One' })
|
|
70
|
+
const author2Doc = createJsonApiDocument('authors', { name: 'Author Two' })
|
|
71
71
|
const author1Result = await basicApi.resources.authors.post({
|
|
72
72
|
inputRecord: author1Doc,
|
|
73
73
|
simplified: false
|
|
74
|
-
})
|
|
74
|
+
})
|
|
75
75
|
const author2Result = await basicApi.resources.authors.post({
|
|
76
76
|
inputRecord: author2Doc,
|
|
77
77
|
simplified: false
|
|
78
|
-
})
|
|
79
|
-
testData.authors = [author1Result.data, author2Result.data]
|
|
78
|
+
})
|
|
79
|
+
testData.authors = [author1Result.data, author2Result.data]
|
|
80
80
|
|
|
81
81
|
const bookDoc = createJsonApiDocument('books',
|
|
82
82
|
{ title: 'Test Book' },
|
|
@@ -88,13 +88,13 @@ describe('Include/Sideloading Operations', () => {
|
|
|
88
88
|
resourceIdentifier('authors', testData.authors[1].id)
|
|
89
89
|
])
|
|
90
90
|
}
|
|
91
|
-
)
|
|
91
|
+
)
|
|
92
92
|
const bookResult = await basicApi.resources.books.post({
|
|
93
93
|
inputRecord: bookDoc,
|
|
94
94
|
simplified: false
|
|
95
|
-
})
|
|
96
|
-
testData.book = bookResult.data
|
|
97
|
-
})
|
|
95
|
+
})
|
|
96
|
+
testData.book = bookResult.data
|
|
97
|
+
})
|
|
98
98
|
|
|
99
99
|
it('should include single belongsTo relationship', async () => {
|
|
100
100
|
const result = await basicApi.resources.books.get({
|
|
@@ -103,20 +103,20 @@ describe('Include/Sideloading Operations', () => {
|
|
|
103
103
|
include: ['publisher']
|
|
104
104
|
},
|
|
105
105
|
simplified: false
|
|
106
|
-
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
validateJsonApiStructure(result, false)
|
|
107
109
|
|
|
108
|
-
validateJsonApiStructure(result, false);
|
|
109
|
-
|
|
110
110
|
// Verify included array exists
|
|
111
|
-
assert(result.included, 'Should have included data')
|
|
112
|
-
assert.equal(result.included.length, 1, 'Should include one resource')
|
|
113
|
-
|
|
111
|
+
assert(result.included, 'Should have included data')
|
|
112
|
+
assert.equal(result.included.length, 1, 'Should include one resource')
|
|
113
|
+
|
|
114
114
|
// Verify included publisher
|
|
115
|
-
const includedPublisher = result.included[0]
|
|
116
|
-
assert.equal(includedPublisher.type, 'publishers')
|
|
117
|
-
assert.equal(includedPublisher.id, testData.publisher.id)
|
|
118
|
-
assert.equal(includedPublisher.attributes.name, 'Test Publisher')
|
|
119
|
-
})
|
|
115
|
+
const includedPublisher = result.included[0]
|
|
116
|
+
assert.equal(includedPublisher.type, 'publishers')
|
|
117
|
+
assert.equal(includedPublisher.id, testData.publisher.id)
|
|
118
|
+
assert.equal(includedPublisher.attributes.name, 'Test Publisher')
|
|
119
|
+
})
|
|
120
120
|
|
|
121
121
|
it('should include multiple relationships', async () => {
|
|
122
122
|
const result = await basicApi.resources.books.get({
|
|
@@ -125,26 +125,26 @@ describe('Include/Sideloading Operations', () => {
|
|
|
125
125
|
include: ['publisher', 'authors', 'country']
|
|
126
126
|
},
|
|
127
127
|
simplified: false
|
|
128
|
-
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
validateJsonApiStructure(result, false)
|
|
129
131
|
|
|
130
|
-
validateJsonApiStructure(result, false);
|
|
131
|
-
|
|
132
132
|
// Verify included array
|
|
133
|
-
assert(result.included)
|
|
134
|
-
assert.equal(result.included.length, 4, 'Should include 4 resources (1 publisher + 2 authors + 1 country)')
|
|
135
|
-
|
|
133
|
+
assert(result.included)
|
|
134
|
+
assert.equal(result.included.length, 4, 'Should include 4 resources (1 publisher + 2 authors + 1 country)')
|
|
135
|
+
|
|
136
136
|
// Verify each type is included
|
|
137
|
-
const includedTypes = result.included.map(r => r.type)
|
|
138
|
-
assert(includedTypes.includes('publishers'))
|
|
139
|
-
assert(includedTypes.includes('authors'))
|
|
140
|
-
assert(includedTypes.includes('countries'))
|
|
141
|
-
|
|
137
|
+
const includedTypes = result.included.map(r => r.type)
|
|
138
|
+
assert(includedTypes.includes('publishers'))
|
|
139
|
+
assert(includedTypes.includes('authors'))
|
|
140
|
+
assert(includedTypes.includes('countries'))
|
|
141
|
+
|
|
142
142
|
// Verify specific resources
|
|
143
|
-
const authors = result.included.filter(r => r.type === 'authors')
|
|
144
|
-
assert.equal(authors.length, 2)
|
|
145
|
-
const authorNames = authors.map(a => a.attributes.name).sort()
|
|
146
|
-
assert.deepEqual(authorNames, ['Author One', 'Author Two'])
|
|
147
|
-
})
|
|
143
|
+
const authors = result.included.filter(r => r.type === 'authors')
|
|
144
|
+
assert.equal(authors.length, 2)
|
|
145
|
+
const authorNames = authors.map(a => a.attributes.name).sort()
|
|
146
|
+
assert.deepEqual(authorNames, ['Author One', 'Author Two'])
|
|
147
|
+
})
|
|
148
148
|
|
|
149
149
|
it('should include relationships in collection queries', async () => {
|
|
150
150
|
const result = await basicApi.resources.books.query({
|
|
@@ -152,46 +152,46 @@ describe('Include/Sideloading Operations', () => {
|
|
|
152
152
|
include: ['publisher', 'country']
|
|
153
153
|
},
|
|
154
154
|
simplified: false
|
|
155
|
-
})
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
validateJsonApiStructure(result, true)
|
|
156
158
|
|
|
157
|
-
validateJsonApiStructure(result, true);
|
|
158
|
-
|
|
159
159
|
// Should have one book
|
|
160
|
-
assert.equal(result.data.length, 1)
|
|
161
|
-
|
|
160
|
+
assert.equal(result.data.length, 1)
|
|
161
|
+
|
|
162
162
|
// Should have included resources
|
|
163
|
-
assert(result.included)
|
|
164
|
-
const includedTypes = result.included.map(r => r.type)
|
|
165
|
-
assert(includedTypes.includes('publishers'))
|
|
166
|
-
assert(includedTypes.includes('countries'))
|
|
167
|
-
})
|
|
168
|
-
})
|
|
163
|
+
assert(result.included)
|
|
164
|
+
const includedTypes = result.included.map(r => r.type)
|
|
165
|
+
assert(includedTypes.includes('publishers'))
|
|
166
|
+
assert(includedTypes.includes('countries'))
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
169
|
|
|
170
170
|
describe('Nested Includes', () => {
|
|
171
|
-
|
|
171
|
+
const testData = {}
|
|
172
172
|
|
|
173
173
|
beforeEach(async () => {
|
|
174
174
|
await cleanTables(knex, [
|
|
175
175
|
'basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'
|
|
176
|
-
])
|
|
176
|
+
])
|
|
177
177
|
|
|
178
178
|
// Create hierarchy: Country -> Publisher -> Book
|
|
179
|
-
const countryDoc = createJsonApiDocument('countries', { name: 'Nested Country', code: 'NC' })
|
|
179
|
+
const countryDoc = createJsonApiDocument('countries', { name: 'Nested Country', code: 'NC' })
|
|
180
180
|
const countryResult = await basicApi.resources.countries.post({
|
|
181
181
|
inputRecord: countryDoc,
|
|
182
182
|
simplified: false
|
|
183
|
-
})
|
|
184
|
-
testData.country = countryResult.data
|
|
183
|
+
})
|
|
184
|
+
testData.country = countryResult.data
|
|
185
185
|
|
|
186
186
|
const publisherDoc = createJsonApiDocument('publishers',
|
|
187
187
|
{ name: 'Nested Publisher' },
|
|
188
188
|
{ country: createRelationship(resourceIdentifier('countries', testData.country.id)) }
|
|
189
|
-
)
|
|
189
|
+
)
|
|
190
190
|
const publisherResult = await basicApi.resources.publishers.post({
|
|
191
191
|
inputRecord: publisherDoc,
|
|
192
192
|
simplified: false
|
|
193
|
-
})
|
|
194
|
-
testData.publisher = publisherResult.data
|
|
193
|
+
})
|
|
194
|
+
testData.publisher = publisherResult.data
|
|
195
195
|
|
|
196
196
|
const bookDoc = createJsonApiDocument('books',
|
|
197
197
|
{ title: 'Nested Book' },
|
|
@@ -199,13 +199,13 @@ describe('Include/Sideloading Operations', () => {
|
|
|
199
199
|
country: createRelationship(resourceIdentifier('countries', testData.country.id)),
|
|
200
200
|
publisher: createRelationship(resourceIdentifier('publishers', testData.publisher.id))
|
|
201
201
|
}
|
|
202
|
-
)
|
|
202
|
+
)
|
|
203
203
|
const bookResult = await basicApi.resources.books.post({
|
|
204
204
|
inputRecord: bookDoc,
|
|
205
205
|
simplified: false
|
|
206
|
-
})
|
|
207
|
-
testData.book = bookResult.data
|
|
208
|
-
})
|
|
206
|
+
})
|
|
207
|
+
testData.book = bookResult.data
|
|
208
|
+
})
|
|
209
209
|
|
|
210
210
|
it('should include nested relationships', async () => {
|
|
211
211
|
const result = await basicApi.resources.books.get({
|
|
@@ -214,33 +214,33 @@ describe('Include/Sideloading Operations', () => {
|
|
|
214
214
|
include: ['publisher.country']
|
|
215
215
|
},
|
|
216
216
|
simplified: false
|
|
217
|
-
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
validateJsonApiStructure(result, false)
|
|
218
220
|
|
|
219
|
-
validateJsonApiStructure(result, false);
|
|
220
|
-
|
|
221
221
|
// Should include both publisher and its country
|
|
222
|
-
assert(result.included)
|
|
223
|
-
assert.equal(result.included.length, 2)
|
|
224
|
-
|
|
222
|
+
assert(result.included)
|
|
223
|
+
assert.equal(result.included.length, 2)
|
|
224
|
+
|
|
225
225
|
// Find the resources
|
|
226
|
-
const publisher = result.included.find(r => r.type === 'publishers')
|
|
227
|
-
const country = result.included.find(r => r.type === 'countries')
|
|
228
|
-
|
|
229
|
-
assert(publisher, 'Should include publisher')
|
|
230
|
-
assert(country, 'Should include country')
|
|
231
|
-
|
|
226
|
+
const publisher = result.included.find(r => r.type === 'publishers')
|
|
227
|
+
const country = result.included.find(r => r.type === 'countries')
|
|
228
|
+
|
|
229
|
+
assert(publisher, 'Should include publisher')
|
|
230
|
+
assert(country, 'Should include country')
|
|
231
|
+
|
|
232
232
|
// Verify the publisher has country relationship
|
|
233
|
-
assert(publisher.relationships?.country, 'Publisher should have country relationship')
|
|
234
|
-
assert.equal(publisher.relationships.country.data.id, country.id)
|
|
235
|
-
})
|
|
233
|
+
assert(publisher.relationships?.country, 'Publisher should have country relationship')
|
|
234
|
+
assert.equal(publisher.relationships.country.data.id, country.id)
|
|
235
|
+
})
|
|
236
236
|
|
|
237
237
|
it('should handle multiple nested includes', async () => {
|
|
238
238
|
// Create an author to have more relationships
|
|
239
|
-
const authorDoc = createJsonApiDocument('authors', { name: 'Nested Author' })
|
|
239
|
+
const authorDoc = createJsonApiDocument('authors', { name: 'Nested Author' })
|
|
240
240
|
const authorResult = await basicApi.resources.authors.post({
|
|
241
241
|
inputRecord: authorDoc,
|
|
242
242
|
simplified: false
|
|
243
|
-
})
|
|
243
|
+
})
|
|
244
244
|
|
|
245
245
|
// Update book to have author
|
|
246
246
|
const patchDoc = {
|
|
@@ -253,12 +253,12 @@ describe('Include/Sideloading Operations', () => {
|
|
|
253
253
|
])
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
|
-
}
|
|
256
|
+
}
|
|
257
257
|
await basicApi.resources.books.patch({
|
|
258
258
|
id: testData.book.id,
|
|
259
259
|
inputRecord: patchDoc,
|
|
260
260
|
simplified: false
|
|
261
|
-
})
|
|
261
|
+
})
|
|
262
262
|
|
|
263
263
|
// Query with multiple nested includes
|
|
264
264
|
const result = await basicApi.resources.books.query({
|
|
@@ -266,30 +266,30 @@ describe('Include/Sideloading Operations', () => {
|
|
|
266
266
|
include: ['publisher.country', 'authors', 'country']
|
|
267
267
|
},
|
|
268
268
|
simplified: false
|
|
269
|
-
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
validateJsonApiStructure(result, true)
|
|
270
272
|
|
|
271
|
-
validateJsonApiStructure(result, true);
|
|
272
|
-
|
|
273
273
|
// Should have all included resources
|
|
274
|
-
assert(result.included)
|
|
275
|
-
const includedTypes = result.included.map(r => r.type)
|
|
276
|
-
assert(includedTypes.includes('publishers'))
|
|
277
|
-
assert(includedTypes.includes('countries'))
|
|
278
|
-
assert(includedTypes.includes('authors'))
|
|
279
|
-
|
|
274
|
+
assert(result.included)
|
|
275
|
+
const includedTypes = result.included.map(r => r.type)
|
|
276
|
+
assert(includedTypes.includes('publishers'))
|
|
277
|
+
assert(includedTypes.includes('countries'))
|
|
278
|
+
assert(includedTypes.includes('authors'))
|
|
279
|
+
|
|
280
280
|
// Verify no duplicates
|
|
281
|
-
const countryResources = result.included.filter(r => r.type === 'countries')
|
|
282
|
-
assert.equal(countryResources.length, 1, 'Should not duplicate country resource')
|
|
283
|
-
})
|
|
284
|
-
})
|
|
281
|
+
const countryResources = result.included.filter(r => r.type === 'countries')
|
|
282
|
+
assert.equal(countryResources.length, 1, 'Should not duplicate country resource')
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
285
|
|
|
286
286
|
describe('Include with Sparse Fieldsets', () => {
|
|
287
|
-
|
|
287
|
+
const testData = {}
|
|
288
288
|
|
|
289
289
|
beforeEach(async () => {
|
|
290
290
|
await cleanTables(knex, [
|
|
291
291
|
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books', 'ext_book_authors'
|
|
292
|
-
])
|
|
292
|
+
])
|
|
293
293
|
|
|
294
294
|
// Use extended API for more fields
|
|
295
295
|
const countryDoc = createJsonApiDocument('countries', {
|
|
@@ -298,12 +298,12 @@ describe('Include/Sideloading Operations', () => {
|
|
|
298
298
|
capital: 'Capital City',
|
|
299
299
|
population: 1000000,
|
|
300
300
|
currency: 'FTC'
|
|
301
|
-
})
|
|
301
|
+
})
|
|
302
302
|
const countryResult = await extendedApi.resources.countries.post({
|
|
303
303
|
inputRecord: countryDoc,
|
|
304
304
|
simplified: false
|
|
305
|
-
})
|
|
306
|
-
testData.country = countryResult.data
|
|
305
|
+
})
|
|
306
|
+
testData.country = countryResult.data
|
|
307
307
|
|
|
308
308
|
const publisherDoc = createJsonApiDocument('publishers',
|
|
309
309
|
{
|
|
@@ -313,12 +313,12 @@ describe('Include/Sideloading Operations', () => {
|
|
|
313
313
|
active: true
|
|
314
314
|
},
|
|
315
315
|
{ country: createRelationship(resourceIdentifier('countries', testData.country.id)) }
|
|
316
|
-
)
|
|
316
|
+
)
|
|
317
317
|
const publisherResult = await extendedApi.resources.publishers.post({
|
|
318
318
|
inputRecord: publisherDoc,
|
|
319
319
|
simplified: false
|
|
320
|
-
})
|
|
321
|
-
testData.publisher = publisherResult.data
|
|
320
|
+
})
|
|
321
|
+
testData.publisher = publisherResult.data
|
|
322
322
|
|
|
323
323
|
const bookDoc = createJsonApiDocument('books',
|
|
324
324
|
{
|
|
@@ -332,13 +332,13 @@ describe('Include/Sideloading Operations', () => {
|
|
|
332
332
|
country: createRelationship(resourceIdentifier('countries', testData.country.id)),
|
|
333
333
|
publisher: createRelationship(resourceIdentifier('publishers', testData.publisher.id))
|
|
334
334
|
}
|
|
335
|
-
)
|
|
335
|
+
)
|
|
336
336
|
const bookResult = await extendedApi.resources.books.post({
|
|
337
337
|
inputRecord: bookDoc,
|
|
338
338
|
simplified: false
|
|
339
|
-
})
|
|
340
|
-
testData.book = bookResult.data
|
|
341
|
-
})
|
|
339
|
+
})
|
|
340
|
+
testData.book = bookResult.data
|
|
341
|
+
})
|
|
342
342
|
|
|
343
343
|
it('should include relationships with sparse fieldsets', async () => {
|
|
344
344
|
const result = await extendedApi.resources.books.get({
|
|
@@ -352,27 +352,27 @@ describe('Include/Sideloading Operations', () => {
|
|
|
352
352
|
}
|
|
353
353
|
},
|
|
354
354
|
simplified: false
|
|
355
|
-
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
validateJsonApiStructure(result, false)
|
|
356
358
|
|
|
357
|
-
validateJsonApiStructure(result, false);
|
|
358
|
-
|
|
359
359
|
// Verify main resource has only requested fields
|
|
360
|
-
assert(result.data.attributes.title)
|
|
361
|
-
assert(result.data.attributes.isbn)
|
|
362
|
-
assert(!result.data.attributes.pages, 'Should not include pages')
|
|
363
|
-
assert(!result.data.attributes.price, 'Should not include price')
|
|
364
|
-
|
|
360
|
+
assert(result.data.attributes.title)
|
|
361
|
+
assert(result.data.attributes.isbn)
|
|
362
|
+
assert(!result.data.attributes.pages, 'Should not include pages')
|
|
363
|
+
assert(!result.data.attributes.price, 'Should not include price')
|
|
364
|
+
|
|
365
365
|
// Verify included resources have only requested fields
|
|
366
|
-
const publisher = result.included.find(r => r.type === 'publishers')
|
|
367
|
-
assert(publisher.attributes.name)
|
|
368
|
-
assert(!publisher.attributes.founded_year, 'Should not include founded_year')
|
|
369
|
-
assert(!publisher.attributes.website, 'Should not include website')
|
|
370
|
-
|
|
371
|
-
const country = result.included.find(r => r.type === 'countries')
|
|
372
|
-
assert(country.attributes.name)
|
|
373
|
-
assert(country.attributes.code)
|
|
374
|
-
assert(!country.attributes.capital, 'Should not include capital')
|
|
375
|
-
assert(!country.attributes.population, 'Should not include population')
|
|
376
|
-
})
|
|
377
|
-
})
|
|
378
|
-
})
|
|
366
|
+
const publisher = result.included.find(r => r.type === 'publishers')
|
|
367
|
+
assert(publisher.attributes.name)
|
|
368
|
+
assert(!publisher.attributes.founded_year, 'Should not include founded_year')
|
|
369
|
+
assert(!publisher.attributes.website, 'Should not include website')
|
|
370
|
+
|
|
371
|
+
const country = result.included.find(r => r.type === 'countries')
|
|
372
|
+
assert(country.attributes.name)
|
|
373
|
+
assert(country.attributes.code)
|
|
374
|
+
assert(!country.attributes.capital, 'Should not include capital')
|
|
375
|
+
assert(!country.attributes.population, 'Should not include population')
|
|
376
|
+
})
|
|
377
|
+
})
|
|
378
|
+
})
|