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.
Files changed (118) hide show
  1. package/connectors_ideas/fastify.js +66 -68
  2. package/connectors_ideas/koa-plugin.js +50 -51
  3. package/eslint.config.js +11 -2
  4. package/examples/url-override-example.js +63 -63
  5. package/index.js +13 -13
  6. package/lib/enhanced-logger.js +51 -51
  7. package/lib/error-formatter.js +61 -61
  8. package/lib/rest-api-errors.js +28 -28
  9. package/package.json +1 -1
  10. package/plugins/core/bulk-operations-plugin.js +142 -145
  11. package/plugins/core/connectors/express-plugin.js +210 -217
  12. package/plugins/core/connectors/lib/busboy-detector.js +84 -84
  13. package/plugins/core/connectors/lib/formidable-detector.js +50 -50
  14. package/plugins/core/connectors/lib/request-helpers.js +74 -74
  15. package/plugins/core/file-handling-plugin.js +125 -125
  16. package/plugins/core/lib/anyapi/anyapi-registry.js +254 -254
  17. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +287 -287
  18. package/plugins/core/lib/anyapi/schema-utils.js +101 -101
  19. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +41 -41
  20. package/plugins/core/lib/dbTablesOperations.js +134 -135
  21. package/plugins/core/lib/fractional-positioning.js +74 -76
  22. package/plugins/core/lib/querying/knex-cross-table-search.js +320 -320
  23. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +144 -144
  24. package/plugins/core/lib/querying/knex-pagination-helpers.js +164 -164
  25. package/plugins/core/lib/querying/knex-process-includes.js +50 -50
  26. package/plugins/core/lib/querying/knex-query-helpers-base.js +31 -31
  27. package/plugins/core/lib/querying/knex-query-helpers.js +451 -452
  28. package/plugins/core/lib/querying/knex-relationship-includes.js +1160 -1170
  29. package/plugins/core/lib/querying/knex-window-queries.js +89 -89
  30. package/plugins/core/lib/querying/url-helpers.js +35 -35
  31. package/plugins/core/lib/querying-writing/compile-schemas.js +99 -99
  32. package/plugins/core/lib/querying-writing/connectors-query-parser.js +31 -31
  33. package/plugins/core/lib/querying-writing/database-capabilities.js +94 -94
  34. package/plugins/core/lib/querying-writing/database-value-normalizers.js +76 -76
  35. package/plugins/core/lib/querying-writing/default-data-helpers.js +27 -27
  36. package/plugins/core/lib/querying-writing/field-utils.js +44 -42
  37. package/plugins/core/lib/querying-writing/knex-constants.js +15 -16
  38. package/plugins/core/lib/querying-writing/knex-field-helpers.js +117 -115
  39. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +41 -41
  40. package/plugins/core/lib/querying-writing/payload-validators.js +275 -275
  41. package/plugins/core/lib/querying-writing/schema-helpers.js +129 -129
  42. package/plugins/core/lib/querying-writing/scope-validations.js +143 -146
  43. package/plugins/core/lib/querying-writing/simplified-helpers.js +133 -129
  44. package/plugins/core/lib/storage/storage-adapter.js +68 -68
  45. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +31 -31
  46. package/plugins/core/lib/writing/many-to-many-manipulations.js +81 -81
  47. package/plugins/core/lib/writing/relationship-processor.js +58 -58
  48. package/plugins/core/rest-api-access.js +11 -15
  49. package/plugins/core/rest-api-anyapi-knex-plugin.js +920 -920
  50. package/plugins/core/rest-api-cors-plugin.js +170 -171
  51. package/plugins/core/rest-api-knex-plugin.js +482 -493
  52. package/plugins/core/rest-api-multihome-plugin.js +247 -251
  53. package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +5 -5
  54. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +20 -21
  55. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +44 -44
  56. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +23 -23
  57. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +15 -15
  58. package/plugins/core/rest-api-plugin-methods/add-route.js +9 -9
  59. package/plugins/core/rest-api-plugin-methods/check-permissions.js +5 -6
  60. package/plugins/core/rest-api-plugin-methods/common.js +295 -297
  61. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +35 -37
  62. package/plugins/core/rest-api-plugin-methods/delete.js +57 -59
  63. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +172 -171
  64. package/plugins/core/rest-api-plugin-methods/get-related.js +96 -96
  65. package/plugins/core/rest-api-plugin-methods/get-relationship.js +16 -18
  66. package/plugins/core/rest-api-plugin-methods/get.js +86 -86
  67. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +16 -17
  68. package/plugins/core/rest-api-plugin-methods/patch.js +63 -64
  69. package/plugins/core/rest-api-plugin-methods/post-relationship.js +54 -55
  70. package/plugins/core/rest-api-plugin-methods/post.js +61 -62
  71. package/plugins/core/rest-api-plugin-methods/put.js +86 -87
  72. package/plugins/core/rest-api-plugin-methods/query.js +88 -88
  73. package/plugins/core/rest-api-plugin-methods/release.js +5 -6
  74. package/plugins/core/rest-api-plugin.js +76 -78
  75. package/plugins/core/rest-api-positioning-plugin.js +251 -252
  76. package/plugins/core/socketio-plugin.js +240 -236
  77. package/plugins/storage/local-storage.js +103 -103
  78. package/plugins/storage/s3-storage.js +41 -42
  79. package/quickTest.js +37 -37
  80. package/scripts/debug-anyapi-review-filter.mjs +18 -18
  81. package/scripts/inspect-anyapi-descriptor-country.mjs +10 -10
  82. package/scripts/inspect-anyapi-descriptor.mjs +10 -10
  83. package/scripts/run-docs.js +112 -113
  84. package/test-debug.js +28 -28
  85. package/tests/TEST_TEMPLATE.test.js +51 -51
  86. package/tests/anyapi-basic.test.js +42 -42
  87. package/tests/anyapi-cursor-pagination.test.js +48 -48
  88. package/tests/bulk-operations.test.js +208 -208
  89. package/tests/computed-fields.test.js +204 -204
  90. package/tests/cors.test.js +412 -413
  91. package/tests/curl.test.js +275 -276
  92. package/tests/custom-idproperty-relationships.test.js +266 -266
  93. package/tests/field-getters.test.js +132 -132
  94. package/tests/field-setters.test.js +110 -110
  95. package/tests/fixtures/api-configs.js +699 -699
  96. package/tests/helpers/storage-mode.js +32 -32
  97. package/tests/helpers/test-utils.js +76 -76
  98. package/tests/include-depth-validation.test.js +76 -76
  99. package/tests/includes.test.js +145 -145
  100. package/tests/multihome.test.js +175 -175
  101. package/tests/nested-includes.test.js +255 -255
  102. package/tests/pagination-cursor-multifield.test.js +164 -164
  103. package/tests/pagination-enhanced.test.js +225 -225
  104. package/tests/polymorphic-relationships.test.js +96 -96
  105. package/tests/polymorphic-simple.test.js +44 -44
  106. package/tests/positioning-advanced.test.js +226 -226
  107. package/tests/positioning-extended.test.js +399 -399
  108. package/tests/positioning-multifilter.test.js +204 -204
  109. package/tests/positioning.test.js +266 -266
  110. package/tests/queries.test.js +184 -184
  111. package/tests/query-limits.test.js +154 -155
  112. package/tests/relationship-endpoints.test.js +127 -127
  113. package/tests/relationships.test.js +178 -179
  114. package/tests/rest-api-access.test.js +86 -86
  115. package/tests/rest-api.test.js +103 -103
  116. package/tests/searchschema-merge.test.js +93 -93
  117. package/tests/socketio.test.js +326 -326
  118. package/tests/virtual-fields.test.js +164 -164
