json-rest-api 1.0.14 → 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.
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 +97 -98
  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 +8 -8
  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,26 +1,26 @@
1
- const passthrough = (value) => value;
2
- const identityTranslate = (_field, value) => value;
3
- const identityScope = (query) => query;
1
+ const passthrough = (value) => value
2
+ const identityTranslate = (_field, value) => value
3
+ const identityScope = (query) => query
4
4
 
5
5
  const selectColumnsOnBuilder = (builder, columns) => {
6
- if (!columns) return builder;
6
+ if (!columns) return builder
7
7
  if (Array.isArray(columns)) {
8
- columns.forEach((column) => builder.select(column));
8
+ columns.forEach((column) => builder.select(column))
9
9
  } else if (typeof columns === 'object') {
10
- builder.select(columns);
10
+ builder.select(columns)
11
11
  }
12
- return builder;
13
- };
12
+ return builder
13
+ }
14
14
 
15
- const normalizeArray = (value, normalizeFn) => value.map((entry) => normalizeFn(entry));
15
+ const normalizeArray = (value, normalizeFn) => value.map((entry) => normalizeFn(entry))
16
16
 
17
17
  const normalizeBelongsToValue = (value) => {
18
- if (value === null || value === undefined) return value;
18
+ if (value === null || value === undefined) return value
19
19
  if (Array.isArray(value)) {
20
- return normalizeArray(value, normalizeBelongsToValue);
20
+ return normalizeArray(value, normalizeBelongsToValue)
21
21
  }
22
- return String(value);
23
- };
22
+ return String(value)
23
+ }
24
24
 
25
25
  const baseAdapter = ({
26
26
  knex,
@@ -32,9 +32,9 @@ const baseAdapter = ({
32
32
  isCanonical = false,
33
33
  }) => {
34
34
  const buildBaseQuery = ({ transaction } = {}) => {
35
- const query = (transaction || knex)(tableName);
36
- return applyResourceScope(query);
37
- };
35
+ const query = (transaction || knex)(tableName)
36
+ return applyResourceScope(query)
37
+ }
38
38
 
39
39
  return {
40
40
  isCanonical: () => isCanonical,
@@ -45,14 +45,14 @@ const baseAdapter = ({
45
45
  applyResourceScope,
46
46
  buildBaseQuery,
47
47
  selectColumns: (builder, columns) => selectColumnsOnBuilder(builder, columns),
48
- };
49
- };
48
+ }
49
+ }
50
50
 
51
51
  const createLegacyAdapter = ({ knex, schemaInfo }) => {
52
- const tableName = schemaInfo.tableName;
53
- const idColumn = schemaInfo.idProperty || 'id';
52
+ const tableName = schemaInfo.tableName
53
+ const idColumn = schemaInfo.idProperty || 'id'
54
54
 
55
- const translateColumn = (column) => column;
55
+ const translateColumn = (column) => column
56
56
 
57
57
  return baseAdapter({
58
58
  knex,
@@ -62,79 +62,79 @@ const createLegacyAdapter = ({ knex, schemaInfo }) => {
62
62
  translateFilterValue: identityTranslate,
63
63
  applyResourceScope: identityScope,
64
64
  isCanonical: false,
65
- });
66
- };
65
+ })
66
+ }
67
67
 
