json-rest-api 1.0.28 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +10 -670
- package/LICENSE-GPL-3.0 +674 -0
- package/LICENSE-MIT +21 -0
- package/README.md +39 -30
- package/docs/API.md +746 -1273
- package/docs/GUIDE/01-getting-started.md +338 -0
- package/docs/GUIDE/02-resources-and-relationships.md +33 -0
- package/docs/GUIDE/03-running-example.md +87 -0
- package/docs/GUIDE/04-creating-and-querying.md +181 -0
- package/docs/GUIDE/05-belongs-to.md +177 -0
- package/docs/GUIDE/06-has-many.md +184 -0
- package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
- package/docs/GUIDE/08-many-to-many.md +184 -0
- package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
- package/docs/GUIDE/10-put-and-patch.md +174 -0
- package/docs/GUIDE/11-relationship-endpoints.md +174 -0
- package/docs/GUIDE/12-field-transformations.md +287 -0
- package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
- package/docs/GUIDE/14-custom-resource-methods.md +125 -0
- package/docs/GUIDE/15-query-projections.md +266 -0
- package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
- package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
- package/docs/GUIDE/18-labels.md +86 -0
- package/docs/GUIDE/19-managed-transactions.md +179 -0
- package/docs/GUIDE/20-transaction-outcomes.md +207 -0
- package/docs/GUIDE/21-schema-and-migrations.md +634 -0
- package/docs/GUIDE/22-version-field-migrations.md +208 -0
- package/docs/GUIDE/23-fastify.md +179 -0
- package/docs/GUIDE/24-cors.md +172 -0
- package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
- package/docs/GUIDE/26-file-uploads.md +278 -0
- package/docs/GUIDE/27-bulk-operations.md +277 -0
- package/docs/GUIDE/28-socketio.md +325 -0
- package/docs/GUIDE/29-writing-plugins.md +278 -0
- package/docs/GUIDE/30-backend-capabilities.md +100 -0
- package/docs/GUIDE/31-positioning.md +181 -0
- package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +90 -31
- package/docs/GUIDE/33-migrating-to-v2.md +3827 -0
- package/docs/GUIDE/index.md +51 -59
- package/docs/QUICKSTART.md +120 -287
- package/docs/architecture.md +75 -0
- package/docs/contributing.md +178 -0
- package/index.d.ts +36 -0
- package/index.js +1 -22
- package/lib/enhanced-logger.js +91 -85
- package/lib/error-context.js +445 -5
- package/lib/error-formatter.js +219 -59
- package/lib/knex-transaction.js +64 -0
- package/lib/logger-types.d.ts +22 -0
- package/lib/missing-package.js +4 -0
- package/lib/rest-api-errors.js +103 -8
- package/lib/runtime/json-rest-api.js +172 -0
- package/lib/transaction-types.d.ts +59 -0
- package/package.json +97 -27
- package/plugins/core/bulk-operations-plugin.js +191 -184
- package/plugins/core/connectors/express-plugin.js +148 -219
- package/plugins/core/connectors/fastify-plugin.js +125 -82
- package/plugins/core/connectors/lib/busboy-detector.js +74 -156
- package/plugins/core/connectors/lib/connector-core.js +144 -20
- package/plugins/core/connectors/lib/formidable-detector.js +63 -120
- package/plugins/core/connectors/lib/http-validators.js +77 -0
- package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
- package/plugins/core/connectors/lib/request-helpers.js +10 -1
- package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
- package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
- package/plugins/core/file-handling-plugin.js +87 -174
- package/plugins/core/lib/anyapi/anyapi-registry.js +213 -164
- package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
- package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
- package/plugins/core/lib/anyapi/schema-utils.js +25 -16
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
- package/plugins/core/lib/dbIntrospection.js +228 -21
- package/plugins/core/lib/dbTablesOperations.js +409 -92
- package/plugins/core/lib/fractional-positioning.js +12 -48
- package/plugins/core/lib/querying/identifier-query.js +19 -0
- package/plugins/core/lib/querying/include-query-helpers.js +364 -0
- package/plugins/core/lib/querying/include-to-many.js +428 -0
- package/plugins/core/lib/querying/include-to-one.js +579 -0
- package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
- package/plugins/core/lib/querying/knex-pagination-helpers.js +67 -330
- package/plugins/core/lib/querying/knex-process-includes.js +5 -110
- package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
- package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
- package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
- package/plugins/core/lib/querying/knex-window-queries.js +62 -253
- package/plugins/core/lib/querying/query-builder-utils.js +44 -4
- package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
- package/plugins/core/lib/querying/query-constraint.js +27 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +205 -30
- package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
- package/plugins/core/lib/querying/sort-helpers.js +20 -1
- package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
- package/plugins/core/lib/querying/url-helpers.js +11 -4
- package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
- package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +238 -187
- package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
- package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
- package/plugins/core/lib/querying-writing/field-utils.js +113 -92
- package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
- package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +111 -287
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
- package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
- package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
- package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
- package/plugins/core/lib/querying-writing/request-contracts.js +109 -44
- package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
- package/plugins/core/lib/querying-writing/response-options.js +35 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
- package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
- package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
- package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
- package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
- package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
- package/plugins/core/lib/storage/storage-adapter.js +142 -62
- package/plugins/core/lib/storage/storage-mapping.js +78 -28
- package/plugins/core/lib/storage/storage-types.d.ts +502 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
- package/plugins/core/lib/writing/relationship-processor.js +94 -158
- package/plugins/core/lib/writing/resource-version.js +172 -0
- package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
- package/plugins/core/rest-api-anyapi-knex-plugin.js +116 -2509
- package/plugins/core/rest-api-autofilter-plugin.js +17 -19
- package/plugins/core/rest-api-cors-plugin.js +52 -205
- package/plugins/core/rest-api-knex-plugin.js +45 -1069
- package/plugins/core/rest-api-label-plugin.js +25 -38
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
- package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
- package/plugins/core/rest-api-plugin-methods/common.js +291 -385
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
- package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -145
- package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
- package/plugins/core/rest-api-plugin-methods/get.js +38 -69
- package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
- package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
- package/plugins/core/rest-api-plugin-methods/post.js +51 -51
- package/plugins/core/rest-api-plugin-methods/put.js +69 -148
- package/plugins/core/rest-api-plugin-methods/query.js +39 -82
- package/plugins/core/rest-api-plugin-methods/release.js +2 -1
- package/plugins/core/rest-api-plugin.js +32 -46
- package/plugins/core/rest-api-positioning-plugin.js +183 -628
- package/plugins/core/rest-api-query-projections-plugin.js +19 -102
- package/plugins/core/rest-api-row-policy-plugin.js +3 -3
- package/plugins/core/socketio-plugin.js +364 -344
- package/plugins/storage/local-storage.js +40 -36
- package/types/autofilter.d.ts +57 -0
- package/types/bulk-methods.d.ts +63 -0
- package/types/errors.d.ts +118 -0
- package/types/fastify-options.d.ts +19 -0
- package/types/file-detectors.d.ts +33 -0
- package/types/file-storage.d.ts +48 -0
- package/types/hook-context.d.ts +180 -0
- package/types/plugin-options.d.ts +53 -0
- package/types/relationship-methods.d.ts +74 -0
- package/types/representations.d.ts +50 -0
- package/types/resource-methods.d.ts +95 -0
- package/types/resource-schema.d.ts +157 -0
- package/types/row-policy.d.ts +31 -0
- package/types/runtime.d.ts +132 -0
- package/types/transactions.d.ts +21 -0
- package/.claude/agents/library-guide-expert.md +0 -30
- package/.claude/agents/rest-api-internals-expert.md +0 -54
- package/.claude/settings.local.json +0 -70
- package/AGENTS.md +0 -34
- package/CLAUDE.md +0 -160
- package/CRUSH.md +0 -55
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
- package/TODO.todo +0 -13
- package/connectors_ideas/fastify.js +0 -217
- package/connectors_ideas/koa-plugin.js +0 -112
- package/docs/.bundle/config +0 -2
- package/docs/COMPARISON.md +0 -433
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
- package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
- package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
- package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
- package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
- package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1238
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
- package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
- package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
- package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
- package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
- package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
- package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
- package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
- package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
- package/docs/Gemfile +0 -6
- package/docs/Gemfile.lock +0 -308
- package/docs/ONBOARDING.md +0 -315
- package/docs/_config.yml +0 -36
- package/docs/_layouts/default.html +0 -123
- package/docs/apple-touch-icon.svg +0 -4
- package/docs/assets/css/style.scss +0 -392
- package/docs/favicon.svg +0 -4
- package/docs/index.md +0 -164
- package/docs/mini-guides/file-uploads-complete.md +0 -161
- package/eslint.config.js +0 -13
- package/examples/url-override-example.js +0 -137
- package/fixing_plan.md +0 -112
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
- package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
- package/plugins/storage/s3-storage.js +0 -93
- package/quickTest.js +0 -136
- package/scripts/debug-anyapi-review-filter.mjs +0 -63
- package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
- package/scripts/inspect-anyapi-descriptor.mjs +0 -19
- package/scripts/run-docs.js +0 -133
- package/test-debug.js +0 -59
- package/tests/README.md +0 -202
- package/tests/TEST_TEMPLATE.test.js +0 -178
- package/tests/anyapi-basic.test.js +0 -105
- package/tests/anyapi-cursor-pagination.test.js +0 -150
- package/tests/anyapi-custom-idproperty.test.js +0 -163
- package/tests/autofilter.test.js +0 -463
- package/tests/bulk-operations.test.js +0 -657
- package/tests/computed-fields.test.js +0 -586
- package/tests/cors.test.js +0 -834
- package/tests/curl.test.js +0 -467
- package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
- package/tests/custom-id-simplified-post.test.js +0 -75
- package/tests/custom-idproperty-relationships.test.js +0 -932
- package/tests/db-introspection.test.js +0 -521
- package/tests/db-table-operations.test.js +0 -798
- package/tests/fastify-plugin.test.js +0 -184
- package/tests/field-getters.test.js +0 -370
- package/tests/field-setters.test.js +0 -306
- package/tests/file-handling.test.js +0 -118
- package/tests/fixtures/api-configs.js +0 -2509
- package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
- package/tests/helpers/fake-fastify.js +0 -99
- package/tests/helpers/storage-mode.js +0 -65
- package/tests/helpers/test-utils.js +0 -203
- package/tests/http-connectors-parity.test.js +0 -395
- package/tests/id-normalization.test.js +0 -444
- package/tests/include-depth-validation.test.js +0 -331
- package/tests/includes.test.js +0 -427
- package/tests/local-storage.test.js +0 -96
- package/tests/logical-id-write-validation.test.js +0 -151
- package/tests/nested-includes.test.js +0 -617
- package/tests/pagination-cursor-multifield.test.js +0 -643
- package/tests/pagination-enhanced.test.js +0 -563
- package/tests/polymorphic-relationships.test.js +0 -347
- package/tests/polymorphic-simple.test.js +0 -148
- package/tests/positioning-advanced.test.js +0 -692
- package/tests/positioning-extended.test.js +0 -915
- package/tests/positioning-multifilter.test.js +0 -699
- package/tests/positioning.test.js +0 -560
- package/tests/post-commit-hooks.test.js +0 -120
- package/tests/projected-fields.test.js +0 -319
- package/tests/public-exports.test.js +0 -15
- package/tests/put-create-parity.test.js +0 -216
- package/tests/queries.test.js +0 -521
- package/tests/query-limits.test.js +0 -584
- package/tests/relationship-endpoints.test.js +0 -620
- package/tests/relationship-include-storage-adapter.test.js +0 -56
- package/tests/relationships.test.js +0 -681
- package/tests/rest-api.test.js +0 -337
- package/tests/return-record-settings.test.js +0 -184
- package/tests/row-policy.test.js +0 -489
- package/tests/s3-storage.test.js +0 -38
- package/tests/searchschema-knex-behavior.test.js +0 -187
- package/tests/searchschema-merge.test.js +0 -151
- package/tests/socketio.test.js +0 -860
- package/tests/storage-mapping.test.js +0 -362
- package/tests/test-development-guide.md +0 -370
- package/tests/virtual-fields.test.js +0 -404
|
@@ -1,712 +0,0 @@
|
|
|
1
|
-
# 2.6 Many to Many Relationships
|
|
2
|
-
|
|
3
|
-
Many-to-many relationships connect two resources through a pivot/junction table. For example, books can have multiple authors, and authors can write multiple books. This relationship is managed through a `book_authors` table that stores the connections.
|
|
4
|
-
|
|
5
|
-
Note that `book_authors` is not just a table, but a first class resource that you can manipulate like any other.
|
|
6
|
-
|
|
7
|
-
Let's create a complete example with books, authors, and their many-to-many relationship:
|
|
8
|
-
|
|
9
|
-
```javascript
|
|
10
|
-
// Define books resource
|
|
11
|
-
await api.addResource('books', {
|
|
12
|
-
schema: {
|
|
13
|
-
title: { type: 'string', required: true, max: 255, search: true, indexed: true },
|
|
14
|
-
isbn: { type: 'string', max: 20, unique: true },
|
|
15
|
-
published_year: { type: 'number', min: 1900, max: 2100 }
|
|
16
|
-
},
|
|
17
|
-
relationships: {
|
|
18
|
-
authors: {
|
|
19
|
-
type: 'manyToMany',
|
|
20
|
-
through: 'book_authors', // The pivot table
|
|
21
|
-
foreignKey: 'book_id', // Column in pivot table pointing to books
|
|
22
|
-
otherKey: 'author_id' // Column in pivot table pointing to authors
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
searchSchema: {
|
|
26
|
-
title: { type: 'string', filterOperator: 'like' },
|
|
27
|
-
|
|
28
|
-
// Cross-table search through many-to-many relationship
|
|
29
|
-
authorName: {
|
|
30
|
-
type: 'string',
|
|
31
|
-
actualField: 'authors.name', // Search author names through the pivot
|
|
32
|
-
filterOperator: 'like'
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
await api.resources.books.createKnexTable();
|
|
37
|
-
|
|
38
|
-
// Define authors resource (already defined above, but showing the many-to-many side)
|
|
39
|
-
await api.addResource('authors', {
|
|
40
|
-
schema: {
|
|
41
|
-
name: { type: 'string', required: true, max: 100, search: true, indexed: true },
|
|
42
|
-
surname: { type: 'string', required: true, max: 100, search: true },
|
|
43
|
-
bio: { type: 'string', max: 1000, nullable: true }
|
|
44
|
-
},
|
|
45
|
-
relationships: {
|
|
46
|
-
books: {
|
|
47
|
-
type: 'manyToMany',
|
|
48
|
-
through: 'book_authors', // Same pivot table
|
|
49
|
-
foreignKey: 'author_id', // Column in pivot table pointing to authors
|
|
50
|
-
otherKey: 'book_id' // Column in pivot table pointing to books
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
searchSchema: {
|
|
54
|
-
name: { type: 'string', filterOperator: 'like' },
|
|
55
|
-
surname: { type: 'string', filterOperator: 'like' },
|
|
56
|
-
|
|
57
|
-
// Cross-table search through many-to-many relationship
|
|
58
|
-
bookTitle: {
|
|
59
|
-
type: 'string',
|
|
60
|
-
actualField: 'books.title', // Search book titles through the pivot
|
|
61
|
-
filterOperator: 'like'
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
await api.resources.authors.createKnexTable();
|
|
66
|
-
|
|
67
|
-
// Define the pivot table resource
|
|
68
|
-
// This is optional but useful if you need to store additional data on the relationship
|
|
69
|
-
await api.addResource('book_authors', {
|
|
70
|
-
schema: {
|
|
71
|
-
book_id: { type: 'id', belongsTo: 'books', as: 'book', required: true },
|
|
72
|
-
author_id: { type: 'id', belongsTo: 'authors', as: 'author', required: true },
|
|
73
|
-
contribution_type: { type: 'string', max: 50, nullable: true }, // e.g., 'primary', 'co-author', 'editor'
|
|
74
|
-
royalty_percentage: { type: 'number', min: 0, max: 100, nullable: true }
|
|
75
|
-
}
|
|
76
|
-
// Note: Composite primary keys are not yet supported, but will be added in a future version
|
|
77
|
-
// For now, the table will use the default 'id' primary key
|
|
78
|
-
});
|
|
79
|
-
await api.resources.book_authors.createKnexTable();
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
The `manyToMany` relationship type requires the following properties:
|
|
83
|
-
- `through`: The pivot table name
|
|
84
|
-
- `foreignKey`: The column in the pivot table pointing to the current resource
|
|
85
|
-
- `otherKey`: The column in the pivot table pointing to the related resource
|
|
86
|
-
|
|
87
|
-
Now let's create some data and explore how to work with many-to-many relationships:
|
|
88
|
-
|
|
89
|
-
```javascript
|
|
90
|
-
// Create some authors
|
|
91
|
-
const author1 = await api.resources.authors.post({
|
|
92
|
-
name: 'Neil',
|
|
93
|
-
surname: 'Gaiman',
|
|
94
|
-
bio: 'British author of fiction, horror, and fantasy'
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const author2 = await api.resources.authors.post({
|
|
98
|
-
name: 'Terry',
|
|
99
|
-
surname: 'Pratchett',
|
|
100
|
-
bio: 'English humorist and fantasy author'
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const author3 = await api.resources.authors.post({
|
|
104
|
-
name: 'Stephen',
|
|
105
|
-
surname: 'King',
|
|
106
|
-
bio: 'American author of horror and supernatural fiction'
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Create books with authors - simplified mode
|
|
110
|
-
const goodOmens = await api.resources.books.post({
|
|
111
|
-
title: 'Good Omens',
|
|
112
|
-
isbn: '978-0060853983',
|
|
113
|
-
published_year: 1990,
|
|
114
|
-
authors: [author1.id, author2.id] // Co-authored by Gaiman and Pratchett
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const americanGods = await api.resources.books.post({
|
|
118
|
-
title: 'American Gods',
|
|
119
|
-
isbn: '978-0380789030',
|
|
120
|
-
published_year: 2001,
|
|
121
|
-
authors: [author1.id] // Written by Gaiman alone
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// Create a book using non-simplified mode
|
|
125
|
-
const theShining = await api.resources.books.post({
|
|
126
|
-
inputRecord: {
|
|
127
|
-
data: {
|
|
128
|
-
type: 'books',
|
|
129
|
-
attributes: {
|
|
130
|
-
title: 'The Shining',
|
|
131
|
-
isbn: '978-0307743657',
|
|
132
|
-
published_year: 1977
|
|
133
|
-
},
|
|
134
|
-
relationships: {
|
|
135
|
-
authors: {
|
|
136
|
-
data: [
|
|
137
|
-
{ type: 'authors', id: author3.id }
|
|
138
|
-
]
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
simplified: false
|
|
144
|
-
});
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Working with Pivot Tables Directly
|
|
148
|
-
|
|
149
|
-
Sometimes you need more control over the pivot table data, such as storing additional information about the relationship itself. There are two approaches:
|
|
150
|
-
|
|
151
|
-
### 1. Creating relationships via the pivot table
|
|
152
|
-
|
|
153
|
-
Instead of using the `authors` field when creating a book, you can create the relationships directly through the pivot table. This is useful when you need to add extra data:
|
|
154
|
-
|
|
155
|
-
```javascript
|
|
156
|
-
// Create a book without authors
|
|
157
|
-
const newBook = await api.resources.books.post({
|
|
158
|
-
title: 'The Color of Magic',
|
|
159
|
-
isbn: '978-0062225672',
|
|
160
|
-
published_year: 1983
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Then create the relationship with extra pivot data
|
|
164
|
-
await api.resources.book_authors.post({
|
|
165
|
-
book_id: newBook.id,
|
|
166
|
-
author_id: author2.id, // Terry Pratchett
|
|
167
|
-
contribution_type: 'primary',
|
|
168
|
-
royalty_percentage: 100
|
|
169
|
-
});
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 2. Updating existing pivot records
|
|
173
|
-
|
|
174
|
-
If you've already created relationships (e.g., using `authors: [author1.id, author2.id]` during book creation), you can update the pivot records to add extra data:
|
|
175
|
-
|
|
176
|
-
```javascript
|
|
177
|
-
// First, find the pivot records for Good Omens
|
|
178
|
-
const pivotRecords = await api.resources.book_authors.query({
|
|
179
|
-
queryParams: {
|
|
180
|
-
filters: {
|
|
181
|
-
book_id: goodOmens.id
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// Update each pivot record with extra data
|
|
187
|
-
for (const record of pivotRecords.data) {
|
|
188
|
-
await api.resources.book_authors.patch({
|
|
189
|
-
id: record.id,
|
|
190
|
-
contribution_type: 'co-author',
|
|
191
|
-
royalty_percentage: 50
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Note:** Be careful not to create duplicate pivot records. If you use `authors: [...]` when creating a book, the pivot records are created automatically. Only manually create pivot records if you haven't used the relationship field during resource creation.
|
|
197
|
-
|
|
198
|
-
## Including Many-to-Many Records (`include`)
|
|
199
|
-
|
|
200
|
-
When you fetch resources with many-to-many relationships, by default you only get the IDs:
|
|
201
|
-
|
|
202
|
-
```javascript
|
|
203
|
-
const book_simplified = await api.resources.books.get({ id: goodOmens.id });
|
|
204
|
-
const book_non_simplified = await api.resources.books.get({ id: goodOmens.id, simplified: false });
|
|
205
|
-
|
|
206
|
-
console.log('Book without includes (simplified):', inspect(book_simplified));
|
|
207
|
-
console.log('Book without includes (non-simplified):', inspect(book_non_simplified));
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
**Expected Output**
|
|
211
|
-
|
|
212
|
-
```text
|
|
213
|
-
Book without includes (simplified):
|
|
214
|
-
{
|
|
215
|
-
id: '1',
|
|
216
|
-
title: 'Good Omens',
|
|
217
|
-
isbn: '978-0060853983',
|
|
218
|
-
published_year: 1990,
|
|
219
|
-
authors_ids: ['1', '2'] // Just the IDs
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
Book without includes (non-simplified):
|
|
223
|
-
{
|
|
224
|
-
data: {
|
|
225
|
-
type: 'books',
|
|
226
|
-
id: '1',
|
|
227
|
-
attributes: {
|
|
228
|
-
title: 'Good Omens',
|
|
229
|
-
isbn: '978-0060853983',
|
|
230
|
-
published_year: 1990
|
|
231
|
-
},
|
|
232
|
-
relationships: {
|
|
233
|
-
authors: {
|
|
234
|
-
data: [
|
|
235
|
-
{ type: 'authors', id: '1' },
|
|
236
|
-
{ type: 'authors', id: '2' }
|
|
237
|
-
]
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
links: { self: '/api/books/1' }
|
|
241
|
-
},
|
|
242
|
-
links: { self: '/api/books/1' }
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## Including Many to many Records (`include`)
|
|
247
|
-
|
|
248
|
-
To retrieve the full related resources through a many-to-many relationship, use the `include` query parameter:
|
|
249
|
-
|
|
250
|
-
```javascript
|
|
251
|
-
// Get a book with its authors included
|
|
252
|
-
const book_with_authors_simplified = await api.resources.books.get({
|
|
253
|
-
id: goodOmens.id,
|
|
254
|
-
queryParams: { include: ['authors'] }
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
const book_with_authors_non_simplified = await api.resources.books.get({
|
|
258
|
-
id: goodOmens.id,
|
|
259
|
-
queryParams: { include: ['authors'] },
|
|
260
|
-
simplified: false
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
// Get all books with their authors
|
|
264
|
-
const books_with_authors_simplified = await api.resources.books.query({
|
|
265
|
-
queryParams: { include: ['authors'] }
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
const books_with_authors_non_simplified = await api.resources.books.query({
|
|
269
|
-
queryParams: { include: ['authors'] },
|
|
270
|
-
simplified: false
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
console.log('Book with authors (simplified):', inspect(book_with_authors_simplified));
|
|
274
|
-
console.log('Book with authors (non-simplified):', inspect(book_with_authors_non_simplified));
|
|
275
|
-
console.log('Books with authors (simplified):', inspect(books_with_authors_simplified));
|
|
276
|
-
console.log('Books with authors (non-simplified):', inspect(books_with_authors_non_simplified));
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
**Expected Output**
|
|
280
|
-
|
|
281
|
-
```text
|
|
282
|
-
Book with authors (simplified): {
|
|
283
|
-
id: '1',
|
|
284
|
-
title: 'Good Omens',
|
|
285
|
-
isbn: '978-0060853983',
|
|
286
|
-
published_year: 1990,
|
|
287
|
-
authors_ids: [ '1', '2' ],
|
|
288
|
-
authors: [
|
|
289
|
-
{
|
|
290
|
-
id: '1',
|
|
291
|
-
name: 'Neil',
|
|
292
|
-
surname: 'Gaiman',
|
|
293
|
-
bio: 'British author of fiction, horror, and fantasy',
|
|
294
|
-
books_ids: []
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
id: '2',
|
|
298
|
-
name: 'Terry',
|
|
299
|
-
surname: 'Pratchett',
|
|
300
|
-
bio: 'English humorist and fantasy author',
|
|
301
|
-
books_ids: []
|
|
302
|
-
}
|
|
303
|
-
]
|
|
304
|
-
}
|
|
305
|
-
Book with authors (non-simplified): {
|
|
306
|
-
data: {
|
|
307
|
-
type: 'books',
|
|
308
|
-
id: '1',
|
|
309
|
-
attributes: {
|
|
310
|
-
title: 'Good Omens',
|
|
311
|
-
isbn: '978-0060853983',
|
|
312
|
-
published_year: 1990
|
|
313
|
-
},
|
|
314
|
-
relationships: {
|
|
315
|
-
authors: {
|
|
316
|
-
data: [ { type: 'authors', id: '1' }, { type: 'authors', id: '2' } ],
|
|
317
|
-
links: {
|
|
318
|
-
self: '/api/books/1/relationships/authors',
|
|
319
|
-
related: '/api/books/1/authors'
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
},
|
|
323
|
-
links: { self: '/api/books/1' }
|
|
324
|
-
},
|
|
325
|
-
included: [
|
|
326
|
-
{
|
|
327
|
-
type: 'authors',
|
|
328
|
-
id: '1',
|
|
329
|
-
attributes: {
|
|
330
|
-
name: 'Neil',
|
|
331
|
-
surname: 'Gaiman',
|
|
332
|
-
bio: 'British author of fiction, horror, and fantasy'
|
|
333
|
-
},
|
|
334
|
-
relationships: { books: { data: [] } },
|
|
335
|
-
links: { self: '/api/authors/1' }
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
type: 'authors',
|
|
339
|
-
id: '2',
|
|
340
|
-
attributes: {
|
|
341
|
-
name: 'Terry',
|
|
342
|
-
surname: 'Pratchett',
|
|
343
|
-
bio: 'English humorist and fantasy author'
|
|
344
|
-
},
|
|
345
|
-
relationships: { books: { data: [] } },
|
|
346
|
-
links: { self: '/api/authors/2' }
|
|
347
|
-
}
|
|
348
|
-
],
|
|
349
|
-
links: { self: '/api/books/1' }
|
|
350
|
-
}
|
|
351
|
-
Books with authors (simplified): {
|
|
352
|
-
data: [
|
|
353
|
-
{
|
|
354
|
-
id: '1',
|
|
355
|
-
title: 'Good Omens',
|
|
356
|
-
isbn: '978-0060853983',
|
|
357
|
-
published_year: 1990,
|
|
358
|
-
authors_ids: [ '1', '2' ],
|
|
359
|
-
authors: [
|
|
360
|
-
{
|
|
361
|
-
id: '1',
|
|
362
|
-
name: 'Neil',
|
|
363
|
-
surname: 'Gaiman',
|
|
364
|
-
bio: 'British author of fiction, horror, and fantasy',
|
|
365
|
-
books_ids: []
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
id: '2',
|
|
369
|
-
name: 'Terry',
|
|
370
|
-
surname: 'Pratchett',
|
|
371
|
-
bio: 'English humorist and fantasy author',
|
|
372
|
-
books_ids: []
|
|
373
|
-
}
|
|
374
|
-
]
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
id: '2',
|
|
378
|
-
title: 'American Gods',
|
|
379
|
-
isbn: '978-0380789030',
|
|
380
|
-
published_year: 2001,
|
|
381
|
-
authors_ids: [ '1' ],
|
|
382
|
-
authors: [
|
|
383
|
-
{
|
|
384
|
-
id: '1',
|
|
385
|
-
name: 'Neil',
|
|
386
|
-
surname: 'Gaiman',
|
|
387
|
-
bio: 'British author of fiction, horror, and fantasy',
|
|
388
|
-
books_ids: []
|
|
389
|
-
}
|
|
390
|
-
]
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
id: '3',
|
|
394
|
-
title: 'The Shining',
|
|
395
|
-
isbn: '978-0307743657',
|
|
396
|
-
published_year: 1977,
|
|
397
|
-
authors_ids: [ '3' ],
|
|
398
|
-
authors: [
|
|
399
|
-
{
|
|
400
|
-
id: '3',
|
|
401
|
-
name: 'Stephen',
|
|
402
|
-
surname: 'King',
|
|
403
|
-
bio: 'American author of horror and supernatural fiction',
|
|
404
|
-
books_ids: []
|
|
405
|
-
}
|
|
406
|
-
]
|
|
407
|
-
}
|
|
408
|
-
],
|
|
409
|
-
links: { self: '/api/books?include=authors' }
|
|
410
|
-
}
|
|
411
|
-
Books with authors (non-simplified): {
|
|
412
|
-
data: [
|
|
413
|
-
{
|
|
414
|
-
type: 'books',
|
|
415
|
-
id: '1',
|
|
416
|
-
attributes: {
|
|
417
|
-
title: 'Good Omens',
|
|
418
|
-
isbn: '978-0060853983',
|
|
419
|
-
published_year: 1990
|
|
420
|
-
},
|
|
421
|
-
relationships: {
|
|
422
|
-
authors: {
|
|
423
|
-
data: [
|
|
424
|
-
{ type: 'authors', id: '1' },
|
|
425
|
-
{ type: 'authors', id: '2' }
|
|
426
|
-
],
|
|
427
|
-
links: {
|
|
428
|
-
self: '/api/books/1/relationships/authors',
|
|
429
|
-
related: '/api/books/1/authors'
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
links: { self: '/api/books/1' }
|
|
434
|
-
},
|
|
435
|
-
{
|
|
436
|
-
type: 'books',
|
|
437
|
-
id: '2',
|
|
438
|
-
attributes: {
|
|
439
|
-
title: 'American Gods',
|
|
440
|
-
isbn: '978-0380789030',
|
|
441
|
-
published_year: 2001
|
|
442
|
-
},
|
|
443
|
-
relationships: {
|
|
444
|
-
authors: {
|
|
445
|
-
data: [ { type: 'authors', id: '1' } ],
|
|
446
|
-
links: {
|
|
447
|
-
self: '/api/books/2/relationships/authors',
|
|
448
|
-
related: '/api/books/2/authors'
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
},
|
|
452
|
-
links: { self: '/api/books/2' }
|
|
453
|
-
},
|
|
454
|
-
{
|
|
455
|
-
type: 'books',
|
|
456
|
-
id: '3',
|
|
457
|
-
attributes: {
|
|
458
|
-
title: 'The Shining',
|
|
459
|
-
isbn: '978-0307743657',
|
|
460
|
-
published_year: 1977
|
|
461
|
-
},
|
|
462
|
-
relationships: {
|
|
463
|
-
authors: {
|
|
464
|
-
data: [ { type: 'authors', id: '3' } ],
|
|
465
|
-
links: {
|
|
466
|
-
self: '/api/books/3/relationships/authors',
|
|
467
|
-
related: '/api/books/3/authors'
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
},
|
|
471
|
-
links: { self: '/api/books/3' }
|
|
472
|
-
}
|
|
473
|
-
],
|
|
474
|
-
included: [
|
|
475
|
-
{
|
|
476
|
-
type: 'authors',
|
|
477
|
-
id: '1',
|
|
478
|
-
attributes: {
|
|
479
|
-
name: 'Neil',
|
|
480
|
-
surname: 'Gaiman',
|
|
481
|
-
bio: 'British author of fiction, horror, and fantasy'
|
|
482
|
-
},
|
|
483
|
-
relationships: { books: { data: [] } },
|
|
484
|
-
links: { self: '/api/authors/1' }
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
type: 'authors',
|
|
488
|
-
id: '2',
|
|
489
|
-
attributes: {
|
|
490
|
-
name: 'Terry',
|
|
491
|
-
surname: 'Pratchett',
|
|
492
|
-
bio: 'English humorist and fantasy author'
|
|
493
|
-
},
|
|
494
|
-
relationships: { books: { data: [] } },
|
|
495
|
-
links: { self: '/api/authors/2' }
|
|
496
|
-
},
|
|
497
|
-
{
|
|
498
|
-
type: 'authors',
|
|
499
|
-
id: '3',
|
|
500
|
-
attributes: {
|
|
501
|
-
name: 'Stephen',
|
|
502
|
-
surname: 'King',
|
|
503
|
-
bio: 'American author of horror and supernatural fiction'
|
|
504
|
-
},
|
|
505
|
-
relationships: { books: { data: [] } },
|
|
506
|
-
links: { self: '/api/authors/3' }
|
|
507
|
-
}
|
|
508
|
-
],
|
|
509
|
-
links: { self: '/api/books?include=authors' }
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
The include system automatically handles the JOIN through the pivot table. In simplified mode, the related resources are embedded directly. In JSON:API mode, they appear in the `included` array.
|
|
515
|
-
|
|
516
|
-
## Search (many to many)
|
|
517
|
-
|
|
518
|
-
The search functionality for many-to-many relationships allows you to filter parent resources based on attributes of their related resources through the pivot table. This is particularly powerful for queries like "find all books written by authors named Neil" or "find all authors who wrote books with 'Gods' in the title".
|
|
519
|
-
|
|
520
|
-
Using the schema definitions from above, which include cross-table search fields:
|
|
521
|
-
|
|
522
|
-
```javascript
|
|
523
|
-
// 1. Find books by author name (searches through the many-to-many relationship)
|
|
524
|
-
const books_by_neil_simplified = await api.resources.books.query({
|
|
525
|
-
queryParams: { filters: { authorName: 'Neil' } }
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
const books_by_neil_non_simplified = await api.resources.books.query({
|
|
529
|
-
queryParams: { filters: { authorName: 'Neil' } },
|
|
530
|
-
simplified: false
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
// 2. Find authors by book title (reverse search through many-to-many)
|
|
534
|
-
const authors_of_gods_books_simplified = await api.resources.authors.query({
|
|
535
|
-
queryParams: { filters: { bookTitle: 'Gods' } }
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
const authors_of_gods_books_non_simplified = await api.resources.authors.query({
|
|
539
|
-
queryParams: { filters: { bookTitle: 'Gods' } },
|
|
540
|
-
simplified: false
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
// 3. Combine searches: Find books by Neil that include full author data
|
|
544
|
-
const neil_books_with_authors = await api.resources.books.query({
|
|
545
|
-
queryParams: {
|
|
546
|
-
filters: { authorName: 'Neil' },
|
|
547
|
-
include: ['authors']
|
|
548
|
-
}
|
|
549
|
-
});
|
|
550
|
-
|
|
551
|
-
console.log('Books by Neil (simplified):', inspect(books_by_neil_simplified));
|
|
552
|
-
console.log('Books by Neil (non-simplified):', inspect(books_by_neil_non_simplified));
|
|
553
|
-
console.log('Authors who wrote books with "Gods" (simplified):', inspect(authors_of_gods_books_simplified));
|
|
554
|
-
console.log('Authors who wrote books with "Gods" (non-simplified):', inspect(authors_of_gods_books_non_simplified));
|
|
555
|
-
console.log('Neil books with full author data:', inspect(neil_books_with_authors));
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
**Expected Output**
|
|
559
|
-
|
|
560
|
-
```text
|
|
561
|
-
Books by Neil (simplified): {
|
|
562
|
-
data: [
|
|
563
|
-
{
|
|
564
|
-
id: '1',
|
|
565
|
-
title: 'Good Omens',
|
|
566
|
-
isbn: '978-0060853983',
|
|
567
|
-
published_year: 1990,
|
|
568
|
-
authors_ids: [ '1', '2' ]
|
|
569
|
-
},
|
|
570
|
-
{
|
|
571
|
-
id: '2',
|
|
572
|
-
title: 'American Gods',
|
|
573
|
-
isbn: '978-0380789030',
|
|
574
|
-
published_year: 2001,
|
|
575
|
-
authors_ids: [ '1' ]
|
|
576
|
-
}
|
|
577
|
-
],
|
|
578
|
-
links: { self: '/api/books?filters[authorName]=Neil' }
|
|
579
|
-
}
|
|
580
|
-
Books by Neil (non-simplified): {
|
|
581
|
-
data: [
|
|
582
|
-
{
|
|
583
|
-
type: 'books',
|
|
584
|
-
id: '1',
|
|
585
|
-
attributes: {
|
|
586
|
-
title: 'Good Omens',
|
|
587
|
-
isbn: '978-0060853983',
|
|
588
|
-
published_year: 1990
|
|
589
|
-
},
|
|
590
|
-
relationships: {
|
|
591
|
-
authors: {
|
|
592
|
-
data: [
|
|
593
|
-
{ type: 'authors', id: '1' },
|
|
594
|
-
{ type: 'authors', id: '2' }
|
|
595
|
-
]
|
|
596
|
-
}
|
|
597
|
-
},
|
|
598
|
-
links: { self: '/api/books/1' }
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
type: 'books',
|
|
602
|
-
id: '2',
|
|
603
|
-
attributes: {
|
|
604
|
-
title: 'American Gods',
|
|
605
|
-
isbn: '978-0380789030',
|
|
606
|
-
published_year: 2001
|
|
607
|
-
},
|
|
608
|
-
relationships: {
|
|
609
|
-
authors: { data: [ { type: 'authors', id: '1' } ] }
|
|
610
|
-
},
|
|
611
|
-
links: { self: '/api/books/2' }
|
|
612
|
-
}
|
|
613
|
-
],
|
|
614
|
-
links: { self: '/api/books?filters[authorName]=Neil' }
|
|
615
|
-
}
|
|
616
|
-
Authors who wrote books with "Gods" (simplified): {
|
|
617
|
-
data: [
|
|
618
|
-
{
|
|
619
|
-
id: '1',
|
|
620
|
-
name: 'Neil',
|
|
621
|
-
surname: 'Gaiman',
|
|
622
|
-
bio: 'British author of fiction, horror, and fantasy',
|
|
623
|
-
books_ids: [ '1', '2' ]
|
|
624
|
-
}
|
|
625
|
-
],
|
|
626
|
-
links: { self: '/api/authors?filters[bookTitle]=Gods' }
|
|
627
|
-
}
|
|
628
|
-
Authors who wrote books with "Gods" (non-simplified): {
|
|
629
|
-
data: [
|
|
630
|
-
{
|
|
631
|
-
type: 'authors',
|
|
632
|
-
id: '1',
|
|
633
|
-
attributes: {
|
|
634
|
-
name: 'Neil',
|
|
635
|
-
surname: 'Gaiman',
|
|
636
|
-
bio: 'British author of fiction, horror, and fantasy'
|
|
637
|
-
},
|
|
638
|
-
relationships: {
|
|
639
|
-
books: {
|
|
640
|
-
data: [ { type: 'books', id: '1' }, { type: 'books', id: '2' } ]
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
links: { self: '/api/authors/1' }
|
|
644
|
-
}
|
|
645
|
-
],
|
|
646
|
-
links: { self: '/api/authors?filters[bookTitle]=Gods' }
|
|
647
|
-
}
|
|
648
|
-
Neil books with full author data: {
|
|
649
|
-
data: [
|
|
650
|
-
{
|
|
651
|
-
id: '1',
|
|
652
|
-
title: 'Good Omens',
|
|
653
|
-
isbn: '978-0060853983',
|
|
654
|
-
published_year: 1990,
|
|
655
|
-
authors_ids: [ '1', '2' ],
|
|
656
|
-
authors: [
|
|
657
|
-
{
|
|
658
|
-
id: '1',
|
|
659
|
-
name: 'Neil',
|
|
660
|
-
surname: 'Gaiman',
|
|
661
|
-
bio: 'British author of fiction, horror, and fantasy',
|
|
662
|
-
books_ids: []
|
|
663
|
-
},
|
|
664
|
-
{
|
|
665
|
-
id: '2',
|
|
666
|
-
name: 'Terry',
|
|
667
|
-
surname: 'Pratchett',
|
|
668
|
-
bio: 'English humorist and fantasy author',
|
|
669
|
-
books_ids: []
|
|
670
|
-
}
|
|
671
|
-
]
|
|
672
|
-
},
|
|
673
|
-
{
|
|
674
|
-
id: '2',
|
|
675
|
-
title: 'American Gods',
|
|
676
|
-
isbn: '978-0380789030',
|
|
677
|
-
published_year: 2001,
|
|
678
|
-
authors_ids: [ '1' ],
|
|
679
|
-
authors: [
|
|
680
|
-
{
|
|
681
|
-
id: '1',
|
|
682
|
-
name: 'Neil',
|
|
683
|
-
surname: 'Gaiman',
|
|
684
|
-
bio: 'British author of fiction, horror, and fantasy',
|
|
685
|
-
books_ids: []
|
|
686
|
-
}
|
|
687
|
-
]
|
|
688
|
-
}
|
|
689
|
-
],
|
|
690
|
-
links: { self: '/api/books?filters[authorName]=Neil&include=authors' }
|
|
691
|
-
}
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
The cross-table search through many-to-many relationships works by:
|
|
695
|
-
1. Starting from the main table (e.g., books)
|
|
696
|
-
2. JOINing through the pivot table (book_authors)
|
|
697
|
-
3. JOINing to the related table (authors)
|
|
698
|
-
4. Applying the filter on the related table's field
|
|
699
|
-
|
|
700
|
-
This generates SQL similar to:
|
|
701
|
-
```sql
|
|
702
|
-
SELECT books.* FROM books
|
|
703
|
-
JOIN book_authors ON books.id = book_authors.book_id
|
|
704
|
-
JOIN authors ON book_authors.author_id = authors.id
|
|
705
|
-
WHERE authors.name LIKE '%Neil%'
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
The system handles all the complexity of the double JOIN transparently, making it easy to search across many-to-many relationships without writing custom queries.
|
|
709
|
-
|
|
710
|
-
---
|
|
711
|
-
|
|
712
|
-
[Previous: 2.5 hasMany records (polymorphic)](./GUIDE_2_5_HasMany_Polymorphic.md) | [Back to Guide](./README.md) | [Next: 2.7 Pagination and ordering](./GUIDE_2_7_Pagination_And_Ordering.md)
|