@@ -1,29 +1,29 @@
1
- import { getForeignKeyFields as getForeignKeyFieldsFromUtils } from '../querying-writing/field-utils.js';
2
- import { RELATIONSHIPS_KEY, RELATIONSHIP_METADATA_KEY, ROW_NUMBER_KEY, COMPUTED_DEPENDENCIES_KEY, getSchemaStructure } from '../querying-writing/knex-constants.js';
3
- import { getUrlPrefix, buildResourceUrl, buildRelationshipUrl } from './url-helpers.js';
1
+ import { getForeignKeyFields as getForeignKeyFieldsFromUtils } from '../querying-writing/field-utils.js'
2
+ import { RELATIONSHIPS_KEY, RELATIONSHIP_METADATA_KEY, ROW_NUMBER_KEY, COMPUTED_DEPENDENCIES_KEY, getSchemaStructure } from '../querying-writing/knex-constants.js'
3
+ import { getUrlPrefix, buildResourceUrl, buildRelationshipUrl } from './url-helpers.js'
4
4
 
5
5
  /**
6
6
  * Transforms a flat database record into JSON:API resource format
7
- *
7
+ *
8
8
  * @private
9
9
  * @param {Object} scope - Scope containing schema and configuration
10
10
  * @param {Object} record - Database record to transform
11
11
  * @param {Object} deps - Dependencies including context with scopeName and polymorphicFields
12
12
  * @returns {Object|null} JSON:API resource object or null if no record
13
- *
13
+ *
14
14
  * @example
15
15
  * // Input: Database record with foreign keys and internal fields
16
- * const record = {
17
- * id: 1,
18
- * title: 'Hello World',
16
+ * const record = {
17
+ * id: 1,
18
+ * title: 'Hello World',
19
19
  * content: 'Article content',
20
20
  * author_id: 2, // Foreign key
21
21
  * category_id: 5, // Foreign key
22
22
  * __$jsonrestapi_rn$__: 1 // Internal field
23
23
  * };
24
- *
24
+ *
25
25
  * const jsonApiResource = toJsonApi(scope, record, deps);
26
- *
26
+ *
27
27
  * // Output: Clean JSON:API resource
28
28
  * // {
29
29
  * // type: 'articles',
@@ -34,7 +34,7 @@ import { getUrlPrefix, buildResourceUrl, buildRelationshipUrl } from './url-help
34
34
  * // // Note: author_id, category_id, and internal fields are removed
35
35
  * // }
36
36
  * // }
37
- *
37
+ *
38
38
  * @example
39
39
  * // Input: Polymorphic record
40
40
  * const record = {
@@ -44,9 +44,9 @@ import { getUrlPrefix, buildResourceUrl, buildRelationshipUrl } from './url-help
44
44
  * commentable_id: 1 // Polymorphic id field
45
45
  * };
46
46
  * // deps.context.polymorphicFields = Set(['commentable_type', 'commentable_id'])
47
- *
47
+ *
48
48
  * const jsonApiResource = toJsonApi(scope, record, deps);
49
- *
49
+ *
50
50
  * // Output: Polymorphic fields filtered out
51
51
  * // {
52
52
  * // type: 'comments',
@@ -55,79 +55,79 @@ import { getUrlPrefix, buildResourceUrl, buildRelationshipUrl } from './url-help
55
55
  * // text: 'Great article!'
56
56
  * // }
57
57
  * // }
58
- *
58
+ *
59
59
  * @description
60
60
  * Used by:
61
61
  * - toJsonApiRecord calls this as the core transformation logic
62
62
  * - buildJsonApiResponse uses this indirectly through toJsonApiRecord
63
- *
63
+ *
64
64
  * Purpose:
65
65
  * - Separates database structure from API structure
66
66
  * - Filters out foreign keys that become relationships in JSON:API
67
67
  * - Removes internal fields used for query optimization
68
68
  * - Ensures clean attribute objects without implementation details
69
- *
69
+ *
70
70
  * Data flow:
71
71
  * - Called after database query returns flat records
72
72
  * - Transforms each record individually
73
73
  * - Output feeds into relationship building and response assembly
74
74
  */