68
68
  const createCanonicalAdapter = ({ knex, schemaInfo }) => {
69
- const descriptor = schemaInfo.descriptor || {};
70
- const canonical = descriptor.canonical || {};
71
- const canonicalFieldMap = descriptor.canonicalFieldMap || {};
72
- const fieldsInfo = descriptor.fields || {};
73
- const belongsToInfo = descriptor.belongsTo || {};
69
+ const descriptor = schemaInfo.descriptor || {}
70
+ const canonical = descriptor.canonical || {}
71
+ const canonicalFieldMap = descriptor.canonicalFieldMap || {}
72
+ const fieldsInfo = descriptor.fields || {}
73
+ const belongsToInfo = descriptor.belongsTo || {}
74
74
 
75
75
  const translateColumn = (field) => {
76
- if (!field) return field;
77
- if (field === 'id') return 'id';
76
+ if (!field) return field
77
+ if (field === 'id') return 'id'
78
78
 
79
- const canonicalEntry = canonicalFieldMap[field];
79
+ const canonicalEntry = canonicalFieldMap[field]
80
80
  if (typeof canonicalEntry === 'string') {
81
- return canonicalEntry;
81
+ return canonicalEntry
82
82
  }
83
83
  if (canonicalEntry && typeof canonicalEntry === 'object') {
84
- if (canonicalEntry.slot) return canonicalEntry.slot;
85
- if (canonicalEntry.slotColumn) return canonicalEntry.slotColumn;
86
- if (canonicalEntry.idSlot) return canonicalEntry.idSlot;
87
- if (canonicalEntry.typeSlot && field.endsWith('_type')) return canonicalEntry.typeSlot;
84
+ if (canonicalEntry.slot) return canonicalEntry.slot
85
+ if (canonicalEntry.slotColumn) return canonicalEntry.slotColumn
86
+ if (canonicalEntry.idSlot) return canonicalEntry.idSlot
87
+ if (canonicalEntry.typeSlot && field.endsWith('_type')) return canonicalEntry.typeSlot
88
88
  }
89
89
 
90
90
  if (!canonicalEntry && field.endsWith('_id')) {
91
- const alias = field.slice(0, -3);
92
- const aliasEntry = canonicalFieldMap[alias];
93
- if (typeof aliasEntry === 'string') return aliasEntry;
94
- if (aliasEntry?.idSlot) return aliasEntry.idSlot;
91
+ const alias = field.slice(0, -3)
92
+ const aliasEntry = canonicalFieldMap[alias]
93
+ if (typeof aliasEntry === 'string') return aliasEntry
94
+ if (aliasEntry?.idSlot) return aliasEntry.idSlot
95
95
  }
96
96
 
97
97
  if (!canonicalEntry && field.endsWith('_type')) {
98
- const alias = field.slice(0, -5);
99
- const aliasEntry = canonicalFieldMap[alias];
100
- if (aliasEntry?.typeSlot) return aliasEntry.typeSlot;
98
+ const alias = field.slice(0, -5)
99
+ const aliasEntry = canonicalFieldMap[alias]
100
+ if (aliasEntry?.typeSlot) return aliasEntry.typeSlot
101
101
  }
102
102
 
103
- const fieldInfo = fieldsInfo[field];
104
- if (fieldInfo?.slot) return fieldInfo.slot;
103
+ const fieldInfo = fieldsInfo[field]
104
+ if (fieldInfo?.slot) return fieldInfo.slot
105
105
 
106
- const belongsInfo = belongsToInfo[field];
107
- if (belongsInfo?.idColumn) return belongsInfo.idColumn;
106
+ const belongsInfo = belongsToInfo[field]
107
+ if (belongsInfo?.idColumn) return belongsInfo.idColumn
108
108
 
109
- return field;
110
- };
109
+ return field
110
+ }
111
111
 
112
112
  const translateFilterValue = (field, value) => {
113
- if (value === null || value === undefined) return value;
113
+ if (value === null || value === undefined) return value
114
114
 
115
- const searchField = schemaInfo.searchSchemaStructure?.[field];
116
- const schemaField = schemaInfo.schemaStructure?.[field];
115
+ const searchField = schemaInfo.searchSchemaStructure?.[field]
116
+ const schemaField = schemaInfo.schemaStructure?.[field]
117
117
  const isRelationship = Boolean(
118
- searchField?.isRelationship
119
- || schemaField?.belongsTo
120
- || schemaField?.belongsToPolymorphic
121
- );
118
+ searchField?.isRelationship ||
119
+ schemaField?.belongsTo ||
120
+ schemaField?.belongsToPolymorphic
121
+ )
122
122
 
123
123
  if (!isRelationship) {
124
124
  if (Array.isArray(value)) {
125
- return normalizeArray(value, passthrough);
125
+ return normalizeArray(value, passthrough)
126
126
  }
127
- return value;
127
+ return value
128
128
  }
129
129
 
130
- return normalizeBelongsToValue(value);
131
- };
130
+ return normalizeBelongsToValue(value)
131
+ }
132
132
 
133
133
  const applyResourceScope = (query) => {
134
134
  return query
135
135
  .where(canonical.tenantColumn, descriptor.tenant)
136
- .where(canonical.resourceColumn, descriptor.resource);
137
- };
136
+ .where(canonical.resourceColumn, descriptor.resource)
137
+ }
138
138
 
139
139
  return baseAdapter({
140
140
  knex,
@@ -144,17 +144,17 @@ const createCanonicalAdapter = ({ knex, schemaInfo }) => {
144
144
  translateFilterValue,
145
145
  applyResourceScope,
146
146
  isCanonical: true,
147
- });
148
- };
147
+ })
148
+ }
149
149
 
150
150
  export const createStorageAdapter = ({ knex, schemaInfo }) => {
151
151
  if (!schemaInfo) {
152
- throw new Error('createStorageAdapter requires schemaInfo');
152
+ throw new Error('createStorageAdapter requires schemaInfo')
153
153
  }
154
154
 
155
155
  if (schemaInfo?.descriptor?.canonical?.tableName) {
156
- return createCanonicalAdapter({ knex, schemaInfo });
156
+ return createCanonicalAdapter({ knex, schemaInfo })
157
157
  }
158
158
 
159
- return createLegacyAdapter({ knex, schemaInfo });
160
- };
159
+ return createLegacyAdapter({ knex, schemaInfo })
160
+ }
@@ -1,12 +1,12 @@
1
- import { getSchemaStructure } from '../querying-writing/knex-constants.js';
1
+ import { getSchemaStructure } from '../querying-writing/knex-constants.js'
2
2
 
