json-rest-api 1.0.14 → 1.0.16
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 +11 -2
- 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 +1 -1
- 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 +99 -99
- 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 +11 -15
- 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,13 +1,13 @@
|
|
|
1
|
-
import { describe, it, before, after, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import knexLib from 'knex'
|
|
4
|
-
import { createExtendedApi } from './fixtures/api-configs.js'
|
|
1
|
+
import { describe, it, before, after, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import knexLib from 'knex'
|
|
4
|
+
import { createExtendedApi } from './fixtures/api-configs.js'
|
|
5
5
|
import {
|
|
6
6
|
validateJsonApiStructure,
|
|
7
7
|
cleanTables,
|
|
8
8
|
createJsonApiDocument,
|
|
9
9
|
createRelationship
|
|
10
|
-
} from './helpers/test-utils.js'
|
|
10
|
+
} from './helpers/test-utils.js'
|
|
11
11
|
|
|
12
12
|
// Create Knex instance for tests
|
|
13
13
|
const knex = knexLib({
|
|
@@ -16,30 +16,30 @@ const knex = knexLib({
|
|
|
16
16
|
filename: ':memory:'
|
|
17
17
|
},
|
|
18
18
|
useNullAsDefault: true
|
|
19
|
-
})
|
|
19
|
+
})
|
|
20
20
|
|
|
21
21
|
// API instance
|
|
22
|
-
let api
|
|
22
|
+
let api
|
|
23
23
|
|
|
24
24
|
describe('Polymorphic Relationship Operations', () => {
|
|
25
25
|
before(async () => {
|
|
26
26
|
// Initialize API
|
|
27
|
-
api = await createExtendedApi(knex)
|
|
28
|
-
})
|
|
27
|
+
api = await createExtendedApi(knex)
|
|
28
|
+
})
|
|
29
29
|
|
|
30
30
|
after(async () => {
|
|
31
31
|
// Close database connection
|
|
32
|
-
await knex.destroy()
|
|
33
|
-
})
|
|
32
|
+
await knex.destroy()
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
describe('Creating Reviews with Polymorphic Relationships', () => {
|
|
36
36
|
beforeEach(async () => {
|
|
37
37
|
// Clean all tables before each test
|
|
38
38
|
await cleanTables(knex, [
|
|
39
|
-
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
39
|
+
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
40
40
|
'ext_book_authors', 'ext_reviews'
|
|
41
|
-
])
|
|
42
|
-
})
|
|
41
|
+
])
|
|
42
|
+
})
|
|
43
43
|
|
|
44
44
|
it('should create a review for a book', async () => {
|
|
45
45
|
// Create a country first
|
|
@@ -48,7 +48,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
48
48
|
name: 'USA',
|
|
49
49
|
code: 'US'
|
|
50
50
|
})
|
|
51
|
-
})
|
|
51
|
+
})
|
|
52
52
|
|
|
53
53
|
// Create a book
|
|
54
54
|
const book = await api.resources.books.post({
|
|
@@ -57,7 +57,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
57
57
|
}, {
|
|
58
58
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
59
59
|
})
|
|
60
|
-
})
|
|
60
|
+
})
|
|
61
61
|
|
|
62
62
|
// Create a review for the book
|
|
63
63
|
const review = await api.resources.reviews.post({
|
|
@@ -69,14 +69,14 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
69
69
|
reviewable_type: 'books',
|
|
70
70
|
reviewable_id: book.data.id
|
|
71
71
|
})
|
|
72
|
-
})
|
|
72
|
+
})
|
|
73
73
|
|
|
74
|
-
validateJsonApiStructure(review)
|
|
75
|
-
assert.equal(review.data.type, 'reviews')
|
|
76
|
-
assert.equal(review.data.attributes.rating, 5)
|
|
74
|
+
validateJsonApiStructure(review)
|
|
75
|
+
assert.equal(review.data.type, 'reviews')
|
|
76
|
+
assert.equal(review.data.attributes.rating, 5)
|
|
77
77
|
// Since polymorphic fields are filtered out from POST responses,
|
|
78
78
|
// we need to GET the record to verify the relationship was saved correctly
|
|
79
|
-
})
|
|
79
|
+
})
|
|
80
80
|
|
|
81
81
|
it('should create a review for an author', async () => {
|
|
82
82
|
// Create an author
|
|
@@ -84,7 +84,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
84
84
|
inputRecord: createJsonApiDocument('authors', {
|
|
85
85
|
name: 'Jane Doe'
|
|
86
86
|
})
|
|
87
|
-
})
|
|
87
|
+
})
|
|
88
88
|
|
|
89
89
|
// Create a review for the author
|
|
90
90
|
const review = await api.resources.reviews.post({
|
|
@@ -96,13 +96,13 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
96
96
|
reviewable_type: 'authors',
|
|
97
97
|
reviewable_id: author.data.id
|
|
98
98
|
})
|
|
99
|
-
})
|
|
99
|
+
})
|
|
100
100
|
|
|
101
|
-
validateJsonApiStructure(review)
|
|
101
|
+
validateJsonApiStructure(review)
|
|
102
102
|
// Polymorphic fields are no longer in attributes, they're in relationships
|
|
103
|
-
assert.equal(review.data.relationships.reviewable.data.type, 'authors')
|
|
104
|
-
assert.equal(review.data.relationships.reviewable.data.id, String(author.data.id))
|
|
105
|
-
})
|
|
103
|
+
assert.equal(review.data.relationships.reviewable.data.type, 'authors')
|
|
104
|
+
assert.equal(review.data.relationships.reviewable.data.id, String(author.data.id))
|
|
105
|
+
})
|
|
106
106
|
|
|
107
107
|
it('should create a review for a publisher', async () => {
|
|
108
108
|
// Create a country
|
|
@@ -111,7 +111,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
111
111
|
name: 'UK',
|
|
112
112
|
code: 'GB'
|
|
113
113
|
})
|
|
114
|
-
})
|
|
114
|
+
})
|
|
115
115
|
|
|
116
116
|
// Create a publisher
|
|
117
117
|
const publisher = await api.resources.publishers.post({
|
|
@@ -120,7 +120,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
120
120
|
}, {
|
|
121
121
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
122
122
|
})
|
|
123
|
-
})
|
|
123
|
+
})
|
|
124
124
|
|
|
125
125
|
// Create a review for the publisher
|
|
126
126
|
const review = await api.resources.reviews.post({
|
|
@@ -132,28 +132,28 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
132
132
|
reviewable_type: 'publishers',
|
|
133
133
|
reviewable_id: publisher.data.id
|
|
134
134
|
})
|
|
135
|
-
})
|
|
135
|
+
})
|
|
136
136
|
|
|
137
|
-
validateJsonApiStructure(review)
|
|
137
|
+
validateJsonApiStructure(review)
|
|
138
138
|
// Polymorphic fields are no longer in attributes, they're in relationships
|
|
139
|
-
assert.equal(review.data.relationships.reviewable.data.type, 'publishers')
|
|
140
|
-
assert.equal(review.data.relationships.reviewable.data.id, String(publisher.data.id))
|
|
141
|
-
})
|
|
139
|
+
assert.equal(review.data.relationships.reviewable.data.type, 'publishers')
|
|
140
|
+
assert.equal(review.data.relationships.reviewable.data.id, String(publisher.data.id))
|
|
141
|
+
})
|
|
142
142
|
|
|
143
143
|
it('should fail to create review with invalid reviewable_type', async () => {
|
|
144
144
|
// Skip this test for now - polymorphic validation happens at relationship level
|
|
145
145
|
// not at the attribute level, so we need to create a proper relationship
|
|
146
146
|
// This would require more complex validation implementation
|
|
147
|
-
})
|
|
148
|
-
})
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
149
|
|
|
150
150
|
describe('Querying Reviews with Polymorphic Relationships', () => {
|
|
151
151
|
beforeEach(async () => {
|
|
152
152
|
await cleanTables(knex, [
|
|
153
|
-
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
153
|
+
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
154
154
|
'ext_book_authors', 'ext_reviews'
|
|
155
|
-
])
|
|
156
|
-
})
|
|
155
|
+
])
|
|
156
|
+
})
|
|
157
157
|
|
|
158
158
|
it('should query reviews and include polymorphic reviewable resource', async () => {
|
|
159
159
|
// Create test data
|
|
@@ -162,7 +162,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
162
162
|
name: 'France',
|
|
163
163
|
code: 'FR'
|
|
164
164
|
})
|
|
165
|
-
})
|
|
165
|
+
})
|
|
166
166
|
|
|
167
167
|
const book = await api.resources.books.post({
|
|
168
168
|
inputRecord: createJsonApiDocument('books', {
|
|
@@ -170,7 +170,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
170
170
|
}, {
|
|
171
171
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
172
172
|
})
|
|
173
|
-
})
|
|
173
|
+
})
|
|
174
174
|
|
|
175
175
|
await api.resources.reviews.post({
|
|
176
176
|
inputRecord: createJsonApiDocument('reviews', {
|
|
@@ -181,26 +181,26 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
181
181
|
reviewable_type: 'books',
|
|
182
182
|
reviewable_id: book.data.id
|
|
183
183
|
})
|
|
184
|
-
})
|
|
184
|
+
})
|
|
185
185
|
|
|
186
186
|
// Query reviews with include
|
|
187
187
|
const result = await api.resources.reviews.query({
|
|
188
188
|
queryParams: {
|
|
189
189
|
include: ['reviewable']
|
|
190
190
|
}
|
|
191
|
-
})
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
validateJsonApiStructure(result, true) // It's a collection
|
|
194
|
+
assert.equal(result.data.length, 1)
|
|
195
|
+
assert.equal(result.data[0].type, 'reviews')
|
|
192
196
|
|
|
193
|
-
validateJsonApiStructure(result, true); // It's a collection
|
|
194
|
-
assert.equal(result.data.length, 1);
|
|
195
|
-
assert.equal(result.data[0].type, 'reviews');
|
|
196
|
-
|
|
197
197
|
// Check included resources
|
|
198
|
-
assert(result.included)
|
|
199
|
-
assert.equal(result.included.length, 1)
|
|
200
|
-
assert.equal(result.included[0].type, 'books')
|
|
201
|
-
assert.equal(result.included[0].id, book.data.id)
|
|
202
|
-
assert.equal(result.included[0].attributes.title, 'Test Book for Review')
|
|
203
|
-
})
|
|
198
|
+
assert(result.included)
|
|
199
|
+
assert.equal(result.included.length, 1)
|
|
200
|
+
assert.equal(result.included[0].type, 'books')
|
|
201
|
+
assert.equal(result.included[0].id, book.data.id)
|
|
202
|
+
assert.equal(result.included[0].attributes.title, 'Test Book for Review')
|
|
203
|
+
})
|
|
204
204
|
|
|
205
205
|
it('should handle mixed polymorphic types in a single query', async () => {
|
|
206
206
|
// Create test data
|
|
@@ -209,7 +209,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
209
209
|
name: 'Germany',
|
|
210
210
|
code: 'DE'
|
|
211
211
|
})
|
|
212
|
-
})
|
|
212
|
+
})
|
|
213
213
|
|
|
214
214
|
const book = await api.resources.books.post({
|
|
215
215
|
inputRecord: createJsonApiDocument('books', {
|
|
@@ -217,13 +217,13 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
217
217
|
}, {
|
|
218
218
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
219
219
|
})
|
|
220
|
-
})
|
|
220
|
+
})
|
|
221
221
|
|
|
222
222
|
const author = await api.resources.authors.post({
|
|
223
223
|
inputRecord: createJsonApiDocument('authors', {
|
|
224
224
|
name: 'German Author'
|
|
225
225
|
})
|
|
226
|
-
})
|
|
226
|
+
})
|
|
227
227
|
|
|
228
228
|
// Create reviews for different types
|
|
229
229
|
await api.resources.reviews.post({
|
|
@@ -235,7 +235,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
235
235
|
reviewable_type: 'books',
|
|
236
236
|
reviewable_id: book.data.id
|
|
237
237
|
})
|
|
238
|
-
})
|
|
238
|
+
})
|
|
239
239
|
|
|
240
240
|
await api.resources.reviews.post({
|
|
241
241
|
inputRecord: createJsonApiDocument('reviews', {
|
|
@@ -246,41 +246,41 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
246
246
|
reviewable_type: 'authors',
|
|
247
247
|
reviewable_id: author.data.id
|
|
248
248
|
})
|
|
249
|
-
})
|
|
249
|
+
})
|
|
250
250
|
|
|
251
251
|
// Query all reviews with includes
|
|
252
252
|
const result = await api.resources.reviews.query({
|
|
253
253
|
queryParams: {
|
|
254
254
|
include: ['reviewable']
|
|
255
255
|
}
|
|
256
|
-
})
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
validateJsonApiStructure(result, true) // It's a collection
|
|
259
|
+
assert.equal(result.data.length, 2)
|
|
257
260
|
|
|
258
|
-
validateJsonApiStructure(result, true); // It's a collection
|
|
259
|
-
assert.equal(result.data.length, 2);
|
|
260
|
-
|
|
261
261
|
// Check included resources
|
|
262
|
-
assert(result.included)
|
|
263
|
-
assert.equal(result.included.length, 2)
|
|
264
|
-
|
|
262
|
+
assert(result.included)
|
|
263
|
+
assert.equal(result.included.length, 2)
|
|
264
|
+
|
|
265
265
|
// Find each type in included
|
|
266
|
-
const includedBook = result.included.find(r => r.type === 'books')
|
|
267
|
-
const includedAuthor = result.included.find(r => r.type === 'authors')
|
|
268
|
-
|
|
269
|
-
assert(includedBook)
|
|
270
|
-
assert.equal(includedBook.attributes.title, 'German Book')
|
|
271
|
-
|
|
272
|
-
assert(includedAuthor)
|
|
273
|
-
assert.equal(includedAuthor.attributes.name, 'German Author')
|
|
274
|
-
})
|
|
275
|
-
})
|
|
266
|
+
const includedBook = result.included.find(r => r.type === 'books')
|
|
267
|
+
const includedAuthor = result.included.find(r => r.type === 'authors')
|
|
268
|
+
|
|
269
|
+
assert(includedBook)
|
|
270
|
+
assert.equal(includedBook.attributes.title, 'German Book')
|
|
271
|
+
|
|
272
|
+
assert(includedAuthor)
|
|
273
|
+
assert.equal(includedAuthor.attributes.name, 'German Author')
|
|
274
|
+
})
|
|
275
|
+
})
|
|
276
276
|
|
|
277
277
|
describe('Reverse Polymorphic Queries', () => {
|
|
278
278
|
beforeEach(async () => {
|
|
279
279
|
await cleanTables(knex, [
|
|
280
|
-
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
280
|
+
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
281
281
|
'ext_book_authors', 'ext_reviews'
|
|
282
|
-
])
|
|
283
|
-
})
|
|
282
|
+
])
|
|
283
|
+
})
|
|
284
284
|
|
|
285
285
|
it('should query books and include their reviews', async () => {
|
|
286
286
|
// Create test data
|
|
@@ -289,7 +289,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
289
289
|
name: 'Spain',
|
|
290
290
|
code: 'ES'
|
|
291
291
|
})
|
|
292
|
-
})
|
|
292
|
+
})
|
|
293
293
|
|
|
294
294
|
const book = await api.resources.books.post({
|
|
295
295
|
inputRecord: createJsonApiDocument('books', {
|
|
@@ -297,7 +297,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
297
297
|
}, {
|
|
298
298
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
299
299
|
})
|
|
300
|
-
})
|
|
300
|
+
})
|
|
301
301
|
|
|
302
302
|
// Create multiple reviews for the book
|
|
303
303
|
await api.resources.reviews.post({
|
|
@@ -309,7 +309,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
309
309
|
reviewable_type: 'books',
|
|
310
310
|
reviewable_id: book.data.id
|
|
311
311
|
})
|
|
312
|
-
})
|
|
312
|
+
})
|
|
313
313
|
|
|
314
314
|
await api.resources.reviews.post({
|
|
315
315
|
inputRecord: createJsonApiDocument('reviews', {
|
|
@@ -320,7 +320,7 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
320
320
|
reviewable_type: 'books',
|
|
321
321
|
reviewable_id: book.data.id
|
|
322
322
|
})
|
|
323
|
-
})
|
|
323
|
+
})
|
|
324
324
|
|
|
325
325
|
// Query book with reviews
|
|
326
326
|
const result = await api.resources.books.get({
|
|
@@ -328,20 +328,20 @@ describe('Polymorphic Relationship Operations', () => {
|
|
|
328
328
|
queryParams: {
|
|
329
329
|
include: ['reviews']
|
|
330
330
|
}
|
|
331
|
-
})
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
validateJsonApiStructure(result)
|
|
334
|
+
assert.equal(result.data.type, 'books')
|
|
332
335
|
|
|
333
|
-
validateJsonApiStructure(result);
|
|
334
|
-
assert.equal(result.data.type, 'books');
|
|
335
|
-
|
|
336
336
|
// Check included reviews
|
|
337
|
-
console.log('Result included:', JSON.stringify(result.included, null, 2))
|
|
338
|
-
assert(result.included)
|
|
339
|
-
assert.equal(result.included.length, 2)
|
|
340
|
-
assert(result.included.every(r => r.type === 'reviews'))
|
|
341
|
-
assert(result.included.every(r =>
|
|
342
|
-
r.relationships.reviewable.data.type === 'books' &&
|
|
337
|
+
console.log('Result included:', JSON.stringify(result.included, null, 2))
|
|
338
|
+
assert(result.included)
|
|
339
|
+
assert.equal(result.included.length, 2)
|
|
340
|
+
assert(result.included.every(r => r.type === 'reviews'))
|
|
341
|
+
assert(result.included.every(r =>
|
|
342
|
+
r.relationships.reviewable.data.type === 'books' &&
|
|
343
343
|
String(r.relationships.reviewable.data.id) === String(book.data.id)
|
|
344
|
-
))
|
|
345
|
-
})
|
|
346
|
-
})
|
|
347
|
-
})
|
|
344
|
+
))
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
})
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { describe, it, before, after, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import knexLib from 'knex'
|
|
4
|
-
import { createExtendedApi } from './fixtures/api-configs.js'
|
|
1
|
+
import { describe, it, before, after, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import knexLib from 'knex'
|
|
4
|
+
import { createExtendedApi } from './fixtures/api-configs.js'
|
|
5
5
|
import {
|
|
6
6
|
validateJsonApiStructure,
|
|
7
7
|
cleanTables,
|
|
8
8
|
createJsonApiDocument,
|
|
9
9
|
createRelationship
|
|
10
|
-
} from './helpers/test-utils.js'
|
|
10
|
+
} from './helpers/test-utils.js'
|
|
11
11
|
|
|
12
12
|
// Create Knex instance for tests
|
|
13
13
|
const knex = knexLib({
|
|
@@ -16,29 +16,29 @@ const knex = knexLib({
|
|
|
16
16
|
filename: ':memory:'
|
|
17
17
|
},
|
|
18
18
|
useNullAsDefault: true
|
|
19
|
-
})
|
|
19
|
+
})
|
|
20
20
|
|
|
21
21
|
// API instance
|
|
22
|
-
let api
|
|
22
|
+
let api
|
|
23
23
|
|
|
24
24
|
describe('Polymorphic Relationships - Basic Tests', () => {
|
|
25
25
|
before(async () => {
|
|
26
26
|
// Initialize API
|
|
27
|
-
api = await createExtendedApi(knex)
|
|
28
|
-
})
|
|
27
|
+
api = await createExtendedApi(knex)
|
|
28
|
+
})
|
|
29
29
|
|
|
30
30
|
after(async () => {
|
|
31
31
|
// Close database connection
|
|
32
|
-
await knex.destroy()
|
|
33
|
-
})
|
|
32
|
+
await knex.destroy()
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
beforeEach(async () => {
|
|
36
36
|
// Clean all tables before each test
|
|
37
37
|
await cleanTables(knex, [
|
|
38
|
-
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
38
|
+
'ext_countries', 'ext_publishers', 'ext_authors', 'ext_books',
|
|
39
39
|
'ext_book_authors', 'ext_reviews'
|
|
40
|
-
])
|
|
41
|
-
})
|
|
40
|
+
])
|
|
41
|
+
})
|
|
42
42
|
|
|
43
43
|
it('should create and retrieve a review for a book', async () => {
|
|
44
44
|
// Create a country first
|
|
@@ -47,7 +47,7 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
47
47
|
name: 'USA',
|
|
48
48
|
code: 'US'
|
|
49
49
|
})
|
|
50
|
-
})
|
|
50
|
+
})
|
|
51
51
|
|
|
52
52
|
// Create a book
|
|
53
53
|
const book = await api.resources.books.post({
|
|
@@ -56,7 +56,7 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
56
56
|
}, {
|
|
57
57
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
58
58
|
})
|
|
59
|
-
})
|
|
59
|
+
})
|
|
60
60
|
|
|
61
61
|
// Create a review for the book
|
|
62
62
|
const review = await api.resources.reviews.post({
|
|
@@ -68,22 +68,22 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
68
68
|
}, {
|
|
69
69
|
reviewable: { data: { type: 'books', id: book.data.id } }
|
|
70
70
|
})
|
|
71
|
-
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
validateJsonApiStructure(review)
|
|
74
|
+
assert.equal(review.data.type, 'reviews')
|
|
75
|
+
assert.equal(review.data.attributes.rating, 5)
|
|
72
76
|
|
|
73
|
-
validateJsonApiStructure(review);
|
|
74
|
-
assert.equal(review.data.type, 'reviews');
|
|
75
|
-
assert.equal(review.data.attributes.rating, 5);
|
|
76
|
-
|
|
77
77
|
// Get the review back
|
|
78
78
|
const retrievedReview = await api.resources.reviews.get({
|
|
79
79
|
id: review.data.id
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
validateJsonApiStructure(retrievedReview)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
validateJsonApiStructure(retrievedReview)
|
|
83
83
|
// Polymorphic fields are no longer in attributes, they're in relationships
|
|
84
|
-
assert.equal(retrievedReview.data.relationships.reviewable.data.type, 'books')
|
|
85
|
-
assert.equal(retrievedReview.data.relationships.reviewable.data.id, String(book.data.id))
|
|
86
|
-
})
|
|
84
|
+
assert.equal(retrievedReview.data.relationships.reviewable.data.type, 'books')
|
|
85
|
+
assert.equal(retrievedReview.data.relationships.reviewable.data.id, String(book.data.id))
|
|
86
|
+
})
|
|
87
87
|
|
|
88
88
|
it('should query all reviews', async () => {
|
|
89
89
|
// Create test data
|
|
@@ -92,7 +92,7 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
92
92
|
name: 'UK',
|
|
93
93
|
code: 'GB'
|
|
94
94
|
})
|
|
95
|
-
})
|
|
95
|
+
})
|
|
96
96
|
|
|
97
97
|
const book = await api.resources.books.post({
|
|
98
98
|
inputRecord: createJsonApiDocument('books', {
|
|
@@ -100,13 +100,13 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
100
100
|
}, {
|
|
101
101
|
country: createRelationship({ type: 'countries', id: country.data.id })
|
|
102
102
|
})
|
|
103
|
-
})
|
|
103
|
+
})
|
|
104
104
|
|
|
105
105
|
const author = await api.resources.authors.post({
|
|
106
106
|
inputRecord: createJsonApiDocument('authors', {
|
|
107
107
|
name: 'Author 1'
|
|
108
108
|
})
|
|
109
|
-
})
|
|
109
|
+
})
|
|
110
110
|
|
|
111
111
|
// Create reviews
|
|
112
112
|
await api.resources.reviews.post({
|
|
@@ -118,7 +118,7 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
118
118
|
}, {
|
|
119
119
|
reviewable: { data: { type: 'books', id: book.data.id } }
|
|
120
120
|
})
|
|
121
|
-
})
|
|
121
|
+
})
|
|
122
122
|
|
|
123
123
|
await api.resources.reviews.post({
|
|
124
124
|
inputRecord: createJsonApiDocument('reviews', {
|
|
@@ -129,20 +129,20 @@ describe('Polymorphic Relationships - Basic Tests', () => {
|
|
|
129
129
|
}, {
|
|
130
130
|
reviewable: { data: { type: 'authors', id: author.data.id } }
|
|
131
131
|
})
|
|
132
|
-
})
|
|
132
|
+
})
|
|
133
133
|
|
|
134
134
|
// Query all reviews
|
|
135
|
-
const result = await api.resources.reviews.query({})
|
|
136
|
-
|
|
137
|
-
validateJsonApiStructure(result, true)
|
|
138
|
-
assert.equal(result.data.length, 2)
|
|
139
|
-
|
|
135
|
+
const result = await api.resources.reviews.query({})
|
|
136
|
+
|
|
137
|
+
validateJsonApiStructure(result, true)
|
|
138
|
+
assert.equal(result.data.length, 2)
|
|
139
|
+
|
|
140
140
|
// Check we have one of each type
|
|
141
141
|
// Polymorphic fields are no longer in attributes, they're in relationships
|
|
142
|
-
const bookReview = result.data.find(r => r.relationships.reviewable.data.type === 'books')
|
|
143
|
-
const authorReview = result.data.find(r => r.relationships.reviewable.data.type === 'authors')
|
|
144
|
-
|
|
145
|
-
assert(bookReview, 'Should have a book review')
|
|
146
|
-
assert(authorReview, 'Should have an author review')
|
|
147
|
-
})
|
|
148
|
-
})
|
|
142
|
+
const bookReview = result.data.find(r => r.relationships.reviewable.data.type === 'books')
|
|
143
|
+
const authorReview = result.data.find(r => r.relationships.reviewable.data.type === 'authors')
|
|
144
|
+
|
|
145
|
+
assert(bookReview, 'Should have a book review')
|
|
146
|
+
assert(authorReview, 'Should have an author review')
|
|
147
|
+
})
|
|
148
|
+
})
|