75
75
  const toJsonApi = (scope, record, deps) => {
76
- if (!record) return null;
77
-
76
+ if (!record) return null
77
+
78
78
  const schemaInstance = scope.vars.schemaInfo.schemaInstance
79
-
80
- const { context } = deps;
81
- const scopeName = context.scopeName;
82
- const idProperty = context.schemaInfo?.idProperty || 'id';
83
- const polymorphicFields = context.polymorphicFields || new Set();
84
-
85
- const { id, ...allAttributes } = record;
86
-
87
- const foreignKeys = schemaInstance ? getForeignKeyFieldsFromUtils(schemaInstance) : new Set();
88
-
79
+
80
+ const { context } = deps
81
+ const scopeName = context.scopeName
82
+ const idProperty = context.schemaInfo?.idProperty || 'id'
83
+ const polymorphicFields = context.polymorphicFields || new Set()
84
+
85
+ const { id, ...allAttributes } = record
86
+
87
+ const foreignKeys = schemaInstance ? getForeignKeyFieldsFromUtils(schemaInstance) : new Set()
88
+
89
89
  const internalFields = new Set([
90
90
  RELATIONSHIPS_KEY,
91
91
  RELATIONSHIP_METADATA_KEY,
92
92
  ROW_NUMBER_KEY,
93
93
  COMPUTED_DEPENDENCIES_KEY
94
- ]);
95
-
96
- const attributes = {};
94
+ ])
95
+
96
+ const attributes = {}
97
97
  Object.entries(allAttributes).forEach(([key, value]) => {
98
98
  if (!foreignKeys.has(key) && !polymorphicFields.has(key) && !internalFields.has(key) && key !== idProperty) {
99
- attributes[key] = value;
99
+ attributes[key] = value
100
100
  }
101
- });
102
-
101
+ })
102
+
103
103
  return {
104
104
  type: scopeName,
105
105
  id: String(id),
106
106
  attributes
107
- };
108
- };
107
+ }
108
+ }
109
109
 
