json-rest-api 1.0.29 → 2.1.0

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 (294) hide show
  1. package/LICENSE +10 -670
  2. package/LICENSE-GPL-3.0 +674 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +39 -30
  5. package/docs/API.md +744 -1273
  6. package/docs/GUIDE/01-getting-started.md +338 -0
  7. package/docs/GUIDE/02-resources-and-relationships.md +33 -0
  8. package/docs/GUIDE/03-running-example.md +87 -0
  9. package/docs/GUIDE/04-creating-and-querying.md +181 -0
  10. package/docs/GUIDE/05-belongs-to.md +177 -0
  11. package/docs/GUIDE/06-has-many.md +184 -0
  12. package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
  13. package/docs/GUIDE/08-many-to-many.md +184 -0
  14. package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
  15. package/docs/GUIDE/10-put-and-patch.md +174 -0
  16. package/docs/GUIDE/11-relationship-endpoints.md +174 -0
  17. package/docs/GUIDE/12-field-transformations.md +287 -0
  18. package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
  19. package/docs/GUIDE/14-custom-resource-methods.md +125 -0
  20. package/docs/GUIDE/15-query-projections.md +266 -0
  21. package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
  22. package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
  23. package/docs/GUIDE/18-labels.md +86 -0
  24. package/docs/GUIDE/19-managed-transactions.md +179 -0
  25. package/docs/GUIDE/20-transaction-outcomes.md +207 -0
  26. package/docs/GUIDE/21-schema-and-migrations.md +733 -0
  27. package/docs/GUIDE/22-version-field-migrations.md +208 -0
  28. package/docs/GUIDE/23-fastify.md +179 -0
  29. package/docs/GUIDE/24-cors.md +172 -0
  30. package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
  31. package/docs/GUIDE/26-file-uploads.md +278 -0
  32. package/docs/GUIDE/27-bulk-operations.md +277 -0
  33. package/docs/GUIDE/28-socketio.md +325 -0
  34. package/docs/GUIDE/29-writing-plugins.md +278 -0
  35. package/docs/GUIDE/30-backend-capabilities.md +103 -0
  36. package/docs/GUIDE/31-positioning.md +181 -0
  37. package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +74 -30
  38. package/docs/GUIDE/33-migrating-to-v2.md +3838 -0
  39. package/docs/GUIDE/index.md +51 -59
  40. package/docs/QUICKSTART.md +120 -287
  41. package/docs/architecture.md +75 -0
  42. package/docs/contributing.md +178 -0
  43. package/index.d.ts +37 -0
  44. package/index.js +3 -22
  45. package/lib/enhanced-logger.js +91 -85
  46. package/lib/error-context.js +445 -5
  47. package/lib/error-formatter.js +219 -59
  48. package/lib/knex-transaction.js +70 -0
  49. package/lib/logger-types.d.ts +22 -0
  50. package/lib/missing-package.js +4 -0
  51. package/lib/rest-api-errors.js +103 -8
  52. package/lib/runtime/json-rest-api.js +172 -0
  53. package/lib/transaction-types.d.ts +59 -0
  54. package/package.json +97 -27
  55. package/plugins/core/bulk-operations-plugin.js +191 -184
  56. package/plugins/core/connectors/express-plugin.js +148 -219
  57. package/plugins/core/connectors/fastify-plugin.js +125 -82
  58. package/plugins/core/connectors/lib/busboy-detector.js +74 -156
  59. package/plugins/core/connectors/lib/connector-core.js +144 -20
  60. package/plugins/core/connectors/lib/formidable-detector.js +63 -120
  61. package/plugins/core/connectors/lib/http-validators.js +77 -0
  62. package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
  63. package/plugins/core/connectors/lib/request-helpers.js +10 -1
  64. package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
  65. package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
  66. package/plugins/core/file-handling-plugin.js +87 -177
  67. package/plugins/core/lib/anyapi/anyapi-registry.js +586 -418
  68. package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
  69. package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
  70. package/plugins/core/lib/anyapi/schema-utils.js +120 -56
  71. package/plugins/core/lib/anyapi/stored-definition.js +109 -0
  72. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
  73. package/plugins/core/lib/dbIntrospection.js +228 -21
  74. package/plugins/core/lib/dbTablesOperations.js +409 -92
  75. package/plugins/core/lib/fractional-positioning.js +12 -48
  76. package/plugins/core/lib/querying/identifier-query.js +19 -0
  77. package/plugins/core/lib/querying/include-query-helpers.js +364 -0
  78. package/plugins/core/lib/querying/include-to-many.js +428 -0
  79. package/plugins/core/lib/querying/include-to-one.js +579 -0
  80. package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
  81. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
  82. package/plugins/core/lib/querying/knex-pagination-helpers.js +48 -317
  83. package/plugins/core/lib/querying/knex-process-includes.js +5 -110
  84. package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
  85. package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
  86. package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
  87. package/plugins/core/lib/querying/knex-window-queries.js +62 -253
  88. package/plugins/core/lib/querying/query-builder-utils.js +44 -4
  89. package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
  90. package/plugins/core/lib/querying/query-constraint.js +27 -0
  91. package/plugins/core/lib/querying/query-field-sort-helpers.js +134 -37
  92. package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
  93. package/plugins/core/lib/querying/sort-helpers.js +13 -1
  94. package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
  95. package/plugins/core/lib/querying/url-helpers.js +11 -4
  96. package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
  97. package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
  98. package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
  99. package/plugins/core/lib/querying-writing/database-value-normalizers.js +179 -194
  100. package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
  101. package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
  102. package/plugins/core/lib/querying-writing/field-utils.js +113 -92
  103. package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
  104. package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
  105. package/plugins/core/lib/querying-writing/knex-field-helpers.js +100 -290
  106. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
  107. package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
  108. package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
  109. package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
  110. package/plugins/core/lib/querying-writing/request-contracts.js +93 -38
  111. package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
  112. package/plugins/core/lib/querying-writing/response-options.js +35 -0
  113. package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
  114. package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
  115. package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
  116. package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
  117. package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
  118. package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
  119. package/plugins/core/lib/storage/storage-adapter.js +128 -62
  120. package/plugins/core/lib/storage/storage-mapping.js +78 -28
  121. package/plugins/core/lib/storage/storage-types.d.ts +502 -0
  122. package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
  123. package/plugins/core/lib/writing/relationship-processor.js +94 -158
  124. package/plugins/core/lib/writing/resource-version.js +172 -0
  125. package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
  126. package/plugins/core/rest-api-anyapi-knex-plugin.js +290 -2475
  127. package/plugins/core/rest-api-autofilter-plugin.js +17 -19
  128. package/plugins/core/rest-api-cors-plugin.js +52 -205
  129. package/plugins/core/rest-api-knex-plugin.js +45 -1077
  130. package/plugins/core/rest-api-label-plugin.js +25 -38
  131. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
  132. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
  133. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
  134. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
  135. package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
  136. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
  137. package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
  138. package/plugins/core/rest-api-plugin-methods/common.js +291 -395
  139. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
  140. package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
  141. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -148
  142. package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
  143. package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
  144. package/plugins/core/rest-api-plugin-methods/get.js +36 -68
  145. package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
  146. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
  147. package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
  148. package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
  149. package/plugins/core/rest-api-plugin-methods/post.js +51 -51
  150. package/plugins/core/rest-api-plugin-methods/put.js +69 -148
  151. package/plugins/core/rest-api-plugin-methods/query.js +37 -81
  152. package/plugins/core/rest-api-plugin-methods/release.js +2 -1
  153. package/plugins/core/rest-api-plugin.js +32 -46
  154. package/plugins/core/rest-api-positioning-plugin.js +183 -628
  155. package/plugins/core/rest-api-query-projections-plugin.js +19 -102
  156. package/plugins/core/rest-api-row-policy-plugin.js +3 -3
  157. package/plugins/core/socketio-plugin.js +364 -344
  158. package/plugins/storage/local-storage.js +40 -36
  159. package/types/anyapi.d.ts +30 -0
  160. package/types/autofilter.d.ts +57 -0
  161. package/types/bulk-methods.d.ts +63 -0
  162. package/types/errors.d.ts +118 -0
  163. package/types/fastify-options.d.ts +19 -0
  164. package/types/file-detectors.d.ts +33 -0
  165. package/types/file-storage.d.ts +48 -0
  166. package/types/hook-context.d.ts +180 -0
  167. package/types/plugin-options.d.ts +65 -0
  168. package/types/relationship-methods.d.ts +74 -0
  169. package/types/representations.d.ts +50 -0
  170. package/types/resource-methods.d.ts +95 -0
  171. package/types/resource-schema.d.ts +157 -0
  172. package/types/row-policy.d.ts +31 -0
  173. package/types/runtime.d.ts +132 -0
  174. package/types/transactions.d.ts +21 -0
  175. package/.claude/agents/library-guide-expert.md +0 -30
  176. package/.claude/agents/rest-api-internals-expert.md +0 -54
  177. package/.claude/settings.local.json +0 -70
  178. package/AGENTS.md +0 -34
  179. package/CLAUDE.md +0 -160
  180. package/CRUSH.md +0 -55
  181. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
  182. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
  183. package/TODO.todo +0 -13
  184. package/connectors_ideas/fastify.js +0 -217
  185. package/connectors_ideas/koa-plugin.js +0 -112
  186. package/docs/.bundle/config +0 -2
  187. package/docs/COMPARISON.md +0 -433
  188. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
  189. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
  190. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
  191. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
  192. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
  193. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
  194. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
  195. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1247
  196. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
  197. package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
  198. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
  199. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
  200. package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
  201. package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
  202. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
  203. package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
  204. package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
  205. package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
  206. package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
  207. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
  208. package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
  209. package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
  210. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
  211. package/docs/Gemfile +0 -6
  212. package/docs/Gemfile.lock +0 -308
  213. package/docs/ONBOARDING.md +0 -315
  214. package/docs/_config.yml +0 -36
  215. package/docs/_layouts/default.html +0 -123
  216. package/docs/apple-touch-icon.svg +0 -4
  217. package/docs/assets/css/style.scss +0 -392
  218. package/docs/favicon.svg +0 -4
  219. package/docs/index.md +0 -164
  220. package/docs/mini-guides/file-uploads-complete.md +0 -161
  221. package/eslint.config.js +0 -13
  222. package/examples/url-override-example.js +0 -137
  223. package/fixing_plan.md +0 -112
  224. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
  225. package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
  226. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
  227. package/plugins/storage/s3-storage.js +0 -93
  228. package/quickTest.js +0 -136
  229. package/scripts/debug-anyapi-review-filter.mjs +0 -63
  230. package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
  231. package/scripts/inspect-anyapi-descriptor.mjs +0 -19
  232. package/scripts/run-docs.js +0 -133
  233. package/test-debug.js +0 -59
  234. package/tests/README.md +0 -202
  235. package/tests/TEST_TEMPLATE.test.js +0 -178
  236. package/tests/anyapi-basic.test.js +0 -105
  237. package/tests/anyapi-cursor-pagination.test.js +0 -148
  238. package/tests/anyapi-custom-idproperty.test.js +0 -163
  239. package/tests/autofilter.test.js +0 -463
  240. package/tests/bulk-operations.test.js +0 -657
  241. package/tests/computed-fields.test.js +0 -586
  242. package/tests/cors.test.js +0 -834
  243. package/tests/curl.test.js +0 -467
  244. package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
  245. package/tests/custom-id-simplified-post.test.js +0 -75
  246. package/tests/custom-idproperty-relationships.test.js +0 -932
  247. package/tests/db-introspection.test.js +0 -521
  248. package/tests/db-table-operations.test.js +0 -798
  249. package/tests/fastify-plugin.test.js +0 -184
  250. package/tests/field-getters.test.js +0 -370
  251. package/tests/field-setters.test.js +0 -306
  252. package/tests/file-handling.test.js +0 -155
  253. package/tests/fixtures/api-configs.js +0 -2566
  254. package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
  255. package/tests/helpers/fake-fastify.js +0 -99
  256. package/tests/helpers/storage-mode.js +0 -65
  257. package/tests/helpers/test-utils.js +0 -203
  258. package/tests/http-connectors-parity.test.js +0 -395
  259. package/tests/id-normalization.test.js +0 -444
  260. package/tests/include-depth-validation.test.js +0 -331
  261. package/tests/includes.test.js +0 -427
  262. package/tests/local-storage.test.js +0 -96
  263. package/tests/logical-id-write-validation.test.js +0 -151
  264. package/tests/nested-includes.test.js +0 -617
  265. package/tests/pagination-boundaries.test.js +0 -154
  266. package/tests/pagination-contract.test.js +0 -122
  267. package/tests/pagination-cursor-multifield.test.js +0 -641
  268. package/tests/pagination-enhanced.test.js +0 -563
  269. package/tests/polymorphic-relationships.test.js +0 -347
  270. package/tests/polymorphic-simple.test.js +0 -148
  271. package/tests/positioning-advanced.test.js +0 -692
  272. package/tests/positioning-extended.test.js +0 -915
  273. package/tests/positioning-multifilter.test.js +0 -699
  274. package/tests/positioning.test.js +0 -560
  275. package/tests/post-commit-hooks.test.js +0 -120
  276. package/tests/projected-fields.test.js +0 -319
  277. package/tests/public-exports.test.js +0 -15
  278. package/tests/put-create-parity.test.js +0 -216
  279. package/tests/queries.test.js +0 -521
  280. package/tests/query-limits.test.js +0 -584
  281. package/tests/relationship-endpoints.test.js +0 -620
  282. package/tests/relationship-include-storage-adapter.test.js +0 -56
  283. package/tests/relationships.test.js +0 -681
  284. package/tests/rest-api.test.js +0 -337
  285. package/tests/return-record-settings.test.js +0 -184
  286. package/tests/row-policy.test.js +0 -489
  287. package/tests/s3-storage.test.js +0 -38
  288. package/tests/searchschema-knex-behavior.test.js +0 -187
  289. package/tests/searchschema-merge.test.js +0 -151
  290. package/tests/socketio.test.js +0 -860
  291. package/tests/storage-mapping.test.js +0 -362
  292. package/tests/temporal-boundaries.test.js +0 -208
  293. package/tests/test-development-guide.md +0 -370
  294. package/tests/virtual-fields.test.js +0 -404
