json-rest-api 1.0.22 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -2
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +180 -0
- package/README.md +22 -1
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
- package/docs/API.md +196 -38
- package/docs/COMPARISON.md +2 -2
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +111 -5
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +5 -1
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +3 -1
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +12 -60
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +2 -2
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +5 -1
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +2 -0
- package/docs/GUIDE/GUIDE_X_Autofiltering.md +355 -0
- package/docs/GUIDE/GUIDE_X_Fastify.md +78 -0
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +370 -0
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +159 -0
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +199 -0
- package/docs/GUIDE/index.md +18 -9
- package/docs/QUICKSTART.md +5 -1
- package/docs/index.md +1 -1
- package/index.js +3 -2
- package/lib/enhanced-logger.js +1 -1
- package/package.json +6 -2
- package/plugins/core/bulk-operations-plugin.js +26 -34
- package/plugins/core/connectors/express-plugin.js +97 -190
- package/plugins/core/connectors/fastify-plugin.js +206 -0
- package/plugins/core/connectors/lib/busboy-detector.js +4 -4
- package/plugins/core/connectors/lib/connector-core.js +195 -0
- package/plugins/core/connectors/lib/transport-http-helpers.js +122 -0
- package/plugins/core/connectors/lib/transport-route-schemas.js +92 -0
- package/plugins/core/lib/anyapi/schema-utils.js +43 -4
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +4 -1
- package/plugins/core/lib/dbIntrospection.js +1078 -0
- package/plugins/core/lib/dbTablesOperations.js +1111 -160
- package/plugins/core/lib/querying/knex-cross-table-search.js +0 -7
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -3
- package/plugins/core/lib/querying/knex-process-includes.js +3 -4
- package/plugins/core/lib/querying/knex-query-helpers.js +21 -76
- package/plugins/core/lib/querying/knex-relationship-includes.js +468 -215
- package/plugins/core/lib/querying/query-builder-utils.js +19 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +135 -0
- package/plugins/core/lib/querying/sort-helpers.js +33 -0
- package/plugins/core/lib/querying/storage-adapter-utils.js +51 -0
- package/plugins/core/lib/querying/url-helpers.js +8 -2
- package/plugins/core/lib/querying-writing/compile-schemas.js +20 -5
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -14
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +13 -12
- package/plugins/core/lib/querying-writing/query-field-helpers.js +88 -0
- package/plugins/core/lib/querying-writing/request-contracts.js +590 -0
- package/plugins/core/lib/querying-writing/resource-id-normalization.js +131 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +0 -2
- package/plugins/core/lib/querying-writing/simplified-helpers.js +4 -11
- package/plugins/core/lib/storage/canonical-storage-mapping.js +133 -0
- package/plugins/core/lib/storage/storage-adapter.js +82 -4
- package/plugins/core/lib/storage/storage-mapping.js +274 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -2
- package/plugins/core/rest-api-anyapi-knex-plugin.js +531 -312
- package/plugins/core/rest-api-autofilter-plugin.js +414 -0
- package/plugins/core/rest-api-knex-plugin.js +271 -226
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +10 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +12 -6
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +1 -0
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
- package/plugins/core/rest-api-plugin-methods/common.js +148 -92
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +11 -2
- package/plugins/core/rest-api-plugin-methods/delete.js +6 -1
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
- package/plugins/core/rest-api-plugin-methods/get-related.js +7 -2
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +7 -2
- package/plugins/core/rest-api-plugin-methods/get.js +29 -14
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +10 -3
- package/plugins/core/rest-api-plugin-methods/patch.js +56 -12
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +11 -2
- package/plugins/core/rest-api-plugin-methods/post.js +21 -8
- package/plugins/core/rest-api-plugin-methods/put.js +73 -21
- package/plugins/core/rest-api-plugin-methods/query.js +15 -53
- package/plugins/core/rest-api-plugin-methods/release.js +0 -2
- package/plugins/core/rest-api-plugin.js +6 -0
- package/plugins/core/rest-api-positioning-plugin.js +2 -5
- package/plugins/core/rest-api-query-projections-plugin.js +130 -0
- package/plugins/core/socketio-plugin.js +1 -4
- package/plugins/storage/local-storage.js +1 -1
- package/plugins/storage/s3-storage.js +5 -2
- package/quickTest.js +1 -0
- package/scripts/run-docs.js +80 -84
- package/test-debug.js +1 -1
- package/tests/README.md +7 -0
- package/tests/anyapi-basic.test.js +3 -0
- package/tests/autofilter.test.js +463 -0
- package/tests/custom-id-mysql-returning-fallback.test.js +128 -0
- package/tests/custom-id-simplified-post.test.js +75 -0
- package/tests/custom-idproperty-relationships.test.js +33 -0
- package/tests/db-introspection.test.js +521 -0
- package/tests/db-table-operations.test.js +786 -0
- package/tests/fastify-plugin.test.js +156 -0
- package/tests/field-getters.test.js +1 -2
- package/tests/field-setters.test.js +0 -4
- package/tests/fixtures/api-configs.js +278 -176
- package/tests/helpers/fake-fastify.js +99 -0
- package/tests/http-connectors-parity.test.js +235 -0
- package/tests/id-normalization.test.js +444 -0
- package/tests/logical-id-write-validation.test.js +151 -0
- package/tests/pagination-cursor-multifield.test.js +11 -11
- package/tests/projected-fields.test.js +319 -0
- package/tests/relationships.test.js +3 -3
- package/tests/searchschema-knex-behavior.test.js +187 -0
- package/tests/searchschema-merge.test.js +21 -69
- package/tests/storage-mapping.test.js +259 -0
- package/audit/00-charter.md +0 -103
- package/audit/01-scope-map.md +0 -84
- package/audit/02-coverage-matrix.csv +0 -174
- package/audit/03-invariants.md +0 -123
- package/audit/04-standards-rubric.md +0 -56
- package/audit/05-competitor-rubric.md +0 -77
- package/audit/06-findings.md +0 -160
- package/audit/07-risk-register.csv +0 -10
- package/audit/08-remediation-roadmap.md +0 -177
- package/audit/09-signoff-check.md +0 -23
- package/audit/10-final-synthesis.md +0 -29
- package/audit/evidence/code/all-files-json-rest-api.txt +0 -168
- package/audit/evidence/code/all-files-json-rest-schema.txt +0 -12
- package/audit/evidence/code/boundary-leak-checks.txt +0 -72
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +0 -480
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +0 -532
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +0 -175
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +0 -138
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +0 -222
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +0 -342
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +0 -304
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +0 -188
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +0 -336
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +0 -165
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +0 -265
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +0 -369
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +0 -72
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +0 -139
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +0 -45
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +0 -396
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +0 -162
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +0 -1314
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +0 -488
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +0 -484
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +0 -857
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +0 -565
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +0 -485
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +0 -560
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +0 -167
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +0 -109
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +0 -1064
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +0 -1983
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +0 -328
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +0 -119
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +0 -160
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +0 -300
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +0 -245
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +0 -459
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +0 -237
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +0 -1135
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +0 -314
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +0 -7
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +0 -71
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +0 -102
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +0 -49
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +0 -39
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +0 -23
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +0 -13
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +0 -639
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +0 -117
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +0 -104
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +0 -199
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +0 -353
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +0 -61
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +0 -184
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +0 -55
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +0 -191
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +0 -110
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +0 -168
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +0 -253
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +0 -207
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +0 -12
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +0 -165
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +0 -668
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +0 -621
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +0 -218
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +0 -124
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +0 -269
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +0 -242
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +0 -77
- package/audit/evidence/code/critical-pass1-risk-keywords.txt +0 -238
- package/audit/evidence/code/critical-pass1-summary.csv +0 -67
- package/audit/evidence/code/critical-pass2-summary.csv +0 -67
- package/audit/evidence/code/early-silent-zones-no-test-token.txt +0 -57
- package/audit/evidence/code/error-model-signals.txt +0 -98
- package/audit/evidence/code/git-files-json-rest-api.txt +0 -171
- package/audit/evidence/code/git-files-json-rest-schema.txt +0 -27
- package/audit/evidence/code/hook-flow-signals.txt +0 -282
- package/audit/evidence/code/idproperty-signals.txt +0 -157
- package/audit/evidence/code/import-cycles-non-anyapi.txt +0 -3
- package/audit/evidence/code/import-hotspots-non-anyapi.txt +0 -96
- package/audit/evidence/code/imports-json-rest-api.txt +0 -354
- package/audit/evidence/code/imports-json-rest-schema.txt +0 -15
- package/audit/evidence/code/in-scope-files-json-rest-api.txt +0 -160
- package/audit/evidence/code/in-scope-files-json-rest-schema.txt +0 -13
- package/audit/evidence/code/non-anyapi-core-files.txt +0 -101
- package/audit/evidence/code/permission-signals.txt +0 -193
- package/audit/evidence/code/query-include-signals.txt +0 -687
- package/audit/evidence/code/transaction-signals.txt +0 -28
- package/audit/evidence/code/validation-signals.txt +0 -650
- package/audit/evidence/code/write-path-signals.txt +0 -61
- package/audit/evidence/docs/docs-claims-signals.txt +0 -1075
- package/audit/evidence/docs/schema-docs-claims-signals.txt +0 -179
- package/audit/evidence/external/corpus-freeze.md +0 -21
- package/audit/evidence/external/npm-competitor-metadata.txt +0 -70
- package/audit/evidence/external/npm-download-signals.txt +0 -23
- package/audit/evidence/external/npm-jsonapi-server.txt +0 -8
- package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +0 -38
- package/audit/evidence/external/readme-fortune-signals.txt +0 -26
- package/audit/evidence/external/readme-fortune.md +0 -165
- package/audit/evidence/external/readme-json-api-serializer-signals.txt +0 -80
- package/audit/evidence/external/readme-json-api-serializer.md +0 -690
- package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
- package/audit/evidence/external/readme-jsonapi-serde-server.md +0 -22
- package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +0 -63
- package/audit/evidence/external/readme-jsonapi-serializer.md +0 -315
- package/audit/evidence/external/readme-jsonapi-server-signals.txt +0 -19
- package/audit/evidence/external/readme-jsonapi-server.md +0 -104
- package/audit/evidence/external/readme-nestjs-json-api-signals.txt +0 -4
- package/audit/evidence/external/readme-nestjs-json-api.md +0 -94
- package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +0 -47
- package/audit/evidence/external/readme-yaser-json-api-nestjs.md +0 -447
- package/audit/evidence/external/standard-jsonapi-snippets.txt +0 -84
- package/audit/evidence/external/standard-rfc-snippets.txt +0 -168
- package/audit/evidence/external/standards-sources.txt +0 -6
- package/audit/evidence/runtime/baseline-commits.txt +0 -2
- package/audit/evidence/runtime/db-adapter-assumptions.txt +0 -3
- package/audit/evidence/runtime/environment.txt +0 -4
- package/audit/evidence/runtime/invariant-runtime-mapping.md +0 -38
- package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +0 -1
- package/audit/evidence/runtime/probe-patch-relationship-error.log +0 -76
- package/audit/evidence/runtime/probe-patch-relationship-error.mjs +0 -67
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +0 -1
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +0 -62
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +0 -47
- package/audit/evidence/runtime/test-exitcodes.txt +0 -4
- package/audit/evidence/runtime/test-summary.md +0 -107
- package/audit/evidence/runtime/trace-anchors.txt +0 -61
- package/audit/evidence/tests/access-multitenancy-test-signals.txt +0 -125
- package/audit/evidence/tests/failing-tests-summary.txt +0 -25
- package/audit/evidence/tests/npm-test-json-rest-api.exitcode +0 -1
- package/audit/evidence/tests/npm-test-json-rest-api.log +0 -5885
- package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +0 -1
- package/audit/evidence/tests/npm-test-json-rest-schema.log +0 -356
- package/audit/evidence/tests/query-include-test-signals.txt +0 -948
- package/audit/evidence/tests/relationship-test-signals.txt +0 -223
- package/audit/evidence/tests/skipped-tests.txt +0 -10
- package/audit/evidence/tests/test-suite-list-non-anyapi.txt +0 -30
- package/audit/evidence/tests/test-suite-list.txt +0 -32
- package/audit/subsystems/docs-drift.md +0 -49
- package/audit/subsystems/pass2-cross-review.md +0 -131
- package/audit/subsystems/plugins-access.md +0 -51
- package/audit/subsystems/plugins-bulk.md +0 -50
- package/audit/subsystems/plugins-cors.md +0 -48
- package/audit/subsystems/plugins-file.md +0 -53
- package/audit/subsystems/plugins-multihome.md +0 -50
- package/audit/subsystems/plugins-positioning.md +0 -54
- package/audit/subsystems/plugins-socketio.md +0 -50
- package/audit/subsystems/query-engine.md +0 -61
- package/audit/subsystems/relationships.md +0 -55
- package/audit/subsystems/rest-orchestration.md +0 -66
- package/audit/subsystems/schema-core.md +0 -64
- package/audit/subsystems/storage-knex.md +0 -57
- package/audit/subsystems/tests.md +0 -48
- package/audit/subsystems/transport-express.md +0 -55
- package/audit/traces/trace-read-get.md +0 -22
- package/audit/traces/trace-read-query.md +0 -25
- package/audit/traces/trace-relationship-endpoints.md +0 -31
- package/audit/traces/trace-write-delete.md +0 -17
- package/audit/traces/trace-write-patch.md +0 -26
- package/audit/traces/trace-write-post.md +0 -22
- package/audit/traces/trace-write-put.md +0 -23
- package/docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md +0 -707
- package/docs/GUIDE/GUIDE_X_Multihome.md +0 -666
- package/plugins/core/lib/querying-writing/payload-validators.js +0 -1314
- package/plugins/core/rest-api-access.js +0 -459
- package/plugins/core/rest-api-multihome-plugin.js +0 -314
- package/tests/multihome.test.js +0 -553
- package/tests/multihome.test.js.bak +0 -550
- package/tests/ownership-optout.test.js +0 -76
- package/tests/rest-api-access.test.js +0 -206
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Api } from 'hooked-api'
|
|
2
|
-
import { RestApiPlugin, RestApiKnexPlugin, RestApiAnyapiKnexPlugin } from '../../index.js'
|
|
3
|
-
import { AccessPlugin } from '../../plugins/core/rest-api-access.js'
|
|
2
|
+
import { RestApiPlugin, RestApiKnexPlugin, RestApiAnyapiKnexPlugin, QueryProjectionsPlugin } from '../../index.js'
|
|
4
3
|
import { ExpressPlugin } from '../../plugins/core/connectors/express-plugin.js'
|
|
5
4
|
import express from 'express'
|
|
6
5
|
import { createServer } from 'http'
|
|
@@ -126,7 +125,8 @@ export async function createBasicApi (knex, pluginOptions = {}) {
|
|
|
126
125
|
country_id: { type: 'number', nullable: true, belongsTo: 'countries', as: 'country' }
|
|
127
126
|
},
|
|
128
127
|
relationships: {
|
|
129
|
-
books: { type: 'hasMany', target: 'books', foreignKey: 'publisher_id' }
|
|
128
|
+
books: { type: 'hasMany', target: 'books', foreignKey: 'publisher_id' },
|
|
129
|
+
authors: { type: 'hasMany', target: 'authors', foreignKey: 'publisher_id' }
|
|
130
130
|
},
|
|
131
131
|
tableName: `${tablePrefix}_publishers`
|
|
132
132
|
})
|
|
@@ -137,7 +137,8 @@ export async function createBasicApi (knex, pluginOptions = {}) {
|
|
|
137
137
|
await api.addResource('authors', {
|
|
138
138
|
schema: {
|
|
139
139
|
id: { type: 'id' },
|
|
140
|
-
name: { type: 'string', required: true, max: 200 }
|
|
140
|
+
name: { type: 'string', required: true, max: 200 },
|
|
141
|
+
publisher_id: { type: 'number', nullable: true, belongsTo: 'publishers', as: 'publisher' }
|
|
141
142
|
},
|
|
142
143
|
relationships: {
|
|
143
144
|
books: { type: 'manyToMany', through: 'book_authors', foreignKey: 'author_id', otherKey: 'book_id' }
|
|
@@ -197,9 +198,12 @@ export async function createBasicApi (knex, pluginOptions = {}) {
|
|
|
197
198
|
}
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Creates a small API focused on resource ID normalization behavior.
|
|
203
|
+
*/
|
|
204
|
+
export async function createIdNormalizationApi (knex, pluginOptions = {}) {
|
|
205
|
+
const apiName = pluginOptions.apiName || 'id-normalization-test-api'
|
|
206
|
+
const tablePrefix = pluginOptions.tablePrefix || 'id_norm'
|
|
203
207
|
if (storageMode.isAnyApi()) {
|
|
204
208
|
storageMode.clearRegistry()
|
|
205
209
|
}
|
|
@@ -230,71 +234,94 @@ export async function createAccessControlApi (knex, pluginOptions = {}) {
|
|
|
230
234
|
put: 'no',
|
|
231
235
|
patch: 'minimal'
|
|
232
236
|
},
|
|
233
|
-
|
|
237
|
+
...(pluginOptions['rest-api'] || {})
|
|
234
238
|
})
|
|
235
|
-
await useStoragePlugin(api, knex, { tenantId })
|
|
236
|
-
await resetAnyApiTables(knex)
|
|
237
239
|
|
|
238
240
|
try {
|
|
239
|
-
await
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
241
|
+
await withTenantContext(tenantId, async () => {
|
|
242
|
+
await useStoragePlugin(api, knex, { tenantId })
|
|
243
|
+
await resetAnyApiTables(knex)
|
|
244
|
+
|
|
245
|
+
await api.addResource('countries', {
|
|
246
|
+
schema: {
|
|
247
|
+
id: { type: 'string', required: true },
|
|
248
|
+
name: { type: 'string', required: true, max: 100 }
|
|
249
|
+
},
|
|
250
|
+
tableName: `${tablePrefix}_countries`,
|
|
251
|
+
...(pluginOptions.countryResourceOptions || {})
|
|
252
|
+
})
|
|
253
|
+
await knex.schema.dropTableIfExists(`${tablePrefix}_countries`)
|
|
254
|
+
await knex.schema.createTable(`${tablePrefix}_countries`, (table) => {
|
|
255
|
+
table.string('id').primary()
|
|
256
|
+
table.string('name').notNullable()
|
|
257
|
+
})
|
|
258
|
+
mapTable(`${tablePrefix}_countries`, 'countries')
|
|
259
|
+
|
|
260
|
+
await api.addResource('publishers', {
|
|
261
|
+
schema: {
|
|
262
|
+
id: { type: 'string', required: true },
|
|
263
|
+
name: { type: 'string', required: true, max: 100 },
|
|
264
|
+
country_id: { type: 'string', nullable: true, belongsTo: 'countries', as: 'country' }
|
|
265
|
+
},
|
|
266
|
+
relationships: {
|
|
267
|
+
tags: { type: 'manyToMany', through: 'publisher_tags', foreignKey: 'publisher_id', otherKey: 'tag_id' }
|
|
268
|
+
},
|
|
269
|
+
tableName: `${tablePrefix}_publishers`,
|
|
270
|
+
...(pluginOptions.publisherResourceOptions || {})
|
|
271
|
+
})
|
|
272
|
+
await knex.schema.dropTableIfExists(`${tablePrefix}_publishers`)
|
|
273
|
+
await knex.schema.createTable(`${tablePrefix}_publishers`, (table) => {
|
|
274
|
+
table.string('id').primary()
|
|
275
|
+
table.string('name').notNullable()
|
|
276
|
+
table.string('country_id').nullable()
|
|
277
|
+
})
|
|
278
|
+
mapTable(`${tablePrefix}_publishers`, 'publishers')
|
|
279
|
+
|
|
280
|
+
await api.addResource('tags', {
|
|
281
|
+
schema: {
|
|
282
|
+
id: { type: 'string', required: true },
|
|
283
|
+
name: { type: 'string', required: true, max: 100 }
|
|
284
|
+
},
|
|
285
|
+
tableName: `${tablePrefix}_tags`,
|
|
286
|
+
...(pluginOptions.tagResourceOptions || {})
|
|
287
|
+
})
|
|
288
|
+
await knex.schema.dropTableIfExists(`${tablePrefix}_tags`)
|
|
289
|
+
await knex.schema.createTable(`${tablePrefix}_tags`, (table) => {
|
|
290
|
+
table.string('id').primary()
|
|
291
|
+
table.string('name').notNullable()
|
|
292
|
+
})
|
|
293
|
+
mapTable(`${tablePrefix}_tags`, 'tags')
|
|
294
|
+
|
|
295
|
+
await api.addResource('publisher_tags', {
|
|
296
|
+
schema: {
|
|
297
|
+
id: { type: 'id' },
|
|
298
|
+
publisher_id: { type: 'string', required: true, belongsTo: 'publishers', as: 'publisher' },
|
|
299
|
+
tag_id: { type: 'string', required: true, belongsTo: 'tags', as: 'tag' }
|
|
300
|
+
},
|
|
301
|
+
tableName: `${tablePrefix}_publisher_tags`
|
|
302
|
+
})
|
|
303
|
+
await knex.schema.dropTableIfExists(`${tablePrefix}_publisher_tags`)
|
|
304
|
+
await knex.schema.createTable(`${tablePrefix}_publisher_tags`, (table) => {
|
|
305
|
+
table.increments('id').primary()
|
|
306
|
+
table.string('publisher_id').notNullable()
|
|
307
|
+
table.string('tag_id').notNullable()
|
|
308
|
+
})
|
|
309
|
+
mapTable(`${tablePrefix}_publisher_tags`, 'publisher_tags')
|
|
310
|
+
if (storageMode.isAnyApi()) {
|
|
311
|
+
const descriptorTenant = api.anyapi?.tenantId || tenantId
|
|
312
|
+
const publishersDescriptor = await api.anyapi.registry.getDescriptor(descriptorTenant, 'publishers')
|
|
313
|
+
const tagsDescriptor = await api.anyapi.registry.getDescriptor(descriptorTenant, 'tags')
|
|
314
|
+
const relationshipKey = publishersDescriptor?.manyToMany?.tags?.relationship
|
|
315
|
+
const inverseRelationshipKey = tagsDescriptor?.manyToMany?.publishers?.relationship
|
|
316
|
+
storageMode.registerLink(
|
|
317
|
+
`${tablePrefix}_publisher_tags`,
|
|
318
|
+
'publishers',
|
|
319
|
+
'tags',
|
|
320
|
+
relationshipKey,
|
|
321
|
+
inverseRelationshipKey
|
|
322
|
+
)
|
|
323
|
+
}
|
|
295
324
|
})
|
|
296
|
-
await api.resources.notes.createKnexTable()
|
|
297
|
-
mapTable(`${tablePrefix}_notes`, 'notes')
|
|
298
325
|
|
|
299
326
|
return api
|
|
300
327
|
} finally {
|
|
@@ -1071,6 +1098,92 @@ export async function createFieldGettersApi (knex, pluginOptions = {}) {
|
|
|
1071
1098
|
return api
|
|
1072
1099
|
}
|
|
1073
1100
|
|
|
1101
|
+
export async function createProjectedFieldsApi (knex, pluginOptions = {}) {
|
|
1102
|
+
const api = new Api({
|
|
1103
|
+
name: 'projected-fields-test-api',
|
|
1104
|
+
log: { level: process.env.LOG_LEVEL || 'info' }
|
|
1105
|
+
})
|
|
1106
|
+
|
|
1107
|
+
const tenantId = storageMode.isAnyApi() ? 'projected_fields_tenant' : storageMode.defaultTenant
|
|
1108
|
+
const previousTenant = storageMode.currentTenant
|
|
1109
|
+
if (storageMode.isAnyApi()) {
|
|
1110
|
+
storageMode.setCurrentTenant(tenantId)
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
await api.use(RestApiPlugin, {
|
|
1114
|
+
simplifiedApi: false,
|
|
1115
|
+
simplifiedTransport: false,
|
|
1116
|
+
returnRecordApi: {
|
|
1117
|
+
post: true,
|
|
1118
|
+
put: false,
|
|
1119
|
+
patch: false
|
|
1120
|
+
},
|
|
1121
|
+
returnRecordTransport: {
|
|
1122
|
+
post: 'full',
|
|
1123
|
+
put: 'no',
|
|
1124
|
+
patch: 'minimal'
|
|
1125
|
+
},
|
|
1126
|
+
sortableFields: ['id', 'first_name', 'last_name'],
|
|
1127
|
+
...pluginOptions['rest-api']
|
|
1128
|
+
})
|
|
1129
|
+
await api.use(QueryProjectionsPlugin)
|
|
1130
|
+
|
|
1131
|
+
await useStoragePlugin(api, knex, { tenantId })
|
|
1132
|
+
await resetAnyApiTables(knex)
|
|
1133
|
+
|
|
1134
|
+
await api.addResource('authors', {
|
|
1135
|
+
schema: {
|
|
1136
|
+
id: { type: 'id' },
|
|
1137
|
+
first_name: { type: 'string', required: true, max: 100 },
|
|
1138
|
+
last_name: { type: 'string', required: true, max: 100 }
|
|
1139
|
+
},
|
|
1140
|
+
queryFields: {
|
|
1141
|
+
full_name: {
|
|
1142
|
+
type: 'string',
|
|
1143
|
+
sortable: true,
|
|
1144
|
+
select: ({ knex, column }) => knex.raw(
|
|
1145
|
+
"trim(coalesce(??, '') || ' ' || coalesce(??, ''))",
|
|
1146
|
+
[column('first_name'), column('last_name')]
|
|
1147
|
+
)
|
|
1148
|
+
},
|
|
1149
|
+
sort_name: {
|
|
1150
|
+
type: 'string',
|
|
1151
|
+
sortable: true,
|
|
1152
|
+
normallyHidden: true,
|
|
1153
|
+
select: ({ knex, column }) => knex.raw(
|
|
1154
|
+
"trim(coalesce(??, '') || ' ' || coalesce(??, ''))",
|
|
1155
|
+
[column('first_name'), column('last_name')]
|
|
1156
|
+
)
|
|
1157
|
+
}
|
|
1158
|
+
},
|
|
1159
|
+
relationships: {
|
|
1160
|
+
books: { type: 'hasMany', target: 'books', foreignKey: 'author_id' }
|
|
1161
|
+
},
|
|
1162
|
+
sortableFields: ['id', 'first_name', 'last_name'],
|
|
1163
|
+
defaultSort: ['full_name'],
|
|
1164
|
+
tableName: 'projected_authors'
|
|
1165
|
+
})
|
|
1166
|
+
await api.resources.authors.createKnexTable()
|
|
1167
|
+
mapTable('projected_authors', 'authors')
|
|
1168
|
+
|
|
1169
|
+
await api.addResource('books', {
|
|
1170
|
+
schema: {
|
|
1171
|
+
id: { type: 'id' },
|
|
1172
|
+
title: { type: 'string', required: true, max: 200 },
|
|
1173
|
+
author_id: { type: 'id', required: true, belongsTo: 'authors', as: 'author' }
|
|
1174
|
+
},
|
|
1175
|
+
tableName: 'projected_books'
|
|
1176
|
+
})
|
|
1177
|
+
await api.resources.books.createKnexTable()
|
|
1178
|
+
mapTable('projected_books', 'books')
|
|
1179
|
+
|
|
1180
|
+
if (storageMode.isAnyApi()) {
|
|
1181
|
+
storageMode.setCurrentTenant(previousTenant)
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
return api
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1074
1187
|
/**
|
|
1075
1188
|
* Creates an API with field setters for testing
|
|
1076
1189
|
*/
|
|
@@ -1288,14 +1401,14 @@ export async function createFieldSettersApi (knex, pluginOptions = {}) {
|
|
|
1288
1401
|
return api
|
|
1289
1402
|
}
|
|
1290
1403
|
|
|
1291
|
-
export async function
|
|
1292
|
-
const {
|
|
1404
|
+
export async function createAutoFilterApi (knex, pluginOptions = {}) {
|
|
1405
|
+
const { AutoFilterPlugin } = await import('../../plugins/core/rest-api-autofilter-plugin.js')
|
|
1293
1406
|
|
|
1294
1407
|
const api = new Api({
|
|
1295
|
-
name: '
|
|
1408
|
+
name: 'autofilter-test-api',
|
|
1296
1409
|
})
|
|
1297
1410
|
|
|
1298
|
-
const tenantId = storageMode.isAnyApi() ? '
|
|
1411
|
+
const tenantId = storageMode.isAnyApi() ? 'autofilter_tenant' : storageMode.defaultTenant
|
|
1299
1412
|
const previousTenant = storageMode.currentTenant
|
|
1300
1413
|
if (storageMode.isAnyApi()) {
|
|
1301
1414
|
storageMode.setCurrentTenant(tenantId)
|
|
@@ -1314,7 +1427,7 @@ export async function createMultiHomeApi (knex, pluginOptions = {}) {
|
|
|
1314
1427
|
put: 'no',
|
|
1315
1428
|
patch: 'minimal'
|
|
1316
1429
|
},
|
|
1317
|
-
sortableFields: ['id', 'title', 'name', '
|
|
1430
|
+
sortableFields: ['id', 'title', 'name', 'workspace_id', 'user_id']
|
|
1318
1431
|
})
|
|
1319
1432
|
|
|
1320
1433
|
await useStoragePlugin(api, knex, { tenantId })
|
|
@@ -1325,34 +1438,77 @@ export async function createMultiHomeApi (knex, pluginOptions = {}) {
|
|
|
1325
1438
|
await api.use(ExpressPlugin, pluginOptions.express || {})
|
|
1326
1439
|
}
|
|
1327
1440
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1441
|
+
const autofilterOptions = pluginOptions.autofilter || {}
|
|
1442
|
+
const workspaceField = pluginOptions.workspaceField || 'workspace_id'
|
|
1443
|
+
const userField = pluginOptions.userField || 'user_id'
|
|
1444
|
+
|
|
1445
|
+
await api.use(AutoFilterPlugin, {
|
|
1446
|
+
...autofilterOptions,
|
|
1447
|
+
resolvers: {
|
|
1448
|
+
workspace: ({ context }) => context.scopeValues?.workspaceId,
|
|
1449
|
+
user: ({ context }) => context.scopeValues?.userId,
|
|
1450
|
+
currentProject: ({ context }) => context.scopeValues?.projectId ?? null,
|
|
1451
|
+
...(autofilterOptions.resolvers || {})
|
|
1452
|
+
},
|
|
1453
|
+
presets: {
|
|
1454
|
+
public: { filters: [] },
|
|
1455
|
+
workspace: {
|
|
1456
|
+
filters: [{ field: workspaceField, resolver: 'workspace' }]
|
|
1457
|
+
},
|
|
1458
|
+
user: {
|
|
1459
|
+
filters: [{ field: userField, resolver: 'user' }]
|
|
1460
|
+
},
|
|
1461
|
+
workspace_user: {
|
|
1462
|
+
filters: [
|
|
1463
|
+
{ field: workspaceField, resolver: 'workspace' },
|
|
1464
|
+
{ field: userField, resolver: 'user' }
|
|
1465
|
+
]
|
|
1466
|
+
},
|
|
1467
|
+
...(autofilterOptions.presets || {})
|
|
1468
|
+
}
|
|
1469
|
+
})
|
|
1470
|
+
|
|
1471
|
+
await api.addResource('workspace_reports', {
|
|
1472
|
+
schema: {
|
|
1473
|
+
id: { type: 'id' },
|
|
1474
|
+
title: { type: 'string', required: true, max: 200 },
|
|
1475
|
+
workspace_id: { type: 'string', required: true }
|
|
1476
|
+
},
|
|
1477
|
+
autofilter: 'workspace',
|
|
1478
|
+
tableName: 'autofilter_workspace_reports'
|
|
1338
1479
|
})
|
|
1480
|
+
await api.resources.workspace_reports.createKnexTable()
|
|
1481
|
+
mapTable('autofilter_workspace_reports', 'workspace_reports')
|
|
1482
|
+
|
|
1483
|
+
await api.addResource('user_notes', {
|
|
1484
|
+
schema: {
|
|
1485
|
+
id: { type: 'id' },
|
|
1486
|
+
body: { type: 'string', required: true, max: 500 },
|
|
1487
|
+
user_id: { type: 'number', required: true }
|
|
1488
|
+
},
|
|
1489
|
+
autofilter: 'user',
|
|
1490
|
+
tableName: 'autofilter_user_notes'
|
|
1491
|
+
})
|
|
1492
|
+
await api.resources.user_notes.createKnexTable()
|
|
1493
|
+
mapTable('autofilter_user_notes', 'user_notes')
|
|
1339
1494
|
|
|
1340
|
-
// Tenant-specific resources
|
|
1341
1495
|
await api.addResource('projects', {
|
|
1342
1496
|
schema: {
|
|
1343
1497
|
id: { type: 'id' },
|
|
1344
1498
|
name: { type: 'string', required: true, max: 200 },
|
|
1345
1499
|
description: { type: 'string', max: 1000 },
|
|
1346
1500
|
status: { type: 'string', defaultTo: 'active' },
|
|
1347
|
-
|
|
1501
|
+
workspace_id: { type: 'string', required: true },
|
|
1502
|
+
user_id: { type: 'number', required: true }
|
|
1348
1503
|
},
|
|
1349
1504
|
relationships: {
|
|
1350
1505
|
tasks: { type: 'hasMany', target: 'tasks', foreignKey: 'project_id' }
|
|
1351
1506
|
},
|
|
1352
|
-
|
|
1507
|
+
autofilter: 'workspace_user',
|
|
1508
|
+
tableName: 'autofilter_projects'
|
|
1353
1509
|
})
|
|
1354
1510
|
await api.resources.projects.createKnexTable()
|
|
1355
|
-
mapTable('
|
|
1511
|
+
mapTable('autofilter_projects', 'projects')
|
|
1356
1512
|
|
|
1357
1513
|
await api.addResource('tasks', {
|
|
1358
1514
|
schema: {
|
|
@@ -1360,37 +1516,40 @@ export async function createMultiHomeApi (knex, pluginOptions = {}) {
|
|
|
1360
1516
|
title: { type: 'string', required: true, max: 200 },
|
|
1361
1517
|
completed: { type: 'boolean', defaultTo: false },
|
|
1362
1518
|
project_id: { type: 'number', belongsTo: 'projects', as: 'project' },
|
|
1363
|
-
|
|
1519
|
+
workspace_id: { type: 'string', required: true },
|
|
1520
|
+
user_id: { type: 'number', required: true }
|
|
1364
1521
|
},
|
|
1365
|
-
|
|
1522
|
+
autofilter: 'workspace_user',
|
|
1523
|
+
tableName: 'autofilter_tasks'
|
|
1366
1524
|
})
|
|
1367
1525
|
await api.resources.tasks.createKnexTable()
|
|
1368
|
-
mapTable('
|
|
1526
|
+
mapTable('autofilter_tasks', 'tasks')
|
|
1369
1527
|
|
|
1370
|
-
await api.addResource('
|
|
1528
|
+
await api.addResource('optional_tasks', {
|
|
1371
1529
|
schema: {
|
|
1372
1530
|
id: { type: 'id' },
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1531
|
+
title: { type: 'string', required: true, max: 200 },
|
|
1532
|
+
project_id: { type: 'number', belongsTo: 'projects', as: 'project', nullable: true }
|
|
1533
|
+
},
|
|
1534
|
+
autofilter: {
|
|
1535
|
+
filters: [{ field: 'project_id', resolver: 'currentProject' }]
|
|
1377
1536
|
},
|
|
1378
|
-
tableName: '
|
|
1537
|
+
tableName: 'autofilter_optional_tasks'
|
|
1379
1538
|
})
|
|
1380
|
-
await api.resources.
|
|
1381
|
-
mapTable('
|
|
1539
|
+
await api.resources.optional_tasks.createKnexTable()
|
|
1540
|
+
mapTable('autofilter_optional_tasks', 'optional_tasks')
|
|
1382
1541
|
|
|
1383
|
-
// Global resource (excluded from multihome)
|
|
1384
1542
|
await api.addResource('system_settings', {
|
|
1385
1543
|
schema: {
|
|
1386
1544
|
id: { type: 'id' },
|
|
1387
1545
|
key: { type: 'string', required: true, unique: true },
|
|
1388
1546
|
value: { type: 'string', required: true }
|
|
1389
1547
|
},
|
|
1390
|
-
|
|
1548
|
+
autofilter: 'public',
|
|
1549
|
+
tableName: 'autofilter_system_settings'
|
|
1391
1550
|
})
|
|
1392
1551
|
await api.resources.system_settings.createKnexTable()
|
|
1393
|
-
mapTable('
|
|
1552
|
+
mapTable('autofilter_system_settings', 'system_settings')
|
|
1394
1553
|
|
|
1395
1554
|
if (storageMode.isAnyApi()) {
|
|
1396
1555
|
storageMode.setCurrentTenant(previousTenant)
|
|
@@ -1786,7 +1945,9 @@ export async function createVirtualFieldsApi (knex, pluginOptions = {}) {
|
|
|
1786
1945
|
}
|
|
1787
1946
|
|
|
1788
1947
|
/**
|
|
1789
|
-
* Creates an API configuration for testing searchSchema merge behavior
|
|
1948
|
+
* Creates an API configuration for testing searchSchema merge behavior.
|
|
1949
|
+
* Shared suites assert merge/validation behavior across storage backends;
|
|
1950
|
+
* backend-specific execution cases live in storage-specific tests.
|
|
1790
1951
|
*/
|
|
1791
1952
|
export async function createSearchSchemaMergeApi (knex, pluginOptions = {}) {
|
|
1792
1953
|
const api = new Api({
|
|
@@ -1825,12 +1986,27 @@ export async function createSearchSchemaMergeApi (knex, pluginOptions = {}) {
|
|
|
1825
1986
|
type: 'array',
|
|
1826
1987
|
filterOperator: 'between'
|
|
1827
1988
|
},
|
|
1989
|
+
// Arbitrary public filter name that searches across multiple fields.
|
|
1990
|
+
// The key `term` is part of the API contract even though there is no `term` column.
|
|
1991
|
+
term: {
|
|
1992
|
+
type: 'string',
|
|
1993
|
+
oneOf: ['name', 'description'],
|
|
1994
|
+
filterOperator: 'like'
|
|
1995
|
+
},
|
|
1828
1996
|
// This is a virtual field
|
|
1829
1997
|
category_name: {
|
|
1830
1998
|
type: 'string',
|
|
1831
1999
|
actualField: 'category.name',
|
|
1832
2000
|
filterOperator: 'like'
|
|
1833
2001
|
},
|
|
2002
|
+
// Arbitrary public filter name with fully custom server-side meaning.
|
|
2003
|
+
// The Knex query layer decides what `availability` means.
|
|
2004
|
+
availability: {
|
|
2005
|
+
type: 'boolean',
|
|
2006
|
+
applyFilter: (query, value) => {
|
|
2007
|
+
query.where('status', value ? 'active' : 'inactive')
|
|
2008
|
+
}
|
|
2009
|
+
},
|
|
1834
2010
|
// This is an explicit field not marked with search:true
|
|
1835
2011
|
// 'in' operator requires array type for validation
|
|
1836
2012
|
status: {
|
|
@@ -1872,77 +2048,3 @@ export async function createSearchSchemaMergeApi (knex, pluginOptions = {}) {
|
|
|
1872
2048
|
|
|
1873
2049
|
return api
|
|
1874
2050
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
/**
|
|
1878
|
-
* Creates an API with resources that OPT OUT of ownership
|
|
1879
|
-
* - public_items_ownerfield: uses ownerField: false
|
|
1880
|
-
* - public_items_ownership: uses ownership: false
|
|
1881
|
-
* Both tables intentionally DO NOT have a user_id column.
|
|
1882
|
-
*/
|
|
1883
|
-
export async function createOwnershipOptOutApi (knex, pluginOptions = {}) {
|
|
1884
|
-
const apiName = pluginOptions.apiName || 'ownership-optout-api'
|
|
1885
|
-
const tablePrefix = pluginOptions.tablePrefix || 'ownopt'
|
|
1886
|
-
if (storageMode.isAnyApi()) {
|
|
1887
|
-
storageMode.clearRegistry()
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
const api = new Api({
|
|
1891
|
-
name: apiName,
|
|
1892
|
-
log: { level: process.env.LOG_LEVEL || 'info' }
|
|
1893
|
-
})
|
|
1894
|
-
|
|
1895
|
-
const previousTenant = storageMode.currentTenant
|
|
1896
|
-
const tenantId = storageMode.isAnyApi()
|
|
1897
|
-
? (pluginOptions.tenantId || `${tablePrefix}_tenant`)
|
|
1898
|
-
: storageMode.defaultTenant
|
|
1899
|
-
if (storageMode.isAnyApi()) {
|
|
1900
|
-
storageMode.setCurrentTenant(tenantId)
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
await api.use(RestApiPlugin, {
|
|
1904
|
-
simplifiedApi: false,
|
|
1905
|
-
simplifiedTransport: false,
|
|
1906
|
-
returnRecordApi: { post: true, put: false, patch: false },
|
|
1907
|
-
returnRecordTransport: { post: 'full', put: 'no', patch: 'minimal' },
|
|
1908
|
-
sortableFields: ['id', 'name']
|
|
1909
|
-
})
|
|
1910
|
-
await useStoragePlugin(api, knex, { tenantId })
|
|
1911
|
-
await resetAnyApiTables(knex)
|
|
1912
|
-
|
|
1913
|
-
try {
|
|
1914
|
-
// Access plugin (defaults: ownership enabled, filterByOwner true)
|
|
1915
|
-
await api.use(AccessPlugin, pluginOptions.access || {})
|
|
1916
|
-
|
|
1917
|
-
// Resource A: disable via ownerField:false
|
|
1918
|
-
await api.addResource('public_items_ownerfield', {
|
|
1919
|
-
schema: {
|
|
1920
|
-
id: { type: 'id' },
|
|
1921
|
-
name: { type: 'string', required: true }
|
|
1922
|
-
},
|
|
1923
|
-
// Important: no user_id column in schema; ownerField disables ownership logic
|
|
1924
|
-
ownerField: false,
|
|
1925
|
-
tableName: `${tablePrefix}_public_items_of`
|
|
1926
|
-
})
|
|
1927
|
-
await api.resources.public_items_ownerfield.createKnexTable()
|
|
1928
|
-
mapTable(`${tablePrefix}_public_items_of`, 'public_items_ownerfield')
|
|
1929
|
-
|
|
1930
|
-
// Resource B: disable via ownership:false
|
|
1931
|
-
await api.addResource('public_items_ownership', {
|
|
1932
|
-
schema: {
|
|
1933
|
-
id: { type: 'id' },
|
|
1934
|
-
name: { type: 'string', required: true }
|
|
1935
|
-
},
|
|
1936
|
-
ownership: false,
|
|
1937
|
-
tableName: `${tablePrefix}_public_items_own`
|
|
1938
|
-
})
|
|
1939
|
-
await api.resources.public_items_ownership.createKnexTable()
|
|
1940
|
-
mapTable(`${tablePrefix}_public_items_own`, 'public_items_ownership')
|
|
1941
|
-
|
|
1942
|
-
return api
|
|
1943
|
-
} finally {
|
|
1944
|
-
if (storageMode.isAnyApi()) {
|
|
1945
|
-
storageMode.setCurrentTenant(previousTenant)
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export class FakeFastifyApp {
|
|
2
|
+
constructor () {
|
|
3
|
+
this.routes = []
|
|
4
|
+
this.parsers = []
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
route (definition) {
|
|
8
|
+
this.routes.push(definition)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
addContentTypeParser (contentType, options, parser) {
|
|
12
|
+
this.parsers.push({ contentType, options, parser })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
hasContentTypeParser (contentType) {
|
|
16
|
+
return this.parsers.some((entry) => entry.contentType === contentType)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class FakeReply {
|
|
21
|
+
constructor () {
|
|
22
|
+
this.statusCode = null
|
|
23
|
+
this.contentType = null
|
|
24
|
+
this.headers = {}
|
|
25
|
+
this.payload = undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
code (statusCode) {
|
|
29
|
+
this.statusCode = statusCode
|
|
30
|
+
return this
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type (contentType) {
|
|
34
|
+
this.contentType = contentType
|
|
35
|
+
return this
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
header (name, value) {
|
|
39
|
+
this.headers[name] = value
|
|
40
|
+
return this
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
send (payload) {
|
|
44
|
+
this.payload = payload
|
|
45
|
+
return this
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function findFastifyRoute (app, method, url) {
|
|
50
|
+
return app.routes.find((route) => route.method === method && route.url === url)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function invokeFastifyRoute (
|
|
54
|
+
app,
|
|
55
|
+
{
|
|
56
|
+
method,
|
|
57
|
+
routeUrl,
|
|
58
|
+
requestUrl = routeUrl,
|
|
59
|
+
headers = {},
|
|
60
|
+
body,
|
|
61
|
+
params = {},
|
|
62
|
+
query = {}
|
|
63
|
+
}
|
|
64
|
+
) {
|
|
65
|
+
const route = findFastifyRoute(app, method, routeUrl)
|
|
66
|
+
if (!route) {
|
|
67
|
+
throw new Error(`Fastify route not found: ${method} ${routeUrl}`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const reply = new FakeReply()
|
|
71
|
+
const request = {
|
|
72
|
+
method,
|
|
73
|
+
url: requestUrl,
|
|
74
|
+
raw: { url: requestUrl },
|
|
75
|
+
headers,
|
|
76
|
+
body,
|
|
77
|
+
params,
|
|
78
|
+
query
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (typeof route.preValidation === 'function') {
|
|
82
|
+
await route.preValidation(request, reply)
|
|
83
|
+
if (reply.statusCode !== null || reply.payload !== undefined) {
|
|
84
|
+
return { route, request, reply }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await route.handler(request, reply)
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (typeof route.errorHandler === 'function') {
|
|
92
|
+
await route.errorHandler(error, request, reply)
|
|
93
|
+
} else {
|
|
94
|
+
throw error
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { route, request, reply }
|
|
99
|
+
}
|