110
110
  /**
111
111
  * Converts a database record to JSON:API format with proper field filtering
112
- *
112
+ *
113
113
  * @param {Object} scope - Scope containing schema and relationship definitions
114
114
  * @param {Object} record - Raw database record
115
115
  * @param {string} scopeName - Resource type name
116
116
  * @returns {Object} JSON:API formatted resource
117
- *
117
+ *
118
118
  * @example
119
119
  * // Input: Database record with various field types
120
- * const record = {
121
- * id: 1,
122
- * title: 'My Article',
120
+ * const record = {
121
+ * id: 1,
122
+ * title: 'My Article',
123
123
  * author_id: 2, // belongsTo relationship
124
124
  * category_id: 3, // belongsTo relationship
125
125
  * views: 150,
126
126
  * published: true
127
127
  * };
128
- *
128
+ *
129
129
  * const jsonApi = toJsonApiRecord(scope, record, 'articles');
130
- *
130
+ *
131
131
  * // Output: Foreign keys filtered out
132
132
  * // {
133
133
  * // type: 'articles',
@@ -138,7 +138,7 @@ const toJsonApi = (scope, record, deps) => {
138
138
  * // published: true
139
139
  * // }
140
140
  * // }
141
- *
141
+ *
142
142
  * @example
143
143
  * // Input: Record with polymorphic relationship
144
144
  * const record = {
@@ -149,9 +149,9 @@ const toJsonApi = (scope, record, deps) => {
149
149
  * commentable_id: 3 // Polymorphic
150
150
  * };
151
151
  * // Schema has polymorphic relationship defined
152
- *
152
+ *
153
153
  * const jsonApi = toJsonApiRecord(scope, record, 'comments');
154
- *
154
+ *
155
155
  * // Output: Both foreign keys and polymorphic fields filtered
156
156
  * // {
157
157
  * // type: 'comments',
@@ -160,20 +160,20 @@ const toJsonApi = (scope, record, deps) => {
160
160
  * // body: 'Nice post!'
161
161
  * // }
162
162
  * // }
163
- *
163
+ *
164
164
  * @description
165
165
  * Used by:
166
166
  * - rest-api-knex-plugin's dataGet method for single resource responses
167
167
  * - rest-api-knex-plugin's dataQuery method for collection responses
168
168
  * - processIncludes when transforming included resources
169
169
  * - buildJsonApiResponse as the primary transformation function
170
- *
170
+ *
171
171
  * Purpose:
172
172
  * - Provides consistent JSON:API transformation across all query operations
173
173
  * - Automatically identifies and filters foreign keys based on schema
174
174
  * - Handles polymorphic relationship fields (type/id pairs)
175
175
  * - Ensures IDs are always strings as required by JSON:API spec
176
- *
176
+ *
177
177
  * Data flow:
178
178
  * 1. Database query returns flat records with all fields
179
179
  * 2. toJsonApiRecord identifies foreign keys from schema
@@ -182,39 +182,39 @@ const toJsonApi = (scope, record, deps) => {
182
182
  * 5. buildJsonApiResponse adds relationships and links to complete the response
183
183
  */