@@ -1,370 +0,0 @@
1
- # Test Development Guide for JSON-REST-API
2
-
3
- ## Missing tests:
4
-
5
- ⎿  ☒ Plan test structure and API configurations
6
- X Create test file with basic setup and utilities
7
- X Implement basic CRUD tests (POST, GET, PUT, PATCH, DELETE)
8
- ? Implement relationship tests (belongsTo, hasMany, many-to-many)
9
- ? Implement query tests (filtering, sorting, pagination)
10
- ? Implement include/sideloading tests
11
- ? Implement sparse fieldsets tests
12
- ? Implement transaction and error handling tests
13
-
14
- This guide provides comprehensive instructions for continuing test development following established patterns.
15
-
16
- ## Critical Requirements
17
-
18
- ### 1. Strict Mode is MANDATORY
19
-
20
- **NEVER** use `simplified: true` in tests (except internally for pivot operations):
21
-
22
- ```javascript
23
- // ✅ CORRECT - Always use simplified: false
24
- const result = await api.resources.books.post({
25
- inputRecord: bookDoc,
26
- simplified: false // REQUIRED
27
- });
28
-
29
- // ❌ WRONG - Never use simplified: true in tests
30
- const result = await api.resources.books.post({
31
- inputRecord: bookDoc,
32
- simplified: true // FORBIDDEN in tests
33
- });
34
- ```
35
-
36
- ### 2. Foreign Keys via Relationships ONLY
37
-
38
- In strict mode, foreign keys MUST be set through relationships:
39
-
40
- ```javascript
41
- // ❌ WRONG - Foreign key in attributes
42
- const bookDoc = createJsonApiDocument('books', {
43
- title: 'My Book',
44
- country_id: 123, // WILL FAIL!
45
- publisher_id: 456 // WILL FAIL!
46
- });
47
-
48
- // ✅ CORRECT - Foreign keys via relationships
49
- const bookDoc = createJsonApiDocument('books',
50
- {
51
- title: 'My Book' // Only non-foreign-key attributes
52
- },
53
- {
54
- country: createRelationship(resourceIdentifier('countries', countryId)),
55
- publisher: createRelationship(resourceIdentifier('publishers', publisherId))
56
- }
57
- );
58
- ```
59
-
60
- ### 3. returnFullRecord Configuration
61
-
62
- Control what methods return:
63
-
64
- ```javascript
65
- // In API configuration
66
- returnFullRecord: {
67
- post: 'full', // Return created record (needed to get ID)
68
- put: 'no', // Don't return after replacement
69
- patch: 'no' // Don't return after update
70
- }
71
-
72
- // Override per call if needed
73
- const result = await api.resources.books.put({
74
- id: bookId,
75
- inputRecord: putDoc,
76
- simplified: false,
77
- returnFullRecord: 'no' // Override to not return
78
- });
79
- ```
80
-
81
- ### 4. Database Operations Rules
82
-
83
- **ONLY** these Knex operations are allowed directly:
84
-
85
- ```javascript
86
- // ✅ ALLOWED - Counting records
87
- const count = await countRecords(knex, 'basic_books');
88
-
89
- // ✅ ALLOWED - Cleaning tables between tests
90
- await cleanTables(knex, ['basic_books', 'basic_authors']);
91
-
92
- // ❌ FORBIDDEN - Direct queries
93
- const books = await knex('basic_books').select('*'); // NO!
94
-
95
- // ❌ FORBIDDEN - Direct inserts
96
- await knex('basic_books').insert({...}); // NO!
97
- ```
98
-
99
- All data operations MUST go through the API.
100
-
101
- ## Test Structure Patterns
102
-
103
- ### Basic Test Setup
104
-
105
- ```javascript
106
- describe('Feature Name', () => {
107
- let basicApi;
108
- let extendedApi;
109
-
110
- before(async () => {
111
- // Initialize APIs once
112
- basicApi = await createBasicApi(knex);
113
- extendedApi = await createExtendedApi(knex);
114
- });
115
-
116
- after(async () => {
117
- // CRITICAL: Close database connection
118
- await knex.destroy();
119
- });
120
-
121
- describe('Sub-feature', () => {
122
- beforeEach(async () => {
123
- // Clean tables before EACH test
124
- await cleanTables(knex, [
125
- 'basic_countries', 'basic_publishers',
126
- 'basic_authors', 'basic_books', 'basic_book_authors'
127
- ]);
128
- });
129
-
130
- it('should do something', async () => {
131
- // Test implementation
132
- });
133
- });
134
- });
135
- ```
136
-
137
- ### Creating Test Data
138
-
139
- ```javascript
140
- // Step 1: Create parent resources first
141
- const countryDoc = createJsonApiDocument('countries', {
142
- name: 'Test Country',
143
- code: 'TC'
144
- });
145
- const countryResult = await basicApi.resources.countries.post({
146
- inputRecord: countryDoc,
147
- simplified: false
148
- });
149
- const countryId = countryResult.data.id;
150
-
151
- // Step 2: Create child resources with relationships
152
- const publisherDoc = createJsonApiDocument('publishers',
153
- { name: 'Test Publisher' },
154
- {
155
- country: createRelationship(resourceIdentifier('countries', countryId))
156
- }
157
- );
158
- const publisherResult = await basicApi.resources.publishers.post({
159
- inputRecord: publisherDoc,
160
- simplified: false
161
- });
162
-
163
- // Step 3: Create many-to-many relationships
164
- const bookDoc = createJsonApiDocument('books',
165
- { title: 'Test Book' },
166
- {
167
- country: createRelationship(resourceIdentifier('countries', countryId)),
168
- publisher: createRelationship(resourceIdentifier('publishers', publisherId)),
169
- authors: createToManyRelationship([
170
- resourceIdentifier('authors', author1Id),
171
- resourceIdentifier('authors', author2Id)
172
- ])
173
- }
174
- );
175
- ```
176
-
177
- ### Validation Patterns
178
-
179
- ```javascript
180
- // 1. Always validate JSON:API structure first
181
- validateJsonApiStructure(result, false); // false = single resource
182
- validateJsonApiStructure(result, true); // true = collection
183
-
184
- // 2. Validate attributes
185
- assertResourceAttributes(result.data, {
186
- title: 'Expected Title',
187
- price: '29.99'
188
- });
189
-
190
- // 3. Validate relationships
191
- assertResourceRelationship(result.data, 'publisher',
192
- resourceIdentifier('publishers', publisherId));
193
-
194
- // 4. Validate included resources
195
- assert(result.included, 'Should have included data');
196
- const publisher = result.included.find(r => r.type === 'publishers');
197
- assert(publisher, 'Should include publisher');
198
-
199
- // 5. Count database records for verification
200
- const count = await countRecords(knex, 'basic_books');
201
- assert.equal(count, 1, 'Should have created one book');
202
- ```
203
-
204
- ## Common Test Scenarios
205
-
206
- ### 1. Testing Relationships
207
-
208
- ```javascript
209
- describe('Relationship Operations', () => {
210
- it('should update many-to-many relationships', async () => {
211
- // Create initial relationships
212
- const bookDoc = createJsonApiDocument('books',
213
- { title: 'Book with Authors' },
214
- {
215
- authors: createToManyRelationship([
216
- resourceIdentifier('authors', author1Id),
217
- resourceIdentifier('authors', author2Id)
218
- ])
219
- }
220
- );
221
-
222
- // Update relationships via PATCH
223
- const patchDoc = {
224
- data: {
225
- type: 'books',
226
- id: String(bookId),
227
- relationships: {
228
- authors: createToManyRelationship([
229
- resourceIdentifier('authors', author2Id), // Keep this
230
- resourceIdentifier('authors', author3Id) // Add this
231
- // author1 will be removed
232
- ])
233
- }
234
- }
235
- };
236
-
237
- await basicApi.resources.books.patch({
238
- id: bookId,
239
- inputRecord: patchDoc,
240
- simplified: false
241
- });
242
-
243
- // Verify pivot table changes
244
- const pivotCount = await countRecords(knex, 'basic_book_authors');
245
- assert.equal(pivotCount, 2);
246
- });
247
- });
248
- ```
249
-
250
- ### 2. Testing Query Operations
251
-
252
- ```javascript
253
- describe('Query Operations', () => {
254
- it('should filter and sort with pagination', async () => {
255
- const result = await api.resources.books.query({
256
- queryParams: {
257
- filters: { language: 'en', price: '19.99' },
258
- sort: ['title', '-published_date'],
259
- page: { number: 1, size: 10 },
260
- include: ['publisher', 'authors']
261
- },
262
- simplified: false
263
- });
264
-
265
- validateJsonApiStructure(result, true);
266
- assert(result.data.length <= 10, 'Should respect page size');
267
- });
268
- });
269
- ```
270
-
271
- ### 3. Testing Error Conditions
272
-
273
- ```javascript
274
- describe('Error Handling', () => {
275
- it('should reject invalid relationships', async () => {
276
- const bookDoc = createJsonApiDocument('books',
277
- { title: 'Invalid Book' },
278
- {
279
- publisher: createRelationship(resourceIdentifier('publishers', 99999))
280
- }
281
- );
282
-
283
- await assert.rejects(
284
- async () => {
285
- await api.resources.books.post({
286
- inputRecord: bookDoc,
287
- simplified: false
288
- });
289
- },
290
- (err) => {
291
- return err.code === 'REST_API_RESOURCE' &&
292
- err.subtype === 'not_found';
293
- },
294
- 'Should throw not found error for invalid publisher'
295
- );
296
- });
297
- });
298
- ```
299
-
300
- ## Schema Configuration for Tests
301
-
302
- ### Enable Filtering
303
-
304
- Add `search: true` to fields that need filtering:
305
-
306
- ```javascript
307
- schema: {
308
- title: { type: 'string', required: true, search: true },
309
- price: { type: 'decimal', precision: 10, scale: 2, search: true },
310
- country_id: {
311
- type: 'number',
312
- belongsTo: 'countries',
313
- as: 'country',
314
- search: true // Enable filtering on foreign key
315
- }
316
- }
317
- ```
318
-
319
- ### Enable Sorting
320
-
321
- Configure sortable fields in plugin options:
322
-
323
- ```javascript
324
- await api.use(RestApiPlugin, {
325
- simplified: false,
326
- sortableFields: ['id', 'title', 'price', 'published_date'],
327
- // ... other options
328
- });
329
- ```
330
-
331
- ## Test Data Best Practices
332
-
333
- 1. **Use descriptive names**: 'Test Book A' instead of 'Book 1'
334
- 2. **Create minimal data**: Only what's needed for the test
335
- 3. **Clean between tests**: Always use `beforeEach` with `cleanTables`
336
- 4. **Store IDs for reuse**: Extract IDs immediately after creation
337
- 5. **Use unique prefixes**: 'basic_' vs 'ext_' for table names
338
-
339
- ## Debugging Tests
340
-
341
- ```bash
342
- # Run with debug output
343
- DEBUG=* npm test
344
-
345
- # Run single test file
346
- npm test -- tests/relationships.test.js
347
-
348
- # Check for hanging tests
349
- # Ensure after() hook closes database: await knex.destroy()
350
- ```
351
-
352
- ## Common Pitfalls to Avoid
353
-
354
- 1. **Forgetting simplified: false** - Will cause validation to fail
355
- 2. **Setting foreign keys in attributes** - Use relationships instead
356
- 3. **Not cleaning between tests** - Causes data conflicts
357
- 4. **Direct database access** - Always use API methods
358
- 5. **Not closing database** - Tests will hang
359
- 6. **Assuming sort order** - Always specify sort explicitly
360
- 7. **Hardcoding IDs** - Always extract from creation responses
361
-
362
- ## Next Test Suites to Implement
363
-
364
- 1. **sparse-fieldsets.test.js** - Field selection tests
365
- 2. **errors.test.js** - Comprehensive error handling
366
- 3. **transactions.test.js** - Transaction rollback tests
367
- 4. **validation.test.js** - Schema validation edge cases
368
- 5. **polymorphic.test.js** - Polymorphic relationship tests
369
-
370
- Each should follow the patterns established in existing tests.