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.
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 +13 -0
  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 +9 -5
  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,19 +1,19 @@
1
1
  /**
2
2
  * Parses database version string to comparable format
3
- *
3
+ *
4
4
  * @param {string} versionString - Raw version string from database
5
5
  * @returns {Object|null} Parsed version with major, minor, patch
6
- *
6
+ *
7
7
  * @example
8
8
  * // Input: MySQL version
9
9
  * parseVersion("8.0.33");
10
10
  * // Output: { major: 8, minor: 0, patch: 33 }
11
- *
11
+ *
12
12
  * @example
13
13
  * // Input: PostgreSQL version with extra info
14
14
  * parseVersion("14.5 (Ubuntu 14.5-1.pgdg20.04+1)");
15
15
  * // Output: { major: 14, minor: 5, patch: 0 }
16
- *
16
+ *
17
17
  * @example
18
18
  * // Input: MariaDB version
19
19
  * parseVersion("10.6.12-MariaDB");
@@ -24,60 +24,60 @@ const parseVersion = (versionString) => {
24
24
  // PostgreSQL: "14.5 (Ubuntu 14.5-1.pgdg20.04+1)"
25
25
  // MariaDB: "10.6.12-MariaDB"
26
26
  // SQLite: "3.35.5"
27
-
28
- const match = versionString.match(/(\d+)\.(\d+)(?:\.(\d+))?/);
29
- if (!match) return null;
30
-
27
+
28
+ const match = versionString.match(/(\d+)\.(\d+)(?:\.(\d+))?/)
29
+ if (!match) return null
30
+
31
31
  return {
32
32
  major: parseInt(match[1]),
33
33
  minor: parseInt(match[2]),
34
34
  patch: match[3] ? parseInt(match[3]) : 0
35
- };
36
- };
35
+ }
36
+ }
37
37
 
38
38
  /**
39
39
  * Checks if the database supports window functions based on version
40
- *
40
+ *
41
41
  * @param {Object} knex - Knex instance
42
42
  * @returns {Promise<boolean>} True if window functions are supported
43
- *
43
+ *
44
44
  * @example
45
45
  * // Input: MySQL 8.0.33
46
46
  * const supports = await supportsWindowFunctions(knex);
47
47
  * // Output: true (MySQL 8.0+ supports window functions)
48
- *
48
+ *
49
49
  * @example
50
- * // Input: MySQL 5.7.42
50
+ * // Input: MySQL 5.7.42
51
51
  * const supports = await supportsWindowFunctions(knex);
52
52
  * // Output: false (MySQL < 8.0 doesn't support window functions)
53
- *
53
+ *
54
54
  * @example
55
55
  * // Input: PostgreSQL (any modern version)
56
56
  * const supports = await supportsWindowFunctions(knex);
57
57
  * // Output: true (PostgreSQL 8.4+ supports window functions)
58
- *
58
+ *
59
59
  * @example
60
60
  * // Input: SQLite 3.24.0
61
61
  * const supports = await supportsWindowFunctions(knex);
62
62
  * // Output: false (SQLite needs 3.25.0+)
63
- *
63
+ *
64
64
  * @description
65
65
  * Used by:
66
66
  * - buildWindowedIncludeQuery to validate before using window functions
67
67
  * - rest-api-knex-plugin to determine query strategies
68
- *
68
+ *
69
69
  * Purpose:
70
70
  * - Prevents runtime errors by checking feature support
71
71
  * - Enables fallback strategies for older databases
72
72
  * - Provides clear error messages about version requirements
73
- *
73
+ *
74
74
  * Data flow:
75
75
  * 1. Identifies database client type from Knex config
76
76
  * 2. For version-dependent databases, queries version string
77
77
  * 3. Parses version and compares against known thresholds
78
78
  * 4. Returns boolean indicating support
79
79
  * 5. Falls back to false if version can't be determined
80
- *
80
+ *
81
81
  * Version requirements:
82
82
  * - PostgreSQL: 8.4+ (all modern versions)
83
83
  * - MySQL: 8.0+
@@ -88,67 +88,67 @@ const parseVersion = (versionString) => {
88
88
  */