184
184
  export const toJsonApiRecord = (scope, record, scopeName) => {
185
- const {
186
- vars: {
185
+ const {
186
+ vars: {
187
187
  schemaInfo: { schemaRelationships: relationships, idProperty }
188
188
  }
189
- } = scope;
190
-
191
- const polymorphicFields = new Set();
189
+ } = scope
190
+
191
+ const polymorphicFields = new Set()
192
192
  try {
193
193
  Object.entries(relationships || {}).forEach(([relName, relDef]) => {
194
194
  if (relDef.belongsToPolymorphic) {
195
- const typeFieldName = relDef.belongsToPolymorphic.typeField || `${relName}_type`;
196
- const idFieldName = relDef.belongsToPolymorphic.idField || `${relName}_id`;
197
- polymorphicFields.add(typeFieldName);
198
- polymorphicFields.add(idFieldName);
195
+ const typeFieldName = relDef.belongsToPolymorphic.typeField || `${relName}_type`
196
+ const idFieldName = relDef.belongsToPolymorphic.idField || `${relName}_id`
197
+ polymorphicFields.add(typeFieldName)
198
+ polymorphicFields.add(idFieldName)
199
199
  }
200
- });
200
+ })
201
201
  } catch (e) {
202
202
  }
203
-
203
+
204
204
  const deps = {
205
205
  context: {
206
206
  scopeName,
207
207
  schemaInfo: { idProperty },
208
208
  polymorphicFields
209
209
  }
210
- };
211
-
212
- return toJsonApi(scope, record, deps);
213
- };
210
+ }
211
+
212
+ return toJsonApi(scope, record, deps)
213
+ }
214
214
 
215
215
  /**
216
216
  * Builds complete JSON:API response with data, relationships, links, and optional includes
217
- *
217
+ *
218
218
  * @async
219
219
  * @param {Object} scope - Scope containing schema and configuration
220
220
  * @param {Array<Object>} records - Primary records to include in response
@@ -223,7 +223,7 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
223
223
  * @param {string} scopeName - Resource type name
224
224
  * @param {Object} context - Request context with pagination metadata
225
225
  * @returns {Promise<Object>} Complete JSON:API response document
226
- *
226
+ *
227
227
  * @example
228
228
  * // Input: Single article with author include
229
229
  * const records = [{
@@ -233,15 +233,15 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
233
233
  * author_id: 2,
234
234
  * category_id: 3
235
235
  * }];
236
- *
236
+ *
237
237
  * const included = [{
238
238
  * type: 'authors',
239
239
  * id: '2',
240
240
  * attributes: { name: 'John Doe', email: 'john@example.com' }
241
241
  * }];
242
- *
242
+ *
243
243
  * const response = await buildJsonApiResponse(scope, records, included, true, 'articles', context);
244
- *
244
+ *
245
245
  * // Output: Complete JSON:API document
246
246
  * // {
247
247
  * // data: {
@@ -281,7 +281,7 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
281
281
  * // self: '/articles/1'
282
282
  * // }
283
283
  * // }
284
- *
284
+ *
285
285
  * @example
286
286
  * // Input: Collection with pagination
287
287
  * const records = [
@@ -289,7 +289,7 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
289
289
  * { id: 2, title: 'Article 2', author_id: 10 },
290
290
  * { id: 3, title: 'Article 3', author_id: 11 }
291
291
  * ];
292
- *
292
+ *
293
293
  * context.returnMeta = {
294
294
  * paginationMeta: { page: 2, pageSize: 3, pageCount: 10, total: 30 },
295
295
  * paginationLinks: {
@@ -300,9 +300,9 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
300
300
  * last: '/articles?page[number]=10&page[size]=3'
301
301
  * }
302
302
  * };
303
- *
303
+ *
304
304
  * const response = await buildJsonApiResponse(scope, records, [], false, 'articles', context);
305
- *
305
+ *
306
306
  * // Output: Collection with pagination metadata
307
307
  * // {
308
308
  * // data: [
@@ -321,20 +321,20 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
321
321
  * // last: '/articles?page[number]=10&page[size]=3'
322
322
  * // }
323
323
  * // }
324
- *
324
+ *
325
325
  * @description
326
326
  * Used by:
327
327
  * - rest-api-knex-plugin's dataGet method for single resource responses
328
328
  * - rest-api-knex-plugin's dataQuery method for collection responses
329
329
  * - Called at the end of the query pipeline to assemble the final response
330
- *
330
+ *
331
331
  * Purpose:
332
332
  * - Assembles all parts of a JSON:API response in the correct structure
333
333
  * - Adds relationship objects with proper links for each foreign key
334
334
  * - Handles both regular belongsTo and polymorphic relationships
335
335
  * - Adds self links to all resources as required by JSON:API
336
336
  * - Includes pagination metadata and links when applicable
337
- *
337
+ *
338
338
  * Data flow:
339
339
  * 1. Query operations fetch primary records and optional includes
340
340
  * 2. Records are transformed to JSON:API format via toJsonApiRecord
@@ -345,27 +345,27 @@ export const toJsonApiRecord = (scope, record, scopeName) => {
345
345
  * 7. Returns complete JSON:API document ready for HTTP response
346
346
  */
