├── .devcontainer └── devcontainer.json ├── .dockerignore ├── .editorconfig ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── feature-request.md │ └── support-request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── release.yml └── workflows │ ├── cache-cleanup.yml │ ├── checks.yml │ ├── codeql.yaml │ ├── dependency-review.yaml │ ├── main.yml │ ├── perf-test.yml │ ├── release-docker.yml │ ├── tag.yml │ └── tests.yml ├── .gitignore ├── .nvmrc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── bench ├── dc-k6.yml ├── definitions │ ├── collections │ │ ├── customers.js │ │ ├── items.js │ │ └── registered-customers.js │ └── views │ │ └── registered-customers.js ├── docker-compose.yml ├── queryParser.bench.js ├── scripts │ ├── bulk-test.js │ ├── load-test.js │ ├── runner.js │ ├── smoke-test.js │ ├── spike-test.js │ ├── stress-test-on-collection.js │ ├── stress-test-on-view.js │ └── utils.js └── utils │ ├── generate-customer-data.js │ └── healthcheck.js ├── default.env ├── docs ├── 10_Overview_and_Usage.md ├── 20_Configuration.md ├── 30_Encryption_configuration.md ├── 40_Performance_Overview.md ├── 50_Writable_Views.md ├── 60_Usage_Best_Practices.md ├── guides │ ├── 10_Migration-Guide-v7.md │ └── _category_.yml └── img │ ├── crud-api-portal.png │ └── position-index.png ├── envSchema.js ├── eslint.config.mjs ├── index.js ├── lib ├── AdditionalCaster.js ├── BadRequestError.js ├── BatchWritableStream.js ├── CrudService.js ├── CrudService.utils.js ├── JSONPath.utils.js ├── JSONSchemaGenerator.js ├── JoinService.js ├── QueryParser.js ├── QueryParser.utils.js ├── acceptHeaderParser.js ├── compilers.js ├── consts.js ├── createIndexes.js ├── gcpKeyStripper.js ├── generatePathFieldsForRawSchema.js ├── generatePathFromJsonSchema.js ├── helpersRoutes.js ├── hooks.js ├── httpInterface.js ├── joinPlugin.js ├── loadModels.js ├── mergeViewsInCollections.js ├── mimeTypeTransform.js ├── model.jsonschema.js ├── mongo │ ├── mongo-crypt-factory.js │ ├── mongo-data-keygen.js │ ├── mongo-keyring-factory.js │ ├── mongo-plugin.js │ └── mongo-schemaMap-generator.js ├── pkFactories.js ├── projectionUtils.js ├── resolveMongoQuery.js ├── schemaGetters.js ├── transformers │ ├── csv.js │ ├── excel.js │ ├── json.js │ ├── ndjson.js │ └── utils.js └── validatorGetters.js ├── package-lock.json ├── package.json ├── scripts └── update-changelog.js ├── tap-snapshots └── tests │ ├── getSchemas.test.js.test.cjs │ ├── httpInterface.getSchema.test.js.test.cjs │ └── transformSchemaForSwagger.test.js.test.cjs └── tests ├── BatchWritableStream.test.js ├── CrudService.special.test.js ├── CrudService.utils.test.js ├── JSONSchemaGenerator.test.js ├── JoinService.test.js ├── acceptHeaderParser.test.js ├── additionalCaster.test.js ├── aggregate.test.js ├── changeStateById.test.js ├── changeStateMany.test.js ├── collectionDefinitions ├── address_statistics.js ├── addresses.js ├── animals.js ├── books-internal.js ├── books.js ├── books_encrypted.js ├── canines.js ├── cars.js ├── felines.js ├── films.js ├── items.js ├── orders-details.js ├── orders-items.js ├── orders.js ├── people.js ├── projects.js ├── riders.js ├── stations.js ├── store-open.js └── store.js ├── compilers.test.js ├── count.test.js ├── createConnection.test.js ├── createIndexes.test.js ├── deleteAll.test.js ├── deleteById.test.js ├── emptyCollectionDefinitions └── .gitkeep ├── emptyViewsDefinitions └── .gitkeep ├── envSchema.test.js ├── expectedSchemas ├── booksBulkSchema.js ├── booksChangeStateManySchema.js ├── booksChangeStateSchema.js ├── booksCountSchema.js ├── booksDeleteListSchema.js ├── booksDeleteSchema.js ├── booksExportSchema.js ├── booksGetItemSchema.js ├── booksGetListLookupSchema.js ├── booksGetListSchema.js ├── booksNewBulkSchema.js ├── booksNewChangeStateManySchema.js ├── booksNewChangeStateSchema.js ├── booksNewCountSchema.js ├── booksNewDeleteListSchema.js ├── booksNewDeleteSchema.js ├── booksNewExportSchema.js ├── booksNewGetItemSchema.js ├── booksNewGetListLookupSchema.js ├── booksNewGetListSchema.js ├── booksNewPatchBulkSchema.js ├── booksNewPatchManySchema.js ├── booksNewPatchSchema.js ├── booksNewPostSchema.js ├── booksNewUpsertOneSchema.js ├── booksPatchBulkSchema.js ├── booksPatchManySchema.js ├── booksPatchSchema.js ├── booksPostSchema.js ├── booksUpsertOneSchema.js ├── carsBulkSchema.js ├── carsChangeStateManySchema.js ├── carsChangeStateSchema.js ├── carsCountSchema.js ├── carsDeleteListSchema.js ├── carsDeleteSchema.js ├── carsExportSchema.js ├── carsGetItemSchema.js ├── carsGetListLookupSchema.js ├── carsGetListSchema.js ├── carsNewBulkSchema.js ├── carsNewChangeStateManySchema.js ├── carsNewChangeStateSchema.js ├── carsNewCountSchema.js ├── carsNewDeleteListSchema.js ├── carsNewDeleteSchema.js ├── carsNewExportSchema.js ├── carsNewGetItemSchema.js ├── carsNewGetListLookupSchema.js ├── carsNewGetListSchema.js ├── carsNewPatchBulkSchema.js ├── carsNewPatchManySchema.js ├── carsNewPatchSchema.js ├── carsNewPostSchema.js ├── carsNewUpsertOneSchema.js ├── carsPatchBulkSchema.js ├── carsPatchManySchema.js ├── carsPatchSchema.js ├── carsPostSchema.js ├── carsUpsertOneSchema.js ├── stationsBulkSchema.js ├── stationsChangeStateManySchema.js ├── stationsChangeStateSchema.js ├── stationsCountSchema.js ├── stationsDeleteListSchema.js ├── stationsDeleteSchema.js ├── stationsExportSchema.js ├── stationsGetItemSchema.js ├── stationsGetListLookupSchema.js ├── stationsGetListSchema.js ├── stationsNewBulkSchema.js ├── stationsNewChangeStateManySchema.js ├── stationsNewChangeStateSchema.js ├── stationsNewCountSchema.js ├── stationsNewDeleteListSchema.js ├── stationsNewDeleteSchema.js ├── stationsNewExportSchema.js ├── stationsNewGetItemSchema.js ├── stationsNewGetListLookupSchema.js ├── stationsNewGetListSchema.js ├── stationsNewPatchBulkSchema.js ├── stationsNewPatchManySchema.js ├── stationsNewPatchSchema.js ├── stationsNewPostSchema.js ├── stationsNewUpsertOneSchema.js ├── stationsPatchBulkSchema.js ├── stationsPatchManySchema.js ├── stationsPatchSchema.js ├── stationsPostSchema.js └── stationsUpsertOneSchema.js ├── filesFixtures ├── bookToUpdate.json ├── bookToUpdateWithoutState.json ├── books.csv ├── books.json ├── books.ndjson ├── booksError.json ├── booksNoId.json └── expectedResults.js ├── findAll.test.js ├── findById.test.js ├── fixtures ├── address_statistics.js ├── addresses.js ├── animals.js ├── books.js ├── films.js ├── items.js ├── lotOfBooksFixtures.js ├── orders-items.js ├── orders.js ├── people.js └── riders.js ├── generatePathFieldsForRawSchema.test.js ├── generatePathFromJsonSchema.test.js ├── generatedJSONSchemasToFiles.js ├── getSchemas.test.js ├── httpInterface.changeStateBulk.test.js ├── httpInterface.changeStateById.test.js ├── httpInterface.countList.test.js ├── httpInterface.deleteById.test.js ├── httpInterface.deleteList.test.js ├── httpInterface.getById.test.js ├── httpInterface.getExport.test.js ├── httpInterface.getList.test.js ├── httpInterface.getSchema.test.js ├── httpInterface.metrics.test.js ├── httpInterface.patchBulk.test.js ├── httpInterface.patchById.special.test.js ├── httpInterface.patchById.test.js ├── httpInterface.patchImport.test.js ├── httpInterface.patchMany.test.js ├── httpInterface.postBulk.test.js ├── httpInterface.postImport.test.js ├── httpInterface.postList.test.js ├── httpInterface.postValid.test.js ├── httpInterface.status.test.js ├── httpInterface.swagger.test.js ├── httpInterface.upsertOne.test.js ├── httpInterface.utils.js ├── insertMany.test.js ├── insertOne.test.js ├── insertOneWithId.test.js ├── integration.test.js ├── joinHttpInterface.test.js ├── lib ├── gcpKeyStripper.test.js ├── mongo │ ├── mongo-crypt-factory.test.js │ ├── mongo-data-keygen.test.js │ ├── mongo-keyring-factory.test.js │ ├── mongo-schemaMap-generator.test.js │ └── test-master-key.txt ├── oneLineKey.pem └── private_key.pem ├── lookupHttpInterface.test.js ├── mergeViewsInCollections.test.js ├── newCollectionDefinitions ├── books.js ├── books_encrypted.js ├── cars.js └── stations.js ├── patchBulk.test.js ├── patchById.test.js ├── patchMany.test.js ├── pkFactories.test.js ├── projectionUtils.test.js ├── queryParser.test.js ├── queryParser.utils.test.js ├── transformSchemaForSwagger.test.js ├── upsertOne.test.js ├── utils.js ├── validator.test.js ├── viewHttpInterface.test.js ├── viewUtils.utils.js ├── viewsDefinitions ├── felines.js └── store-open.js ├── viewsDefinitionsLookup ├── orders-details.js └── orders-items.js └── wrongDefinitions └── wrong.js /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Node.js", 3 | "image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bookworm", 4 | "features": { 5 | "ghcr.io/devcontainers/features/docker-in-docker:2": { 6 | "moby": true, 7 | "installDockerComposeSwitch": false 8 | } 9 | }, 10 | "postCreateCommand": "npm ci", 11 | "customizations": { 12 | "vscode": { 13 | "settings": { 14 | "files.eol": "\n", 15 | "files.insertFinalNewline": true, 16 | "files.trimFinalNewlines": true, 17 | "files.trimTrailingWhitespace": false 18 | }, 19 | "extensions": [ 20 | "editorconfig.editorconfig", 21 | "christian-kohler.npm-intellisense" 22 | ] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .devcontainer 2 | .git 3 | .github 4 | .idea 5 | .local 6 | .tap 7 | .vscode 8 | bench 9 | docs 10 | node_modules 11 | scripts 12 | tap-snapshots 13 | tests 14 | .dockerignore 15 | .editorconfig 16 | .eslintrc.js 17 | .gitignore 18 | .npmrc 19 | .nvmrc 20 | CODE_OF_CONDUCT.md 21 | CONTRIBUTING.md 22 | *.env 23 | .env* 24 | Dockerfile 25 | eslint.config.mjs 26 | README.md 27 | .clinic 28 | *.log 29 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = tab 6 | tab_width = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 120 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | extends: '@mia-platform/eslint-config-mia', 5 | parserOptions: { 6 | ecmaVersion: 2022, 7 | ecmaFeatures: { 8 | jsx: true, 9 | }, 10 | }, 11 | ignorePatterns: [ 12 | 'bench', 13 | ], 14 | overrides: [ 15 | { 16 | files: [ 17 | 'tests/**/*.js', 18 | 'tests/expectedSchemas/*.js', 19 | ], 20 | rules: { 21 | 'id-length': 'off', 22 | 'max-lines': 'off', 23 | 24 | }, 25 | }, 26 | { 27 | files: [ 28 | 'lib/**/*.js', 29 | 'index.js', 30 | ], 31 | rules: { 32 | 'valid-jsdoc': 'off', 33 | }, 34 | }, 35 | ], 36 | } 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41E Bug report" 3 | about: Found a bug or a regression? Let us know. 4 | title: '' 5 | labels: bug 6 | 7 | --- 8 | 15 | 16 | **Description** 17 | 18 | 19 | **Environment** 20 | 21 | 22 | I'm using CRUD Service version X.Y.Z 23 | 24 | **Minimal Reproduction** 25 | 26 | 27 | **Additional context** 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature request" 3 | about: Suggest an idea to improve the CRUD Service. 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 14 | 15 | ## Feature Description 16 | 20 | 21 | ## Desired solution 22 | 23 | 24 | ## Possible alternatives 25 | 26 | 27 | ## Additional context 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❓ Support request" 3 | about: Questions and requests for support. 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Pull Request Type 6 | 7 | 8 | - [ ] Bugfix 9 | - [ ] Feature 10 | - [ ] Code style update (formatting, local variables) 11 | - [ ] Refactoring (no functional changes, no api changes) 12 | - [ ] Build related changes 13 | - [ ] CI related changes 14 | - [ ] Documentation content changes 15 | - [ ] Other... Please describe: 16 | 17 | ## Description 18 | 19 | 23 | 24 | ## PR Checklist 25 | 26 | 27 | - [ ] The commit message follows our guidelines included in the [CONTRIBUTING.md](../CONTRIBUTING.md#how-to-submit-a-pr) 28 | - [ ] Tests for the changes have been added (for bug fixes / features) 29 | - [ ] Docs have been added / updated (for bug fixes / features) 30 | 31 | ## Does this PR introduce a breaking change? 32 | 33 | - [ ] Yes 34 | - [ ] No 35 | 36 | 37 | 38 | ## Other information 39 | 40 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | timezone: "Europe/Rome" 8 | groups: 9 | minor-actions-dependencies: 10 | update-types: 11 | - "minor" 12 | - "patch" 13 | commit-message: 14 | include: "scope" 15 | prefix: "ci" 16 | 17 | - package-ecosystem: "devcontainers" 18 | directory: "/" 19 | schedule: 20 | interval: "monthly" 21 | timezone: "Europe/Rome" 22 | commit-message: 23 | include: "scope" 24 | prefix: "build" 25 | 26 | 27 | - package-ecosystem: "npm" 28 | directory: "/" 29 | schedule: 30 | interval: "weekly" 31 | open-pull-requests-limit: 10 32 | groups: 33 | fastify: 34 | patterns: 35 | - "@fastify*" 36 | update-types: 37 | - "minor" 38 | - "patch" 39 | miaPlatform: 40 | patterns: 41 | - "@mia-platform*" 42 | update-types: 43 | - "minor" 44 | - "patch" 45 | lodash: 46 | patterns: 47 | - "@lodash*" 48 | update-types: 49 | - "minor" 50 | - "patch" 51 | ajv: 52 | patterns: 53 | - "ajv" 54 | - "ajv-*" 55 | update-types: 56 | - "minor" 57 | - "patch" 58 | eslint: 59 | patterns: 60 | - "eslint" 61 | - "@eslint" 62 | update-types: 63 | - "minor" 64 | - "patch" 65 | 66 | - package-ecosystem: "docker" 67 | directory: "/" 68 | schedule: 69 | interval: "weekly" 70 | open-pull-requests-limit: 10 71 | ignore: 72 | - dependency-name: "node" 73 | update-types: ["version-update:semver-major"] 74 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | authors: 4 | - dependabot 5 | categories: 6 | - title: Breaking Changes 🛠 7 | labels: 8 | - breaking 9 | - title: Exciting New Features 🎉 10 | labels: 11 | - enhancement 12 | - title: Bug fixes 🎉 13 | labels: 14 | - bug 15 | - title: Security Fixes 🔐 16 | labels: 17 | - security 18 | - title: Other Changes 19 | labels: 20 | - "*" -------------------------------------------------------------------------------- /.github/workflows/cache-cleanup.yml: -------------------------------------------------------------------------------- 1 | # Automatic clean up of actions cache generated by PRs 2 | # https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries 3 | 4 | name: Github Actions Cleanup 5 | on: 6 | pull_request: 7 | types: 8 | - closed 9 | 10 | jobs: 11 | cleanup: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Cleanup 15 | run: | 16 | gh extension install actions/gh-actions-cache 17 | 18 | echo "Fetching list of cache key" 19 | cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 ) 20 | 21 | ## Setting this to not fail the workflow while deleting cache keys. 22 | set +e 23 | echo "Deleting caches..." 24 | for cacheKey in $cacheKeysForPR 25 | do 26 | gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm 27 | done 28 | echo "Done" 29 | env: 30 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | REPO: ${{ github.repository }} 32 | BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge 33 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: Checks 2 | 3 | on: 4 | workflow_call: 5 | 6 | jobs: 7 | checks: 8 | name: Lint Code 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Repository 12 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 13 | with: 14 | show-progress: false 15 | - name: Setup Node.js 16 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 17 | with: 18 | node-version-file: .nvmrc 19 | check-latest: true 20 | cache: npm 21 | - name: Install Dependencies 22 | run: npm ci 23 | - name: Run Linter 24 | run: npm run lint 25 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yaml: -------------------------------------------------------------------------------- 1 | name: Code Scanning 2 | on: 3 | push: 4 | branches: 5 | - main 6 | tags: 7 | - "v*" 8 | pull_request: 9 | branches: 10 | - main 11 | paths-ignore: 12 | - "**/*.md" 13 | - docs/** 14 | schedule: 15 | - cron: 0 5 * * 1 # Run every monday at 5 UTC 16 | 17 | jobs: 18 | codeql: 19 | runs-on: ubuntu-latest 20 | permissions: 21 | security-events: write 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | with: 26 | show-progress: false 27 | - name: Initialize CodeQL 28 | uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 29 | with: 30 | languages: javascript-typescript 31 | - name: Perform CodeQL Analysis 32 | uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 33 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yaml: -------------------------------------------------------------------------------- 1 | name: Dependency Review 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | paths-ignore: 7 | - "**/*.md" 8 | - docs/** 9 | 10 | jobs: 11 | dependency-review: 12 | name: Dependencies Review 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: read 16 | pull-requests: write 17 | steps: 18 | - name: Checkout Repository 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | with: 21 | show-progress: false 22 | - name: Dependency Review 23 | uses: actions/dependency-review-action@ce3cf9537a52e8119d91fd484ab5b8a807627bf8 # v4.6.0 24 | with: 25 | fail-on-scopes: runtime,unknown 26 | comment-summary-in-pr: on-failure 27 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | branches: 7 | - main 8 | paths: 9 | - ".github/workflows/**" 10 | - "lib/**" 11 | - "tests/**" 12 | - "package.json" 13 | - "package-lock.json" 14 | - "Dockerfile" 15 | - "index.js" 16 | - "envSchema.js" 17 | push: 18 | branches: 19 | - main 20 | paths: 21 | - ".github/workflows/**" 22 | - "lib/**" 23 | - "tests/**" 24 | - "package.json" 25 | - "package-lock.json" 26 | - "Dockerfile" 27 | - "index.js" 28 | - "envSchema.js" 29 | 30 | jobs: 31 | checks: 32 | uses: ./.github/workflows/checks.yml 33 | 34 | tests: 35 | needs: 36 | - checks 37 | uses: ./.github/workflows/tests.yml 38 | secrets: 39 | token: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | release-docker: 42 | needs: 43 | - tests 44 | if: ${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} 45 | uses: ./.github/workflows/release-docker.yml 46 | secrets: 47 | docker_username: ${{ secrets.BOT_DOCKER_USERNAME }} 48 | docker_token: ${{ secrets.BOT_DOCKER_TOKEN }} 49 | github_cr_token: ${{ secrets.GITHUB_TOKEN }} 50 | nexus_username: ${{ secrets.NEXUS_USER }} 51 | nexus_token: ${{ secrets.NEXUS_TOKEN }} 52 | sysdig_token: ${{ secrets.SYSDIG_SECURE_TOKEN }} 53 | 54 | perf-test: 55 | needs: 56 | - checks 57 | - release-docker 58 | - tests 59 | uses: ./.github/workflows/perf-test.yml 60 | -------------------------------------------------------------------------------- /.github/workflows/perf-test.yml: -------------------------------------------------------------------------------- 1 | name: 'Performance Test' 2 | 3 | on: 4 | workflow_call: 5 | push: 6 | tags: 7 | - "v*" 8 | 9 | jobs: 10 | k6_ci_test: 11 | name: k6 CI Test run 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 17 | with: 18 | show-progress: false 19 | 20 | - name: Setup Node.js 21 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 22 | with: 23 | node-version-file: .nvmrc 24 | check-latest: true 25 | cache: npm 26 | 27 | - name: start CRUD Service via docker file 28 | working-directory: bench 29 | run: docker compose --file docker-compose.yml up -d 30 | 31 | - name: Populate "Customer" collection and "Registered Customer" View 32 | run: npm i && node bench/utils/generate-customer-data.js -c mongodb://localhost:27017/bench-test -d bench-test -n 100000 -s 250 33 | 34 | - name: Run k6 load test (collection Items) 35 | working-directory: bench 36 | run: docker compose -f dc-k6.yml up k6-load-test 37 | 38 | - name: Run k6 spike test (collection Customers) 39 | working-directory: bench 40 | run: docker compose -f dc-k6.yml up k6-spike-test 41 | 42 | - name: Run k6 stress test (view Registered Customers) 43 | working-directory: bench 44 | run: docker compose -f dc-k6.yml up k6-stress-test-on-view 45 | -------------------------------------------------------------------------------- /.github/workflows/tag.yml: -------------------------------------------------------------------------------- 1 | name: Tag CI 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | tests: 10 | uses: ./.github/workflows/tests.yml 11 | secrets: 12 | token: ${{ secrets.GITHUB_TOKEN }} 13 | 14 | release-docker: 15 | needs: 16 | - tests 17 | if: ${{ startsWith(github.ref, 'refs/tags/v') }} 18 | uses: ./.github/workflows/release-docker.yml 19 | secrets: 20 | docker_username: ${{ secrets.BOT_DOCKER_USERNAME }} 21 | docker_token: ${{ secrets.BOT_DOCKER_TOKEN }} 22 | github_cr_token: ${{ secrets.GITHUB_TOKEN }} 23 | nexus_username: ${{ secrets.NEXUS_USER }} 24 | nexus_token: ${{ secrets.NEXUS_TOKEN }} 25 | kms_gcp_project: ${{ secrets.MIA_PLATFORM_KMS_GCP_PROJECT }} 26 | gcp_wif: ${{ secrets.MIA_PLATFORM_WIF }} 27 | cosign_key: ${{ secrets.MIA_PLATFORM_KEY_KMS }} 28 | sysdig_token: ${{ secrets.SYSDIG_SECURE_TOKEN }} 29 | 30 | release: 31 | runs-on: ubuntu-latest 32 | needs: 33 | - release-docker 34 | steps: 35 | - name: Checkout 36 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 37 | with: 38 | show-progress: false 39 | 40 | - name: Release 41 | uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 42 | with: 43 | generate_release_notes: true 44 | prerelease: ${{ startsWith(github.ref, 'refs/tags/') && contains(github.ref, '-rc.') }} 45 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/jod 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | First off, thank you for considering contributing to this project. 4 | 5 | Please follow these guidelines for helping us to better address your issue, assessing changes, and helping you finalize 6 | your pull requests. There are many ways to contribute, from writing examples, improving the documentation, submitting 7 | bug reports and feature requests or writing code which can be incorporated into the module itself. 8 | 9 | ## Code of Conduct 10 | 11 | This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md), please read it and follow it 12 | before contributing. If you find someone that is not respecting it please report its behaviour. 13 | 14 | ## How Can I Contribute 15 | 16 | There are several ways to contribute. You can [fork the repository](#fork) and [propose a Pull Request](CONTRIBUTING.md#how-to-submit-a-pr), or you can start a discussion to report a bug, an indesired behavior of the application, or to simply suggest a feature. 17 | 18 | Before opening a new thread, please verify whether there's already a discussion about the topic of your interest. You can find them: 19 | - in the [issues tab](https://github.com/mia-platform/crud-service/issues); 20 | - in the [official Mia Platform Community Discussion page](https://github.com/mia-platform/community/discussions?discussions_q=label%3A%22CRUD+Service%22); 21 | 22 | ### Reporting Bugs 23 | 24 | If you find a bug, or you notice something that should be modified or improved, you can do so in the *Issues* section. 25 | 26 | Before doing that, please search if there isn’t already a similar issue already open. If you find a similar issue 27 | that is already closed, open a new one and include a link to it inside the body of the new one. 28 | 29 | ### Propose a New Feature 30 | 31 | Before starting to implement a new feature, open the relative issue for starting an open discussion on where is can be 32 | relevant and expose alternative solutions or potential pitfall that you can encounter. Fill all the information required 33 | by the template. 34 | 35 | #### Run your tests 36 | 37 | Any update to the code must be tested properly. We can refer to the [Local Development section of the README](./README.md#local-development). Please make sure that any update you want to propose includes enough tests, and the old ones pass as well. 38 | 39 | #### How to submit a PR 40 | 41 | * Commits should follow standards: `(): ` (e.g. `feat(core): Add new feature`) 42 | * In the `Unreleased` section in CHANGELOG.md, compile the changelog adding the improvement added in the PR. 43 | Changelog should follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) standard. 44 | 45 | ## Fork 46 | 47 | If you want to fork our project, you could make it and keep in sync with our template. 48 | All contribution which could improve the existent code base are welcome! 49 | 50 | To keep a fork up to date, you can follow this [GitHub guide](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork). 51 | For all the information about forks, [see this link](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks). -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM docker.io/curlimages/curl:8.13.0@sha256:d43bdb28bae0be0998f3be83199bfb2b81e0a30b034b6d7586ce7e05de34c3fd AS crypt-lib 3 | 4 | ARG TARGETARCH 5 | 6 | WORKDIR /cryptd 7 | 8 | ARG CRYPTD_VERSION=7.0.15 9 | ARG CRYPTD_OS=debian12 10 | 11 | # debian doesn't suppport arm architecture for now, if we switch to ubuntu we can uncomment the arm bit 12 | RUN case "${TARGETARCH}" in \ 13 | 'amd64') \ 14 | cryptd_arch="x86_64"; \ 15 | ;; \ 16 | # 'arm64') \ 17 | # cryptd_arch="aarch64"; \ 18 | # ;; \ 19 | *) echo >&2 "error: unsupported architecture ($TARGETARCH)"; exit 1; ;; \ 20 | esac; \ 21 | curl -fsSL "https://downloads.mongodb.com/linux/mongo_crypt_shared_v1-linux-${cryptd_arch}-enterprise-${CRYPTD_OS}-${CRYPTD_VERSION}.tgz" -o "/tmp/mongo_crypt_shared.tgz" \ 22 | && tar -xvf "/tmp/mongo_crypt_shared.tgz" --no-same-permissions --no-same-owner -C "/cryptd" 23 | 24 | ######################################################################################################################## 25 | 26 | FROM docker.io/library/node:22.16.0-bookworm-slim@sha256:2f3571619daafc6b53232ebf2fcc0817c1e64795e92de317c1684a915d13f1a5 AS build 27 | 28 | ENV NODE_ENV=production 29 | 30 | WORKDIR /build-dir 31 | 32 | COPY package.json . 33 | COPY package-lock.json . 34 | 35 | RUN npm ci 36 | 37 | COPY . . 38 | 39 | ######################################################################################################################## 40 | 41 | # create a CRUD Service image that does not support automatic CSFLE 42 | # and therefore it can be employed by everybody in any MongoDB product 43 | FROM docker.io/library/node:22.16.0-bookworm-slim@sha256:2f3571619daafc6b53232ebf2fcc0817c1e64795e92de317c1684a915d13f1a5 AS crud-service-no-encryption 44 | 45 | ARG COMMIT_SHA 46 | ARG DEBIAN_FRONTEND=noninteractive 47 | 48 | RUN apt-get update && apt-get install --assume-yes --no-install-recommends \ 49 | tini \ 50 | && apt-get autoremove --assume-yes \ 51 | && rm -rf /var/lib/apt/lists/* 52 | 53 | ENV NODE_ENV=production 54 | ENV LOG_LEVEL=info 55 | ENV HTTP_PORT=3000 56 | ENV SERVICE_PREFIX=/ 57 | ENV EXPOSE_METRICS=true 58 | ENV ENABLE_TRACING=false 59 | 60 | EXPOSE ${HTTP_PORT} 61 | 62 | WORKDIR /home/node/app 63 | 64 | COPY --from=build /build-dir ./ 65 | 66 | HEALTHCHECK --start-period=5s CMD wget -qO- http://localhost:${HTTP_PORT}/-/healthz &> /dev/null || exit 1 67 | 68 | USER node 69 | 70 | ENTRYPOINT ["/usr/bin/tini", "--"] 71 | 72 | CMD ./node_modules/.bin/lc39 ./index.js --port=${HTTP_PORT} --log-level=${LOG_LEVEL} --prefix=${SERVICE_PREFIX} --expose-metrics=${EXPOSE_METRICS} --enable-tracing=${ENABLE_TRACING} 73 | 74 | ######################################################################################################################## 75 | 76 | # extend previous stage to add the support to automatic MongoDB CSFLE feature, 77 | # which can be leveraged by users adopting a MongoDB Atlas or MongoDB enterprise products 78 | FROM crud-service-no-encryption AS crud-service-with-encryption 79 | 80 | ENV CRYPT_SHARED_LIB_PATH=/cryptd/mongo_crypt_v1.so 81 | 82 | COPY --from=crypt-lib /cryptd/lib/mongo_crypt_v1.so /cryptd/mongo_crypt_v1.so 83 | -------------------------------------------------------------------------------- /bench/dc-k6.yml: -------------------------------------------------------------------------------- 1 | services: 2 | runner: 3 | image: grafana/k6:0.48.0 4 | deploy: 5 | resources: 6 | limits: 7 | memory: 512Mb 8 | cpus: "1" 9 | volumes: 10 | - ./scripts:/app 11 | networks: 12 | - k6-net 13 | command: [ 14 | "run", 15 | "--out", 16 | "json=runner-results.json", 17 | "/app/runner.js", 18 | ] 19 | k6-bulk-test: 20 | image: grafana/k6:0.48.0 21 | deploy: 22 | resources: 23 | limits: 24 | memory: 512Mb 25 | cpus: "1" 26 | volumes: 27 | - ./scripts:/app 28 | networks: 29 | - k6-net 30 | command: [ 31 | "run", 32 | "--out", 33 | "json=bulk-test-results.json", 34 | "/app/bulk-test.js", 35 | ] 36 | k6-load-test: 37 | image: grafana/k6:0.48.0 38 | deploy: 39 | resources: 40 | limits: 41 | memory: 512Mb 42 | cpus: "1" 43 | volumes: 44 | - ./scripts:/app 45 | networks: 46 | - k6-net 47 | command: [ 48 | "run", 49 | "--out", 50 | "json=load-test-results.json", 51 | "/app/load-test.js", 52 | ] 53 | k6-smoke-test: 54 | image: grafana/k6:0.48.0 55 | deploy: 56 | resources: 57 | limits: 58 | memory: 512Mb 59 | cpus: "1" 60 | volumes: 61 | - ./scripts:/app 62 | networks: 63 | - k6-net 64 | command: [ 65 | "run", 66 | "--out", 67 | "json=smoke-test-results.json", 68 | "/app/smoke-test.js", 69 | ] 70 | k6-stress-test-on-collection: 71 | image: grafana/k6:0.48.0 72 | deploy: 73 | resources: 74 | limits: 75 | memory: 512Mb 76 | cpus: "1" 77 | volumes: 78 | - ./scripts:/app 79 | networks: 80 | - k6-net 81 | command: [ 82 | "run", 83 | "--out", 84 | "json=stress-test-on-collection-results.json", 85 | "/app/stress-test-on-collection.js", 86 | ] 87 | k6-stress-test-on-view: 88 | image: grafana/k6:0.48.0 89 | deploy: 90 | resources: 91 | limits: 92 | memory: 512Mb 93 | cpus: "1" 94 | volumes: 95 | - ./scripts:/app 96 | networks: 97 | - k6-net 98 | command: [ 99 | "run", 100 | "--out", 101 | "json=stress-test-on-view-results.json", 102 | "/app/stress-test-on-view.js", 103 | ] 104 | k6-spike-test: 105 | image: grafana/k6:0.48.0 106 | deploy: 107 | resources: 108 | limits: 109 | memory: 512Mb 110 | cpus: "1" 111 | volumes: 112 | - ./scripts:/app 113 | networks: 114 | - k6-net 115 | command: [ 116 | "run", 117 | "--out", 118 | "json=spike-test-results.json", 119 | "/app/spike-test.js", 120 | ] 121 | 122 | networks: 123 | k6-net: 124 | -------------------------------------------------------------------------------- /bench/definitions/views/registered-customers.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'registered-customers', 21 | source: 'customers', 22 | type: 'view', 23 | pipeline: [ 24 | { 25 | $project: { 26 | _id: 1, 27 | name: 1, 28 | updaterId: 1, 29 | updatedAt: 1, 30 | creatorId: 1, 31 | createdAt: 1, 32 | customerId: 1, 33 | firstName: 1, 34 | lastName: 1, 35 | shopID: 1, 36 | canBeContacted: 1, 37 | purchasesCount: 1, 38 | __STATE__: 1, 39 | }, 40 | }, 41 | ], 42 | } 43 | -------------------------------------------------------------------------------- /bench/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | database: 3 | image: mongo:6.0 4 | ports: 5 | - '27017:27017' 6 | volumes: 7 | - mongo:/data/db 8 | networks: 9 | - k6-net 10 | deploy: 11 | resources: 12 | limits: 13 | memory: 4GB 14 | cpus: "2" 15 | healthcheck: 16 | test: [ "CMD", "mongosh", "--eval", "db.adminCommand('ping')" ] 17 | interval: 10s 18 | timeout: 5s 19 | retries: 3 20 | start_period: 5s 21 | 22 | crud-service: 23 | build: 24 | context: .. 25 | dockerfile: Dockerfile 26 | ports: 27 | - '3000:3000' 28 | depends_on: 29 | database: 30 | condition: service_healthy 31 | networks: 32 | - k6-net 33 | deploy: 34 | resources: 35 | limits: 36 | memory: 500Mb 37 | cpus: "2" 38 | environment: 39 | LOG_LEVEL: info 40 | COLLECTION_DEFINITION_FOLDER: /home/node/app/definitions/collections 41 | VIEWS_DEFINITION_FOLDER: /home/node/app/definitions/views 42 | USER_ID_HEADER_KEY: userid 43 | CRUD_LIMIT_CONSTRAINT_ENABLED: "true" 44 | CRUD_MAX_LIMIT: 200 45 | MONGODB_URL: "mongodb://database:27017/bench-test" 46 | volumes: 47 | - ./definitions:/home/node/app/definitions 48 | - ./utils/healthcheck.js:/home/node/app/healthcheck/healthcheck.js 49 | healthcheck: 50 | test: [ "CMD-SHELL", "node /home/node/app/healthcheck/healthcheck.js" ] 51 | interval: 10s 52 | timeout: 5s 53 | retries: 5 54 | start_period: 10s 55 | 56 | networks: 57 | k6-net: 58 | 59 | volumes: 60 | mongo: 61 | -------------------------------------------------------------------------------- /bench/queryParser.bench.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const QueryParser = require('../lib/QueryParser') 20 | const collectionDefinition = require('../tests/collectionDefinitions/books') 21 | 22 | const bench = require('fastbench') 23 | 24 | const queryParser = new QueryParser(collectionDefinition) 25 | 26 | const run = bench([ 27 | function integer(done) { 28 | queryParser.parseAndCast({ price: 33.3 }) 29 | process.nextTick(done) 30 | }, 31 | function string(done) { 32 | queryParser.parseAndCast({ name: 'foo' }) 33 | process.nextTick(done) 34 | }, 35 | function integerDate(done) { 36 | queryParser.parseAndCast({ publishDate: 1517827514394 }) 37 | process.nextTick(done) 38 | }, 39 | function stringDate(done) { 40 | queryParser.parseAndCast({ publishDate: '2018-02-05T10:45:14.394Z' }) 41 | process.nextTick(done) 42 | }, 43 | function string24ObjectId(done) { 44 | queryParser.parseAndCast({ _id: 'aaaaaaaaaaaaaaaaaaaaaaaa' }) 45 | process.nextTick(done) 46 | }, 47 | function string12ObjectId(done) { 48 | queryParser.parseAndCast({ _id: 'bbbbbbbbbbbb' }) 49 | process.nextTick(done) 50 | }, 51 | function $and(done) { 52 | queryParser.parseAndCast({ 53 | $and: [ 54 | { name: 'foo' }, 55 | { price: 33.3 }, 56 | { publishDate: 1517827514394 }, 57 | ], 58 | }) 59 | process.nextTick(done) 60 | }, 61 | function $or(done) { 62 | queryParser.parseAndCast({ 63 | $or: [ 64 | { name: 'foo' }, 65 | { price: 33.3 }, 66 | { publishDate: 1517827514394 }, 67 | ], 68 | }) 69 | process.nextTick(done) 70 | }, 71 | ], 1000000) 72 | 73 | run(run) 74 | -------------------------------------------------------------------------------- /bench/scripts/runner.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import http from 'k6/http' 18 | import { sleep, check } from 'k6' 19 | import { 20 | randomIntBetween, 21 | randomString, 22 | } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js' 23 | 24 | // 25 | // This file represent a stub of a k6 test. Feel free to modify based on your needs. 26 | // 27 | 28 | const generateItems = (length = 10000) => { 29 | return Array.from(Array(length).keys()).map((counter) => ({ 30 | string: randomString(5), 31 | number: randomIntBetween(1, 10), 32 | boolean: randomIntBetween(0, 1) === 1, 33 | date: new Date(randomIntBetween(0, 10)), 34 | object: { 35 | string: `object-${randomString(5)}`, 36 | number: randomIntBetween(1, 10), 37 | boolean: randomIntBetween(0, 1) === 1, 38 | counter, 39 | }, 40 | array: Array.from(Array(randomIntBetween(1, 10)).keys()).map((i) => ({ 41 | string: `array-${i}-${randomString(5)}`, 42 | number: randomIntBetween(1, 10), 43 | boolean: randomIntBetween(0, 1) === 1, 44 | })), 45 | })) 46 | } 47 | 48 | export const options = { 49 | stages: [ 50 | { duration: '10s', target: 5 }, 51 | { duration: '20s', target: 20 }, 52 | { duration: '150s', target: 50 }, 53 | { duration: '20s', target: 20 }, 54 | { duration: '10s', target: 5 }, 55 | ], 56 | thresholds: { 57 | checks: ['rate==1'], 58 | http_req_failed: ['rate<0.01'], 59 | 'http_req_duration{type:bulk}': ['p(90)<4500'], 60 | }, 61 | } 62 | 63 | export function setup() { 64 | // Here it goes any code we want to execute before running our tests 65 | const getProbe = http.get(`http://crud-service:3000/items/`, { 66 | headers: { 'Content-Type': 'application/json', 'accept': 'application/json' }, 67 | tags: { type: 'get' }, 68 | }) 69 | check(getProbe, { 'GET /items returns status 200': res => res.status === 200 }) 70 | } 71 | 72 | export default function() { 73 | const items = generateItems() 74 | 75 | const postList = http.post(`http://crud-service:3000/items/bulk`, JSON.stringify(items), { 76 | headers: { 'Content-Type': 'application/json', 'accept': 'application/json' }, 77 | tags: { type: 'bulk' }, 78 | }) 79 | check(postList, { 'POST / returns status 200': res => res.status === 200 }) 80 | } 81 | 82 | export function teardown(data) { 83 | // Here it goes any code we want to execute after running our tests 84 | } 85 | -------------------------------------------------------------------------------- /bench/scripts/smoke-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js' 18 | import { executeGetTests } from './utils.js' 19 | 20 | // 21 | // Test on collection "customers" 22 | // Type of test: smoke test 23 | // 24 | // 5 concurrent users for 1 minutes 25 | // 26 | 27 | export const options = { 28 | vus: 5, 29 | duration: '1m', 30 | thresholds: { 31 | checks: ['rate==1'], 32 | http_req_failed: ['rate<0.01'], 33 | http_req_duration: ['p(90)<150', 'p(95)<300'], 34 | }, 35 | } 36 | 37 | export default function() { 38 | executeGetTests('customers') 39 | } 40 | 41 | export function handleSummary(data) { 42 | return { 43 | stdout: textSummary(data, { enableColors: true }), 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bench/scripts/spike-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js' 18 | import { executeGetTests } from './utils.js' 19 | 20 | // 21 | // Test on collection "customers" 22 | // Type of test: spike test 23 | // 24 | // 5 concurrent users for the first 5 seconds 25 | // Then number of users rise to 500 in a 20-seconds span 26 | // Before to cool down to 5 users in 20 seconds to conclude the test 27 | // 28 | 29 | export const options = { 30 | stages: [ 31 | { duration: '10s', target: 5 }, 32 | { duration: '30s', target: 500 }, 33 | { duration: '30s', target: 5 }, 34 | ], 35 | thresholds: { 36 | checks: ['rate==1'], 37 | http_req_failed: ['rate<0.01'], 38 | 'http_req_duration{type:getList}': ['p(90)<250'], 39 | 'http_req_duration{type:getListWithQueryOperator}': ['p(90)<250'], 40 | 'http_req_duration{type:getById}': ['p(90)<250'], 41 | 'http_req_duration{type:count}': ['p(90)<250'], 42 | 'http_req_duration{type:export}': ['p(90)<250'], 43 | }, 44 | } 45 | 46 | export default function() { 47 | executeGetTests('customers') 48 | } 49 | 50 | export function handleSummary(data) { 51 | return { 52 | stdout: textSummary(data, { enableColors: true }), 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bench/scripts/stress-test-on-collection.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js' 18 | import { executeGetTests } from './utils' 19 | 20 | // 21 | // Test on collection "customers" 22 | // Type of test: stress test 23 | // 24 | // 5 concurrent users for the first 5 seconds 25 | // Then number of users rise to 200 in a 10-seconds span 26 | // It stays high for 45 seconds 27 | // Then it goes back to 5 users in 30 seconds to conclude the test 28 | // 29 | 30 | export const options = { 31 | stages: [ 32 | { duration: '5s', target: 5 }, 33 | { duration: '10s', target: 250 }, 34 | { duration: '75s', target: 250 }, 35 | { duration: '10s', target: 5 }, 36 | { duration: '10s', target: 5 }, 37 | ], 38 | thresholds: { 39 | checks: ['rate==1'], 40 | http_req_failed: ['rate<0.01'], 41 | 'http_req_duration{type:getList}': ['p(90)<250'], 42 | 'http_req_duration{type:getListWithQueryOperator}': ['p(90)<250'], 43 | 'http_req_duration{type:getById}': ['p(90)<250'], 44 | 'http_req_duration{type:count}': ['p(90)<250'], 45 | 'http_req_duration{type:export}': ['p(90)<250'], 46 | }, 47 | } 48 | 49 | export default function() { 50 | executeGetTests('customers') 51 | } 52 | 53 | export function handleSummary(data) { 54 | return { 55 | stdout: textSummary(data, { enableColors: true }), 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /bench/scripts/stress-test-on-view.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js' 18 | import { executeGetTests } from './utils.js' 19 | 20 | // 21 | // Test on view "registered-customers" 22 | // Type of test: stress test 23 | // 24 | // 5 concurrent users for the first 5 seconds 25 | // Then number of users rise to 200 in a 10-seconds span 26 | // It stays high for 45 seconds 27 | // Then it goes back to 5 users in 30 seconds to conclude the test 28 | // 29 | 30 | export const options = { 31 | stages: [ 32 | { duration: '5s', target: 5 }, 33 | { duration: '10s', target: 250 }, 34 | { duration: '75s', target: 250 }, 35 | { duration: '10s', target: 5 }, 36 | { duration: '10s', target: 5 }, 37 | ], 38 | thresholds: { 39 | checks: ['rate==1'], 40 | http_req_failed: ['rate<0.01'], 41 | 'http_req_duration{type:getList}': ['p(90)<250'], 42 | 'http_req_duration{type:getListWithQueryOperator}': ['p(90)<250'], 43 | 'http_req_duration{type:getById}': ['p(90)<250'], 44 | 'http_req_duration{type:count}': ['p(90)<250'], 45 | 'http_req_duration{type:export}': ['p(90)<250'], 46 | }, 47 | } 48 | 49 | export default function() { 50 | executeGetTests('registered-customers') 51 | } 52 | 53 | export function handleSummary(data) { 54 | return { 55 | stdout: textSummary(data, { enableColors: true }), 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /bench/utils/healthcheck.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | async function main() { 20 | try { 21 | await fetch('http://localhost:3000/-/healthz') 22 | } catch (error) { 23 | process.exitCode = 1 24 | } 25 | } 26 | 27 | main() 28 | -------------------------------------------------------------------------------- /default.env: -------------------------------------------------------------------------------- 1 | # Crud Service 2 | LOG_LEVEL=debug 3 | COLLECTION_DEFINITION_FOLDER=${PWD}/tests/collectionDefinitions 4 | VIEWS_DEFINITION_FOLDER=${PWD}/tests/viewsDefinitions 5 | USER_ID_HEADER_KEY=userid 6 | CRUD_LIMIT_CONSTRAINT_ENABLED=true 7 | CRUD_MAX_LIMIT=200 8 | MONGODB_URL=mongodb://localhost:27017/crud-local 9 | -------------------------------------------------------------------------------- /docs/guides/10_Migration-Guide-v7.md: -------------------------------------------------------------------------------- 1 | # Migration Guide to V7 2 | 3 | This document describes the breaking changes introduced with the new version v7.0.0 of the CRUD Service 4 | and how they should be tackled in order to safely upgrade CRUD Service version. 5 | 6 | ### MongoDB Support [#189](https://github.com/mia-platform/crud-service/pull/189) 7 | 8 | With this new release of CRUD Service it is introduced the support to Mongo v7, while 9 | the support to MongoDB v4.2 was dropped. For this reason, while the service may still 10 | work with such MongoDB version, it is recommended to upgrade your MongoDB cluster version 11 | to v4.4. or higher to ensure full compatibility with CRUD Service. 12 | 13 | For more details on CRUD Service compatibility with MongoDB, please visit the Marketplace 14 | [_compatibility matrix_](https://docs.mia-platform.eu/docs/marketplace/compatibility_matrices/mongo_compatibility_matrix). 15 | 16 | ### Duplicated Key Response Error Code [#140](https://github.com/mia-platform/crud-service/pull/140) 17 | 18 | Following the discussion CRUD Service response on [unique constraint violation](https://github.com/mia-platform/community/discussions/175), it has been decided 19 | to change the returned HTTP error code from `422 Unprocessable Entity` to `409 Conflict`. 20 | This modification should improve the clarity on what happened to the requested operation. 21 | 22 | In order to safely migrate the CRUD Service version, it is important to ensure that all 23 | the applications depending on the specific response code, returned in case of duplicate 24 | key, are appropriately modified to accept the new response code. 25 | 26 | ### Disallowed State Transition Error Code [#122](https://github.com/mia-platform/crud-service/pull/122) 27 | 28 | As discussed in issue [#53](https://github.com/mia-platform/crud-service/issues/53), it has 29 | been decided to change the returned HTTP error code from `404 Not Found` to `400 Bad Request`. 30 | This modification should improve the clarity on what happened to the requested operation. 31 | 32 | In order to safely migrate the CRUD Service version, it is important to ensure that all 33 | the applications depending on the specific response code, returned in case of duplicate 34 | key, are appropriately modified to accept the new response code. 35 | 36 | ### Access to Fields Outside the Collection Schema Model [#127](https://github.com/mia-platform/crud-service/pull/127) | [#144](https://github.com/mia-platform/crud-service/pull/144) 37 | 38 | In response to issue [#55](https://github.com/mia-platform/crud-service/issues/55), the access 39 | to collection properties has been enforced to cover only fields defined in the collection schema model. 40 | Requesting to access an unexpected field now returns an HTTP error `400 Bad request`. At 41 | the same time, when requesting documents via `GET //` and `GET //:id` endpoints, 42 | properties that may be available on the collection documents but that are not explicitly defined 43 | in the collection schema model are removed from the actual response body. 44 | 45 | In order to safely migrate the CRUD Service version, it is important to ensure that either: 46 | - all the applications depending on this specific behavior are modified appropriately 47 | - the collections model definition is reviewed and potentially updated to include all the fields actually required by the applications -------------------------------------------------------------------------------- /docs/guides/_category_.yml: -------------------------------------------------------------------------------- 1 | label: 'Guides' 2 | position: 10 3 | collapsible: true 4 | collapsed: true -------------------------------------------------------------------------------- /docs/img/crud-api-portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mia-platform/crud-service/643f251055d3e69b20923a4189a3a1cd2000011d/docs/img/crud-api-portal.png -------------------------------------------------------------------------------- /docs/img/position-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mia-platform/crud-service/643f251055d3e69b20923a4189a3a1cd2000011d/docs/img/position-index.png -------------------------------------------------------------------------------- /lib/AdditionalCaster.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | function castItem(value) { 22 | if (value === null || value === undefined) { 23 | return value 24 | } 25 | 26 | // Custom GeoPoint type 27 | if (typeof value === 'object' && value.type === 'Point' && Array.isArray(value.coordinates)) { 28 | return value.coordinates 29 | } 30 | 31 | if (value instanceof ObjectId) { 32 | return value.toString() 33 | } 34 | if (value instanceof Date) { 35 | return value.toISOString() 36 | } 37 | 38 | // NOTE: this works also for arrays 39 | if (typeof value === 'object') { 40 | for (const key of Object.keys(value)) { 41 | value[key] = castItem(value[key]) 42 | } 43 | } 44 | 45 | return value 46 | } 47 | 48 | // a function that return an ObjectId if the input id is in the correct format, a string otherwise. 49 | function castCollectionId(id) { 50 | return ObjectId.isValid(id) ? new ObjectId(id) : id 51 | } 52 | 53 | module.exports = { castItem, castCollectionId } 54 | -------------------------------------------------------------------------------- /lib/BadRequestError.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { BAD_REQUEST_ERROR_STATUS_CODE } = require('./consts') 20 | 21 | function BadRequestError(message) { 22 | this.statusCode = BAD_REQUEST_ERROR_STATUS_CODE 23 | this.message = message 24 | this.error = 'Bad Request' 25 | } 26 | 27 | module.exports = BadRequestError 28 | -------------------------------------------------------------------------------- /lib/BatchWritableStream.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | const { Writable } = require('stream') 19 | 20 | class BatchWritableStream extends Writable { 21 | constructor(options) { 22 | super(options) 23 | 24 | if (!options.processBatch || options.processBatch[Symbol.toStringTag] !== 'AsyncFunction') { 25 | throw new Error('BatchWritableStream requires an async "processBatch" function') 26 | } 27 | 28 | this.processBatch = options.processBatch 29 | this.batchSize = options.batchSize || 1000 30 | this.flushBatch() 31 | } 32 | 33 | flushBatch() { 34 | this.batch = [] 35 | } 36 | 37 | _write(chunk, _encoding, callback) { 38 | this.batch.push(chunk) 39 | if (this.batch.length >= this.batchSize) { 40 | this.processBatch(this.batch) 41 | .then(() => { 42 | this.flushBatch() 43 | callback() 44 | }) 45 | .catch((error) => callback(error)) 46 | } else { 47 | return callback() 48 | } 49 | } 50 | 51 | _final(callback) { 52 | if (this.batch.length > 0) { 53 | this.processBatch(this.batch) 54 | .then(() => { 55 | this.flushBatch() 56 | callback() 57 | }) 58 | .catch((error) => callback(error)) 59 | } else { 60 | return callback() 61 | } 62 | } 63 | } 64 | 65 | module.exports = BatchWritableStream 66 | -------------------------------------------------------------------------------- /lib/CrudService.utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { STATES, __STATE__ } = require('./consts') 20 | 21 | function getStateQuery(states) { 22 | if (!states || states.length === 0) { 23 | return { [__STATE__]: STATES.PUBLIC } 24 | } 25 | 26 | if (states.length === 1) { 27 | return { [__STATE__]: states[0] } 28 | } 29 | 30 | return { [__STATE__]: { $in: states } } 31 | } 32 | 33 | module.exports = { 34 | getStateQuery, 35 | } 36 | -------------------------------------------------------------------------------- /lib/JSONPath.utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const pointerSeparator = new RegExp('/+', 'g') 20 | const miaConfigurations = new RegExp('/(properties|schema|items|__mia_configuration)', 'g') 21 | 22 | function getPathFromPointer(pointer) { 23 | return pointer 24 | .slice(1) 25 | .replace(miaConfigurations, '') 26 | .replace(pointerSeparator, '.') 27 | } 28 | 29 | module.exports = { 30 | getPathFromPointer, 31 | pointerSeparator, 32 | } 33 | -------------------------------------------------------------------------------- /lib/acceptHeaderParser.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const acceptHeaderRegex = /(?(?.+?)\/(?.+?)(?:\+(?.+?))?)(?:;.*?(?:\s*q=(?[.\d]+))?.*?)?(?:,|$)/g 4 | 5 | function getAccept(acceptHeader) { 6 | const accepts = [] 7 | 8 | const matches = acceptHeader.matchAll(acceptHeaderRegex) 9 | 10 | for (const match of matches) { 11 | const { content, weight } = match.groups 12 | 13 | accepts.push({ content, weight: weight ?? 1.0 }) 14 | } 15 | 16 | // take the first with the highest quality param ensuring that not whitespaces are captured 17 | return accepts.sort(sortAcceptsByQualityReversed)?.[0]?.content.trim() 18 | } 19 | 20 | function sortAcceptsByQualityReversed(typeA, typeB) { 21 | if (typeA.weight < typeB.weight) { 22 | return 1 23 | } 24 | 25 | if (typeA.weight > typeB.weight) { 26 | return -1 27 | } 28 | 29 | return 0 30 | } 31 | 32 | /** 33 | * Returns the reply type callback used by fastify 34 | * @param {string} defaultAccept default type that will be used as reply type if wildcard 35 | * is found in the input accept header 36 | * @returns {(acceptHeader: string) => string} replyType callback 37 | */ 38 | function getReplyTypeCallback(defaultAccept) { 39 | return (acceptHeader = '') => { 40 | const accept = getAccept(acceptHeader) 41 | 42 | if (!accept || accept === '*/*') { return defaultAccept } 43 | 44 | return accept 45 | } 46 | } 47 | 48 | module.exports = { 49 | getAccept, 50 | getReplyTypeCallback, 51 | } 52 | -------------------------------------------------------------------------------- /lib/gcpKeyStripper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { readFileSync } = require('fs') 20 | 21 | const readAndStripPrivateKeyContent = (keyPath) => { 22 | const privateKeyFileContent = readFileSync(keyPath, { encoding: 'utf-8' }) 23 | return privateKeyFileContent 24 | .replace('-----BEGIN PRIVATE KEY-----', '') 25 | .replace('-----END PRIVATE KEY-----', '') 26 | .replace(/\\n/g, '') 27 | .trim() 28 | } 29 | 30 | module.exports = { 31 | readAndStripPrivateKeyContent, 32 | } 33 | -------------------------------------------------------------------------------- /lib/mergeViewsInCollections.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = function mergeViewsInCollections(collections, views) { 20 | const mergedCollections = [...collections] 21 | 22 | for (let i = 0; i < views.length; i++) { 23 | const { name: viewName, pipeline, enableLookup = false } = views[i] 24 | 25 | const associatedCollectionIndex = collections.findIndex(({ name: collectionName }) => collectionName === viewName) 26 | 27 | if (associatedCollectionIndex >= 0) { 28 | mergedCollections[associatedCollectionIndex] = { 29 | ...collections[associatedCollectionIndex], 30 | ...views[i], 31 | // Mandatory to initialize the collection in Mongo as a MongoDB View 32 | type: 'view', 33 | pipeline, 34 | enableLookup, 35 | 36 | } 37 | } 38 | } 39 | return mergedCollections 40 | } 41 | -------------------------------------------------------------------------------- /lib/mimeTypeTransform.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 'use strict' 17 | 18 | const excel = require('./transformers/excel') 19 | const ndjson = require('./transformers/ndjson') 20 | const json = require('./transformers/json') 21 | const csv = require('./transformers/csv') 22 | 23 | module.exports = { 24 | getFileMimeStringifiers: (contentType, parsingOptions = {}) => { 25 | switch (contentType) { 26 | case 'application/x-ndjson': 27 | return ndjson(parsingOptions).stringifier 28 | case 'application/json': 29 | return json(parsingOptions).stringifier 30 | case 'text/csv': 31 | return csv(parsingOptions).stringifier 32 | case 'application/vnd.ms-excel': 33 | return excel(parsingOptions).stringifier 34 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 35 | return excel(parsingOptions).stringifier 36 | default: 37 | return undefined 38 | } 39 | }, 40 | getFileMimeParser: (contentType, parsingOptions) => { 41 | switch (contentType) { 42 | case 'application/x-ndjson': 43 | return ndjson(parsingOptions).parser 44 | case 'application/json': 45 | return json(parsingOptions).parser 46 | case 'text/csv': 47 | return csv(parsingOptions).parser 48 | case 'application/vnd.ms-excel': 49 | return excel(parsingOptions).parser 50 | case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 51 | return excel(parsingOptions).parser 52 | default: 53 | return undefined 54 | } 55 | }, 56 | } 57 | 58 | -------------------------------------------------------------------------------- /lib/mongo/mongo-crypt-factory.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { readFileSync } = require('fs') 20 | 21 | const { readAndStripPrivateKeyContent } = require('../gcpKeyStripper') 22 | 23 | const encryptConfigMap = { 24 | gcp: ({ config }) => { 25 | const { KMS_GCP_EMAIL, KMS_GCP_PRIVATE_KEY_PATH } = config 26 | return { 27 | gcp: { 28 | email: KMS_GCP_EMAIL, 29 | privateKey: readAndStripPrivateKeyContent(KMS_GCP_PRIVATE_KEY_PATH), 30 | }, 31 | } 32 | }, 33 | local: ({ config }) => { 34 | const { LOCAL_MASTER_KEY_PATH } = config 35 | return { 36 | local: { 37 | key: readFileSync(LOCAL_MASTER_KEY_PATH), 38 | }, 39 | } 40 | }, 41 | } 42 | 43 | const enrichConfiguration = ({ config }, kmsProviders, schemaMap) => { 44 | const { KEY_VAULT_NAMESPACE, CRYPT_SHARED_LIB_PATH } = config 45 | const encryptionConfig = { 46 | keyVaultNamespace: KEY_VAULT_NAMESPACE, 47 | kmsProviders, 48 | extraOptions: { 49 | cryptSharedLibPath: CRYPT_SHARED_LIB_PATH, 50 | }, 51 | } 52 | if (schemaMap) { encryptionConfig.schemaMap = schemaMap } 53 | return encryptionConfig 54 | } 55 | 56 | function generateEncryptionConfig(fastify, schemaMap) { 57 | const { KMS_PROVIDER } = fastify.config 58 | const factory = encryptConfigMap[KMS_PROVIDER] 59 | if (factory) { 60 | const kmsProvider = factory(fastify) 61 | return enrichConfiguration(fastify, kmsProvider, schemaMap) 62 | } 63 | } 64 | 65 | module.exports = generateEncryptionConfig 66 | -------------------------------------------------------------------------------- /lib/mongo/mongo-keyring-factory.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const factories = { 20 | gcp: ({ config }) => { 21 | const { KMS_GCP_PROJECT_ID, KMS_GCP_LOCATION, KMS_GCP_KEY_RING, KMS_GCP_KEY_NAME } = config 22 | return { 23 | masterKey: { 24 | projectId: KMS_GCP_PROJECT_ID, 25 | location: KMS_GCP_LOCATION, 26 | keyRing: KMS_GCP_KEY_RING, 27 | keyName: KMS_GCP_KEY_NAME, 28 | }, 29 | } 30 | }, 31 | } 32 | 33 | const retrieveKeyRing = ({ config }) => { 34 | const { KMS_PROVIDER } = config 35 | const factory = factories[KMS_PROVIDER] 36 | return factory ? factory({ config }) : {} 37 | } 38 | 39 | module.exports = retrieveKeyRing 40 | -------------------------------------------------------------------------------- /lib/pkFactories.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | const { randomUUID } = require('crypto') 21 | const { VIEWS_PREFIX } = require('./consts') 22 | 23 | function getDatabaseNameByType(type) { 24 | return `${type}PK` 25 | } 26 | 27 | function getPrefixedDatabaseName(type) { 28 | return `${VIEWS_PREFIX}_${getDatabaseNameByType(type)}` 29 | } 30 | 31 | function getUUIDPKFactory() { 32 | return { 33 | createPk() { 34 | return randomUUID() 35 | }, 36 | } 37 | } 38 | 39 | function getObjectIdFactory() { 40 | return { 41 | createPk() { 42 | return new ObjectId() 43 | }, 44 | } 45 | } 46 | 47 | const pkFactories = { 48 | string: getUUIDPKFactory(), 49 | ObjectId: getObjectIdFactory(), 50 | } 51 | module.exports = { 52 | pkFactories, 53 | getDatabaseNameByType, 54 | getPrefixedDatabaseName, 55 | } 56 | -------------------------------------------------------------------------------- /lib/resolveMongoQuery.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const BadRequestError = require('./BadRequestError') 4 | 5 | /** 6 | * This function resolves a mongodb query that has to be performed over a CRUD resource. 7 | * 8 | * @param {import('./QueryParser')} queryParser the QueryParser istance 9 | * @param {string?} clientQueryString the raw string representing a mongodb query 10 | * @param {unknown?} aclRows acl expression for rows filtering 11 | * @param {unknown?} otherParams additional parameters that will be appended to the query with $and operator 12 | * @param {boolean} textQuery if the query that needs to be resolved contains a text filter 13 | * @returns {import('mongodb').Document} mongodb query 14 | */ 15 | function resolveMongoQuery( 16 | queryParser, 17 | clientQueryString, 18 | aclRows, 19 | otherParams, 20 | textQuery 21 | ) { 22 | const mongoQuery = { 23 | $and: [], 24 | } 25 | 26 | if (clientQueryString) { 27 | const clientQuery = JSON.parse(clientQueryString) 28 | mongoQuery.$and.push(clientQuery) 29 | } 30 | if (otherParams) { 31 | for (const key of Object.keys(otherParams)) { 32 | const value = otherParams[key] 33 | mongoQuery.$and.push({ [key]: value }) 34 | } 35 | } 36 | 37 | if (aclRows) { 38 | if (Array.isArray(aclRows)) { 39 | mongoQuery.$and.push({ $and: aclRows }) 40 | } else { 41 | mongoQuery.$and.push(aclRows) 42 | } 43 | } 44 | 45 | try { 46 | if (textQuery) { 47 | queryParser.parseAndCastTextSearchQuery(mongoQuery) 48 | } else { 49 | queryParser.parseAndCast(mongoQuery) 50 | } 51 | } catch (error) { 52 | throw new BadRequestError(error.message) 53 | } 54 | 55 | if (!mongoQuery.$and.length) { 56 | return {} 57 | } 58 | 59 | return mongoQuery 60 | } 61 | 62 | module.exports = resolveMongoQuery 63 | -------------------------------------------------------------------------------- /lib/transformers/csv.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 'use strict' 17 | 18 | const csvParse = require('csv-parse') 19 | const csvStringify = require('csv-stringify') 20 | 21 | const QUOTE_CHAR = '"' 22 | 23 | module.exports = (parsingOptions) => ({ 24 | stringifier: ({ fields }) => [csvStringify.stringify({ 25 | encoding: 'utf8', 26 | delimiter: ',', 27 | escape: QUOTE_CHAR, 28 | header: true, 29 | quote: QUOTE_CHAR, 30 | quoted_string: true, 31 | ...parsingOptions, 32 | columns: fields, 33 | cast: { 34 | object: (value) => { 35 | try { 36 | return { value: JSON.stringify(value), quote: true } 37 | } catch (errs) { 38 | return value 39 | } 40 | }, 41 | }, 42 | })], 43 | parser: () => csvParse.parse({ 44 | encoding: 'utf8', 45 | bom: true, 46 | delimiter: ',', 47 | columns: true, 48 | skip_empty_lines: true, 49 | relax_quotes: true, 50 | escape: '\\', 51 | ...parsingOptions, 52 | cast: (value) => { 53 | try { 54 | return JSON.parse(value) 55 | } catch (errs) { 56 | return value 57 | } 58 | }, 59 | }), 60 | }) 61 | -------------------------------------------------------------------------------- /lib/transformers/excel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 'use strict' 17 | 18 | const { Transform } = require('stream') 19 | const XLSXTransformStream = require('xlsx-write-stream') 20 | const { formatDataForColumnExport } = require('./utils') 21 | 22 | 23 | module.exports = () => ({ 24 | stringifier: ({ fields }) => { 25 | let headerProcessed = false 26 | const dataTransformer = new Transform({ 27 | transform(chunk, _, callback) { 28 | if (!headerProcessed) { 29 | headerProcessed = true 30 | this.push(fields) 31 | } 32 | 33 | const data = fields.reduce((acc, field) => { 34 | acc.push(formatDataForColumnExport(chunk[field])) 35 | return acc 36 | }, []) 37 | this.push(data) 38 | return callback() 39 | }, 40 | objectMode: true, 41 | }) 42 | const xlsxTransformer = new XLSXTransformStream() 43 | return [dataTransformer, xlsxTransformer] 44 | }, 45 | parser: () => { throw new Error('not implemented') }, 46 | }) 47 | -------------------------------------------------------------------------------- /lib/transformers/json.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 'use strict' 17 | 18 | const JSONStream = require('JSONStream') 19 | 20 | module.exports = () => ({ 21 | stringifier: () => [JSONStream.stringify()], 22 | parser: () => JSONStream.parse('*'), 23 | }) 24 | -------------------------------------------------------------------------------- /lib/transformers/ndjson.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 'use strict' 17 | 18 | const ndjson = require('ndjson') 19 | 20 | module.exports = () => ({ 21 | stringifier: () => [ndjson.stringify()], 22 | parser: () => ndjson.parse(), 23 | }) 24 | -------------------------------------------------------------------------------- /lib/transformers/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | formatDataForColumnExport: data => { 5 | if (!data) { 6 | return '' 7 | } 8 | 9 | return typeof data === 'object' 10 | ? JSON.stringify(data) 11 | : data 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /lib/validatorGetters.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { default: Ajv } = require('ajv') 20 | const ajvFormats = require('ajv-formats') 21 | const ajvKeywords = require('ajv-keywords') 22 | const { SCHEMA_CUSTOM_KEYWORDS } = require('./consts') 23 | const through2 = require('through2') 24 | 25 | /** 26 | * @param {Ajv} ajv 27 | */ 28 | function decorateAjv(ajv) { 29 | ajvFormats(ajv) 30 | ajvKeywords(ajv, 'instanceof') 31 | ajv.addVocabulary(Object.values(SCHEMA_CUSTOM_KEYWORDS)) 32 | } 33 | 34 | /** 35 | * @type {Ajv} 36 | */ 37 | const ajvSerializer = new Ajv({ 38 | coerceTypes: true, 39 | useDefaults: true, 40 | removeAdditional: true, 41 | allowUnionTypes: true, 42 | }) 43 | 44 | 45 | /** 46 | * @type {Ajv} 47 | */ 48 | const ajvWithAdditionalProperties = new Ajv({ 49 | coerceTypes: true, 50 | useDefaults: true, 51 | removeAdditional: false, 52 | allowUnionTypes: true, 53 | }) 54 | 55 | decorateAjv(ajvWithAdditionalProperties) 56 | decorateAjv(ajvSerializer) 57 | 58 | function getAjvResponseValidationFunction(schema, additionalProperties = false) { 59 | // We need this custom validator to remove properties without breaking other tests and avoid 60 | // unwanted behaviors 61 | return additionalProperties ? ajvWithAdditionalProperties.compile(schema) : ajvSerializer.compile(schema) 62 | } 63 | 64 | function validateStream(validate) { 65 | return through2.obj((chunk, _, callback) => { 66 | validate(chunk) 67 | callback(validate.errors, chunk) 68 | }) 69 | } 70 | 71 | function shouldValidateStream(schema, shouldValidate) { 72 | if (shouldValidate) { 73 | const validate = getAjvResponseValidationFunction(schema) 74 | return () => validateStream(validate) 75 | } 76 | } 77 | 78 | function shouldValidateItem(schema, shouldValidate) { 79 | if (shouldValidate) { 80 | const validate = getAjvResponseValidationFunction(schema) 81 | return item => validate(item) 82 | } 83 | } 84 | 85 | /** 86 | * 87 | * @returns {Ajv} 88 | */ 89 | function getAjvValidator() { 90 | return new Ajv({ 91 | coerceTypes: true, 92 | useDefaults: true, 93 | allowUnionTypes: true, 94 | // allow properties and pattern properties to overlap -> this should help validating nested fields 95 | allowMatchingProperties: true, 96 | }) 97 | } 98 | 99 | module.exports = { 100 | getAjvResponseValidationFunction, 101 | validateStream, 102 | shouldValidateStream, 103 | shouldValidateItem, 104 | decorateAjv, 105 | ajvSerializer, 106 | getAjvValidator, 107 | } 108 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mia-platform/crud-service", 3 | "version": "7.2.3", 4 | "description": "HTTP interface to perform CRUD operations on MongoDB collections defined in the API Console", 5 | "homepage": "https://www.mia-platform.eu/", 6 | "bugs": { 7 | "url": "https://github.com/mia-platform/crud-service/issues" 8 | }, 9 | "license": "Apache-2.0", 10 | "author": "Mia Platform Fast Data Team", 11 | "main": "index.js", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/mia-platform/crud-service" 15 | }, 16 | "scripts": { 17 | "bench:queryParser": "node bench/queryParser.bench.js", 18 | "bench:init": "docker compose -f bench/docker-compose.yml up -d --force-recreate && node bench/utils/generate-customer-data.js", 19 | "checkonly": "! grep -r '\\.only' tests/", 20 | "coverage": "npm run unit -- --jobs=4", 21 | "postcoverage": "tap report --coverage-report=lcovonly --coverage-report=text-summary", 22 | "lint": "eslint .", 23 | "start": "lc39 index.js", 24 | "start:local": "set -a && . ./local.env && lc39 index.js", 25 | "pretest": "node tests/generatedJSONSchemasToFiles.js && eslint --fix tests/expectedSchemas/*.js", 26 | "test": "npm run lint && npm run unit -- --disable-coverage && npm run checkonly", 27 | "unit": "MONGO_HOST=${MONGO_HOST_CI:-127.0.0.1} MONGO_VERSION=${MONGO_VERSION:-6.0.2} CRYPT_SHARED_LIB_PATH=${CRYPT_SHARED_LIB_PATH:-.local/lib/mongo_crypt_v1.so} tap -b --allow-incomplete-coverage 'tests/**/*.test.js'", 28 | "update-changelog": "node ./scripts/update-changelog.js ${npm_package_version}", 29 | "version": "npm run update-changelog && git add CHANGELOG.md" 30 | }, 31 | "dependencies": { 32 | "@fastify/env": "^4.4.0", 33 | "@fastify/mongodb": "^8.0.0", 34 | "@fastify/multipart": "^8.3.0", 35 | "@mia-platform/lc39": "^8.0.2", 36 | "@mia-platform/mongodb-healthchecker": "^1.0.1", 37 | "ajv-formats": "^3.0.1", 38 | "ajv-keywords": "^5.1.0", 39 | "csv-parse": "^5.6.0", 40 | "csv-stringify": "^6.5.2", 41 | "fastify-plugin": "^4.5.1", 42 | "jsonpath-plus": "^9.0.0", 43 | "JSONStream": "^1.3.5", 44 | "lodash": "^4.17.21", 45 | "mongodb-client-encryption": "^6.4.0", 46 | "ndjson": "^2.0.0", 47 | "p-limit": "^6.2.0", 48 | "pino": "^9.7.0", 49 | "through2": "^4.0.2", 50 | "xlsx-write-stream": "^1.0.3" 51 | }, 52 | "peerDependencies": { 53 | "ajv": "^8.17.1", 54 | "fast-json-stringify": "^6.0.1", 55 | "fastify": "^4.29.0", 56 | "mongodb": "^6.16.0" 57 | }, 58 | "devDependencies": { 59 | "@eslint/js": "^9.27.0", 60 | "@faker-js/faker": "^9.8.0", 61 | "@mia-platform/eslint-config-mia": "^3.0.0", 62 | "abstract-logging": "^2.0.1", 63 | "commander": "^14.0.0", 64 | "eslint": "^9.27.0", 65 | "eslint-plugin-n": "^17.18.0", 66 | "fastbench": "^1.0.1", 67 | "form-data": "^4.0.2", 68 | "globals": "^16.2.0", 69 | "mock-require": "^3.0.3", 70 | "node-xlsx": "^0.24.0", 71 | "tap": "^21.1.0", 72 | "uuid-validate": "0.0.3" 73 | }, 74 | "engines": { 75 | "node": ">=v20" 76 | }, 77 | "private": true, 78 | "tap": { 79 | "timeout": 240, 80 | "allow-incomplete-coverage": true, 81 | "allow-empty-coverage": true 82 | }, 83 | "nyc": { 84 | "include": [ 85 | "lib/**/*.js", 86 | "*.js" 87 | ] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /scripts/update-changelog.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { join } = require('path') 20 | const { readFileSync, writeFileSync } = require('fs') 21 | 22 | function getISODateStringFrom(aJSDate) { 23 | return aJSDate 24 | .toISOString() 25 | .split('T') 26 | .shift() 27 | } 28 | 29 | function getNewContentForCHANGELOG({ aSemVerString, anISODateString }) { 30 | return `[Unreleased]\n\n## ${aSemVerString} - ${anISODateString}` 31 | } 32 | 33 | const CHANGELOG_PATH = join(__dirname, '../CHANGELOG.md') 34 | 35 | let changelog = readFileSync(CHANGELOG_PATH, { encoding: 'utf-8' }) 36 | 37 | changelog = changelog.replace('[Unreleased]', getNewContentForCHANGELOG({ 38 | aSemVerString: process.argv[2], 39 | anISODateString: getISODateStringFrom(new Date()), 40 | })) 41 | 42 | writeFileSync(CHANGELOG_PATH, changelog) 43 | -------------------------------------------------------------------------------- /tap-snapshots/tests/transformSchemaForSwagger.test.js.test.cjs: -------------------------------------------------------------------------------- 1 | /* IMPORTANT 2 | * This snapshot file is auto-generated, but designed for humans. 3 | * It should be checked into source control and tracked carefully. 4 | * Re-generate by setting TAP_SNAPSHOT=1 and running tests. 5 | * Make sure to inspect the output below. Do not ignore changes! 6 | */ 7 | 'use strict' 8 | exports[`tests/transformSchemaForSwagger.test.js > TAP > transformSchemaForSwagger > remove unique id from schema > must match snapshot 1`] = ` 9 | { 10 | "summary": "Update an item of the books collection by ID", 11 | "tags": [ 12 | "Books Endpoint" 13 | ], 14 | "params": { 15 | "type": "object", 16 | "properties": { 17 | "id": { 18 | "type": "string", 19 | "description": "the doc _id" 20 | } 21 | } 22 | }, 23 | "body": { 24 | "type": "object", 25 | "properties": { 26 | "foo": { 27 | "type": "string" 28 | } 29 | }, 30 | "additionalProperties": false 31 | }, 32 | "querystring": { 33 | "type": "object", 34 | "properties": { 35 | "name": { 36 | "type": "string", 37 | "description": "The name of the book" 38 | } 39 | }, 40 | "patternProperties": { 41 | "metadata\\\\.somethingArrayObject\\\\.\\\\d+\\\\..+$$": true 42 | }, 43 | "additionalProperties": false 44 | }, 45 | "response": { 46 | "200": { 47 | "type": "object", 48 | "properties": { 49 | "_id": { 50 | "type": "string", 51 | "examples": [ 52 | "000000000000000000000000" 53 | ], 54 | "pattern": "^[a-fA-F\\\\d]{24}$", 55 | "description": "Hexadecimal identifier of the document in the collection" 56 | } 57 | } 58 | } 59 | } 60 | } 61 | ` 62 | -------------------------------------------------------------------------------- /tests/CrudService.utils.test.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2023 Mia s.r.l. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict' 19 | 20 | const tap = require('tap') 21 | const { STATES, __STATE__ } = require('../lib/consts') 22 | const { getStateQuery } = require('../lib/CrudService.utils') 23 | 24 | tap.test('crudService utils', async test => { 25 | test.test('getStateQuery', async t => { 26 | t.test('one state returns basic query', async assert => { 27 | const mockStates = [STATES.DRAFT] 28 | const queryResult = getStateQuery(mockStates) 29 | assert.strictSame(queryResult, { [__STATE__]: STATES.DRAFT }) 30 | }) 31 | 32 | t.test('empty array returns default query', async assert => { 33 | const mockStates = [] 34 | const queryResult = getStateQuery(mockStates) 35 | assert.strictSame(queryResult, { [__STATE__]: STATES.PUBLIC }) 36 | }) 37 | 38 | t.test('more states returns $in query', async assert => { 39 | const mockStates = [STATES.PUBLIC, STATES.DELETED] 40 | const queryResult = getStateQuery(mockStates) 41 | assert.strictSame(queryResult, { [__STATE__]: { $in: [STATES.PUBLIC, STATES.DELETED] } }) 42 | }) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/address_statistics.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'address-statistics', 21 | endpointBasePath: '/address-statistics-endpoint', 22 | defaultState: 'DRAFT', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'addressId', 31 | type: 'ObjectId', 32 | description: 'The address to refer to', 33 | required: true, 34 | }, 35 | { 36 | name: 'count', 37 | type: 'number', 38 | description: '--', 39 | required: true, 40 | }, 41 | { 42 | name: 'tag', 43 | type: 'string', 44 | description: 'The tag', 45 | required: true, 46 | }, 47 | { 48 | name: 'updaterId', 49 | type: 'string', 50 | description: 'User id that has requested the last change successfully', 51 | required: true, 52 | }, 53 | { 54 | name: 'updatedAt', 55 | type: 'Date', 56 | description: 'Date of the request that has performed the last change', 57 | required: true, 58 | }, 59 | { 60 | name: 'creatorId', 61 | type: 'string', 62 | description: 'User id that has created this object', 63 | required: true, 64 | }, 65 | { 66 | name: 'createdAt', 67 | type: 'Date', 68 | description: 'Date of the request that has performed the object creation', 69 | required: true, 70 | }, 71 | { 72 | name: '__STATE__', 73 | type: 'string', 74 | description: 'The state of the document', 75 | required: true, 76 | }, 77 | ], 78 | indexes: [], 79 | } 80 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/addresses.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'addresses', 21 | endpointBasePath: '/addresses-endpoint', 22 | defaultState: 'DRAFT', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'displayName', 31 | type: 'string', 32 | description: 'The display name', 33 | required: true, 34 | }, 35 | { 36 | name: 'street', 37 | type: 'string', 38 | description: 'The street of the house', 39 | required: true, 40 | }, 41 | { 42 | name: 'house_number', 43 | type: 'string', 44 | description: 'The number of the house', 45 | required: true, 46 | }, 47 | { 48 | name: 'updaterId', 49 | type: 'string', 50 | description: 'User id that has requested the last change successfully', 51 | required: true, 52 | }, 53 | { 54 | name: 'updatedAt', 55 | type: 'Date', 56 | description: 'Date of the request that has performed the last change', 57 | required: true, 58 | }, 59 | { 60 | name: 'creatorId', 61 | type: 'string', 62 | description: 'User id that has created this object', 63 | required: true, 64 | }, 65 | { 66 | name: 'createdAt', 67 | type: 'Date', 68 | description: 'Date of the request that has performed the object creation', 69 | required: true, 70 | }, 71 | { 72 | name: '__STATE__', 73 | type: 'string', 74 | description: 'The state of the document', 75 | required: true, 76 | }, 77 | ], 78 | indexes: [], 79 | } 80 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/animals.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'animals', 21 | endpointBasePath: '/animals-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'name', 61 | type: 'string', 62 | required: true, 63 | nullable: false, 64 | }, 65 | { 66 | name: 'family', 67 | type: 'string', 68 | required: true, 69 | nullable: false, 70 | }, 71 | { 72 | name: 'specie', 73 | type: 'string', 74 | required: true, 75 | nullable: false, 76 | }, 77 | { 78 | name: 'weight', 79 | type: 'number', 80 | required: true, 81 | nullable: false, 82 | }, 83 | ], 84 | indexes: [ 85 | { 86 | name: '_id', 87 | type: 'normal', 88 | unique: true, 89 | fields: [ 90 | { 91 | name: '_id', 92 | order: 1, 93 | }, 94 | ], 95 | }, 96 | { 97 | name: 'createdAt', 98 | type: 'normal', 99 | unique: false, 100 | fields: [ 101 | { 102 | name: 'createdAt', 103 | order: -1, 104 | }, 105 | ], 106 | }, 107 | ], 108 | } 109 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/canines.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'canines', 21 | endpointBasePath: '/canines-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'string', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'name', 61 | type: 'string', 62 | required: true, 63 | nullable: false, 64 | }, 65 | { 66 | name: 'weight', 67 | type: 'number', 68 | required: true, 69 | nullable: false, 70 | }, 71 | ], 72 | source: 'animals', 73 | type: 'view', 74 | pipeline: [ 75 | { 76 | $match: { family: 'canines' }, 77 | }, 78 | { 79 | $project: { 80 | _id: 1, 81 | name: 1, 82 | updaterId: 1, 83 | updatedAt: 1, 84 | creatorId: 1, 85 | createdAt: 1, 86 | weight: 1, 87 | __STATE__: 1, 88 | }, 89 | }, 90 | ], 91 | } 92 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/cars.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'cars', 21 | endpointBasePath: '/cars-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'name', 31 | type: 'string', 32 | description: 'The car\'s name', 33 | required: true, 34 | }, 35 | { 36 | name: 'price', 37 | type: 'number', 38 | description: 'The car\'s price', 39 | required: false, 40 | }, 41 | { 42 | name: 'position', 43 | type: 'GeoPoint', 44 | description: 'The car\'s position', 45 | required: false, 46 | }, 47 | { 48 | name: 'additionalInfo', 49 | type: 'RawObject', 50 | required: false, 51 | }, 52 | { 53 | name: 'updaterId', 54 | type: 'string', 55 | description: 'User id that has requested the last change successfully', 56 | required: true, 57 | }, 58 | { 59 | name: 'updatedAt', 60 | type: 'Date', 61 | description: 'Date of the request that has performed the last change', 62 | required: true, 63 | }, 64 | { 65 | name: 'creatorId', 66 | type: 'string', 67 | description: 'User id that has created this object', 68 | required: true, 69 | }, 70 | { 71 | name: 'createdAt', 72 | type: 'Date', 73 | description: 'Date of the request that has performed the object creation', 74 | required: true, 75 | }, 76 | { 77 | name: '__STATE__', 78 | type: 'string', 79 | description: 'The state of the document', 80 | required: true, 81 | }, 82 | ], 83 | indexes: [ 84 | { 85 | name: 'nameUnique', 86 | type: 'normal', 87 | unique: true, 88 | fields: [ 89 | { 90 | name: 'name', 91 | order: 1, 92 | }, 93 | ], 94 | }, 95 | { 96 | name: 'priceIndex', 97 | type: 'normal', 98 | unique: false, 99 | fields: [ 100 | { 101 | name: 'price', 102 | order: 1, 103 | }, 104 | ], 105 | }, 106 | { 107 | name: 'positionIndex', 108 | type: 'geo', 109 | unique: false, 110 | field: 'position', 111 | }, 112 | { 113 | name: 'ttlIndex', 114 | type: 'normal', 115 | expireAfterSeconds: 100, 116 | unique: false, 117 | fields: [ 118 | { 119 | name: 'createdAt', 120 | order: 1, 121 | }, 122 | ], 123 | }, 124 | ], 125 | } 126 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/felines.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'felines', 21 | endpointBasePath: '/felines-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'string', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'name', 61 | type: 'string', 62 | required: true, 63 | nullable: false, 64 | }, 65 | { 66 | name: 'weight', 67 | type: 'number', 68 | required: true, 69 | nullable: false, 70 | }, 71 | ], 72 | indexes: [ 73 | { 74 | name: '_id', 75 | type: 'normal', 76 | unique: true, 77 | fields: [ 78 | { 79 | name: '_id', 80 | order: 1, 81 | }, 82 | ], 83 | }, 84 | { 85 | name: 'createdAt', 86 | type: 'normal', 87 | unique: false, 88 | fields: [ 89 | { 90 | name: 'createdAt', 91 | order: -1, 92 | }, 93 | ], 94 | }, 95 | ], 96 | } 97 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/films.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'films', 21 | endpointBasePath: '/films-endpoint', 22 | defaultState: 'DRAFT', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'title', 31 | type: 'string', 32 | description: 'The Title of the episode', 33 | required: true, 34 | }, 35 | { 36 | name: 'episode_id', 37 | type: 'number', 38 | description: 'The number of the episode', 39 | required: true, 40 | }, 41 | { 42 | name: 'updaterId', 43 | type: 'string', 44 | description: 'User id that has requested the last change successfully', 45 | required: true, 46 | }, 47 | { 48 | name: 'updatedAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the last change', 51 | required: true, 52 | }, 53 | { 54 | name: 'creatorId', 55 | type: 'string', 56 | description: 'User id that has created this object', 57 | required: true, 58 | }, 59 | { 60 | name: 'createdAt', 61 | type: 'Date', 62 | description: 'Date of the request that has performed the object creation', 63 | required: true, 64 | }, 65 | { 66 | name: '__STATE__', 67 | type: 'string', 68 | description: 'The state of the document', 69 | required: true, 70 | }, 71 | ], 72 | indexes: [], 73 | } 74 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/items.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'items', 21 | endpointBasePath: '/items-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'name', 61 | type: 'string', 62 | required: true, 63 | nullable: false, 64 | }, 65 | { 66 | name: 'rating', 67 | type: 'number', 68 | required: false, 69 | nullable: true, 70 | }, 71 | ], 72 | indexes: [ 73 | { 74 | name: '_id', 75 | type: 'normal', 76 | unique: true, 77 | fields: [ 78 | { 79 | name: '_id', 80 | order: 1, 81 | }, 82 | ], 83 | }, 84 | { 85 | name: 'createdAt', 86 | type: 'normal', 87 | unique: false, 88 | fields: [ 89 | { 90 | name: 'createdAt', 91 | order: -1, 92 | }, 93 | ], 94 | }, 95 | ], 96 | } 97 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/orders-details.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'orders-details', 21 | endpointBasePath: '/orders-details-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'rider', 61 | type: 'RawObject', 62 | schema: { 63 | properties: { 64 | value: { 65 | type: 'string', 66 | __mia_configuration: { 67 | type: 'ObjectId', 68 | }, 69 | }, 70 | label: { type: 'string' }, 71 | }, 72 | }, 73 | additionalProperties: false, 74 | required: true, 75 | nullable: false, 76 | }, 77 | { 78 | name: 'items', 79 | type: 'Array', 80 | items: { 81 | type: 'ObjectId', 82 | }, 83 | description: 'The item to deliver to the customer', 84 | required: true, 85 | nullable: false, 86 | }, 87 | { 88 | name: 'paid', 89 | type: 'boolean', 90 | description: 'Whether the order has been payed', 91 | required: false, 92 | nullable: true, 93 | }, 94 | ], 95 | indexes: [ 96 | { 97 | name: '_id', 98 | type: 'normal', 99 | unique: true, 100 | fields: [ 101 | { 102 | name: '_id', 103 | order: 1, 104 | }, 105 | ], 106 | }, 107 | { 108 | name: 'createdAt', 109 | type: 'normal', 110 | unique: false, 111 | fields: [ 112 | { 113 | name: 'createdAt', 114 | order: -1, 115 | }, 116 | ], 117 | }, 118 | ], 119 | } 120 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/orders-items.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'orders-items', 21 | endpointBasePath: '/orders-items-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'items', 61 | type: 'Array', 62 | items: { 63 | type: 'RawObject', 64 | schema: { 65 | properties: { 66 | value: { 67 | type: 'string', 68 | }, 69 | label: { type: 'string' }, 70 | }, 71 | }, 72 | }, 73 | additionalProperties: false, 74 | required: false, 75 | nullable: true, 76 | }, 77 | { 78 | name: 'paid', 79 | type: 'boolean', 80 | description: 'Whether the order has been payed', 81 | required: false, 82 | nullable: true, 83 | }, 84 | ], 85 | indexes: [ 86 | { 87 | name: '_id', 88 | type: 'normal', 89 | unique: true, 90 | fields: [ 91 | { 92 | name: '_id', 93 | order: 1, 94 | }, 95 | ], 96 | }, 97 | { 98 | name: 'createdAt', 99 | type: 'normal', 100 | unique: false, 101 | fields: [ 102 | { 103 | name: 'createdAt', 104 | order: -1, 105 | }, 106 | ], 107 | }, 108 | ], 109 | } 110 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/orders.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'orders', 21 | endpointBasePath: '/orders-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'id_rider', 61 | type: 'ObjectId', 62 | description: 'The id of the rider who will deliver the items', 63 | required: true, 64 | nullable: false, 65 | }, 66 | { 67 | name: 'items', 68 | type: 'Array', 69 | items: { 70 | type: 'string', 71 | }, 72 | description: 'The id of items to deliver to the customer', 73 | required: true, 74 | nullable: false, 75 | }, 76 | { 77 | name: 'paid', 78 | type: 'boolean', 79 | description: 'Whether the order has been payed', 80 | required: false, 81 | nullable: true, 82 | }, 83 | ], 84 | indexes: [ 85 | { 86 | name: '_id', 87 | type: 'normal', 88 | unique: true, 89 | fields: [ 90 | { 91 | name: '_id', 92 | order: 1, 93 | }, 94 | ], 95 | }, 96 | { 97 | name: 'createdAt', 98 | type: 'normal', 99 | unique: false, 100 | fields: [ 101 | { 102 | name: 'createdAt', 103 | order: -1, 104 | }, 105 | ], 106 | }, 107 | ], 108 | } 109 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/people.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'people', 21 | endpointBasePath: '/people-endpoint', 22 | defaultState: 'DRAFT', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'name', 31 | type: 'string', 32 | description: 'The name of the guy', 33 | required: true, 34 | }, 35 | { 36 | name: 'height', 37 | type: 'number', 38 | description: 'The height of the guy', 39 | required: true, 40 | }, 41 | { 42 | name: 'films', 43 | type: 'Array', 44 | items: { 45 | type: 'ObjectId', 46 | }, 47 | description: 'Films where the guy appears', 48 | required: false, 49 | }, 50 | { 51 | name: 'updaterId', 52 | type: 'string', 53 | description: 'User id that has requested the last change successfully', 54 | required: true, 55 | }, 56 | { 57 | name: 'updatedAt', 58 | type: 'Date', 59 | description: 'Date of the request that has performed the last change', 60 | required: true, 61 | }, 62 | { 63 | name: 'creatorId', 64 | type: 'string', 65 | description: 'User id that has created this object', 66 | required: true, 67 | }, 68 | { 69 | name: 'createdAt', 70 | type: 'Date', 71 | description: 'Date of the request that has performed the object creation', 72 | required: true, 73 | }, 74 | { 75 | name: '__STATE__', 76 | type: 'string', 77 | description: 'The state of the document', 78 | required: true, 79 | }, 80 | ], 81 | indexes: [ 82 | ], 83 | } 84 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/riders.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'riders', 21 | endpointBasePath: '/riders-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'updaterId', 31 | type: 'string', 32 | description: 'User id that has requested the last change successfully', 33 | required: true, 34 | }, 35 | { 36 | name: 'updatedAt', 37 | type: 'Date', 38 | description: 'Date of the request that has performed the last change', 39 | required: true, 40 | }, 41 | { 42 | name: 'creatorId', 43 | type: 'string', 44 | description: 'User id that has created this object', 45 | required: true, 46 | }, 47 | { 48 | name: 'createdAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the object creation', 51 | required: true, 52 | }, 53 | { 54 | name: '__STATE__', 55 | type: 'string', 56 | description: 'The state of the document', 57 | required: true, 58 | }, 59 | { 60 | name: 'name', 61 | type: 'string', 62 | required: true, 63 | nullable: false, 64 | }, 65 | { 66 | name: 'surname', 67 | type: 'string', 68 | required: true, 69 | nullable: false, 70 | }, 71 | ], 72 | indexes: [ 73 | { 74 | name: '_id', 75 | type: 'normal', 76 | unique: true, 77 | fields: [ 78 | { 79 | name: '_id', 80 | order: 1, 81 | }, 82 | ], 83 | }, 84 | { 85 | name: 'createdAt', 86 | type: 'normal', 87 | unique: false, 88 | fields: [ 89 | { 90 | name: 'createdAt', 91 | order: -1, 92 | }, 93 | ], 94 | }, 95 | ], 96 | } 97 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/store-open.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'store-open', 21 | endpointBasePath: '/store-open-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'name', 31 | type: 'string', 32 | description: 'The name of the store', 33 | required: true, 34 | }, 35 | { 36 | name: 'address', 37 | type: 'string', 38 | description: 'The complete address of the store', 39 | required: true, 40 | }, 41 | { 42 | name: 'updaterId', 43 | type: 'string', 44 | description: 'User id that has requested the last change successfully', 45 | required: true, 46 | }, 47 | { 48 | name: 'updatedAt', 49 | type: 'Date', 50 | description: 'Date of the request that has performed the last change', 51 | required: true, 52 | }, 53 | { 54 | name: 'creatorId', 55 | type: 'string', 56 | description: 'User id that has created this object', 57 | required: true, 58 | }, 59 | { 60 | name: 'createdAt', 61 | type: 'Date', 62 | description: 'Date of the request that has performed the object creation', 63 | required: true, 64 | }, 65 | { 66 | name: '__STATE__', 67 | type: 'string', 68 | description: 'The state of the document', 69 | required: true, 70 | }, 71 | ], 72 | indexes: [ 73 | ], 74 | } 75 | -------------------------------------------------------------------------------- /tests/collectionDefinitions/store.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'store', 21 | endpointBasePath: '/store-endpoint', 22 | defaultState: 'PUBLIC', 23 | fields: [ 24 | { 25 | name: '_id', 26 | type: 'ObjectId', 27 | required: true, 28 | }, 29 | { 30 | name: 'name', 31 | type: 'string', 32 | description: 'The name of the store', 33 | required: true, 34 | }, 35 | { 36 | name: 'address', 37 | type: 'string', 38 | description: 'The complete address of the store', 39 | required: true, 40 | }, 41 | { 42 | name: 'currentlyWorking', 43 | type: 'boolean', 44 | description: 'Whether the store is open or not', 45 | required: true, 46 | }, 47 | { 48 | name: 'managerId', 49 | type: 'string', 50 | description: 'Identifier of the manager', 51 | required: true, 52 | }, 53 | { 54 | name: 'updaterId', 55 | type: 'string', 56 | description: 'User id that has requested the last change successfully', 57 | required: true, 58 | }, 59 | { 60 | name: 'updatedAt', 61 | type: 'Date', 62 | description: 'Date of the request that has performed the last change', 63 | required: true, 64 | }, 65 | { 66 | name: 'creatorId', 67 | type: 'string', 68 | description: 'User id that has created this object', 69 | required: true, 70 | }, 71 | { 72 | name: 'createdAt', 73 | type: 'Date', 74 | description: 'Date of the request that has performed the object creation', 75 | required: true, 76 | }, 77 | { 78 | name: '__STATE__', 79 | type: 'string', 80 | description: 'The state of the document', 81 | required: true, 82 | }, 83 | ], 84 | indexes: [ 85 | ], 86 | } 87 | -------------------------------------------------------------------------------- /tests/compilers.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | const Fastify = require('fastify') 21 | const { addValidatorCompiler } = require('../lib/compilers') 22 | const books = require('./collectionDefinitions/books') 23 | const loadModels = require('../lib/loadModels') 24 | const { getMongoDatabaseName, getMongoURL } = require('./utils') 25 | const { registerMongoInstances } = require('../lib/mongo/mongo-plugin') 26 | const { SCHEMAS_ID } = require('../lib/schemaGetters') 27 | 28 | 29 | const SCHEMA_CUSTOM_KEYWORDS = { 30 | UNIQUE_OPERATION_ID: 'operationId', 31 | } 32 | 33 | tap.test('compilers', async(t) => { 34 | const databaseName = getMongoDatabaseName() 35 | 36 | t.test('validator compiler should extract property correctly without collisions', async t => { 37 | const fastify = Fastify() 38 | 39 | t.teardown(async() => fastify.close()) 40 | 41 | fastify.decorate('config', { MONGODB_URL: getMongoURL(databaseName) }) 42 | fastify.decorate('collections', [books]) 43 | fastify.decorate('modelName', 'books-endpoint') 44 | await registerMongoInstances(fastify) 45 | 46 | 47 | await loadModels(fastify) 48 | 49 | //* here i add a fake model to test collision 50 | // eslint-disable-next-line require-atomic-updates 51 | fastify.models['books-endpoint-2'] = {} 52 | 53 | addValidatorCompiler(fastify, fastify.models, { HELPERS_PREFIX: '/helpers' }) 54 | 55 | const schema = { 56 | [SCHEMA_CUSTOM_KEYWORDS.UNIQUE_OPERATION_ID]: `books__MIA__${SCHEMAS_ID.POST_ITEM}__MIA__response.200`, 57 | type: 'object', 58 | properties: { 59 | id: { 60 | type: 'string', 61 | }, 62 | }, 63 | required: ['id'], 64 | } 65 | 66 | const url = '/test-url' 67 | 68 | const validationFunc = fastify.validatorCompiler({ schema, url }) 69 | 70 | t.ok(validationFunc, 'Validator function should be created') 71 | t.equal(typeof validationFunc, 'function', 'Validator function should be a function') 72 | //* here we test that post schema from model is recognized correctly. 73 | //* we pass an empty object for ok validation and a wrong formatted _id for ko validation 74 | t.ok(validationFunc({}), 'Validation should return true with invalid obj') 75 | t.notOk(validationFunc({ _id: 'a' }), 'Validation should return false with invalid obj') 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /tests/createConnection.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | const { ObjectId } = require('mongodb') 21 | const { getDatabaseNameByType } = require('../lib/pkFactories') 22 | const { fixtures, stationFixtures } = require('./utils') 23 | const { setUpMultipleCollectionTest } = require('./httpInterface.utils') 24 | 25 | const multipleFixtures = { 26 | books: fixtures, 27 | stations: stationFixtures, 28 | } 29 | 30 | tap.test('Fastify register two different mongo instance', async t => { 31 | const { fastify } = await setUpMultipleCollectionTest(t, multipleFixtures, ['books', 'stations']) 32 | const mongoDbStringCollection = fastify.mongo[getDatabaseNameByType('string')].db.collection('books') 33 | const mongoDbObjectIdCollection = fastify.mongo[getDatabaseNameByType('ObjectId')].db.collection('stations') 34 | 35 | await t.test('Collection exists', async assert => { 36 | assert.ok(mongoDbStringCollection) 37 | assert.ok(mongoDbObjectIdCollection) 38 | assert.end() 39 | }) 40 | 41 | await t.test('The correct pkFactory is used and different ids are generated', async assert => { 42 | const stringIdentifier = 'stringIdentifier' 43 | const objectIdIdentifier = 'objectIdIdentifier' 44 | 45 | await mongoDbStringCollection.insertOne({ testIdentifier: stringIdentifier }) 46 | await mongoDbObjectIdCollection.insertOne({ testIdentifier: objectIdIdentifier }) 47 | 48 | const stringDocument = await mongoDbStringCollection.findOne({ testIdentifier: stringIdentifier }) 49 | const objectIdDocument = await mongoDbObjectIdCollection.findOne({ testIdentifier: objectIdIdentifier }) 50 | 51 | assert.ok(stringDocument) 52 | assert.ok(objectIdDocument) 53 | 54 | assert.throws(() => new ObjectId(stringDocument._id)) 55 | assert.doesNotThrow(() => new ObjectId(objectIdDocument._id)) 56 | assert.end() 57 | }) 58 | }).then() 59 | -------------------------------------------------------------------------------- /tests/emptyCollectionDefinitions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mia-platform/crud-service/643f251055d3e69b20923a4189a3a1cd2000011d/tests/emptyCollectionDefinitions/.gitkeep -------------------------------------------------------------------------------- /tests/emptyViewsDefinitions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mia-platform/crud-service/643f251055d3e69b20923a4189a3a1cd2000011d/tests/emptyViewsDefinitions/.gitkeep -------------------------------------------------------------------------------- /tests/expectedSchemas/carsBulkSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Insert new items in the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'body': { 25 | 'operationId': 'cars__MIA__postBulk__MIA__body', 26 | 'type': 'array', 27 | 'items': { 28 | 'type': 'object', 29 | 'required': [ 30 | 'name', 31 | ], 32 | 'properties': { 33 | 'name': { 34 | 'type': 'string', 35 | 'description': "The car's name", 36 | }, 37 | 'price': { 38 | 'type': 'number', 39 | 'description': "The car's price", 40 | }, 41 | 'position': { 42 | 'type': 'array', 43 | 'items': { 44 | 'type': 'number', 45 | }, 46 | 'minItems': 2, 47 | 'maxItems': 3, 48 | 'description': "The car's position", 49 | }, 50 | 'additionalInfo': { 51 | 'type': 'object', 52 | 'additionalProperties': true, 53 | }, 54 | '__STATE__': { 55 | 'type': 'string', 56 | 'enum': [ 57 | 'PUBLIC', 58 | 'DRAFT', 59 | 'TRASH', 60 | 'DELETED', 61 | ], 62 | 'description': 'The state of the document', 63 | 'default': 'PUBLIC', 64 | }, 65 | }, 66 | 'additionalProperties': false, 67 | }, 68 | }, 69 | 'response': { 70 | '200': { 71 | 'operationId': 'cars__MIA__postBulk__MIA__response.200', 72 | 'type': 'array', 73 | 'items': { 74 | 'type': 'object', 75 | 'properties': { 76 | '_id': { 77 | 'type': 'string', 78 | 'description': 'Hexadecimal identifier of the document in the collection', 79 | 'pattern': '^[a-fA-F\\d]{24}$', 80 | 'example': '000000000000000000000000', 81 | }, 82 | }, 83 | }, 84 | }, 85 | }, 86 | } 87 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsChangeStateManySchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Change state of multiple items of cars.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'body': { 25 | 'operationId': 'cars__MIA__changeStateMany__MIA__body', 26 | 'type': 'array', 27 | 'items': { 28 | 'type': 'object', 29 | 'properties': { 30 | 'filter': { 31 | 'type': 'object', 32 | 'properties': { 33 | '_id': { 34 | 'type': 'string', 35 | 'description': 'Hexadecimal identifier of the document in the collection', 36 | 'pattern': '^[a-fA-F\\d]{24}$', 37 | 'example': '000000000000000000000000', 38 | }, 39 | 'creatorId': { 40 | 'type': 'string', 41 | 'description': 'User id that has created this object', 42 | }, 43 | 'createdAt': { 44 | 'type': 'string', 45 | 'example': '1997-04-24T07:00:00.000Z', 46 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 47 | }, 48 | 'updaterId': { 49 | 'type': 'string', 50 | 'description': 'User id that has requested the last change successfully', 51 | }, 52 | 'updatedAt': { 53 | 'type': 'string', 54 | 'example': '1997-04-24T07:00:00.000Z', 55 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 56 | }, 57 | 'name': { 58 | 'type': 'string', 59 | 'description': "The car's name", 60 | }, 61 | 'price': { 62 | 'type': 'number', 63 | 'description': "The car's price", 64 | }, 65 | 'additionalInfo': { 66 | 'type': 'object', 67 | 'additionalProperties': true, 68 | }, 69 | }, 70 | }, 71 | 'stateTo': { 72 | 'type': 'string', 73 | 'enum': [ 74 | 'PUBLIC', 75 | 'DRAFT', 76 | 'TRASH', 77 | 'DELETED', 78 | ], 79 | }, 80 | }, 81 | 'required': [ 82 | 'filter', 83 | 'stateTo', 84 | ], 85 | 'additionalProperties': false, 86 | }, 87 | 'minItems': 1, 88 | }, 89 | 'response': { 90 | '200': { 91 | 'operationId': 'cars__MIA__changeStateMany__MIA__response.200', 92 | 'type': 'integer', 93 | 'minimum': 0, 94 | 'description': 'Number of updated cars', 95 | }, 96 | }, 97 | } 98 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsChangeStateSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Change state of an item of cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'params': { 25 | 'operationId': 'cars__MIA__changeState__MIA__params', 26 | 'properties': { 27 | 'id': { 28 | 'type': 'string', 29 | 'description': 'the ID of the item to have the property __STATE__ updated', 30 | }, 31 | }, 32 | 'type': 'object', 33 | }, 34 | 'querystring': { 35 | 'operationId': 'cars__MIA__changeState__MIA__querystring', 36 | 'type': 'object', 37 | 'properties': { 38 | 'creatorId': { 39 | 'type': 'string', 40 | 'description': 'User id that has created this object', 41 | }, 42 | 'createdAt': { 43 | 'type': 'string', 44 | 'example': '1997-04-24T07:00:00.000Z', 45 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 46 | }, 47 | 'updaterId': { 48 | 'type': 'string', 49 | 'description': 'User id that has requested the last change successfully', 50 | }, 51 | 'updatedAt': { 52 | 'type': 'string', 53 | 'example': '1997-04-24T07:00:00.000Z', 54 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 55 | }, 56 | 'name': { 57 | 'type': 'string', 58 | 'description': "The car's name", 59 | }, 60 | 'price': { 61 | 'type': 'number', 62 | 'description': "The car's price", 63 | }, 64 | '_q': { 65 | 'type': 'string', 66 | 'description': 'Additional query part to forward to MongoDB', 67 | }, 68 | '_rawp': { 69 | 'type': 'string', 70 | 'description': 'Additional raw stringified projection for MongoDB', 71 | }, 72 | }, 73 | 'additionalProperties': false, 74 | }, 75 | 'body': { 76 | 'operationId': 'cars__MIA__changeState__MIA__body', 77 | 'type': 'object', 78 | 'required': [ 79 | 'stateTo', 80 | ], 81 | 'properties': { 82 | 'stateTo': { 83 | 'type': 'string', 84 | 'enum': [ 85 | 'PUBLIC', 86 | 'TRASH', 87 | 'DRAFT', 88 | 'DELETED', 89 | ], 90 | }, 91 | }, 92 | }, 93 | } 94 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsDeleteListSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Delete multiple items from the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'querystring': { 25 | 'operationId': 'cars__MIA__deleteList__MIA__querystring', 26 | 'type': 'object', 27 | 'properties': { 28 | 'creatorId': { 29 | 'type': 'string', 30 | 'description': 'User id that has created this object', 31 | }, 32 | 'createdAt': { 33 | 'type': 'string', 34 | 'example': '1997-04-24T07:00:00.000Z', 35 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 36 | }, 37 | 'updaterId': { 38 | 'type': 'string', 39 | 'description': 'User id that has requested the last change successfully', 40 | }, 41 | 'updatedAt': { 42 | 'type': 'string', 43 | 'example': '1997-04-24T07:00:00.000Z', 44 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 45 | }, 46 | 'name': { 47 | 'type': 'string', 48 | 'description': "The car's name", 49 | }, 50 | 'price': { 51 | 'type': 'number', 52 | 'description': "The car's price", 53 | }, 54 | '_q': { 55 | 'type': 'string', 56 | 'description': 'Additional query part to forward to MongoDB', 57 | }, 58 | '_st': { 59 | 'type': 'string', 60 | 'pattern': '(PUBLIC|DRAFT|TRASH|DELETED)(,(PUBLIC|DRAFT|TRASH|DELETED))*', 61 | 'default': 'PUBLIC', 62 | 'description': 'Filter by \\_\\_STATE__, multiple states can be specified in OR by providing a comma separated list', 63 | }, 64 | '_rawp': { 65 | 'type': 'string', 66 | 'description': 'Additional raw stringified projection for MongoDB', 67 | }, 68 | }, 69 | 'additionalProperties': false, 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsDeleteSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Delete an item with specific ID from the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'params': { 25 | 'type': 'object', 26 | 'properties': { 27 | 'id': { 28 | 'type': 'string', 29 | 'description': 'The ID of the item to delete', 30 | }, 31 | }, 32 | 'operationId': 'cars__MIA__deleteItem__MIA__params', 33 | }, 34 | 'querystring': { 35 | 'operationId': 'cars__MIA__deleteItem__MIA__querystring', 36 | 'type': 'object', 37 | 'properties': { 38 | 'creatorId': { 39 | 'type': 'string', 40 | 'description': 'User id that has created this object', 41 | }, 42 | 'createdAt': { 43 | 'type': 'string', 44 | 'example': '1997-04-24T07:00:00.000Z', 45 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 46 | }, 47 | 'updaterId': { 48 | 'type': 'string', 49 | 'description': 'User id that has requested the last change successfully', 50 | }, 51 | 'updatedAt': { 52 | 'type': 'string', 53 | 'example': '1997-04-24T07:00:00.000Z', 54 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 55 | }, 56 | 'name': { 57 | 'type': 'string', 58 | 'description': "The car's name", 59 | }, 60 | 'price': { 61 | 'type': 'number', 62 | 'description': "The car's price", 63 | }, 64 | '_q': { 65 | 'type': 'string', 66 | 'description': 'Additional query part to forward to MongoDB', 67 | }, 68 | '_st': { 69 | 'type': 'string', 70 | 'pattern': '(PUBLIC|DRAFT|TRASH|DELETED)(,(PUBLIC|DRAFT|TRASH|DELETED))*', 71 | 'default': 'PUBLIC', 72 | 'description': 'Filter by \\_\\_STATE__, multiple states can be specified in OR by providing a comma separated list', 73 | }, 74 | '_rawp': { 75 | 'type': 'string', 76 | 'description': 'Additional raw stringified projection for MongoDB', 77 | }, 78 | }, 79 | 'additionalProperties': false, 80 | }, 81 | } 82 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsNewBulkSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Insert new items in the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'body': { 25 | 'operationId': 'cars__MIA__postBulk__MIA__body', 26 | 'type': 'array', 27 | 'items': { 28 | 'type': 'object', 29 | 'required': [ 30 | 'name', 31 | ], 32 | 'properties': { 33 | 'name': { 34 | 'type': 'string', 35 | 'description': "The car's name", 36 | }, 37 | 'price': { 38 | 'type': 'number', 39 | 'description': "The car's price", 40 | }, 41 | 'position': { 42 | 'type': 'array', 43 | 'items': { 44 | 'type': 'number', 45 | }, 46 | 'minItems': 2, 47 | 'maxItems': 3, 48 | 'description': "The car's position", 49 | }, 50 | 'additionalInfo': { 51 | 'type': 'object', 52 | 'additionalProperties': true, 53 | }, 54 | '__STATE__': { 55 | 'type': 'string', 56 | 'enum': [ 57 | 'PUBLIC', 58 | 'DRAFT', 59 | 'TRASH', 60 | 'DELETED', 61 | ], 62 | 'description': 'The state of the document', 63 | 'default': 'PUBLIC', 64 | }, 65 | }, 66 | 'additionalProperties': false, 67 | }, 68 | }, 69 | 'response': { 70 | '200': { 71 | 'operationId': 'cars__MIA__postBulk__MIA__response.200', 72 | 'type': 'array', 73 | 'items': { 74 | 'type': 'object', 75 | 'properties': { 76 | '_id': { 77 | 'type': 'string', 78 | 'description': 'Hexadecimal identifier of the document in the collection', 79 | 'pattern': '^[a-fA-F\\d]{24}$', 80 | 'example': '000000000000000000000000', 81 | }, 82 | }, 83 | }, 84 | }, 85 | }, 86 | } 87 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsNewDeleteListSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Delete multiple items from the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'querystring': { 25 | 'operationId': 'cars__MIA__deleteList__MIA__querystring', 26 | 'type': 'object', 27 | 'properties': { 28 | 'creatorId': { 29 | 'type': 'string', 30 | 'description': 'User id that has created this object', 31 | }, 32 | 'createdAt': { 33 | 'type': 'string', 34 | 'example': '1997-04-24T07:00:00.000Z', 35 | 'anyOf': [ 36 | { 37 | 'format': 'date-time', 38 | }, 39 | { 40 | 'format': 'date', 41 | }, 42 | { 43 | 'format': 'time', 44 | }, 45 | ], 46 | }, 47 | 'updaterId': { 48 | 'type': 'string', 49 | 'description': 'User id that has requested the last change successfully', 50 | }, 51 | 'updatedAt': { 52 | 'type': 'string', 53 | 'example': '1997-04-24T07:00:00.000Z', 54 | 'anyOf': [ 55 | { 56 | 'format': 'date-time', 57 | }, 58 | { 59 | 'format': 'date', 60 | }, 61 | { 62 | 'format': 'time', 63 | }, 64 | ], 65 | }, 66 | 'name': { 67 | 'type': 'string', 68 | 'description': "The car's name", 69 | }, 70 | 'price': { 71 | 'type': 'number', 72 | 'description': "The car's price", 73 | }, 74 | '_q': { 75 | 'type': 'string', 76 | 'description': 'Additional query part to forward to MongoDB', 77 | }, 78 | '_st': { 79 | 'type': 'string', 80 | 'pattern': '(PUBLIC|DRAFT|TRASH|DELETED)(,(PUBLIC|DRAFT|TRASH|DELETED))*', 81 | 'default': 'PUBLIC', 82 | 'description': 'Filter by \\_\\_STATE__, multiple states can be specified in OR by providing a comma separated list', 83 | }, 84 | '_rawp': { 85 | 'type': 'string', 86 | 'description': 'Additional raw stringified projection for MongoDB', 87 | }, 88 | }, 89 | 'additionalProperties': false, 90 | }, 91 | } 92 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsNewDeleteSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Delete an item with specific ID from the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'params': { 25 | 'type': 'object', 26 | 'properties': { 27 | 'id': { 28 | 'type': 'string', 29 | 'description': 'The ID of the item to delete', 30 | }, 31 | }, 32 | 'operationId': 'cars__MIA__deleteItem__MIA__params', 33 | }, 34 | 'querystring': { 35 | 'operationId': 'cars__MIA__deleteItem__MIA__querystring', 36 | 'type': 'object', 37 | 'properties': { 38 | 'creatorId': { 39 | 'type': 'string', 40 | 'description': 'User id that has created this object', 41 | }, 42 | 'createdAt': { 43 | 'type': 'string', 44 | 'example': '1997-04-24T07:00:00.000Z', 45 | 'anyOf': [ 46 | { 47 | 'format': 'date-time', 48 | }, 49 | { 50 | 'format': 'date', 51 | }, 52 | { 53 | 'format': 'time', 54 | }, 55 | ], 56 | }, 57 | 'updaterId': { 58 | 'type': 'string', 59 | 'description': 'User id that has requested the last change successfully', 60 | }, 61 | 'updatedAt': { 62 | 'type': 'string', 63 | 'example': '1997-04-24T07:00:00.000Z', 64 | 'anyOf': [ 65 | { 66 | 'format': 'date-time', 67 | }, 68 | { 69 | 'format': 'date', 70 | }, 71 | { 72 | 'format': 'time', 73 | }, 74 | ], 75 | }, 76 | 'name': { 77 | 'type': 'string', 78 | 'description': "The car's name", 79 | }, 80 | 'price': { 81 | 'type': 'number', 82 | 'description': "The car's price", 83 | }, 84 | '_q': { 85 | 'type': 'string', 86 | 'description': 'Additional query part to forward to MongoDB', 87 | }, 88 | '_st': { 89 | 'type': 'string', 90 | 'pattern': '(PUBLIC|DRAFT|TRASH|DELETED)(,(PUBLIC|DRAFT|TRASH|DELETED))*', 91 | 'default': 'PUBLIC', 92 | 'description': 'Filter by \\_\\_STATE__, multiple states can be specified in OR by providing a comma separated list', 93 | }, 94 | '_rawp': { 95 | 'type': 'string', 96 | 'description': 'Additional raw stringified projection for MongoDB', 97 | }, 98 | }, 99 | 'additionalProperties': false, 100 | }, 101 | } 102 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsNewPostSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Add a new item to the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'body': { 25 | 'operationId': 'cars__MIA__postItem__MIA__body', 26 | 'type': 'object', 27 | 'required': [ 28 | 'name', 29 | ], 30 | 'properties': { 31 | 'name': { 32 | 'type': 'string', 33 | 'description': "The car's name", 34 | }, 35 | 'price': { 36 | 'type': 'number', 37 | 'description': "The car's price", 38 | }, 39 | 'position': { 40 | 'type': 'array', 41 | 'items': { 42 | 'type': 'number', 43 | }, 44 | 'minItems': 2, 45 | 'maxItems': 3, 46 | 'description': "The car's position", 47 | }, 48 | 'additionalInfo': { 49 | 'type': 'object', 50 | 'additionalProperties': true, 51 | }, 52 | '__STATE__': { 53 | 'type': 'string', 54 | 'enum': [ 55 | 'PUBLIC', 56 | 'DRAFT', 57 | 'TRASH', 58 | 'DELETED', 59 | ], 60 | 'description': 'The state of the document', 61 | 'default': 'PUBLIC', 62 | }, 63 | }, 64 | 'additionalProperties': false, 65 | }, 66 | 'response': { 67 | '200': { 68 | 'operationId': 'cars__MIA__postItem__MIA__response.200', 69 | 'type': 'object', 70 | 'properties': { 71 | '_id': { 72 | 'type': 'string', 73 | 'description': 'Hexadecimal identifier of the document in the collection', 74 | 'pattern': '^[a-fA-F\\d]{24}$', 75 | 'example': '000000000000000000000000', 76 | }, 77 | }, 78 | }, 79 | }, 80 | } 81 | -------------------------------------------------------------------------------- /tests/expectedSchemas/carsPostSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Add a new item to the cars collection.', 21 | 'tags': [ 22 | 'cars endpoint', 23 | ], 24 | 'body': { 25 | 'operationId': 'cars__MIA__postItem__MIA__body', 26 | 'type': 'object', 27 | 'required': [ 28 | 'name', 29 | ], 30 | 'properties': { 31 | 'name': { 32 | 'type': 'string', 33 | 'description': "The car's name", 34 | }, 35 | 'price': { 36 | 'type': 'number', 37 | 'description': "The car's price", 38 | }, 39 | 'position': { 40 | 'type': 'array', 41 | 'items': { 42 | 'type': 'number', 43 | }, 44 | 'minItems': 2, 45 | 'maxItems': 3, 46 | 'description': "The car's position", 47 | }, 48 | 'additionalInfo': { 49 | 'type': 'object', 50 | 'additionalProperties': true, 51 | }, 52 | '__STATE__': { 53 | 'type': 'string', 54 | 'enum': [ 55 | 'PUBLIC', 56 | 'DRAFT', 57 | 'TRASH', 58 | 'DELETED', 59 | ], 60 | 'description': 'The state of the document', 61 | 'default': 'PUBLIC', 62 | }, 63 | }, 64 | 'additionalProperties': false, 65 | }, 66 | 'response': { 67 | '200': { 68 | 'operationId': 'cars__MIA__postItem__MIA__response.200', 69 | 'type': 'object', 70 | 'properties': { 71 | '_id': { 72 | 'type': 'string', 73 | 'description': 'Hexadecimal identifier of the document in the collection', 74 | 'pattern': '^[a-fA-F\\d]{24}$', 75 | 'example': '000000000000000000000000', 76 | }, 77 | }, 78 | }, 79 | }, 80 | } 81 | -------------------------------------------------------------------------------- /tests/expectedSchemas/stationsPostSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | 'summary': 'Add a new item to the stations collection.', 21 | 'tags': [ 22 | 'stations endpoint', 23 | ], 24 | 'body': { 25 | 'operationId': 'stations__MIA__postItem__MIA__body', 26 | 'type': 'object', 27 | 'properties': { 28 | 'Cap': { 29 | 'type': 'number', 30 | 'nullable': true, 31 | }, 32 | 'CodiceMIR': { 33 | 'type': 'string', 34 | 'nullable': true, 35 | }, 36 | 'Comune': { 37 | 'type': 'string', 38 | 'nullable': true, 39 | }, 40 | 'Direttrici': { 41 | 'type': [ 42 | 'array', 43 | 'string', 44 | 'null', 45 | ], 46 | 'anyOf': [ 47 | { 48 | 'type': 'array', 49 | 'items': { 50 | 'type': 'string', 51 | 'nullable': true, 52 | }, 53 | 'nullable': true, 54 | }, 55 | { 56 | 'type': 'string', 57 | 'nullable': true, 58 | }, 59 | ], 60 | 'nullable': true, 61 | }, 62 | 'Indirizzo': { 63 | 'type': 'string', 64 | 'nullable': true, 65 | }, 66 | 'country': { 67 | 'type': 'string', 68 | 'nullable': true, 69 | }, 70 | 'nonNullableDate': { 71 | 'type': 'string', 72 | 'example': '1997-04-24T07:00:00.000Z', 73 | 'pattern': '^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:\\d{2}))?$', 74 | 'description': '"date-time" according with https://tools.ietf.org/html/rfc3339#section-5.6', 75 | 'nullable': false, 76 | }, 77 | '__STATE__': { 78 | 'type': 'string', 79 | 'enum': [ 80 | 'PUBLIC', 81 | 'DRAFT', 82 | 'TRASH', 83 | 'DELETED', 84 | ], 85 | 'description': 'The state of the document', 86 | 'default': 'DRAFT', 87 | }, 88 | }, 89 | 'additionalProperties': false, 90 | }, 91 | 'response': { 92 | '200': { 93 | 'operationId': 'stations__MIA__postItem__MIA__response.200', 94 | 'type': 'object', 95 | 'properties': { 96 | '_id': { 97 | 'type': 'string', 98 | 'pattern': '^(?!\\s*$).+', 99 | 'description': 'String identifier of the document in the collection', 100 | 'example': '00000000-0000-4000-0000-000000000000', 101 | }, 102 | }, 103 | }, 104 | }, 105 | } 106 | -------------------------------------------------------------------------------- /tests/filesFixtures/bookToUpdate.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "64940bd37955234169667b47", 4 | "name": "Pride and Prejudice", 5 | "author": "Jane Austen", 6 | "authorAddressId": "aaaaaaaaaaaaaaaaaaaaaaab", 7 | "isbn": "Updated ISBN", 8 | "publishDate": "2023-01-01T00:00:00.000Z", 9 | "price": 15.99, 10 | "isPromoted": false, 11 | "position": [ 12 | 10, 13 | 20, 14 | 30.5 15 | ], 16 | "tags": [ 17 | "romance", 18 | "classic" 19 | ], 20 | "tagIds": [ 21 | 2, 22 | 6 23 | ], 24 | "additionalInfo": { 25 | "footnotePages": [ 26 | 10, 27 | 20, 28 | 30, 29 | 40, 30 | 50 31 | ], 32 | "foo": 50, 33 | "notes": { 34 | "mynote": "intriguing" 35 | } 36 | }, 37 | "metadata": { 38 | "somethingNumber": 2, 39 | "somethingString": "meta-string-2", 40 | "somethingArrayObject": [ 41 | { 42 | "arrayItemObjectChildNumber": 5 43 | } 44 | ], 45 | "somethingArrayOfNumbers": [ 46 | 2, 47 | 3 48 | ] 49 | }, 50 | "attachments": [ 51 | { 52 | "name": "attachment-2", 53 | "nestedArr": [ 54 | 4, 55 | 5, 56 | 6 57 | ], 58 | "detail": { 59 | "size": 10 60 | } 61 | }, 62 | { 63 | "name": "attachment-2b", 64 | "other": "extra-info-2b" 65 | } 66 | ], 67 | "editionsDates": [ 68 | { 69 | "edition": 2, 70 | "date": "2019-06-08T00:00:00.000Z" 71 | }, 72 | { 73 | "edition": 1, 74 | "date": "2018-05-01T00:00:00.000Z" 75 | } 76 | ], 77 | "__STATE__": "PUBLIC" 78 | } 79 | ] -------------------------------------------------------------------------------- /tests/filesFixtures/bookToUpdateWithoutState.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "64940bd37955234169667b47", 4 | "name": "Pride and Prejudice", 5 | "author": "Jane Austen", 6 | "authorAddressId": "aaaaaaaaaaaaaaaaaaaaaaab", 7 | "isbn": "Updated ISBN", 8 | "publishDate": "2023-01-01T00:00:00.000Z", 9 | "price": 15.99, 10 | "isPromoted": false, 11 | "position": [ 12 | 10, 13 | 20, 14 | 30.5 15 | ], 16 | "tags": [ 17 | "romance", 18 | "classic" 19 | ], 20 | "tagIds": [ 21 | 2, 22 | 6 23 | ], 24 | "additionalInfo": { 25 | "footnotePages": [ 26 | 10, 27 | 20, 28 | 30, 29 | 40, 30 | 50 31 | ], 32 | "foo": 50, 33 | "notes": { 34 | "mynote": "intriguing" 35 | } 36 | }, 37 | "metadata": { 38 | "somethingNumber": 2, 39 | "somethingString": "meta-string-2", 40 | "somethingArrayObject": [ 41 | { 42 | "arrayItemObjectChildNumber": 5 43 | } 44 | ], 45 | "somethingArrayOfNumbers": [ 46 | 2, 47 | 3 48 | ] 49 | }, 50 | "attachments": [ 51 | { 52 | "name": "attachment-2", 53 | "nestedArr": [ 54 | 4, 55 | 5, 56 | 6 57 | ], 58 | "detail": { 59 | "size": 10 60 | } 61 | }, 62 | { 63 | "name": "attachment-2b", 64 | "other": "extra-info-2b" 65 | } 66 | ], 67 | "editionsDates": [ 68 | { 69 | "edition": 2, 70 | "date": "2019-06-08T00:00:00.000Z" 71 | }, 72 | { 73 | "edition": 1, 74 | "date": "2018-05-01T00:00:00.000Z" 75 | } 76 | ] 77 | } 78 | ] -------------------------------------------------------------------------------- /tests/filesFixtures/books.csv: -------------------------------------------------------------------------------- 1 | "_id","name","author","authorAddressId","isbn","publishDate","price","isPromoted","position","tags","tagIds","tagObjectIds","additionalInfo","metadata","attachments","editionsDates","__STATE__" 2 | "64940bd37955234169667b47","Pride and Prejudice","Jane Austen","aaaaaaaaaaaaaaaaaaaaaaab","fake isbn 2","2023-01-01T00:00:00.000Z",15.99,false,"[10,20,30.5]","[\"romance\",\"classic\"]","[2,6]","[]","{\"footnotePages\":[10,20,30,40,50],\"foo\":50,\"notes\":{\"mynote\":\"intriguing\"}}","{\"somethingNumber\":2,\"somethingString\":\"meta-string-2\",\"somethingArrayObject\":[{\"arrayItemObjectChildNumber\":5}],\"somethingArrayOfNumbers\":[2,3]}","[{\"name\":\"attachment-2\",\"nestedArr\":[4,5,6],\"detail\":{\"size\":10}},{\"name\":\"attachment-2b\",\"other\":\"extra-info-2b\"}]","[{\"edition\":2,\"date\":\"2019-06-08T00:00:00.000Z\"},{\"edition\":1,\"date\":\"2018-05-01T00:00:00.000Z\"}]","PUBLIC" 3 | "64940bdc44b126f8f27108ce","1984","George Orwell","aaaaaaaaaaaaaaaaaaaaaaac","fake isbn 3","2023-02-01T00:00:00.000Z",18.99,true,"[15,25,35.5]","[\"dystopia\",\"classic\"]","[3,7]","[]","{\"footnotePages\":[11,21,31,41,51],\"foo\":51,\"notes\":{\"mynote\":\"terrifying\"}}","{\"somethingNumber\":3,\"somethingString\":\"meta-string-3\",\"somethingArrayObject\":[{\"arrayItemObjectChildNumber\":6}],\"somethingArrayOfNumbers\":[3,4]}","[{\"name\":\"attachment-3\",\"nestedArr\":[5,6,7],\"detail\":{\"size\":11}},{\"name\":\"attachment-3b\",\"other\":\"extra-info-3b\"}]","[{\"edition\":2,\"date\":\"2019-07-08T00:00:00.000Z\"},{\"edition\":1,\"date\":\"2018-06-01T00:00:00.000Z\"}]","PUBLIC" 4 | "64940be3dbb33787acf63b9c","To Kill a Mockingbird","Harper Lee","aaaaaaaaaaaaaaaaaaaaaaad","fake isbn 4","2023-03-01T00:00:00.000Z",20.99,true,"[20,30,40.5]","[\"classic\",\"race\"]","[4,8]","[]","{\"footnotePages\":[15,25,35,45,55],\"foo\":55,\"notes\":{\"mynote\":\"touching\"}}","{\"somethingNumber\":4,\"somethingString\":\"meta-string-4\",\"somethingArrayObject\":[{\"arrayItemObjectChildNumber\":7}],\"somethingArrayOfNumbers\":[4,5]}","[{\"name\":\"attachment-4\",\"nestedArr\":[6,7,8],\"detail\":{\"size\":12}},{\"name\":\"attachment-4b\",\"other\":\"extra-info-4b\"}]","[{\"edition\":2,\"date\":\"2019-08-08T00:00:00.000Z\"},{\"edition\":1,\"date\":\"2018-07-01T00:00:00.000Z\"}]","PUBLIC" -------------------------------------------------------------------------------- /tests/filesFixtures/books.ndjson: -------------------------------------------------------------------------------- 1 | {"_id":"64940bd37955234169667b47","name":"Pride and Prejudice","author":"Jane Austen","authorAddressId":"aaaaaaaaaaaaaaaaaaaaaaab","isbn":"fake isbn 2","publishDate":"2023-01-01T00:00:00.000Z","price":15.99,"isPromoted":false,"position":[10,20,30.5],"tags":["romance","classic"],"tagIds":[2,6],"tagObjectIds":[],"additionalInfo":{"footnotePages":[10,20,30,40,50],"foo":50,"notes":{"mynote":"intriguing"}},"metadata":{"somethingNumber":2,"somethingString":"meta-string-2","somethingArrayObject":[{"arrayItemObjectChildNumber":5}],"somethingArrayOfNumbers":[2,3]},"attachments":[{"name":"attachment-2","nestedArr":[4,5,6],"detail":{"size":10}},{"name":"attachment-2b","other":"extra-info-2b"}],"editionsDates":[{"edition":2,"date":"2019-06-08T00:00:00.000Z"},{"edition":1,"date":"2018-05-01T00:00:00.000Z"}],"__STATE__":"PUBLIC"} 2 | {"_id":"64940bdc44b126f8f27108ce","name":"1984","author":"George Orwell","authorAddressId":"aaaaaaaaaaaaaaaaaaaaaaac","isbn":"fake isbn 3","publishDate":"2023-02-01T00:00:00.000Z","price":18.99,"isPromoted":true,"position":[15,25,35.5],"tags":["dystopia","classic"],"tagIds":[3,7],"tagObjectIds":[],"additionalInfo":{"footnotePages":[11,21,31,41,51],"foo":51,"notes":{"mynote":"terrifying"}},"metadata":{"somethingNumber":3,"somethingString":"meta-string-3","somethingArrayObject":[{"arrayItemObjectChildNumber":6}],"somethingArrayOfNumbers":[3,4]},"attachments":[{"name":"attachment-3","nestedArr":[5,6,7],"detail":{"size":11}},{"name":"attachment-3b","other":"extra-info-3b"}],"editionsDates":[{"edition":2,"date":"2019-07-08T00:00:00.000Z"},{"edition":1,"date":"2018-06-01T00:00:00.000Z"}],"__STATE__":"PUBLIC"} 3 | {"_id":"64940be3dbb33787acf63b9c","name":"To Kill a Mockingbird","author":"Harper Lee","authorAddressId":"aaaaaaaaaaaaaaaaaaaaaaad","isbn":"fake isbn 4","publishDate":"2023-03-01T00:00:00.000Z","price":20.99,"isPromoted":true,"position":[20,30,40.5],"tags":["classic","race"],"tagIds":[4,8],"tagObjectIds":[],"additionalInfo":{"footnotePages":[15,25,35,45,55],"foo":55,"notes":{"mynote":"touching"}},"metadata":{"somethingNumber":4,"somethingString":"meta-string-4","somethingArrayObject":[{"arrayItemObjectChildNumber":7}],"somethingArrayOfNumbers":[4,5]},"attachments":[{"name":"attachment-4","nestedArr":[6,7,8],"detail":{"size":12}},{"name":"attachment-4b","other":"extra-info-4b"}],"editionsDates":[{"edition":2,"date":"2019-08-08T00:00:00.000Z"},{"edition":1,"date":"2018-07-01T00:00:00.000Z"}],"__STATE__":"PUBLIC"} -------------------------------------------------------------------------------- /tests/filesFixtures/booksError.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "64940bd37955234169667b47", 4 | "name": "Pride and Prejudice", 5 | "isbn": "fake isbn 2", 6 | "publishDate": "InvalidDate" 7 | } 8 | ] -------------------------------------------------------------------------------- /tests/filesFixtures/booksNoId.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Pride and Prejudice", 4 | "isbn": "fake isbn 2", 5 | "publishDate": "2023-01-01T00:00:00.000Z" 6 | }, 7 | { 8 | "name": "Pride and Prejudice 2 the revenge", 9 | "isbn": "fake isbn 10", 10 | "publishDate": "2023-01-01T00:00:00.000Z" 11 | } 12 | ] -------------------------------------------------------------------------------- /tests/fixtures/address_statistics.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | module.exports = [ 22 | { 23 | _id: new ObjectId('aaaaaaaaaaaaaaaaaaaaaaaa'), 24 | addressId: new ObjectId('111111111111111111111111'), 25 | count: 1, 26 | tag: 'tag1', 27 | }, 28 | { 29 | _id: new ObjectId('bbbbbbbbbbbbbbbbbbbbbbbb'), 30 | addressId: new ObjectId('222222222222222222222222'), 31 | count: 2, 32 | tag: 'tag1', 33 | }, 34 | { 35 | _id: new ObjectId('cccccccccccccccccccccccc'), 36 | addressId: new ObjectId('333333333333333333333333'), 37 | count: 3, 38 | tag: 'tag1', 39 | }, 40 | { 41 | _id: new ObjectId('dddddddddddddddddddddddd'), 42 | addressId: new ObjectId('111111111111111111111111'), 43 | count: 4, 44 | tag: 'tag2', 45 | }, 46 | { 47 | _id: new ObjectId('eeeeeeeeeeeeeeeeeeeeeeee'), 48 | addressId: new ObjectId('222222222222222222222222'), 49 | count: 5, 50 | tag: 'tag2', 51 | }, 52 | { 53 | _id: new ObjectId('ffffffffffffffffffffffff'), 54 | addressId: new ObjectId('222222222222222222222222'), 55 | count: 6, 56 | tag: 'tag3', 57 | }, 58 | ] 59 | -------------------------------------------------------------------------------- /tests/fixtures/addresses.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | module.exports = [ 22 | { 23 | _id: new ObjectId('111111111111111111111111'), 24 | displayName: 'via Calatafimi, 11', 25 | street: 'via Calatafimi', 26 | house_number: 11, 27 | }, 28 | { 29 | _id: new ObjectId('222222222222222222222222'), 30 | displayName: 'via dei Pazzi, 0', 31 | street: 'via dei Pazzi', 32 | house_number: 0, 33 | }, 34 | { 35 | _id: new ObjectId('333333333333333333333333'), 36 | displayName: 'via Cilea, 123', 37 | street: 'via Cilea', 38 | house_number: 123, 39 | }, 40 | ] 41 | -------------------------------------------------------------------------------- /tests/fixtures/books.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | const fixtures = [ 22 | { 23 | _id: new ObjectId('000000000000000000000000'), 24 | name: 'fake name other-0', 25 | isbn: 'fake isbn other-0', 26 | authorAddressId: new ObjectId('111111111111111111111111'), 27 | price: 10, 28 | }, 29 | { 30 | _id: new ObjectId('111111111111111111111111'), 31 | name: 'fake name other-1', 32 | isbn: 'fake isbn other-1', 33 | authorAddressId: new ObjectId('444444444444444444444444'), 34 | price: 11, 35 | }, 36 | { 37 | _id: new ObjectId('222222222222222222222222'), 38 | name: 'fake name other-2', 39 | isbn: 'fake isbn other-2', 40 | authorAddressId: new ObjectId('222222222222222222222222'), 41 | price: 2, 42 | }, 43 | ] 44 | 45 | module.exports = fixtures 46 | -------------------------------------------------------------------------------- /tests/fixtures/films.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | module.exports = [ 22 | { 23 | _id: new ObjectId('aaaaaaaaaaaaaaaaaaaaaaaa'), 24 | title: 'A New Hope', 25 | episode_id: 1, 26 | }, 27 | { 28 | _id: new ObjectId('bbbbbbbbbbbbbbbbbbbbbbbb'), 29 | title: 'Attack of the Clones', 30 | episode_id: 2, 31 | }, 32 | { 33 | _id: new ObjectId('cccccccccccccccccccccccc'), 34 | title: 'The Phantom Menace', 35 | episode_id: 3, 36 | }, 37 | ] 38 | -------------------------------------------------------------------------------- /tests/fixtures/items.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | const { 21 | __STATE__, 22 | STATES, 23 | UPDATERID, 24 | UPDATEDAT, 25 | CREATORID, 26 | CREATEDAT, 27 | } = require('../../lib/consts') 28 | 29 | const updatedAtDate = new Date('2017-11-11') 30 | const createdAtDate = new Date('2017-11-10') 31 | const creatorId = 'my-creator-id' 32 | const updaterId = 'my-updated-id' 33 | 34 | module.exports = [ 35 | { 36 | _id: ObjectId.createFromHexString('555555555555555555555555'), 37 | name: 'spatzle', 38 | rating: 4.9, 39 | [CREATEDAT]: createdAtDate, 40 | [CREATORID]: creatorId, 41 | [UPDATERID]: updaterId, 42 | [UPDATEDAT]: updatedAtDate, 43 | [__STATE__]: STATES.PUBLIC, 44 | }, 45 | { 46 | _id: ObjectId.createFromHexString('666666666666666666666666'), 47 | name: 'lasagna', 48 | rating: 3.8, 49 | [CREATEDAT]: createdAtDate, 50 | [CREATORID]: creatorId, 51 | [UPDATERID]: updaterId, 52 | [UPDATEDAT]: updatedAtDate, 53 | [__STATE__]: STATES.PUBLIC, 54 | }, 55 | { 56 | _id: ObjectId.createFromHexString('777777777777777777777777'), 57 | name: 'pizza', 58 | rating: 4.5, 59 | [CREATEDAT]: createdAtDate, 60 | [CREATORID]: creatorId, 61 | [UPDATERID]: updaterId, 62 | [UPDATEDAT]: updatedAtDate, 63 | [__STATE__]: STATES.PUBLIC, 64 | }, 65 | { 66 | _id: ObjectId.createFromHexString('888888888888888888888888'), 67 | name: 'piadina', 68 | rating: 4.3, 69 | [CREATEDAT]: createdAtDate, 70 | [CREATORID]: creatorId, 71 | [UPDATERID]: updaterId, 72 | [UPDATEDAT]: updatedAtDate, 73 | [__STATE__]: STATES.PUBLIC, 74 | }, 75 | ] 76 | -------------------------------------------------------------------------------- /tests/fixtures/lotOfBooksFixtures.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | const { 22 | __STATE__, 23 | STATES, 24 | UPDATERID, 25 | UPDATEDAT, 26 | CREATORID, 27 | CREATEDAT, 28 | } = require('../../lib/consts') 29 | 30 | const date2 = new Date('2017-11-22') 31 | 32 | const updatedAtDate = new Date('2017-11-11') 33 | const createdAtDate = new Date('2017-11-10') 34 | const creatorId = 'my-creator-id' 35 | const updaterId = 'my-updated-id' 36 | 37 | const data = [] 38 | for (let index = 0; index < 201; index++) { 39 | data.push({ 40 | _id: ObjectId.createFromHexString(`999999999999999999999${(`${index}`).padStart(3, '0')}`), 41 | name: `fake name other-${index}`, 42 | author: `fake author other-${index}`, 43 | isbn: `fake isbn other-${index}`, 44 | price: 5, 45 | isPromoted: false, 46 | publishDate: date2, 47 | attachments: [], 48 | additionalInfo: null, 49 | editionsDates: null, 50 | [CREATEDAT]: createdAtDate, 51 | [CREATORID]: creatorId, 52 | [UPDATERID]: updaterId, 53 | [UPDATEDAT]: updatedAtDate, 54 | [__STATE__]: STATES.PUBLIC, 55 | }) 56 | } 57 | module.exports = data 58 | -------------------------------------------------------------------------------- /tests/fixtures/orders.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | const { 21 | __STATE__, 22 | STATES, 23 | UPDATERID, 24 | UPDATEDAT, 25 | CREATORID, 26 | CREATEDAT, 27 | } = require('../../lib/consts') 28 | 29 | const updatedAtDate = new Date('2017-11-11') 30 | const createdAtDate = new Date('2017-11-10') 31 | const creatorId = 'my-creator-id' 32 | const updaterId = 'my-updated-id' 33 | 34 | module.exports = [ 35 | { 36 | _id: ObjectId.createFromHexString('111111111111111111111111'), 37 | id_rider: ObjectId.createFromHexString('222222222222222222222222'), 38 | items: [ 39 | ObjectId.createFromHexString('555555555555555555555555'), 40 | ObjectId.createFromHexString('666666666666666666666666'), 41 | ], 42 | paid: true, 43 | [CREATEDAT]: createdAtDate, 44 | [CREATORID]: creatorId, 45 | [UPDATERID]: updaterId, 46 | [UPDATEDAT]: updatedAtDate, 47 | [__STATE__]: STATES.PUBLIC, 48 | }, 49 | { 50 | _id: ObjectId.createFromHexString('222222222222222222222222'), 51 | id_rider: ObjectId.createFromHexString('333333333333333333333333'), 52 | items: [ 53 | ObjectId.createFromHexString('555555555555555555555555'), 54 | ObjectId.createFromHexString('777777777777777777777777'), 55 | ], 56 | paid: true, 57 | [CREATEDAT]: createdAtDate, 58 | [CREATORID]: creatorId, 59 | [UPDATERID]: updaterId, 60 | [UPDATEDAT]: updatedAtDate, 61 | [__STATE__]: STATES.PUBLIC, 62 | }, 63 | { 64 | _id: ObjectId.createFromHexString('333333333333333333333333'), 65 | id_rider: ObjectId.createFromHexString('333333333333333333333333'), 66 | items: [ 67 | ObjectId.createFromHexString('888888888888888888888888'), 68 | ], 69 | paid: true, 70 | [CREATEDAT]: createdAtDate, 71 | [CREATORID]: creatorId, 72 | [UPDATERID]: updaterId, 73 | [UPDATEDAT]: updatedAtDate, 74 | [__STATE__]: STATES.PUBLIC, 75 | }, 76 | ] 77 | -------------------------------------------------------------------------------- /tests/fixtures/people.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | 21 | module.exports = [ 22 | { 23 | _id: new ObjectId('111111111111111111111111'), 24 | name: 'Luke, Skywalker', 25 | height: 172, 26 | films: [ 27 | new ObjectId('aaaaaaaaaaaaaaaaaaaaaaaa'), 28 | ], 29 | }, 30 | { 31 | _id: new ObjectId('222222222222222222222222'), 32 | name: 'C-3PO', 33 | height: 167, 34 | films: [ 35 | new ObjectId('bbbbbbbbbbbbbbbbbbbbbbbb'), 36 | ], 37 | }, 38 | { 39 | _id: new ObjectId('333333333333333333333333'), 40 | name: 'R2-D2', 41 | height: 96, 42 | films: [ 43 | ], 44 | }, 45 | { 46 | _id: new ObjectId('444444444444444444444444'), 47 | name: 'Darth Vader', 48 | height: 202, 49 | films: [ 50 | new ObjectId('aaaaaaaaaaaaaaaaaaaaaaaa'), 51 | new ObjectId('bbbbbbbbbbbbbbbbbbbbbbbb'), 52 | new ObjectId('cccccccccccccccccccccccc'), 53 | ], 54 | }, 55 | { 56 | _id: new ObjectId('555555555555555555555555'), 57 | name: 'wrong data', 58 | }, 59 | ] 60 | -------------------------------------------------------------------------------- /tests/fixtures/riders.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { ObjectId } = require('mongodb') 20 | const { 21 | __STATE__, 22 | STATES, 23 | UPDATERID, 24 | UPDATEDAT, 25 | CREATORID, 26 | CREATEDAT, 27 | } = require('../../lib/consts') 28 | 29 | const updatedAtDate = new Date('2017-11-11') 30 | const createdAtDate = new Date('2017-11-10') 31 | const creatorId = 'my-creator-id' 32 | const updaterId = 'my-updated-id' 33 | 34 | module.exports = [ 35 | { 36 | _id: ObjectId.createFromHexString('111111111111111111111111'), 37 | name: 'Mario', 38 | surname: 'Rossi', 39 | [CREATEDAT]: createdAtDate, 40 | [CREATORID]: creatorId, 41 | [UPDATERID]: updaterId, 42 | [UPDATEDAT]: updatedAtDate, 43 | [__STATE__]: STATES.PUBLIC, 44 | }, 45 | { 46 | _id: ObjectId.createFromHexString('222222222222222222222222'), 47 | name: 'Jon', 48 | surname: 'Snow', 49 | [CREATEDAT]: createdAtDate, 50 | [CREATORID]: creatorId, 51 | [UPDATERID]: updaterId, 52 | [UPDATEDAT]: updatedAtDate, 53 | [__STATE__]: STATES.PUBLIC, 54 | }, 55 | { 56 | _id: ObjectId.createFromHexString('333333333333333333333333'), 57 | name: 'Harry', 58 | surname: 'Potter', 59 | [CREATEDAT]: createdAtDate, 60 | [CREATORID]: creatorId, 61 | [UPDATERID]: updaterId, 62 | [UPDATEDAT]: updatedAtDate, 63 | [__STATE__]: STATES.PUBLIC, 64 | }, 65 | { 66 | _id: ObjectId.createFromHexString('444444444444444444444444'), 67 | name: 'Harry', 68 | surname: 'Houdini', 69 | [CREATEDAT]: createdAtDate, 70 | [CREATORID]: creatorId, 71 | [UPDATERID]: updaterId, 72 | [UPDATEDAT]: updatedAtDate, 73 | [__STATE__]: STATES.PUBLIC, 74 | }, 75 | ] 76 | -------------------------------------------------------------------------------- /tests/getSchemas.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | const { getMongoDatabaseName, getMongoURL } = require('./utils') 21 | const path = require('path') 22 | const lc39 = require('@mia-platform/lc39') 23 | 24 | tap.test('getSchemas', async t => { 25 | t.test('return json', async t => { 26 | const fastify = await startFastify(t) 27 | const response = await fastify.inject({ 28 | method: 'GET', 29 | url: '/-/schemas', 30 | }) 31 | 32 | t.strictSame(response.statusCode, 200) 33 | t.matchSnapshot(response.payload) 34 | }) 35 | 36 | t.test('return ndjson', async t => { 37 | const fastify = await startFastify(t) 38 | const response = await fastify.inject({ 39 | method: 'GET', 40 | url: '/-/schemas', 41 | headers: { 42 | accept: 'application/x-ndjson', 43 | }, 44 | }) 45 | 46 | t.strictSame(response.statusCode, 200) 47 | t.matchSnapshot(response.payload) 48 | }) 49 | 50 | t.test('HELPERS_PREFIX', async t => { 51 | const fastify = await startFastify(t, { 52 | HELPERS_PREFIX: '/_/', 53 | }) 54 | 55 | const wrongUrlResponse = await fastify.inject({ 56 | method: 'GET', 57 | url: '/-/schemas', 58 | }) 59 | t.strictSame(wrongUrlResponse.statusCode, 404) 60 | 61 | const rightUrlResponse = await fastify.inject({ 62 | method: 'GET', 63 | url: '/_/schemas', 64 | }) 65 | t.strictSame(rightUrlResponse.statusCode, 200) 66 | }) 67 | }) 68 | 69 | async function startFastify(t, envs = {}) { 70 | const databaseName = getMongoDatabaseName() 71 | const mongoURL = getMongoURL(databaseName) 72 | 73 | const fastify = await lc39('./index.js', { 74 | envVariables: { 75 | MONGODB_URL: mongoURL, 76 | COLLECTION_DEFINITION_FOLDER: path.join(__dirname, 'collectionDefinitions'), 77 | USER_ID_HEADER_KEY: 'userid', 78 | ...envs, 79 | }, 80 | logLevel: 'silent', 81 | }) 82 | 83 | t.teardown(async() => { 84 | await fastify.close() 85 | }) 86 | 87 | return fastify 88 | } 89 | -------------------------------------------------------------------------------- /tests/httpInterface.getSchema.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | const { getMongoDatabaseName, getMongoURL } = require('./utils') 21 | const path = require('path') 22 | const lc39 = require('@mia-platform/lc39') 23 | const { prefix } = require('./httpInterface.utils') 24 | 25 | tap.test('getSchemas', async t => { 26 | const databaseName = getMongoDatabaseName() 27 | const mongoURL = getMongoURL(databaseName) 28 | 29 | const fastify = await lc39('./index.js', { 30 | envVariables: { 31 | MONGODB_URL: mongoURL, 32 | COLLECTION_DEFINITION_FOLDER: path.join(__dirname, 'collectionDefinitions'), 33 | USER_ID_HEADER_KEY: 'userid', 34 | }, 35 | logLevel: 'silent', 36 | }) 37 | 38 | t.teardown(async() => { 39 | await fastify.close() 40 | }) 41 | 42 | const response = await fastify.inject({ 43 | method: 'GET', 44 | url: `${prefix}/schema`, 45 | }) 46 | 47 | t.strictSame(response.statusCode, 200) 48 | t.matchSnapshot(JSON.parse(response.payload)) 49 | }) 50 | -------------------------------------------------------------------------------- /tests/httpInterface.metrics.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | 21 | const { setUpTest, prefix } = require('./httpInterface.utils') 22 | 23 | const DOC = { 24 | name: null, 25 | isbn: 'aaaaa', 26 | } 27 | 28 | tap.test('HTTP GET /-/metrics', async t => { 29 | const { fastify } = await setUpTest(t, null, undefined, true) 30 | 31 | let response 32 | response = await fastify.inject({ 33 | method: 'GET', 34 | url: `${prefix}/count`, 35 | }) 36 | t.strictSame(response.statusCode, 200) 37 | 38 | response = await fastify.inject({ 39 | method: 'GET', 40 | url: `${prefix}/`, 41 | }) 42 | t.strictSame(response.statusCode, 200) 43 | 44 | response = await fastify.inject({ 45 | method: 'POST', 46 | url: `${prefix}/`, 47 | payload: DOC, 48 | }) 49 | t.strictSame(response.statusCode, 200) 50 | 51 | const metricsResponse = await fastify.inject({ 52 | method: 'GET', 53 | url: '/-/metrics', 54 | }) 55 | t.strictSame(metricsResponse.statusCode, 200) 56 | 57 | t.ok(/mia_platform_crud_service_collection_invocation{collection_name="books-endpoint",type="fetch"} 2/.test(metricsResponse.payload)) 58 | t.ok(/mia_platform_crud_service_collection_invocation{collection_name="books-endpoint",type="insert_or_update"} 1/.test(metricsResponse.payload)) 59 | 60 | t.end() 61 | }) 62 | -------------------------------------------------------------------------------- /tests/httpInterface.swagger.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | 21 | const { setUpTest } = require('./httpInterface.utils') 22 | const { SCHEMA_CUSTOM_KEYWORDS } = require('../lib/consts') 23 | const { fixtures, BOOKS_COLLECTION_NAME } = require('./utils') 24 | 25 | tap.test('HTTP swagger', t => { 26 | t.test('ok - Swagger 2.0', async t => { 27 | const { fastify } = await setUpTest(t) 28 | 29 | const response = await fastify.inject({ 30 | method: 'GET', 31 | url: '/documentation/json', 32 | }) 33 | 34 | t.test('should return 200', t => { 35 | t.strictSame(response.statusCode, 200) 36 | t.end() 37 | }) 38 | t.test('should return application/json', t => { 39 | t.ok(/application\/json/.test(response.headers['content-type'])) 40 | t.end() 41 | }) 42 | t.test('should return a valid Swagger 2.0', async t => { 43 | const swagger = JSON.parse(response.payload) 44 | t.matchStrict(swagger, { swagger: '2.0' }) 45 | t.end() 46 | }) 47 | t.test('should not contain unique id of schema', t => { 48 | const swagger = response.payload 49 | const regex = new RegExp(`"${SCHEMA_CUSTOM_KEYWORDS.UNIQUE_OPERATION_ID}"`, 'g') 50 | t.notOk(swagger.match(regex)) 51 | t.end() 52 | }) 53 | }) 54 | 55 | t.test('ok - OpenAPI 3.0', async t => { 56 | const { fastify } = await setUpTest(t, fixtures, BOOKS_COLLECTION_NAME, false, false, 'openapi') 57 | 58 | const response = await fastify.inject({ 59 | method: 'GET', 60 | url: '/documentation/json', 61 | }) 62 | 63 | t.test('should return 200', t => { 64 | t.strictSame(response.statusCode, 200) 65 | t.end() 66 | }) 67 | t.test('should return application/json', t => { 68 | t.ok(/application\/json/.test(response.headers['content-type'])) 69 | t.end() 70 | }) 71 | t.test('should return a valid OpenAPI 3.0', async t => { 72 | const swagger = JSON.parse(response.payload) 73 | t.matchStrict(swagger, { openapi: '3.0' }) 74 | t.end() 75 | }) 76 | t.test('should not contain unique id of schema', t => { 77 | const swagger = response.payload 78 | const regex = new RegExp(`"${SCHEMA_CUSTOM_KEYWORDS.UNIQUE_OPERATION_ID}"`, 'g') 79 | t.notOk(swagger.match(regex)) 80 | t.end() 81 | }) 82 | }) 83 | 84 | t.end() 85 | }) 86 | -------------------------------------------------------------------------------- /tests/lib/gcpKeyStripper.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | const path = require('path') 21 | 22 | const { readAndStripPrivateKeyContent } = require('../../lib/gcpKeyStripper') 23 | 24 | tap.test('throw exception for key not found', (t) => { 25 | t.throws(() => readAndStripPrivateKeyContent('invalid_key.pem')) 26 | t.end() 27 | }) 28 | 29 | tap.test('correctly strip one line key', (t) => { 30 | const strippedContent = readAndStripPrivateKeyContent(path.join(__dirname, './oneLineKey.pem')) 31 | t.equal(strippedContent, 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQXGukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63ilAkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlFL0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5kX6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2eplU9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=') 32 | t.end() 33 | }) 34 | -------------------------------------------------------------------------------- /tests/lib/mongo/mongo-keyring-factory.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | 21 | const keyringFactory = require('../../../lib/mongo/mongo-keyring-factory') 22 | 23 | const buildFastifyInstance = (config) => ({ config }) 24 | 25 | tap.test('empty keyring configuration for undefined provider', t => { 26 | const fastify = buildFastifyInstance({ KMS_PROVIDER: undefined }) 27 | t.match(keyringFactory(fastify), {}) 28 | 29 | t.end() 30 | }) 31 | 32 | tap.test('right crypt configuration for non gcp kms provider', t => { 33 | const fastify = buildFastifyInstance({ KMS_PROVIDER: 'local' }) 34 | t.match(keyringFactory(fastify), {}) 35 | 36 | t.end() 37 | }) 38 | 39 | tap.test('right crypt configuration for gcp kms provider', t => { 40 | const fastify = buildFastifyInstance({ 41 | KMS_PROVIDER: 'gcp', 42 | KMS_GCP_PROJECT_ID: 'projectId', 43 | KMS_GCP_LOCATION: 'location', 44 | KMS_GCP_KEY_RING: 'keyRing', 45 | KMS_GCP_KEY_NAME: 'keyName', 46 | }) 47 | const expectedKeyring = { 48 | masterKey: { 49 | projectId: 'projectId', 50 | location: 'location', 51 | keyRing: 'keyRing', 52 | keyName: 'keyName', 53 | }, 54 | } 55 | t.match(keyringFactory(fastify), expectedKeyring) 56 | 57 | t.end() 58 | }) 59 | -------------------------------------------------------------------------------- /tests/lib/mongo/test-master-key.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mia-platform/crud-service/643f251055d3e69b20923a4189a3a1cd2000011d/tests/lib/mongo/test-master-key.txt -------------------------------------------------------------------------------- /tests/lib/oneLineKey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY-----\nMIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp\nwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5\n1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh\n3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2\npIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX\nGukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il\nAkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF\nL0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k\nX6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl\nU9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ\n37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=\n-----END PRIVATE KEY-----\n 2 | -------------------------------------------------------------------------------- /tests/lib/private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp 3 | wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5 4 | 1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh 5 | 3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2 6 | pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX 7 | GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il 8 | AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF 9 | L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k 10 | X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl 11 | U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ 12 | 37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0= 13 | -----END PRIVATE KEY----- 14 | -------------------------------------------------------------------------------- /tests/newCollectionDefinitions/stations.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { STATES } = require('../../lib/consts') 20 | 21 | module.exports = { 22 | description: 'Collection of stations', 23 | name: 'stations', 24 | schema: { 25 | type: 'object', 26 | required: [ 27 | '_id', 28 | 'creatorId', 29 | 'createdAt', 30 | 'updaterId', 31 | 'updatedAt', 32 | '__STATE__', 33 | ], 34 | properties: { 35 | _id: { 36 | type: 'string', 37 | description: '_id', 38 | }, 39 | updaterId: { 40 | type: 'string', 41 | description: 'User id that has requested the last change successfully', 42 | }, 43 | updatedAt: { 44 | type: 'string', 45 | format: 'date-time', 46 | description: 'Date of the request that has performed the last change', 47 | }, 48 | creatorId: { 49 | type: 'string', 50 | description: 'User id that has created this object', 51 | }, 52 | createdAt: { 53 | type: 'string', 54 | format: 'date-time', 55 | description: 'Date of the request that has performed the object creation', 56 | }, 57 | __STATE__: { 58 | type: 'string', 59 | enum: Object.values(STATES), 60 | description: 'The state of the document', 61 | }, 62 | Cap: { 63 | type: 'number', 64 | nullable: true, 65 | }, 66 | CodiceMIR: { 67 | type: 'string', 68 | nullable: true, 69 | }, 70 | Comune: { 71 | type: 'string', 72 | nullable: true, 73 | }, 74 | Direttrici: { 75 | type: 'array', 76 | nullable: true, 77 | items: { 78 | type: 'string', 79 | }, 80 | }, 81 | Indirizzo: { 82 | type: 'string', 83 | nullable: true, 84 | }, 85 | country: { 86 | type: 'string', 87 | nullable: true, 88 | }, 89 | nonNullableDate: { 90 | type: 'string', 91 | format: 'date-time', 92 | nullable: false, 93 | }, 94 | }, 95 | }, 96 | indexes: [ 97 | { 98 | name: '_id', 99 | type: 'normal', 100 | unique: true, 101 | fields: [ 102 | { 103 | name: '_id', 104 | order: 1, 105 | }, 106 | ], 107 | }, 108 | ], 109 | endpointBasePath: '/stations-endpoint', 110 | defaultState: 'DRAFT', 111 | } 112 | -------------------------------------------------------------------------------- /tests/pkFactories.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const tap = require('tap') 20 | 21 | const { pkFactories } = require('../lib/pkFactories') 22 | const { ObjectId } = require('mongodb') 23 | const validate = require('uuid-validate') 24 | 25 | tap.test('pkFactories', async t => { 26 | const UUIDFactory = pkFactories.string 27 | const ObjectIdFactory = pkFactories.ObjectId 28 | 29 | t.test('A correct UUID is generated by the factory', async assert => { 30 | assert.ok(validate(UUIDFactory.createPk(), 4)) 31 | assert.end() 32 | }) 33 | 34 | t.test('A correct ObjectId is generated by the factory', async assert => { 35 | const newID = ObjectIdFactory.createPk().toHexString() 36 | assert.doesNotThrow(() => new ObjectId(newID), {}, { skip: false }) 37 | assert.end() 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /tests/viewUtils.utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | const { STATES } = require('../lib/consts') 20 | const ordersFixture = require('./fixtures/orders') 21 | const ridersFixture = require('./fixtures/riders') 22 | 23 | const expectedOrderDetailsViewDocs = ordersFixture 24 | .map(order => { 25 | const { id_rider: idRider, ...viewField } = order 26 | const { 27 | _id, 28 | name, 29 | surname, 30 | } = ridersFixture 31 | .find(rider => rider._id.toString() === idRider.toString()) 32 | 33 | return { 34 | ...viewField, 35 | rider: { 36 | label: `${name} ${surname}`, 37 | value: _id, 38 | }, 39 | } 40 | }) 41 | 42 | const expectedOrderDetailsViewDocsPublic = expectedOrderDetailsViewDocs 43 | .filter(doc => doc.__STATE__ === STATES.PUBLIC) 44 | 45 | const riderObjectToLookup = ({ name, surname, _id }) => ({ 46 | label: `${name} ${surname}`, 47 | value: _id, 48 | }) 49 | 50 | const expectedRidersLookup = ridersFixture.map(riderObjectToLookup) 51 | 52 | module.exports = { 53 | lookupAddressPrefix: '/orders-details-endpoint/lookup/rider', 54 | prefix: '/orders-endpoint', 55 | ordersFixture, 56 | ridersFixture, 57 | expectedOrderDetailsViewDocs, 58 | expectedOrderDetailsViewDocsPublic, 59 | expectedRidersLookup, 60 | riderObjectToLookup, 61 | } 62 | -------------------------------------------------------------------------------- /tests/viewsDefinitions/felines.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'felines', 21 | source: 'animals', 22 | type: 'view', 23 | pipeline: [ 24 | { 25 | $match: { family: 'felines' }, 26 | }, 27 | { 28 | $project: { 29 | _id: 1, 30 | name: 1, 31 | updaterId: 1, 32 | updatedAt: 1, 33 | creatorId: 1, 34 | createdAt: 1, 35 | weight: 1, 36 | 37 | /* 38 | NOTE: __STATE__ field MUST be returned in the final record produced by the pipeline 39 | On the contrary, records without the __STATE__ field would always be filtered out 40 | by the CRUD Service operations 41 | (e.g. listing records via GET method would not consider them in the result set) 42 | */ 43 | __STATE__: 1, 44 | }, 45 | }, 46 | ], 47 | } 48 | -------------------------------------------------------------------------------- /tests/viewsDefinitions/store-open.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'store-open', 21 | source: 'store', 22 | pipeline: [ 23 | { 24 | $match: { currentlyWorking: true }, 25 | }, 26 | { 27 | $project: { 28 | _id: 1, 29 | name: 1, 30 | updaterId: 1, 31 | updatedAt: 1, 32 | creatorId: 1, 33 | createdAt: 1, 34 | address: 1, 35 | 36 | /* 37 | NOTE: __STATE__ field MUST be returned in the final record produced by the pipeline 38 | On the contrary, records without the __STATE__ field would always be filtered out 39 | by the CRUD Service operations 40 | (e.g. listing records via GET method would not consider them in the result set) 41 | */ 42 | __STATE__: 1, 43 | }, 44 | }, 45 | ], 46 | } 47 | -------------------------------------------------------------------------------- /tests/viewsDefinitionsLookup/orders-details.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'orders-details', 21 | source: 'orders', 22 | type: 'view', 23 | enableLookup: true, 24 | pipeline: [ 25 | { 26 | $lookup: { 27 | from: 'riders', 28 | localField: 'id_rider', 29 | foreignField: '_id', 30 | as: 'rider', 31 | pipeline: [ 32 | { 33 | $project: { 34 | _id: 0, 35 | value: { 36 | $toObjectId: '$_id', 37 | }, 38 | label: { 39 | $toString: { 40 | $concat: ['$name', ' ', '$surname'], 41 | }, 42 | }, 43 | }, 44 | }, 45 | ], 46 | }, 47 | }, 48 | { 49 | $unwind: { 50 | path: '$rider', 51 | preserveNullAndEmptyArrays: true, 52 | }, 53 | }, 54 | { 55 | $project: { 56 | _id: 1, 57 | updaterId: 1, 58 | updatedAt: 1, 59 | creatorId: 1, 60 | createdAt: 1, 61 | rider: 1, 62 | items: 1, 63 | paid: 1, 64 | 65 | /* 66 | NOTE: __STATE__ field MUST be returned in the final record produced by the pipeline 67 | On the contrary, records without the __STATE__ field would always be filtered out 68 | by the CRUD Service operations 69 | (e.g. listing records via GET method would not consider them in the result set) 70 | */ 71 | __STATE__: 1, 72 | }, 73 | }, 74 | ], 75 | } 76 | -------------------------------------------------------------------------------- /tests/viewsDefinitionsLookup/orders-items.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'orders-items', 21 | source: 'orders', 22 | type: 'view', 23 | enableLookup: true, 24 | pipeline: [ 25 | { 26 | $match: { 27 | __STATE__: 'PUBLIC', 28 | }, 29 | }, 30 | { 31 | $lookup: { 32 | from: 'items', 33 | localField: 'items', 34 | foreignField: '_id', 35 | as: 'items', 36 | pipeline: [ 37 | { 38 | $project: { 39 | _id: 0, 40 | value: { 41 | $toObjectId: '$_id', 42 | }, 43 | label: { $toString: '$name' }, 44 | }, 45 | }, 46 | ], 47 | }, 48 | }, 49 | { 50 | $project: { 51 | _id: 1, 52 | updaterId: 1, 53 | updatedAt: 1, 54 | creatorId: 1, 55 | createdAt: 1, 56 | items: 1, 57 | paid: 1, 58 | 59 | /* 60 | NOTE: __STATE__ field MUST be returned in the final record produced by the pipeline 61 | On the contrary, records without the __STATE__ field would always be filtered out 62 | by the CRUD Service operations 63 | (e.g. listing records via GET method would not consider them in the result set) 64 | */ 65 | __STATE__: 1, 66 | }, 67 | }, 68 | ], 69 | } 70 | -------------------------------------------------------------------------------- /tests/wrongDefinitions/wrong.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Mia s.r.l. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 'use strict' 18 | 19 | module.exports = { 20 | name: 'books', 21 | endpointBasePath: '/books-endpoint', 22 | defaultState: 'DRAFT', 23 | indexes: [ 24 | { 25 | name: 'uniqueISBN', 26 | type: 'normal', 27 | unique: true, 28 | fields: [ 29 | { 30 | name: 'isbn', 31 | order: 1, 32 | }, 33 | ], 34 | }, 35 | { 36 | name: 'positionIndex', 37 | type: 'geo', 38 | unique: false, 39 | field: 'position', 40 | }, 41 | { 42 | name: 'textIndex', 43 | type: 'text', 44 | unique: false, 45 | fields: [ 46 | { name: 'name' }, 47 | { name: 'author' }, 48 | ], 49 | weights: { 50 | name: 1, 51 | author: 1, 52 | }, 53 | defaultLanguage: 'en', 54 | languageOverride: 'idioma', 55 | }, 56 | { 57 | name: 'isPromotedPartialIndex', 58 | type: 'normal', 59 | unique: false, 60 | fields: [ 61 | { 62 | name: 'isPromoted', 63 | order: 1, 64 | }, 65 | ], 66 | usePartialFilter: true, 67 | partialFilterExpression: '{"isPromoted": { "$eq": true } }', 68 | }, 69 | ], 70 | } 71 | --------------------------------------------------------------------------------