89
89
  export const supportsWindowFunctions = async (knex) => {
90
90
  try {
91
- const client = knex.client.config.client;
92
-
93
- let versionString;
94
-
91
+ const client = knex.client.config.client
92
+
93
+ let versionString
94
+
95
95
  switch (client) {
96
96
  case 'pg':
97
97
  case 'postgresql':
98
98
  // PostgreSQL 8.4+ supports window functions (all modern versions)
99
- return true;
100
-
99
+ return true
100
+
101
101
  case 'mysql':
102
102
  case 'mysql2':
103
103
  try {
104
- const row = await knex.first(knex.raw('VERSION() as version'));
105
- const mysqlVersion = parseVersion(row.version);
104
+ const row = await knex.first(knex.raw('VERSION() as version'))
105
+ const mysqlVersion = parseVersion(row.version)
106
106
 
107
- return mysqlVersion && mysqlVersion.major >= 8;
107
+ return mysqlVersion && mysqlVersion.major >= 8
108
108
  } catch (dbError) {
109
- console.warn(`[supportsWindowFunctions] Failed to get MySQL version: ${dbError.message}`);
110
- return false;
109
+ console.warn(`[supportsWindowFunctions] Failed to get MySQL version: ${dbError.message}`)
110
+ return false
111
111
  }
112
-
112
+
113
113
  case 'sqlite3':
114
114
  case 'better-sqlite3':
115
115
  try {
116
- versionString = await knex.raw('SELECT sqlite_version() as version');
117
- const sqliteVersion = versionString[0].version;
116
+ versionString = await knex.raw('SELECT sqlite_version() as version')
117
+ const sqliteVersion = versionString[0].version
118
118
  // SQLite 3.25.0+ supports window functions
119
- const parsed = parseVersion(sqliteVersion);
120
- return parsed && (parsed.major > 3 || (parsed.major === 3 && parsed.minor >= 25));
119
+ const parsed = parseVersion(sqliteVersion)
120
+ return parsed && (parsed.major > 3 || (parsed.major === 3 && parsed.minor >= 25))
121
121
  } catch (dbError) {
122
- console.warn(`[supportsWindowFunctions] Failed to get SQLite version: ${dbError.message}`);
123
- return false;
122
+ console.warn(`[supportsWindowFunctions] Failed to get SQLite version: ${dbError.message}`)
123
+ return false
124
124
  }
125
-
125
+
126
126
  case 'mssql':
127
127
  // SQL Server 2005+ supports window functions
128
- return true;
129
-
128
+ return true
129
+
130
130
  case 'oracledb':
131
131
  // Oracle has supported window functions for a long time
132
- return true;
133
-
132
+ return true
133
+
134
134
  default:
135
135
  // For MariaDB, we need to check if it's actually MariaDB or MySQL
136
136
  if (client.includes('maria')) {
137
137
  try {
138
- versionString = await knex.raw('SELECT VERSION() as version');
139
- const version = versionString[0].version.toLowerCase();
138
+ versionString = await knex.raw('SELECT VERSION() as version')
139
+ const version = versionString[0].version.toLowerCase()
140
140
  if (version.includes('mariadb')) {
141
- const mariaVersion = parseVersion(version);
141
+ const mariaVersion = parseVersion(version)
142
142
  // MariaDB 10.2+ supports window functions
143
- return mariaVersion && (mariaVersion.major > 10 ||
144
- (mariaVersion.major === 10 && mariaVersion.minor >= 2));
143
+ return mariaVersion && (mariaVersion.major > 10 ||
144
+ (mariaVersion.major === 10 && mariaVersion.minor >= 2))
145
145
  }
146
146
  } catch (dbError) {
147
- console.warn(`[supportsWindowFunctions] Failed to get MariaDB version: ${dbError.message}`);
148
- return false;
147
+ console.warn(`[supportsWindowFunctions] Failed to get MariaDB version: ${dbError.message}`)
148
+ return false
149
149
  }
150
150
  }
151
- return false;
151
+ return false
152
152
  }
153
153
  } catch (error) {
154
154
  // Log error with context
@@ -156,52 +156,52 @@ export const supportsWindowFunctions = async (knex) => {
156
156
  error: error.message,
157
157
  stack: error.stack,
158
158
  client: knex?.client?.config?.client || 'unknown'
159
- });
159
+ })
160
160
  // If we can't determine, assume no support for safety
161
- return false;
161
+ return false
162
162
  }
163
- };
163
+ }
164
164
 