347
347
  export const buildJsonApiResponse = async (scope, records, included = [], isSingle = false, scopeName, context) => {
348
- const {
349
- vars: {
350
- schemaInfo: { schemaInstance: schemaInstance, schemaRelationships: relationships, idProperty }
348
+ const {
349
+ vars: {
350
+ schemaInfo: { schemaInstance, schemaRelationships: relationships, idProperty }
351
351
  }
352
- } = scope;
353
-
354
- const idField = idProperty || 'id';
355
-
356
- const schemaStructure = getSchemaStructure(schemaInstance);
357
-
352
+ } = scope
353
+
354
+ const idField = idProperty || 'id'
355
+
356
+ const schemaStructure = getSchemaStructure(schemaInstance)
357
+
358
358
  const processedRecords = records.map(record => {
359
- const { [RELATIONSHIPS_KEY]: _relationships, ...cleanRecord } = record;
360
- const jsonApiRecord = toJsonApiRecord(scope, cleanRecord, scopeName);
361
-
359
+ const { [RELATIONSHIPS_KEY]: _relationships, ...cleanRecord } = record
360
+ const jsonApiRecord = toJsonApiRecord(scope, cleanRecord, scopeName)
361
+
362
362
  if (_relationships) {
363
- jsonApiRecord.relationships = _relationships;
363
+ jsonApiRecord.relationships = _relationships
364
364
  }
365
-
365
+
366
366
  for (const [fieldName, fieldDef] of Object.entries(schemaStructure)) {
367
367
  if (fieldDef.belongsTo && fieldDef.as && fieldName in cleanRecord) {
368
- jsonApiRecord.relationships = jsonApiRecord.relationships || {};
368
+ jsonApiRecord.relationships = jsonApiRecord.relationships || {}
369
369
  if (!jsonApiRecord.relationships[fieldDef.as]) {
370
370
  if (cleanRecord[fieldName] !== null && cleanRecord[fieldName] !== undefined) {
371
371
  const relationshipObject = {
@@ -373,113 +373,113 @@ export const buildJsonApiResponse = async (scope, records, included = [], isSing
373
373
  type: fieldDef.belongsTo,
374
374
  id: String(cleanRecord[fieldName])
375
375
  }
376
- };
377
-
376
+ }
377
+
378
378
  relationshipObject.links = {
379
379
  self: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, true),
380
380
  related: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, false)
381
- };
382
-
383
- jsonApiRecord.relationships[fieldDef.as] = relationshipObject;
381
+ }
382
+
383
+ jsonApiRecord.relationships[fieldDef.as] = relationshipObject
384
384
  } else {
385
385
  const relationshipObject = {
386
386
  data: null
387
- };
388
-
387
+ }
388
+
389
389
  relationshipObject.links = {
390
390
  self: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, true),
391
391
  related: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, false)
392
- };
393
-
394
- jsonApiRecord.relationships[fieldDef.as] = relationshipObject;
392
+ }
393
+
394
+ jsonApiRecord.relationships[fieldDef.as] = relationshipObject
395
395
  }
396
396
  }
397
397
  }
398
398
  }
