json-rest-api 1.0.22 → 1.0.24

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 (290) hide show
  1. package/CLAUDE.md +1 -2
  2. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +180 -0
  3. package/README.md +22 -1
  4. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
  5. package/docs/API.md +196 -38
  6. package/docs/COMPARISON.md +2 -2
  7. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +111 -5
  8. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +5 -1
  9. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +3 -1
  10. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +12 -60
  11. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +2 -2
  12. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +5 -1
  13. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +2 -0
  14. package/docs/GUIDE/GUIDE_X_Autofiltering.md +355 -0
  15. package/docs/GUIDE/GUIDE_X_Fastify.md +78 -0
  16. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +370 -0
  17. package/docs/GUIDE/GUIDE_X_Query_Projections.md +159 -0
  18. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +199 -0
  19. package/docs/GUIDE/index.md +18 -9
  20. package/docs/QUICKSTART.md +5 -1
  21. package/docs/index.md +1 -1
  22. package/index.js +3 -2
  23. package/lib/enhanced-logger.js +1 -1
  24. package/package.json +6 -2
  25. package/plugins/core/bulk-operations-plugin.js +26 -34
  26. package/plugins/core/connectors/express-plugin.js +97 -190
  27. package/plugins/core/connectors/fastify-plugin.js +206 -0
  28. package/plugins/core/connectors/lib/busboy-detector.js +4 -4
  29. package/plugins/core/connectors/lib/connector-core.js +195 -0
  30. package/plugins/core/connectors/lib/transport-http-helpers.js +122 -0
  31. package/plugins/core/connectors/lib/transport-route-schemas.js +92 -0
  32. package/plugins/core/lib/anyapi/schema-utils.js +43 -4
  33. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +4 -1
  34. package/plugins/core/lib/dbIntrospection.js +1078 -0
  35. package/plugins/core/lib/dbTablesOperations.js +1111 -160
  36. package/plugins/core/lib/querying/knex-cross-table-search.js +0 -7
  37. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -3
  38. package/plugins/core/lib/querying/knex-process-includes.js +3 -4
  39. package/plugins/core/lib/querying/knex-query-helpers.js +21 -76
  40. package/plugins/core/lib/querying/knex-relationship-includes.js +468 -215
  41. package/plugins/core/lib/querying/query-builder-utils.js +19 -0
  42. package/plugins/core/lib/querying/query-field-sort-helpers.js +135 -0
  43. package/plugins/core/lib/querying/sort-helpers.js +33 -0
  44. package/plugins/core/lib/querying/storage-adapter-utils.js +51 -0
  45. package/plugins/core/lib/querying/url-helpers.js +8 -2
  46. package/plugins/core/lib/querying-writing/compile-schemas.js +20 -5
  47. package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -14
  48. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +13 -12
  49. package/plugins/core/lib/querying-writing/query-field-helpers.js +88 -0
  50. package/plugins/core/lib/querying-writing/request-contracts.js +590 -0
  51. package/plugins/core/lib/querying-writing/resource-id-normalization.js +131 -0
  52. package/plugins/core/lib/querying-writing/schema-helpers.js +0 -2
  53. package/plugins/core/lib/querying-writing/simplified-helpers.js +4 -11
  54. package/plugins/core/lib/storage/canonical-storage-mapping.js +133 -0
  55. package/plugins/core/lib/storage/storage-adapter.js +82 -4
  56. package/plugins/core/lib/storage/storage-mapping.js +274 -0
  57. package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -2
  58. package/plugins/core/rest-api-anyapi-knex-plugin.js +531 -312
  59. package/plugins/core/rest-api-autofilter-plugin.js +414 -0
  60. package/plugins/core/rest-api-knex-plugin.js +271 -226
  61. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +10 -5
  62. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +12 -6
  63. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +1 -0
  64. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
  65. package/plugins/core/rest-api-plugin-methods/common.js +148 -92
  66. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +11 -2
  67. package/plugins/core/rest-api-plugin-methods/delete.js +6 -1
  68. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
  69. package/plugins/core/rest-api-plugin-methods/get-related.js +7 -2
  70. package/plugins/core/rest-api-plugin-methods/get-relationship.js +7 -2
  71. package/plugins/core/rest-api-plugin-methods/get.js +29 -14
  72. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +10 -3
  73. package/plugins/core/rest-api-plugin-methods/patch.js +56 -12
  74. package/plugins/core/rest-api-plugin-methods/post-relationship.js +11 -2
  75. package/plugins/core/rest-api-plugin-methods/post.js +21 -8
  76. package/plugins/core/rest-api-plugin-methods/put.js +73 -21
  77. package/plugins/core/rest-api-plugin-methods/query.js +15 -53
  78. package/plugins/core/rest-api-plugin-methods/release.js +0 -2
  79. package/plugins/core/rest-api-plugin.js +6 -0
  80. package/plugins/core/rest-api-positioning-plugin.js +2 -5
  81. package/plugins/core/rest-api-query-projections-plugin.js +130 -0
  82. package/plugins/core/socketio-plugin.js +1 -4
  83. package/plugins/storage/local-storage.js +1 -1
  84. package/plugins/storage/s3-storage.js +5 -2
  85. package/quickTest.js +1 -0
  86. package/scripts/run-docs.js +80 -84
  87. package/test-debug.js +1 -1
  88. package/tests/README.md +7 -0
  89. package/tests/anyapi-basic.test.js +3 -0
  90. package/tests/autofilter.test.js +463 -0
  91. package/tests/custom-id-mysql-returning-fallback.test.js +128 -0
  92. package/tests/custom-id-simplified-post.test.js +75 -0
  93. package/tests/custom-idproperty-relationships.test.js +33 -0
  94. package/tests/db-introspection.test.js +521 -0
  95. package/tests/db-table-operations.test.js +786 -0
  96. package/tests/fastify-plugin.test.js +156 -0
  97. package/tests/field-getters.test.js +1 -2
  98. package/tests/field-setters.test.js +0 -4
  99. package/tests/fixtures/api-configs.js +278 -176
  100. package/tests/helpers/fake-fastify.js +99 -0
  101. package/tests/http-connectors-parity.test.js +235 -0
  102. package/tests/id-normalization.test.js +444 -0
  103. package/tests/logical-id-write-validation.test.js +151 -0
  104. package/tests/pagination-cursor-multifield.test.js +11 -11
  105. package/tests/projected-fields.test.js +319 -0
  106. package/tests/relationships.test.js +3 -3
  107. package/tests/searchschema-knex-behavior.test.js +187 -0
  108. package/tests/searchschema-merge.test.js +21 -69
  109. package/tests/storage-mapping.test.js +259 -0
  110. package/audit/00-charter.md +0 -103
  111. package/audit/01-scope-map.md +0 -84
  112. package/audit/02-coverage-matrix.csv +0 -174
  113. package/audit/03-invariants.md +0 -123
  114. package/audit/04-standards-rubric.md +0 -56
  115. package/audit/05-competitor-rubric.md +0 -77
  116. package/audit/06-findings.md +0 -160
  117. package/audit/07-risk-register.csv +0 -10
  118. package/audit/08-remediation-roadmap.md +0 -177
  119. package/audit/09-signoff-check.md +0 -23
  120. package/audit/10-final-synthesis.md +0 -29
  121. package/audit/evidence/code/all-files-json-rest-api.txt +0 -168
  122. package/audit/evidence/code/all-files-json-rest-schema.txt +0 -12
  123. package/audit/evidence/code/boundary-leak-checks.txt +0 -72
  124. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +0 -480
  125. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +0 -532
  126. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +0 -175
  127. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +0 -138
  128. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +0 -222
  129. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +0 -342
  130. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +0 -304
  131. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +0 -188
  132. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +0 -336
  133. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +0 -165
  134. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +0 -265
  135. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +0 -369
  136. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +0 -72
  137. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +0 -139
  138. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +0 -45
  139. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +0 -396
  140. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +0 -162
  141. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +0 -1314
  142. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +0 -488
  143. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +0 -484
  144. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +0 -857
  145. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +0 -565
  146. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +0 -485
  147. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +0 -560
  148. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +0 -167
  149. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +0 -109
  150. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +0 -1064
  151. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +0 -1983
  152. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +0 -328
  153. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +0 -119
  154. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +0 -160
  155. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +0 -300
  156. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +0 -245
  157. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +0 -459
  158. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +0 -237
  159. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +0 -1135
  160. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +0 -314
  161. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +0 -7
  162. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +0 -71
  163. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +0 -102
  164. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +0 -49
  165. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +0 -39
  166. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +0 -23
  167. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +0 -13
  168. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +0 -639
  169. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +0 -117
  170. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +0 -104
  171. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +0 -199
  172. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +0 -353
  173. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +0 -61
  174. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +0 -184
  175. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +0 -55
  176. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +0 -191
  177. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +0 -110
  178. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +0 -168
  179. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +0 -253
  180. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +0 -207
  181. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +0 -12
  182. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +0 -165
  183. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +0 -668
  184. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +0 -621
  185. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +0 -218
  186. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +0 -124
  187. package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +0 -269
  188. package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +0 -242
  189. package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +0 -77
  190. package/audit/evidence/code/critical-pass1-risk-keywords.txt +0 -238
  191. package/audit/evidence/code/critical-pass1-summary.csv +0 -67
  192. package/audit/evidence/code/critical-pass2-summary.csv +0 -67
  193. package/audit/evidence/code/early-silent-zones-no-test-token.txt +0 -57
  194. package/audit/evidence/code/error-model-signals.txt +0 -98
  195. package/audit/evidence/code/git-files-json-rest-api.txt +0 -171
  196. package/audit/evidence/code/git-files-json-rest-schema.txt +0 -27
  197. package/audit/evidence/code/hook-flow-signals.txt +0 -282
  198. package/audit/evidence/code/idproperty-signals.txt +0 -157
  199. package/audit/evidence/code/import-cycles-non-anyapi.txt +0 -3
  200. package/audit/evidence/code/import-hotspots-non-anyapi.txt +0 -96
  201. package/audit/evidence/code/imports-json-rest-api.txt +0 -354
  202. package/audit/evidence/code/imports-json-rest-schema.txt +0 -15
  203. package/audit/evidence/code/in-scope-files-json-rest-api.txt +0 -160
  204. package/audit/evidence/code/in-scope-files-json-rest-schema.txt +0 -13
  205. package/audit/evidence/code/non-anyapi-core-files.txt +0 -101
  206. package/audit/evidence/code/permission-signals.txt +0 -193
  207. package/audit/evidence/code/query-include-signals.txt +0 -687
  208. package/audit/evidence/code/transaction-signals.txt +0 -28
  209. package/audit/evidence/code/validation-signals.txt +0 -650
  210. package/audit/evidence/code/write-path-signals.txt +0 -61
  211. package/audit/evidence/docs/docs-claims-signals.txt +0 -1075
  212. package/audit/evidence/docs/schema-docs-claims-signals.txt +0 -179
  213. package/audit/evidence/external/corpus-freeze.md +0 -21
  214. package/audit/evidence/external/npm-competitor-metadata.txt +0 -70
  215. package/audit/evidence/external/npm-download-signals.txt +0 -23
  216. package/audit/evidence/external/npm-jsonapi-server.txt +0 -8
  217. package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +0 -38
  218. package/audit/evidence/external/readme-fortune-signals.txt +0 -26
  219. package/audit/evidence/external/readme-fortune.md +0 -165
  220. package/audit/evidence/external/readme-json-api-serializer-signals.txt +0 -80
  221. package/audit/evidence/external/readme-json-api-serializer.md +0 -690
  222. package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
  223. package/audit/evidence/external/readme-jsonapi-serde-server.md +0 -22
  224. package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +0 -63
  225. package/audit/evidence/external/readme-jsonapi-serializer.md +0 -315
  226. package/audit/evidence/external/readme-jsonapi-server-signals.txt +0 -19
  227. package/audit/evidence/external/readme-jsonapi-server.md +0 -104
  228. package/audit/evidence/external/readme-nestjs-json-api-signals.txt +0 -4
  229. package/audit/evidence/external/readme-nestjs-json-api.md +0 -94
  230. package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +0 -47
  231. package/audit/evidence/external/readme-yaser-json-api-nestjs.md +0 -447
  232. package/audit/evidence/external/standard-jsonapi-snippets.txt +0 -84
  233. package/audit/evidence/external/standard-rfc-snippets.txt +0 -168
  234. package/audit/evidence/external/standards-sources.txt +0 -6
  235. package/audit/evidence/runtime/baseline-commits.txt +0 -2
  236. package/audit/evidence/runtime/db-adapter-assumptions.txt +0 -3
  237. package/audit/evidence/runtime/environment.txt +0 -4
  238. package/audit/evidence/runtime/invariant-runtime-mapping.md +0 -38
  239. package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +0 -1
  240. package/audit/evidence/runtime/probe-patch-relationship-error.log +0 -76
  241. package/audit/evidence/runtime/probe-patch-relationship-error.mjs +0 -67
  242. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +0 -1
  243. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +0 -62
  244. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +0 -47
  245. package/audit/evidence/runtime/test-exitcodes.txt +0 -4
  246. package/audit/evidence/runtime/test-summary.md +0 -107
  247. package/audit/evidence/runtime/trace-anchors.txt +0 -61
  248. package/audit/evidence/tests/access-multitenancy-test-signals.txt +0 -125
  249. package/audit/evidence/tests/failing-tests-summary.txt +0 -25
  250. package/audit/evidence/tests/npm-test-json-rest-api.exitcode +0 -1
  251. package/audit/evidence/tests/npm-test-json-rest-api.log +0 -5885
  252. package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +0 -1
  253. package/audit/evidence/tests/npm-test-json-rest-schema.log +0 -356
  254. package/audit/evidence/tests/query-include-test-signals.txt +0 -948
  255. package/audit/evidence/tests/relationship-test-signals.txt +0 -223
  256. package/audit/evidence/tests/skipped-tests.txt +0 -10
  257. package/audit/evidence/tests/test-suite-list-non-anyapi.txt +0 -30
  258. package/audit/evidence/tests/test-suite-list.txt +0 -32
  259. package/audit/subsystems/docs-drift.md +0 -49
  260. package/audit/subsystems/pass2-cross-review.md +0 -131
  261. package/audit/subsystems/plugins-access.md +0 -51
  262. package/audit/subsystems/plugins-bulk.md +0 -50
  263. package/audit/subsystems/plugins-cors.md +0 -48
  264. package/audit/subsystems/plugins-file.md +0 -53
  265. package/audit/subsystems/plugins-multihome.md +0 -50
  266. package/audit/subsystems/plugins-positioning.md +0 -54
  267. package/audit/subsystems/plugins-socketio.md +0 -50
  268. package/audit/subsystems/query-engine.md +0 -61
  269. package/audit/subsystems/relationships.md +0 -55
  270. package/audit/subsystems/rest-orchestration.md +0 -66
  271. package/audit/subsystems/schema-core.md +0 -64
  272. package/audit/subsystems/storage-knex.md +0 -57
  273. package/audit/subsystems/tests.md +0 -48
  274. package/audit/subsystems/transport-express.md +0 -55
  275. package/audit/traces/trace-read-get.md +0 -22
  276. package/audit/traces/trace-read-query.md +0 -25
  277. package/audit/traces/trace-relationship-endpoints.md +0 -31
  278. package/audit/traces/trace-write-delete.md +0 -17
  279. package/audit/traces/trace-write-patch.md +0 -26
  280. package/audit/traces/trace-write-post.md +0 -22
  281. package/audit/traces/trace-write-put.md +0 -23
  282. package/docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md +0 -707
  283. package/docs/GUIDE/GUIDE_X_Multihome.md +0 -666
  284. package/plugins/core/lib/querying-writing/payload-validators.js +0 -1314
  285. package/plugins/core/rest-api-access.js +0 -459
  286. package/plugins/core/rest-api-multihome-plugin.js +0 -314
  287. package/tests/multihome.test.js +0 -553
  288. package/tests/multihome.test.js.bak +0 -550
  289. package/tests/ownership-optout.test.js +0 -76
  290. package/tests/rest-api-access.test.js +0 -206