3
3
  /**
4
4
  * Processes belongsTo relationships from JSON:API input to foreign key updates
5
- *
5
+ *
6
6
  * @param {Object} scope - The scope object containing schema info
7
7
  * @param {Object} deps - Dependencies object containing context with inputRecord
8
8
  * @returns {Object} Object mapping foreign key fields to their values
9
- *
9
+ *
10
10
  * @example
11
11
  * // Input: JSON:API document with relationships
12
12
  * const inputRecord = {
@@ -23,18 +23,18 @@ import { getSchemaStructure } from '../querying-writing/knex-constants.js';
23
23
  * }
24
24
  * }
25
25
  * };
26
- *
26
+ *
27
27
  * // Schema has: author_id field with belongsTo: 'users', as: 'author'
28
28
  * // Schema has: category_id field with belongsTo: 'categories', as: 'category'
29
- *
29
+ *
30
30
  * const updates = processBelongsToRelationships(scope, { context: { inputRecord } });
31
- *
31
+ *
32
32
  * // Output: Foreign key values extracted
33
33
  * // {
34
34
  * // author_id: '123',
35
35
  * // category_id: '456'
36
36
  * // }
37
- *
37
+ *
38
38
  * @example
39
39
  * // Input: Removing a relationship (setting to null)
40
40
  * const inputRecord = {
@@ -48,26 +48,26 @@ import { getSchemaStructure } from '../querying-writing/knex-constants.js';
48
48
  * }
49
49
  * }
50
50
  * };
51
- *
51
+ *
52
52
  * const updates = processBelongsToRelationships(scope, { context: { inputRecord } });
53
- *
53
+ *
54
54
  * // Output: Foreign key set to null
55
55
  * // {
56
56
  * // author_id: null
57
57
  * // }
58
- *
58
+ *
59
59
  * @description
60
60
  * Used by:
61
61
  * - rest-api-knex-plugin's dataPut and dataPatch methods
62
62
  * - Called before saving to extract foreign keys from JSON:API relationships
63
63
  * - Works in conjunction with relationship-processor for complete handling
64
- *
64
+ *
65
65
  * Purpose:
66
66
  * - Converts JSON:API relationship format to database foreign keys
67
67
  * - Maps from relationship names (e.g., 'author') to field names (e.g., 'author_id')
68
68
  * - Handles both setting relationships (with id) and removing them (null)
69
69
  * - Only processes belongsTo relationships, not hasMany
70
- *
70
+ *
71
71
  * Data flow:
72
72
  * 1. Receives JSON:API document with relationships section
73
73
  * 2. Looks up schema to find foreign key fields
@@ -76,35 +76,35 @@ import { getSchemaStructure } from '../querying-writing/knex-constants.js';
76
76
  * 5. Returns object ready to merge with attributes for database update
77
77
  */
78
78
  export const processBelongsToRelationships = (scope, deps) => {
79
- const foreignKeyUpdates = {};
80
-
79
+ const foreignKeyUpdates = {}
80
+
81
81
  // Extract values from deps
82
- const { context } = deps;
83
- const inputRecord = context.inputRecord;
84
-
82
+ const { context } = deps
83
+ const inputRecord = context.inputRecord
84
+
85
85
  if (!inputRecord.data.relationships) {
86
- return foreignKeyUpdates;
86
+ return foreignKeyUpdates
87
87
  }
88
-
88
+
89
89
  // Extract schema from scope
90
- const {
91
- vars: {
90
+ const {
91
+ vars: {
92
92
  schemaInfo: { schema }
93
93
  }
94
- } = scope;
95
-
94
+ } = scope
95
+
96
96
  // Schema might be a Schema object or plain object
97
- const schemaStructure = getSchemaStructure(schema);
98
-
97
+ const schemaStructure = getSchemaStructure(schema)
98
+
99
99
  for (const [fieldName, fieldDef] of Object.entries(schemaStructure)) {
100
100
  if (fieldDef.belongsTo && fieldDef.as) {
101
- const relName = fieldDef.as;
101
+ const relName = fieldDef.as
102
102
  if (inputRecord.data.relationships[relName] !== undefined) {
103
- const relData = inputRecord.data.relationships[relName];
104
- foreignKeyUpdates[fieldName] = relData.data?.id || null;
103
+ const relData = inputRecord.data.relationships[relName]
104
+ foreignKeyUpdates[fieldName] = relData.data?.id || null
105
105
  }
106
106
  }
107
107
  }
108
-
109
- return foreignKeyUpdates;
110
- };
108
+
109
+ return foreignKeyUpdates
110
+ }