399
-
399
+
400
400
  Object.entries(relationships || {}).forEach(([relName, relDef]) => {
401
401
  if (relDef.belongsToPolymorphic) {
402
- const typeValue = cleanRecord[relDef.belongsToPolymorphic.typeField];
403
- const idValue = cleanRecord[relDef.belongsToPolymorphic.idField];
404
-
402
+ const typeValue = cleanRecord[relDef.belongsToPolymorphic.typeField]
403
+ const idValue = cleanRecord[relDef.belongsToPolymorphic.idField]
404
+
405
405
  if (typeValue && idValue) {
406
- jsonApiRecord.relationships = jsonApiRecord.relationships || {};
406
+ jsonApiRecord.relationships = jsonApiRecord.relationships || {}
407
407
  const relationshipObject = {
408
408
  data: {
409
409
  type: typeValue,
410
410
  id: String(idValue)
411
411
  }
412
- };
413
-
412
+ }
413
+
414
414
  relationshipObject.links = {
415
415
  self: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, true),
416
416
  related: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, false)
417
- };
418
-
419
- jsonApiRecord.relationships[relName] = relationshipObject;
417
+ }
418
+
419
+ jsonApiRecord.relationships[relName] = relationshipObject
420
420
  } else if (typeValue === null || idValue === null) {
421
- jsonApiRecord.relationships = jsonApiRecord.relationships || {};
421
+ jsonApiRecord.relationships = jsonApiRecord.relationships || {}
422
422
  const relationshipObject = {
423
423
  data: null
424
- };
425
-
424
+ }
425
+
426
426
  relationshipObject.links = {
427
427
  self: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, true),
428
428
  related: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, false)
429
- };
430
-
431
- jsonApiRecord.relationships[relName] = relationshipObject;
429
+ }
430
+
431
+ jsonApiRecord.relationships[relName] = relationshipObject
432
432
  }
433
433
  }
434
- });
435
-
436
- return jsonApiRecord;
437
- });
438
-
439
- const urlPrefix = context.urlPrefix || scope.vars.transport?.mountPath || '';
440
- const normalizedData = isSingle ? processedRecords[0] : processedRecords;
441
-
434
+ })
435
+
436
+ return jsonApiRecord
437
+ })
438
+
439
+ const urlPrefix = context.urlPrefix || scope.vars.transport?.mountPath || ''
440
+ const normalizedData = isSingle ? processedRecords[0] : processedRecords
441
+
442
442
  if (normalizedData) {
443
443
  if (Array.isArray(normalizedData)) {
444
444
  normalizedData.forEach(item => {
445
- if (!item.links) item.links = {};
446
- item.links.self = buildResourceUrl(context, scope, scopeName, item.id);
447
- });
445
+ if (!item.links) item.links = {}
446
+ item.links.self = buildResourceUrl(context, scope, scopeName, item.id)
447
+ })
448
448
  } else {
449
- if (!normalizedData.links) normalizedData.links = {};
450
- normalizedData.links.self = buildResourceUrl(context, scope, scopeName, normalizedData.id);
449
+ if (!normalizedData.links) normalizedData.links = {}
450
+ normalizedData.links.self = buildResourceUrl(context, scope, scopeName, normalizedData.id)
451
451
  }
452
452
  }
453
453
 
454
454
  const response = {
455
455
  data: normalizedData
456
- };
456
+ }
457
457
 
458
458
  if (included.length > 0) {
459
459
  included.forEach(item => {
460
- if (!item.links) item.links = {};
461
- item.links.self = buildResourceUrl(context, scope, item.type, item.id);
462
- });
463
-
464
- response.included = included;
460
+ if (!item.links) item.links = {}
461
+ item.links.self = buildResourceUrl(context, scope, item.type, item.id)
462
+ })
463
+
464
+ response.included = included
465
465
  }
466
466
 
467
467
  if (context?.returnMeta?.paginationMeta) {
468
468
  response.meta = {
469
469
  pagination: context.returnMeta.paginationMeta
470
- };
470
+ }
471
471
  }
472
-
472
+
473
473
  if (context?.returnMeta?.paginationLinks) {
474
- response.links = context.returnMeta.paginationLinks;
474
+ response.links = context.returnMeta.paginationLinks
475
475
  } else {
476
- const urlPrefix = getUrlPrefix(context, scope);
476
+ const urlPrefix = getUrlPrefix(context, scope)
477
477
  response.links = {
478
- self: isSingle
478
+ self: isSingle
479
479
  ? buildResourceUrl(context, scope, scopeName, normalizedData.id)
480
480
  : `${urlPrefix}/${scopeName}${context?.returnMeta?.queryString || ''}`
481
- };
481
+ }
482
482
  }
483
483
 
484
- return response;
485
- };
484
+ return response
485
+ }