@@ -1,687 +0,0 @@
1
- plugins/core/rest-api-plugin-methods/query.js:15: * @param {string[]} [queryParams.include=[]] - An optional array of relationship paths to sideload for each resource in the collection. These paths will be converted to a comma-separated string for the URL (e.g., `['author', 'comments.user']` becomes `author,comments.user`). Supports deep relationships (e.g., "publisher.country").
2
- plugins/core/rest-api-plugin-methods/query.js:16: * @param {object} [queryParams.fields] - An object to request only specific fields (sparse fieldsets) for each resource in the collection and its included relationships. Keys are resource types, values are comma-separated field names.
3
- plugins/core/rest-api-plugin-methods/query.js:19: * @param {object} [queryParams.page] - An object for pagination. Typically includes `number` (page number) and `size` (items per page). E.g., `{ number: 1, size: 10 }`.
4
- plugins/core/rest-api-plugin-methods/query.js:54: context.queryParams.include = cascadeConfig('include', [params.queryParams], [])
5
- plugins/core/rest-api-plugin-methods/query.js:77: // (preventing SQL injection), pagination uses valid page[size]/page[number] format, and include
6
- plugins/core/rest-api-plugin-methods/query.js:78: // paths reference real relationships. Example: sort: ['-createdAt', 'title'] is checked against
7
- plugins/core/rest-api-plugin-methods/query.js:80: validateQueryPayload({ queryParams: context.queryParams }, context.sortableFields, vars.includeDepthLimit)
8
- plugins/core/rest-api-plugin-methods/query.js:172: for (const entry of (context.record.included || [])) {
9
- plugins/core/rest-api-plugin-methods/query.js:198: // Example: {data: {type: 'posts', id: '1', attributes: {title: 'My Post'}, relationships: {author: {data: {type: 'users', id: '123'}}}}}
10
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:66: * - Filters out foreign keys that become relationships in JSON:API
11
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:73: * - Output feeds into relationship building and response assembly
12
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:113: * @param {Object} scope - Scope containing schema and relationship definitions
13
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:123: * author_id: 2, // belongsTo relationship
14
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:124: * category_id: 3, // belongsTo relationship
15
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:143: * // Input: Record with polymorphic relationship
16
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:151: * // Schema has polymorphic relationship defined
17
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:168: * - processIncludes when transforming included resources
18
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:174: * - Handles polymorphic relationship fields (type/id pairs)
19
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:181: * 4. Returns clean JSON:API resource ready for relationship processing
20
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:182: * 5. buildJsonApiResponse adds relationships and links to complete the response
21
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:187: schemaInfo: { schemaRelationships: relationships, idProperty }
22
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:193: Object.entries(relationships || {}).forEach(([relName, relDef]) => {
23
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:216: * Builds complete JSON:API response with data, relationships, links, and optional includes
24
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:220: * @param {Array<Object>} records - Primary records to include in response
25
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:221: * @param {Array<Object>} included - Resources to include in 'included' array
26
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:224: * @param {Object} context - Request context with pagination metadata
27
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:228: * // Input: Single article with author include
28
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:237: * const included = [{
29
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:243: * const response = await buildJsonApiResponse(scope, records, included, true, 'articles', context);
30
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:254: * // relationships: {
31
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:258: * // self: '/articles/1/relationships/author',
32
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:265: * // self: '/articles/1/relationships/category',
33
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:274: * // included: [{
34
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:286: * // Input: Collection with pagination
35
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:294: * paginationMeta: { page: 2, pageSize: 3, pageCount: 10, total: 30 },
36
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:295: * paginationLinks: {
37
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:306: * // Output: Collection with pagination metadata
38
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:314: * // pagination: { page: 2, pageSize: 3, pageCount: 10, total: 30 }
39
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:333: * - Adds relationship objects with proper links for each foreign key
40
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:334: * - Handles both regular belongsTo and polymorphic relationships
41
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:336: * - Includes pagination metadata and links when applicable
42
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:339: * 1. Query operations fetch primary records and optional includes
43
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:341: * 3. buildJsonApiResponse adds relationship objects for all foreign keys
44
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:343: * 5. Assembles included resources with their own links
45
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:344: * 6. Adds pagination metadata and links if provided
46
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:347:export const buildJsonApiResponse = async (scope, records, included = [], isSingle = false, scopeName, context) => {
47
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:350: schemaInfo: { schemaInstance, schemaRelationships: relationships, idProperty }
48
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:359: const { [RELATIONSHIPS_KEY]: _relationships, ...cleanRecord } = record
49
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:362: if (_relationships) {
50
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:363: jsonApiRecord.relationships = _relationships
51
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:368: jsonApiRecord.relationships = jsonApiRecord.relationships || {}
52
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:369: if (!jsonApiRecord.relationships[fieldDef.as]) {
53
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:371: const relationshipObject = {
54
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:378: relationshipObject.links = {
55
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:383: jsonApiRecord.relationships[fieldDef.as] = relationshipObject
56
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:385: const relationshipObject = {
57
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:389: relationshipObject.links = {
58
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:394: jsonApiRecord.relationships[fieldDef.as] = relationshipObject
59
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:400: Object.entries(relationships || {}).forEach(([relName, relDef]) => {
60
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:406: jsonApiRecord.relationships = jsonApiRecord.relationships || {}
61
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:407: const relationshipObject = {
62
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:414: relationshipObject.links = {
63
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:419: jsonApiRecord.relationships[relName] = relationshipObject
64
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:421: jsonApiRecord.relationships = jsonApiRecord.relationships || {}
65
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:422: const relationshipObject = {
66
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:426: relationshipObject.links = {
67
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:431: jsonApiRecord.relationships[relName] = relationshipObject
68
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:458: if (included.length > 0) {
69
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:459: included.forEach(item => {
70
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:464: response.included = included
71
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:467: if (context?.returnMeta?.paginationMeta) {
72
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:469: pagination: context.returnMeta.paginationMeta
73
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:473: if (context?.returnMeta?.paginationLinks) {
74
- plugins/core/lib/querying/knex-json-api-transformers-querying.js:474: response.links = context.returnMeta.paginationLinks
75
- plugins/core/lib/querying/knex-query-helpers.js:130: * Processes filters that target polymorphic relationships where a single relationship can point to different types of resources
76
- plugins/core/lib/querying/knex-query-helpers.js:140: * polymorphicField: 'commentable', // Points to the polymorphic relationship
77
- plugins/core/lib/querying/knex-query-helpers.js:189: * - Enables filtering on polymorphic relationships without knowing the concrete type
78
- plugins/core/lib/querying/knex-query-helpers.js:250: // Get the relationship definition
79
- plugins/core/lib/querying/knex-query-helpers.js:251: const relationships = scopes[scopeName].vars.schemaInfo.schemaRelationships
80
- plugins/core/lib/querying/knex-query-helpers.js:252: const polyRel = relationships[polymorphicField]
81
- plugins/core/lib/querying/knex-query-helpers.js:256: `Polymorphic field '${polymorphicField}' not found in relationships for scope '${scopeName}'`
82
- plugins/core/lib/querying/knex-query-helpers.js:301: if (targetFieldPath.includes('.')) {
83
- plugins/core/lib/querying/knex-query-helpers.js:310: const relationshipName = pathParts[i]
84
- plugins/core/lib/querying/knex-query-helpers.js:312: // Find the foreign key for this relationship
85
- plugins/core/lib/querying/knex-query-helpers.js:319: if (fieldDef.as === relationshipName && fieldDef.belongsTo) {
86
- plugins/core/lib/querying/knex-query-helpers.js:327: // Check relationships for hasOne
87
- plugins/core/lib/querying/knex-query-helpers.js:329: const rel = currentRelationships?.[relationshipName]
88
- plugins/core/lib/querying/knex-query-helpers.js:333: 'Cross-table polymorphic search through hasOne relationships not yet supported'
89
- plugins/core/lib/querying/knex-query-helpers.js:338: `Cannot resolve relationship '${relationshipName}' in path '${targetFieldPath}' for scope '${currentScope}'`
90
- plugins/core/lib/querying/knex-query-helpers.js:343: const nextAlias = `${currentAlias}_${relationshipName}`
91
- plugins/core/lib/querying/knex-query-helpers.js:369: // Pre-fetch relationships for WHERE clause processing
92
- plugins/core/lib/querying/knex-query-helpers.js:371: const relationships = scopes[scopeName].vars.schemaInfo.schemaRelationships
93
- plugins/core/lib/querying/knex-query-helpers.js:374: const polyRel = relationships[polymorphicField]
94
- plugins/core/lib/querying/knex-query-helpers.js:410: if (targetFieldPath.includes('.')) {
95
- plugins/core/lib/querying/knex-query-helpers.js:488: * // Input: Deep nested relationships (3 levels)
96
- plugins/core/lib/querying/knex-query-helpers.js:498: * // Result: Chain of JOINs following relationships
97
- plugins/core/lib/querying/knex-query-helpers.js:514: * - Detects one-to-many relationships and adds DISTINCT to prevent duplicates
98
- plugins/core/lib/querying/knex-query-helpers.js:564: if (fieldDef.actualField?.includes('.')) {
99
- plugins/core/lib/querying/knex-query-helpers.js:577: if (field.includes('.')) {
100
- plugins/core/lib/querying/knex-query-helpers.js:609: if (!trimmed.includes('.')) {
101
- plugins/core/lib/querying/knex-query-helpers.js:620: if (field.includes('.')) {
102
- plugins/core/lib/querying/knex-query-helpers.js:628: if (field.includes('.')) {
103
- plugins/core/lib/querying/knex-query-helpers.js:687: if (join.isPolymorphic && join.joinCondition.includes(' AND ')) {
104
- plugins/core/lib/querying/knex-query-helpers.js:732: if (!fieldDef.actualField?.includes('.') &&
105
- plugins/core/lib/querying/knex-query-helpers.js:733: !fieldDef.oneOf?.some(f => f.includes('.'))) {
106
- plugins/core/lib/querying/knex-query-helpers.js:987: if (fieldDef.actualField?.includes('.') ||
107
- plugins/core/lib/querying/knex-query-helpers.js:988: fieldDef.oneOf?.some(f => f.includes('.')) ||
108
- plugins/core/lib/querying/url-helpers.js:76: * Build a relationship URL
109
- plugins/core/lib/querying/url-helpers.js:82: * @param {string} relationshipName - Name of the relationship
110
- plugins/core/lib/querying/url-helpers.js:83: * @param {boolean} isRelationshipEndpoint - If true, builds /relationships/ URL
111
- plugins/core/lib/querying/url-helpers.js:84: * @returns {string} Complete relationship URL
112
- plugins/core/lib/querying/url-helpers.js:87: * // For relationship linkage endpoint
113
- plugins/core/lib/querying/url-helpers.js:89: * // Returns: "https://api.example.com/api/books/1/relationships/author"
114
- plugins/core/lib/querying/url-helpers.js:95:export function buildRelationshipUrl (context, scope, scopeName, id, relationshipName, isRelationshipEndpoint = false) {
115
- plugins/core/lib/querying/url-helpers.js:98: return `${urlPrefix}/${scopeName}/${id}/relationships/${relationshipName}`
116
- plugins/core/lib/querying/url-helpers.js:100: return `${urlPrefix}/${scopeName}/${id}/${relationshipName}`
117
- plugins/core/lib/querying/knex-relationship-includes.js:5: * This module implements the JSON:API include functionality, enabling compound documents
118
- plugins/core/lib/querying/knex-relationship-includes.js:6: * that contain both primary data and related resources. It handles all relationship types
119
- plugins/core/lib/querying/knex-relationship-includes.js:7: * and supports arbitrary nesting depths while preventing N+1 query problems.
120
- plugins/core/lib/querying/knex-relationship-includes.js:10: * // Input: Simple include request
121
- plugins/core/lib/querying/knex-relationship-includes.js:11: * // GET /articles?include=author
122
- plugins/core/lib/querying/knex-relationship-includes.js:37: * // Input: Nested includes
123
- plugins/core/lib/querying/knex-relationship-includes.js:38: * // GET /articles?include=comments.author
124
- plugins/core/lib/querying/knex-relationship-includes.js:46: * // Input: Polymorphic includes
125
- plugins/core/lib/querying/knex-relationship-includes.js:47: * // GET /activities?include=trackable
126
- plugins/core/lib/querying/knex-relationship-includes.js:58: * - Results go into the 'included' section of JSON:API response
127
- plugins/core/lib/querying/knex-relationship-includes.js:61: * - Implements JSON:API compound documents with primary data and included resources
128
- plugins/core/lib/querying/knex-relationship-includes.js:62: * - Prevents N+1 queries through batch loading (1 query per resource type)
129
- plugins/core/lib/querying/knex-relationship-includes.js:69: * 1. Parse include parameter into tree structure (author,comments.author)
130
- plugins/core/lib/querying/knex-relationship-includes.js:70: * 2. For each relationship, determine type (belongsTo, hasMany, polymorphic)
131
- plugins/core/lib/querying/knex-relationship-includes.js:72: * 4. Recursively process nested includes
132
- plugins/core/lib/querying/knex-relationship-includes.js:73: * 5. Store all included resources in deduplication Map
133
- plugins/core/lib/querying/knex-relationship-includes.js:74: * 6. Return array of unique included resources
134
- plugins/core/lib/querying/knex-relationship-includes.js:80:import { buildWindowedIncludeQuery, applyStandardIncludeConfig, buildOrderByClause } from './knex-window-queries.js'
135
- plugins/core/lib/querying/knex-relationship-includes.js:115: * // Input: Comments with polymorphic commentable relationship
136
- plugins/core/lib/querying/knex-relationship-includes.js:132: * // Input: Some records have null relationships
137
- plugins/core/lib/querying/knex-relationship-includes.js:154: * - Minimizes database queries when loading polymorphic relationships
138
- plugins/core/lib/querying/knex-relationship-includes.js:180: if (!grouped[type].includes(id)) {
139
- plugins/core/lib/querying/knex-relationship-includes.js:189: * Parses the include parameter string into a tree structure
140
- plugins/core/lib/querying/knex-relationship-includes.js:191: * @param {string|Array<string>} includeParam - The include parameter value
141
- plugins/core/lib/querying/knex-relationship-includes.js:192: * @returns {Object} Nested object representing the include tree
142
- plugins/core/lib/querying/knex-relationship-includes.js:195: * // Input: Simple comma-separated includes
143
- plugins/core/lib/querying/knex-relationship-includes.js:205: * // Input: Nested includes with dot notation
144
- plugins/core/lib/querying/knex-relationship-includes.js:217: * // Input: Complex mixed-depth includes
145
- plugins/core/lib/querying/knex-relationship-includes.js:234: * - buildIncludedResources parses the include parameter before processing
146
- plugins/core/lib/querying/knex-relationship-includes.js:239: * - Enables recursive traversal of relationship includes
147
- plugins/core/lib/querying/knex-relationship-includes.js:249:export const parseIncludeTree = (includeParam) => {
148
- plugins/core/lib/querying/knex-relationship-includes.js:250: if (!includeParam) return {}
149
- plugins/core/lib/querying/knex-relationship-includes.js:253: const includes = Array.isArray(includeParam)
150
- plugins/core/lib/querying/knex-relationship-includes.js:254: ? includeParam
151
- plugins/core/lib/querying/knex-relationship-includes.js:255: : includeParam.split(',').map(s => s.trim()).filter(Boolean)
152
- plugins/core/lib/querying/knex-relationship-includes.js:259: includes.forEach(include => {
153
- plugins/core/lib/querying/knex-relationship-includes.js:260: const parts = include.split('.')
154
- plugins/core/lib/querying/knex-relationship-includes.js:275: * Loads relationship metadata for included resources
155
- plugins/core/lib/querying/knex-relationship-includes.js:276: * This ensures included resources have complete JSON:API representation
156
- plugins/core/lib/querying/knex-relationship-includes.js:279: * @param {Array<Object>} records - Records to add relationships to
157
- plugins/core/lib/querying/knex-relationship-includes.js:289: const relationships = schemaInfo.schemaRelationships || {}
158
- plugins/core/lib/querying/knex-relationship-includes.js:295: // Process belongsTo relationships from schema
159
- plugins/core/lib/querying/knex-relationship-includes.js:312: // Process hasMany, hasOne and manyToMany relationships
160
- plugins/core/lib/querying/knex-relationship-includes.js:313: for (const [relName, relDef] of Object.entries(relationships)) {
161
- plugins/core/lib/querying/knex-relationship-includes.js:315: // Add empty relationship data - will be populated if explicitly included
162
- plugins/core/lib/querying/knex-relationship-includes.js:321: // Process polymorphic relationships defined in relationships section
163
- plugins/core/lib/querying/knex-relationship-includes.js:343: console.error('[loadRelationshipMetadata] Error loading relationship metadata:', errorContext)
164
- plugins/core/lib/querying/knex-relationship-includes.js:344: throw new Error(`Failed to load relationship metadata for scope '${scopeName}': ${error.message}`)
165
- plugins/core/lib/querying/knex-relationship-includes.js:349: * Loads belongsTo relationships (many-to-one)
166
- plugins/core/lib/querying/knex-relationship-includes.js:351: * This function loads the "parent" side of a relationship. For example, if comments
167
- plugins/core/lib/querying/knex-relationship-includes.js:355: * - records: Array<Object> - Records to load relationships for
168
- plugins/core/lib/querying/knex-relationship-includes.js:358: * - includeName: string - The relationship name (e.g., 'author')
169
- plugins/core/lib/querying/knex-relationship-includes.js:359: * - subIncludes: Object - Nested includes to process recursively
170
- plugins/core/lib/querying/knex-relationship-includes.js:360: * - included: Map - Map of already included resources
171
- plugins/core/lib/querying/knex-relationship-includes.js:362: * - currentPath: string - Current include path for tracking
172
- plugins/core/lib/querying/knex-relationship-includes.js:372: const { records, scopeName, fieldName, fieldDef, includeName, subIncludes, included, processedPaths, currentPath, fields, idProperty } = scope
173
- plugins/core/lib/querying/knex-relationship-includes.js:377: includeName,
174
- plugins/core/lib/querying/knex-relationship-includes.js:401: // No relationships to load, set all to null
175
- plugins/core/lib/querying/knex-relationship-includes.js:404: const relationshipObject = { data: null }
176
- plugins/core/lib/querying/knex-relationship-includes.js:409: relationshipObject.links = {
177
- plugins/core/lib/querying/knex-relationship-includes.js:410: self: `${urlPrefix}/${scopeName}/${record[idProperty]}/relationships/${includeName}`,
178
- plugins/core/lib/querying/knex-relationship-includes.js:411: related: `${urlPrefix}/${scopeName}/${record[idProperty]}/${includeName}`
179
- plugins/core/lib/querying/knex-relationship-includes.js:415: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
180
- plugins/core/lib/querying/knex-relationship-includes.js:450: // Load relationship metadata for all target records
181
- plugins/core/lib/querying/knex-relationship-includes.js:459: // Set relationships on original records
182
- plugins/core/lib/querying/knex-relationship-includes.js:476: // Add relationships from metadata
183
- plugins/core/lib/querying/knex-relationship-includes.js:478: jsonApiRecord.relationships = targetRecord[RELATIONSHIP_METADATA_KEY]
184
- plugins/core/lib/querying/knex-relationship-includes.js:488: const relationshipObject = { data: { type: targetScope, id: String(targetId) } }
185
- plugins/core/lib/querying/knex-relationship-includes.js:493: relationshipObject.links = {
186
- plugins/core/lib/querying/knex-relationship-includes.js:494: self: `${urlPrefix}/${scopeName}/${record[idProperty]}/relationships/${includeName}`,
187
- plugins/core/lib/querying/knex-relationship-includes.js:495: related: `${urlPrefix}/${scopeName}/${record[idProperty]}/${includeName}`
188
- plugins/core/lib/querying/knex-relationship-includes.js:499: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
189
- plugins/core/lib/querying/knex-relationship-includes.js:501: // Add to included if not already there
190
- plugins/core/lib/querying/knex-relationship-includes.js:503: if (!included.has(resourceKey)) {
191
- plugins/core/lib/querying/knex-relationship-includes.js:504: included.set(resourceKey, jsonApiRecord) // Now includes relationships!
192
- plugins/core/lib/querying/knex-relationship-includes.js:512: const relationshipObject = { data: null }
193
- plugins/core/lib/querying/knex-relationship-includes.js:517: relationshipObject.links = {
194
- plugins/core/lib/querying/knex-relationship-includes.js:518: self: `${urlPrefix}/${scopeName}/${record[idProperty]}/relationships/${includeName}`,
195
- plugins/core/lib/querying/knex-relationship-includes.js:519: related: `${urlPrefix}/${scopeName}/${record[idProperty]}/${includeName}`
196
- plugins/core/lib/querying/knex-relationship-includes.js:523: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
197
- plugins/core/lib/querying/knex-relationship-includes.js:527: // Process nested includes if any
198
- plugins/core/lib/querying/knex-relationship-includes.js:529: const nextPath = `${currentPath}.${includeName}`
199
- plugins/core/lib/querying/knex-relationship-includes.js:532: { records: targetRecordsToProcess, scopeName: targetScope, includeTree: subIncludes, included, processedPaths, currentPath: nextPath, fields, idProperty: targetIdProperty },
200
- plugins/core/lib/querying/knex-relationship-includes.js:539: log.error('[INCLUDE] Error loading belongsTo relationship:', {
201
- plugins/core/lib/querying/knex-relationship-includes.js:541: includeName,
202
- plugins/core/lib/querying/knex-relationship-includes.js:550: `Failed to load belongsTo relationship '${includeName}' for field '${fieldName}': ${error.message}`
203
- plugins/core/lib/querying/knex-relationship-includes.js:553: enhancedError.context = { fieldName, includeName, targetScope: fieldDef.belongsTo }
204
- plugins/core/lib/querying/knex-relationship-includes.js:559: * Loads hasMany relationships (one-to-many or many-to-many)
205
- plugins/core/lib/querying/knex-relationship-includes.js:561: * This function loads the "child" side of a relationship. For example, if articles
206
- plugins/core/lib/querying/knex-relationship-includes.js:563: * many-to-many relationships through a pivot table.
207
- plugins/core/lib/querying/knex-relationship-includes.js:566: * - records: Array<Object> - Parent records to load relationships for
208
- plugins/core/lib/querying/knex-relationship-includes.js:568: * - includeName: string - The relationship name to include
209
- plugins/core/lib/querying/knex-relationship-includes.js:569: * - relDef: Object - The relationship definition
210
- plugins/core/lib/querying/knex-relationship-includes.js:570: * - subIncludes: Object - Nested includes to process recursively
211
- plugins/core/lib/querying/knex-relationship-includes.js:571: * - included: Map - Map of already included resources
212
- plugins/core/lib/querying/knex-relationship-includes.js:573: * - currentPath: string - Current include path for tracking
213
- plugins/core/lib/querying/knex-relationship-includes.js:582: const { records, scopeName, includeName, relDef, subIncludes, included, processedPaths, currentPath, fields } = scope
214
- plugins/core/lib/querying/knex-relationship-includes.js:585: log.trace('[INCLUDE] Loading hasMany/manyToMany relationship:', {
215
- plugins/core/lib/querying/knex-relationship-includes.js:587: includeName,
216
- plugins/core/lib/querying/knex-relationship-includes.js:602: // Check if this is a many-to-many relationship
217
- plugins/core/lib/querying/knex-relationship-includes.js:604: // Handle many-to-many relationship
218
- plugins/core/lib/querying/knex-relationship-includes.js:610: throw new Error(`Missing foreignKey or otherKey in many-to-many relationship '${relName}' for scope '${scopeName}'`)
219
- plugins/core/lib/querying/knex-relationship-includes.js:613: // For manyToMany, the target scope is the relationship name itself
220
- plugins/core/lib/querying/knex-relationship-includes.js:614: const targetScope = includeName
221
- plugins/core/lib/querying/knex-relationship-includes.js:628: // No relationships found, set empty arrays for all records
222
- plugins/core/lib/querying/knex-relationship-includes.js:631: const relationshipObject = { data: [] }
223
- plugins/core/lib/querying/knex-relationship-includes.js:636: relationshipObject.links = {
224
- plugins/core/lib/querying/knex-relationship-includes.js:637: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${includeName}`,
225
- plugins/core/lib/querying/knex-relationship-includes.js:638: related: `${urlPrefix}/${scopeName}/${record.id}/${includeName}`
226
- plugins/core/lib/querying/knex-relationship-includes.js:642: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
227
- plugins/core/lib/querying/knex-relationship-includes.js:652: includeConfig: relDef.include
228
- plugins/core/lib/querying/knex-relationship-includes.js:674: if (relDef.include?.strategy === 'window') {
229
- plugins/core/lib/querying/knex-relationship-includes.js:675: // For many-to-many with window functions, we need to limit per parent
230
- plugins/core/lib/querying/knex-relationship-includes.js:682: const effectiveLimit = relDef.include?.limit ?? targetVars.queryDefaultLimit ?? DEFAULT_QUERY_LIMIT
231
- plugins/core/lib/querying/knex-relationship-includes.js:688: detail: `Requested include limit (${effectiveLimit}) exceeds queryMaxLimit (${targetVars.queryMaxLimit})`,
232
- plugins/core/lib/querying/knex-relationship-includes.js:694: const windowQuery = knex
233
- plugins/core/lib/querying/knex-relationship-includes.js:699: windowQuery.select(`${targetTable}.${targetIdProperty} as id`)
234
- plugins/core/lib/querying/knex-relationship-includes.js:702: windowQuery.select(
235
- plugins/core/lib/querying/knex-relationship-includes.js:705: buildOrderByClause(relDef.include?.orderBy || [targetIdProperty], targetTable) +
236
- plugins/core/lib/querying/knex-relationship-includes.js:717: .from(windowQuery.as('_windowed'))
237
- plugins/core/lib/querying/knex-relationship-includes.js:737: // Apply standard include config (global limits)
238
- plugins/core/lib/querying/knex-relationship-includes.js:738: if (relDef.include) {
239
- plugins/core/lib/querying/knex-relationship-includes.js:740: query = applyStandardIncludeConfig(query, relDef.include, targetVars, log)
240
- plugins/core/lib/querying/knex-relationship-includes.js:748: // Step 5: Load relationship metadata for all target records
241
- plugins/core/lib/querying/knex-relationship-includes.js:767: // Step 7: Set relationships on parent records
242
- plugins/core/lib/querying/knex-relationship-includes.js:778: // Add to included
243
- plugins/core/lib/querying/knex-relationship-includes.js:780: if (!included.has(resourceKey)) {
244
- plugins/core/lib/querying/knex-relationship-includes.js:787: // Add relationships from metadata
245
- plugins/core/lib/querying/knex-relationship-includes.js:789: jsonApiRecord.relationships = childRecord[RELATIONSHIP_METADATA_KEY]
246
- plugins/core/lib/querying/knex-relationship-includes.js:799: included.set(resourceKey, jsonApiRecord)
247
- plugins/core/lib/querying/knex-relationship-includes.js:804: const relationshipObject = { data: relData }
248
- plugins/core/lib/querying/knex-relationship-includes.js:809: relationshipObject.links = {
249
- plugins/core/lib/querying/knex-relationship-includes.js:810: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${includeName}`,
250
- plugins/core/lib/querying/knex-relationship-includes.js:811: related: `${urlPrefix}/${scopeName}/${record.id}/${includeName}`
251
- plugins/core/lib/querying/knex-relationship-includes.js:815: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
252
- plugins/core/lib/querying/knex-relationship-includes.js:817: // Update the record in the included Map if it exists
253
- plugins/core/lib/querying/knex-relationship-includes.js:819: if (included.has(recordKey)) {
254
- plugins/core/lib/querying/knex-relationship-includes.js:820: const existingRecord = included.get(recordKey)
255
- plugins/core/lib/querying/knex-relationship-includes.js:821: if (!existingRecord.relationships) {
256
- plugins/core/lib/querying/knex-relationship-includes.js:822: existingRecord.relationships = {}
257
- plugins/core/lib/querying/knex-relationship-includes.js:824: existingRecord.relationships[includeName] = relationshipObject
258
- plugins/core/lib/querying/knex-relationship-includes.js:828: // Step 8: Process nested includes if any
259
- plugins/core/lib/querying/knex-relationship-includes.js:830: const nextPath = `${currentPath}.${includeName}`
260
- plugins/core/lib/querying/knex-relationship-includes.js:833: { records: targetRecords, scopeName: targetScope, includeTree: subIncludes, included, processedPaths, currentPath: nextPath, fields, idProperty: targetIdProperty },
261
- plugins/core/lib/querying/knex-relationship-includes.js:839: // Handle one-to-many relationship
262
- plugins/core/lib/querying/knex-relationship-includes.js:845: throw new Error(`Missing foreignKey in hasMany relationship '${relName}' for scope '${scopeName}'`)
263
- plugins/core/lib/querying/knex-relationship-includes.js:850: includeConfig: relDef.include
264
- plugins/core/lib/querying/knex-relationship-includes.js:872: // Check if we should use window functions
265
- plugins/core/lib/querying/knex-relationship-includes.js:873: if (relDef.include?.strategy === 'window') {
266
- plugins/core/lib/querying/knex-relationship-includes.js:875: // Try to build window function query
267
- plugins/core/lib/querying/knex-relationship-includes.js:886: relDef.include || {},
268
- plugins/core/lib/querying/knex-relationship-includes.js:891: log.debug('[INCLUDE] Using window function strategy with limits')
269
- plugins/core/lib/querying/knex-relationship-includes.js:893: // If window functions not supported, this will throw a clear error
270
- plugins/core/lib/querying/knex-relationship-includes.js:894: if (error.details?.requiredFeature === 'window_functions') {
271
- plugins/core/lib/querying/knex-relationship-includes.js:906: // Build standard query if not using window functions
272
- plugins/core/lib/querying/knex-relationship-includes.js:919: relDef.include || {},
273
- plugins/core/lib/querying/knex-relationship-includes.js:928: // If using window functions, remove the row number column
274
- plugins/core/lib/querying/knex-relationship-includes.js:938: // Load relationship metadata for all target records
275
- plugins/core/lib/querying/knex-relationship-includes.js:951: // Set relationships on parent records
276
- plugins/core/lib/querying/knex-relationship-includes.js:957: // Add to included
277
- plugins/core/lib/querying/knex-relationship-includes.js:959: if (!included.has(resourceKey)) {
278
- plugins/core/lib/querying/knex-relationship-includes.js:966: // Add relationships from metadata
279
- plugins/core/lib/querying/knex-relationship-includes.js:968: jsonApiRecord.relationships = childRecord[RELATIONSHIP_METADATA_KEY]
280
- plugins/core/lib/querying/knex-relationship-includes.js:978: included.set(resourceKey, jsonApiRecord)
281
- plugins/core/lib/querying/knex-relationship-includes.js:983: const relationshipObject = { data: relData }
282
- plugins/core/lib/querying/knex-relationship-includes.js:988: relationshipObject.links = {
283
- plugins/core/lib/querying/knex-relationship-includes.js:989: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${includeName}`,
284
- plugins/core/lib/querying/knex-relationship-includes.js:990: related: `${urlPrefix}/${scopeName}/${record.id}/${includeName}`
285
- plugins/core/lib/querying/knex-relationship-includes.js:994: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
286
- plugins/core/lib/querying/knex-relationship-includes.js:996: // Update the record in the included Map if it exists
287
- plugins/core/lib/querying/knex-relationship-includes.js:998: if (included.has(recordKey)) {
288
- plugins/core/lib/querying/knex-relationship-includes.js:999: const existingRecord = included.get(recordKey)
289
- plugins/core/lib/querying/knex-relationship-includes.js:1000: if (!existingRecord.relationships) {
290
- plugins/core/lib/querying/knex-relationship-includes.js:1001: existingRecord.relationships = {}
291
- plugins/core/lib/querying/knex-relationship-includes.js:1003: existingRecord.relationships[includeName] = relationshipObject
292
- plugins/core/lib/querying/knex-relationship-includes.js:1007: // Process nested includes
293
- plugins/core/lib/querying/knex-relationship-includes.js:1009: const nextPath = `${currentPath}.${includeName}`
294
- plugins/core/lib/querying/knex-relationship-includes.js:1012: { records: targetRecords, scopeName: targetScope, includeTree: subIncludes, included, processedPaths, currentPath: nextPath, fields, idProperty: targetIdProperty },
295
- plugins/core/lib/querying/knex-relationship-includes.js:1020: log.error('[INCLUDE] Error loading hasMany relationship:', {
296
- plugins/core/lib/querying/knex-relationship-includes.js:1022: includeName,
297
- plugins/core/lib/querying/knex-relationship-includes.js:1031: `Failed to load hasMany relationship '${includeName}' for scope '${scopeName}': ${error.message}`
298
- plugins/core/lib/querying/knex-relationship-includes.js:1034: enhancedError.context = { scopeName, includeName, hasThrough: !!relDef.through }
299
- plugins/core/lib/querying/knex-relationship-includes.js:1040: * Loads hasOne relationships (one-to-one)
300
- plugins/core/lib/querying/knex-relationship-includes.js:1049: const { records, scopeName, includeName, relDef, subIncludes, included, processedPaths, currentPath, fields } = scope
301
- plugins/core/lib/querying/knex-relationship-includes.js:1073: throw new Error(`Missing foreignKey in hasOne relationship '${includeName}' for scope '${scopeName}'`)
302
- plugins/core/lib/querying/knex-relationship-includes.js:1113: log.warn(`[INCLUDE] Multiple records found for hasOne relationship '${includeName}' with ${foreignKey}=${parentId}`)
303
- plugins/core/lib/querying/knex-relationship-includes.js:1139: record[RELATIONSHIPS_KEY][includeName] = {
304
- plugins/core/lib/querying/knex-relationship-includes.js:1143: // Add to included if not already there
305
- plugins/core/lib/querying/knex-relationship-includes.js:1145: if (!included.has(key)) {
306
- plugins/core/lib/querying/knex-relationship-includes.js:1146: included.set(key, transformed)
307
- plugins/core/lib/querying/knex-relationship-includes.js:1149: // Process nested includes if any
308
- plugins/core/lib/querying/knex-relationship-includes.js:1151: const newPath = `${currentPath}.${includeName}`
309
- plugins/core/lib/querying/knex-relationship-includes.js:1155: { records: [relatedRecord], scopeName: targetScope, includeTree: subIncludes, included, processedPaths, currentPath: newPath, fields },
310
- plugins/core/lib/querying/knex-relationship-includes.js:1162: record[RELATIONSHIPS_KEY][includeName] = { data: null }
311
- plugins/core/lib/querying/knex-relationship-includes.js:1168: * Loads polymorphic belongsTo relationships
312
- plugins/core/lib/querying/knex-relationship-includes.js:1170: * Handles relationships where a record can belong to different types of parent records.
313
- plugins/core/lib/querying/knex-relationship-includes.js:1174: * - records: Array<Object> - Records with polymorphic relationships
314
- plugins/core/lib/querying/knex-relationship-includes.js:1175: * - relName: string - The relationship name
315
- plugins/core/lib/querying/knex-relationship-includes.js:1176: * - relDef: Object - The relationship definition with belongsToPolymorphic
316
- plugins/core/lib/querying/knex-relationship-includes.js:1177: * - subIncludes: Object - Nested includes to process recursively
317
- plugins/core/lib/querying/knex-relationship-includes.js:1178: * - included: Map - Map of already included resources
318
- plugins/core/lib/querying/knex-relationship-includes.js:1180: * - currentPath: string - Current include path for tracking
319
- plugins/core/lib/querying/knex-relationship-includes.js:1189: const { records, scopeName, relName, relDef, subIncludes, included, processedPaths, currentPath, fields } = scope
320
- plugins/core/lib/querying/knex-relationship-includes.js:1214: if (!types.includes(targetType)) {
321
- plugins/core/lib/querying/knex-relationship-includes.js:1257: // Load relationship metadata for all target records
322
- plugins/core/lib/querying/knex-relationship-includes.js:1266: // Add to included and set relationships
323
- plugins/core/lib/querying/knex-relationship-includes.js:1275: // Add to included
324
- plugins/core/lib/querying/knex-relationship-includes.js:1277: if (!included.has(resourceKey)) {
325
- plugins/core/lib/querying/knex-relationship-includes.js:1284: // Add relationships from metadata
326
- plugins/core/lib/querying/knex-relationship-includes.js:1286: jsonApiRecord.relationships = targetRecord[RELATIONSHIP_METADATA_KEY]
327
- plugins/core/lib/querying/knex-relationship-includes.js:1296: included.set(resourceKey, jsonApiRecord)
328
- plugins/core/lib/querying/knex-relationship-includes.js:1299: const relationshipObject = {
329
- plugins/core/lib/querying/knex-relationship-includes.js:1306: relationshipObject.links = {
330
- plugins/core/lib/querying/knex-relationship-includes.js:1307: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${relName}`,
331
- plugins/core/lib/querying/knex-relationship-includes.js:1312: record[RELATIONSHIPS_KEY][relName] = relationshipObject
332
- plugins/core/lib/querying/knex-relationship-includes.js:1314: const relationshipObject = { data: null }
333
- plugins/core/lib/querying/knex-relationship-includes.js:1319: relationshipObject.links = {
334
- plugins/core/lib/querying/knex-relationship-includes.js:1320: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${relName}`,
335
- plugins/core/lib/querying/knex-relationship-includes.js:1325: record[RELATIONSHIPS_KEY][relName] = relationshipObject
336
- plugins/core/lib/querying/knex-relationship-includes.js:1330: // Process nested includes for this type
337
- plugins/core/lib/querying/knex-relationship-includes.js:1335: { records: targetRecords, scopeName: targetType, includeTree: subIncludes, included, processedPaths, currentPath: nextPath, fields, idProperty: targetIdProperty },
338
- plugins/core/lib/querying/knex-relationship-includes.js:1342: // Set null for records without relationships
339
- plugins/core/lib/querying/knex-relationship-includes.js:1346: const relationshipObject = { data: null }
340
- plugins/core/lib/querying/knex-relationship-includes.js:1351: relationshipObject.links = {
341
- plugins/core/lib/querying/knex-relationship-includes.js:1352: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${relName}`,
342
- plugins/core/lib/querying/knex-relationship-includes.js:1357: record[RELATIONSHIPS_KEY][relName] = relationshipObject
343
- plugins/core/lib/querying/knex-relationship-includes.js:1362: log.error('[INCLUDE] Error loading polymorphic belongsTo relationship:', {
344
- plugins/core/lib/querying/knex-relationship-includes.js:1372: `Failed to load polymorphic belongsTo relationship '${relName}': ${error.message}`
345
- plugins/core/lib/querying/knex-relationship-includes.js:1381: * Loads reverse polymorphic relationships (via)
346
- plugins/core/lib/querying/knex-relationship-includes.js:1383: * Handles loading "child" records that have a polymorphic relationship back to the parent.
347
- plugins/core/lib/querying/knex-relationship-includes.js:1389: * - includeName: string - The relationship name
348
- plugins/core/lib/querying/knex-relationship-includes.js:1390: * - relDef: Object - The relationship definition with 'via' property
349
- plugins/core/lib/querying/knex-relationship-includes.js:1391: * - subIncludes: Object - Nested includes to process recursively
350
- plugins/core/lib/querying/knex-relationship-includes.js:1392: * - included: Map - Map of already included resources
351
- plugins/core/lib/querying/knex-relationship-includes.js:1394: * - currentPath: string - Current include path for tracking
352
- plugins/core/lib/querying/knex-relationship-includes.js:1403: const { records, scopeName, includeName, relDef, subIncludes, included, processedPaths, currentPath, fields } = scope
353
- plugins/core/lib/querying/knex-relationship-includes.js:1408: includeName,
354
- plugins/core/lib/querying/knex-relationship-includes.js:1421: log.warn('[INCLUDE] Via relationship not found or not polymorphic:', {
355
- plugins/core/lib/querying/knex-relationship-includes.js:1471: // Apply include configuration (limits, ordering, etc.)
356
- plugins/core/lib/querying/knex-relationship-includes.js:1475: relDef.include || {},
357
- plugins/core/lib/querying/knex-relationship-includes.js:1486: // Load relationship metadata for all target records
358
- plugins/core/lib/querying/knex-relationship-includes.js:1499: // Set relationships on parent records
359
- plugins/core/lib/querying/knex-relationship-includes.js:1505: // Add to included
360
- plugins/core/lib/querying/knex-relationship-includes.js:1507: if (!included.has(resourceKey)) {
361
- plugins/core/lib/querying/knex-relationship-includes.js:1514: // Add relationships from metadata
362
- plugins/core/lib/querying/knex-relationship-includes.js:1516: jsonApiRecord.relationships = childRecord[RELATIONSHIP_METADATA_KEY]
363
- plugins/core/lib/querying/knex-relationship-includes.js:1526: included.set(resourceKey, jsonApiRecord)
364
- plugins/core/lib/querying/knex-relationship-includes.js:1531: const relationshipObject = { data: relData }
365
- plugins/core/lib/querying/knex-relationship-includes.js:1536: relationshipObject.links = {
366
- plugins/core/lib/querying/knex-relationship-includes.js:1537: self: `${urlPrefix}/${scopeName}/${record.id}/relationships/${includeName}`,
367
- plugins/core/lib/querying/knex-relationship-includes.js:1538: related: `${urlPrefix}/${scopeName}/${record.id}/${includeName}`
368
- plugins/core/lib/querying/knex-relationship-includes.js:1542: record[RELATIONSHIPS_KEY][includeName] = relationshipObject
369
- plugins/core/lib/querying/knex-relationship-includes.js:1545: // Process nested includes
370
- plugins/core/lib/querying/knex-relationship-includes.js:1547: const nextPath = `${currentPath}.${includeName}`
371
- plugins/core/lib/querying/knex-relationship-includes.js:1550: { records: targetRecords, scopeName: targetScope, includeTree: subIncludes, included, processedPaths, currentPath: nextPath, fields, idProperty: targetIdProperty },
372
- plugins/core/lib/querying/knex-relationship-includes.js:1557: log.error('[INCLUDE] Error loading reverse polymorphic relationship:', {
373
- plugins/core/lib/querying/knex-relationship-includes.js:1559: includeName,
374
- plugins/core/lib/querying/knex-relationship-includes.js:1569: `Failed to load reverse polymorphic relationship '${includeName}' via '${relDef?.via}' for scope '${scopeName}': ${error.message}`
375
- plugins/core/lib/querying/knex-relationship-includes.js:1572: enhancedError.context = { scopeName, includeName, via: relDef?.via, targetScope: relDef?.target }
376
- plugins/core/lib/querying/knex-relationship-includes.js:1578: * Processes includes for a set of records
377
- plugins/core/lib/querying/knex-relationship-includes.js:1580: * This is the main recursive function that processes the include tree. It examines
378
- plugins/core/lib/querying/knex-relationship-includes.js:1581: * the schema to determine relationship types and calls the appropriate loader function.
379
- plugins/core/lib/querying/knex-relationship-includes.js:1584: * - records: Array<Object> - Records to process includes for
380
- plugins/core/lib/querying/knex-relationship-includes.js:1586: * - includeTree: Object - Parsed include tree from parseIncludeTree
381
- plugins/core/lib/querying/knex-relationship-includes.js:1587: * - included: Map - Map storing all included resources
382
- plugins/core/lib/querying/knex-relationship-includes.js:1589: * - currentPath: string - Current path in the include tree (default '')
383
- plugins/core/lib/querying/knex-relationship-includes.js:1599: const { records, scopeName, includeTree, included, processedPaths, currentPath = '', fields = {}, idProperty } = scope
384
- plugins/core/lib/querying/knex-relationship-includes.js:1602: log.trace('[INCLUDE] Processing includes:', {
385
- plugins/core/lib/querying/knex-relationship-includes.js:1604: includes: Object.keys(includeTree),
386
- plugins/core/lib/querying/knex-relationship-includes.js:1620: // Process each include
387
- plugins/core/lib/querying/knex-relationship-includes.js:1621: for (const [includeName, subIncludes] of Object.entries(includeTree)) {
388
- plugins/core/lib/querying/knex-relationship-includes.js:1622: const fullPath = currentPath ? `${currentPath}.${includeName}` : includeName
389
- plugins/core/lib/querying/knex-relationship-includes.js:1635: // Look for belongsTo relationships in schema fields
390
- plugins/core/lib/querying/knex-relationship-includes.js:1637: if (fieldDef.as === includeName && fieldDef.belongsTo) {
391
- plugins/core/lib/querying/knex-relationship-includes.js:1639: { records, scopeName, fieldName, fieldDef, includeName, subIncludes, included, processedPaths, currentPath, fields, idProperty },
392
- plugins/core/lib/querying/knex-relationship-includes.js:1647: // Check relationships
393
- plugins/core/lib/querying/knex-relationship-includes.js:1649: const relDef = schemaRelationships[includeName]
394
- plugins/core/lib/querying/knex-relationship-includes.js:1653: // Handle hasOne relationship
395
- plugins/core/lib/querying/knex-relationship-includes.js:1656: includeName,
396
- plugins/core/lib/querying/knex-relationship-includes.js:1660: { records, scopeName, includeName, relDef, subIncludes, included, processedPaths, currentPath, fields },
397
- plugins/core/lib/querying/knex-relationship-includes.js:1668: { records, scopeName, includeName, relDef, subIncludes, included, processedPaths, currentPath, fields },
398
- plugins/core/lib/querying/knex-relationship-includes.js:1674: includeName,
399
- plugins/core/lib/querying/knex-relationship-includes.js:1680: { records, scopeName, includeName, relDef, subIncludes, included, processedPaths, currentPath, fields },
400
- plugins/core/lib/querying/knex-relationship-includes.js:1687: { records, scopeName, relName: includeName, relDef, subIncludes, included, processedPaths, currentPath, fields },
401
- plugins/core/lib/querying/knex-relationship-includes.js:1694: } catch (includeError) {
402
- plugins/core/lib/querying/knex-relationship-includes.js:1695: // Log specific include error and continue with other includes
403
- plugins/core/lib/querying/knex-relationship-includes.js:1696: log.error('[INCLUDE] Error processing include:', {
404
- plugins/core/lib/querying/knex-relationship-includes.js:1698: includeName,
405
- plugins/core/lib/querying/knex-relationship-includes.js:1700: error: includeError.message
406
- plugins/core/lib/querying/knex-relationship-includes.js:1703: throw includeError
407
- plugins/core/lib/querying/knex-relationship-includes.js:1707: log.warn('[INCLUDE] Unknown relationship:', {
408
- plugins/core/lib/querying/knex-relationship-includes.js:1709: includeName,
409
- plugins/core/lib/querying/knex-relationship-includes.js:1720: includeTree: Object.keys(includeTree || {}),
410
- plugins/core/lib/querying/knex-relationship-includes.js:1730: * Main entry point for building included resources
411
- plugins/core/lib/querying/knex-relationship-includes.js:1732: * Takes a set of records and an include parameter, loads all requested relationships,
412
- plugins/core/lib/querying/knex-relationship-includes.js:1733: * and returns both the included resources and the records with relationship data attached.
413
- plugins/core/lib/querying/knex-relationship-includes.js:1738: * - includeParam: string - The include parameter value (e.g., "author,comments.author")
414
- plugins/core/lib/querying/knex-relationship-includes.js:1745: * @returns {Promise<Object>} Object with included array and records with relationships
415
- plugins/core/lib/querying/knex-relationship-includes.js:1752: * includeParam: 'author,comments.author',
416
- plugins/core/lib/querying/knex-relationship-includes.js:1759: * // result.included = [
417
- plugins/core/lib/querying/knex-relationship-includes.js:1765: * // result.recordsWithRelationships = original records with _relationships added
418
- plugins/core/lib/querying/knex-relationship-includes.js:1768: const { records, scopeName, includeParam, fields, idProperty } = scope
419
- plugins/core/lib/querying/knex-relationship-includes.js:1771: log.trace('[INCLUDE] Building included resources:', { scopeName, includeParam, recordCount: records.length })
420
- plugins/core/lib/querying/knex-relationship-includes.js:1773: // Check if includes are empty or records are empty
421
- plugins/core/lib/querying/knex-relationship-includes.js:1774: if (!includeParam || records.length === 0) {
422
- plugins/core/lib/querying/knex-relationship-includes.js:1775: log.trace('[INCLUDE] No includes requested or no records')
423
- plugins/core/lib/querying/knex-relationship-includes.js:1777: included: [],
424
- plugins/core/lib/querying/knex-relationship-includes.js:1783: if (Array.isArray(includeParam) && includeParam.length === 0) {
425
- plugins/core/lib/querying/knex-relationship-includes.js:1784: log.trace('[INCLUDE] Empty include array, no relationships to load')
426
- plugins/core/lib/querying/knex-relationship-includes.js:1786: included: [],
427
- plugins/core/lib/querying/knex-relationship-includes.js:1791: // Parse the include parameter
428
- plugins/core/lib/querying/knex-relationship-includes.js:1792: const includeTree = parseIncludeTree(includeParam)
429
- plugins/core/lib/querying/knex-relationship-includes.js:1794: log.debug('[INCLUDE] Parsed include tree:', includeTree)
430
- plugins/core/lib/querying/knex-relationship-includes.js:1796: // Use a Map to track included resources by type:id
431
- plugins/core/lib/querying/knex-relationship-includes.js:1797: const included = new Map()
432
- plugins/core/lib/querying/knex-relationship-includes.js:1800: // Process all includes
433
- plugins/core/lib/querying/knex-relationship-includes.js:1802: { records, scopeName, includeTree, included, processedPaths, currentPath: '', fields, idProperty },
434
- plugins/core/lib/querying/knex-relationship-includes.js:1807: const includedArray = Array.from(included.values())
435
- plugins/core/lib/querying/knex-relationship-includes.js:1809: log.debug('[INCLUDE] Completed building includes:', {
436
- plugins/core/lib/querying/knex-relationship-includes.js:1810: includedCount: includedArray.length,
437
- plugins/core/lib/querying/knex-relationship-includes.js:1811: uniqueTypes: [...new Set(includedArray.map(r => r.type))]
438
- plugins/core/lib/querying/knex-relationship-includes.js:1815: included: includedArray,
439
- plugins/core/lib/querying/knex-relationship-includes.js:1820: log.error('[INCLUDE] Failed to build included resources:', {
440
- plugins/core/lib/querying/knex-relationship-includes.js:1822: includeParam,
441
- plugins/core/lib/querying/knex-relationship-includes.js:1829: const enhancedError = new Error(`Failed to build included resources for scope '${scopeName}': ${error.message}`)
442
- plugins/core/lib/querying/knex-relationship-includes.js:1833: includeParam,
443
- plugins/core/lib/querying/knex-relationship-includes.js:1841: * Loads relationship identifiers for all hasMany relationships without fetching full related records.
444
- plugins/core/lib/querying/knex-relationship-includes.js:1844: * This function ensures that all hasMany relationships (one-to-many, many-to-many, and polymorphic)
445
- plugins/core/lib/querying/knex-relationship-includes.js:1846: * are not included via the ?include parameter.
446
- plugins/core/lib/querying/knex-relationship-includes.js:1849: * 1. **JSON:API Consistency**: The JSON:API spec allows servers to include relationship identifiers
447
- plugins/core/lib/querying/knex-relationship-includes.js:1851: * clients always know what relationships exist and their IDs.
448
- plugins/core/lib/querying/knex-relationship-includes.js:1853: * 2. **Simplified Mode Support**: In simplified mode, relationship IDs are transformed into
449
- plugins/core/lib/querying/knex-relationship-includes.js:1855: * these objects only appear when using ?include, creating an inconsistent API where fields appear/disappear.
450
- plugins/core/lib/querying/knex-relationship-includes.js:1858: * clients the ability to know what relationships exist without the cost of fetching all data.
451
- plugins/core/lib/querying/knex-relationship-includes.js:1861: * - Runs ONE query per relationship type (not per record) to fetch all related IDs
452
- plugins/core/lib/querying/knex-relationship-includes.js:1862: * - Populates the relationship data with resource identifiers: `{ type: 'resource', id: '123' }`
453
- plugins/core/lib/querying/knex-relationship-includes.js:1863: * - Handles all relationship types: one-to-many, many-to-many, and polymorphic
454
- plugins/core/lib/querying/knex-relationship-includes.js:1867: * This runs after the main records are fetched but before includes are processed.
455
- plugins/core/lib/querying/knex-relationship-includes.js:1868: * If includes ARE specified, they will overwrite these IDs with full data.
456
- plugins/core/lib/querying/knex-relationship-includes.js:1870: * @param {Array<Object>} records - The parent records to load relationships for
457
- plugins/core/lib/querying/knex-relationship-includes.js:1874: * @returns {Promise<void>} Modifies records in place by adding relationship data
458
- plugins/core/lib/querying/knex-relationship-includes.js:1882: const relationships = schemaInfo.schemaRelationships || {}
459
- plugins/core/lib/querying/knex-relationship-includes.js:1885: // Process each hasMany relationship
460
- plugins/core/lib/querying/knex-relationship-includes.js:1886: for (const [relName, relDef] of Object.entries(relationships)) {
461
- plugins/core/lib/querying/knex-relationship-includes.js:1895: throw new Error(`Missing foreignKey in hasMany relationship '${relName}' for scope '${scopeName}'`)
462
- plugins/core/lib/querying/knex-relationship-includes.js:1911: // Many-to-many relationship
463
- plugins/core/lib/querying/knex-relationship-includes.js:1918: throw new Error(`Missing foreignKey or otherKey in manyToMany relationship '${relName}' for scope '${scopeName}'`)
464
- plugins/core/lib/querying/knex-relationship-includes.js:1970: // For manyToMany, the target type is the relationship name itself
465
- plugins/core/lib/querying/knex-process-includes.js:1:import { buildIncludedResources } from './knex-relationship-includes.js'
466
- plugins/core/lib/querying/knex-process-includes.js:4: * Processes the ?include= parameter to load related resources efficiently
467
- plugins/core/lib/querying/knex-process-includes.js:7: * @param {Array<Object>} records - The primary records to load includes for
468
- plugins/core/lib/querying/knex-process-includes.js:9: * @returns {Promise<Array<Object>>} Array of included resources in JSON:API format
469
- plugins/core/lib/querying/knex-process-includes.js:12: * // Input: Articles with author relationship
470
- plugins/core/lib/querying/knex-process-includes.js:22: * queryParams: { include: ['author'] },
471
- plugins/core/lib/querying/knex-process-includes.js:27: * const included = await processIncludes(scope, articles, deps);
472
- plugins/core/lib/querying/knex-process-includes.js:36: * // Input: Nested includes with dot notation
473
- plugins/core/lib/querying/knex-process-includes.js:42: * include: ['author', 'comments.user'] // Load author AND comment users
474
- plugins/core/lib/querying/knex-process-includes.js:47: * const included = await processIncludes(scope, articles, deps);
475
- plugins/core/lib/querying/knex-process-includes.js:59: * // Input: With sparse fieldsets limiting included data
476
- plugins/core/lib/querying/knex-process-includes.js:63: * include: ['author'],
477
- plugins/core/lib/querying/knex-process-includes.js:65: * users: 'name' // Only include name field for users
478
- plugins/core/lib/querying/knex-process-includes.js:71: * const included = await processIncludes(scope, articles, deps);
479
- plugins/core/lib/querying/knex-process-includes.js:81: * - rest-api-knex-plugin's dataGet method when includes are requested
480
- plugins/core/lib/querying/knex-process-includes.js:82: * - rest-api-knex-plugin's dataQuery method for collection includes
481
- plugins/core/lib/querying/knex-process-includes.js:86: * - Implements JSON:API compound documents with primary data and includes
482
- plugins/core/lib/querying/knex-process-includes.js:87: * - Prevents N+1 queries by batch loading all related resources
483
- plugins/core/lib/querying/knex-process-includes.js:88: * - Handles complex nested includes like 'comments.author.company'
484
- plugins/core/lib/querying/knex-process-includes.js:89: * - Automatically deduplicates included resources
485
- plugins/core/lib/querying/knex-process-includes.js:90: * - Respects sparse fieldsets on included resources
486
- plugins/core/lib/querying/knex-process-includes.js:93: * 1. Receives primary records and include directives
487
- plugins/core/lib/querying/knex-process-includes.js:94: * 2. Parses include parameter (comma-separated, possibly nested with dots)
488
- plugins/core/lib/querying/knex-process-includes.js:96: * 4. Returns flat array of all included resources
489
- plugins/core/lib/querying/knex-process-includes.js:97: * 5. These resources go into the 'included' section of JSON:API response
490
- plugins/core/lib/querying/knex-process-includes.js:116: if (!queryParams.include) {
491
- plugins/core/lib/querying/knex-process-includes.js:120: log.debug('[PROCESS-INCLUDES] Processing includes:', queryParams.include)
492
- plugins/core/lib/querying/knex-process-includes.js:122: const includeResult = await buildIncludedResources(
493
- plugins/core/lib/querying/knex-process-includes.js:126: includeParam: queryParams.include,
494
- plugins/core/lib/querying/knex-process-includes.js:141: includedCount: includeResult.included.length,
495
- plugins/core/lib/querying/knex-process-includes.js:142: types: [...new Set(includeResult.included.map(r => r.type))]
496
- plugins/core/lib/querying/knex-process-includes.js:145: return includeResult.included
497
- plugins/core/lib/querying/knex-process-includes.js:150: log.error('[PROCESS-INCLUDES] Error processing includes:', {
498
- plugins/core/lib/querying/knex-process-includes.js:153: includeParam: context?.queryParams?.include,
499
- plugins/core/lib/querying/knex-process-includes.js:158: console.error('[PROCESS-INCLUDES] Error processing includes:', error)
500
- plugins/core/lib/querying/knex-process-includes.js:162: `Failed to process includes${context?.scopeName ? ` for scope '${context.scopeName}'` : ''}: ${error.message}`
501
- plugins/core/lib/querying/knex-cross-table-search.js:7: * @param {Object} scopes - All registered hooked-api scopes containing schema and relationship definitions
502
- plugins/core/lib/querying/knex-cross-table-search.js:87: * @param {Object} scopes - All registered hooked-api scopes containing schema and relationship definitions
503
- plugins/core/lib/querying/knex-cross-table-search.js:93: * @throws {Error} If path is invalid or relationships not properly configured
504
- plugins/core/lib/querying/knex-cross-table-search.js:96: * // Input: Simple belongsTo relationship
505
- plugins/core/lib/querying/knex-cross-table-search.js:97: * // articles table has author_id field, authors schema defines belongsTo relationship
506
- plugins/core/lib/querying/knex-cross-table-search.js:112: * // Input: Multi-level path through relationships
507
- plugins/core/lib/querying/knex-cross-table-search.js:130: * // relationshipField: 'author_id',
508
- plugins/core/lib/querying/knex-cross-table-search.js:131: * // relationshipType: 'belongsTo'
509
- plugins/core/lib/querying/knex-cross-table-search.js:138: * // relationshipField: 'company_id',
510
- plugins/core/lib/querying/knex-cross-table-search.js:139: * // relationshipType: 'belongsTo'
511
- plugins/core/lib/querying/knex-cross-table-search.js:145: * // Input: One-to-many relationship (hasMany)
512
- plugins/core/lib/querying/knex-cross-table-search.js:167: * - Supports many-to-one (belongsTo), one-to-many (hasMany), and many-to-many relationships
513
- plugins/core/lib/querying/knex-cross-table-search.js:168: * - Handles polymorphic relationships and multi-level paths
514
- plugins/core/lib/querying/knex-cross-table-search.js:172: * 2. buildJoinChain analyzes relationship path segment by segment
515
- plugins/core/lib/querying/knex-cross-table-search.js:173: * 3. For each segment, finds the appropriate relationship definition
516
- plugins/core/lib/querying/knex-cross-table-search.js:187: const relationshipPath = pathSegments.slice(0, -1)
517
- plugins/core/lib/querying/knex-cross-table-search.js:189: log.trace('[BUILD-JOIN] Parsed path:', { relationshipPath, targetFieldName })
518
- plugins/core/lib/querying/knex-cross-table-search.js:194: for (let i = 0; i < relationshipPath.length; i++) {
519
- plugins/core/lib/querying/knex-cross-table-search.js:195: const targetScope = relationshipPath[i]
520
- plugins/core/lib/querying/knex-cross-table-search.js:197: log.trace('[BUILD-JOIN] Looking for direct relationship:', { from: currentScope, to: targetScope })
521
- plugins/core/lib/querying/knex-cross-table-search.js:209: let relationshipType = null
522
- plugins/core/lib/querying/knex-cross-table-search.js:210: let relationshipField = null
523
- plugins/core/lib/querying/knex-cross-table-search.js:211: let relationshipDef = null
524
- plugins/core/lib/querying/knex-cross-table-search.js:223: relationshipType = 'hasManyPolymorphic'
525
- plugins/core/lib/querying/knex-cross-table-search.js:224: relationshipField = { typeField, idField, via: relDef.via }
526
- plugins/core/lib/querying/knex-cross-table-search.js:225: relationshipDef = relDef
527
- plugins/core/lib/querying/knex-cross-table-search.js:226: log.trace('[BUILD-JOIN] Found polymorphic hasMany relationship:', {
528
- plugins/core/lib/querying/knex-cross-table-search.js:235: relationshipType = 'manyToMany'
529
- plugins/core/lib/querying/knex-cross-table-search.js:236: relationshipField = {
530
- plugins/core/lib/querying/knex-cross-table-search.js:241: relationshipDef = relDef
531
- plugins/core/lib/querying/knex-cross-table-search.js:242: log.trace('[BUILD-JOIN] Found many-to-many relationship:', {
532
- plugins/core/lib/querying/knex-cross-table-search.js:253: relationshipType = 'hasMany'
533
- plugins/core/lib/querying/knex-cross-table-search.js:254: relationshipField = relDef.foreignKey
534
- plugins/core/lib/querying/knex-cross-table-search.js:255: if (!relationshipField) {
535
- plugins/core/lib/querying/knex-cross-table-search.js:256: log.error('[BUILD-JOIN] Missing foreignKey in hasMany relationship:', { relName, currentScope })
536
- plugins/core/lib/querying/knex-cross-table-search.js:257: throw new Error(`Missing foreignKey in hasMany relationship '${relName}' for scope '${currentScope}'`)
537
- plugins/core/lib/querying/knex-cross-table-search.js:259: relationshipDef = relDef
538
- plugins/core/lib/querying/knex-cross-table-search.js:260: log.trace('[BUILD-JOIN] Found hasMany relationship:', { relName, targetScope, foreignKey: relationshipField })
539
- plugins/core/lib/querying/knex-cross-table-search.js:270: relationshipType = 'belongsTo'
540
- plugins/core/lib/querying/knex-cross-table-search.js:271: relationshipField = fieldName
541
- plugins/core/lib/querying/knex-cross-table-search.js:272: relationshipDef = fieldDef
542
- plugins/core/lib/querying/knex-cross-table-search.js:273: log.trace('[BUILD-JOIN] Found belongsTo relationship:', { fieldName, targetScope })
543
- plugins/core/lib/querying/knex-cross-table-search.js:281: `No searchable relationship from '${currentScope}' to '${targetScope}'. `
544
- plugins/core/lib/querying/knex-cross-table-search.js:290: if (relationshipType === 'manyToMany') {
545
- plugins/core/lib/querying/knex-cross-table-search.js:291: const { through, foreignKey, otherKey } = relationshipField
546
- plugins/core/lib/querying/knex-cross-table-search.js:304: relationshipField: foreignKey,
547
- plugins/core/lib/querying/knex-cross-table-search.js:305: relationshipType: 'manyToMany_pivot',
548
- plugins/core/lib/querying/knex-cross-table-search.js:318: relationshipField: otherKey,
549
- plugins/core/lib/querying/knex-cross-table-search.js:319: relationshipType: 'manyToMany_target',
550
- plugins/core/lib/querying/knex-cross-table-search.js:326: if (relationshipType === 'hasManyPolymorphic') {
551
- plugins/core/lib/querying/knex-cross-table-search.js:327: const { typeField, idField } = relationshipField
552
- plugins/core/lib/querying/knex-cross-table-search.js:330: } else if (relationshipType === 'hasMany') {
553
- plugins/core/lib/querying/knex-cross-table-search.js:332: joinCondition = `${previousAlias}.id = ${joinAlias}.${relationshipField}`
554
- plugins/core/lib/querying/knex-cross-table-search.js:335: joinCondition = `${previousAlias}.${relationshipField} = ${joinAlias}.id`
555
- plugins/core/lib/querying/knex-cross-table-search.js:342: isOneToMany: relationshipType === 'hasMany' || relationshipType === 'hasManyPolymorphic',
556
- plugins/core/lib/querying/knex-cross-table-search.js:343: isPolymorphic: relationshipType === 'hasManyPolymorphic',
557
- plugins/core/lib/querying/knex-cross-table-search.js:344: relationshipField,
558
- plugins/core/lib/querying/knex-cross-table-search.js:345: relationshipType,
559
- plugins/core/lib/querying/knex-cross-table-search.js:353: const finalScope = relationshipPath[relationshipPath.length - 1]
560
- plugins/core/lib/querying/knex-cross-table-search.js:357: throw new Error(`Invalid path '${targetPath}': no relationships to traverse`)
561
- plugins/core/lib/querying/knex-cross-table-search.js:377: sourceField: lastJoin.relationshipField,
562
- plugins/core/lib/querying/knex-cross-table-search.js:390: * @param {Object} scopes - All registered hooked-api scopes containing schema and relationship definitions
563
- plugins/core/lib/querying/knex-cross-table-search.js:458: if (fieldDef.actualField && fieldDef.actualField.includes('.')) {
564
- plugins/core/lib/querying/knex-cross-table-search.js:469: if (field.includes('.')) {
565
- plugins/core/lib/querying/knex-cross-table-search.js:488: * @param {Object} scopes - All registered hooked-api scopes containing schema and relationship definitions
566
- plugins/core/lib/querying/knex-window-queries.js:5: * Builds a window function query for limited includes per parent record
567
- plugins/core/lib/querying/knex-window-queries.js:12: * @param {Object} includeConfig - Include configuration (limit, orderBy)
568
- plugins/core/lib/querying/knex-window-queries.js:26: * { windowFunctions: true },
569
- plugins/core/lib/querying/knex-window-queries.js:31: * // WITH _windowed AS (
570
- plugins/core/lib/querying/knex-window-queries.js:40: * // SELECT * FROM _windowed
571
- plugins/core/lib/querying/knex-window-queries.js:46: * // Input: Database doesn't support window functions
572
- plugins/core/lib/querying/knex-window-queries.js:54: * { windowFunctions: false, dbInfo: { client: 'mysql', version: '5.7' } }
573
- plugins/core/lib/querying/knex-window-queries.js:58: * // "Include limits require window function support. Your database (mysql 5.7)
574
- plugins/core/lib/querying/knex-window-queries.js:64: * - loadHasMany when strategy: 'window' and database supports window functions
575
- plugins/core/lib/querying/knex-window-queries.js:65: * - Enables per-parent limits for one-to-many relationships
576
- plugins/core/lib/querying/knex-window-queries.js:68: * - Solves the "N+1 limit" problem where you want X records per parent
577
- plugins/core/lib/querying/knex-window-queries.js:69: * - Without window functions, LIMIT 10 gives 10 total across all parents
578
- plugins/core/lib/querying/knex-window-queries.js:70: * - With window functions, each parent gets up to 10 related records
579
- plugins/core/lib/querying/knex-window-queries.js:71: * - Critical for consistent API responses with includes
580
- plugins/core/lib/querying/knex-window-queries.js:86: includeConfig,
581
- plugins/core/lib/querying/knex-window-queries.js:90: const { orderBy = [] } = includeConfig
582
- plugins/core/lib/querying/knex-window-queries.js:93: const effectiveLimit = includeConfig.limit ?? scopeVars.queryDefaultLimit ?? DEFAULT_QUERY_LIMIT
583
- plugins/core/lib/querying/knex-window-queries.js:99: detail: `Requested include limit (${effectiveLimit}) exceeds queryMaxLimit (${scopeVars.queryMaxLimit})`,
584
- plugins/core/lib/querying/knex-window-queries.js:104: // Check if window functions are supported
585
- plugins/core/lib/querying/knex-window-queries.js:105: if (!capabilities.windowFunctions) {
586
- plugins/core/lib/querying/knex-window-queries.js:108: `Include limits require window function support. Your database (${dbInfo.client} ${dbInfo.version}) does not support this feature. ` +
587
- plugins/core/lib/querying/knex-window-queries.js:114: requiredFeature: 'window_functions'
588
- plugins/core/lib/querying/knex-window-queries.js:119: // Build the window function query
589
- plugins/core/lib/querying/knex-window-queries.js:143: .from(subquery.as('_windowed'))
590
- plugins/core/lib/querying/knex-window-queries.js:209: * Applies standard (non-windowed) include configuration to a query
591
- plugins/core/lib/querying/knex-window-queries.js:212: * @param {Object} includeConfig - Include configuration object
592
- plugins/core/lib/querying/knex-window-queries.js:218: * // Input: Basic include with limit and ordering
593
- plugins/core/lib/querying/knex-window-queries.js:270: * // Log: "No limit applied to include query (explicitly disabled)"
594
- plugins/core/lib/querying/knex-window-queries.js:274: * - loadHasMany when window functions not available or not requested
595
- plugins/core/lib/querying/knex-window-queries.js:275: * - loadReversePolymorphic for standard relationship queries
596
- plugins/core/lib/querying/knex-window-queries.js:276: * - Any include loader that needs consistent limit/order handling
597
- plugins/core/lib/querying/knex-window-queries.js:279: * - Provides fallback when window functions unavailable
598
- plugins/core/lib/querying/knex-window-queries.js:292:export const applyStandardIncludeConfig = (query, includeConfig, scopeVars, log) => {
599
- plugins/core/lib/querying/knex-window-queries.js:293: const { orderBy = [] } = includeConfig
600
- plugins/core/lib/querying/knex-window-queries.js:303: const requestedLimit = includeConfig.limit
601
- plugins/core/lib/querying/knex-window-queries.js:316: log.debug('Applied include limit:', {
602
- plugins/core/lib/querying/knex-window-queries.js:324: log.debug('No limit applied to include query (explicitly disabled)')
603
- plugins/core/lib/querying/knex-query-helpers-base.js:26: * // Response will only include these 3 fields, reducing payload size
604
- plugins/core/lib/querying/knex-query-helpers-base.js:56: * 5. JSON:API response includes only requested attributes
605
- plugins/core/lib/querying/knex-pagination-helpers.js:2: * Calculates pagination metadata from query results
606
- plugins/core/lib/querying/knex-pagination-helpers.js:38: * - Applied when offset-based pagination is enabled
607
- plugins/core/lib/querying/knex-pagination-helpers.js:41: * - Provides consistent pagination metadata across all collection responses
608
- plugins/core/lib/querying/knex-pagination-helpers.js:43: * - Validates pagination parameters to prevent invalid states
609
- plugins/core/lib/querying/knex-pagination-helpers.js:46: * 1. Query method counts total records when pagination.counts is enabled
610
- plugins/core/lib/querying/knex-pagination-helpers.js:48: * 3. Returns metadata that goes into response.meta.pagination
611
- plugins/core/lib/querying/knex-pagination-helpers.js:49: * 4. Used by generatePaginationLinks to determine which links to include
612
- plugins/core/lib/querying/knex-pagination-helpers.js:73: * Generates JSON:API compliant pagination links for offset-based pagination
613
- plugins/core/lib/querying/knex-pagination-helpers.js:78: * @param {Object} paginationMeta - Pagination metadata from calculatePaginationMeta
614
- plugins/core/lib/querying/knex-pagination-helpers.js:90: * const paginationMeta = {
615
- plugins/core/lib/querying/knex-pagination-helpers.js:98: * const links = generatePaginationLinks(urlPrefix, scopeName, queryParams, paginationMeta);
616
- plugins/core/lib/querying/knex-pagination-helpers.js:111: * const paginationMeta = { page: 1, pageSize: 10, pageCount: 3 };
617
- plugins/core/lib/querying/knex-pagination-helpers.js:112: * const links = generatePaginationLinks('/api', 'users', {}, paginationMeta);
618
- plugins/core/lib/querying/knex-pagination-helpers.js:125: * - Called when offset-based pagination is used (not cursor-based)
619
- plugins/core/lib/querying/knex-pagination-helpers.js:128: * - JSON:API spec requires pagination links for easy navigation
620
- plugins/core/lib/querying/knex-pagination-helpers.js:129: * - Preserves all other query parameters (filters, sorts, includes)
621
- plugins/core/lib/querying/knex-pagination-helpers.js:131: * - Only includes prev/next when applicable
622
- plugins/core/lib/querying/knex-pagination-helpers.js:134: * 1. After records are fetched and pagination calculated
623
- plugins/core/lib/querying/knex-pagination-helpers.js:136: * 3. Conditionally includes prev (not on page 1) and next (not on last page)
624
- plugins/core/lib/querying/knex-pagination-helpers.js:139:export const generatePaginationLinks = (urlPrefix, scopeName, queryParams, paginationMeta) => {
625
- plugins/core/lib/querying/knex-pagination-helpers.js:143: const { page, pageCount, pageSize } = paginationMeta
626
- plugins/core/lib/querying/knex-pagination-helpers.js:199: * Creates an opaque cursor string from record data for cursor-based pagination
627
- plugins/core/lib/querying/knex-pagination-helpers.js:201: * @param {Object} record - Database record to create cursor from
628
- plugins/core/lib/querying/knex-pagination-helpers.js:202: * @param {Array<string>} sortFields - Fields to include in cursor (default: ['id'])
629
- plugins/core/lib/querying/knex-pagination-helpers.js:203: * @returns {string} URL-safe cursor string
630
- plugins/core/lib/querying/knex-pagination-helpers.js:206: * // Input: Simple ID-based cursor
631
- plugins/core/lib/querying/knex-pagination-helpers.js:212: * const cursor = createCursor(record, ['id']);
632
- plugins/core/lib/querying/knex-pagination-helpers.js:215: * // This cursor marks position at record with id=123
633
- plugins/core/lib/querying/knex-pagination-helpers.js:218: * // Input: Multi-field cursor for complex sorting
634
- plugins/core/lib/querying/knex-pagination-helpers.js:224: * const cursor = createCursor(record, ['created_at', 'id']);
635
- plugins/core/lib/querying/knex-pagination-helpers.js:237: * const cursor = createCursor(record, ['category', 'title', 'id']);
636
- plugins/core/lib/querying/knex-pagination-helpers.js:244: * - generateCursorPaginationLinks to create next/prev cursors
637
- plugins/core/lib/querying/knex-pagination-helpers.js:245: * - buildCursorMeta to provide cursor in response metadata
638
- plugins/core/lib/querying/knex-pagination-helpers.js:248: * - Cursor-based pagination is more stable than offset for changing data
639
- plugins/core/lib/querying/knex-pagination-helpers.js:256: * 3. Creates cursor encoding those values
640
- plugins/core/lib/querying/knex-pagination-helpers.js:273: * Parses a cursor string back into field/value pairs
641
- plugins/core/lib/querying/knex-pagination-helpers.js:275: * @param {string} cursor - Cursor string to parse
642
- plugins/core/lib/querying/knex-pagination-helpers.js:277: * @throws {Error} If cursor format is invalid
643
- plugins/core/lib/querying/knex-pagination-helpers.js:280: * // Input: Simple cursor
644
- plugins/core/lib/querying/knex-pagination-helpers.js:281: * const cursor = "id:123";
645
- plugins/core/lib/querying/knex-pagination-helpers.js:282: * const data = parseCursor(cursor);
646
- plugins/core/lib/querying/knex-pagination-helpers.js:288: * // Input: Multi-field cursor with URL-encoded values
647
- plugins/core/lib/querying/knex-pagination-helpers.js:289: * const cursor = "created_at:2024-01-15T08%3A30%3A00.000Z,id:5";
648
- plugins/core/lib/querying/knex-pagination-helpers.js:290: * const data = parseCursor(cursor);
649
- plugins/core/lib/querying/knex-pagination-helpers.js:300: * // Input: Invalid cursor (throws error)
650
- plugins/core/lib/querying/knex-pagination-helpers.js:305: * // "Invalid cursor format: Invalid cursor format: missing colon separator"
651
- plugins/core/lib/querying/knex-pagination-helpers.js:311: * - Used to build WHERE clause for cursor-based queries
652
- plugins/core/lib/querying/knex-pagination-helpers.js:314: * - Decodes cursor back to usable values for SQL queries
653
- plugins/core/lib/querying/knex-pagination-helpers.js:316: * - Validates cursor format to prevent injection attacks
654
- plugins/core/lib/querying/knex-pagination-helpers.js:319: * 1. Client sends page[after]=cursor parameter
655
- plugins/core/lib/querying/knex-pagination-helpers.js:320: * 2. parseCursor extracts field values from cursor
656
- plugins/core/lib/querying/knex-pagination-helpers.js:322: * 4. Ensures pagination continues from exact position
657
- plugins/core/lib/querying/knex-pagination-helpers.js:324:export const parseCursor = (cursor) => {
658
- plugins/core/lib/querying/knex-pagination-helpers.js:327: if (!cursor || cursor.trim() === '') {
659
- plugins/core/lib/querying/knex-pagination-helpers.js:328: throw new Error('Empty cursor')
660
- plugins/core/lib/querying/knex-pagination-helpers.js:331: const pairs = cursor.split(',')
661
- plugins/core/lib/querying/knex-pagination-helpers.js:336: throw new Error('Invalid cursor format: missing colon separator')
662
- plugins/core/lib/querying/knex-pagination-helpers.js:343: throw new Error('Invalid cursor format: empty field name')
663
- plugins/core/lib/querying/knex-pagination-helpers.js:351: throw new Error(`Invalid cursor format: ${e.message}`)
664
- plugins/core/lib/querying/knex-pagination-helpers.js:356: * Generates pagination links for cursor-based pagination
665
- plugins/core/lib/querying/knex-pagination-helpers.js:364: * @param {Array<string>} sortFields - Fields used for cursor
666
- plugins/core/lib/querying/knex-pagination-helpers.js:392: * // The 'next' cursor points after the last record (id:3)
667
- plugins/core/lib/querying/knex-pagination-helpers.js:414: * - rest-api-knex-plugin when cursor pagination is enabled
668
- plugins/core/lib/querying/knex-pagination-helpers.js:415: * - Called after fetching records with cursor-based query
669
- plugins/core/lib/querying/knex-pagination-helpers.js:418: * - Cursor pagination is more efficient for large datasets
670
- plugins/core/lib/querying/knex-pagination-helpers.js:419: * - Stable pagination when data is being added/removed
671
- plugins/core/lib/querying/knex-pagination-helpers.js:420: * - Only includes 'next' link when more data exists
672
- plugins/core/lib/querying/knex-pagination-helpers.js:424: * 1. After cursor-based query fetches records
673
- plugins/core/lib/querying/knex-pagination-helpers.js:425: * 2. If hasMore is true, creates cursor from last record
674
- plugins/core/lib/querying/knex-pagination-helpers.js:490: * Builds cursor pagination metadata for the response
675
- plugins/core/lib/querying/knex-pagination-helpers.js:495: * @param {Array<string>} sortFields - Fields used for cursor
676
- plugins/core/lib/querying/knex-pagination-helpers.js:496: * @returns {Object} Metadata with pageSize, hasMore, and optional cursor
677
- plugins/core/lib/querying/knex-pagination-helpers.js:511: * // cursor: {
678
- plugins/core/lib/querying/knex-pagination-helpers.js:527: * // // No cursor property since hasMore is false
679
- plugins/core/lib/querying/knex-pagination-helpers.js:532: * - rest-api-knex-plugin adds this to response.meta for cursor pagination
680
- plugins/core/lib/querying/knex-pagination-helpers.js:533: * - Provides cursor that client can use directly if needed
681
- plugins/core/lib/querying/knex-pagination-helpers.js:536: * - Gives clients direct access to cursor for custom pagination
682
- plugins/core/lib/querying/knex-pagination-helpers.js:538: * - Simpler than offset pagination metadata (no total count)
683
- plugins/core/lib/querying/knex-pagination-helpers.js:541: * 1. Called after fetching records with cursor query
684
- plugins/core/lib/querying/knex-pagination-helpers.js:542: * 2. Creates cursor from last record if more exist
685
- plugins/core/lib/querying/knex-pagination-helpers.js:543: * 3. Added to response.meta.pagination
686
- plugins/core/lib/querying/knex-pagination-helpers.js:544: * 4. Clients can use cursor directly or use the next link
687
- plugins/core/lib/querying/knex-pagination-helpers.js:554: meta.cursor = {