165
165
  /**
166
166
  * Gets database info for error messages and capability checks
167
- *
167
+ *
168
168
  * @param {Object} knex - Knex instance
169
169
  * @returns {Promise<Object>} Database info with client and version
170
- *
170
+ *
171
171
  * @example
172
172
  * // Input: MySQL connection
173
173
  * const info = await getDatabaseInfo(knex);
174
174
  * // Output: { client: 'MySQL', version: '8.0.33' }
175
- *
175
+ *
176
176
  * @example
177
177
  * // Input: PostgreSQL connection
178
178
  * const info = await getDatabaseInfo(knex);
179
- * // Output: {
180
- * // client: 'PostgreSQL',
179
+ * // Output: {
180
+ * // client: 'PostgreSQL',
181
181
  * // version: 'PostgreSQL 14.5 (Ubuntu 14.5-1.pgdg20.04+1)'
182
182
  * // }
183
- *
183
+ *
184
184
  * @example
185
185
  * // Input: Connection error case
186
186
  * const info = await getDatabaseInfo(knexWithError);
187
- * // Output: {
188
- * // client: 'MySQL',
187
+ * // Output: {
188
+ * // client: 'MySQL',
189
189
  * // version: 'unknown',
190
190
  * // error: 'Connection refused'
191
191
  * // }
192
- *
192
+ *
193
193
  * @description
194
194
  * Used by:
195
195
  * - Error messages to show which database/version lacks a feature
196
196
  * - Capability detection for feature flags
197
197
  * - Debugging connection issues
198
- *
198
+ *
199
199
  * Purpose:
200
200
  * - Provides human-readable database identification
201
201
  * - Helps users understand version requirements
202
202
  * - Enables detailed error messages
203
203
  * - Gracefully handles query failures
204
- *
204
+ *
205
205
  * Data flow:
206
206
  * 1. Identifies client type from Knex config
207
207
  * 2. Runs version query specific to each database
@@ -211,42 +211,42 @@ export const supportsWindowFunctions = async (knex) => {
211
211
  */
212
212
  export const getDatabaseInfo = async (knex) => {
213
213
  try {
214
- const client = knex.client.config.client;
215
-
216
- let versionString;
214
+ const client = knex.client.config.client
215
+
216
+ let versionString
217
217
  switch (client) {
218
218
  case 'mysql':
219
219
  case 'mysql2':
220
- try {
221
- const row = await knex.first(knex.raw('VERSION() as version'));
222
- return { client: 'MySQL', version: row.version };
223
- } catch (dbError) {
224
- console.warn(`[getDatabaseInfo] Failed to get MySQL version: ${dbError.message}`);
225
- return { client: 'MySQL', version: 'unknown', error: dbError.message };
226
- }
227
-
220
+ try {
221
+ const row = await knex.first(knex.raw('VERSION() as version'))
222
+ return { client: 'MySQL', version: row.version }
223
+ } catch (dbError) {
224
+ console.warn(`[getDatabaseInfo] Failed to get MySQL version: ${dbError.message}`)
225
+ return { client: 'MySQL', version: 'unknown', error: dbError.message }
226
+ }
227
+
228
228
  case 'sqlite3':
229
229
  case 'better-sqlite3':
230
230
  try {
231
- versionString = await knex.raw('SELECT sqlite_version() as version');
232
- return { client: 'SQLite', version: versionString[0].version };
231
+ versionString = await knex.raw('SELECT sqlite_version() as version')
232
+ return { client: 'SQLite', version: versionString[0].version }
233
233
  } catch (dbError) {
234
- console.warn(`[getDatabaseInfo] Failed to get SQLite version: ${dbError.message}`);
235
- return { client: 'SQLite', version: 'unknown', error: dbError.message };
234
+ console.warn(`[getDatabaseInfo] Failed to get SQLite version: ${dbError.message}`)
235
+ return { client: 'SQLite', version: 'unknown', error: dbError.message }
236
236
  }
237
-
237
+
238
238
  case 'pg':
239
239
  case 'postgresql':
240
240
  try {
241
- versionString = await knex.raw('SELECT version() as version');
242
- return { client: 'PostgreSQL', version: versionString.rows[0].version };
241
+ versionString = await knex.raw('SELECT version() as version')
242
+ return { client: 'PostgreSQL', version: versionString.rows[0].version }
243
243
  } catch (dbError) {
244
- console.warn(`[getDatabaseInfo] Failed to get PostgreSQL version: ${dbError.message}`);
245
- return { client: 'PostgreSQL', version: 'unknown', error: dbError.message };
244
+ console.warn(`[getDatabaseInfo] Failed to get PostgreSQL version: ${dbError.message}`)
245
+ return { client: 'PostgreSQL', version: 'unknown', error: dbError.message }
246
246
  }
247
-
247
+
248
248
  default:
249
- return { client, version: 'unknown' };
249
+ return { client, version: 'unknown' }
250
250
  }
251
251
  } catch (error) {
252
252
  // Log unexpected errors
@@ -254,12 +254,12 @@ export const getDatabaseInfo = async (knex) => {
254
254
  error: error.message,
255
255
  stack: error.stack,
256
256
  client: knex?.client?.config?.client || 'unknown'
257
- });
258
-
259
- return {
260
- client: knex?.client?.config?.client || 'unknown',
257
+ })
258
+
259
+ return {
260
+ client: knex?.client?.config?.client || 'unknown',
261
261
  version: 'unknown',
262
- error: error.message
263
- };
262
+ error: error.message
263
+ }
264
264
  }
265
- };
265
+ }