json-rest-api 1.0.28 → 2.0.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 (289) 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 +746 -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 +634 -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 +100 -0
  36. package/docs/GUIDE/31-positioning.md +181 -0
  37. package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +90 -31
  38. package/docs/GUIDE/33-migrating-to-v2.md +3827 -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 +36 -0
  44. package/index.js +1 -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 +64 -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 -174
  67. package/plugins/core/lib/anyapi/anyapi-registry.js +213 -164
  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 +25 -16
  71. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
  72. package/plugins/core/lib/dbIntrospection.js +228 -21
  73. package/plugins/core/lib/dbTablesOperations.js +409 -92
  74. package/plugins/core/lib/fractional-positioning.js +12 -48
  75. package/plugins/core/lib/querying/identifier-query.js +19 -0
  76. package/plugins/core/lib/querying/include-query-helpers.js +364 -0
  77. package/plugins/core/lib/querying/include-to-many.js +428 -0
  78. package/plugins/core/lib/querying/include-to-one.js +579 -0
  79. package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
  80. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
  81. package/plugins/core/lib/querying/knex-pagination-helpers.js +67 -330
  82. package/plugins/core/lib/querying/knex-process-includes.js +5 -110
  83. package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
  84. package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
  85. package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
  86. package/plugins/core/lib/querying/knex-window-queries.js +62 -253
  87. package/plugins/core/lib/querying/query-builder-utils.js +44 -4
  88. package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
  89. package/plugins/core/lib/querying/query-constraint.js +27 -0
  90. package/plugins/core/lib/querying/query-field-sort-helpers.js +205 -30
  91. package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
  92. package/plugins/core/lib/querying/sort-helpers.js +20 -1
  93. package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
  94. package/plugins/core/lib/querying/url-helpers.js +11 -4
  95. package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
  96. package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
  97. package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
  98. package/plugins/core/lib/querying-writing/database-value-normalizers.js +238 -187
  99. package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
  100. package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
  101. package/plugins/core/lib/querying-writing/field-utils.js +113 -92
  102. package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
  103. package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
  104. package/plugins/core/lib/querying-writing/knex-field-helpers.js +111 -287
  105. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
  106. package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
  107. package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
  108. package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
  109. package/plugins/core/lib/querying-writing/request-contracts.js +109 -44
  110. package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
  111. package/plugins/core/lib/querying-writing/response-options.js +35 -0
  112. package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
  113. package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
  114. package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
  115. package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
  116. package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
  117. package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
  118. package/plugins/core/lib/storage/storage-adapter.js +142 -62
  119. package/plugins/core/lib/storage/storage-mapping.js +78 -28
  120. package/plugins/core/lib/storage/storage-types.d.ts +502 -0
  121. package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
  122. package/plugins/core/lib/writing/relationship-processor.js +94 -158
  123. package/plugins/core/lib/writing/resource-version.js +172 -0
  124. package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
  125. package/plugins/core/rest-api-anyapi-knex-plugin.js +116 -2509
  126. package/plugins/core/rest-api-autofilter-plugin.js +17 -19
  127. package/plugins/core/rest-api-cors-plugin.js +52 -205
  128. package/plugins/core/rest-api-knex-plugin.js +45 -1069
  129. package/plugins/core/rest-api-label-plugin.js +25 -38
  130. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
  131. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
  132. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
  133. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
  134. package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
  135. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
  136. package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
  137. package/plugins/core/rest-api-plugin-methods/common.js +291 -385
  138. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
  139. package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
  140. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -145
  141. package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
  142. package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
  143. package/plugins/core/rest-api-plugin-methods/get.js +38 -69
  144. package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
  145. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
  146. package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
  147. package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
  148. package/plugins/core/rest-api-plugin-methods/post.js +51 -51
  149. package/plugins/core/rest-api-plugin-methods/put.js +69 -148
  150. package/plugins/core/rest-api-plugin-methods/query.js +39 -82
  151. package/plugins/core/rest-api-plugin-methods/release.js +2 -1
  152. package/plugins/core/rest-api-plugin.js +32 -46
  153. package/plugins/core/rest-api-positioning-plugin.js +183 -628
  154. package/plugins/core/rest-api-query-projections-plugin.js +19 -102
  155. package/plugins/core/rest-api-row-policy-plugin.js +3 -3
  156. package/plugins/core/socketio-plugin.js +364 -344
  157. package/plugins/storage/local-storage.js +40 -36
  158. package/types/autofilter.d.ts +57 -0
  159. package/types/bulk-methods.d.ts +63 -0
  160. package/types/errors.d.ts +118 -0
  161. package/types/fastify-options.d.ts +19 -0
  162. package/types/file-detectors.d.ts +33 -0
  163. package/types/file-storage.d.ts +48 -0
  164. package/types/hook-context.d.ts +180 -0
  165. package/types/plugin-options.d.ts +53 -0
  166. package/types/relationship-methods.d.ts +74 -0
  167. package/types/representations.d.ts +50 -0
  168. package/types/resource-methods.d.ts +95 -0
  169. package/types/resource-schema.d.ts +157 -0
  170. package/types/row-policy.d.ts +31 -0
  171. package/types/runtime.d.ts +132 -0
  172. package/types/transactions.d.ts +21 -0
  173. package/.claude/agents/library-guide-expert.md +0 -30
  174. package/.claude/agents/rest-api-internals-expert.md +0 -54
  175. package/.claude/settings.local.json +0 -70
  176. package/AGENTS.md +0 -34
  177. package/CLAUDE.md +0 -160
  178. package/CRUSH.md +0 -55
  179. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
  180. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
  181. package/TODO.todo +0 -13
  182. package/connectors_ideas/fastify.js +0 -217
  183. package/connectors_ideas/koa-plugin.js +0 -112
  184. package/docs/.bundle/config +0 -2
  185. package/docs/COMPARISON.md +0 -433
  186. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
  187. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
  188. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
  189. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
  190. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
  191. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
  192. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
  193. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1238
  194. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
  195. package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
  196. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
  197. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
  198. package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
  199. package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
  200. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
  201. package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
  202. package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
  203. package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
  204. package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
  205. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
  206. package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
  207. package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
  208. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
  209. package/docs/Gemfile +0 -6
  210. package/docs/Gemfile.lock +0 -308
  211. package/docs/ONBOARDING.md +0 -315
  212. package/docs/_config.yml +0 -36
  213. package/docs/_layouts/default.html +0 -123
  214. package/docs/apple-touch-icon.svg +0 -4
  215. package/docs/assets/css/style.scss +0 -392
  216. package/docs/favicon.svg +0 -4
  217. package/docs/index.md +0 -164
  218. package/docs/mini-guides/file-uploads-complete.md +0 -161
  219. package/eslint.config.js +0 -13
  220. package/examples/url-override-example.js +0 -137
  221. package/fixing_plan.md +0 -112
  222. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
  223. package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
  224. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
  225. package/plugins/storage/s3-storage.js +0 -93
  226. package/quickTest.js +0 -136
  227. package/scripts/debug-anyapi-review-filter.mjs +0 -63
  228. package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
  229. package/scripts/inspect-anyapi-descriptor.mjs +0 -19
  230. package/scripts/run-docs.js +0 -133
  231. package/test-debug.js +0 -59
  232. package/tests/README.md +0 -202
  233. package/tests/TEST_TEMPLATE.test.js +0 -178
  234. package/tests/anyapi-basic.test.js +0 -105
  235. package/tests/anyapi-cursor-pagination.test.js +0 -150
  236. package/tests/anyapi-custom-idproperty.test.js +0 -163
  237. package/tests/autofilter.test.js +0 -463
  238. package/tests/bulk-operations.test.js +0 -657
  239. package/tests/computed-fields.test.js +0 -586
  240. package/tests/cors.test.js +0 -834
  241. package/tests/curl.test.js +0 -467
  242. package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
  243. package/tests/custom-id-simplified-post.test.js +0 -75
  244. package/tests/custom-idproperty-relationships.test.js +0 -932
  245. package/tests/db-introspection.test.js +0 -521
  246. package/tests/db-table-operations.test.js +0 -798
  247. package/tests/fastify-plugin.test.js +0 -184
  248. package/tests/field-getters.test.js +0 -370
  249. package/tests/field-setters.test.js +0 -306
  250. package/tests/file-handling.test.js +0 -118
  251. package/tests/fixtures/api-configs.js +0 -2509
  252. package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
  253. package/tests/helpers/fake-fastify.js +0 -99
  254. package/tests/helpers/storage-mode.js +0 -65
  255. package/tests/helpers/test-utils.js +0 -203
  256. package/tests/http-connectors-parity.test.js +0 -395
  257. package/tests/id-normalization.test.js +0 -444
  258. package/tests/include-depth-validation.test.js +0 -331
  259. package/tests/includes.test.js +0 -427
  260. package/tests/local-storage.test.js +0 -96
  261. package/tests/logical-id-write-validation.test.js +0 -151
  262. package/tests/nested-includes.test.js +0 -617
  263. package/tests/pagination-cursor-multifield.test.js +0 -643
  264. package/tests/pagination-enhanced.test.js +0 -563
  265. package/tests/polymorphic-relationships.test.js +0 -347
  266. package/tests/polymorphic-simple.test.js +0 -148
  267. package/tests/positioning-advanced.test.js +0 -692
  268. package/tests/positioning-extended.test.js +0 -915
  269. package/tests/positioning-multifilter.test.js +0 -699
  270. package/tests/positioning.test.js +0 -560
  271. package/tests/post-commit-hooks.test.js +0 -120
  272. package/tests/projected-fields.test.js +0 -319
  273. package/tests/public-exports.test.js +0 -15
  274. package/tests/put-create-parity.test.js +0 -216
  275. package/tests/queries.test.js +0 -521
  276. package/tests/query-limits.test.js +0 -584
  277. package/tests/relationship-endpoints.test.js +0 -620
  278. package/tests/relationship-include-storage-adapter.test.js +0 -56
  279. package/tests/relationships.test.js +0 -681
  280. package/tests/rest-api.test.js +0 -337
  281. package/tests/return-record-settings.test.js +0 -184
  282. package/tests/row-policy.test.js +0 -489
  283. package/tests/s3-storage.test.js +0 -38
  284. package/tests/searchschema-knex-behavior.test.js +0 -187
  285. package/tests/searchschema-merge.test.js +0 -151
  286. package/tests/socketio.test.js +0 -860
  287. package/tests/storage-mapping.test.js +0 -362
  288. package/tests/test-development-guide.md +0 -370
  289. 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.