json-rest-api 1.0.21 → 1.0.22
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.
- package/audit/00-charter.md +103 -0
- package/audit/01-scope-map.md +84 -0
- package/audit/02-coverage-matrix.csv +174 -0
- package/audit/03-invariants.md +123 -0
- package/audit/04-standards-rubric.md +56 -0
- package/audit/05-competitor-rubric.md +77 -0
- package/audit/06-findings.md +160 -0
- package/audit/07-risk-register.csv +10 -0
- package/audit/08-remediation-roadmap.md +177 -0
- package/audit/09-signoff-check.md +23 -0
- package/audit/10-final-synthesis.md +29 -0
- package/audit/evidence/code/all-files-json-rest-api.txt +168 -0
- package/audit/evidence/code/all-files-json-rest-schema.txt +12 -0
- package/audit/evidence/code/boundary-leak-checks.txt +72 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +480 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +532 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +175 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +138 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +222 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +342 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +304 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +188 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +336 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +165 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +265 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +369 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +72 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +139 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +45 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +396 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +162 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +1314 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +488 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +484 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +857 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +565 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +485 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +560 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +167 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +109 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +1064 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +1983 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +328 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +119 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +160 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +300 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +245 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +459 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +237 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +1135 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +314 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +7 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +71 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +102 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +49 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +39 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +23 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +13 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +639 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +117 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +104 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +199 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +353 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +61 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +184 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +55 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +191 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +110 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +168 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +253 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +207 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +12 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +165 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +668 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +621 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +218 -0
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +124 -0
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +269 -0
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +242 -0
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +77 -0
- package/audit/evidence/code/critical-pass1-risk-keywords.txt +238 -0
- package/audit/evidence/code/critical-pass1-summary.csv +67 -0
- package/audit/evidence/code/critical-pass2-summary.csv +67 -0
- package/audit/evidence/code/early-silent-zones-no-test-token.txt +57 -0
- package/audit/evidence/code/error-model-signals.txt +98 -0
- package/audit/evidence/code/git-files-json-rest-api.txt +171 -0
- package/audit/evidence/code/git-files-json-rest-schema.txt +27 -0
- package/audit/evidence/code/hook-flow-signals.txt +282 -0
- package/audit/evidence/code/idproperty-signals.txt +157 -0
- package/audit/evidence/code/import-cycles-non-anyapi.txt +3 -0
- package/audit/evidence/code/import-hotspots-non-anyapi.txt +96 -0
- package/audit/evidence/code/imports-json-rest-api.txt +354 -0
- package/audit/evidence/code/imports-json-rest-schema.txt +15 -0
- package/audit/evidence/code/in-scope-files-json-rest-api.txt +160 -0
- package/audit/evidence/code/in-scope-files-json-rest-schema.txt +13 -0
- package/audit/evidence/code/non-anyapi-core-files.txt +101 -0
- package/audit/evidence/code/permission-signals.txt +193 -0
- package/audit/evidence/code/query-include-signals.txt +687 -0
- package/audit/evidence/code/transaction-signals.txt +28 -0
- package/audit/evidence/code/validation-signals.txt +650 -0
- package/audit/evidence/code/write-path-signals.txt +61 -0
- package/audit/evidence/docs/docs-claims-signals.txt +1075 -0
- package/audit/evidence/docs/schema-docs-claims-signals.txt +179 -0
- package/audit/evidence/external/corpus-freeze.md +21 -0
- package/audit/evidence/external/npm-competitor-metadata.txt +70 -0
- package/audit/evidence/external/npm-download-signals.txt +23 -0
- package/audit/evidence/external/npm-jsonapi-server.txt +8 -0
- package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +38 -0
- package/audit/evidence/external/readme-fortune-signals.txt +26 -0
- package/audit/evidence/external/readme-fortune.md +165 -0
- package/audit/evidence/external/readme-json-api-serializer-signals.txt +80 -0
- package/audit/evidence/external/readme-json-api-serializer.md +690 -0
- package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
- package/audit/evidence/external/readme-jsonapi-serde-server.md +22 -0
- package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +63 -0
- package/audit/evidence/external/readme-jsonapi-serializer.md +315 -0
- package/audit/evidence/external/readme-jsonapi-server-signals.txt +19 -0
- package/audit/evidence/external/readme-jsonapi-server.md +104 -0
- package/audit/evidence/external/readme-nestjs-json-api-signals.txt +4 -0
- package/audit/evidence/external/readme-nestjs-json-api.md +94 -0
- package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +47 -0
- package/audit/evidence/external/readme-yaser-json-api-nestjs.md +447 -0
- package/audit/evidence/external/standard-jsonapi-snippets.txt +84 -0
- package/audit/evidence/external/standard-rfc-snippets.txt +168 -0
- package/audit/evidence/external/standards-sources.txt +6 -0
- package/audit/evidence/runtime/baseline-commits.txt +2 -0
- package/audit/evidence/runtime/db-adapter-assumptions.txt +3 -0
- package/audit/evidence/runtime/environment.txt +4 -0
- package/audit/evidence/runtime/invariant-runtime-mapping.md +38 -0
- package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +1 -0
- package/audit/evidence/runtime/probe-patch-relationship-error.log +76 -0
- package/audit/evidence/runtime/probe-patch-relationship-error.mjs +67 -0
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +1 -0
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +62 -0
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +47 -0
- package/audit/evidence/runtime/test-exitcodes.txt +4 -0
- package/audit/evidence/runtime/test-summary.md +107 -0
- package/audit/evidence/runtime/trace-anchors.txt +61 -0
- package/audit/evidence/tests/access-multitenancy-test-signals.txt +125 -0
- package/audit/evidence/tests/failing-tests-summary.txt +25 -0
- package/audit/evidence/tests/npm-test-json-rest-api.exitcode +1 -0
- package/audit/evidence/tests/npm-test-json-rest-api.log +5885 -0
- package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +1 -0
- package/audit/evidence/tests/npm-test-json-rest-schema.log +356 -0
- package/audit/evidence/tests/query-include-test-signals.txt +948 -0
- package/audit/evidence/tests/relationship-test-signals.txt +223 -0
- package/audit/evidence/tests/skipped-tests.txt +10 -0
- package/audit/evidence/tests/test-suite-list-non-anyapi.txt +30 -0
- package/audit/evidence/tests/test-suite-list.txt +32 -0
- package/audit/subsystems/docs-drift.md +49 -0
- package/audit/subsystems/pass2-cross-review.md +131 -0
- package/audit/subsystems/plugins-access.md +51 -0
- package/audit/subsystems/plugins-bulk.md +50 -0
- package/audit/subsystems/plugins-cors.md +48 -0
- package/audit/subsystems/plugins-file.md +53 -0
- package/audit/subsystems/plugins-multihome.md +50 -0
- package/audit/subsystems/plugins-positioning.md +54 -0
- package/audit/subsystems/plugins-socketio.md +50 -0
- package/audit/subsystems/query-engine.md +61 -0
- package/audit/subsystems/relationships.md +55 -0
- package/audit/subsystems/rest-orchestration.md +66 -0
- package/audit/subsystems/schema-core.md +64 -0
- package/audit/subsystems/storage-knex.md +57 -0
- package/audit/subsystems/tests.md +48 -0
- package/audit/subsystems/transport-express.md +55 -0
- package/audit/traces/trace-read-get.md +22 -0
- package/audit/traces/trace-read-query.md +25 -0
- package/audit/traces/trace-relationship-endpoints.md +31 -0
- package/audit/traces/trace-write-delete.md +17 -0
- package/audit/traces/trace-write-patch.md +26 -0
- package/audit/traces/trace-write-post.md +22 -0
- package/audit/traces/trace-write-put.md +23 -0
- package/package.json +3 -3
|
@@ -0,0 +1,687 @@
|
|
|
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 = {
|