diff --git a/.buildkite/publish/docker-compose.yml b/.buildkite/publish/docker-compose.yml index 247f15c60408..5eba73e4b973 100644 --- a/.buildkite/publish/docker-compose.yml +++ b/.buildkite/publish/docker-compose.yml @@ -28,7 +28,8 @@ services: - TEST_MSSQL_JDBC_URI_MIGRATE=sqlserver://mssql:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; - TEST_MSSQL_SHADOWDB_JDBC_URI_MIGRATE=sqlserver://mssql:1433;database=tests-migrate-shadowdb;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; # MongoDB - - TEST_MONGO_URI=mongodb://root:prisma@mongo:27017/tests?authSource=admin + - TEST_MONGO_URI=mongodb://root:prisma@mongo:27018/tests?authSource=admin + - TEST_MONGO_URI_MIGRATE=mongodb://root:prisma@mongodb_migrate:27017/tests-migrate?authSource=admin # CockroachDB - TEST_COCKROACH_URI=postgresql://prisma@cockroachdb:26257/ # Other vars !\ If not defined, they cannot be accessed @@ -55,10 +56,12 @@ services: - postgres - postgres_isolated - mysql + - mysql_isolated - mariadb - mssql - mongo - - mongo-seed + - mongodb_migrate + - mongodb_migrate_seed - cockroachdb postgres: @@ -68,8 +71,8 @@ services: - POSTGRES_DB=tests - POSTGRES_USER=prisma - POSTGRES_PASSWORD=prisma - volumes: - - postgres:/var/lib/postgresql/data + ports: + - '5432:5432' postgres_isolated: image: postgres:10 @@ -78,8 +81,15 @@ services: - POSTGRES_DB=tests - POSTGRES_USER=prisma - POSTGRES_PASSWORD=prisma - volumes: - - postgres_isolated:/var/lib/postgresql/data + ports: + - '5435:5432' + + cockroachdb: + image: prismagraphql/build:cockroach-custom + restart: always + command: start-single-node --insecure + ports: + - '26257:26257' mysql: image: mysql:8.0 @@ -89,9 +99,8 @@ services: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=tests - MYSQL_USER=prisma - - MYSQL_PASSWORD=prisma - volumes: - - mysql:/var/lib/mysql + ports: + - '3306:3306' mysql_isolated: image: mysql:8.0 @@ -102,8 +111,8 @@ services: - MYSQL_DATABASE=tests - MYSQL_USER=prisma - MYSQL_PASSWORD=prisma - volumes: - - mysql_isolated:/var/lib/mysql + ports: + - '3307:3306' mariadb: image: mariadb:10 @@ -113,8 +122,8 @@ services: - MYSQL_DATABASE=tests - MYSQL_USER=prisma - MYSQL_PASSWORD=prisma - volumes: - - mariadb:/var/lib/mysql + ports: + - '4306:3306' mssql: image: mcr.microsoft.com/mssql/server:2019-latest @@ -122,36 +131,31 @@ services: environment: - ACCEPT_EULA=Y - SA_PASSWORD=Pr1sm4_Pr1sm4 - volumes: - - mssql:/var/opt/mssql + ports: + - '1433:1433' - mongo: + mongodb_migrate: image: mongo:4 restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: prisma - MONGO_INITDB_DATABASE: tests + MONGO_INITDB_DATABASE: tests-migrate ports: - '27017:27017' - mongo-seed: - build: ../../docker/mongo-seed - links: - - mongo + mongodb_migrate_seed: + build: ../../docker/mongodb_migrate_seed + depends_on: + - mongodb_migrate - cockroachdb: - image: prismagraphql/build:cockroach-custom - restart: always - command: start-single-node --insecure + mongo: + build: ../../docker/mongodb_replica + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: prisma + MONGO_REPLICA_HOST: mongo + MONGO_REPLICA_PORT: 27018 ports: - - '26257:26257' - -volumes: - postgres: - postgres_isolated: - mysql: - mysql_isolated: - mariadb: - mssql: + - '27018:27018' # TODO: investigate why isolated containers aren't used in the tests diff --git a/.buildkite/publish/publish.yml b/.buildkite/publish/publish.yml index 29b73691583d..fbdad6c36398 100644 --- a/.buildkite/publish/publish.yml +++ b/.buildkite/publish/publish.yml @@ -1,5 +1,5 @@ steps: - - label: ":llama: Publish" + - label: ':llama: Publish' timeout_in_minutes: 45 plugins: - docker-compose#v3.9.0: diff --git a/.buildkite/test/docker-compose.14.yml b/.buildkite/test/docker-compose.14.yml index 3572d4764fcc..b09cb31b9d77 100644 --- a/.buildkite/test/docker-compose.14.yml +++ b/.buildkite/test/docker-compose.14.yml @@ -28,7 +28,8 @@ services: - TEST_MSSQL_JDBC_URI_MIGRATE=sqlserver://mssql:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; - TEST_MSSQL_SHADOWDB_JDBC_URI_MIGRATE=sqlserver://mssql:1433;database=tests-migrate-shadowdb;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; # MongoDB - - TEST_MONGO_URI=mongodb://root:prisma@mongo:27017/tests?authSource=admin + - TEST_MONGO_URI=mongodb://root:prisma@mongo:27018/tests?authSource=admin + - TEST_MONGO_URI_MIGRATE=mongodb://root:prisma@mongodb_migrate:27017/tests-migrate?authSource=admin # CockroachDB - TEST_COCKROACH_URI=postgresql://prisma@cockroachdb:26257/ # Other vars @@ -49,7 +50,8 @@ services: - mariadb - mssql - mongo - - mongo-seed + - mongodb_migrate + - mongodb_migrate_seed - cockroachdb postgres: @@ -59,8 +61,8 @@ services: - POSTGRES_DB=tests - POSTGRES_USER=prisma - POSTGRES_PASSWORD=prisma - volumes: - - postgres:/var/lib/postgresql/data + ports: + - '5432:5432' postgres_isolated: image: postgres:10 @@ -69,8 +71,15 @@ services: - POSTGRES_DB=tests - POSTGRES_USER=prisma - POSTGRES_PASSWORD=prisma - volumes: - - postgres_isolated:/var/lib/postgresql/data + ports: + - '5435:5432' + + cockroachdb: + image: prismagraphql/build:cockroach-custom + restart: always + command: start-single-node --insecure + ports: + - '26257:26257' mysql: image: mysql:8.0 @@ -80,9 +89,8 @@ services: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=tests - MYSQL_USER=prisma - - MYSQL_PASSWORD=prisma - volumes: - - mysql:/var/lib/mysql + ports: + - '3306:3306' mysql_isolated: image: mysql:8.0 @@ -93,8 +101,8 @@ services: - MYSQL_DATABASE=tests - MYSQL_USER=prisma - MYSQL_PASSWORD=prisma - volumes: - - mysql_isolated:/var/lib/mysql + ports: + - '3307:3306' mariadb: image: mariadb:10 @@ -104,8 +112,8 @@ services: - MYSQL_DATABASE=tests - MYSQL_USER=prisma - MYSQL_PASSWORD=prisma - volumes: - - mariadb:/var/lib/mysql + ports: + - '4306:3306' mssql: image: mcr.microsoft.com/mssql/server:2019-latest @@ -113,35 +121,30 @@ services: environment: - ACCEPT_EULA=Y - SA_PASSWORD=Pr1sm4_Pr1sm4 - volumes: - - mssql:/var/opt/mssql + ports: + - '1433:1433' - mongo: + mongodb_migrate: image: mongo:4 restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: prisma - MONGO_INITDB_DATABASE: tests + MONGO_INITDB_DATABASE: tests-migrate ports: - '27017:27017' - mongo-seed: - build: ../../docker/mongo-seed - links: - - mongo + mongodb_migrate_seed: + build: ../../docker/mongodb_migrate_seed + depends_on: + - mongodb_migrate - cockroachdb: - image: prismagraphql/build:cockroach-custom - restart: always - command: start-single-node --insecure + mongo: + build: ../../docker/mongodb_replica + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: prisma + MONGO_REPLICA_HOST: mongo + MONGO_REPLICA_PORT: 27018 ports: - - '26257:26257' - -volumes: - postgres: - postgres_isolated: - mysql: - mysql_isolated: - mariadb: - mssql: + - '27018:27018' diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e8deb9097ae0..edcaca0a0b78 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,43 +1,43 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/typescript-node { - "name": "Node.js & TypeScript", - "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick a Node version: 12, 14, 16 - "args": { - "VARIANT": "14" - } - }, + "name": "Node.js & TypeScript", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick a Node version: 12, 14, 16 + "args": { + "VARIANT": "14" + } + }, - // Set *default* container specific settings.json values on container create. - "settings": { - "telemetry.enableTelemetry": false, - "redhat.telemetry.enabled": false, - "vulnCost.sendStatistics": false, + // Set *default* container specific settings.json values on container create. + "settings": { + "telemetry.enableTelemetry": false, + "redhat.telemetry.enabled": false, + "vulnCost.sendStatistics": false, - "editor.renderWhitespace": "all", - "editor.renderControlCharacters": true, - "editor.formatOnSave": true, + "editor.renderWhitespace": "all", + "editor.renderControlCharacters": true, + "editor.formatOnSave": true, - "files.insertFinalNewline": true, - }, + "files.insertFinalNewline": true + }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - // "dbaeumer.vscode-eslint", - "Prisma.prisma-insider", - "esbenp.prettier-vscode", - "Orta.vscode-jest", - "GitHub.vscode-pull-request-github" - ], + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + // "dbaeumer.vscode-eslint", + "Prisma.prisma-insider", + "esbenp.prettier-vscode", + "Orta.vscode-jest", + "GitHub.vscode-pull-request-github" + ], - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "pnpm install", + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "pnpm install", - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "node" + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "node" } diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000000..4636e967492e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,21 @@ +# common +dist/ +esm/ +build/ +fixtures/ +byline.ts +prism.ts +charm.ts +pnpm-lock.yaml + +# client +packages/client/generator-build/ +packages/client/declaration/ +packages/client/runtime/ +packages/client/src/__tests__/types/ + +# cli +packages/cli/prisma-client/ +packages/cli/install/ +packages/cli/preinstall/ +packages/cli/**/tmp-* \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 0dc8d6ffa79f..593d997a6606 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,7 +20,7 @@ const ignorePatterns = flatten( module.exports = { root: true, parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'jest'], + plugins: ['@typescript-eslint', 'jest', 'simple-import-sort', 'import'], env: { node: true, es6: true, @@ -29,7 +29,7 @@ module.exports = { parserOptions: { ecmaVersion: 2020, sourceType: 'module', - project: ['./packages/*/tsconfig.eslint.json'], + project: ['./tsconfig.json', './packages/*/tsconfig.json'], // debugLevel: true, }, ignorePatterns, @@ -86,12 +86,18 @@ module.exports = { additionalTestBlockFunctions: ['testIf', 'describeIf'], }, ], + // https://github.com/lydell/eslint-plugin-simple-import-sort + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + 'import/first': 'error', + 'import/newline-after-import': 'error', + 'import/no-duplicates': 'error', }, }, ], settings: { jest: { - version: 26, + version: 27, }, }, } diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1e93a1387eeb..fe8480bf14e8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug report description: Create a bug report to help us improve Prisma -labels: "kind/bug" +labels: 'kind/bug' body: - type: markdown attributes: @@ -29,7 +29,7 @@ body: - type: textarea attributes: label: Expected behavior - description: A clear and concise description of what you expected to happen. + description: A clear and concise description of what you expected to happen. - type: textarea attributes: label: Prisma information diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 141c326ffeb9..602431d422d8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,9 +1,9 @@ --- name: Feature request about: Suggest an idea for this project -title: "" -labels: "" -assignees: "" +title: '' +labels: '' +assignees: '' --- ## Problem diff --git a/.github/renovate.json b/.github/renovate.json index 68374390e02e..18a44b0fa6a5 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -3,8 +3,7 @@ "extends": ["config:base", ":disableRateLimiting"], "schedule": ["at any time"], "semanticCommits": "enabled", - "dependencyDashboard": true, - "reviewers": ["@Jolg42", "@millsp"], + "reviewers": ["@Jolg42", "@millsp", "@aqrln"], "rebaseWhen": "conflicted", "ignoreDeps": [ "sqlite3", @@ -19,11 +18,7 @@ "automerge": "true", "depTypeList": ["devDependencies"], "updateTypes": ["patch", "minor"], - "excludePackageNames": [ - "@prisma/studio", - "@prisma/studio-server", - "checkpoint-client" - ], + "excludePackageNames": ["@prisma/studio", "@prisma/studio-server", "checkpoint-client"], "schedule": ["before 8am on Wednesday"] }, { @@ -43,14 +38,12 @@ "groupName": "Studio", "automerge": "true", "packageNames": ["@prisma/studio", "@prisma/studio-server"], - "updateTypes": ["patch", "minor"], - "reviewers": ["@madebysid", "@jolg42", "millsp"] + "updateTypes": ["patch", "minor"] }, { "groupName": "checkpoint-client", "packageNames": ["checkpoint-client"], - "updateTypes": ["patch", "minor"], - "reviewers": ["@Weakky", "jolg42", "millsp"] + "updateTypes": ["patch", "minor"] }, { "groupName": "jest", @@ -64,6 +57,7 @@ }, { "groupName": "react-prisma", + "automerge": "true", "paths": ["packages/react-prisma/**"], "rangeStrategy": "replace", "schedule": ["before 8am on Wednesday"] diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 10ec060dc98a..df5cccb88a2c 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -29,17 +29,16 @@ jobs: name: all runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: '12' + cache: 'pnpm' + node-version: '16' - run: bash .github/workflows/setup.sh env: @@ -67,3 +66,19 @@ jobs: comment-on-alert: true fail-on-alert: true alert-comment-cc-users: '@Jolg42,@millsp' + + - name: 'Set current job url in SLACK_FOOTER env var' + if: ${{ failure() }} + run: echo "SLACK_FOOTER=<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Click here to go to the job logs>" >> $GITHUB_ENV + + - name: Slack Notification on Failure + if: ${{ failure() }} + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_TITLE: 'Benchmark failed :x:' + SLACK_COLOR: '#FF0000' + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: feed-prisma-failures + SLACK_USERNAME: Prismo + SLACK_ICON_EMOJI: ':boom:' + SLACK_MSG_AUTHOR: prisma-bot diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000000..95c33d191f2b --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,63 @@ +name: 'CodeQL: Code Scanning' + +on: + # push: + # branches: [ main ] + # pull_request: + # # The branches below must be a subset of the branches above + # branches: [ main ] + schedule: + # Runs at 14:43 UTC on Sun. + - cron: '43 14 * * 0' + workflow_dispatch: + +jobs: + analyze: + name: Analyze + # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest + runs-on: ubuntu-latest + + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + language: ['javascript'] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + + - name: 'Set current job url in SLACK_FOOTER env var' + if: ${{ failure() }} + run: echo "SLACK_FOOTER=<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Click here to go to the job logs>" >> $GITHUB_ENV + + - name: Slack Notification on Failure + if: ${{ failure() }} + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_TITLE: 'CodeQL: Code Scanning failed :x:' + SLACK_COLOR: '#FF0000' + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: feed-prisma-failures + SLACK_USERNAME: Prismo + SLACK_ICON_EMOJI: ':boom:' + SLACK_MSG_AUTHOR: prisma-bot diff --git a/.github/workflows/codesee-arch-diagram.yml b/.github/workflows/codesee-arch-diagram.yml new file mode 100644 index 000000000000..cd9993373743 --- /dev/null +++ b/.github/workflows/codesee-arch-diagram.yml @@ -0,0 +1,57 @@ +on: + push: + branches: + - main + pull_request_target: + types: [opened, synchronize, reopened] + +name: CodeSee Map + +jobs: + test_map_action: + runs-on: ubuntu-latest + continue-on-error: true + name: Run CodeSee Map Analysis + steps: + - name: checkout + id: checkout + uses: actions/checkout@v3 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + + # codesee-detect-languages has an output with id languages. + - name: Detect Languages + id: detect-languages + uses: Codesee-io/codesee-detect-languages-action@latest + + - name: Configure Node.js 14 + uses: actions/setup-node@v3 + if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }} + with: + node-version: '14' + + - name: Generate Map + id: generate-map + uses: Codesee-io/codesee-map-action@latest + with: + step: map + github_ref: ${{ github.ref }} + languages: ${{ steps.detect-languages.outputs.languages }} + + - name: Upload Map + id: upload-map + uses: Codesee-io/codesee-map-action@latest + with: + step: mapUpload + api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} + github_ref: ${{ github.ref }} + + - name: Insights + id: insights + uses: Codesee-io/codesee-map-action@latest + with: + step: insights + api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} + github_ref: ${{ github.ref }} diff --git a/.github/workflows/detect-jobs-to-run.js b/.github/workflows/detect-jobs-to-run.js index d104fa4c3d83..922521a3e14f 100755 --- a/.github/workflows/detect-jobs-to-run.js +++ b/.github/workflows/detect-jobs-to-run.js @@ -1,73 +1,57 @@ #!/usr/bin/env node // @ts-check -const { stdin } = process; +const { stdin } = process // From https://github.com/sindresorhus/get-stdin/blob/main/index.js async function getStdin() { - let result = ""; + let result = '' if (stdin.isTTY) { - return result; + return result } - stdin.setEncoding("utf8"); + stdin.setEncoding('utf8') for await (const chunk of stdin) { - result += chunk; + result += chunk } - return result; + return result } async function main() { - const stdinData = await getStdin(); - console.log("stdin:", stdinData); + const stdinData = await getStdin() + console.log('stdin:', stdinData) /** * @type string[] **/ - const filesChanged = JSON.parse(stdinData); - console.log("filesChanged:", filesChanged); + const filesChanged = JSON.parse(stdinData) + console.log('filesChanged:', filesChanged) - const jobsToRun = []; + const jobsToRun = [] // If changes are located only in one of the paths below - if ( - filesChanged.every((fileChanged) => - fileChanged.startsWith("packages/cli/") - ) - ) { - jobsToRun.push("-cli-"); - } else if ( - filesChanged.every((fileChanged) => - fileChanged.startsWith("packages/client/") - ) - ) { - jobsToRun.push("-client-"); - jobsToRun.push("-integration-tests-"); - jobsToRun.push("-cli-"); - } else if ( - filesChanged.every((fileChanged) => - fileChanged.startsWith("packages/integration-tests/") - ) - ) { - jobsToRun.push("-integration-tests-"); - } else if ( - filesChanged.every((fileChanged) => - fileChanged.startsWith("packages/migrate/") - ) - ) { - jobsToRun.push("-migrate-"); - jobsToRun.push("-cli-"); + if (filesChanged.every((fileChanged) => fileChanged.startsWith('packages/cli/'))) { + jobsToRun.push('-cli-') + } else if (filesChanged.every((fileChanged) => fileChanged.startsWith('packages/client/'))) { + jobsToRun.push('-client-') + jobsToRun.push('-integration-tests-') + jobsToRun.push('-cli-') + } else if (filesChanged.every((fileChanged) => fileChanged.startsWith('packages/integration-tests/'))) { + jobsToRun.push('-integration-tests-') + } else if (filesChanged.every((fileChanged) => fileChanged.startsWith('packages/migrate/'))) { + jobsToRun.push('-migrate-') + jobsToRun.push('-cli-') } else { - jobsToRun.push("-all-"); + jobsToRun.push('-all-') } - console.log("jobsToRun:", jobsToRun); - console.log("::set-output name=jobs::" + jobsToRun.join()); + console.log('jobsToRun:', jobsToRun) + console.log('::set-output name=jobs::' + jobsToRun.join()) } main().then(function () { - console.log("Done"); -}); + console.log('Done') +}) diff --git a/.github/workflows/install-mysql.ps1 b/.github/workflows/install-mysql.ps1 index 9d5d81a00f96..a699ff2b60d4 100644 --- a/.github/workflows/install-mysql.ps1 +++ b/.github/workflows/install-mysql.ps1 @@ -1,4 +1,5 @@ -Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh') +iwr -useb 'https://get.scoop.sh' -outfile 'scoopinstaller.ps1' +.\scoopinstaller.ps1 -RunAsAdmin scoop install mysql diff --git a/.github/workflows/label-stale-issues.yml b/.github/workflows/label-stale-issues.yml index bbd9b83338a7..83ffb264711a 100644 --- a/.github/workflows/label-stale-issues.yml +++ b/.github/workflows/label-stale-issues.yml @@ -1,7 +1,7 @@ -name: "Labels stale issues" +name: 'Labels stale issues' on: schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' workflow_dispatch: jobs: @@ -11,12 +11,28 @@ jobs: - uses: pantharshit00/stale@v3.1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: "DUMMY, FOR ENABLING" + stale-issue-message: 'DUMMY, FOR ENABLING' days-before-stale: 90 days-before-close: -1 - exempt-issue-labels: "kind/discussion,kind/docs,kind/feature,kind/improvement,kind/question,kind/epic,kind/subtask" - stale-issue-label: "status/needs-action" + exempt-issue-labels: 'kind/discussion,kind/docs,kind/feature,kind/improvement,kind/question,kind/epic,kind/subtask' + stale-issue-label: 'status/needs-action' skip-stale-issue-message: true skip-stale-pr-message: true ascending: true operations-per-run: 100 + + - name: 'Set current job url in SLACK_FOOTER env var' + if: ${{ failure() }} + run: echo "SLACK_FOOTER=<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Click here to go to the job logs>" >> $GITHUB_ENV + + - name: Slack Notification on Failure + if: ${{ failure() }} + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_TITLE: 'Labels stale issues failed :x:' + SLACK_COLOR: '#FF0000' + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: feed-prisma-failures + SLACK_USERNAME: Prismo + SLACK_ICON_EMOJI: ':boom:' + SLACK_MSG_AUTHOR: prisma-bot diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml new file mode 100644 index 000000000000..a0106f941b0b --- /dev/null +++ b/.github/workflows/scorecards-analysis.yml @@ -0,0 +1,69 @@ +name: Scorecards supply-chain security +on: + # when a branch protection rule has been edited, created or deleted + branch_protection_rule: + push: + # Only the default branch is supported. + branches: [main] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecards analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + actions: read + contents: read + + steps: + - name: 'Checkout code' + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: 'Run analysis' + uses: ossf/scorecard-action@v1.0.4 + with: + results_file: results.sarif + results_format: sarif + # Read-only PAT token. To create it, + # follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation. + repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} + # Publish the results to enable scorecard badges. For more details, see + # https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories, `publish_results` will automatically be set to `false`, + # regardless of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). + - name: 'Upload artifact' + uses: actions/upload-artifact@v3.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: 'Upload to code-scanning' + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: results.sarif + + - name: 'Set current job url in SLACK_FOOTER env var' + run: echo "SLACK_FOOTER=<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Click here to go to the job logs>" >> $GITHUB_ENV + + - name: Slack Notification on Failure + if: ${{ failure() }} + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_TITLE: 'Scorecards supply-chain security failed :x:' + SLACK_COLOR: '#FF0000' + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: feed-prisma-failures + SLACK_USERNAME: Prismo + SLACK_ICON_EMOJI: ':boom:' + SLACK_MSG_AUTHOR: prisma-bot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 93d9c4d00ae4..75e0bc4527f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,6 +44,7 @@ on: - 'graphs/**' env: + HAS_BUILDPULSE_SECRETS: ${{ secrets.BUILDPULSE_ACCESS_KEY_ID != '' && secrets.BUILDPULSE_SECRET_ACCESS_KEY != '' }} PRISMA_TELEMETRY_INFORMATION: 'prisma test.yml' jobs: @@ -54,7 +55,7 @@ jobs: jobs: ${{ steps.detect.outputs.jobs }} steps: - id: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - id: files uses: Ana06/get-changed-files@v1.2 # it's a fork of jitterbit/get-changed-files@v1 which works better with pull requests with: @@ -81,16 +82,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: '12' - run: bash .github/workflows/setup.sh @@ -106,7 +106,7 @@ jobs: # CLIENT (without types test) # client: - timeout-minutes: 25 + timeout-minutes: 35 runs-on: ${{ matrix.os }} needs: detect_jobs_to_run @@ -120,7 +120,7 @@ jobs: node: [12, 16] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set CLI Engine Type run: | @@ -130,16 +130,15 @@ jobs: run: | echo "PRISMA_CLIENT_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV - - run: docker-compose -f docker/docker-compose.yml up --detach postgres postgres_isolated mysql mysql_isolated mssql cockroachdb + - run: docker-compose -f docker/docker-compose.yml up --detach postgres postgres_isolated mysql mysql_isolated mssql mongo cockroachdb - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -160,6 +159,7 @@ jobs: TEST_MYSQL_ISOLATED_URI: mysql://root:root@localhost:3307/tests TEST_MSSQL_URI: mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/master TEST_MSSQL_JDBC_URI: sqlserver://localhost:1433;database=master;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; + TEST_MONGO_URI: 'mongodb://root:prisma@localhost:27018/tests?authSource=admin' NODE_OPTIONS: '--max-old-space-size=8096' - uses: codecov/codecov-action@v2 @@ -184,16 +184,15 @@ jobs: node: [12] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -235,10 +234,11 @@ jobs: - mysql - mariadb - mssql + # - mongo node: [12] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set CLI Engine Type run: | @@ -251,14 +251,13 @@ jobs: - run: docker-compose -f docker/docker-compose.yml up --detach ${{matrix.database}} if: matrix.database != 'sqlite' - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -310,7 +309,7 @@ jobs: node: [12, 16] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: docker-compose -f docker/docker-compose.yml up --detach postgres mysql mssql @@ -322,14 +321,13 @@ jobs: run: | echo "PRISMA_CLIENT_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -373,9 +371,9 @@ jobs: node: [12, 16] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - run: docker-compose -f docker/docker-compose.yml up --detach postgres mysql mssql mongo mongo-seed + - run: docker-compose -f docker/docker-compose.yml up --detach postgres mysql mssql mongodb_migrate mongodb_migrate_seed - name: Set CLI Engine Type run: | @@ -385,14 +383,13 @@ jobs: run: | echo "PRISMA_CLIENT_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -420,7 +417,7 @@ jobs: TEST_MSSQL_URI: mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/master TEST_MSSQL_JDBC_URI_MIGRATE: 'sqlserver://localhost:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;' TEST_MSSQL_SHADOWDB_JDBC_URI_MIGRATE: 'sqlserver://localhost:1433;database=tests-migrate-shadowdb;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;' - TEST_MONGO_URI: 'mongodb://root:prisma@localhost:27017/tests?authSource=admin' + TEST_MONGO_URI_MIGRATE: 'mongodb://root:prisma@localhost:27017/tests-migrate?authSource=admin' - uses: codecov/codecov-action@v2 with: @@ -446,7 +443,7 @@ jobs: node: [12, 16] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set CLI Engine Type run: | @@ -456,14 +453,13 @@ jobs: run: | echo "PRISMA_CLIENT_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -502,16 +498,15 @@ jobs: node: [12, 16] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -563,27 +558,26 @@ jobs: name: generator-helper-${{ matrix.os }} # - # Run all tests on macOS and Windows. + # Run (almost) all tests on macOS and Windows. # # Unlike the other jobs, this job doesn't use Docker (and thus skips some # tests that require dependencies not easily installable without Docker). # - # It also runs the tests for different packages sequentially to prevent the - # combinatorial explosion of the number of parallel jobs, to minimize the - # number of times we need to install MySQL using the package manager + # It also runs most tests for different packages sequentially (except client, + # see below) to prevent the combinatorial explosion of the number of parallel jobs, + # to minimize the number of times we need to install MySQL using the package manager # (PostgreSQL and MongoDB are provided by GitHub Actions out of the box), and # minimize the time spent waiting for a free runner. # no-docker: timeout-minutes: 40 runs-on: ${{ matrix.os }} - needs: detect_jobs_to_run + needs: detect_jobs_to_run if: | ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-sdk-') || - contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-migrate-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-cli-') }} @@ -591,19 +585,20 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-11, windows-latest] + os: [macos-latest, windows-latest] node: [16] queryEngine: ['library', 'binary'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Prerequisites shell: bash run: | echo "TEST_SKIP_MSSQL=true" >> $GITHUB_ENV + echo "TEST_SKIP_MONGODB=true" >> $GITHUB_ENV echo "TEST_SKIP_COCKROACHDB=true" >> $GITHUB_ENV - echo "TEST_MONGO_URI=mongodb://localhost:27017/tests" >> $GITHUB_ENV + echo "TEST_MONGO_URI_MIGRATE=mongodb://localhost:27017/tests-migrate" >> $GITHUB_ENV echo "PRISMA_CLI_QUERY_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV echo "PRISMA_CLIENT_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV @@ -613,14 +608,13 @@ jobs: - name: Setup MySQL run: bash .github/workflows/setup-mysql.sh - - name: Cache .pnpm-store - uses: actions/cache@v2 + - uses: pnpm/action-setup@v2.2.1 with: - path: ~/.pnpm-store - key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/pnpm-lock.yaml') }} + version: latest - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: + cache: 'pnpm' node-version: ${{ matrix.node }} - run: bash .github/workflows/setup.sh @@ -631,12 +625,13 @@ jobs: - name: Test packages/sdk if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') }} || contains(needs.detect_jobs_to_run.outputs.jobs, '-sdk-') }} - run: pnpm run test + run: pnpm run test -- --testTimeout=40000 working-directory: packages/sdk env: CI: true SKIP_GIT: true GITHUB_CONTEXT: ${{ toJson(github) }} + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/sdk/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' - uses: codecov/codecov-action@v2 if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') }} || contains(needs.detect_jobs_to_run.outputs.jobs, '-sdk-') }} @@ -645,31 +640,15 @@ jobs: flags: sdk,${{ matrix.os }},${{ matrix.queryEngine }} name: sdk-${{ matrix.os }}-${{ matrix.queryEngine }} - - name: Test packages/client - if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') }} - run: pnpm run test-notypes - working-directory: packages/client - env: - CI: true - SKIP_GIT: true - GITHUB_CONTEXT: ${{ toJson(github) }} - NODE_OPTIONS: '--max-old-space-size=8096' - - - uses: codecov/codecov-action@v2 - if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') }} - with: - files: ./packages/client/src/__tests__/coverage/clover.xml - flags: client,${{ matrix.os }},${{ matrix.queryEngine }} - name: client-${{ matrix.os }}-${{ matrix.queryEngine }} - - name: Test packages/migrate if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-migrate-') }} - run: pnpm run test + run: pnpm run test -- --testTimeout=40000 working-directory: packages/migrate env: CI: true SKIP_GIT: true GITHUB_CONTEXT: ${{ toJson(github) }} + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/migrate/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' - uses: codecov/codecov-action@v2 if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-migrate-') }} @@ -680,12 +659,13 @@ jobs: - name: Test packages/cli if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-cli-') }} - run: pnpm run test + run: pnpm run test -- --testTimeout=40000 working-directory: packages/cli env: CI: true SKIP_GIT: true GITHUB_CONTEXT: ${{ toJson(github) }} + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/cli/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' - uses: codecov/codecov-action@v2 if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-cli-') }} @@ -702,6 +682,7 @@ jobs: CI: true SKIP_GIT: true GITHUB_CONTEXT: ${{ toJson(github) }} + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/debug/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' - uses: codecov/codecov-action@v2 if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') }} @@ -718,6 +699,7 @@ jobs: CI: true SKIP_GIT: true GITHUB_CONTEXT: ${{ toJson(github) }} + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/engine-core/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' - uses: codecov/codecov-action@v2 if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') }} @@ -734,6 +716,7 @@ jobs: CI: true SKIP_GIT: true GITHUB_CONTEXT: ${{ toJson(github) }} + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/generator-helper/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' - uses: codecov/codecov-action@v2 if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') }} @@ -741,3 +724,108 @@ jobs: files: ./packages/generator-helper/src/__tests__/coverage/clover.xml flags: generator-helper,${{ matrix.os }},library,binary name: generator-helper-${{ matrix.os }} + + - name: Upload test results to BuildPulse for flaky test detection + # Only run this step for branches where where we have access to secrets. + # Run this step even when the tests fail. Skip if the workflow is cancelled. + if: env.HAS_BUILDPULSE_SECRETS == 'true' && !cancelled() + uses: Workshop64/buildpulse-action@main + with: + account: 17219288 + repository: 192925833 + path: packages + key: ${{ secrets.BUILDPULSE_ACCESS_KEY_ID }} + secret: ${{ secrets.BUILDPULSE_SECRET_ACCESS_KEY }} + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: ${{ github.job }}_${{ matrix.os }}_node-${{ matrix.node }}_${{ matrix.queryEngine }}_junit.xml + path: packages/*/junit.xml + + # + # Run Client tests on macOS and Windows. (Reasoning see above) + # + no-docker-client: + timeout-minutes: 40 + runs-on: ${{ matrix.os }} + + needs: detect_jobs_to_run + if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') }} + + strategy: + fail-fast: false + matrix: + os: [macos-latest, windows-latest] + node: [16] + queryEngine: ['library', 'binary'] + + steps: + - uses: actions/checkout@v3 + + - name: Prerequisites + shell: bash + run: | + echo "TEST_SKIP_MSSQL=true" >> $GITHUB_ENV + echo "TEST_SKIP_MONGODB=true" >> $GITHUB_ENV + echo "TEST_SKIP_COCKROACHDB=true" >> $GITHUB_ENV + echo "TEST_MONGO_URI_MIGRATE=mongodb://localhost:27017/tests-migrate" >> $GITHUB_ENV + echo "PRISMA_CLI_QUERY_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV + echo "PRISMA_CLIENT_ENGINE_TYPE=${{ matrix.queryEngine }}" >> $GITHUB_ENV + + - name: Setup PostgreSQL + run: bash .github/workflows/setup-postgres.sh + + - name: Setup MySQL + run: bash .github/workflows/setup-mysql.sh + + - uses: pnpm/action-setup@v2.2.1 + with: + version: latest + + - uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node }} + + - run: bash .github/workflows/setup.sh + env: + CI: true + SKIP_GIT: true + GITHUB_CONTEXT: ${{ toJson(github) }} + + - name: Test packages/client + if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') }} + run: pnpm run test-notypes -- --testTimeout=40000 + working-directory: packages/client + env: + CI: true + SKIP_GIT: true + GITHUB_CONTEXT: ${{ toJson(github) }} + NODE_OPTIONS: '--max-old-space-size=8096' + JEST_JUNIT_SUITE_NAME: '${{ github.job }}/client/${{ matrix.os }}/node-${{ matrix.node }}/${{ matrix.queryEngine }}' + + - uses: codecov/codecov-action@v2 + if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') }} + with: + files: ./packages/client/src/__tests__/coverage/clover.xml + flags: client,${{ matrix.os }},${{ matrix.queryEngine }} + name: client-${{ matrix.os }}-${{ matrix.queryEngine }} + + - name: Upload test results to BuildPulse for flaky test detection + # Only run this step for branches where where we have access to secrets. + # Run this step even when the tests fail. Skip if the workflow is cancelled. + if: env.HAS_BUILDPULSE_SECRETS == 'true' && !cancelled() + uses: Workshop64/buildpulse-action@main + with: + account: 17219288 + repository: 192925833 + path: packages/client + key: ${{ secrets.BUILDPULSE_ACCESS_KEY_ID }} + secret: ${{ secrets.BUILDPULSE_SECRET_ACCESS_KEY }} + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: ${{ github.job }}_${{ matrix.os }}_node-${{ matrix.node }}_${{ matrix.queryEngine }}_junit.xml + path: packages/*/junit.xml diff --git a/.github/workflows/update-engines-version.yml b/.github/workflows/update-engines-version.yml index 21692b0bf60e..8c6cfc31e72d 100644 --- a/.github/workflows/update-engines-version.yml +++ b/.github/workflows/update-engines-version.yml @@ -3,23 +3,25 @@ on: workflow_dispatch: inputs: version: - description: "Version to check and update the engines version" + description: 'Version to check and update the engines version' required: true jobs: update_engines: - name: "Check and update @prisma/engines@${{ github.event.inputs.version }}" + name: 'Check and update @prisma/engines@${{ github.event.inputs.version }}' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Use Node.js - uses: actions/setup-node@v2 - - - uses: pnpm/action-setup@v2.0.1 + - uses: pnpm/action-setup@v2.2.1 with: version: latest - + + - uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: '16' + # This step uses `@prisma/ensure-npm-release` (abbv. `enr`) https://github.com/prisma/ensure-npm-release - name: Check if version is available on npm run: | @@ -28,25 +30,30 @@ jobs: pnpx -y -p @prisma/ensure-npm-release enr update -p @prisma/engines-version -u ${{ github.event.inputs.version }} pnpx -y -p @prisma/ensure-npm-release enr update -p @prisma/fetch-engine -u ${{ github.event.inputs.version }} pnpx -y -p @prisma/ensure-npm-release enr update -p @prisma/get-platform -u ${{ github.event.inputs.version }} - echo 'Awesome - proceeding to make the PR' - + echo 'Awesome - proceeding to update the dependencies' + - name: Update the engines dependencies - run: | - echo 'Updating @prisma/engines, @prisma/engines-version, @prisma/fetch-engine and @prisma/get-platform to ${{ github.event.inputs.version }} using pnpm' - pnpm update -r @prisma/engines@${{ github.event.inputs.version }} @prisma/engines-version@${{ github.event.inputs.version }} @prisma/fetch-engine@${{ github.event.inputs.version }} @prisma/get-platform@${{ github.event.inputs.version }} + uses: nick-fields/retry@v2 + with: + timeout_minutes: 7 + max_attempts: 3 + command: | + echo 'Updating @prisma/engines, @prisma/engines-version, @prisma/fetch-engine and @prisma/get-platform to ${{ github.event.inputs.version }} using pnpm' + pnpm update -r @prisma/engines@${{ github.event.inputs.version }} @prisma/engines-version@${{ github.event.inputs.version }} @prisma/fetch-engine@${{ github.event.inputs.version }} @prisma/get-platform@${{ github.event.inputs.version }} + echo 'Awesome - proceeding to make the PR' - name: Create Pull Request id: cpr uses: peter-evans/create-pull-request@v3 with: token: ${{ secrets.BOT_TOKEN }} - commit-message: "chore(deps): update engines to ${{ github.event.inputs.version }}" - committer: "Prismo " - author: "Prismo " + commit-message: 'chore(deps): update engines to ${{ github.event.inputs.version }}' + committer: 'Prismo ' + author: 'Prismo ' branch: deps/engines-${{ github.event.inputs.version }} delete-branch: true labels: automerge - title: "chore(deps): update engines to ${{ github.event.inputs.version }}" + title: 'chore(deps): update engines to ${{ github.event.inputs.version }}' body: | This automatic PR updates the engines to version `${{ github.event.inputs.version }}`. This will get automatically merged if all the tests pass. ## Packages: @@ -60,8 +67,8 @@ jobs: - name: PR url run: | echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" - - - name: Sleep for 5 seconds + + - name: Sleep for 5 seconds run: sleep 5s shell: bash @@ -71,3 +78,19 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.cpr.outputs.pull-request-number }} + + - name: 'Set current job url in SLACK_FOOTER env var' + if: ${{ failure() }} + run: echo "SLACK_FOOTER=<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Click here to go to the job logs>" >> $GITHUB_ENV + + - name: Slack Notification on Failure + if: ${{ failure() }} + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_TITLE: 'Update Engines Version failed :x:' + SLACK_COLOR: '#FF0000' + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: feed-prisma-failures + SLACK_USERNAME: Prismo + SLACK_ICON_EMOJI: ':boom:' + SLACK_MSG_AUTHOR: prisma-bot diff --git a/.github/workflows/update-studio-version.yml b/.github/workflows/update-studio-version.yml index b9c5da23c9f1..dbd1ce7e4165 100644 --- a/.github/workflows/update-studio-version.yml +++ b/.github/workflows/update-studio-version.yml @@ -1,33 +1,34 @@ - name: Update Studio Version on: workflow_dispatch: inputs: version: - description: "Version to check and update the studio version" + description: 'Version to check and update the studio version' required: true jobs: update_studio: - name: "Check and update @prisma/studio-server@${{ github.event.inputs.version }}" + name: 'Check and update @prisma/studio-server@${{ github.event.inputs.version }}' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - name: Use Node.js - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 - - uses: pnpm/action-setup@v2.0.1 + - uses: pnpm/action-setup@v2.2.1 with: version: latest - + + - uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: '16' + # This step uses `@prisma/ensure-npm-release` (abbv. `enr`) https://github.com/prisma/ensure-npm-release - name: Check if version is available on npm run: | echo 'Checking that package @prisma/studio-server have the published version @${{ github.event.inputs.version }}' pnpx -y -p @prisma/ensure-npm-release enr update -p @prisma/studio-server -u ${{ github.event.inputs.version }} echo 'Awesome - proceeding to make the PR' - + - name: Update the studio dependencies run: | echo 'Updating @prisma/studio-server to ${{ github.event.inputs.version }} using pnpm' @@ -38,13 +39,13 @@ jobs: uses: peter-evans/create-pull-request@v3 with: token: ${{ secrets.BOT_TOKEN }} - commit-message: "chore(deps): update studio to ${{ github.event.inputs.version }}" - committer: "Prismo " - author: "Prismo " + commit-message: 'chore(deps): update studio to ${{ github.event.inputs.version }}' + committer: 'Prismo ' + author: 'Prismo ' branch: deps/studio-${{ github.event.inputs.version }} delete-branch: true labels: automerge - title: "chore(deps): update studio to ${{ github.event.inputs.version }}" + title: 'chore(deps): update studio to ${{ github.event.inputs.version }}' body: | This automatic PR updates the studio to version `${{ github.event.inputs.version }}`. This will get automatically merged if all the tests pass. ## Packages: @@ -55,8 +56,8 @@ jobs: - name: PR url run: | echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" - - - name: Sleep for 5 seconds + + - name: Sleep for 5 seconds run: sleep 5s shell: bash @@ -66,3 +67,19 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.cpr.outputs.pull-request-number }} + + - name: 'Set current job url in SLACK_FOOTER env var' + if: ${{ failure() }} + run: echo "SLACK_FOOTER=<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Click here to go to the job logs>" >> $GITHUB_ENV + + - name: Slack Notification on Failure + if: ${{ failure() }} + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_TITLE: 'Update Studio Version failed :x:' + SLACK_COLOR: '#FF0000' + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_CHANNEL: feed-prisma-failures + SLACK_USERNAME: Prismo + SLACK_ICON_EMOJI: ':boom:' + SLACK_MSG_AUTHOR: prisma-bot diff --git a/.gitignore b/.gitignore index 7cb7ddb595c6..6a5056a8f96d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,6 @@ query_engine-windows.dll.node dist/ *.tsbuildinfo -.env* .prisma .pnpm-store @@ -28,8 +27,14 @@ coverage node_modules .pnpm-store/ -.env* yarn-error.log .DS_Store pnpm-debug.log .pnpm-debug.log + +.envrc + +esm +reproductions/* +!reproductions/basic-sqlite +!reproductions/pnpm-workspace.yaml diff --git a/.husky/pre-commit b/.husky/pre-commit index 3bb0de0dbcf2..5e5927356989 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -pnpm exec ts-node scripts/lint.ts --staged +pnpm exec lint-staged diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56476695eb58..e30896cd68d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,24 +6,6 @@ To get you started on a good foot, we've created an easy overview of the most im We also encourage you to join our sprawling [community](https://www.prisma.io/community) online, where you can discuss ideas, ask questions and get inspiration for what to build next. -## Table of Contents - -- Contributing Code - - General Prerequisites - - General Setup - - Prisma Client - - Initial Setup - - Building and Running Prisma Client - - Tests - - Prisma Migrate - - Initial Setup - - Building and Running Prisma Migrate - - Tests -- Additional Resources -- Conventions - - Git Commit Messages -- Legal - ## Contributing Code Welcome to the monorepo for our TypeScript code for the Prisma ORM. (for the Engines' code written in Rust [it's there](https://github.com/prisma/prisma-engines) @@ -31,8 +13,10 @@ Welcome to the monorepo for our TypeScript code for the Prisma ORM. (for the Eng ## General Prerequisites 1. Install Node.js `>=12.6` minimum, [latest LTS is recommended](https://nodejs.org/en/about/releases/) + - Recommended: use [`nvm`](https://github.com/nvm-sh/nvm) for managing Node.js versions -1. Install [`pnpm`](https://pnpm.js.org/) (for installing npm dependencies, using pnpm workspaces) + +1. Install [`pnpm`](https://pnpm.io/) (for installing npm dependencies, using pnpm workspaces) 1. Install [`docker`](https://www.docker.com/products/docker-desktop) (for managing databases for our tests) 1. Install [`ts-node`](https://github.com/TypeStrong/ts-node) (for running Node.js scripts written in TypeScript) 1. Install [`direnv`](https://github.com/direnv/direnv/blob/master/docs/installation.md) (for managing .envrc for environment variables) @@ -59,8 +43,7 @@ pnpm i pnpm run setup ``` -Note for Windows: -Use the latest version of [Git Bash](https://gitforwindows.org/) +> 💡 For Windows users: use the latest version of [Git Bash](https://gitforwindows.org/). ## Building packages when you make changes @@ -68,24 +51,75 @@ In the root directory: - `pnpm run setup` will install and build all the packages - `pnpm -r run build` (-r for recursive) will build all the packages -- `pnpm -r run dev` (-r for recursive) will build all the packages without running `tsc` (Fastest) +- `pnpm -r run dev` (-r for recursive) will build all the packages, without running `tsc` +- `pnpm run watch` will continuously build any packages that have been modified, without running `tsc` (Fastest) In a package directory, like `packages/client`: - `pnpm run build` will build the package - `pnpm run dev` will build the package without running `tsc` (Fastest) -Note: Our builder is ESbuild +> 💡 Our builder is built on top of esbuild ## Prisma Client ### First contribution -1. `cd packages/client` -1. `ts-node fixtures/generate.ts ./fixtures/blog/ --skip-transpile` -1. `cd fixtures/blog` -1. `npx prisma db push --skip-generate` will create the database structure -1. `ts-node main` +Create a reproduction folder for developing, trying a new feature, or a fix. + +#### Setting up a locally-linked development folder + +Set up a local project that will be linked to the local packages. + +```sh +cd reproductions && pnpm install +# Copy a template from the reproduction folder +cp -r basic-sqlite my-repro && cd my-repro +# Ensure that the db and the schema are synced +pnpx prisma db push --skip-generate +# Do some code changes, always re-generate the client, then try it out +pnpx prisma generate && pnpx ts-node index.ts +``` + +> 💡 This works best when compiling with `pnpm run watch` in the background. + +> 💡 In any successful setup `pnpx prisma -v` should return version `0.0.0`. + +
+ Alternatives + + #### Detailed steps for a locally-linked dev folder + ```sh + cd reproductions + mkdir my-repro + cd my-repro + pnpm init -y + pnpm add ../../packages/client + pnpm add -D ../../packages/cli + pnpm add -D typescript ts-node + pnpm add -D @types/node + touch index.ts + pnpx tsc --init + pnpx prisma init + # > Manually populate the schema.prisma + # > Manually add 👇 to the generator block + # output = "../node_modules/.prisma/client" + # > Manually populate the index.ts + pnpx prisma db push --skip-generate + pnpx prisma generate && pnpx ts-node index.ts # Try it out + ``` + +#### Developing and working in the fixture folder + +```sh +cd packages/client +ts-node fixtures/generate.ts ./fixtures/blog/ --skip-transpile +cd fixtures/blog +npx prisma db push --skip-generate +ts-node main.ts # Try it out +``` + +
### Tests @@ -101,8 +135,10 @@ The integration tests consisting of mini projects are located in [`src/client/sr Run the tests: -1. `cd packages/client` -2. `pnpm run test integration` +```sh +cd packages/client +pnpm run test integration +``` ##### Creating a new folder-based integration test @@ -117,8 +153,10 @@ The integration tests consisting of mini project are located in [`packages/integ Run the tests: -1. `cd packages/integration-tests` -2. `pnpm run test` +```sh +cd packages/integration-tests +pnpm run test +``` ## Prisma Migrate @@ -128,13 +166,15 @@ Run the tests: 1. Then modify some code 1. `../../src/bin.ts dev` for running `prisma migrate dev` +> 💡 You can also test your changes in a reproduction project via the [CLI](#developing-prisma-cli). + ### Tests For an overview, adding, running tests & guidelines see [TESTING.md](./TESTING.md). Tests fixtures are located in [`./packages/migrate/src/__tests__/fixtures`](./packages/migrate/src/__tests__/fixtures) -## Additional Ressources +## Additional Resources - [ARCHITECTURE.md](./ARCHITECTURE.md) - [TESTING.md](./TESTING.md) @@ -143,10 +183,35 @@ Tests fixtures are located in [`./packages/migrate/src/__tests__/fixtures`](./pa ## Prisma CLI -### Developing `prisma` CLI +### First contribution + +Create a reproduction folder for developing, trying a new feature, or a fix. + +#### Setting up a locally-linked development folder + +Set up a local project that will be linked to the local packages. + +```sh +cd reproductions && pnpm install +# Copy a template from the reproduction folder +cp -r basic-sqlite my-repro && cd my-repro +# Do some code changes, compile, then try it out +pnpx prisma generate +``` + +> 💡 This works best when compiling with `pnpm run watch` in the background. + +> 💡 In any successful setup `pnpx prisma -v` should return version `0.0.0`. + +
+ Alternatives + +```sh +cd packages/cli +../src/bin.ts generate # Try it out +``` -1. `cd packages/cli` -1. `../src/bin.ts generate` to run `prisma generate` +
## Conventions diff --git a/README.md b/README.md index 6320853ed103..ed69c1aef086 100644 --- a/README.md +++ b/README.md @@ -184,10 +184,7 @@ const allUsers = await prisma.user.findMany({ // Run inside `async` function const filteredPosts = await prisma.post.findMany({ where: { - OR: [ - { title: { contains: 'prisma' } }, - { content: { contains: 'prisma' } }, - ], + OR: [{ title: { contains: 'prisma' } }, { content: { contains: 'prisma' } }], }, }) ``` diff --git a/TESTING.md b/TESTING.md index f24622363304..4fd5397fc448 100644 --- a/TESTING.md +++ b/TESTING.md @@ -21,17 +21,18 @@ export TEST_MYSQL_SHADOWDB_URI_MIGRATE="mysql://root:root@localhost:3306/tests-m export TEST_MARIADB_URI="mysql://prisma:prisma@localhost:4306/tests" -export TEST_MSSQL_URI="mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/tests" # for `mssql` lib used in some tests -export TEST_MSSQL_JDBC_URI="sqlserver://localhost:1433;database=tests;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;" +export TEST_MSSQL_URI="mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/master" # for `mssql` lib used in some tests +export TEST_MSSQL_JDBC_URI="sqlserver://localhost:1433;database=master;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;" export TEST_MSSQL_JDBC_URI_MIGRATE="sqlserver://localhost:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;" export TEST_MSSQL_SHADOWDB_JDBC_URI_MIGRATE="sqlserver://localhost:1433;database=tests-migrate-shadowdb;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;" -export TEST_MONGO_URI="mongodb://root:prisma@localhost:27017/tests?authSource=admin" +export TEST_MONGO_URI="mongodb://root:prisma@localhost:27018/tests?authSource=admin" +export TEST_MONGO_URI_MIGRATE="mongodb://root:prisma@localhost:27017/tests-migrate?authSource=admin" export TEST_COCKROACH_URI=postgresql://prisma@localhost:26257/ ``` -- Load the environnment variables with: +- Load the environment variables with: ```sh direnv allow diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index c560e61124a0..a93749799020 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,28 +1,8 @@ version: '3.7' -services: - # In Docker - # - TEST_POSTGRES_URI_MIGRATE=postgres://prisma:prisma@postgres/tests-migrate - # - TEST_POSTGRES_URI=postgres://prisma:prisma@postgres/tests - # - TEST_POSTGRES_ISOLATED_URI=postgres://prisma:prisma@postgres_isolated:5435/tests - # - TEST_MYSQL_URI=mysql://prisma:prisma@mysql:3306/tests - # - TEST_MYSQL_ISOLATED_URI=mysql://prisma:prisma@mysql_isolated:3306/tests - # - TEST_MARIADB_URI=mysql://prisma:prisma@mariadb:4306/tests - # - TEST_MSSQL_URI=sqlserver://SA:Pr1sm4_Pr1sm4@mssql:1433/master - # - TEST_MSSQL_JDBC_URI=sqlserver://mssql:1433;database=master;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; - # - TEST_MONGO_URI=mongodb://root:prisma@mongo:27017/tests?authSource=admin - # - # Outside Docker - # - TEST_POSTGRES_URI_MIGRATE=postgres://prisma:prisma@localhost:5432/tests-migrate - # - TEST_POSTGRES_URI=postgres://prisma:prisma@localhost:5432/tests - # - TEST_COCKROACH_URI=postgresql://prisma@localhost:26257/ - # - TEST_POSTGRES_ISOLATED_URI=postgres://prisma:prisma@localhost:5435/tests - # - TEST_MYSQL_URI=mysql://prisma:prisma@localhost:3306/tests - # - TEST_MYSQL_ISOLATED_URI=mysql://prisma:prisma@localhost:3307/tests - # - TEST_MARIADB_URI=mysql://prisma:prisma@localhost:4306/tests - # - TEST_MSSQL_URI=sqlserver://SA:Pr1sm4_Pr1sm4@localhost:1433/master - # - TEST_MSSQL_JDBC_URI=sqlserver://mssql:1433;database=master;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true; - # - TEST_MONGO_URI=mongodb://root:prisma@localhost:27017/tests?authSource=admin +# For connection urls to the following instances, see +# https://github.com/prisma/prisma/blob/main/TESTING.md#environment-variables +services: postgres: image: postgres:10 restart: always @@ -30,8 +10,6 @@ services: - POSTGRES_DB=tests - POSTGRES_USER=prisma - POSTGRES_PASSWORD=prisma - volumes: - - postgres:/var/lib/postgresql/data ports: - '5432:5432' @@ -42,8 +20,6 @@ services: - POSTGRES_DB=tests - POSTGRES_USER=prisma - POSTGRES_PASSWORD=prisma - volumes: - - postgres_isolated:/var/lib/postgresql/data ports: - '5435:5432' @@ -62,14 +38,9 @@ services: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=tests - MYSQL_USER=prisma - - MYSQL_PASSWORD=prisma - # https://stackoverflow.com/questions/55559386/how-to-fix-mbind-operation-not-permitted-in-mysql-error-log - cap_add: - - SYS_NICE # CAP_SYS_NICE - volumes: - - mysql:/var/lib/mysql ports: - '3306:3306' + mysql_isolated: image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password @@ -79,13 +50,9 @@ services: - MYSQL_DATABASE=tests - MYSQL_USER=prisma - MYSQL_PASSWORD=prisma - # https://stackoverflow.com/questions/55559386/how-to-fix-mbind-operation-not-permitted-in-mysql-error-log - cap_add: - - SYS_NICE # CAP_SYS_NICE - volumes: - - mysql_isolated:/var/lib/mysql ports: - '3307:3306' + mariadb: image: mariadb:10 restart: always @@ -94,8 +61,6 @@ services: - MYSQL_DATABASE=tests - MYSQL_USER=prisma - MYSQL_PASSWORD=prisma - volumes: - - mariadb:/var/lib/mysql ports: - '4306:3306' @@ -105,30 +70,31 @@ services: environment: - ACCEPT_EULA=Y - SA_PASSWORD=Pr1sm4_Pr1sm4 - volumes: - - mssql:/var/opt/mssql ports: - '1433:1433' - mongo: + mongodb_migrate: image: mongo:4 restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: prisma - MONGO_INITDB_DATABASE: tests + MONGO_INITDB_DATABASE: tests-migrate ports: - '27017:27017' - mongo-seed: - build: ./mongo-seed - links: - - mongo + mongodb_migrate_seed: + build: ./mongodb_migrate_seed + depends_on: + - mongodb_migrate -volumes: - postgres: - postgres_isolated: - mysql: - mysql_isolated: - mariadb: - mssql: + # Replica Set (required for Prisma Client) + mongo: + build: ./mongodb_replica + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: prisma + MONGO_REPLICA_HOST: localhost + MONGO_REPLICA_PORT: 27018 + ports: + - '27018:27018' diff --git a/docker/mongo-seed/Dockerfile b/docker/mongo-seed/Dockerfile deleted file mode 100644 index a11c03001fc6..000000000000 --- a/docker/mongo-seed/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM mongo:4 - -COPY init.json /init.json - -CMD mongoimport --uri mongodb://root:prisma@mongo:27017/tests?authSource=admin --collection users --type json --file /init.json --jsonArray diff --git a/docker/mongodb_migrate_seed/Dockerfile b/docker/mongodb_migrate_seed/Dockerfile new file mode 100644 index 000000000000..3d5a3ea681f1 --- /dev/null +++ b/docker/mongodb_migrate_seed/Dockerfile @@ -0,0 +1,7 @@ +FROM mongo:4 + +COPY init.json /init.json + +# https://docs.mongodb.com/database-tools/mongoimport/ +# Drop and import collection +CMD mongoimport --uri mongodb://root:prisma@mongodb_migrate:27017/tests-migrate?authSource=admin --drop --collection users --type json --file /init.json --jsonArray diff --git a/docker/mongo-seed/init.json b/docker/mongodb_migrate_seed/init.json similarity index 69% rename from docker/mongo-seed/init.json rename to docker/mongodb_migrate_seed/init.json index ba0e35892a30..b32767029dca 100644 --- a/docker/mongo-seed/init.json +++ b/docker/mongodb_migrate_seed/init.json @@ -3,14 +3,17 @@ "name": "Jane Smith", "email": "1@prisma.io", "admin": true, + "numberOrString1": 1234, "hobbies": [ { "name": "Swimming", "tags": ["tag"], + "numberOrString2": 1234, "objects": [ { "name": "Object 1", - "tags": ["tag"] + "tags": ["tag"], + "numberOrString3": 1234 } ] } @@ -20,14 +23,17 @@ "name": "John Smith", "email": "2@prisma.io", "admin": false, + "numberOrString1": "567", "hobbies": [ { "name": "Running", "tags": ["tag"], + "numberOrString2": "567", "objects": [ { "name": "Object 1", - "tags": ["tag"] + "tags": ["tag"], + "numberOrString3": "567" } ] }, diff --git a/docker/mongodb_replica/Dockerfile b/docker/mongodb_replica/Dockerfile new file mode 100644 index 000000000000..62876faab953 --- /dev/null +++ b/docker/mongodb_replica/Dockerfile @@ -0,0 +1,11 @@ +FROM mongo:4 + +# we take over the default & start mongo in replica set mode in a background task +ENTRYPOINT mongod --port $MONGO_REPLICA_PORT --replSet rs0 --bind_ip 0.0.0.0 & MONGOD_PID=$!; \ +# we prepare the replica set with a single node and prepare the root user config +INIT_REPL_CMD="rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: '$MONGO_REPLICA_HOST:$MONGO_REPLICA_PORT' }] })"; \ +INIT_USER_CMD="db.createUser({ user: '$MONGO_INITDB_ROOT_USERNAME', pwd: '$MONGO_INITDB_ROOT_PASSWORD', roles: [ 'root' ] })"; \ +# we wait for the replica set to be ready and then submit the commands just above +until (mongo admin --port $MONGO_REPLICA_PORT --eval "$INIT_REPL_CMD && $INIT_USER_CMD"); do sleep 1; done; \ +# we are done but we keep the container by waiting on signals from the mongo task +echo "REPLICA SET ONLINE"; wait $MONGOD_PID; diff --git a/graphs/devDependencies.png b/graphs/devDependencies.png index 965a56880cbe..aaa15e4325b5 100644 Binary files a/graphs/devDependencies.png and b/graphs/devDependencies.png differ diff --git a/helpers/blaze/flatten.ts b/helpers/blaze/flatten.ts index cd64752c42db..a3900fc85eed 100644 --- a/helpers/blaze/flatten.ts +++ b/helpers/blaze/flatten.ts @@ -1,14 +1,14 @@ import type { L } from 'ts-toolbelt' -import { reduce } from './reduce' + import { concat } from './concat' +import { reduce } from './reduce' function wrap(item: unknown) { return Array.isArray(item) ? item : [item] } // eslint-disable-next-line prettier/prettier -type Flatten = - (I extends L.List ? I[number] : I)[] & {} +type Flatten = (I extends L.List ? I[number] : I)[] & {} /** * Returns a new array with all sub-array elements concatenated. diff --git a/helpers/blaze/handle.ts b/helpers/blaze/handle.ts index 9220f631d1e0..c3c59913592a 100644 --- a/helpers/blaze/handle.ts +++ b/helpers/blaze/handle.ts @@ -6,9 +6,7 @@ function handleSync(fn: () => R): R | E { } } -async function handleAsync( - fn: () => Promise | R, -): Promise { +async function handleAsync(fn: () => Promise | R): Promise { try { return await fn() } catch (e: unknown) { diff --git a/helpers/blaze/map.ts b/helpers/blaze/map.ts index 4fecfa40a3ef..6edaae0d4e83 100644 --- a/helpers/blaze/map.ts +++ b/helpers/blaze/map.ts @@ -1,6 +1,4 @@ -import type { A } from 'ts-toolbelt' -import type { L } from 'ts-toolbelt' -import type { O } from 'ts-toolbelt' +import type { A, L, O } from 'ts-toolbelt' export type LMapper = (item: I, key: number) => R export type OMapper = (item: I, key: string) => R @@ -9,10 +7,7 @@ type Map = { [K in keyof A]: R } -function mapList( - object: L & L.List, - mapper: LMapper, -): Map { +function mapList(object: L & L.List, mapper: LMapper): Map { const mapped = new Array(object.length) for (let i = 0; i < object.length; ++i) { @@ -22,10 +17,7 @@ function mapList( return mapped as any } -function mapObject( - object: O & O.Record, - mapper: OMapper, -): Map { +function mapObject(object: O & O.Record, mapper: OMapper): Map { const mapped = {} const keys = Object.keys(object) @@ -45,9 +37,7 @@ function mapObject( * @returns */ const map: typeof mapList & typeof mapObject = ((object: any, mapper: any) => { - return Array.isArray(object) - ? mapList(object, mapper) - : mapObject(object, mapper) + return Array.isArray(object) ? mapList(object, mapper) : mapObject(object, mapper) }) as any export { map } diff --git a/helpers/blaze/pipe.ts b/helpers/blaze/pipe.ts index 222b44a1aad6..223da1a95cef 100644 --- a/helpers/blaze/pipe.ts +++ b/helpers/blaze/pipe.ts @@ -1,5 +1,5 @@ -import type { F } from 'ts-toolbelt' -import type { A } from 'ts-toolbelt' +import type { A, F } from 'ts-toolbelt' + import { skip } from './transduce' function pipeSync(fn: F.Function, ...fns: F.Function[]) { @@ -42,28 +42,16 @@ pipe.async = pipeAsync // TODO: use the one from ts-toolbelt (broken atm since ts 4.1) export declare type PipeMultiSync = { (...fns: [F.Function]): F.Function - ( - ...fns: [F.Function, F.Function<[R0], R1>] - ): F.Function - ( - ...fns: [F.Function, F.Function<[R0], R1>, F.Function<[R1], R2>] - ): F.Function + (...fns: [F.Function, F.Function<[R0], R1>]): F.Function + (...fns: [F.Function, F.Function<[R0], R1>, F.Function<[R1], R2>]): F.Function< + P, + R2 + > ( - ...fns: [ - F.Function, - F.Function<[R0], R1>, - F.Function<[R1], R2>, - F.Function<[R2], R3>, - ] + ...fns: [F.Function, F.Function<[R0], R1>, F.Function<[R1], R2>, F.Function<[R2], R3>] ): F.Function ( - ...fns: [ - F.Function, - F.Function<[R0], R1>, - F.Function<[R1], R2>, - F.Function<[R2], R3>, - F.Function<[R3], R4>, - ] + ...fns: [F.Function, F.Function<[R0], R1>, F.Function<[R1], R2>, F.Function<[R2], R3>, F.Function<[R3], R4>] ): F.Function ( ...fns: [ @@ -129,22 +117,13 @@ export declare type PipeMultiSync = { export declare type PipeMultiAsync = { // eslint-disable-next-line prettier/prettier - ( - ...fns: [F.Function ] - ): F.Function>> + (...fns: [F.Function]): F.Function>> ( // eslint-disable-next-line prettier/prettier - ...fns: [ - F.Function , - F.Function<[A.Await], R1>, - ] + ...fns: [F.Function, F.Function<[A.Await], R1>] ): F.Function>> ( - ...fns: [ - F.Function, - F.Function<[A.Await], R1>, - F.Function<[A.Await], R2>, - ] + ...fns: [F.Function, F.Function<[A.Await], R1>, F.Function<[A.Await], R2>] ): F.Function>> ( ...fns: [ diff --git a/helpers/blaze/reduce.ts b/helpers/blaze/reduce.ts index e727bedc7235..08622cdc8984 100644 --- a/helpers/blaze/reduce.ts +++ b/helpers/blaze/reduce.ts @@ -1,11 +1,6 @@ import type { L } from 'ts-toolbelt' -export type Reducer = ( - acc: R, - item: I, - pos: number, - exit: (acc: R) => R, -) => R +export type Reducer = (acc: R, item: I, pos: number, exit: (acc: R) => R) => R /** * Calls the specified callback function for all the elements in an array. The @@ -18,11 +13,7 @@ export type Reducer = ( * @param acc initial value * @returns */ -const reduce = , I, R>( - list: L & L.List, - reducer: Reducer, - acc: R, -) => { +const reduce = , I, R>(list: L & L.List, reducer: Reducer, acc: R) => { let exited = false const exit = (acc: R) => { diff --git a/helpers/blaze/repeat.ts b/helpers/blaze/repeat.ts index ce6e2a0b8d34..73b0ce2aa6dc 100644 --- a/helpers/blaze/repeat.ts +++ b/helpers/blaze/repeat.ts @@ -1,5 +1,4 @@ -import type { L } from 'ts-toolbelt' -import type { F } from 'ts-toolbelt' +import type { F, L } from 'ts-toolbelt' /** * An accumulable function can be passed its output as input @@ -17,10 +16,7 @@ type Accumulable = (arg0: R, ...rest: P[]) => R * repeat(concat, times(10))([1], [2]) * ``` */ -function repeat

, R>( - f: (...p: P) => R, - again: (...p: F.NoInfer

) => boolean, -) { +function repeat

, R>(f: (...p: P) => R, again: (...p: F.NoInfer

) => boolean) { return (...p: P) => { // ts does not understand const pClone: any = [...p] diff --git a/helpers/blaze/transduce.ts b/helpers/blaze/transduce.ts index c52e6db01002..d1beb19e6ed5 100644 --- a/helpers/blaze/transduce.ts +++ b/helpers/blaze/transduce.ts @@ -2,10 +2,7 @@ import type { L } from 'ts-toolbelt' const skip = Symbol('skip') -function transduceSync, I, R>( - list: L & L.List, - transformer: (item: I) => R | typeof skip, -) { +function transduceSync, I, R>(list: L & L.List, transformer: (item: I) => R | typeof skip) { const transduced = [] as R[] for (let i = 0; i < list.length; ++i) { @@ -82,4 +79,4 @@ const transduce = transduceSync as typeof transduceSync & { transduce.async = transduceAsync -export { transduce, Filter, Mapper, skip } +export { Filter, Mapper, skip, transduce } diff --git a/helpers/compile/build.ts b/helpers/compile/build.ts index 980793bdad64..c1e8a1f83dc8 100644 --- a/helpers/compile/build.ts +++ b/helpers/compile/build.ts @@ -1,17 +1,19 @@ -import execa from 'execa' +import { watch as createWatcher } from 'chokidar' import * as esbuild from 'esbuild' +import execa from 'execa' +import glob from 'globby' +import path from 'path' + import { flatten } from '../blaze/flatten' -import { pipe } from '../blaze/pipe' +import { handle } from '../blaze/handle' import { map } from '../blaze/map' +import { pipe } from '../blaze/pipe' import { transduce } from '../blaze/transduce' -import glob from 'glob' -import path from 'path' -import { watch as createWatcher } from 'chokidar' -import { tscPlugin } from './plugins/tscPlugin' -import { onErrorPlugin } from './plugins/onErrorPlugin' +import { depCheckPlugin } from './plugins/depCheckPlugin' import { fixImportsPlugin } from './plugins/fixImportsPlugin' -import { handle } from '../blaze/handle' +import { onErrorPlugin } from './plugins/onErrorPlugin' import { replaceWithPlugin } from './plugins/replaceWithPlugin' +import { tscPlugin } from './plugins/tscPlugin' export type BuildResult = esbuild.BuildResult export type BuildOptions = esbuild.BuildOptions & { @@ -133,14 +135,42 @@ async function executeEsBuild(options: BuildOptions) { return esbuild.build(options) } +/** + * A blank esbuild run to do an analysis of our deps + */ +async function dependencyCheck(options: BuildOptions) { + // we only check our dependencies for a full build + if (process.env.DEV === 'true') return options + + // we need to bundle everything to do the analysis + const buildPromise = esbuild.build({ + entryPoints: glob.sync('**/*.{j,t}s', { + ignore: ['./src/__tests__/**/*'], + gitignore: true, + }), + logLevel: 'silent', // there will be errors + bundle: true, // we bundle to get everything + write: false, // no need to write for analysis + outdir: 'out', + plugins: [depCheckPlugin(options.bundle)], + }) + + // we absolutely don't care if it has any errors + await buildPromise.catch(() => {}) + + return options +} + /** * Execution pipeline that applies a set of actions * @param options */ export async function build(options: BuildOptions[]) { + await transduce.async(options, dependencyCheck) + return transduce.async( createBuildOptions(options), - pipe.async(computeOptions, addExtensionFormat, addDefaultOutDir, executeEsBuild, watch), + pipe.async(computeOptions, addExtensionFormat, addDefaultOutDir, executeEsBuild, watch(options)), ) } @@ -148,33 +178,44 @@ export async function build(options: BuildOptions[]) { * Executes the build and rebuilds what is necessary * @param builds */ -function watch(build: esbuild.BuildResult | esbuild.BuildIncremental | undefined) { - if (process.env.WATCH !== 'true') return build +const watch = (options: BuildOptions[]) => (result?: esbuild.BuildResult | esbuild.BuildIncremental) => { + if (process.env.WATCH !== 'true') return result + + // common chokidar options for the watchers + const config = { ignoreInitial: true, useFsEvents: true, ignored: ['./src/__tests__/**/*'] } // prepare the incremental builds watcher - const watched = getWatchedFiles(build) - const watcher = createWatcher(watched, { - ignoreInitial: true, - useFsEvents: true, - }) + const watched = getWatchedFiles(result) + const changeWatcher = createWatcher(watched, config) - watcher.once('all', async () => { + // watcher for restarting a full rebuild + const restartWatcher = createWatcher(['./src/**/*'], config) + + // triggers quick rebuild on file change + changeWatcher.on('change', async () => { const timeBefore = Date.now() // we handle possible rebuild exceptions - const result = await handle.async(() => { - return build?.rebuild?.() + const rebuildResult = await handle.async(() => { + return result?.rebuild?.() }) - if (result instanceof Error) { - console.error(result.message) - watch(build) // re-watch original build - } else { - watch(result) // watch incremented build + if (rebuildResult instanceof Error) { + console.error(rebuildResult.message) } - const timeAfter = Date.now() - console.log(`${timeAfter - timeBefore}ms`) + console.log(`${Date.now() - timeBefore}ms`) + }) + + // triggers a full rebuild on added file + restartWatcher.once('add', async () => { + void changeWatcher.close() // stop all + + // only one watcher will do this task + if (watchLock === false) { + watchLock = true + await build(options) + } }) return undefined @@ -182,6 +223,9 @@ function watch(build: esbuild.BuildResult | esbuild.BuildIncremental | undefined // Utils :::::::::::::::::::::::::::::::::::::::::::::::::: +// so that only one watcher restarts a full build +let watchLock = false + // get a default directory if needed (no outfile) function getOutDir(options: BuildOptions) { if (options.outfile !== undefined) { @@ -193,7 +237,7 @@ function getOutDir(options: BuildOptions) { // get the esm output path from an original path function getEsmOutDir(options: BuildOptions) { - return `${getOutDir(options)}/esm` + return `esm/${getOutDir(options)}` } // get the esm output file from an original path @@ -202,7 +246,7 @@ function getEsmOutFile(options: BuildOptions) { const dirname = getOutDir(options) const filename = path.basename(options.outfile) - return `${dirname}/esm/${filename}` + return `esm/${dirname}/${filename}` } return undefined diff --git a/helpers/compile/depcheck.ts b/helpers/compile/plugins/depCheckPlugin.ts similarity index 76% rename from helpers/compile/depcheck.ts rename to helpers/compile/plugins/depCheckPlugin.ts index 904907f59db7..5dc2edc134db 100644 --- a/helpers/compile/depcheck.ts +++ b/helpers/compile/plugins/depCheckPlugin.ts @@ -1,6 +1,5 @@ -import * as esbuild from 'esbuild' +import type * as esbuild from 'esbuild' import { builtinModules } from 'module' -import glob from 'globby' import path from 'path' // packages that aren't detected but used @@ -18,6 +17,8 @@ const unusedIgnore = [ 'typescript', 'ts-node', 'ts-jest', + '@swc/core', + '@swc/jest', 'jest', // these are missing 3rd party deps @@ -39,17 +40,18 @@ const unusedIgnore = [ const missingIgnore = ['.prisma', '@prisma/client'] /** - * Checks for unused and missing dependencies + * Checks for unused and missing dependencies. */ -const unusedPlugin: esbuild.Plugin = { - name: 'unusedPlugin', +export const depCheckPlugin = (bundle?: boolean): esbuild.Plugin => ({ + name: 'depCheckPlugin', setup(build) { // we load the package.json of the project do do our analysis const pkgJsonPath = path.join(process.cwd(), 'package.json') - const pkgContents = require(pkgJsonPath) as object + const pkgContents = require(pkgJsonPath) as Record const regDependencies = Object.keys(pkgContents['dependencies'] ?? {}) const devDependencies = Object.keys(pkgContents['devDependencies'] ?? {}) - const dependencies = new Set([...regDependencies, ...devDependencies]) + const peerDependencies = Object.keys(pkgContents['peerDependencies'] ?? {}) + const dependencies = [...regDependencies, ...(bundle ? devDependencies : [])] // we prepare to collect dependencies that are only packages const collectedDependencies = new Set() @@ -80,7 +82,7 @@ const unusedPlugin: esbuild.Plugin = { // we take all the collected deps that aren't deps and aren't native const missingDependencies = [...collectedDependencies].filter((dep) => { - return !dependencies.has(dep) && !builtinModules.includes(dep) + return !dependencies.includes(dep) && !builtinModules.includes(dep) }) // we exclude the deps that match our unusedIgnore patterns @@ -90,25 +92,13 @@ const unusedPlugin: esbuild.Plugin = { // we exclude the deps that match our unusedIgnore patterns const filteredMissingDeps = missingDependencies.filter((dep) => { - return !missingIgnore.some((pattern) => dep.match(pattern)) + return !missingIgnore.some((pattern) => dep.match(pattern)) && !peerDependencies.includes(dep) }) - console.warn('unusedDependencies', filteredUnusedDeps) - console.warn('missingDependencies', filteredMissingDeps) + console.warn('unusedDependencies', JSON.stringify(filteredUnusedDeps)) + console.warn('missingDependencies', JSON.stringify(filteredMissingDeps)) + + if (filteredMissingDeps.length > 0) process.exit(1) }) }, -} - -void esbuild - .build({ - entryPoints: glob.sync('**/*.{j,t}s', { - ignore: ['**/packages/**/*', '**/*.d.ts'], - gitignore: true, - }), - logLevel: 'silent', // there will be errors - bundle: true, // we bundle to get everything - write: false, // no need to write for analysis - outdir: 'out', - plugins: [unusedPlugin], - }) - .catch(() => {}) +}) diff --git a/helpers/compile/plugins/fill-plugin/fillPlugin.ts b/helpers/compile/plugins/fill-plugin/fillPlugin.ts index 90937f9ad053..a301ab473b52 100644 --- a/helpers/compile/plugins/fill-plugin/fillPlugin.ts +++ b/helpers/compile/plugins/fill-plugin/fillPlugin.ts @@ -1,8 +1,8 @@ -import * as esbuild from 'esbuild' -import resolve from 'resolve' -import path from 'path' import crypto from 'crypto' +import * as esbuild from 'esbuild' import os from 'os' +import path from 'path' +import resolve from 'resolve' type LoadCache = { [K in string]: string } diff --git a/helpers/compile/plugins/replaceWithPlugin.ts b/helpers/compile/plugins/replaceWithPlugin.ts index 13f4937ad729..2904f78feb35 100644 --- a/helpers/compile/plugins/replaceWithPlugin.ts +++ b/helpers/compile/plugins/replaceWithPlugin.ts @@ -1,6 +1,6 @@ -import { builtinModules } from 'module' import type * as esbuild from 'esbuild' import fs from 'fs' +import { builtinModules } from 'module' type Replacement = [RegExp, string | ((regex: RegExp, contents: string) => string | Promise)] diff --git a/helpers/compile/plugins/tscPlugin.ts b/helpers/compile/plugins/tscPlugin.ts index 1549d068b8a4..64a98e0aab4c 100644 --- a/helpers/compile/plugins/tscPlugin.ts +++ b/helpers/compile/plugins/tscPlugin.ts @@ -1,4 +1,5 @@ import type * as esbuild from 'esbuild' + import { run } from '../build' /** diff --git a/package.json b/package.json index 0dd9fb5ad044..1443e9871fd7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "private": true, + "name": "dev-env", "triggerEmptyDevReleaseByIncrementingThisNumber": 0, "license": "Apache-2.0", "maintainers": [ @@ -15,7 +16,6 @@ "setup": "ts-node scripts/setup.ts", "build": "ts-node scripts/setup.ts --build", "watch": "pnpm -r run dev && WATCH=true pnpm -r run dev --parallel --stream", - "depcheck": "node -r esbuild-register helpers/compile/depcheck.ts", "publish-all-dryrun": "ts-node scripts/ci/publish.ts --publish --dry-run", "publish-all": "ts-node scripts/ci/publish.ts --publish", "bump-engines": "ts-node scripts/bump-engines.ts", @@ -24,9 +24,10 @@ "status": "ts-node scripts/ci/publish.ts --status", "pull": "ts-node scripts/ci/publish.ts --pull", "preinstall": "node ./scripts/only-allow-pnpm.js pnpm", - "precommit-all": "ts-node scripts/lint.ts --staged", + "precommit": "lint-staged", "eslint": "eslint", - "lint": "ts-node scripts/lint.ts", + "lint": "eslint --fix --ext .ts .", + "format": "prettier --write .", "bench": "ts-node scripts/bench.ts | tee output.txt", "prepare": "is-ci || husky install" }, @@ -36,7 +37,7 @@ "@types/benchmark": "2.1.1", "@types/glob": "7.2.0", "@types/graphviz": "0.0.34", - "@types/node": "14.18.3", + "@types/node": "14.18.12", "@types/redis": "2.8.32", "@types/resolve": "1.20.1", "@typescript-eslint/eslint-plugin": "5.9.0", @@ -51,16 +52,20 @@ "eslint": "8.6.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-jest": "26.0.0", "eslint-plugin-prettier": "4.0.0", + "eslint-plugin-simple-import-sort": "7.0.0", "eventemitter3": "4.0.7", "execa": "5.1.1", "glob": "7.2.0", "globby": "11.0.4", - "graphviz": "0.0.9", + "graphviz-mit": "0.0.9", "husky": "7.0.4", "is-ci": "3.0.1", - "node-fetch": "2.6.6", + "jest-junit": "13.0.0", + "lint-staged": "12.3.4", + "node-fetch": "2.6.7", "p-map": "4.0.0", "p-reduce": "2.1.0", "p-retry": "4.6.1", @@ -68,6 +73,7 @@ "prettier": "2.5.1", "redis": "3.1.2", "redis-lock": "0.1.4", + "regenerator-runtime": "0.13.9", "resolve": "1.21.0", "safe-buffer": "5.2.1", "semver": "7.3.5", @@ -79,5 +85,12 @@ "tty-browserify": "0.0.1", "typescript": "4.5.4", "util": "0.12.4" + }, + "lint-staged": { + "*.{md,yml,json}": "prettier --write", + "*.{js,ts}": [ + "eslint --fix", + "prettier --write" + ] } } diff --git a/packages/cli/.eslintignore b/packages/cli/.eslintignore deleted file mode 100644 index ce2517a35c85..000000000000 --- a/packages/cli/.eslintignore +++ /dev/null @@ -1,10 +0,0 @@ -/node_modules -/build -/dist -/prisma-client -/runtime -/src/__tests__ -/fixtures/project/subdir/@prisma/client -/tmp-mysql -/tmp-postgresql -/tmp-sqlite diff --git a/packages/cli/.eslintrc.js b/packages/cli/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/cli/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/cli/helpers/build.ts b/packages/cli/helpers/build.ts index e3df243d487a..0377676ded42 100644 --- a/packages/cli/helpers/build.ts +++ b/packages/cli/helpers/build.ts @@ -1,12 +1,12 @@ -import type { BuildOptions } from '../../../helpers/compile/build' -import { run } from '../../../helpers/compile/build' -import { build } from '../../../helpers/compile/build' -import { copy } from 'fs-extra' -import path from 'path' import type * as esbuild from 'esbuild' import fs from 'fs' -import { promisify } from 'util' +import { copy } from 'fs-extra' import lineReplace from 'line-replace' +import path from 'path' +import { promisify } from 'util' + +import type { BuildOptions } from '../../../helpers/compile/build' +import { build, run } from '../../../helpers/compile/build' const copyFile = promisify(fs.copyFile) diff --git a/packages/cli/jest.config.js b/packages/cli/jest.config.js index b47c3c379ab2..6871c05c3256 100644 --- a/packages/cli/jest.config.js +++ b/packages/cli/jest.config.js @@ -1,11 +1,24 @@ module.exports = { - preset: 'ts-jest', + transform: { + '^.+\\.ts$': '@swc/jest', + }, testEnvironment: 'node', testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], - // todo duplicated serializer from client package, should share - snapshotSerializers: ['./src/__tests__/__helpers__/snapshotSerializer.ts'], + snapshotSerializers: ['@prisma/sdk/src/utils/jestSnapshotSerializer'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/cli/package.json b/packages/cli/package.json index 2f05a4291995..0840821af0a3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -68,30 +68,25 @@ "devDependencies": { "@prisma/client": "workspace:*", "@prisma/debug": "workspace:*", - "@prisma/fetch-engine": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/fetch-engine": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/generator-helper": "workspace:*", - "@prisma/get-platform": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/get-platform": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/migrate": "workspace:*", "@prisma/sdk": "workspace:*", - "@prisma/studio": "0.452.0", - "@prisma/studio-server": "0.452.0", + "@prisma/studio": "0.458.0", + "@prisma/studio-server": "0.458.0", + "@swc/core": "1.2.141", + "@swc/jest": "0.2.17", "@types/debug": "4.1.7", "@types/fs-extra": "9.0.13", - "@types/jest": "27.4.0", + "@types/jest": "27.4.1", "@types/rimraf": "3.0.2", - "@types/ws": "8.2.2", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", + "@types/ws": "8.5.3", "chalk": "4.1.2", - "checkpoint-client": "1.1.20", + "checkpoint-client": "1.1.21", "debug": "4.3.3", - "dotenv": "10.0.0", + "dotenv": "16.0.0", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", "execa": "5.1.1", "fast-deep-equal": "3.1.3", "fs-extra": "10.0.0", @@ -99,45 +94,32 @@ "get-port": "5.1.1", "global-dirs": "3.0.0", "is-installed-globally": "0.4.0", - "jest": "27.4.6", + "jest": "27.5.1", + "jest-junit": "13.0.0", "line-replace": "2.0.1", - "lint-staged": "12.1.5", "log-update": "4.0.0", "make-dir": "3.1.0", - "node-fetch": "2.6.6", + "node-fetch": "2.6.7", "open": "7.4.2", "pkg-up": "3.1.0", - "prettier": "2.5.1", "replace-string": "3.1.0", "resolve-pkg": "2.0.0", "rimraf": "3.0.2", "strip-ansi": "6.0.1", "tempy": "1.0.1", - "ts-jest": "27.1.2", "typescript": "4.5.4" }, "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "test": "jest --maxConcurrency=1 --verbose", "install": "node scripts/install-entry.js", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", "tsc": "tsc -d -p tsconfig.build.json", "prepublishOnly": "pnpm run build", - "preinstall": "node scripts/preinstall-entry.js", - "precommit": "lint-staged" + "preinstall": "node scripts/preinstall-entry.js" }, "dependencies": { - "@prisma/engines": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908" - }, - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] + "@prisma/engines": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77" }, "sideEffects": false } diff --git a/packages/cli/scripts/install.js b/packages/cli/scripts/install.js index 6d00de5ac615..d8681ee21973 100644 --- a/packages/cli/scripts/install.js +++ b/packages/cli/scripts/install.js @@ -14,9 +14,7 @@ if (process.env.INIT_CWD && process.env.NOW_BUILDER) { } async function ensurePostInstall() { - const initPkgPath = eval( - `require('path').resolve(process.env.INIT_CWD, 'package.json')`, - ) + const initPkgPath = eval(`require('path').resolve(process.env.INIT_CWD, 'package.json')`) if (fs.existsSync(initPkgPath)) { if (addPostInstallHook(initPkgPath)) { return diff --git a/packages/cli/scripts/preinstall.js b/packages/cli/scripts/preinstall.js index ee3fedf364fd..4b5545d14f9f 100644 --- a/packages/cli/scripts/preinstall.js +++ b/packages/cli/scripts/preinstall.js @@ -1,6 +1,6 @@ const path = require('path') const globalDirs = require('global-dirs') -const { drawBox } = require('@prisma/sdk/dist/drawBox') +const { drawBox } = require('@prisma/sdk/dist/utils/drawBox') const isInstalledGlobally = require('is-installed-globally') const BOLD = '\u001b[1m' @@ -10,15 +10,11 @@ const RESET = '\u001b[0m' // returns { pkgManager: 'yarn' | 'npm', pkgPath: string } | null function isPackageInstalledGlobally(name) { try { - const pkgPath = require.resolve( - path.join(globalDirs.yarn.packages, `${name}/package.json`), - ) + const pkgPath = require.resolve(path.join(globalDirs.yarn.packages, `${name}/package.json`)) return { pkgManager: 'yarn', pkgPath } } catch (_) { try { - const pkgPath = require.resolve( - path.join(globalDirs.npm.packages, `${name}/package.json`), - ) + const pkgPath = require.resolve(path.join(globalDirs.npm.packages, `${name}/package.json`)) return { pkgManager: 'npm', pkgPath } } catch (_) { // @@ -42,40 +38,6 @@ function prismaIsInstalledGlobally() { const b = (str) => BOLD + str + RESET const white = (str) => WHITE_BRIGHT + str + RESET -/** - * Get the package manager name currently being used. - * - */ -function getPackageManagerName() { - const userAgent = process.env.npm_config_user_agent - if (!userAgent) return null - - const name = parsePackageManagerName(userAgent) - if (!name) return null - - return name -} - -/** - * Parse package manager name from useragent. If parsing fails, `null` is returned. - */ -function parsePackageManagerName(userAgent) { - let packageManager = null - - // example: 'yarn/1.22.4 npm/? node/v13.11.0 darwin x64' - // References: - // - https://pnpm.js.org/en/3.6/only-allow-pnpm - // - https://github.com/cameronhunter/npm-config-user-agent-parser - if (userAgent) { - const matchResult = userAgent.match(/^([^\/]+)\/.+/) - if (matchResult) { - packageManager = matchResult[1].trim() - } - } - - return packageManager -} - export function main() { const nodeVersions = process.version.split('.') const nodeMajorVersion = parseInt(nodeVersions[0].slice(1)) @@ -114,14 +76,10 @@ export function main() { The package ${white('prisma2')} has been renamed to ${white('prisma')}. Please uninstall ${white('prisma2')} globally first. -Then install ${white('prisma')} to continue using ${b('Prisma 2.0')}: +Then install ${white('prisma')} to continue using ${b('Prisma 2+')}: # Uninstall old CLI - ${white( - installedGlobally.pkgManager === 'yarn' - ? 'yarn global remove prisma2' - : 'npm uninstall -g prisma2', - )} + ${white(installedGlobally.pkgManager === 'yarn' ? 'yarn global remove prisma2' : 'npm uninstall -g prisma2')} # Install new CLI ${white(`npm install prisma${isDev ? '@dev' : ''} --save-dev`)} @@ -133,8 +91,6 @@ Learn more here: https://pris.ly/preview025 ` } - console.error( - drawBox({ str: message, verticalPadding: 1, horizontalPadding: 3 }), - ) + console.error(drawBox({ str: message, verticalPadding: 1, horizontalPadding: 3 })) process.exit(1) } diff --git a/packages/cli/src/CLI.ts b/packages/cli/src/CLI.ts index ada99b61fdd6..55daf2a19d32 100644 --- a/packages/cli/src/CLI.ts +++ b/packages/cli/src/CLI.ts @@ -1,9 +1,9 @@ -import chalk from 'chalk' +import { ensureBinariesExist } from '@prisma/engines' import type { Command, Commands } from '@prisma/sdk' -import { arg, isError, format, HelpError, unknownCommand, logger } from '@prisma/sdk' +import { arg, format, HelpError, isError, link, logger, unknownCommand } from '@prisma/sdk' +import chalk from 'chalk' + import { Version } from './Version' -import { link } from '@prisma/sdk' -import { ensureBinariesExist } from '@prisma/engines' /** * CLI command diff --git a/packages/cli/src/Doctor.ts b/packages/cli/src/Doctor.ts index 0bfb45f0168d..7705fcb9df1a 100644 --- a/packages/cli/src/Doctor.ts +++ b/packages/cli/src/Doctor.ts @@ -1,22 +1,23 @@ +import type { DMMF } from '@prisma/generator-helper' +import { getSchemaPathAndPrint } from '@prisma/migrate' import type { Command } from '@prisma/sdk' import { arg, - getSchemaPath, - getDMMF, + canConnectToDatabase, + format, getConfig, + getDMMF, + HelpError, IntrospectionEngine, keyBy, + loadEnvFile, pick, - format, - HelpError, - canConnectToDatabase, } from '@prisma/sdk' import chalk from 'chalk' +import equal from 'fast-deep-equal' import fs from 'fs' import path from 'path' import { promisify } from 'util' -import type { DMMF } from '@prisma/generator-helper' -import equal from 'fast-deep-equal' const readFile = promisify(fs.readFile) type IncorrectFieldTypes = Array<{ @@ -67,21 +68,9 @@ ${chalk.bold('Examples')} return this.help() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new Error( - `Could not find a ${chalk.bold( - 'schema.prisma', - )} file that is required for this command.\nYou can either provide it with ${chalk.greenBright( - '--schema', - )}, set it as \`prisma.schema\` in your package.json or put it into the default location ${chalk.greenBright( - './prisma/schema.prisma', - )} https://pris.ly/d/prisma-schema-location`, - ) - } + loadEnvFile(args['--schema'], true) - console.log(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) const schema = await readFile(schemaPath, 'utf-8') const localDmmf = await getDMMF({ datamodel: schema }) diff --git a/packages/cli/src/Format.ts b/packages/cli/src/Format.ts index cdecc4b301b4..1038461015a0 100644 --- a/packages/cli/src/Format.ts +++ b/packages/cli/src/Format.ts @@ -1,9 +1,9 @@ +import { getSchemaPathAndPrint } from '@prisma/migrate' import type { Command } from '@prisma/sdk' -import { arg, format, formatms, formatSchema, getDMMF, getSchemaPath, HelpError } from '@prisma/sdk' +import { arg, format, formatms, formatSchema, getDMMF, HelpError } from '@prisma/sdk' import chalk from 'chalk' import fs from 'fs' import os from 'os' -import path from 'path' /** * $ prisma format @@ -52,21 +52,7 @@ Or specify a Prisma schema path return this.help() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new Error( - `Could not find a ${chalk.bold( - 'schema.prisma', - )} file that is required for this command.\nYou can either provide it with ${chalk.greenBright( - '--schema', - )}, set it as \`prisma.schema\` in your package.json or put it into the default location ${chalk.greenBright( - './prisma/schema.prisma', - )} https://pris.ly/d/prisma-schema-location`, - ) - } - - console.log(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) let output = await formatSchema({ schemaPath, diff --git a/packages/cli/src/Generate.ts b/packages/cli/src/Generate.ts index 9e361791c7d0..1c0f47fb9ba2 100644 --- a/packages/cli/src/Generate.ts +++ b/packages/cli/src/Generate.ts @@ -1,5 +1,6 @@ /* eslint-disable eslint-comments/disable-enable-pair, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/restrict-template-expressions */ import { enginesVersion } from '@prisma/engines' +import { getSchemaPathAndPrint } from '@prisma/migrate' import type { Command, Generator } from '@prisma/sdk' import { arg, @@ -7,11 +8,11 @@ import { getCommandWithExecutor, getGenerators, getGeneratorSuccessMessage, - getSchemaPath, HelpError, highlightTS, isError, link, + loadEnvFile, logger, missingGeneratorMessage, parseEnvValue, @@ -21,8 +22,10 @@ import fs from 'fs' import logUpdate from 'log-update' import path from 'path' import resolvePkg from 'resolve-pkg' + import { breakingChangesMessage } from './utils/breakingChanges' import { simpleDebounce } from './utils/simpleDebounce' + const pkg = eval(`require('../package.json')`) /** @@ -115,27 +118,10 @@ ${chalk.bold('Examples')} const watchMode = args['--watch'] || false - const schemaPath = await getSchemaPath(args['--schema'], { cwd }) - if (!schemaPath) { - if (isPostinstall) { - logger.warn(`The postinstall script automatically ran \`prisma generate\` and did not find your \`prisma/schema.prisma\`. -If you have a Prisma schema file in a custom path, you will need to run -\`prisma generate --schema=./path/to/your/schema.prisma\` to generate Prisma Client. -If you do not have a Prisma schema file yet, you can ignore this message.`) - return '' - } - throw new Error( - `Could not find a ${chalk.bold( - 'schema.prisma', - )} file that is required for this command.\nYou can either provide it with ${chalk.greenBright( - '--schema', - )}, set it as \`prisma.schema\` in your package.json or put it into the default location ${chalk.greenBright( - './prisma/schema.prisma', - )} https://pris.ly/d/prisma-schema-location`, - ) - } + loadEnvFile(args['--schema'], true) - logger.log(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema'], cwd) + if (!schemaPath) return '' // TODO Extract logic from here let hasJsClient diff --git a/packages/cli/src/Init.ts b/packages/cli/src/Init.ts index b3efe2b3b3bc..d9b934a8517f 100644 --- a/packages/cli/src/Init.ts +++ b/packages/cli/src/Init.ts @@ -1,12 +1,21 @@ -import type { Command } from '@prisma/sdk' -import { arg, canConnectToDatabase, format, getCommandWithExecutor, HelpError, link, logger } from '@prisma/sdk' -import { protocolToConnectorType } from '@prisma/sdk/dist/convertCredentials' import type { ConnectorType } from '@prisma/generator-helper' +import type { Command } from '@prisma/sdk' +import { + arg, + canConnectToDatabase, + format, + getCommandWithExecutor, + HelpError, + link, + logger, + protocolToConnectorType, +} from '@prisma/sdk' import chalk from 'chalk' import dotenv from 'dotenv' import fs from 'fs' import path from 'path' import { isError } from 'util' + import { printError } from './utils/prompt/utils/print' export const defaultSchema = (provider: ConnectorType = 'postgresql') => { @@ -47,9 +56,9 @@ export const defaultEnv = ( ) => { let env = comments ? `# Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings\n\n` : '' env += `DATABASE_URL="${url}"` @@ -66,6 +75,8 @@ export const defaultPort = (provider: ConnectorType) => { return 27017 case 'postgresql': return 5432 + case 'cockroachdb': + return 26257 } return undefined @@ -75,10 +86,14 @@ export const defaultURL = (provider: ConnectorType, port = defaultPort(provider) switch (provider) { case 'postgresql': return `postgresql://johndoe:randompassword@localhost:${port}/mydb?schema=${schema}` + case 'cockroachdb': + return `postgresql://johndoe:randompassword@localhost:${port}/mydb?schema=${schema}` case 'mysql': return `mysql://johndoe:randompassword@localhost:${port}/mydb` case 'sqlserver': return `sqlserver://localhost:${port};database=mydb;user=SA;password=randompassword;` + case 'jdbc:sqlserver': + return `jdbc:sqlserver://localhost:${port};database=mydb;user=SA;password=randompassword;` case 'mongodb': return `mongodb+srv://root:randompassword@cluster0.ab1cd.mongodb.net/mydb?retryWrites=true&w=majority` case 'sqlite': diff --git a/packages/cli/src/Studio.ts b/packages/cli/src/Studio.ts index 47bada02cd8e..3d919b34b638 100644 --- a/packages/cli/src/Studio.ts +++ b/packages/cli/src/Studio.ts @@ -1,6 +1,7 @@ import { enginesVersion } from '@prisma/engines' +import { getSchemaPathAndPrint } from '@prisma/migrate' import type { Command } from '@prisma/sdk' -import { arg, format, getSchemaPath, HelpError, isError } from '@prisma/sdk' +import { arg, format, HelpError, isError, loadEnvFile } from '@prisma/sdk' import { StudioServer } from '@prisma/studio-server' import chalk from 'chalk' import getPort from 'get-port' @@ -78,21 +79,9 @@ ${chalk.bold('Examples')} return this.help() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new Error( - `Could not find a ${chalk.bold( - 'schema.prisma', - )} file that is required for this command.\nYou can either provide it with ${chalk.greenBright( - '--schema', - )}, set it as \`prisma.schema\` in your package.json or put it into the default location ${chalk.greenBright( - './prisma/schema.prisma', - )} https://pris.ly/d/prisma-schema-location`, - ) - } + loadEnvFile(args['--schema'], true) - console.log(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) const hostname = args['--hostname'] const port = args['--port'] || (await getPort({ port: getPort.makeRange(5555, 5600) })) diff --git a/packages/cli/src/Telemetry.ts b/packages/cli/src/Telemetry.ts index 00389f26475f..53ae8affadf5 100644 --- a/packages/cli/src/Telemetry.ts +++ b/packages/cli/src/Telemetry.ts @@ -1,6 +1,6 @@ import type { Command } from '@prisma/sdk' -import * as checkpoint from 'checkpoint-client' import { getCLIPathHash, getProjectHash } from '@prisma/sdk' +import * as checkpoint from 'checkpoint-client' /** * $ prisma telemetry diff --git a/packages/cli/src/Validate.ts b/packages/cli/src/Validate.ts index 938b75cf9c23..87a8a7c92867 100644 --- a/packages/cli/src/Validate.ts +++ b/packages/cli/src/Validate.ts @@ -1,8 +1,8 @@ +import { getSchemaPathAndPrint } from '@prisma/migrate' import type { Command } from '@prisma/sdk' -import { arg, format, getConfig, getDMMF, getSchemaPath, HelpError } from '@prisma/sdk' +import { arg, format, getConfig, getDMMF, HelpError, loadEnvFile } from '@prisma/sdk' import chalk from 'chalk' import fs from 'fs' -import path from 'path' /** * $ prisma validate @@ -50,21 +50,9 @@ ${chalk.bold('Examples')} return this.help() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new Error( - `Could not find a ${chalk.bold( - 'schema.prisma', - )} file that is required for this command.\nYou can either provide it with ${chalk.greenBright( - '--schema', - )}, set it as \`prisma.schema\` in your package.json or put it into the default location ${chalk.greenBright( - './prisma/schema.prisma', - )} https://pris.ly/d/prisma-schema-location`, - ) - } + loadEnvFile(args['--schema'], true) - console.log(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) const schema = fs.readFileSync(schemaPath, 'utf-8') diff --git a/packages/cli/src/Version.ts b/packages/cli/src/Version.ts index 306784b065e4..20437dc67ec4 100644 --- a/packages/cli/src/Version.ts +++ b/packages/cli/src/Version.ts @@ -12,12 +12,15 @@ import { getVersion, HelpError, isError, + loadEnvFile, resolveBinary, } from '@prisma/sdk' import chalk from 'chalk' import fs from 'fs' import path from 'path' + import { getInstalledPrismaClientVersion } from './utils/getClientVersion' + const packageJson = require('../package.json') // eslint-disable-line @typescript-eslint/no-var-requires interface BinaryInfo { @@ -66,6 +69,8 @@ export class Version implements Command { return this.help() } + loadEnvFile(undefined, true) + const platform = await getPlatform() const cliQueryEngineBinaryType = getCliQueryEngineBinaryType() const introspectionEngine = await this.resolveEngine(BinaryType.introspectionEngine) diff --git a/packages/cli/src/__tests__/__helpers__/context.ts b/packages/cli/src/__tests__/__helpers__/context.ts deleted file mode 100644 index 2118651430c9..000000000000 --- a/packages/cli/src/__tests__/__helpers__/context.ts +++ /dev/null @@ -1,149 +0,0 @@ -import execa, { ExecaChildProcess } from 'execa' -import fs from 'fs-jetpack' -import { FSJetpack } from 'fs-jetpack/types' -import path from 'path' -import tempy from 'tempy' - -/** - * Base test context. - */ -type BaseContext = { - tmpDir: string - fs: FSJetpack - mocked: { - cwd: string - } - /** - * Setup the temporary directory based on the contents of some fixture. - */ - fixture: (name: string) => void - /** - * Spawn the Prisma cli using the temporary directory as the CWD. - * - * @remarks - * - * For this to work the source must be built - */ - cli: (...input: string[]) => ExecaChildProcess -} - -/** - * Create test context to use in tests. Provides the following: - * - * - A temporary directory - * - an fs-jetpack instance bound to the temporary directory - * - Mocked process.cwd via Node process.chdir - * - Fixture loader for boostrapping the temporary directory with content - */ -export const Context = { - new: function (ctx: BaseContext = {} as any) { - const c = ctx as BaseContext - - beforeEach(() => { - c.tmpDir = tempy.directory() - c.fs = fs.cwd(c.tmpDir) - c.fixture = (name: string) => { - // copy the fixture in isolated tmp directory - c.fs.copy(path.join(__dirname, '..', 'fixtures', name), '.', { - overwrite: true, - }) - // symlink to local client version in tmp dir - c.fs.symlink( - path.join(__dirname, '..', '..', '..', '..', 'client'), - path.join(c.fs.cwd(), 'node_modules', '@prisma', 'client'), - ) - } - c.mocked = c.mocked ?? { - cwd: process.cwd(), - } - c.cli = (...input) => { - return execa.node( - path.join(__dirname, '../../../build/index.js'), - input, - { - cwd: c.fs.cwd(), - stdio: 'pipe', - all: true, - }, - ) - } - process.chdir(c.tmpDir) - }) - - afterEach(() => { - process.chdir(c.mocked.cwd) - }) - - return factory(ctx) - }, -} - -/** - * Factory for creating a context contributor possibly configured in some special way. - */ -type ContextContributorFactory = - Settings extends {} - ? () => ContextContributor - : (settings: Settings) => ContextContributor - -/** - * A function that provides additonal test context. - */ -type ContextContributor = (ctx: Context) => NewContext - -/** - * Main context builder API that permits recursively building up context. - */ -function factory(ctx: Context) { - return { - add( - contextContributor: ContextContributor, - ) { - contextContributor(ctx) - return factory(ctx as any) - }, - assemble(): Context { - return ctx - }, - } -} - -/** - * Test context contributor. Mocks console.error with a Jest spy before each test. - */ -export const consoleContext: ContextContributorFactory< - {}, - BaseContext, - { - mocked: { - 'console.error': jest.SpyInstance - 'console.log': jest.SpyInstance - 'console.info': jest.SpyInstance - 'console.warn': jest.SpyInstance - } - } -> = () => (ctx) => { - beforeEach(() => { - ctx.mocked['console.error'] = jest - .spyOn(console, 'error') - .mockImplementation(() => {}) - ctx.mocked['console.log'] = jest - .spyOn(console, 'log') - .mockImplementation(() => {}) - ctx.mocked['console.info'] = jest - .spyOn(console, 'info') - .mockImplementation(() => {}) - ctx.mocked['console.warn'] = jest - .spyOn(console, 'warn') - .mockImplementation(() => {}) - }) - - afterEach(() => { - ctx.mocked['console.error'].mockRestore() - ctx.mocked['console.log'].mockRestore() - ctx.mocked['console.info'].mockRestore() - ctx.mocked['console.warn'].mockRestore() - }) - - return null as any -} diff --git a/packages/cli/src/__tests__/__helpers__/snapshotSerializer.ts b/packages/cli/src/__tests__/__helpers__/snapshotSerializer.ts deleted file mode 100644 index d76a3aad3a63..000000000000 --- a/packages/cli/src/__tests__/__helpers__/snapshotSerializer.ts +++ /dev/null @@ -1,75 +0,0 @@ -import path from 'path' -import replaceAll from 'replace-string' // sindre's replaceAll polyfill -import stripAnsi from 'strip-ansi' -import { platformRegex } from '@prisma/sdk' - -function trimErrorPaths(str) { - const parentDir = path.dirname(path.dirname(__dirname)) - - return replaceAll(str, parentDir, '') -} - -function normalizeToUnixPaths(str) { - return replaceAll(str, path.sep, '/') -} - -function removePlatforms(str) { - return str.replace(platformRegex, 'TEST_PLATFORM') -} - -function normalizeGithubLinks(str) { - return str.replace(/https:\/\/github.com\/prisma\/prisma-client-js\/issues\/\S+/, 'TEST_GITHUB_LINK') -} - -function normalizeRustError(str) { - return str.replace(/\/rustc\/(.+)\//g, '/rustc/hash/').replace(/(\[.*)(:\d*:\d*)(\])/g, '[/some/rust/path:0:0$3') -} - -function normalizeTmpDir(str) { - return str.replace(/\/tmp\/([a-z0-9]+)\//g, '/tmp/dir/') -} - -function normalizeMs(str) { - return str.replace(/\d{1,3}ms/g, 'XXms') -} - -/** - * Replace dynamic variable bits of Prisma schema with static strings. - */ -function prepareSchemaForSnapshot(schema: string): string { - const urlRegex = /url\s*=\s*.+/ - const outputRegex = /output\s*=\s*.+/ - return schema - .split('\n') - .map((line) => { - const urlMatch = urlRegex.exec(line) - if (urlMatch) { - return `${line.slice(0, urlMatch.index)}url = "***"` - } - const outputMatch = outputRegex.exec(line) - if (outputMatch) { - return `${line.slice(0, outputMatch.index)}output = "***"` - } - return line - }) - .join('\n') -} - -export function test(value) { - return typeof value === 'string' || value instanceof Error -} - -export function serialize(value) { - const message = typeof value === 'string' ? value : value instanceof Error ? value.message : '' - return prepareSchemaForSnapshot( - normalizeGithubLinks( - normalizeRustError( - normalizeMs( - normalizeTmpDir( - normalizeGithubLinks(normalizeToUnixPaths(removePlatforms(trimErrorPaths(stripAnsi(message))))), - ), - ), - ), - ), - ) -} diff --git a/packages/cli/src/__tests__/commands/CLI.test.ts b/packages/cli/src/__tests__/commands/CLI.test.ts index 5cc40127cbce..e96c80da6f5a 100644 --- a/packages/cli/src/__tests__/commands/CLI.test.ts +++ b/packages/cli/src/__tests__/commands/CLI.test.ts @@ -1,21 +1,22 @@ -import { CLI } from '../../CLI' -import { consoleContext, Context } from '../__helpers__/context' import { - MigrateCommand, - MigrateDev, - MigrateResolve, - MigrateStatus, - MigrateReset, - MigrateDeploy, - DbPush, + DbCommand, DbPull, + DbPush, // DbDrop, DbSeed, - DbCommand, handlePanic, + MigrateCommand, + MigrateDeploy, + MigrateDev, + MigrateReset, + MigrateResolve, + MigrateStatus, } from '@prisma/migrate' +import { jestConsoleContext, jestContext } from '@prisma/sdk' + +import { CLI } from '../../CLI' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() const cliInstance = CLI.new( { @@ -63,9 +64,7 @@ const cliInstance = CLI.new( ) it('no params should return help', async () => { - const spy = jest - .spyOn(cliInstance, 'help') - .mockImplementation(() => 'Help Me') + const spy = jest.spyOn(cliInstance, 'help').mockImplementation(() => 'Help Me') await cliInstance.parse([]) expect(spy).toHaveBeenCalledTimes(1) @@ -73,9 +72,7 @@ it('no params should return help', async () => { }) it('wrong flag', async () => { - const spy = jest - .spyOn(cliInstance, 'help') - .mockImplementation(() => 'Help Me') + const spy = jest.spyOn(cliInstance, 'help').mockImplementation(() => 'Help Me') await cliInstance.parse(['--something']) expect(spy).toHaveBeenCalledTimes(1) @@ -83,9 +80,7 @@ it('wrong flag', async () => { }) it('help flag', async () => { - const spy = jest - .spyOn(cliInstance, 'help') - .mockImplementation(() => 'Help Me') + const spy = jest.spyOn(cliInstance, 'help').mockImplementation(() => 'Help Me') await cliInstance.parse(['--help']) expect(spy).toHaveBeenCalledTimes(1) @@ -105,8 +100,7 @@ it('introspect should include deprecation warning', async () => { `) expect(ctx.mocked['console.log'].mock.calls).toHaveLength(0) expect(ctx.mocked['console.info'].mock.calls).toHaveLength(0) - expect(ctx.mocked['console.warn'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(` prisma:warn prisma:warn The prisma introspect command is deprecated. Please use prisma db pull instead. prisma:warn diff --git a/packages/cli/src/__tests__/commands/Doctor.test.ts b/packages/cli/src/__tests__/commands/Doctor.test.ts index f60c8a7c7726..a705ba3bbb14 100644 --- a/packages/cli/src/__tests__/commands/Doctor.test.ts +++ b/packages/cli/src/__tests__/commands/Doctor.test.ts @@ -1,24 +1,23 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' + import { Doctor } from '../../Doctor' -import { consoleContext, Context } from '../__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() it.skip('doctor should succeed when schema and db do match', async () => { ctx.fixture('example-project') const result = Doctor.new().parse([]) await expect(result).resolves.toEqual('Everything in sync 🔄') - expect( - ctx.mocked['console.error'].mock.calls.join('\n'), - ).toMatchInlineSnapshot(`👩‍⚕️🏥 Prisma Doctor checking the database...`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot( + `👩‍⚕️🏥 Prisma Doctor checking the database...`, + ) }) it('should fail when db is missing', async () => { ctx.fixture('schema-db-out-of-sync') ctx.fs.remove('dev.db') const result = Doctor.new().parse([]) - await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( - `P1003: SQLite database file doesn't exist`, - ) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`P1003: SQLite database file doesn't exist`) }) it('should fail when Prisma schema is missing', async () => { diff --git a/packages/cli/src/__tests__/commands/Format.test.ts b/packages/cli/src/__tests__/commands/Format.test.ts index fd363ee0fbf4..1f4d54a51efe 100644 --- a/packages/cli/src/__tests__/commands/Format.test.ts +++ b/packages/cli/src/__tests__/commands/Format.test.ts @@ -1,8 +1,9 @@ +import { jestContext } from '@prisma/sdk' import fs from 'fs-jetpack' + import { Format } from '../../Format' -import { Context } from '../__helpers__/context' -const ctx = Context.new().assemble() +const ctx = jestContext.new().assemble() it('format should add a trailing EOL', async () => { ctx.fixture('example-project/prisma') @@ -18,7 +19,5 @@ it('format should add missing backrelation', async () => { it('format should throw if schema is broken', async () => { ctx.fixture('example-project/prisma') - await expect( - Format.new().parse(['--schema=broken.prisma']), - ).rejects.toThrowError() + await expect(Format.new().parse(['--schema=broken.prisma'])).rejects.toThrowError() }) diff --git a/packages/cli/src/__tests__/commands/Generate.test.ts b/packages/cli/src/__tests__/commands/Generate.test.ts index 39ee6dcf00c0..73071ef3c2ac 100644 --- a/packages/cli/src/__tests__/commands/Generate.test.ts +++ b/packages/cli/src/__tests__/commands/Generate.test.ts @@ -1,9 +1,9 @@ +import { getClientEngineType, jestConsoleContext, jestContext } from '@prisma/sdk' import path from 'path' -import { getClientEngineType } from '@prisma/sdk' + import { Generate } from '../../Generate' -import { consoleContext, Context } from '../__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('using cli', () => { it('should work with a custom output dir', async () => { @@ -15,7 +15,7 @@ describe('using cli', () => { } const { main } = await import(ctx.fs.path('main.ts')) - expect(cleanSnapshot(data.stdout)).toMatchSnapshot() + expect(replaceEngineType(data.stdout)).toMatchSnapshot() await expect(main()).resolves.toMatchSnapshot() }, 60000) // timeout @@ -32,8 +32,8 @@ describe('using cli', () => { throw new Error(data.stderr + data.stdout) } - expect(cleanSnapshot(data.stdout)).toContain(`I am a minimal generator`) - }, 30000) // timeout + expect(data.stdout).toContain(`I am a minimal generator`) + }, 50000) // timeout }) describe('--schema from project directory', () => { @@ -42,13 +42,13 @@ describe('--schema from project directory', () => { const result = await Generate.new().parse(['--schema=./schema.prisma']) expect(replaceEngineType(result)).toMatchInlineSnapshot(` -✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./@prisma/client in XXms -You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client -\`\`\` -import { PrismaClient } from './@prisma/client' -const prisma = new PrismaClient() -\`\`\` -`) + ✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./@prisma/client in XXXms + You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client + \`\`\` + import { PrismaClient } from './@prisma/client' + const prisma = new PrismaClient() + \`\`\` + `) }) it('--schema relative path: should fail - invalid path', async () => { @@ -65,13 +65,13 @@ const prisma = new PrismaClient() const result = await Generate.new().parse([`--schema=${absoluteSchemaPath}`]) expect(replaceEngineType(result)).toMatchInlineSnapshot(` -✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./@prisma/client in XXms -You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client -\`\`\` -import { PrismaClient } from './@prisma/client' -const prisma = new PrismaClient() -\`\`\` -`) + ✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./@prisma/client in XXXms + You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client + \`\`\` + import { PrismaClient } from './@prisma/client' + const prisma = new PrismaClient() + \`\`\` + `) }) it('--schema absolute path: should fail - invalid path', async () => { @@ -88,13 +88,13 @@ describe('--schema from parent directory', () => { const result = await Generate.new().parse(['--schema=./subdirectory/schema.prisma']) expect(replaceEngineType(result)).toMatchInlineSnapshot(` -✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./subdirectory/@prisma/client in XXms -You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client -\`\`\` -import { PrismaClient } from './subdirectory/@prisma/client' -const prisma = new PrismaClient() -\`\`\` -`) + ✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./subdirectory/@prisma/client in XXXms + You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client + \`\`\` + import { PrismaClient } from './subdirectory/@prisma/client' + const prisma = new PrismaClient() + \`\`\` + `) }) it('--schema relative path: should fail - invalid path', async () => { @@ -113,13 +113,13 @@ const prisma = new PrismaClient() const result = await Generate.new().parse([`--schema=${absoluteSchemaPath}`]) expect(replaceEngineType(result)).toMatchInlineSnapshot(` -✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./subdirectory/@prisma/client in XXms -You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client -\`\`\` -import { PrismaClient } from './subdirectory/@prisma/client' -const prisma = new PrismaClient() -\`\`\` -`) + ✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./subdirectory/@prisma/client in XXXms + You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client + \`\`\` + import { PrismaClient } from './subdirectory/@prisma/client' + const prisma = new PrismaClient() + \`\`\` + `) }) it('--schema absolute path: should fail - invalid path', async () => { @@ -131,14 +131,6 @@ const prisma = new PrismaClient() }) }) -function cleanSnapshot(str: string): string { - return str - .replace(/\d+ms/g, 'XXms') - .replace(/\d+s/g, 'XXs') - .replace(/\(version:.+\)/g, '(version: 0.0.0)') - .replace(new RegExp(getClientEngineType(), 'g'), 'TEST_ENGINE_TYPE') -} - function replaceEngineType(result: string | Error) { if (result instanceof Error) { return result diff --git a/packages/cli/src/__tests__/commands/Init.test.ts b/packages/cli/src/__tests__/commands/Init.test.ts index 0905b47c49de..a52df223c436 100644 --- a/packages/cli/src/__tests__/commands/Init.test.ts +++ b/packages/cli/src/__tests__/commands/Init.test.ts @@ -1,10 +1,11 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' import fs from 'fs' import { join } from 'path' import stripAnsi from 'strip-ansi' + import { defaultEnv, defaultGitIgnore, defaultSchema } from '../../Init' -import { consoleContext, Context } from '../__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() test('is schema and env written on disk replace', async () => { const result = await ctx.cli('init') @@ -28,9 +29,9 @@ test('works with url param', async () => { const env = fs.readFileSync(join(ctx.tmpDir, '.env'), 'utf-8') expect(env).toMatchInlineSnapshot(` # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="file:dev.db" @@ -48,9 +49,9 @@ test('works with provider param - postgresql', async () => { const env = fs.readFileSync(join(ctx.tmpDir, '.env'), 'utf-8') expect(env).toMatchInlineSnapshot(` # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" @@ -68,9 +69,9 @@ test('works with provider param - mysql', async () => { const env = fs.readFileSync(join(ctx.tmpDir, '.env'), 'utf-8') expect(env).toMatchInlineSnapshot(` # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="mysql://johndoe:randompassword@localhost:3306/mydb" @@ -88,9 +89,9 @@ test('works with provider param - SQLITE', async () => { const env = fs.readFileSync(join(ctx.tmpDir, '.env'), 'utf-8') expect(env).toMatchInlineSnapshot(` # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="file:./dev.db" @@ -108,9 +109,9 @@ test('works with provider param - SqlServer', async () => { const env = fs.readFileSync(join(ctx.tmpDir, '.env'), 'utf-8') expect(env).toMatchInlineSnapshot(` # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="sqlserver://localhost:1433;database=mydb;user=SA;password=randompassword;" @@ -128,9 +129,9 @@ test('works with provider param - MongoDB', async () => { const env = fs.readFileSync(join(ctx.tmpDir, '.env'), 'utf-8') expect(env).toMatchInlineSnapshot(` # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="mongodb+srv://root:randompassword@cluster0.ab1cd.mongodb.net/mydb?retryWrites=true&w=majority" diff --git a/packages/cli/src/__tests__/commands/Studio.test.ts b/packages/cli/src/__tests__/commands/Studio.test.ts index 65b652d5434a..7a2283984f64 100644 --- a/packages/cli/src/__tests__/commands/Studio.test.ts +++ b/packages/cli/src/__tests__/commands/Studio.test.ts @@ -2,6 +2,7 @@ import fs from 'fs' import fetch from 'node-fetch' import path from 'path' import rimraf from 'rimraf' + import { Studio } from '../../Studio' const STUDIO_TEST_PORT = 5678 @@ -18,7 +19,7 @@ async function sendRequest(message: any): Promise { let studio: Studio -describe('studio', () => { +describe('studio with default schema.prisma filename', () => { jest.setTimeout(20000) beforeAll(async () => { @@ -47,8 +48,8 @@ describe('studio', () => { await new Promise((r) => setTimeout(() => r(null), 2000)) }) - afterAll(async () => { - await studio.instance!.stop() + afterAll(() => { + studio.instance!.stop() }) test('can start up correctly', async () => { @@ -197,7 +198,189 @@ describe('studio', () => { }, }, }) + expect(res).toMatchSnapshot() + }) +}) + +describe('studio with custom schema.prisma filename', () => { + jest.setTimeout(20000) + + beforeAll(async () => { + // Before every test, we'd like to reset the DB. + // We do this by duplicating the original SQLite DB file, and using the duplicate as the datasource in our schema + rimraf.sync(path.join(__dirname, '../fixtures/studio-test-project-custom-filename/dev_tmp.db')) + fs.copyFileSync( + path.join(__dirname, '../fixtures/studio-test-project-custom-filename/dev.db'), + path.join(__dirname, '../fixtures/studio-test-project-custom-filename/dev_tmp.db'), + ) + + // Clean up Client generation directory + rimraf.sync(path.join(__dirname, '../prisma-client')) + studio = Studio.new() + + await studio.parse([ + '--schema', + path.join(__dirname, '../fixtures/studio-test-project-custom-filename/schema1.prisma'), + '--port', + `${STUDIO_TEST_PORT}`, + '--browser', + 'none', + ]) + + // Give Studio time to start + await new Promise((r) => setTimeout(() => r(null), 2000)) + }) + + afterAll(() => { + studio.instance!.stop() + }) + + test('can start up correctly', async () => { + const res = await fetch(`http://localhost:${STUDIO_TEST_PORT}`) + expect(res.status).toEqual(200) + }) + + test('can respond to `findMany` queries', async () => { + const res = await sendRequest({ + requestId: 1, + channel: 'prisma', + action: 'clientRequest', + payload: { + data: { + modelName: 'with_all_field_types', + operation: 'findMany', + args: { + select: { + id: true, + string: true, + int: true, + float: true, + datetime: true, + relation: true, + relation_list: true, + }, + }, + }, + }, + }) + + expect(res).toMatchSnapshot() + }) + + test('can respond to `create` queries', async () => { + const res = await sendRequest({ + requestId: 2, + channel: 'prisma', + action: 'clientRequest', + payload: { + data: { + modelName: 'with_all_field_types', + operation: 'create', + args: { + data: { + id: 3, + string: '', + int: 0, + float: 0.0, + datetime: '2020-08-03T00:00:00.000Z', + relation: { + connect: { + id: 3, + }, + }, + relation_list: { + connect: { + id: 3, + }, + }, + }, + select: { + id: true, + string: true, + int: true, + float: true, + datetime: true, + relation: true, + relation_list: true, + }, + }, + }, + }, + }) + + expect(res).toMatchSnapshot() + }) + + test('can respond to `update` queries', async () => { + const res = await sendRequest({ + requestId: 3, + channel: 'prisma', + action: 'clientRequest', + payload: { + data: { + modelName: 'with_all_field_types', + operation: 'update', + args: { + where: { + id: 1, + }, + data: { + string: 'Changed String', + int: 100, + float: 100.5, + datetime: '2025-08-03T00:00:00.000Z', + relation: { + connect: { + id: 3, + }, + }, + relation_list: { + connect: { + id: 3, + }, + }, + }, + select: { + id: true, + string: true, + int: true, + float: true, + datetime: true, + relation: true, + relation_list: true, + }, + }, + }, + }, + }) expect(res).toMatchSnapshot() }) + + test('can respond to `delete` queries', async () => { + const res = await sendRequest({ + requestId: 4, + channel: 'prisma', + action: 'clientRequest', + payload: { + data: { + modelName: 'with_all_field_types', + operation: 'delete', + args: { + where: { id: 2 }, + select: { + id: true, + string: true, + int: true, + float: true, + datetime: true, + relation: true, + relation_list: true, + }, + }, + }, + }, + }) + expect(res).toMatchSnapshot() + }) }) diff --git a/packages/cli/src/__tests__/commands/Version.test.ts b/packages/cli/src/__tests__/commands/Version.test.ts index db4254066570..b97cf42354ad 100644 --- a/packages/cli/src/__tests__/commands/Version.test.ts +++ b/packages/cli/src/__tests__/commands/Version.test.ts @@ -1,12 +1,13 @@ import { getCliQueryEngineBinaryType } from '@prisma/engines' import { BinaryType, download } from '@prisma/fetch-engine' import { getPlatform } from '@prisma/get-platform' -import { engineEnvVarMap } from '@prisma/sdk' +import { engineEnvVarMap, jestConsoleContext, jestContext } from '@prisma/sdk' import makeDir from 'make-dir' import path from 'path' -import { consoleContext, Context } from '../__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const packageJson = require('../../../package.json') // eslint-disable-line @typescript-eslint/no-var-requires + +const ctx = jestContext.new().add(jestConsoleContext()).assemble() const testIf = (condition: boolean) => (condition ? test : test.skip) const useNodeAPI = getCliQueryEngineBinaryType() === BinaryType.libqueryEngine const version = '5a2e5869b69a983e279380ec68596b71beae9eff' @@ -46,7 +47,7 @@ describe('version', () => { } const data = await ctx.cli('--version') - expect(cleanSnapshot(data.stdout)).toMatchSnapshot() + expect(cleanSnapshot(data.stdout, `x.x.x.${version}`)).toMatchSnapshot() // cleanup for (const engine in envVarMap) { @@ -54,7 +55,7 @@ describe('version', () => { delete process[envVar] } }, - 20000, + 50000, ) // Binary Tests @@ -89,7 +90,7 @@ describe('version', () => { } const data = await ctx.cli('--version') - expect(cleanSnapshot(data.stdout)).toMatchSnapshot() + expect(cleanSnapshot(data.stdout, `x.x.x.${version}`)).toMatchSnapshot() // cleanup for (const engine in envVarMap) { @@ -97,10 +98,33 @@ describe('version', () => { delete process[envVar] } }, - 20000, + 50000, ) }) -function cleanSnapshot(str: string): string { - return str.replace(/:(.*)/g, ': placeholder') +function cleanSnapshot(str: string, versionOverride?: string): string { + // sanitize engine path + // Query Engine (Node-API) : libquery-engine e996df5d66a2314d1da15d31047f9777fc2fbdd9 (at ../../home/runner/work/prisma/prisma/node_modules/.pnpm/@prisma+engines@3.11.0-41.e996df5d66a2314d1da15d31047f9777fc2fbdd9/node_modules/@prisma/engines/libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node) + // + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // Query Engine (Node-API) : libquery-engine 5a2e5869b69a983e279380ec68596b71beae9eff (at ../../cli/src/__tests__/commands/version-test-engines/libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node, resolved by PRISMA_QUERY_ENGINE_LIBRARY) + // => ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // Query Engine (Node-API) : libquery-engine e996df5d66a2314d1da15d31047f9777fc2fbdd9 (at sanitized_path/libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node) + // ^^^^^^^^^^^^^^^^^^^ + str = str.replace(/\(at (.*engines)(\/|\\)/g, '(at sanitized_path/') + + // replace engine version hash + const currentEngineVersion = versionOverride ?? packageJson.dependencies['@prisma/engines'] + const currentEngineCommit = currentEngineVersion.split('.').pop().split('-').pop() + const defaultEngineVersion = packageJson.dependencies['@prisma/engines'] + const defaultEngineHash = defaultEngineVersion.split('.').pop() + str = str.replace(new RegExp(currentEngineCommit, 'g'), 'ENGINE_VERSION') + str = str.replace(new RegExp(defaultEngineHash, 'g'), 'ENGINE_VERSION') + + // replace studio version + str = str.replace(packageJson.devDependencies['@prisma/studio-server'], 'STUDIO_VERSION') + + // sanitize windows specific engine names + str = str.replace(/\.exe/g, '') + + return str } diff --git a/packages/cli/src/__tests__/commands/__snapshots__/Format.test.ts.snap b/packages/cli/src/__tests__/commands/__snapshots__/Format.test.ts.snap index f60c207c7ac0..1cd52c3a489d 100644 --- a/packages/cli/src/__tests__/commands/__snapshots__/Format.test.ts.snap +++ b/packages/cli/src/__tests__/commands/__snapshots__/Format.test.ts.snap @@ -3,12 +3,12 @@ exports[`format should add a trailing EOL 1`] = ` generator client { provider = "prisma-client-js" - output = "***" + output = "../generated/client" } datasource db { provider = "sqlite" - url = "***" + url = "file:dev.db" } model Post { @@ -41,12 +41,12 @@ model User { exports[`format should add missing backrelation 1`] = ` generator client { provider = "prisma-client-js" - output = "***" + output = "../generated/client" } datasource db { provider = "sqlite" - url = "***" + url = "file:dev.db" } model Post { diff --git a/packages/cli/src/__tests__/commands/__snapshots__/Generate.test.ts.snap b/packages/cli/src/__tests__/commands/__snapshots__/Generate.test.ts.snap index f6c3c6f6ee98..7b6c03fed406 100644 --- a/packages/cli/src/__tests__/commands/__snapshots__/Generate.test.ts.snap +++ b/packages/cli/src/__tests__/commands/__snapshots__/Generate.test.ts.snap @@ -3,7 +3,7 @@ exports[`using cli should work with a custom output dir 1`] = ` Prisma schema loaded from prisma/schema.prisma -✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./generated/client in XXms +✔ Generated Prisma Client (0.0.0 | TEST_ENGINE_TYPE) to ./generated/client in XXXms You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client \`\`\` import { PrismaClient } from './generated/client' diff --git a/packages/cli/src/__tests__/commands/__snapshots__/Init.test.ts.snap b/packages/cli/src/__tests__/commands/__snapshots__/Init.test.ts.snap index e232f517a2cf..b299ed2de81b 100644 --- a/packages/cli/src/__tests__/commands/__snapshots__/Init.test.ts.snap +++ b/packages/cli/src/__tests__/commands/__snapshots__/Init.test.ts.snap @@ -1,7 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`appends when .env present 1`] = ` -Environment variables loaded from .env ✔ Your Prisma schema was created at prisma/schema.prisma You can now open it in your favorite editor. @@ -22,9 +21,9 @@ SOMTHING="is here" # This was inserted by \`prisma init\`: # Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview). +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" @@ -47,7 +46,6 @@ https://pris.ly/d/getting-started `; exports[`warns when DATABASE_URL present in .env 1`] = ` -Environment variables loaded from .env ✔ Your Prisma schema was created at prisma/schema.prisma You can now open it in your favorite editor. diff --git a/packages/cli/src/__tests__/commands/__snapshots__/Studio.test.ts.snap b/packages/cli/src/__tests__/commands/__snapshots__/Studio.test.ts.snap index 3b2129a4b1ed..6c6829c8d4ae 100644 --- a/packages/cli/src/__tests__/commands/__snapshots__/Studio.test.ts.snap +++ b/packages/cli/src/__tests__/commands/__snapshots__/Studio.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`studio can respond to \`create\` queries 1`] = ` +exports[`studio with custom schema.prisma filename can respond to \`create\` queries 1`] = ` Object { action: clientRequest, channel: -prisma, @@ -30,7 +30,7 @@ Object { } `; -exports[`studio can respond to \`delete\` queries 1`] = ` +exports[`studio with custom schema.prisma filename can respond to \`delete\` queries 1`] = ` Object { action: clientRequest, channel: -prisma, @@ -54,7 +54,7 @@ Object { } `; -exports[`studio can respond to \`findMany\` queries 1`] = ` +exports[`studio with custom schema.prisma filename can respond to \`findMany\` queries 1`] = ` Object { action: clientRequest, channel: -prisma, @@ -93,7 +93,130 @@ Object { } `; -exports[`studio can respond to \`update\` queries 1`] = ` +exports[`studio with custom schema.prisma filename can respond to \`update\` queries 1`] = ` +Object { + action: clientRequest, + channel: -prisma, + payload: Object { + data: Object { + datetime: 2025-08-03T00:00:00.000Z, + float: 100.5, + id: 1, + int: 100, + relation: Object { + id: 3, + name: Relation Target 003, + waft_id: 1, + }, + relation_list: Array [ + Object { + id: 3, + name: Relation Target 003, + waft_id: 1, + }, + ], + string: Changed String, + }, + error: null, + }, + requestId: 3, +} +`; + +exports[`studio with default schema.prisma filename can respond to \`create\` queries 1`] = ` +Object { + action: clientRequest, + channel: -prisma, + payload: Object { + data: Object { + datetime: 2020-08-03T00:00:00.000Z, + float: 0, + id: 3, + int: 0, + relation: Object { + id: 3, + name: Relation Target 003, + waft_id: 3, + }, + relation_list: Array [ + Object { + id: 3, + name: Relation Target 003, + waft_id: 3, + }, + ], + string: , + }, + error: null, + }, + requestId: 2, +} +`; + +exports[`studio with default schema.prisma filename can respond to \`delete\` queries 1`] = ` +Object { + action: clientRequest, + channel: -prisma, + payload: Object { + data: Object { + datetime: 1970-01-01T00:00:00.000Z, + float: 0, + id: 2, + int: 0, + relation: Object { + id: 2, + name: Relation Target 002, + waft_id: 2, + }, + relation_list: Array [], + string: Delete me, + }, + error: null, + }, + requestId: 4, +} +`; + +exports[`studio with default schema.prisma filename can respond to \`findMany\` queries 1`] = ` +Object { + action: clientRequest, + channel: -prisma, + payload: Object { + data: Array [ + Object { + datetime: 2020-08-03T00:00:00.000Z, + float: 3.14, + id: 1, + int: 42, + relation: Object { + id: 1, + name: Relation Target 001, + waft_id: 1, + }, + relation_list: Array [], + string: Some string, + }, + Object { + datetime: 1970-01-01T00:00:00.000Z, + float: 0, + id: 2, + int: 0, + relation: Object { + id: 2, + name: Relation Target 002, + waft_id: 2, + }, + relation_list: Array [], + string: Delete me, + }, + ], + error: null, + }, + requestId: 1, +} +`; + +exports[`studio with default schema.prisma filename can respond to \`update\` queries 1`] = ` Object { action: clientRequest, channel: -prisma, diff --git a/packages/cli/src/__tests__/commands/__snapshots__/Version.test.ts.snap b/packages/cli/src/__tests__/commands/__snapshots__/Version.test.ts.snap index 066c21d37c9f..11998a0fe202 100644 --- a/packages/cli/src/__tests__/commands/__snapshots__/Version.test.ts.snap +++ b/packages/cli/src/__tests__/commands/__snapshots__/Version.test.ts.snap @@ -1,49 +1,49 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`version basic version (Node-API) 1`] = ` -prisma : placeholder -@prisma/client : placeholder -Current platform : placeholder -Query Engine (Node-API) : placeholder -Migration Engine : placeholder -Introspection Engine : placeholder -Format Binary : placeholder -Default Engines Hash : placeholder -Studio : placeholder +prisma : 0.0.0 +@prisma/client : 0.0.0 +Current platform : TEST_PLATFORM +Query Engine (Node-API) : libquery-engine ENGINE_VERSION (at sanitized_path/libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node) +Migration Engine : migration-engine-cli ENGINE_VERSION (at sanitized_path/migration-engine-TEST_PLATFORM) +Introspection Engine : introspection-core ENGINE_VERSION (at sanitized_path/introspection-engine-TEST_PLATFORM) +Format Binary : prisma-fmt ENGINE_VERSION (at sanitized_path/prisma-fmt-TEST_PLATFORM) +Default Engines Hash : ENGINE_VERSION +Studio : STUDIO_VERSION `; exports[`version basic version 1`] = ` -prisma : placeholder -@prisma/client : placeholder -Current platform : placeholder -Query Engine (Binary) : placeholder -Migration Engine : placeholder -Introspection Engine : placeholder -Format Binary : placeholder -Default Engines Hash : placeholder -Studio : placeholder +prisma : 0.0.0 +@prisma/client : 0.0.0 +Current platform : TEST_PLATFORM +Query Engine (Binary) : query-engine ENGINE_VERSION (at sanitized_path/query-engine-TEST_PLATFORM) +Migration Engine : migration-engine-cli ENGINE_VERSION (at sanitized_path/migration-engine-TEST_PLATFORM) +Introspection Engine : introspection-core ENGINE_VERSION (at sanitized_path/introspection-engine-TEST_PLATFORM) +Format Binary : prisma-fmt ENGINE_VERSION (at sanitized_path/prisma-fmt-TEST_PLATFORM) +Default Engines Hash : ENGINE_VERSION +Studio : STUDIO_VERSION `; exports[`version version with custom binaries (Node-API) 1`] = ` -prisma : placeholder -@prisma/client : placeholder -Current platform : placeholder -Query Engine (Node-API) : placeholder -Migration Engine : placeholder -Introspection Engine : placeholder -Format Binary : placeholder -Default Engines Hash : placeholder -Studio : placeholder +prisma : 0.0.0 +@prisma/client : 0.0.0 +Current platform : TEST_PLATFORM +Query Engine (Node-API) : libquery-engine ENGINE_VERSION (at sanitized_path/libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node, resolved by PRISMA_QUERY_ENGINE_LIBRARY) +Migration Engine : migration-engine-cli ENGINE_VERSION (at sanitized_path/migration-engine-TEST_PLATFORM, resolved by PRISMA_MIGRATION_ENGINE_BINARY) +Introspection Engine : introspection-core ENGINE_VERSION (at sanitized_path/introspection-engine-TEST_PLATFORM, resolved by PRISMA_INTROSPECTION_ENGINE_BINARY) +Format Binary : prisma-fmt ENGINE_VERSION (at sanitized_path/prisma-fmt-TEST_PLATFORM, resolved by PRISMA_FMT_BINARY) +Default Engines Hash : ENGINE_VERSION +Studio : STUDIO_VERSION `; exports[`version version with custom binaries 1`] = ` -prisma : placeholder -@prisma/client : placeholder -Current platform : placeholder -Query Engine (Binary) : placeholder -Migration Engine : placeholder -Introspection Engine : placeholder -Format Binary : placeholder -Default Engines Hash : placeholder -Studio : placeholder +prisma : 0.0.0 +@prisma/client : 0.0.0 +Current platform : TEST_PLATFORM +Query Engine (Binary) : query-engine ENGINE_VERSION (at sanitized_path/query-engine-TEST_PLATFORM, resolved by PRISMA_QUERY_ENGINE_BINARY) +Migration Engine : migration-engine-cli ENGINE_VERSION (at sanitized_path/migration-engine-TEST_PLATFORM, resolved by PRISMA_MIGRATION_ENGINE_BINARY) +Introspection Engine : introspection-core ENGINE_VERSION (at sanitized_path/introspection-engine-TEST_PLATFORM, resolved by PRISMA_INTROSPECTION_ENGINE_BINARY) +Format Binary : prisma-fmt ENGINE_VERSION (at sanitized_path/prisma-fmt-TEST_PLATFORM, resolved by PRISMA_FMT_BINARY) +Default Engines Hash : ENGINE_VERSION +Studio : STUDIO_VERSION `; diff --git a/packages/cli/src/__tests__/dependent-generator.test.ts b/packages/cli/src/__tests__/dependent-generator.test.ts index 88fc976c408b..06eaff47a85e 100644 --- a/packages/cli/src/__tests__/dependent-generator.test.ts +++ b/packages/cli/src/__tests__/dependent-generator.test.ts @@ -1,6 +1,7 @@ import 'ts-node/register' -import path from 'path' + import execa from 'execa' +import path from 'path' process.removeAllListeners('warning') @@ -8,14 +9,10 @@ it('should error when dependent generator is missing', async () => { expect.assertions(1) try { - await execa.node( - path.join(__dirname, '../../build/index.js'), - ['generate'], - { - cwd: path.join(__dirname, './fixtures/dependent-generator'), - stdio: 'pipe', - }, - ) + await execa.node(path.join(__dirname, '../../build/index.js'), ['generate'], { + cwd: path.join(__dirname, './fixtures/dependent-generator'), + stdio: 'pipe', + }) } catch (e) { expect(e.stderr).toMatchSnapshot() } diff --git a/packages/cli/src/__tests__/dotenv-1-custom-schema-path.test.ts b/packages/cli/src/__tests__/dotenv-1-custom-schema-path.test.ts index dd2a4b7b3b50..dcfa6fe15c86 100644 --- a/packages/cli/src/__tests__/dotenv-1-custom-schema-path.test.ts +++ b/packages/cli/src/__tests__/dotenv-1-custom-schema-path.test.ts @@ -1,19 +1,13 @@ -import { consoleContext, Context } from './__helpers__/context' +import { jestConsoleContext, jestContext, loadEnvFile } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() -it('should read .env file in root folder and custom-path', async () => { - process.argv.push('--version') - process.argv.push('--schema=./custom-path/schema.prisma') +it('should read .env file in root folder and custom-path', () => { ctx.fixture('dotenv-1-custom-schema-path') - await import('../bin') - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + loadEnvFile('./custom-path/schema.prisma', true) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchSnapshot() - expect(process.env.DOTENV_PRISMA_WHEN_CUSTOM_SCHEMA_PATH_SHOULD_WORK).toEqual( - 'file:dev.db', - ) + expect(process.env.DOTENV_PRISMA_WHEN_CUSTOM_SCHEMA_PATH_SHOULD_WORK).toEqual('file:dev.db') expect(process.env.DOTENV_ROOT).toEqual('shouldbebread') - expect( - process.env.DOTENV_PRISMA_WHEN_CUSTOM_SCHEMA_PATH_SHOULD_BE_UNDEFINED, - ).toEqual(undefined) + expect(process.env.DOTENV_PRISMA_WHEN_CUSTOM_SCHEMA_PATH_SHOULD_BE_UNDEFINED).toEqual(undefined) }) diff --git a/packages/cli/src/__tests__/dotenv-2-prisma-folder.test.ts b/packages/cli/src/__tests__/dotenv-2-prisma-folder.test.ts index d5dcf2c5d0f7..972c8ca18427 100644 --- a/packages/cli/src/__tests__/dotenv-2-prisma-folder.test.ts +++ b/packages/cli/src/__tests__/dotenv-2-prisma-folder.test.ts @@ -1,12 +1,13 @@ -import { consoleContext, Context } from './__helpers__/context' +import { jestConsoleContext, jestContext, loadEnvFile } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() -it('should read .env file in prisma folder', async () => { - process.argv.push('--version') +it('should read .env file in prisma folder', () => { ctx.fixture('dotenv-2-prisma-folder') - await import('../bin') - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + loadEnvFile(undefined, true) + + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchSnapshot() + expect(process.env.DOTENV_PRISMA_SHOULD_WORK).toEqual('file:dev.db') expect(process.env.DOTENV_ROOT_SHOULD_BE_UNDEFINED).toEqual(undefined) }) diff --git a/packages/cli/src/__tests__/dotenv-3-conflict.test.ts b/packages/cli/src/__tests__/dotenv-3-conflict.test.ts index 75d58e94d6db..30790e60e9c7 100644 --- a/packages/cli/src/__tests__/dotenv-3-conflict.test.ts +++ b/packages/cli/src/__tests__/dotenv-3-conflict.test.ts @@ -1,13 +1,13 @@ -import { consoleContext, Context } from './__helpers__/context' +import { jestConsoleContext, jestContext } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() it('should throw error', async () => { ctx.fixture('dotenv-3-conflict') expect.assertions(1) await expect( - ctx.cli('version').catch((e) => { + ctx.cli('validate').catch((e) => { const message = e.message.split('\n').slice(1).join('\n') throw new Error(message) }), diff --git a/packages/cli/src/__tests__/dotenv-4-prisma-when-no-schema.test.ts b/packages/cli/src/__tests__/dotenv-4-prisma-when-no-schema.test.ts index 48af7046db15..59d64258f78c 100644 --- a/packages/cli/src/__tests__/dotenv-4-prisma-when-no-schema.test.ts +++ b/packages/cli/src/__tests__/dotenv-4-prisma-when-no-schema.test.ts @@ -1,12 +1,13 @@ -import { consoleContext, Context } from './__helpers__/context' +import { jestConsoleContext, jestContext, loadEnvFile } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() -it('should read .env file in prisma folder when there is no schema', async () => { - process.argv.push('--version') +it('should read .env file in prisma folder when there is no schema', () => { ctx.fixture('dotenv-4-prisma-no-schema') - await import('../bin') - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + loadEnvFile(undefined, true) + + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchSnapshot() + expect(process.env.DOTENV_PRISMA_NO_SCHEMA_SHOULD_WORK).toEqual('file:dev.db') expect(process.env.DOTENV_ROOT_SHOULD_BE_UNDEFINED).toEqual(undefined) }) diff --git a/packages/cli/src/__tests__/dotenv-5-only-root.test.ts b/packages/cli/src/__tests__/dotenv-5-only-root.test.ts index 1afa341b05b3..ace2b8b5c4f8 100644 --- a/packages/cli/src/__tests__/dotenv-5-only-root.test.ts +++ b/packages/cli/src/__tests__/dotenv-5-only-root.test.ts @@ -1,11 +1,12 @@ -import { consoleContext, Context } from './__helpers__/context' +import { jestConsoleContext, jestContext, loadEnvFile } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() -it('should not load root .env file', async () => { - process.argv.push('--version') +it('should not load root .env file', () => { ctx.fixture('dotenv-5-only-root') - await import('../bin') - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + loadEnvFile(undefined, true) + + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchSnapshot() + expect(process.env.DOTENV_ROOT_SHOULD_BE_UNDEFINED).toEqual(undefined) }) diff --git a/packages/cli/src/__tests__/dotenv-6-expand.test.ts b/packages/cli/src/__tests__/dotenv-6-expand.test.ts index 88d8e8083cc2..69094b9d1015 100644 --- a/packages/cli/src/__tests__/dotenv-6-expand.test.ts +++ b/packages/cli/src/__tests__/dotenv-6-expand.test.ts @@ -1,13 +1,13 @@ -import { consoleContext, Context } from './__helpers__/context' +import { jestConsoleContext, jestContext, loadEnvFile } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() -it('should read expanded env vars', async () => { +it('should read expanded env vars', () => { ctx.fixture('dotenv-6-expand') - process.argv.push('--version') - process.argv.push('--schema=./expand/schema.prisma') - await import('../bin') - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + loadEnvFile('./expand/schema.prisma', true) + + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchSnapshot() + expect(process.env.DOTENV_PRISMA_EXPAND_DATABASE_URL_WITH_SCHEMA).toEqual( 'postgres://user:password@server.host:5432/database?ssl=1&schema=schema1234', ) diff --git a/packages/cli/src/__tests__/fixtures/studio-test-project-custom-filename/dev.db b/packages/cli/src/__tests__/fixtures/studio-test-project-custom-filename/dev.db new file mode 100644 index 000000000000..99c947fd5b6c Binary files /dev/null and b/packages/cli/src/__tests__/fixtures/studio-test-project-custom-filename/dev.db differ diff --git a/packages/cli/src/__tests__/fixtures/studio-test-project-custom-filename/schema1.prisma b/packages/cli/src/__tests__/fixtures/studio-test-project-custom-filename/schema1.prisma new file mode 100644 index 000000000000..e5592cf5e362 --- /dev/null +++ b/packages/cli/src/__tests__/fixtures/studio-test-project-custom-filename/schema1.prisma @@ -0,0 +1,29 @@ +datasource my_db { + provider = "sqlite" + url = "file:./dev_tmp.db" +} + +generator client { + provider = "prisma-client-js" +} + +model with_all_field_types { + id Int @id + string String + int Int + float Float + datetime DateTime + + relation relation_target? @relation("waft_rt") + relation_list relation_target[] @relation("waft_rt_list") +} + +model relation_target { + id Int @id + name String + + // waft = With All Field Types + waft_id Int? @unique + waft with_all_field_types? @relation("waft_rt", fields: [waft_id], references: [id]) + wafts with_all_field_types[] @relation("waft_rt_list") +} diff --git a/packages/cli/src/__tests__/fixtures/studio-test-project/schema.prisma b/packages/cli/src/__tests__/fixtures/studio-test-project/schema.prisma index 6204ca10c18d..e5592cf5e362 100644 --- a/packages/cli/src/__tests__/fixtures/studio-test-project/schema.prisma +++ b/packages/cli/src/__tests__/fixtures/studio-test-project/schema.prisma @@ -14,7 +14,7 @@ model with_all_field_types { float Float datetime DateTime - relation relation_target? @relation("waft_rt") + relation relation_target? @relation("waft_rt") relation_list relation_target[] @relation("waft_rt_list") } @@ -23,7 +23,7 @@ model relation_target { name String // waft = With All Field Types - waft_id Int? + waft_id Int? @unique waft with_all_field_types? @relation("waft_rt", fields: [waft_id], references: [id]) - wafts with_all_field_types[] @relation("waft_rt_list", fields: [waft_id], references: [id]) + wafts with_all_field_types[] @relation("waft_rt_list") } diff --git a/packages/cli/src/__tests__/update-message.test.ts b/packages/cli/src/__tests__/update-message.test.ts index d3f50e37042c..bef84faa60d9 100644 --- a/packages/cli/src/__tests__/update-message.test.ts +++ b/packages/cli/src/__tests__/update-message.test.ts @@ -1,8 +1,10 @@ import 'ts-node/register' + +import { jestConsoleContext, jestContext } from '@prisma/sdk' + import { printUpdateMessage } from '../utils/printUpdateMessage' -import { consoleContext, Context } from './__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('update available message', () => { it('dev tag - minor', () => { diff --git a/packages/cli/src/bin.ts b/packages/cli/src/bin.ts index 7596ff94e2e0..8a74cca78e6c 100755 --- a/packages/cli/src/bin.ts +++ b/packages/cli/src/bin.ts @@ -1,25 +1,63 @@ #!/usr/bin/env ts-node -// hides ExperimentalWarning: The fs.promises API is experimental -process.env.NODE_NO_WARNINGS = '1' - +import Debug from '@prisma/debug' +import { enginesVersion } from '@prisma/engines' +import { + DbCommand, + DbExecute, + DbPull, + DbPush, + // DbDrop, + DbSeed, + handlePanic, + MigrateCommand, + MigrateDeploy, + MigrateDev, + MigrateDiff, + MigrateReset, + MigrateResolve, + MigrateStatus, +} from '@prisma/migrate' import { arg, getCLIPathHash, + getConfig, getProjectHash, getSchema, - getConfig, - tryLoadEnvs, - getEnvPaths, + HelpError, + isCurrentBinInstalledGlobally, + isError, parseEnvValue, } from '@prisma/sdk' import chalk from 'chalk' +import * as checkpoint from 'checkpoint-client' +import path from 'path' + +import { CLI } from './CLI' +import { Dev } from './Dev' +import { Doctor } from './Doctor' +import { Format } from './Format' +import { Generate } from './Generate' +import { Init } from './Init' +/* + When running bin.ts with ts-node with DEBUG="*" + This error shows and blocks the execution + Quick hack is to comment the Studio import and usage to use the CLI without building it... + prisma:cli Error: Cannot find module '@prisma/sdk' + prisma:cli Require stack: + prisma:cli - /Users/j42/Dev/prisma-meow/node_modules/.pnpm/@prisma+studio-pcw@0.456.0/node_modules/@prisma/studio-pcw/dist/index.js +*/ +import { Studio } from './Studio' +import { Telemetry } from './Telemetry' +import { detectPrisma1 } from './utils/detectPrisma1' +import { printUpdateMessage } from './utils/printUpdateMessage' +import { Validate } from './Validate' +import { Version } from './Version' // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment const packageJson = require('../package.json') -const commandArray = process.argv.slice(2) -import Debug from '@prisma/debug' +const commandArray = process.argv.slice(2) process.removeAllListeners('warning') @@ -53,56 +91,6 @@ const args = arg( true, ) -// -// Read .env file only if next to schema.prisma -// -// if the CLI is called without any command like `prisma` we can ignore .env loading -if (commandArray.length) { - try { - const envPaths = getEnvPaths(args['--schema']) - const envData = tryLoadEnvs(envPaths, { conflictCheck: 'error' }) - envData && envData.message && console.log(envData.message) - } catch (e) { - handleIndividualError(e) - } -} - -/** - * Dependencies - */ -import * as checkpoint from 'checkpoint-client' -import { isError, HelpError } from '@prisma/sdk' -import { - MigrateCommand, - MigrateDev, - MigrateResolve, - MigrateStatus, - MigrateReset, - MigrateDeploy, - DbPush, - DbPull, - // DbDrop, - DbSeed, - DbCommand, - handlePanic, -} from '@prisma/migrate' - -import { CLI } from './CLI' -import { Init } from './Init' -import { Dev } from './Dev' -import { Version } from './Version' -import { Generate } from './Generate' -import { isCurrentBinInstalledGlobally } from '@prisma/sdk' -import { Validate } from './Validate' -import { Format } from './Format' -import { Doctor } from './Doctor' -import { Studio } from './Studio' -import { Telemetry } from './Telemetry' -import { printUpdateMessage } from './utils/printUpdateMessage' -import { enginesVersion } from '@prisma/engines' -import path from 'path' -import { detectPrisma1 } from './utils/detectPrisma1' - // because chalk ... if (process.env.NO_COLOR) { chalk.level = 0 @@ -127,8 +115,10 @@ async function main(): Promise { resolve: MigrateResolve.new(), reset: MigrateReset.new(), deploy: MigrateDeploy.new(), + diff: MigrateDiff.new(), }), db: DbCommand.new({ + execute: DbExecute.new(), pull: DbPull.new(), push: DbPush.new(), // drop: DbDrop.new(), @@ -138,7 +128,6 @@ async function main(): Promise { * @deprecated since version 2.30.0, use `db pull` instead (renamed) */ introspect: DbPull.new(), - dev: Dev.new(), studio: Studio.new(), generate: Generate.new(), version: Version.new(), @@ -146,6 +135,8 @@ async function main(): Promise { format: Format.new(), doctor: Doctor.new(), telemetry: Telemetry.new(), + // TODO remove Legacy + dev: Dev.new(), }, [ 'version', @@ -153,7 +144,6 @@ async function main(): Promise { 'migrate', 'db', 'introspect', - 'dev', 'studio', 'generate', 'validate', diff --git a/packages/cli/src/utils/detectPrisma1.ts b/packages/cli/src/utils/detectPrisma1.ts index 7f9cfa96e93a..8f1508fffcfd 100644 --- a/packages/cli/src/utils/detectPrisma1.ts +++ b/packages/cli/src/utils/detectPrisma1.ts @@ -6,7 +6,7 @@ export function detectPrisma1() { throw new Error( `We detected a Prisma 1 project. For Prisma 1, please use the \`prisma1\` CLI instead. You can install it with \`npm install -g prisma1\`. -If you want to upgrade to Prisma 2, please have a look at our upgrade guide: +If you want to upgrade to Prisma 2+, please have a look at our upgrade guide: http://pris.ly/d/upgrading-to-prisma2`, ) } diff --git a/packages/cli/src/utils/prompt/utils/deepExtend.ts b/packages/cli/src/utils/prompt/utils/deepExtend.ts index 5b9636bb5e72..61b1b74a40d9 100644 --- a/packages/cli/src/utils/prompt/utils/deepExtend.ts +++ b/packages/cli/src/utils/prompt/utils/deepExtend.ts @@ -71,7 +71,7 @@ function safeGetProperty(object, property): any { } /** - * Extening object that entered in first argument. + * Extending object that entered in first argument. * * Returns extended object or false if have no target object or incorrect type. * diff --git a/packages/cli/src/utils/prompt/utils/templates/__tests__/sortModels.test.ts b/packages/cli/src/utils/prompt/utils/templates/__tests__/sortModels.test.ts index 2deb5ca19f3a..a9440849aaed 100644 --- a/packages/cli/src/utils/prompt/utils/templates/__tests__/sortModels.test.ts +++ b/packages/cli/src/utils/prompt/utils/templates/__tests__/sortModels.test.ts @@ -1,6 +1,7 @@ -import { sortModels } from '../sortModels' import type { DMMF } from '@prisma/generator-helper' +import { sortModels } from '../sortModels' + test('sortModels', () => { const models: DMMF.Model[] = [ { diff --git a/packages/cli/src/utils/test-handlePanic.ts b/packages/cli/src/utils/test-handlePanic.ts index 099fbd4667e7..b314bf47014c 100644 --- a/packages/cli/src/utils/test-handlePanic.ts +++ b/packages/cli/src/utils/test-handlePanic.ts @@ -1,7 +1,7 @@ import { handlePanic } from '@prisma/migrate' -import path from 'path' -import fs from 'fs' import { IntrospectionEngine } from '@prisma/sdk' +import fs from 'fs' +import path from 'path' async function main() { const packageJsonVersion = '0.0.0' diff --git a/packages/cli/tsconfig.eslint.json b/packages/cli/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/cli/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/client/.eslintignore b/packages/client/.eslintignore deleted file mode 100644 index 801970943aea..000000000000 --- a/packages/client/.eslintignore +++ /dev/null @@ -1,10 +0,0 @@ -/node_modules -/generator-build -/declaration -/runtime -/sandbox - -generated-dmmf.ts -/src/__tests__/types -/src/__tests__/benchmarks -/src/__tests__/__helpers__/dmmf-types.ts diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/client/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/client/.gitignore b/packages/client/.gitignore index 584a36c636a5..871a4cb29377 100644 --- a/packages/client/.gitignore +++ b/packages/client/.gitignore @@ -5,4 +5,5 @@ pnpm-lock.yaml *.tsbuildinfo +junit.xml .DS_Store diff --git a/packages/client/fixtures/generate.ts b/packages/client/fixtures/generate.ts index dcb8d4667b3b..3504f977de72 100644 --- a/packages/client/fixtures/generate.ts +++ b/packages/client/fixtures/generate.ts @@ -1,9 +1,10 @@ -import fs from 'fs' -import { generateInFolder } from '../src/utils/generateInFolder' import arg from 'arg' import chalk from 'chalk' +import fs from 'fs' import path from 'path' +import { generateInFolder } from '../src/utils/generateInFolder' + async function main() { const args = arg({ '--skip-transpile': Boolean, diff --git a/packages/client/fixtures/mongo/prisma/schema.prisma b/packages/client/fixtures/mongo/prisma/schema.prisma index 080baebd3a44..cbf1f7ef1c05 100644 --- a/packages/client/fixtures/mongo/prisma/schema.prisma +++ b/packages/client/fixtures/mongo/prisma/schema.prisma @@ -8,7 +8,7 @@ generator client { } model User { - id String @id @default(dbgenerated()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId email String @unique } diff --git a/packages/client/helpers/build.ts b/packages/client/helpers/build.ts index 44c0afa53cf1..198bbd82b550 100644 --- a/packages/client/helpers/build.ts +++ b/packages/client/helpers/build.ts @@ -1,11 +1,12 @@ +import { Extractor, ExtractorConfig } from '@microsoft/api-extractor' +import fs from 'fs' +import path from 'path' +import resolve from 'resolve' + import type { BuildOptions } from '../../../helpers/compile/build' import { build } from '../../../helpers/compile/build' import { fillPlugin } from '../../../helpers/compile/plugins/fill-plugin/fillPlugin' import { replaceWithPlugin } from '../../../helpers/compile/plugins/replaceWithPlugin' -import { Extractor, ExtractorConfig } from '@microsoft/api-extractor' -import resolve from 'resolve' -import path from 'path' -import fs from 'fs' const inlineUndiciWasm = replaceWithPlugin([ [ @@ -39,7 +40,7 @@ const runtimeBuildConfig: BuildOptions = { // that fixes an issue with lz-string umd builds 'define.amd': 'false', }, - plugins: [inlineUndiciWasm], + plugins: [], } // we define the config for browser @@ -103,6 +104,7 @@ function bundleTypeDefinitions(filename: string, outfile: string) { bundledPackages: [ 'decimal.js', 'sql-template-tag', + '@opentelemetry/api', '@prisma/sdk', '@prisma/engine-core', '@prisma/generator-helper', diff --git a/packages/client/helpers/jestSetup.js b/packages/client/helpers/jestSetup.js index 2a8b9b503d7a..770ed9af21d5 100644 --- a/packages/client/helpers/jestSetup.js +++ b/packages/client/helpers/jestSetup.js @@ -1,4 +1 @@ process.env.PRISMA_HIDE_PREVIEW_FLAG_WARNINGS = 'true' - -// Needed to hide warnings because of patchJest.js -process.setMaxListeners(200) diff --git a/packages/client/helpers/jestSnapshotSerializer.js b/packages/client/helpers/jestSnapshotSerializer.js deleted file mode 100644 index c12dfc559601..000000000000 --- a/packages/client/helpers/jestSnapshotSerializer.js +++ /dev/null @@ -1,60 +0,0 @@ -const path = require('path') -const replaceAll = require('replace-string') // sindre's replaceAll polyfill -const stripAnsi = require('strip-ansi') -const { platformRegex } = require('@prisma/sdk') - -function trimErrorPaths(str) { - const parentDir = path.dirname(path.dirname(__dirname)) - - return replaceAll(str, parentDir, '') -} - -function normalizeToUnixPaths(str) { - // TODO: Windows: this breaks some tests by replacing backslashes outside of file names. - return replaceAll(str, path.sep, '/') -} - -function removePlatforms(str) { - return str.replace(platformRegex, 'TEST_PLATFORM') -} - -function normalizeGithubLinks(str) { - return str.replace(/https:\/\/github.com\/prisma\/prisma(-client-js)?\/issues\/\S+/, 'TEST_GITHUB_LINK') -} - -function normalizeTsClientStackTrace(str) { - return str.replace(/([/\\]client[/\\]src[/\\]__tests__[/\\].*test.ts)(:\d*:\d*)/, '$1:0:0') -} - -// When updating snapshots this is sensitive to OS -// macOS will update extension to .dylib.node, but CI uses .so.node for example -// Note that on Windows the file name doesn't start with "lib". -function normalizeNodeApiLibFilePath(str) { - return str.replace( - /((lib)?query_engine-TEST_PLATFORM.)(.*)(.node)/, - 'libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node', - ) -} - -function normalizeBinaryFilePath(str) { - return str.replace(/query-engine-TEST_PLATFORM\.exe/, 'query-engine-TEST_PLATFORM') -} - -const serializer = { - test(value) { - return typeof value === 'string' || value instanceof Error - }, - serialize(value) { - const message = typeof value === 'string' ? value : value instanceof Error ? value.message : '' - // TODO: consider introducing a helper function like pipe or compose - return normalizeGithubLinks( - normalizeToUnixPaths( - normalizeBinaryFilePath( - normalizeNodeApiLibFilePath(removePlatforms(normalizeTsClientStackTrace(trimErrorPaths(stripAnsi(message))))), - ), - ), - ) - }, -} - -module.exports = serializer diff --git a/packages/client/jest.config.js b/packages/client/jest.config.js index fe0fc71e2bb4..a5f5a608c916 100644 --- a/packages/client/jest.config.js +++ b/packages/client/jest.config.js @@ -15,6 +15,7 @@ module.exports = { '/src/__tests__/benchmarks/', '/src/__tests__/types/.*/test.ts', '/src/__tests__/integration/happy/exhaustive-schema/generated-dmmf.ts', + '/src/__tests__/integration/happy/exhaustive-schema-mongo/generated-dmmf.ts', '__helpers__/', 'node_modules/', 'index.ts', @@ -24,7 +25,19 @@ module.exports = { '.bench.ts', ], collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], - snapshotSerializers: ['./helpers/jestSnapshotSerializer'], + snapshotSerializers: ['@prisma/sdk/src/utils/jestSnapshotSerializer'], testTimeout: 90000, setupFiles: ['./helpers/jestSetup.js'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/client/package.json b/packages/client/package.json index 11a3196a85c5..c5b2e5607d22 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -42,17 +42,12 @@ "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "test": "jest --verbose", "test-notypes": "jest --verbose --testPathIgnorePatterns src/__tests__/types/types.test.ts", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", "generate": "node scripts/postinstall.js", "postinstall": "node scripts/postinstall.js", "prepare": "cp scripts/backup-index.js index.js && cp scripts/backup-index.d.ts index.d.ts", - "prepublishOnly": "pnpm run build", - "precommit": "lint-staged" + "prepublishOnly": "pnpm run build" }, "files": [ "README.md", @@ -65,33 +60,27 @@ ], "devDependencies": { "@microsoft/api-extractor": "7.19.3", + "@opentelemetry/api": "1.0.3", "@prisma/debug": "workspace:*", "@prisma/engine-core": "workspace:*", - "@prisma/engines": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", - "@prisma/fetch-engine": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/engines": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", + "@prisma/fetch-engine": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/generator-helper": "workspace:*", - "@prisma/get-platform": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/get-platform": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/migrate": "workspace:*", "@prisma/sdk": "workspace:*", "@timsuchanek/copy": "1.4.5", "@types/debug": "4.1.7", - "@types/jest": "27.4.0", + "@types/jest": "27.4.1", "@types/js-levenshtein": "1.1.1", - "@types/mssql": "6.0.8", - "@types/node": "12.20.39", - "@types/pg": "8.6.3", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", + "@types/mssql": "7.1.5", + "@types/node": "12.20.47", + "@types/pg": "8.6.5", "arg": "5.0.1", "benchmark": "2.1.4", "chalk": "4.1.2", "decimal.js": "10.3.1", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", "execa": "5.1.1", "flat-map-polyfill": "0.3.8", "fs-monkey": "1.0.3", @@ -99,19 +88,19 @@ "indent-string": "4.0.0", "is-obj": "2.0.0", "is-regexp": "2.1.0", - "jest": "27.4.6", + "jest": "27.5.1", + "jest-junit": "13.0.0", "js-levenshtein": "1.1.6", "klona": "2.0.5", - "lint-staged": "12.1.5", "lz-string": "1.4.4", "make-dir": "3.1.0", - "mariadb": "2.5.5", - "mssql": "7.3.0", + "mariadb": "3.0.0", + "mssql": "8.0.1", "pg": "8.7.1", "pkg-up": "3.1.0", "pluralize": "8.0.0", - "prettier": "2.5.1", "replace-string": "3.1.0", + "resolve": "1.22.0", "rimraf": "3.0.2", "sort-keys": "4.2.0", "source-map-support": "0.5.21", @@ -119,7 +108,7 @@ "stacktrace-parser": "0.1.10", "strip-ansi": "6.0.1", "strip-indent": "3.0.0", - "ts-jest": "27.1.2", + "ts-jest": "27.1.3", "ts-node": "10.4.0", "tsd": "0.19.1", "typescript": "4.5.4" @@ -133,13 +122,7 @@ } }, "dependencies": { - "@prisma/engines-version": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908" - }, - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] + "@prisma/engines-version": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77" }, "sideEffects": false } diff --git a/packages/client/scripts/colors.js b/packages/client/scripts/colors.js index 25ec9a9e7f6e..ac30d2e340a8 100644 --- a/packages/client/scripts/colors.js +++ b/packages/client/scripts/colors.js @@ -1,11 +1,11 @@ 'use strict' -const isObject = (val) => - val !== null && typeof val === 'object' && !Array.isArray(val) +const isObject = (val) => val !== null && typeof val === 'object' && !Array.isArray(val) // this is a modified version of https://github.com/chalk/ansi-regex (MIT License) -/* eslint-disable-next-line no-control-regex */ -const ANSI_REGEX = /[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g +const ANSI_REGEX = + /* eslint-disable-next-line no-control-regex */ + /[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g const create = () => { const colors = { enabled: true, visible: true, styles: {}, keys: {} } @@ -30,9 +30,7 @@ const create = () => { } const wrap = (style, input, newline) => { - return typeof style === 'function' - ? style(input) - : style.wrap(input, newline) + return typeof style === 'function' ? style(input) : style.wrap(input, newline) } const style = (input, stack) => { @@ -126,9 +124,7 @@ const create = () => { let fn = typeof color === 'string' ? colors[color] : color if (typeof fn !== 'function') { - throw new TypeError( - 'Expected alias to be the name of an existing color (string) or a function', - ) + throw new TypeError('Expected alias to be the name of an existing color (string) or a function') } if (!fn.stack) { diff --git a/packages/client/scripts/postinstall.js b/packages/client/scripts/postinstall.js index b45dfde2291c..f0bb4b39b26e 100644 --- a/packages/client/scripts/postinstall.js +++ b/packages/client/scripts/postinstall.js @@ -42,7 +42,7 @@ function findPackageRoot(startPath, limit = 10) { if (pkg.name && !['@prisma/cli', 'prisma'].includes(pkg.name)) { return pkgPath.replace('package.json', '') } - } catch {} + } catch {} // eslint-disable-line no-empty } currentPath = path.join(currentPath, '../') } @@ -61,7 +61,6 @@ async function main() { const installedGlobally = localPath ? undefined : await isInstalledGlobally() // this is needed, so that the Generate command does not fail in postinstall - process.env.PRISMA_GENERATE_IN_POSTINSTALL = 'true' // this is needed, so we can find the correct schemas in yarn workspace projects @@ -77,20 +76,11 @@ async function main() { }) try { if (localPath) { - await run('node', [ - localPath, - 'generate', - '--postinstall', - doubleQuote(getPostInstallTrigger()), - ]) + await run('node', [localPath, 'generate', '--postinstall', doubleQuote(getPostInstallTrigger())]) return } if (installedGlobally) { - await run('prisma', [ - 'generate', - '--postinstall', - doubleQuote(getPostInstallTrigger()), - ]) + await run('prisma', ['generate', '--postinstall', doubleQuote(getPostInstallTrigger())]) return } } catch (e) { @@ -116,16 +106,14 @@ function getLocalPackagePath() { if (packagePath) { return require.resolve('prisma') } - } catch (e) { - // - } + } catch (e) {} // eslint-disable-line no-empty try { const packagePath = require.resolve('@prisma/cli/package.json') if (packagePath) { return require.resolve('@prisma/cli') } - } catch (e) {} + } catch (e) {} // eslint-disable-line no-empty return null } @@ -136,12 +124,8 @@ async function isInstalledGlobally() { if (result.stdout.includes('@prisma/client')) { return true } else { - console.error(`${c.yellow('warning')} You still have the ${c.bold( - 'prisma', - )} cli (Prisma 1) installed globally. -Please uninstall it with either ${c.green('npm remove -g prisma')} or ${c.green( - 'yarn global remove prisma', - )}.`) + console.error(`${c.yellow('warning')} You still have the ${c.bold('prisma')} cli (Prisma 1) installed globally. +Please uninstall it with either ${c.green('npm remove -g prisma')} or ${c.green('yarn global remove prisma')}.`) } } catch (e) { return false @@ -154,9 +138,7 @@ if (!process.env.PRISMA_SKIP_POSTINSTALL_GENERATE) { if (e.stderr) { if (e.stderr.includes(`Can't find schema.prisma`)) { console.error( - `${c.yellow('warning')} @prisma/client needs a ${c.bold( - 'schema.prisma', - )} to function, but couldn't find it. + `${c.yellow('warning')} @prisma/client needs a ${c.bold('schema.prisma')} to function, but couldn't find it. Please either create one manually or use ${c.bold('prisma init')}. Once you created it, run ${c.bold('prisma generate')}. To keep Prisma related things separate, we recommend creating it in a subfolder called ${c.underline( @@ -204,30 +186,18 @@ async function ensureEmptyDotPrisma() { const dotPrismaClientDir = path.join(__dirname, '../../../.prisma/client') await makeDir(dotPrismaClientDir) const defaultIndexJsPath = path.join(dotPrismaClientDir, 'index.js') - const defaultIndexBrowserJSPath = path.join( - dotPrismaClientDir, - 'index-browser.js', - ) + const defaultIndexBrowserJSPath = path.join(dotPrismaClientDir, 'index-browser.js') const defaultIndexDTSPath = path.join(dotPrismaClientDir, 'index.d.ts') if (!fs.existsSync(defaultIndexJsPath)) { - await copyFile( - path.join(__dirname, 'default-index.js'), - defaultIndexJsPath, - ) + await copyFile(path.join(__dirname, 'default-index.js'), defaultIndexJsPath) } if (!fs.existsSync(defaultIndexBrowserJSPath)) { - await copyFile( - path.join(__dirname, 'default-index-browser.js'), - defaultIndexBrowserJSPath, - ) + await copyFile(path.join(__dirname, 'default-index-browser.js'), defaultIndexBrowserJSPath) } if (!fs.existsSync(defaultIndexDTSPath)) { - await copyFile( - path.join(__dirname, 'default-index.d.ts'), - defaultIndexDTSPath, - ) + await copyFile(path.join(__dirname, 'default-index.d.ts'), defaultIndexDTSPath) } } catch (e) { console.error(e) @@ -330,9 +300,7 @@ function getPostInstallTrigger() { return `${UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR}: ${maybe_npm_config_argv_string}` } - const npm_config_arv_original = npm_config_arv_original_arr - .filter((arg) => arg !== '') - .join(' ') + const npm_config_arv_original = npm_config_arv_original_arr.filter((arg) => arg !== '').join(' ') const command = npm_config_arv_original === '' @@ -371,10 +339,10 @@ function parsePackageManagerName(userAgent) { // example: 'yarn/1.22.4 npm/? node/v13.11.0 darwin x64' // References: - // - https://pnpm.js.org/en/3.6/only-allow-pnpm + // - https://pnpm.io/only-allow-pnpm // - https://github.com/cameronhunter/npm-config-user-agent-parser if (userAgent) { - const matchResult = userAgent.match(/^([^\/]+)\/.+/) + const matchResult = userAgent.match(/^([^/]+)\/.+/) if (matchResult) { packageManager = matchResult[1].trim() } diff --git a/packages/client/src/__tests__/__helpers__/dmmf-types.ts b/packages/client/src/__tests__/__helpers__/dmmf-types.ts index 131e8d9cdc26..7bb940bab5be 100644 --- a/packages/client/src/__tests__/__helpers__/dmmf-types.ts +++ b/packages/client/src/__tests__/__helpers__/dmmf-types.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper' +import type { DMMF } from '@prisma/generator-helper' const dmmf: DMMF.Document = { datamodel: { @@ -144,6 +144,7 @@ const dmmf: DMMF.Document = { uniqueIndexes: [], }, ], + types: [], }, mappings: { modelOperations: [ @@ -1108,38 +1109,38 @@ const dmmf: DMMF.Document = { inputTypes: [ { isList: false, - location: 'scalar', - type: 'String', + location: 'inputObjectTypes', + namespace: 'prisma', + type: 'UserCreateNestedOneWithoutPostsInput', }, ], isNullable: false, isRequired: true, - name: 'title', + name: 'author', }, { inputTypes: [ { isList: false, location: 'scalar', - type: 'Boolean', + type: 'String', }, ], isNullable: false, - isRequired: false, - name: 'published', + isRequired: true, + name: 'title', }, { inputTypes: [ { isList: false, - location: 'inputObjectTypes', - namespace: 'prisma', - type: 'UserCreateNestedOneWithoutPostsInput', + location: 'scalar', + type: 'Boolean', }, ], isNullable: false, - isRequired: true, - name: 'author', + isRequired: false, + name: 'published', }, ], name: 'PostCreateInput', @@ -1209,52 +1210,52 @@ const dmmf: DMMF.Document = { fields: [ { inputTypes: [ - { - isList: false, - location: 'scalar', - type: 'String', - }, { isList: false, location: 'inputObjectTypes', namespace: 'prisma', - type: 'StringFieldUpdateOperationsInput', + type: 'UserUpdateOneRequiredWithoutPostsInput', }, ], isNullable: false, isRequired: false, - name: 'title', + name: 'author', }, { inputTypes: [ { isList: false, location: 'scalar', - type: 'Boolean', + type: 'String', }, { isList: false, location: 'inputObjectTypes', namespace: 'prisma', - type: 'BoolFieldUpdateOperationsInput', + type: 'StringFieldUpdateOperationsInput', }, ], isNullable: false, isRequired: false, - name: 'published', + name: 'title', }, { inputTypes: [ + { + isList: false, + location: 'scalar', + type: 'Boolean', + }, { isList: false, location: 'inputObjectTypes', namespace: 'prisma', - type: 'UserUpdateOneRequiredWithoutPostsInput', + type: 'BoolFieldUpdateOperationsInput', }, ], isNullable: false, isRequired: false, - name: 'author', + name: 'published', }, ], name: 'PostUpdateInput', @@ -3130,48 +3131,6 @@ const dmmf: DMMF.Document = { ], name: 'UserCreateNestedOneWithoutPostsInput', }, - { - constraints: { - maxNumFields: 1, - minNumFields: 1, - }, - fields: [ - { - inputTypes: [ - { - isList: false, - location: 'scalar', - type: 'String', - }, - ], - isNullable: false, - isRequired: false, - name: 'set', - }, - ], - name: 'StringFieldUpdateOperationsInput', - }, - { - constraints: { - maxNumFields: 1, - minNumFields: 1, - }, - fields: [ - { - inputTypes: [ - { - isList: false, - location: 'scalar', - type: 'Boolean', - }, - ], - isNullable: false, - isRequired: false, - name: 'set', - }, - ], - name: 'BoolFieldUpdateOperationsInput', - }, { constraints: { maxNumFields: null, @@ -3258,6 +3217,48 @@ const dmmf: DMMF.Document = { ], name: 'UserUpdateOneRequiredWithoutPostsInput', }, + { + constraints: { + maxNumFields: 1, + minNumFields: 1, + }, + fields: [ + { + inputTypes: [ + { + isList: false, + location: 'scalar', + type: 'String', + }, + ], + isNullable: false, + isRequired: false, + name: 'set', + }, + ], + name: 'StringFieldUpdateOperationsInput', + }, + { + constraints: { + maxNumFields: 1, + minNumFields: 1, + }, + fields: [ + { + inputTypes: [ + { + isList: false, + location: 'scalar', + type: 'Boolean', + }, + ], + isNullable: false, + isRequired: false, + name: 'set', + }, + ], + name: 'BoolFieldUpdateOperationsInput', + }, { constraints: { maxNumFields: 1, @@ -5840,7 +5841,7 @@ const dmmf: DMMF.Document = { }, { args: [], - isNullable: true, + isNullable: false, name: '_count', outputType: { isList: false, diff --git a/packages/client/src/__tests__/__snapshots__/include.test.ts.snap b/packages/client/src/__tests__/__snapshots__/include.test.ts.snap index 174df480085a..e9b0bf7dd641 100644 --- a/packages/client/src/__tests__/__snapshots__/include.test.ts.snap +++ b/packages/client/src/__tests__/__snapshots__/include.test.ts.snap @@ -24,7 +24,7 @@ query { title content authorId - optionnal + optional } } } @@ -40,7 +40,7 @@ query { title content authorId - optionnal + optional author { id email @@ -87,7 +87,7 @@ query { title content authorId - optionnal + optional author { id email @@ -110,7 +110,7 @@ query { title content authorId - optionnal + optional } } } diff --git a/packages/client/src/__tests__/__snapshots__/select.test.ts.snap b/packages/client/src/__tests__/__snapshots__/select.test.ts.snap index dfb7455d81c2..f1ab71659641 100644 --- a/packages/client/src/__tests__/__snapshots__/select.test.ts.snap +++ b/packages/client/src/__tests__/__snapshots__/select.test.ts.snap @@ -37,7 +37,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -57,7 +57,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -77,7 +77,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -110,7 +110,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -140,7 +140,7 @@ query { title content authorId - optionnal + optional } } } @@ -161,7 +161,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -194,7 +194,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -221,7 +221,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -250,7 +250,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -300,7 +300,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -317,7 +317,7 @@ Invalid \`prisma.createOnePost()\` invocation: ? createdAt?: DateTime, ? updatedAt?: DateTime, ? content?: String | null, -? optionnal?: Float | null, +? optional?: Float | null, ? author?: { ? create?: UserCreateWithoutPostsInput | UserUncheckedCreateWithoutPostsInput, ? connectOrCreate?: UserCreateOrConnectWithoutPostsInput, @@ -354,7 +354,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -376,7 +376,7 @@ Invalid \`prisma.createOnePost()\` invocation: ? createdAt?: DateTime, ? updatedAt?: DateTime, ? content?: String | null, -? optionnal?: Float | null, +? optional?: Float | null, ? categories?: { ? create?: CategoryCreateWithoutPostsInput | CategoryCreateWithoutPostsInput | CategoryUncheckedCreateWithoutPostsInput | CategoryUncheckedCreateWithoutPostsInput, ? connectOrCreate?: CategoryCreateOrConnectWithoutPostsInput | CategoryCreateOrConnectWithoutPostsInput, @@ -476,7 +476,7 @@ query { age_gt: 10123123123 id_endsWith: "veryLongNameGoIntoaNewLineNow@gmail.com" name_contains: "hans" - name_gt: 2131203912039123 + name_gt: 2020123100000023 name_in: ["hans"] AND: [ { @@ -541,7 +541,7 @@ Invalid \`prisma.findManyUser()\` invocation: ~~~~~~~~~~~ name_contains: 'hans', ~~~~~~~~~~~~~ - name_gt: 2131203912039123, + name_gt: 2020123100000023, ~~~~~~~ name_in: [ ~~~~~~~ @@ -827,7 +827,7 @@ Invalid \`prisma.findManyUser()\` invocation: ~~~~~~~~~~~ name_contains: 'hans', ~~~~~~~~~~~~~ - name_gt: 2131203912039123, + name_gt: 2020123100000023, ~~~~~~~ name_in: [ ~~~~~~~ diff --git a/packages/client/src/__tests__/__snapshots__/undefined-vs-null.test.ts.snap b/packages/client/src/__tests__/__snapshots__/undefined-vs-null.test.ts.snap index 11f278372825..cd6f0396ec65 100644 --- a/packages/client/src/__tests__/__snapshots__/undefined-vs-null.test.ts.snap +++ b/packages/client/src/__tests__/__snapshots__/undefined-vs-null.test.ts.snap @@ -17,7 +17,7 @@ mutation { title content authorId - optionnal + optional } } `; @@ -35,7 +35,7 @@ mutation { title content authorId - optionnal + optional } } `; diff --git a/packages/client/src/__tests__/atLeastOne.test.ts b/packages/client/src/__tests__/atLeastOne.test.ts index b6e9a0a67c79..95fdd6951025 100644 --- a/packages/client/src/__tests__/atLeastOne.test.ts +++ b/packages/client/src/__tests__/atLeastOne.test.ts @@ -1,7 +1,8 @@ import stripAnsi from 'strip-ansi' + import { enums } from '../fixtures/enums' -import { DMMFClass, makeDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument } from '../runtime' describe('at least one validation', () => { let dmmf diff --git a/packages/client/src/__tests__/atomicOperationsUpdate.test.ts b/packages/client/src/__tests__/atomicOperationsUpdate.test.ts index f63fd759dc5c..64f03505e008 100644 --- a/packages/client/src/__tests__/atomicOperationsUpdate.test.ts +++ b/packages/client/src/__tests__/atomicOperationsUpdate.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { blog } from '../fixtures/blog' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 let dmmf diff --git a/packages/client/src/__tests__/batching.test.ts b/packages/client/src/__tests__/batching.test.ts index e5578324290c..2651faea4a61 100644 --- a/packages/client/src/__tests__/batching.test.ts +++ b/packages/client/src/__tests__/batching.test.ts @@ -1,7 +1,7 @@ -import { PrismaClientFetcher } from '../runtime/PrismaClientFetcher' import { blog } from '../fixtures/blog' import { getDMMF } from '../generation/getDMMF' import { DMMFClass, makeDocument } from '../runtime' +import { RequestHandler } from '../runtime/RequestHandler' describe('batching', () => { test('basic batching', async () => { @@ -9,13 +9,15 @@ describe('batching', () => { const batches: any[] = [] const requests: any[] = [] - const fetcher = new PrismaClientFetcher({ + const fetcher = new RequestHandler({ $connect: () => Promise.resolve(), _engine: { + // @ts-expect-error requestBatch: (batch) => { batches.push(batch) return Promise.resolve(batch.map(() => ({ data: { data: null }, elapsed: 0.2 }))) }, + // @ts-expect-error request: (request) => { requests.push(request) return Promise.resolve({ data: { data: null }, elapsed: 0.3 }) @@ -122,13 +124,15 @@ describe('batching', () => { const batches: any[] = [] const requests: any[] = [] - const fetcher = new PrismaClientFetcher({ + const fetcher = new RequestHandler({ $connect: () => Promise.resolve(), _engine: { + // @ts-expect-error requestBatch: (batch) => { batches.push(batch) return Promise.resolve(batch.map(() => ({ data: { data: null }, elapsed: 0.2 }))) }, + // @ts-expect-error request: (request) => { requests.push(request) return Promise.resolve({ data: { data: null }, elapsed: 0.3 }) @@ -193,7 +197,7 @@ describe('batching', () => { title content authorId - optionnal + optional } }, query { @@ -224,13 +228,15 @@ describe('batching', () => { const batches: any[] = [] const requests: any[] = [] - const fetcher = new PrismaClientFetcher({ + const fetcher = new RequestHandler({ $connect: () => Promise.resolve(), _engine: { + // @ts-expect-error requestBatch: (batch) => { batches.push(batch) return Promise.resolve(batch.map(() => ({ data: { data: null }, elapsed: 0.2 }))) }, + // @ts-expect-error request: (request) => { requests.push(request) return Promise.resolve({ data: { data: null }, elapsed: 0.3 }) diff --git a/packages/client/src/__tests__/benchmarks/huge-schema/compile.ts b/packages/client/src/__tests__/benchmarks/huge-schema/compile.ts index 762b7982bb26..1e57096b9084 100644 --- a/packages/client/src/__tests__/benchmarks/huge-schema/compile.ts +++ b/packages/client/src/__tests__/benchmarks/huge-schema/compile.ts @@ -1,4 +1,5 @@ import { PrismaClient } from '@prisma/client' + const client = new PrismaClient() async function main() { diff --git a/packages/client/src/__tests__/benchmarks/huge-schema/huge-schema.bench.ts b/packages/client/src/__tests__/benchmarks/huge-schema/huge-schema.bench.ts index efb88d0de96f..710238ff65a0 100644 --- a/packages/client/src/__tests__/benchmarks/huge-schema/huge-schema.bench.ts +++ b/packages/client/src/__tests__/benchmarks/huge-schema/huge-schema.bench.ts @@ -3,6 +3,7 @@ import Benchmark from 'benchmark' import execa from 'execa' import path from 'path' + import { compileFile } from '../../../utils/compileFile' import { generateTestClient } from '../../../utils/getTestClient' @@ -55,12 +56,7 @@ suite }) execa.sync( 'zip', - [ - '-r', - 'dotPlusAtPrismaClientFolder.zip', - './node_modules/.prisma/client', - './node_modules/@prisma/client', - ], + ['-r', 'dotPlusAtPrismaClientFolder.zip', './node_modules/.prisma/client', './node_modules/@prisma/client'], { stdout: 'pipe', cwd: __dirname, @@ -87,9 +83,9 @@ function getSize(targetPath: string): { size: string; unit: string } { const match = regex.exec(str) const pkgSize = { size: match[1], unit: match[3] } console.log( - `${targetPath.replace('./node_modules/', '').replace('./', '')} size x ${ - pkgSize.size - } ${pkgSize.unit}B ±0.00% (1 runs sampled)`, + `${targetPath.replace('./node_modules/', '').replace('./', '')} size x ${pkgSize.size} ${ + pkgSize.unit + }B ±0.00% (1 runs sampled)`, ) return pkgSize diff --git a/packages/client/src/__tests__/buildNFTAnnotations.test.ts b/packages/client/src/__tests__/buildNFTAnnotations.test.ts new file mode 100644 index 000000000000..644ee6b82ad8 --- /dev/null +++ b/packages/client/src/__tests__/buildNFTAnnotations.test.ts @@ -0,0 +1,126 @@ +import { ClientEngineType } from '@prisma/sdk' + +import { buildNFTAnnotations } from '../generation/utils/buildNFTAnnotations' + +function normalizePaths(snapshot: string): string { + if (process.platform === 'win32') { + return snapshot.replace(/\\\\/g, '/') + } + return snapshot +} + +describe('library', () => { + it('generates annotations for a schema and a single engine', () => { + const annotations = buildNFTAnnotations(ClientEngineType.Library, ['debian-openssl-1.1.x'], 'out') + + expect(normalizePaths(annotations)).toMatchInlineSnapshot(` + + path.join(__dirname, "libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node"); + path.join(process.cwd(), "out/libquery_engine-TEST_PLATFORM.so.node") + path.join(__dirname, "schema.prisma"); + path.join(process.cwd(), "out/schema.prisma") + `) + }) + + it('generates annotations for a schema and multiple engines', () => { + const annotations = buildNFTAnnotations( + ClientEngineType.Library, + ['debian-openssl-1.1.x', 'darwin', 'windows'], + 'out', + ) + + expect(normalizePaths(annotations)).toMatchInlineSnapshot(` + + path.join(__dirname, "libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node"); + path.join(process.cwd(), "out/libquery_engine-TEST_PLATFORM.so.node") + + path.join(__dirname, "libquery_engine-TEST_PLATFORM.dylib.node"); + path.join(process.cwd(), "out/libquery_engine-TEST_PLATFORM.dylib.node") + + path.join(__dirname, "query_engine-TEST_PLATFORM.dll.node"); + path.join(process.cwd(), "out/query_engine-TEST_PLATFORM.dll.node") + path.join(__dirname, "schema.prisma"); + path.join(process.cwd(), "out/schema.prisma") + `) + }) +}) + +describe('binary', () => { + it('generates annotations for a schema and a single engine', () => { + const annotations = buildNFTAnnotations(ClientEngineType.Binary, ['debian-openssl-1.1.x'], 'out') + + expect(normalizePaths(annotations)).toMatchInlineSnapshot(` + + path.join(__dirname, "query-engine-TEST_PLATFORM"); + path.join(process.cwd(), "out/query-engine-TEST_PLATFORM") + path.join(__dirname, "schema.prisma"); + path.join(process.cwd(), "out/schema.prisma") + `) + }) + + it('generates annotations for a schema and multiple engines', () => { + const annotations = buildNFTAnnotations( + ClientEngineType.Binary, + ['debian-openssl-1.1.x', 'darwin', 'windows'], + 'out', + ) + + expect(normalizePaths(annotations)).toMatchInlineSnapshot(` + + path.join(__dirname, "query-engine-TEST_PLATFORM"); + path.join(process.cwd(), "out/query-engine-TEST_PLATFORM") + + path.join(__dirname, "query-engine-TEST_PLATFORM"); + path.join(process.cwd(), "out/query-engine-TEST_PLATFORM") + + path.join(__dirname, "query-engine-TEST_PLATFORM"); + path.join(process.cwd(), "out/query-engine-TEST_PLATFORM") + path.join(__dirname, "schema.prisma"); + path.join(process.cwd(), "out/schema.prisma") + `) + }) +}) + +describe('dataproxy', () => { + it('generates no annotations', () => { + const annotations = buildNFTAnnotations( + ClientEngineType.DataProxy, + ['debian-openssl-1.1.x', 'darwin', 'windows'], + 'out', + ) + + // TODO: when using .toMatchInlineSnapshot(), this fails after updating snapshots. + // Probably an issue with the snapshot serializer? + expect(normalizePaths(annotations)).toBe(` + +`) + }) +}) + +describe('special cases', () => { + /** + * The build image (Debian) is different from the runtime image (RHEL) on Netlify, + * so the build-time targets are replaced with what will actually be required at run time. + */ + it('replaces platforms with ["rhel-openssl-1.0.x"] on Netlify', () => { + process.env.NETLIFY = 'true' + + const annotations = buildNFTAnnotations( + ClientEngineType.Library, + ['debian-openssl-1.1.x', 'darwin', 'windows'], + 'out', + ) + + delete process.env.NETLIFY + + expect(normalizePaths(annotations)).toMatchInlineSnapshot(` + + path.join(__dirname, "libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node"); + path.join(process.cwd(), "out/libquery_engine-TEST_PLATFORM.so.node") + path.join(__dirname, "schema.prisma"); + path.join(process.cwd(), "out/schema.prisma") + `) + + expect(annotations).toContain('rhel-openssl-1.0.x') + }) +}) diff --git a/packages/client/src/__tests__/dateWhere.test.ts b/packages/client/src/__tests__/dateWhere.test.ts index 24cb7ee7dd72..6737d12f0f9c 100644 --- a/packages/client/src/__tests__/dateWhere.test.ts +++ b/packages/client/src/__tests__/dateWhere.test.ts @@ -1,5 +1,5 @@ -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' const datamodel = `generator client { provider = "prisma-client-js" diff --git a/packages/client/src/__tests__/deepAndOr.test.ts b/packages/client/src/__tests__/deepAndOr.test.ts index df5b6d72049b..71bcc5c76115 100644 --- a/packages/client/src/__tests__/deepAndOr.test.ts +++ b/packages/client/src/__tests__/deepAndOr.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { blog } from '../fixtures/blog' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 let dmmf diff --git a/packages/client/src/__tests__/deepQuery.test.ts b/packages/client/src/__tests__/deepQuery.test.ts index fbbea3822531..c3bbca0936dc 100644 --- a/packages/client/src/__tests__/deepQuery.test.ts +++ b/packages/client/src/__tests__/deepQuery.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { recommender } from '../fixtures/recommender' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 let dmmf diff --git a/packages/client/src/__tests__/deepSome.test.ts b/packages/client/src/__tests__/deepSome.test.ts index 4849739f4890..644ef59242b0 100644 --- a/packages/client/src/__tests__/deepSome.test.ts +++ b/packages/client/src/__tests__/deepSome.test.ts @@ -1,7 +1,8 @@ import chalk from 'chalk' + import { blog } from '../fixtures/blog' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' chalk.level = 0 diff --git a/packages/client/src/__tests__/dmmf.test.ts b/packages/client/src/__tests__/dmmf.test.ts index 6ca06580b270..ef6cf38e3bf2 100644 --- a/packages/client/src/__tests__/dmmf.test.ts +++ b/packages/client/src/__tests__/dmmf.test.ts @@ -1,4 +1,5 @@ import stripAnsi from 'strip-ansi' + import { getDMMF } from '../generation/getDMMF' describe('dmmf', () => { diff --git a/packages/client/src/__tests__/dmmfTypes.test.ts b/packages/client/src/__tests__/dmmfTypes.test.ts index 841c8b8eeae7..53148386e0ac 100644 --- a/packages/client/src/__tests__/dmmfTypes.test.ts +++ b/packages/client/src/__tests__/dmmfTypes.test.ts @@ -1,8 +1,9 @@ -import { getDMMF } from '../generation/getDMMF' import fs from 'fs' import path from 'path' import sortKeys from 'sort-keys' +import { getDMMF } from '../generation/getDMMF' + const blog = `datasource db { provider = "postgres" url = env("MY_POSTGRES_DB") diff --git a/packages/client/src/__tests__/generation/generator.test.ts b/packages/client/src/__tests__/generation/generator.test.ts index 7344b89b5383..c937fcea656b 100644 --- a/packages/client/src/__tests__/generation/generator.test.ts +++ b/packages/client/src/__tests__/generation/generator.test.ts @@ -1,13 +1,17 @@ -import { getGenerator, getPackedPackage, parseEnvValue, ClientEngineType, getClientEngineType } from '@prisma/sdk' +import { ClientEngineType, getClientEngineType, getGenerator, getPackedPackage, parseEnvValue } from '@prisma/sdk' import fs from 'fs' import path from 'path' import rimraf from 'rimraf' import stripAnsi from 'strip-ansi' import { promisify } from 'util' + import { omit } from '../../omit' + const del = promisify(rimraf) -jest.setTimeout(30000) +if (process.env.CI) { + jest.setTimeout(100_000) +} describe('generator', () => { test('minimal', async () => { diff --git a/packages/client/src/__tests__/include.test.ts b/packages/client/src/__tests__/include.test.ts index be548db69e6e..87a5ea018341 100644 --- a/packages/client/src/__tests__/include.test.ts +++ b/packages/client/src/__tests__/include.test.ts @@ -1,13 +1,14 @@ import stripAnsi from 'strip-ansi' + import { blog } from '../fixtures/blog' -import { DMMFClass } from '../runtime/dmmf' -import { makeDocument } from '../runtime/query' import { getDMMF } from '../generation/getDMMF' +import { DMMFHelper } from '../runtime/dmmf' +import { makeDocument } from '../runtime/query' let dmmf beforeAll(async () => { const dmmfDocument = await getDMMF({ datamodel: blog }) - dmmf = new DMMFClass(dmmfDocument) + dmmf = new DMMFHelper(dmmfDocument) }) describe('include validation', () => { @@ -210,7 +211,7 @@ The \`include\` statement for type Post must not be empty. Available options are title content authorId - optionnal + optional } } } @@ -421,7 +422,7 @@ Unknown field \`mauthor\` for include statement on model Post. Available options title content authorId - optionnal + optional } } } diff --git a/packages/client/src/__tests__/integration/errors/can-not-connect-to-database/test.ts b/packages/client/src/__tests__/integration/errors/can-not-connect-to-database/test.ts index 947405373bc3..c101d44d8a40 100644 --- a/packages/client/src/__tests__/integration/errors/can-not-connect-to-database/test.ts +++ b/packages/client/src/__tests__/integration/errors/can-not-connect-to-database/test.ts @@ -20,17 +20,17 @@ describe('can-not-connect-to-database', () => { } catch (err) { expect(err).toMatchInlineSnapshot(` -Invalid \`prisma.user.findUnique()\` invocation in -/client/src/__tests__/integration/errors/can-not-connect-to-database/test.ts:0:0 + Invalid \`prisma.user.findUnique()\` invocation in + /client/src/__tests__/integration/errors/can-not-connect-to-database/test.ts:0:0 - 12 test('auto-connect', async () => { - 13 expect.assertions(1) - 14 try { -→ 15 await prisma.user.findUnique( - Can't reach database server at \`localhost\`:\`5444\` + 12 test('auto-connect', async () => { + 13 expect.assertions(1) + 14 try { + → 15 await prisma.user.findUnique( + Can't reach database server at \`localhost\`:\`5444\` -Please make sure your database server is running at \`localhost\`:\`5444\`. -`) + Please make sure your database server is running at \`localhost\`:\`5444\`. + `) } }) @@ -40,10 +40,10 @@ Please make sure your database server is running at \`localhost\`:\`5444\`. await prisma.$connect() } catch (err) { expect(err).toMatchInlineSnapshot(` - Can't reach database server at \`localhost\`:\`5444\` - - Please make sure your database server is running at \`localhost\`:\`5444\`. - `) + Can't reach database server at \`localhost\`:\`5444\` + + Please make sure your database server is running at \`localhost\`:\`5444\`. + `) } }) }) diff --git a/packages/client/src/__tests__/integration/errors/client-version-error/test.ts b/packages/client/src/__tests__/integration/errors/client-version-error/test.ts index 98e30122f4e5..0c297d711227 100644 --- a/packages/client/src/__tests__/integration/errors/client-version-error/test.ts +++ b/packages/client/src/__tests__/integration/errors/client-version-error/test.ts @@ -9,29 +9,29 @@ test('client-version-error', async () => { expect(e.clientVersion).toMatchInlineSnapshot(`client-test-version`) expect(e).toMatchInlineSnapshot(` -Invalid \`prisma.user.findMany()\` invocation in -/client/src/__tests__/integration/errors/client-version-error/test.ts:0:0 + Invalid \`prisma.user.findMany()\` invocation in + /client/src/__tests__/integration/errors/client-version-error/test.ts:0:0 - 4 const PrismaClient = await getTestClient() - 5 const prisma = new PrismaClient() - 6 try { -→ 7 await prisma.user.findMany({ - invalidArg: true - ~~~~~~~~~~ - }) + 4 const PrismaClient = await getTestClient() + 5 const prisma = new PrismaClient() + 6 try { + → 7 await prisma.user.findMany({ + invalidArg: true + ~~~~~~~~~~ + }) -Unknown arg \`invalidArg\` in invalidArg for type User. Did you mean \`where\`? Available args: -type findManyUser { - where?: UserWhereInput - orderBy?: List | UserOrderByWithRelationInput - cursor?: UserWhereUniqueInput - take?: Int - skip?: Int - distinct?: List -} + Unknown arg \`invalidArg\` in invalidArg for type User. Did you mean \`where\`? Available args: + type findManyUser { + where?: UserWhereInput + orderBy?: List | UserOrderByWithRelationInput + cursor?: UserWhereUniqueInput + take?: Int + skip?: Int + distinct?: List + } -`) + `) await prisma.$disconnect() } }) diff --git a/packages/client/src/__tests__/integration/errors/color-format/test.ts b/packages/client/src/__tests__/integration/errors/color-format/test.ts index 21eab8abb51e..fda2334bca7b 100644 --- a/packages/client/src/__tests__/integration/errors/color-format/test.ts +++ b/packages/client/src/__tests__/integration/errors/color-format/test.ts @@ -1,4 +1,5 @@ import stripAnsi from 'strip-ansi' + import { getTestClient } from '../../../../utils/getTestClient' test('client colorless errorFormat argument', async () => { diff --git a/packages/client/src/__tests__/integration/errors/corruption/test.ts b/packages/client/src/__tests__/integration/errors/corruption/test.ts index 3577b24c37fe..3be230327b3e 100644 --- a/packages/client/src/__tests__/integration/errors/corruption/test.ts +++ b/packages/client/src/__tests__/integration/errors/corruption/test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' test('corruption of query engine binary', async () => { diff --git a/packages/client/src/__tests__/integration/errors/error-link/test.ts b/packages/client/src/__tests__/integration/errors/error-link/test.ts index e4347c61aa83..9f2a61a3b1c5 100644 --- a/packages/client/src/__tests__/integration/errors/error-link/test.ts +++ b/packages/client/src/__tests__/integration/errors/error-link/test.ts @@ -1,4 +1,5 @@ import { ClientEngineType, getClientEngineType } from '@prisma/sdk' + import { getTestClient } from '../../../../utils/getTestClient' test('error-link', async () => { diff --git a/packages/client/src/__tests__/integration/errors/executeRaw-alter-postgres/test.ts b/packages/client/src/__tests__/integration/errors/executeRaw-alter-postgres/test.ts index d449d0fec32c..f0c47203ae6d 100644 --- a/packages/client/src/__tests__/integration/errors/executeRaw-alter-postgres/test.ts +++ b/packages/client/src/__tests__/integration/errors/executeRaw-alter-postgres/test.ts @@ -1,6 +1,7 @@ -import { getTestClient } from '../../../../utils/getTestClient' -import sql from 'sql-template-tag' import path from 'path' +import sql from 'sql-template-tag' + +import { getTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/errors/incorrect-column-type/test.ts b/packages/client/src/__tests__/integration/errors/incorrect-column-type/test.ts index 0bc9bf61ceb3..7666b06fb66c 100644 --- a/packages/client/src/__tests__/integration/errors/incorrect-column-type/test.ts +++ b/packages/client/src/__tests__/integration/errors/incorrect-column-type/test.ts @@ -21,7 +21,7 @@ test('incorrect-column-type', async () => { 13 }) 14 → 15 await expect(prisma.user.findMany()).rejects.toThrowErrorMatchingInlineSnapshot( - Attempted to serialize scalar '123' with incompatible type 'String' for field name. + Error converting field "name" of expected non-nullable type "String", found incompatible value of "123". `) await prisma.$disconnect() }) diff --git a/packages/client/src/__tests__/integration/errors/int-errors/__snapshots__/test.ts.snap b/packages/client/src/__tests__/integration/errors/int-errors/__snapshots__/test.ts.snap index bac8c1ab6089..45cee93da7d3 100644 --- a/packages/client/src/__tests__/integration/errors/int-errors/__snapshots__/test.ts.snap +++ b/packages/client/src/__tests__/integration/errors/int-errors/__snapshots__/test.ts.snap @@ -5,6 +5,26 @@ Argument age: Got invalid value 'thisisastringwith30characters' on prisma.update `; -exports[`int-errors overflow-int 1`] = `Value out of range for the type. Out of range value for column 'age' at row 1`; +exports[`int-errors overflow-int 1`] = ` -exports[`int-errors signed-int 1`] = `Value out of range for the type. Out of range value for column 'age' at row 1`; +Invalid \`prisma.user.update()\` invocation in +/client/src/__tests__/integration/errors/int-errors/test.ts:0:0 + + 54 + 55 test('overflow-int', async () => { + 56 try { +→ 57 await prisma.user.update( + Value out of range for the type. Out of range value for column 'age' at row 1 +`; + +exports[`int-errors signed-int 1`] = ` + +Invalid \`prisma.user.update()\` invocation in +/client/src/__tests__/integration/errors/int-errors/test.ts:0:0 + + 68 + 69 test('signed-int', async () => { + 70 try { +→ 71 await prisma.user.update( + Value out of range for the type. Out of range value for column 'age' at row 1 +`; diff --git a/packages/client/src/__tests__/integration/errors/invalid-input/test.ts b/packages/client/src/__tests__/integration/errors/invalid-input/test.ts index c2af58ab8f7d..e92c929ab05c 100644 --- a/packages/client/src/__tests__/integration/errors/invalid-input/test.ts +++ b/packages/client/src/__tests__/integration/errors/invalid-input/test.ts @@ -18,28 +18,28 @@ test('invalid-input', async () => { } catch (e) { expect(e).toMatchInlineSnapshot(` -Invalid \`prisma.user.create()\` invocation in -/client/src/__tests__/integration/errors/invalid-input/test.ts:0:0 - - 7 await prisma.user.deleteMany() - 8 - 9 try { -→ 10 await prisma.user.create({ - data: { - email: 'a@a.de', - posts: { - connect: { - id: [] - ~~ - } - } - } - }) - -Argument id: Got invalid value [] on prisma.createOneUser. Provided List<>, expected String. - - -`) + Invalid \`prisma.user.create()\` invocation in + /client/src/__tests__/integration/errors/invalid-input/test.ts:0:0 + + 7 await prisma.user.deleteMany() + 8 + 9 try { + → 10 await prisma.user.create({ + data: { + email: 'a@a.de', + posts: { + connect: { + id: [] + ~~ + } + } + } + }) + + Argument id: Got invalid value [] on prisma.createOneUser. Provided List<>, expected String. + + + `) } await prisma.$disconnect() diff --git a/packages/client/src/__tests__/integration/errors/invalid-url/test.ts b/packages/client/src/__tests__/integration/errors/invalid-url/test.ts index 4e2f371d610e..c737b4be8656 100644 --- a/packages/client/src/__tests__/integration/errors/invalid-url/test.ts +++ b/packages/client/src/__tests__/integration/errors/invalid-url/test.ts @@ -21,15 +21,15 @@ describe('invalid-url', () => { } catch (err) { expect(err).toMatchInlineSnapshot(` -Invalid \`prisma.user.findUnique()\` invocation in -/client/src/__tests__/integration/errors/invalid-url/test.ts:0:0 + Invalid \`prisma.user.findUnique()\` invocation in + /client/src/__tests__/integration/errors/invalid-url/test.ts:0:0 - 13 expect.assertions(1) - 14 - 15 try { -→ 16 await prisma.user.findUnique( - The provided database string is invalid. The provided arguments are not supported in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. -`) + 13 expect.assertions(1) + 14 + 15 try { + → 16 await prisma.user.findUnique( + The provided database string is invalid. The provided arguments are not supported in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + `) } }) diff --git a/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/binary.test.ts b/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/binary.test.ts index 1385361c7c8c..032f756465f8 100644 --- a/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/binary.test.ts +++ b/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/binary.test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' test('missing-engine-native-binaryTarget: binary', async () => { @@ -41,10 +42,10 @@ test('missing-engine-native-binaryTarget: binary', async () => { Invalid \`prisma.user.findMany()\` invocation in /client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/binary.test.ts:0:0 - 35 }) - 36 - 37 await expect(async () => { - → 38 await prisma.user.findMany( + 36 }) + 37 + 38 await expect(async () => { + → 39 await prisma.user.findMany( Query engine binary for current platform "TEST_PLATFORM" could not be found. This probably happens, because you built Prisma Client on a different platform. (Prisma Client looked in "/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/node_modules/@prisma/client/runtime/query-engine-TEST_PLATFORM") @@ -63,6 +64,6 @@ test('missing-engine-native-binaryTarget: binary', async () => { in the "schema.prisma" file as described in https://pris.ly/d/client-generator, but something went wrong. That's suboptimal. - Please create an issue at TEST_GITHUB_LINK + Please create an issue at https://github.com/prisma/prisma/issues/new `) }) diff --git a/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/library.test.ts b/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/library.test.ts index 38a3067adac9..527f5f451c18 100644 --- a/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/library.test.ts +++ b/packages/client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/library.test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' test('missing-engine-native-binaryTarget: library', async () => { @@ -36,10 +37,10 @@ test('missing-engine-native-binaryTarget: library', async () => { Invalid \`prisma.user.findMany()\` invocation in /client/src/__tests__/integration/errors/missing-engine-native-binaryTarget/library.test.ts:0:0 - 30 }) - 31 - 32 await expect(async () => { - → 33 await prisma.user.findMany( + 31 }) + 32 + 33 await expect(async () => { + → 34 await prisma.user.findMany( Query engine library for current platform "TEST_PLATFORM" could not be found. You incorrectly pinned it to TEST_PLATFORM @@ -60,6 +61,6 @@ test('missing-engine-native-binaryTarget: library', async () => { in the "schema.prisma" file as described in https://pris.ly/d/client-generator, but something went wrong. That's suboptimal. - Please create an issue at TEST_GITHUB_LINK + Please create an issue at https://github.com/prisma/prisma/issues/new `) }) diff --git a/packages/client/src/__tests__/integration/errors/missing-engine/binary.test.ts b/packages/client/src/__tests__/integration/errors/missing-engine/binary.test.ts index ce43037d4542..39cd9b102f96 100644 --- a/packages/client/src/__tests__/integration/errors/missing-engine/binary.test.ts +++ b/packages/client/src/__tests__/integration/errors/missing-engine/binary.test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' test('missing-engine: binary', async () => { @@ -41,10 +42,10 @@ test('missing-engine: binary', async () => { Invalid \`prisma.user.findMany()\` invocation in /client/src/__tests__/integration/errors/missing-engine/binary.test.ts:0:0 - 35 }) - 36 - 37 await expect(async () => { - → 38 await prisma.user.findMany( + 36 }) + 37 + 38 await expect(async () => { + → 39 await prisma.user.findMany( Query engine binary for current platform "TEST_PLATFORM" could not be found. This probably happens, because you built Prisma Client on a different platform. (Prisma Client looked in "/client/src/__tests__/integration/errors/missing-engine/node_modules/@prisma/client/runtime/query-engine-TEST_PLATFORM") diff --git a/packages/client/src/__tests__/integration/errors/missing-engine/library.test.ts b/packages/client/src/__tests__/integration/errors/missing-engine/library.test.ts index aa6fd3fae1bb..e65083c8647b 100644 --- a/packages/client/src/__tests__/integration/errors/missing-engine/library.test.ts +++ b/packages/client/src/__tests__/integration/errors/missing-engine/library.test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' test('missing-engine: library', async () => { @@ -36,10 +37,10 @@ test('missing-engine: library', async () => { Invalid \`prisma.user.findMany()\` invocation in /client/src/__tests__/integration/errors/missing-engine/library.test.ts:0:0 - 30 }) - 31 - 32 await expect(async () => { - → 33 await prisma.user.findMany( + 31 }) + 32 + 33 await expect(async () => { + → 34 await prisma.user.findMany( Query engine library for current platform "TEST_PLATFORM" could not be found. You incorrectly pinned it to TEST_PLATFORM diff --git a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-mysql/test.ts b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-mysql/test.ts index 5732f731a610..e866b1ceb83a 100644 --- a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-mysql/test.ts +++ b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-mysql/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' @@ -54,15 +55,15 @@ describe('referentialActions-onDelete-default-foreign-key-error(mysql)', () => { } catch (e) { expect(e.message).toMatchInlineSnapshot(` -Invalid \`prisma.user.delete()\` invocation in -/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-mysql/test.ts:0:0 + Invalid \`prisma.user.delete()\` invocation in + /client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-mysql/test.ts:0:0 - 46 expect(await prisma.post.findMany()).toHaveLength(1) - 47 - 48 try { -→ 49 await prisma.user.delete( - Foreign key constraint failed on the field: \`authorId\` -`) + 47 expect(await prisma.post.findMany()).toHaveLength(1) + 48 + 49 try { + → 50 await prisma.user.delete( + Foreign key constraint failed on the field: \`authorId\` + `) expect(await prisma.user.findMany()).toHaveLength(1) expect(await prisma.profile.findMany()).toHaveLength(1) expect(await prisma.post.findMany()).toHaveLength(1) diff --git a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-postgresql/test.ts b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-postgresql/test.ts index 56ad5acb511a..ee08dbea0310 100644 --- a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-postgresql/test.ts +++ b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-postgresql/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' @@ -52,15 +53,15 @@ describe('referentialActions-onDelete-default-foreign-key-error(postgresql)', () } catch (e) { expect(e.message).toMatchInlineSnapshot(` -Invalid \`prisma.user.delete()\` invocation in -/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-postgresql/test.ts:0:0 + Invalid \`prisma.user.delete()\` invocation in + /client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-postgresql/test.ts:0:0 - 44 expect(await prisma.user.findMany()).toHaveLength(1) - 45 - 46 try { -→ 47 await prisma.user.delete( - Foreign key constraint failed on the field: \`Post_authorId_fkey (index)\` -`) + 45 expect(await prisma.user.findMany()).toHaveLength(1) + 46 + 47 try { + → 48 await prisma.user.delete( + Foreign key constraint failed on the field: \`Post_authorId_fkey (index)\` + `) } }) }) diff --git a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlite/test.ts b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlite/test.ts index 7bfafdcc2b1a..a898e3123d34 100644 --- a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlite/test.ts +++ b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlite/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { migrateDb } from '../../__helpers__/migrateDb' @@ -46,15 +47,15 @@ describe('referentialActions-onDelete-default-foreign-key-error(sqlite)', () => } catch (e) { expect(e.message).toMatchInlineSnapshot(` -Invalid \`prisma.user.delete()\` invocation in -/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlite/test.ts:0:0 + Invalid \`prisma.user.delete()\` invocation in + /client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlite/test.ts:0:0 - 38 expect(await prisma.user.findMany()).toHaveLength(1) - 39 - 40 try { -→ 41 await prisma.user.delete( - Foreign key constraint failed on the field: \`foreign key\` -`) + 39 expect(await prisma.user.findMany()).toHaveLength(1) + 40 + 41 try { + → 42 await prisma.user.delete( + Foreign key constraint failed on the field: \`foreign key\` + `) } }) }) diff --git a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlserver/test.ts b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlserver/test.ts index 81a7ee0ecf19..905507dd6737 100644 --- a/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlserver/test.ts +++ b/packages/client/src/__tests__/integration/errors/referentialActions-onDelete-default-foreign-key-error-sqlserver/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/errors/source-map-support/test.ts b/packages/client/src/__tests__/integration/errors/source-map-support/test.ts index e9e4d7f7e5b3..7ce956643ac5 100644 --- a/packages/client/src/__tests__/integration/errors/source-map-support/test.ts +++ b/packages/client/src/__tests__/integration/errors/source-map-support/test.ts @@ -1,4 +1,5 @@ import 'source-map-support/register' + import { getTestClient } from '../../../../utils/getTestClient' /* eslint-disable */ diff --git a/packages/client/src/__tests__/integration/errors/uncheckedScalarValidation/test.ts b/packages/client/src/__tests__/integration/errors/uncheckedScalarValidation/test.ts index eb88a73c0a1c..d3993267f0cd 100644 --- a/packages/client/src/__tests__/integration/errors/uncheckedScalarValidation/test.ts +++ b/packages/client/src/__tests__/integration/errors/uncheckedScalarValidation/test.ts @@ -36,60 +36,60 @@ test('uncheckedScalarInputs validation', async () => { } catch (e) { expect(e).toMatchInlineSnapshot(` -Invalid \`prisma.trip.create()\` invocation in -/client/src/__tests__/integration/errors/uncheckedScalarValidation/test.ts:0:0 + Invalid \`prisma.trip.create()\` invocation in + /client/src/__tests__/integration/errors/uncheckedScalarValidation/test.ts:0:0 - 6 const prisma = new PrismaClient() - 7 - 8 try { -→ 9 await prisma.trip.create({ - data: { - name: 'Trip 1', - description: 'This is a description', - public: false, - dateFrom: new Date('2020-12-29T10:15:16.495Z'), - dateTo: new Date('2020-12-29T10:15:16.495Z'), - adults: 12, - backgroundUrl: 'https://duckduckgo.com', - userId: 1, - activities: { - create: [ - { - name: 'Activity1', - description: 'This is activity 1', - location: 'Some location', - date: new Date('2020-12-29T10:15:16.495Z'), + 6 const prisma = new PrismaClient() + 7 + 8 try { + → 9 await prisma.trip.create({ + data: { + name: 'Trip 1', + description: 'This is a description', public: false, - timezone: 'Europe/Berlin', - maxPeople: 1, - activityTypeId: 1, - tripId: 1 - ~~~~~~ + dateFrom: new Date('2020-12-29T10:15:16.495Z'), + dateTo: new Date('2020-12-29T10:15:16.495Z'), + adults: 12, + backgroundUrl: 'https://duckduckgo.com', + userId: 1, + activities: { + create: [ + { + name: 'Activity1', + description: 'This is activity 1', + location: 'Some location', + date: new Date('2020-12-29T10:15:16.495Z'), + public: false, + timezone: 'Europe/Berlin', + maxPeople: 1, + activityTypeId: 1, + tripId: 1 + ~~~~~~ + } + ] + } } - ] - } - } - }) + }) -Unknown arg \`tripId\` in data.activities.create.0.tripId for type ActivityUncheckedCreateWithoutTripInput. Did you mean \`id\`? Available args: -type ActivityUncheckedCreateWithoutTripInput { - id?: Int - uuid?: String - activityTypeId: Int - name: String - description?: String | Null - location: String - date: DateTime - timezone: String - public: Boolean - maxPeople?: Int | Null - createdAt?: DateTime - updatedAt?: DateTime - users?: UsersToActivitiesUncheckedCreateNestedManyWithoutActivityInput -} + Unknown arg \`tripId\` in data.activities.create.0.tripId for type ActivityUncheckedCreateWithoutTripInput. Did you mean \`id\`? Available args: + type ActivityUncheckedCreateWithoutTripInput { + id?: Int + uuid?: String + activityTypeId: Int + name: String + description?: String | Null + location: String + date: DateTime + timezone: String + public: Boolean + maxPeople?: Int | Null + createdAt?: DateTime + updatedAt?: DateTime + users?: UsersToActivitiesUncheckedCreateNestedManyWithoutActivityInput + } -`) + `) } await prisma.$disconnect() diff --git a/packages/client/src/__tests__/integration/errors/union-validation/test.ts b/packages/client/src/__tests__/integration/errors/union-validation/test.ts index a7445ecd647f..4fd94b9668d7 100644 --- a/packages/client/src/__tests__/integration/errors/union-validation/test.ts +++ b/packages/client/src/__tests__/integration/errors/union-validation/test.ts @@ -23,38 +23,38 @@ test('union validation', async () => { } catch (e) { expect(e).toMatchInlineSnapshot(` -Invalid \`prisma.organization.create()\` invocation in -/client/src/__tests__/integration/errors/union-validation/test.ts:0:0 - - 6 const prisma = new PrismaClient() - 7 - 8 try { -→ 9 await prisma.organization.create({ - data: { - fullName: 'name', - accounts: { - create: { - operator: { - create: { - prefix: 'prefix', - + organization: { - + create?: OrganizationCreateWithoutOperatorInput | OrganizationUncheckedCreateWithoutOperatorInput, - + connectOrCreate?: OrganizationCreateOrConnectWithoutOperatorInput, - + connect?: OrganizationWhereUniqueInput - + }, - ? id?: String + Invalid \`prisma.organization.create()\` invocation in + /client/src/__tests__/integration/errors/union-validation/test.ts:0:0 + + 6 const prisma = new PrismaClient() + 7 + 8 try { + → 9 await prisma.organization.create({ + data: { + fullName: 'name', + accounts: { + create: { + operator: { + create: { + prefix: 'prefix', + + organization: { + + create?: OrganizationCreateWithoutOperatorInput | OrganizationUncheckedCreateWithoutOperatorInput, + + connectOrCreate?: OrganizationCreateOrConnectWithoutOperatorInput, + + connect?: OrganizationWhereUniqueInput + + }, + ? id?: String + } + } + } } } - } - } - } - }) + }) -Argument organization for data.accounts.create.operator.create.organization is missing. + Argument organization for data.accounts.create.operator.create.organization is missing. -Note: Lines with + are required, lines with ? are optional. + Note: Lines with + are required, lines with ? are optional. -`) + `) } await prisma.$disconnect() diff --git a/packages/client/src/__tests__/integration/errors/wrong-native-types-mysql/test.ts b/packages/client/src/__tests__/integration/errors/wrong-native-types-mysql/test.ts index 8f02a7a4908b..319e7579a10c 100644 --- a/packages/client/src/__tests__/integration/errors/wrong-native-types-mysql/test.ts +++ b/packages/client/src/__tests__/integration/errors/wrong-native-types-mysql/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' @@ -110,9 +111,17 @@ test('wrong-native-types-mysql C: Char, VarChar, TinyText, Text, MediumText, Lon lText: true, }, }), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `The provided value for the column is too long for the column's type. Column: char`, - ) + ).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.c.create()\` invocation in + /client/src/__tests__/integration/errors/wrong-native-types-mysql/test.ts:0:0 + + 100 } + 101 + 102 await expect(async () => + → 103 prisma.c.create( + The provided value for the column is too long for the column's type. Column: char + `) await prisma.$disconnect() }) diff --git a/packages/client/src/__tests__/integration/errors/wrong-native-types-postgres/test.ts b/packages/client/src/__tests__/integration/errors/wrong-native-types-postgres/test.ts index 9b2d36d2c34d..5144f02be915 100644 --- a/packages/client/src/__tests__/integration/errors/wrong-native-types-postgres/test.ts +++ b/packages/client/src/__tests__/integration/errors/wrong-native-types-postgres/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' @@ -114,7 +115,15 @@ test('wrong-native-types-postgres C: Char, VarChar, Text, Bit, VarBit, Uuid', as }, }), ).rejects.toThrowErrorMatchingInlineSnapshot(` - Error occurred during query execution: + + Invalid \`prisma.c.create()\` invocation in + /client/src/__tests__/integration/errors/wrong-native-types-postgres/test.ts:0:0 + + 103 } + 104 + 105 await expect(async () => + → 106 prisma.c.create( + Error occurred during query execution: ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: ToSql(4), cause: Some(Error { kind: ConversionError("Unexpected character for bits input. Expected only 1 and 0."), original_code: None, original_message: None }) }) }) `) diff --git a/packages/client/src/__tests__/integration/happy/aggregations/test.ts b/packages/client/src/__tests__/integration/happy/aggregations/test.ts index cfca9215fbbd..60aea6c59cde 100644 --- a/packages/client/src/__tests__/integration/happy/aggregations/test.ts +++ b/packages/client/src/__tests__/integration/happy/aggregations/test.ts @@ -1,4 +1,5 @@ import { getTestClient } from '../../../../utils/getTestClient' + describe('aggregations', () => { test('general', async () => { const PrismaClient = await getTestClient() @@ -116,27 +117,27 @@ describe('aggregations', () => { } catch (err) { expect(err.message).toMatchInlineSnapshot(` - Invalid \`prisma.user.aggregate()\` invocation: + Invalid \`prisma.user.aggregate()\` invocation: - { - where: { - age: { - gt: -1 - } - }, - skip: 0, - take: 10000, - _avg: { - ? age?: true, - email: true - ~~~~~ - } - } + { + _avg: { + ? age?: true, + email: true + ~~~~~ + }, + where: { + age: { + gt: -1 + } + }, + skip: 0, + take: 10000 + } - Unknown field \`email\` for select statement on model UserAvgAggregateOutputType. Available options are listed in green. Did you mean \`age\`? + Unknown field \`email\` for select statement on model UserAvgAggregateOutputType. Available options are listed in green. Did you mean \`age\`? - `) + `) } await prisma.$disconnect() diff --git a/packages/client/src/__tests__/integration/happy/async-hooks/test.ts b/packages/client/src/__tests__/integration/happy/async-hooks/test.ts index 4a98acfe6544..11be8033d504 100644 --- a/packages/client/src/__tests__/integration/happy/async-hooks/test.ts +++ b/packages/client/src/__tests__/integration/happy/async-hooks/test.ts @@ -1,4 +1,5 @@ import { executionAsyncId } from 'async_hooks' + import { getTestClient } from '../../../../utils/getTestClient' test('async-hooks', async () => { diff --git a/packages/client/src/__tests__/integration/happy/atomic-operations/test.ts b/packages/client/src/__tests__/integration/happy/atomic-operations/test.ts index af2617013b76..7a732a58ca36 100644 --- a/packages/client/src/__tests__/integration/happy/atomic-operations/test.ts +++ b/packages/client/src/__tests__/integration/happy/atomic-operations/test.ts @@ -1,7 +1,9 @@ import fs from 'fs' import path from 'path' import { promisify } from 'util' + import { getTestClient } from '../../../../utils/getTestClient' + const copyFile = promisify(fs.copyFile) test('atomic-operations', async () => { diff --git a/packages/client/src/__tests__/integration/happy/binary/test.ts b/packages/client/src/__tests__/integration/happy/binary/test.ts index 4c496d46b53e..c227cf31a27a 100644 --- a/packages/client/src/__tests__/integration/happy/binary/test.ts +++ b/packages/client/src/__tests__/integration/happy/binary/test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' test('binary', async () => { diff --git a/packages/client/src/__tests__/integration/happy/blog-dot-env-root/test.ts b/packages/client/src/__tests__/integration/happy/blog-dot-env-root/test.ts index de58cf3ff549..5970e2364d7e 100644 --- a/packages/client/src/__tests__/integration/happy/blog-dot-env-root/test.ts +++ b/packages/client/src/__tests__/integration/happy/blog-dot-env-root/test.ts @@ -1,4 +1,5 @@ import { generateTestClient } from '../../../../utils/getTestClient' + test('blog-dot-env-root', async () => { await generateTestClient() diff --git a/packages/client/src/__tests__/integration/happy/blog-env-cockroachdb/test.ts b/packages/client/src/__tests__/integration/happy/blog-env-cockroachdb/test.ts index 04d4d50585ef..7b7024fb1faa 100644 --- a/packages/client/src/__tests__/integration/happy/blog-env-cockroachdb/test.ts +++ b/packages/client/src/__tests__/integration/happy/blog-env-cockroachdb/test.ts @@ -1,4 +1,5 @@ import sql from 'sql-template-tag' + import { generateTestClient } from '../../../../utils/getTestClient' import type { SetupParams } from '../../../../utils/setupPostgres' import { setupPostgres, tearDownPostgres } from '../../../../utils/setupPostgres' diff --git a/packages/client/src/__tests__/integration/happy/blog-env-mongo/schema.prisma b/packages/client/src/__tests__/integration/happy/blog-env-mongo/schema.prisma new file mode 100644 index 000000000000..5d5c296052f3 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/blog-env-mongo/schema.prisma @@ -0,0 +1,35 @@ +datasource db { + provider = "mongodb" + url = env("TEST_MONGO_URI") +} + +generator client { + provider = "prisma-client-js" + previewFeatures = ["mongodb"] +} + +model User { + id String @id @default(auto()) @map("_id") @db.ObjectId + email String @unique + name String? + posts Post[] +} + +model Post { + id String @id @default(auto()) @map("_id") @db.ObjectId + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + published Boolean + title String + content String? + authorId String? + author User? @relation(fields: [authorId], references: [id]) + jsonData Json? + coinflips Boolean[] + ids String[] @db.ObjectId +} + +enum Role { + USER + ADMIN +} diff --git a/packages/client/src/__tests__/integration/happy/blog-env-mongo/test.ts b/packages/client/src/__tests__/integration/happy/blog-env-mongo/test.ts new file mode 100644 index 000000000000..774ae339ac01 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/blog-env-mongo/test.ts @@ -0,0 +1,343 @@ +import { generateTestClient } from '../../../../utils/getTestClient' +// @ts-ignore +import type { PrismaClient } from './node_modules/@prisma/client' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +describeIf(!process.env.TEST_SKIP_MONGODB)('blog-env-mongo', () => { + let prisma: PrismaClient // Generated Client instance + const requests: any[] = [] + + beforeAll(async () => { + await generateTestClient() + const { PrismaClient } = require('./node_modules/@prisma/client') + + prisma = new PrismaClient({ + errorFormat: 'colorless', + __internal: { + measurePerformance: true, + hooks: { + beforeRequest: (r: any) => requests.push(r), + }, + }, + log: [ + { + emit: 'event', + level: 'error', + }, + ], + }) + }) + + afterEach(async () => { + for (const key of Object.keys(prisma)) { + await prisma[key]?.['deleteMany']?.() + } + await prisma.$disconnect() + }) + + test('includes version in generated client', () => { + const { Prisma } = require('./node_modules/@prisma/client') + + const { prismaVersion } = Prisma + + expect(prismaVersion).not.toBeUndefined() + expect(prismaVersion.client).not.toBeUndefined() + }) + + test('does not leak connection strings in node_modules', () => { + // @ts-ignore + expect(prisma.internalDatasources).toBeUndefined() + }) + + test('invokes beforeRequest hook', async () => { + await prisma.user.findMany() + expect(requests.length).toBeGreaterThan(0) + }) + + test('can throw validation errors', async () => { + expect.assertions(2) + + const { + Prisma: { PrismaClientValidationError }, + } = require('./node_modules/@prisma/client') + + try { + await prisma.post.create({ + // @ts-ignore + data: {}, + }) + } catch (e) { + expect(e).not.toBeUndefined() + expect(e).toBeInstanceOf(PrismaClientValidationError) + } + }) + + test('can run findMany queries', async () => { + await prisma.post.create({ + data: { + published: false, + title: 'title', + content: 'content', + }, + }) + const posts = await prisma.post.findMany() + expect(posts).not.toHaveLength(0) + }) + + test('can run findMany queries with a `null` where', async () => { + await prisma.post.create({ + data: { + published: false, + title: 'null where', + content: null, + }, + }) + const posts = await prisma.post.findMany({ + where: { + content: null, + }, + }) + expect(posts.length).not.toBe(0) + }) + + test('can run create queries', async () => { + const post = await prisma.post.create({ + data: { + published: false, + title: 'Some title', + ids: ['620e79238fb8973a4a738664', '620e792a4927392287834903'], + }, + }) + + expect(post).not.toBeUndefined() + expect(post.ids).toHaveLength(2) + }) + + test('can run delete queries', async () => { + const post = await prisma.post.create({ + data: { + published: false, + title: 'Some title', + }, + }) + const deletedPost = await prisma.post.delete({ + where: { id: post.id }, + select: { + authorId: true, + content: true, + published: true, + title: true, + }, + }) + + expect(deletedPost).toMatchInlineSnapshot(` + Object { + authorId: null, + content: null, + published: false, + title: Some title, + } + `) + }) + + test('can run update queries', async () => { + const post = await prisma.post.create({ + data: { + published: false, + title: 'Some title', + }, + }) + const updatedPost = await prisma.post.update({ + where: { + id: post.id, + }, + data: { + title: 'Updated title', + ids: ['620e79866f46aba24d751441'], + }, + select: { + authorId: true, + content: true, + published: true, + title: true, + ids: true, + }, + }) + + expect(updatedPost).toMatchInlineSnapshot(` + Object { + authorId: null, + content: null, + ids: Array [ + 620e79866f46aba24d751441, + ], + published: false, + title: Updated title, + } + `) + }) + + test('should throw Malformed ObjectID error: in 2 different fields', async () => { + const post = prisma.post.create({ + data: { + id: 'something invalid 1111', // first + published: false, + title: 'Some title', + ids: ['something invalid 2222'], // second + }, + }) + + // Message doesn't distinguish if one or more values failed / which one failed + // seems it errors on the first one + // https://github.com/prisma/prisma/issues/11885 + await expect(post).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.post.create()\` invocation in + /client/src/__tests__/integration/happy/blog-env-mongo/test.ts:0:0 + + 179 }) + 180 + 181 test('should throw Malformed ObjectID error: in 2 different fields', async () => { + → 182 const post = prisma.post.create( + Inconsistent column data: Malformed ObjectID: invalid character 's' was found at index 0 in the provided hex string: "something invalid 1111". + `) + }) + + test('should throw Malformed ObjectID error for: _id', async () => { + const post = prisma.post.create({ + data: { + published: false, + title: 'Some title', + ids: ['something invalid'], + }, + }) + + await expect(post).rejects.toThrowError( + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + expect.objectContaining({ + message: expect.stringContaining('Malformed ObjectID'), + }), + ) + }) + + test('should throw Malformed ObjectID error for: ids String[] @db.ObjectId', async () => { + const post = prisma.post.create({ + data: { + id: 'something invalid', + published: false, + title: 'Some title', + }, + }) + + await expect(post).rejects.toThrowError( + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + expect.objectContaining({ + message: expect.stringContaining('Malformed ObjectID'), + }), + ) + }) + + describe('findRaw', () => { + test('all', async () => { + await prisma.user.create({ data: { email: 'c@a.de', name: 'C' } }) + const users = await prisma.user.findRaw({}) + expect(users).not.toHaveLength(0) + }) + + test('single', async () => { + await prisma.user.create({ data: { email: 'd@a.de', name: 'D' } }) + const users = await prisma.user.findRaw({ filter: { name: 'D' } }) + expect(users).toHaveLength(1) + }) + + test('projection', async () => { + await prisma.user.create({ data: { email: 'e@a.de', name: 'E' } }) + const users = await prisma.user.findRaw({ + filter: { name: 'E' }, + options: { projection: { _id: false } }, + }) + expect(users).toMatchInlineSnapshot(` + Array [ + Object { + email: e@a.de, + name: E, + }, + ] + `) + }) + }) + + describe('aggregateRaw', () => { + test('group', async () => { + await prisma.user.create({ data: { email: '1@a.de', name: 'A' } }) + await prisma.user.create({ data: { email: '2@a.de', name: 'A' } }) + await prisma.user.create({ data: { email: '3@a.de', name: 'B' } }) + await prisma.user.create({ data: { email: '4@a.de', name: 'B' } }) + const users = await prisma.user.aggregateRaw({ + pipeline: [{ $group: { _id: '$name', total: { $sum: 1 } } }, { $sort: { _id: -1 } }], + }) + expect(users).toMatchInlineSnapshot(` + Array [ + Object { + _id: B, + total: 2, + }, + Object { + _id: A, + total: 2, + }, + ] + `) + }) + + test('match', async () => { + await prisma.user.create({ data: { email: '1@a.de', name: 'A' } }) + await prisma.user.create({ data: { email: '3@a.de', name: 'A' } }) + const users = await prisma.user.aggregateRaw({ + pipeline: [{ $match: { name: 'A' } }, { $project: { email: true, _id: false } }], + }) + expect(users).toMatchInlineSnapshot(` + Array [ + Object { + email: 1@a.de, + }, + Object { + email: 3@a.de, + }, + ] + `) + }) + }) + + describe('runCommandRaw', () => { + test('aggregate', async () => { + await prisma.user.create({ data: { email: '1@a.de', name: 'A' } }) + await prisma.user.create({ data: { email: '3@a.de', name: 'A' } }) + + const users = await prisma.$runCommandRaw({ + aggregate: 'User', + pipeline: [{ $match: { name: 'A' } }, { $project: { email: true, _id: false } }], + explain: false, + }) + + expect(users).toMatchInlineSnapshot(` + Object { + cursor: Object { + firstBatch: Array [ + Object { + email: 1@a.de, + }, + Object { + email: 3@a.de, + }, + ], + id: 0, + ns: tests.User, + }, + ok: 1, + } + `) + }) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/blog-env-mssql/test.ts b/packages/client/src/__tests__/integration/happy/blog-env-mssql/test.ts index 736eae3ab4d2..d3d693cecbef 100644 --- a/packages/client/src/__tests__/integration/happy/blog-env-mssql/test.ts +++ b/packages/client/src/__tests__/integration/happy/blog-env-mssql/test.ts @@ -1,4 +1,5 @@ import sql from 'sql-template-tag' + import { generateTestClient } from '../../../../utils/getTestClient' import type { SetupParams } from '../../../../utils/setupMSSQL' import { setupMSSQL } from '../../../../utils/setupMSSQL' diff --git a/packages/client/src/__tests__/integration/happy/blog-update/dev.db b/packages/client/src/__tests__/integration/happy/blog-update/dev.db index 496dd27096cd..cb4f1df5f0fa 100644 Binary files a/packages/client/src/__tests__/integration/happy/blog-update/dev.db and b/packages/client/src/__tests__/integration/happy/blog-update/dev.db differ diff --git a/packages/client/src/__tests__/integration/happy/blog-update/schema.prisma b/packages/client/src/__tests__/integration/happy/blog-update/schema.prisma index cf20338a6ab8..d6e35a5976df 100644 --- a/packages/client/src/__tests__/integration/happy/blog-update/schema.prisma +++ b/packages/client/src/__tests__/integration/happy/blog-update/schema.prisma @@ -9,7 +9,7 @@ generator client { // / User model comment model User { - id String @default(uuid()) @id + id String @id @default(uuid()) email String @unique // / name comment name String? @@ -20,7 +20,7 @@ model User { } model Profile { - id String @default(cuid()) @id + id String @id @default(cuid()) bio String? notrequired String? user User @relation(fields: [userId], references: [id]) @@ -30,13 +30,13 @@ model Profile { } model Post { - id String @default(cuid()) @id + id String @id @default(cuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt published Boolean title String content String? - optionnal String? + optional String? authorId String? @map("author") author User? @relation(fields: [authorId], references: [id]) lastReviewedAt DateTime? @default(now()) diff --git a/packages/client/src/__tests__/integration/happy/blog-update/test.ts b/packages/client/src/__tests__/integration/happy/blog-update/test.ts index 89f6a501672c..7e856b7afc06 100644 --- a/packages/client/src/__tests__/integration/happy/blog-update/test.ts +++ b/packages/client/src/__tests__/integration/happy/blog-update/test.ts @@ -1,7 +1,9 @@ import fs from 'fs' import path from 'path' import { promisify } from 'util' + import { getTestClient } from '../../../../utils/getTestClient' + const copyFile = promisify(fs.copyFile) test('blog-update', async () => { @@ -27,7 +29,7 @@ test('blog-update', async () => { published: true, title: 'mytitle', content: 'somecontent', - optionnal: 'optionnal', + optional: 'optional', lastReviewedAt: someDate, lastPublishedAt: someDate, })), @@ -70,7 +72,7 @@ test('blog-update', async () => { content: true, title: true, published: true, - optionnal: true, + optional: true, }, }, }, @@ -96,7 +98,7 @@ test('blog-update', async () => { updateMany: { data: { content: null, - optionnal: { + optional: { set: null, }, lastReviewedAt: null, @@ -118,31 +120,31 @@ test('blog-update', async () => { posts: Array [ Object { content: null, - optionnal: null, + optional: null, published: true, title: mytitle, }, Object { content: null, - optionnal: null, + optional: null, published: true, title: mytitle, }, Object { content: null, - optionnal: null, + optional: null, published: true, title: mytitle, }, Object { content: null, - optionnal: null, + optional: null, published: true, title: mytitle, }, Object { content: null, - optionnal: null, + optional: null, published: true, title: mytitle, }, diff --git a/packages/client/src/__tests__/integration/happy/chaining/dev.db b/packages/client/src/__tests__/integration/happy/chaining/dev.db index 50405f887ef6..09b6082e5a81 100644 Binary files a/packages/client/src/__tests__/integration/happy/chaining/dev.db and b/packages/client/src/__tests__/integration/happy/chaining/dev.db differ diff --git a/packages/client/src/__tests__/integration/happy/chaining/schema.prisma b/packages/client/src/__tests__/integration/happy/chaining/schema.prisma index 6d722cf03bd9..469fcd2b3a6a 100644 --- a/packages/client/src/__tests__/integration/happy/chaining/schema.prisma +++ b/packages/client/src/__tests__/integration/happy/chaining/schema.prisma @@ -15,8 +15,9 @@ model User { age Int? posts Post[] likes Like[] - property Property @relation(fields: [propertyId], references: [id]) - propertyId String + property Property? @relation(fields: [propertyId], references: [id]) + propertyId String? + Banking Banking? } model Property { @@ -55,3 +56,11 @@ model Like { House House[] @@unique([userId, postId]) } + +model Banking { + id String @id @default(cuid()) + userId String + user User? @relation(fields: [userId], references: [id]) + iban String + bic String +} \ No newline at end of file diff --git a/packages/client/src/__tests__/integration/happy/chaining/test.ts b/packages/client/src/__tests__/integration/happy/chaining/test.ts index 1512af69209a..61565be71073 100644 --- a/packages/client/src/__tests__/integration/happy/chaining/test.ts +++ b/packages/client/src/__tests__/integration/happy/chaining/test.ts @@ -1,95 +1,207 @@ import { getTestClient } from '../../../../utils/getTestClient' -test('chaining', async () => { - const PrismaClient = await getTestClient() - const prisma = new PrismaClient() - - const a: any[] = [] - a.push( - await prisma.user - .findUnique({ +let prisma +describe('chaining', () => { + test('lower-cased relations', async () => { + const a: any[] = [] + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .property(), + ) + + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .property() + .house(), + ) + + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .property() + .house() + .like(), + ) + + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .property() + .house() + .like() + .post(), + ) + + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .property() + .house() + .like() + .post() + .author(), + ) + + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .property() + .house() + .like() + .post() + .author() + .property(), + ) + + expect(a).toMatchInlineSnapshot(` + Array [ + null, + null, + null, + null, + null, + null, + ] + `) + }) + + test('upper-cased relations', async () => { + const a: any[] = [] + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .Banking(), + ) + + a.push( + await prisma.user + .findUnique({ + where: { + email: 'a@a.de', + }, + }) + .Banking() + .user(), + ) + + expect(a).toMatchInlineSnapshot(` + Array [ + null, + null, + ] + `) + }) + + test('findFirst', async () => { + const posts = await prisma.user + .findFirst({ where: { - email: 'a@a.de', + email: 'email@email.io', }, }) - .property(), - ) + .posts() - a.push( - await prisma.user - .findUnique({ - where: { - email: 'a@a.de', + expect(posts).toMatchInlineSnapshot(`Array []`) + }) + + test('create', async () => { + const posts = await prisma.user + .create({ + data: { + email: 'email2@email.io', }, }) - .property() - .house(), - ) + .posts() - a.push( - await prisma.user - .findUnique({ + expect(posts).toMatchInlineSnapshot(`Array []`) + }) + + test('update', async () => { + const posts = await prisma.user + .update({ where: { - email: 'a@a.de', + email: 'email@email.io', }, + data: {}, }) - .property() - .house() - .like(), - ) - - a.push( - await prisma.user - .findUnique({ + .posts() + + expect(posts).toMatchInlineSnapshot(`Array []`) + }) + + test('upsert', async () => { + const posts = await prisma.user + .upsert({ where: { - email: 'a@a.de', + email: 'email@email.io', }, - }) - .property() - .house() - .like() - .post(), - ) - - a.push( - await prisma.user - .findUnique({ - where: { - email: 'a@a.de', + create: { + email: 'email@email.io', }, + update: {}, }) - .property() - .house() - .like() - .post() - .author(), - ) - - a.push( - await prisma.user - .findUnique({ + .posts() + + expect(posts).toMatchInlineSnapshot(`Array []`) + }) + + test('delete', async () => { + const posts = await prisma.user + .delete({ where: { - email: 'a@a.de', + email: 'email@email.io', }, }) - .property() - .house() - .like() - .post() - .author() - .property(), - ) - - await prisma.$disconnect() - - expect(a).toMatchInlineSnapshot(` - Array [ - null, - null, - null, - null, - null, - null, - ] - `) + .posts() + + expect(posts).toMatchInlineSnapshot(`Array []`) + }) + + beforeAll(async () => { + const PrismaClient = await getTestClient() + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.user.deleteMany() + const user = await prisma.user.create({ + data: { + email: 'email@email.io', + }, + }) + }) + + afterAll(async () => { + await prisma.$disconnect() + }) }) diff --git a/packages/client/src/__tests__/integration/happy/chmod/test.ts b/packages/client/src/__tests__/integration/happy/chmod/test.ts index cf3939d9c732..6d0c22a268c7 100644 --- a/packages/client/src/__tests__/integration/happy/chmod/test.ts +++ b/packages/client/src/__tests__/integration/happy/chmod/test.ts @@ -2,6 +2,7 @@ import { getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' const testIf = (condition: boolean) => (condition ? test : test.skip) diff --git a/packages/client/src/__tests__/integration/happy/client-engine/test.ts b/packages/client/src/__tests__/integration/happy/client-engine/test.ts index e9343e027ab3..2feab49eaeac 100644 --- a/packages/client/src/__tests__/integration/happy/client-engine/test.ts +++ b/packages/client/src/__tests__/integration/happy/client-engine/test.ts @@ -1,7 +1,8 @@ +import { ClientEngineType, DEFAULT_CLIENT_ENGINE_TYPE } from '@prisma/sdk' import fs from 'fs' import os from 'os' import path from 'path' -import { ClientEngineType, DEFAULT_CLIENT_ENGINE_TYPE } from '@prisma/sdk' + import { generateTestClient } from '../../../../utils/getTestClient' const buildSchema = (engineType?: string) => ` diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentOptionalPropDataA.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentOptionalPropDataA.ts new file mode 100644 index 000000000000..341bff9bda78 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentOptionalPropDataA.ts @@ -0,0 +1,15 @@ +export function commentOptionalPropDataA(id: string) { + return { + id: id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + } +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentOptionalPropDataB.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentOptionalPropDataB.ts new file mode 100644 index 000000000000..505b36f4d00e --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentOptionalPropDataB.ts @@ -0,0 +1,19 @@ +export function commentOptionalPropDataB(id: string) { + return { + id: id, + country: 'France', + content: { + text: 'Goodbye World', + upvotes: [ + { + vote: false, + userId: '11', + }, + { + vote: true, + userId: '12', + }, + ], + }, + } +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredListDataA.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredListDataA.ts new file mode 100644 index 000000000000..ad632baa3a50 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredListDataA.ts @@ -0,0 +1,15 @@ +export function commentRequiredListDataA(id: string) { + return { + id: id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + } +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredListDataB.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredListDataB.ts new file mode 100644 index 000000000000..d77047d8c2aa --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredListDataB.ts @@ -0,0 +1,28 @@ +export function commentRequiredListDataB(id: string) { + return { + id: id, + country: 'France', + contents: { + set: [ + { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '11', + }, + }, + { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + { + text: 'Hello World', + upvotes: [], + }, + ], + }, + } +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredPropDataA.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredPropDataA.ts new file mode 100644 index 000000000000..9828af027909 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredPropDataA.ts @@ -0,0 +1,15 @@ +export function commentRequiredPropDataA(id: string) { + return { + id: id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + } +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredPropDataB.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredPropDataB.ts new file mode 100644 index 000000000000..b72df58009e0 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/__helpers__/build-data/commentRequiredPropDataB.ts @@ -0,0 +1,19 @@ +export function commentRequiredPropDataB(id: string) { + return { + id: id, + country: 'France', + content: { + text: 'Goodbye World', + upvotes: [ + { + vote: false, + userId: '11', + }, + { + vote: true, + userId: '12', + }, + ], + }, + } +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/list.ts new file mode 100644 index 000000000000..b063386b2dda --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/list.ts @@ -0,0 +1,61 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '6ccccccccccccccccccccccc' + +/** + * Test aggregate operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('aggregate > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple aggregate + */ + test('simple', async () => { + const comment = await prisma.commentRequiredList.aggregate({ + where: { id }, + orderBy: { + contents: { + _count: 'asc', + }, + }, + _count: true, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + _count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/optional.ts new file mode 100644 index 000000000000..ba8ae6640a8f --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/optional.ts @@ -0,0 +1,63 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '4ccccccccccccccccccccccc' + +/** + * Test aggregate operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('aggregate > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple aggregate + */ + test('aggregate', async () => { + const comment = await prisma.commentOptionalProp.aggregate({ + where: { id }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + _count: true, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + _count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/required.ts new file mode 100644 index 000000000000..57b3eed9e0fd --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/aggregate/required.ts @@ -0,0 +1,63 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '5ccccccccccccccccccccccc' + +/** + * Test aggregate operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('aggregate > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple aggregate + */ + test('aggregate', async () => { + const comment = await prisma.commentRequiredProp.aggregate({ + where: { id }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + _count: true, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + _count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/count/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/count/list.ts new file mode 100644 index 000000000000..2155a29bbf80 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/count/list.ts @@ -0,0 +1,56 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '7ccccccccccccccccccccccc' + +/** + * Test count operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('count > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple count + */ + test('simple', async () => { + const comment = await prisma.commentRequiredList.count({ + where: { id }, + orderBy: { + contents: { + _count: 'asc', + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(`1`) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/count/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/count/optional.ts new file mode 100644 index 000000000000..6f77f137b3de --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/count/optional.ts @@ -0,0 +1,58 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '8ccccccccccccccccccccccc' + +/** + * Test count operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('count > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple count + */ + test('count', async () => { + const comment = await prisma.commentOptionalProp.count({ + where: { id }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(`1`) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/count/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/count/required.ts new file mode 100644 index 000000000000..184c631f3f1b --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/count/required.ts @@ -0,0 +1,59 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '9ccccccccccccccccccccccc' + +/** + * Test count operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('count > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple count + */ + test('count', async () => { + const comment = await prisma.commentRequiredProp.count({ + where: { id }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + _count: true, + }) + + expect(comment).toMatchInlineSnapshot(`1`) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/create/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/create/list.ts new file mode 100644 index 000000000000..6f38f6f934a6 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/create/list.ts @@ -0,0 +1,186 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '4bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test create operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('create > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: [ + { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + ], + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 4bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 4bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredList.create({ + data: { + country: 'France', + // @-ts-expect-error + contents: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.contents.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredList.create({ + data: { + country: 'France', + // @-ts-expect-error + contents: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument contents for data.contents must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + ], + country: France, + id: 4bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/create/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/create/optional.ts new file mode 100644 index 000000000000..a6c5be0b1e3e --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/create/optional.ts @@ -0,0 +1,182 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '4aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test create operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('create > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 4aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 4aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: null, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 4aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: null, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 4aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: France, + id: 4aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/create/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/create/required.ts new file mode 100644 index 000000000000..6b17c8730c8a --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/create/required.ts @@ -0,0 +1,178 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = 'aaaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test create operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('create > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: aaaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: aaaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredProp.create({ + data: { + country: 'France', + // @-ts-expect-error + content: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.content.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredProp.create({ + data: { + country: 'France', + // @-ts-expect-error + content: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Got invalid value null on prisma.createOneCommentRequiredProp'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: France, + id: aaaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/list.ts new file mode 100644 index 000000000000..8163dc330c50 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/list.ts @@ -0,0 +1,146 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '5bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test createMany operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('createMany > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredList.createMany({ + data: { + id, + country: 'France', + contents: { + set: [ + { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + ], + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredList.createMany({ + data: { + id, + country: 'France', + contents: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredList.createMany({ + data: { + country: 'France', + // @-ts-expect-error + contents: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.0.contents.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredList.createMany({ + data: { + country: 'France', + // @-ts-expect-error + contents: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument contents for data.0.contents must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredList.createMany({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/optional.ts new file mode 100644 index 000000000000..f65ba98f3f66 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/optional.ts @@ -0,0 +1,144 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '9aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test createMany operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('createMany > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentOptionalProp.createMany({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentOptionalProp.createMany({ + data: { + id, + country: 'France', + content: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = await prisma.commentOptionalProp.createMany({ + data: { + id, + country: 'France', + content: { + set: null, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = await prisma.commentOptionalProp.createMany({ + data: { + id, + country: 'France', + content: null, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentOptionalProp.createMany({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/required.ts new file mode 100644 index 000000000000..a4cc1c1a67f0 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/createMany/required.ts @@ -0,0 +1,144 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = 'bbbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test createMany operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('createMany > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredProp.createMany({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredProp.createMany({ + data: { + id, + country: 'France', + content: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredProp.createMany({ + data: { + country: 'France', + // @-ts-expect-error + content: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.0.content.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredProp.createMany({ + data: { + country: 'France', + // @-ts-expect-error + content: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Got invalid value null on prisma.createManyCommentRequiredProp'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredProp.createMany({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/delete/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/delete/list.ts new file mode 100644 index 000000000000..72b1bbb0c905 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/delete/list.ts @@ -0,0 +1,55 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '6bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test delete operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('delete > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple delete + */ + test('delete', async () => { + await prisma.commentRequiredList.delete({ + where: { id }, + }) + + const count = await prisma.commentRequiredList.count({ + where: { id }, + }) + + expect(count).toBe(0) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/delete/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/delete/optional.ts new file mode 100644 index 000000000000..b0224a65082d --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/delete/optional.ts @@ -0,0 +1,55 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '5aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test delete operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('delete > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple delete + */ + test('delete', async () => { + await prisma.commentOptionalProp.delete({ + where: { id }, + }) + + const count = await prisma.commentOptionalProp.count({ + where: { id }, + }) + + expect(count).toBe(0) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/delete/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/delete/required.ts new file mode 100644 index 000000000000..c4766f38e874 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/delete/required.ts @@ -0,0 +1,55 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '0aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test delete operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('delete > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple delete + */ + test('delete', async () => { + await prisma.commentRequiredProp.delete({ + where: { id }, + }) + + const count = await prisma.commentRequiredProp.count({ + where: { id }, + }) + + expect(count).toBe(0) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/list.ts new file mode 100644 index 000000000000..2b16f31ddb4d --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/list.ts @@ -0,0 +1,55 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '7bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test deleteMany operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('deleteMany > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple delete + */ + test('delete', async () => { + await prisma.commentRequiredList.deleteMany({ + where: { id }, + }) + + const count = await prisma.commentRequiredList.count({ + where: { id }, + }) + + expect(count).toBe(0) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/optional.ts new file mode 100644 index 000000000000..35510a0a2563 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/optional.ts @@ -0,0 +1,55 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '6aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test deleteMany operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('deleteMany > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple delete + */ + test('delete', async () => { + await prisma.commentOptionalProp.deleteMany({ + where: { id }, + }) + + const count = await prisma.commentOptionalProp.count({ + where: { id }, + }) + + expect(count).toBe(0) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/required.ts new file mode 100644 index 000000000000..989798a6fd29 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/deleteMany/required.ts @@ -0,0 +1,55 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '1aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test deleteMany operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('deleteMany > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple delete + */ + test('delete', async () => { + await prisma.commentRequiredProp.deleteMany({ + where: { id }, + }) + + const count = await prisma.commentRequiredProp.count({ + where: { id }, + }) + + expect(count).toBe(0) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/list.ts new file mode 100644 index 000000000000..27337e7e86eb --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/list.ts @@ -0,0 +1,125 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '8bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test findFirst operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('findFirst > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple find + */ + test('simple', async () => { + const comment = await prisma.commentRequiredList.findFirst({ + where: { id }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 8bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Select + */ + test('select', async () => { + const comment = await prisma.commentRequiredList.findFirst({ + where: { id }, + select: { + contents: { + select: { + text: true, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + }, + ], + } + `) + }) + + /** + * Order by + */ + test('orderBy', async () => { + const comment = await prisma.commentRequiredList.findFirst({ + where: { id }, + orderBy: { + contents: { + _count: 'asc', + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 8bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/optional.ts new file mode 100644 index 000000000000..5d71e1e50680 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/optional.ts @@ -0,0 +1,121 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '7aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test findFirst operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('findFirst > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple find + */ + test('simple', async () => { + const comment = await prisma.commentOptionalProp.findFirst({ + where: { id }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 7aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Select + */ + test('select', async () => { + const comment = await prisma.commentOptionalProp.findFirst({ + where: { id }, + select: { + content: { + select: { + text: true, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + }, + } + `) + }) + + /** + * Order by + */ + test('orderBy', async () => { + const comment = await prisma.commentOptionalProp.findFirst({ + where: { id }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 7aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/required.ts new file mode 100644 index 000000000000..9d3673986bf6 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/findFirst/required.ts @@ -0,0 +1,121 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '2aaaaaaaaaaaaaaaaaaaaaaa' + +/** + * Test findFirst operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('findFirst > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple find + */ + test('find', async () => { + const comment = await prisma.commentRequiredProp.findFirst({ + where: { id }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 2aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) + + /** + * Select + */ + test('select', async () => { + const comment = await prisma.commentRequiredProp.findFirst({ + where: { id }, + select: { + content: { + select: { + text: true, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + }, + } + `) + }) + + /** + * Order by + */ + test('orderBy', async () => { + const comment = await prisma.commentRequiredProp.findFirst({ + where: { id }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 2aaaaaaaaaaaaaaaaaaaaaaa, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/list.ts new file mode 100644 index 000000000000..f5553a41b344 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/list.ts @@ -0,0 +1,368 @@ +import { getTestClient } from '../../../../../utils/getTestClient' +import { commentRequiredListDataA } from '../__helpers__/build-data/commentRequiredListDataA' +import { commentRequiredListDataB } from '../__helpers__/build-data/commentRequiredListDataB' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id1 = '9bbbbbbbbbbbbbbbbbbbbbbb' +const id2 = '0ddddddddddddddddddddddd' + +/** + * Test findMany operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('findMany > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { OR: [{ id: id1 }, { id: id2 }] } }) + await prisma.commentRequiredList.createMany({ + data: [commentRequiredListDataA(id1), commentRequiredListDataB(id2)], + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple find + */ + test('simple', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { id: id1 }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 9bbbbbbbbbbbbbbbbbbbbbbb, + }, + ] + `) + }) + + /** + * Select + */ + test('select', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { id: id1 }, + select: { + contents: { + select: { + text: true, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Hello World, + }, + ], + }, + ] + `) + }) + + /** + * Order by + */ + test('orderBy', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { OR: [{ id: id1 }, { id: id2 }] }, + orderBy: { + contents: { + _count: 'desc', + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + ], + }, + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + Object { + text: Hello World, + upvotes: Array [], + }, + ], + country: France, + id: 0ddddddddddddddddddddddd, + }, + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 9bbbbbbbbbbbbbbbbbbbbbbb, + }, + ] + `) + }) + + /** + * Filter equals + */ + test('filter equals', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + contents: { equals: commentRequiredListDataA(id1).contents.set }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 9bbbbbbbbbbbbbbbbbbbbbbb, + }, + ] + `) + }) + + /** + * Filter equals shorthand + */ + test('filter equals shorthand', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + contents: commentRequiredListDataA(id1).contents.set, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 9bbbbbbbbbbbbbbbbbbbbbbb, + }, + ] + `) + }) + + /** + * Filter every + */ + test('filter every', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + contents: { every: { upvotes: { every: { vote: true } } } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 9bbbbbbbbbbbbbbbbbbbbbbb, + }, + ] + `) + }) + + /** + * Filter some + */ + test('filter some', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + contents: { some: { upvotes: { some: { vote: false } } } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + ], + }, + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + Object { + text: Hello World, + upvotes: Array [], + }, + ], + country: France, + id: 0ddddddddddddddddddddddd, + }, + ] + `) + }) + + /** + * Filter empty + */ + test('filter empty', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + contents: { some: { upvotes: { isEmpty: true } } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + ], + }, + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + Object { + text: Hello World, + upvotes: Array [], + }, + ], + country: France, + id: 0ddddddddddddddddddddddd, + }, + ] + `) + }) + + /** + * Filter none + */ + test('filter none', async () => { + const comment = await prisma.commentRequiredList.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + contents: { none: { upvotes: { isEmpty: true } } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 9bbbbbbbbbbbbbbbbbbbbbbb, + }, + ] + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/optional.ts new file mode 100644 index 000000000000..161729fcca3d --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/optional.ts @@ -0,0 +1,272 @@ +import { getTestClient } from '../../../../../utils/getTestClient' +import { commentOptionalPropDataA } from '../__helpers__/build-data/commentOptionalPropDataA' +import { commentOptionalPropDataB } from '../__helpers__/build-data/commentOptionalPropDataB' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id1 = '8aaaaaaaaaaaaaaaaaaaaaaa' +const id2 = '1ddddddddddddddddddddddd' + +/** + * Test findMany operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('findMany > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { OR: [{ id: id1 }, { id: id2 }] } }) + await prisma.commentOptionalProp.createMany({ + data: [commentOptionalPropDataA(id1), commentOptionalPropDataB(id2)], + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple find + */ + test('simple', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { id: id1 }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 8aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Select + */ + test('select', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { id: id1 }, + select: { + content: { + select: { + text: true, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + }, + }, + ] + `) + }) + + /** + * Order by + */ + test('orderBy', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { OR: [{ id: id1 }, { id: id2 }] }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + Object { + userId: 12, + vote: true, + }, + ], + }, + country: France, + id: 1ddddddddddddddddddddddd, + }, + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 8aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter equals + */ + test('filter equals', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: { equals: commentOptionalPropDataA(id1).content.set }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 8aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter equals shorthand + */ + test('filter equals shorthand', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: commentOptionalPropDataA(id1).content.set, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 8aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter is + */ + test('filter is', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: { is: { OR: [{ text: 'Hello World' }, { text: 'Goodbye World' }] } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + Object { + userId: 12, + vote: true, + }, + ], + }, + country: France, + id: 1ddddddddddddddddddddddd, + }, + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 8aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter isNot + */ + test('filter isNot', async () => { + const comment = await prisma.commentOptionalProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: { isNot: { text: 'Goodbye World' } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 8aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/required.ts new file mode 100644 index 000000000000..74f67cc430fd --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/findMany/required.ts @@ -0,0 +1,272 @@ +import { getTestClient } from '../../../../../utils/getTestClient' +import { commentRequiredPropDataA } from '../__helpers__/build-data/commentRequiredPropDataA' +import { commentRequiredPropDataB } from '../__helpers__/build-data/commentRequiredPropDataB' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id1 = '3aaaaaaaaaaaaaaaaaaaaaaa' +const id2 = '2ddddddddddddddddddddddd' + +/** + * Test findMany operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('findMany > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { OR: [{ id: id1 }, { id: id2 }] } }) + await prisma.commentRequiredProp.createMany({ + data: [commentRequiredPropDataA(id1), commentRequiredPropDataB(id2)], + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple find + */ + test('simple', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { id: id1 }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Select + */ + test('select', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { id: id1 }, + select: { + content: { + select: { + text: true, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + }, + }, + ] + `) + }) + + /** + * Order by + */ + test('orderBy', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { OR: [{ id: id1 }, { id: id2 }] }, + orderBy: { + content: { + upvotes: { + _count: 'desc', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + Object { + userId: 12, + vote: true, + }, + ], + }, + country: France, + id: 2ddddddddddddddddddddddd, + }, + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter equals + */ + test('filter equals', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: commentRequiredPropDataA(id1).content.set, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter equals shorthand + */ + test('filter equals shorthand', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: commentRequiredPropDataA(id1).content.set, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter is + */ + test('filter is', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: { is: { OR: [{ text: 'Hello World' }, { text: 'Goodbye World' }] } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 11, + vote: false, + }, + Object { + userId: 12, + vote: true, + }, + ], + }, + country: France, + id: 2ddddddddddddddddddddddd, + }, + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) + + /** + * Filter isNot + */ + test('filter isNot', async () => { + const comment = await prisma.commentRequiredProp.findMany({ + where: { + OR: [{ id: id1 }, { id: id2 }], + content: { isNot: { text: 'Goodbye World' } }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Array [ + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3aaaaaaaaaaaaaaaaaaaaaaa, + }, + ] + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/schema.prisma b/packages/client/src/__tests__/integration/happy/composites-mongo/schema.prisma new file mode 100644 index 000000000000..5c305114878d --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/schema.prisma @@ -0,0 +1,40 @@ +datasource db { + provider = "mongodb" + url = env("TEST_MONGO_URI") +} + +generator client { + provider = "prisma-client-js" + previewFeatures = ["mongodb"] +} + +model CommentRequiredProp { + id String @id @default(auto()) @map("_id") @db.ObjectId + + country String? + content CommentContent +} + +model CommentOptionalProp { + id String @id @default(auto()) @map("_id") @db.ObjectId + + country String? + content CommentContent? +} + +model CommentRequiredList { + id String @id @default(auto()) @map("_id") @db.ObjectId + + country String? + contents CommentContent[] +} + +type CommentContent { + text String + upvotes CommentContentUpvotes[] +} + +type CommentContentUpvotes { + vote Boolean + userId String +} diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/update/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/update/list.ts new file mode 100644 index 000000000000..49f8fc819a32 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/update/list.ts @@ -0,0 +1,336 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '0ccccccccccccccccccccccc' + +/** + * Test update operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('update > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredList.update({ + where: { id }, + data: { + country: 'Mars', + contents: { + set: [ + { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + ], + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + ], + country: Mars, + id: 0ccccccccccccccccccccccc, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredList.update({ + where: { id }, + data: { + country: 'Mars', + contents: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + ], + country: Mars, + id: 0ccccccccccccccccccccccc, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredList.update({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + contents: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.contents.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredList.update({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + contents: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument contents for data.contents must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredList.update({ + where: { id }, + data: { + country: 'Mars', + contents: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: false, + }, + Object { + userId: 11, + vote: false, + }, + ], + }, + ], + country: Mars, + id: 0ccccccccccccccccccccccc, + } + `) + }) + + /** + * Simple push + */ + test('push', async () => { + const comment = await prisma.commentRequiredList.update({ + where: { id }, + data: { + contents: { + push: { + text: 'Goodbye World', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + Object { + text: Goodbye World, + upvotes: Array [], + }, + ], + country: France, + id: 0ccccccccccccccccccccccc, + } + `) + }) + + /** + * Simple updateMany + */ + test.skip('updateMany', async () => {}) + + /** + * Simple deleteMany + */ + test.skip('deleteMany', async () => {}) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = prisma.commentRequiredList.update({ + where: { id }, + data: { + contents: { + // @-ts-expect-error + unset: true, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `unset` in data.contents.unset for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = prisma.commentRequiredList.update({ + where: { id }, + data: { + contents: { + upsert: { + update: {}, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.contents.upsert for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = prisma.commentRequiredList.update({ + where: { id }, + data: { + contents: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.contents.upsert for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/update/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/update/optional.ts new file mode 100644 index 000000000000..d6378ecb3201 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/update/optional.ts @@ -0,0 +1,417 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '0bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test update operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('update > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'France', + content: { + set: null, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'France', + content: null, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: false, + }, + Object { + userId: 11, + vote: false, + }, + ], + }, + country: Mars, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple update + */ + test('update', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + content: { + upsert: { + update: { + text: 'Goodbye World', + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Update push nested list + */ + test('update push nested list', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + upsert: { + update: { + upvotes: { + push: [{ userId: '11', vote: true }], + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Update push nested list + */ + test('update set nested list', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + upsert: { + update: { + upvotes: { + set: [{ userId: '11', vote: true }], + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + content: { + unset: true, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + content: { + upsert: { + update: { + // TODO: validation error if removed + text: 'Hello World', + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = await prisma.commentOptionalProp.update({ + where: { id }, + data: { + content: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 0bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/update/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/update/required.ts new file mode 100644 index 000000000000..f14ba268d234 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/update/required.ts @@ -0,0 +1,386 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = 'cccccccccccccccccccccccc' + +/** + * Test update operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('update > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: cccccccccccccccccccccccc, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: cccccccccccccccccccccccc, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + content: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.content.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + content: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument content for data.content must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: false, + }, + Object { + userId: 11, + vote: false, + }, + ], + }, + country: Mars, + id: cccccccccccccccccccccccc, + } + `) + }) + + /** + * Simple update + */ + test('update', async () => { + const comment = await prisma.commentRequiredProp.update({ + where: { id }, + data: { + content: { + update: { + text: 'Goodbye World', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: cccccccccccccccccccccccc, + } + `) + }) + + /** + * Update push nested list + */ + test('update push nested list', async () => { + const comment = await prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + update: { + upvotes: { + push: [{ userId: '11', vote: true }], + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: cccccccccccccccccccccccc, + } + `) + }) + + /** + * Update push nested list + */ + test('update set nested list', async () => { + const comment = await prisma.commentRequiredProp.update({ + where: { id }, + data: { + country: 'Mars', + content: { + update: { + upvotes: { + set: [{ userId: '11', vote: true }], + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: cccccccccccccccccccccccc, + } + `) + }) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = prisma.commentRequiredProp.update({ + where: { id }, + data: { + content: { + // @-ts-expect-error + unset: true, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `unset` in data.content.unset for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = prisma.commentRequiredProp.update({ + where: { id }, + data: { + content: { + upsert: { + update: {}, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.content.upsert for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = prisma.commentRequiredProp.update({ + where: { id }, + data: { + content: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.content.upsert for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/list.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/list.ts new file mode 100644 index 000000000000..17c7884471a6 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/list.ts @@ -0,0 +1,280 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '1ccccccccccccccccccccccc' + +/** + * Test updateMany operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('updateMany > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + country: 'Mars', + contents: { + set: [ + { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + ], + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + country: 'Mars', + contents: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + contents: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.contents.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + contents: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument contents for data.contents must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + country: 'Mars', + contents: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple push + */ + test('push', async () => { + const comment = await prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + contents: { + push: { + text: 'Goodbye World', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple updateMany + */ + test.skip('updateMany', async () => {}) + + /** + * Simple deleteMany + */ + test.skip('deleteMany', async () => {}) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + contents: { + // @-ts-expect-error + unset: true, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `unset` in data.contents.unset for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + contents: { + upsert: { + update: {}, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.contents.upsert for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = prisma.commentRequiredList.updateMany({ + where: { id }, + data: { + contents: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.contents.upsert for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/optional.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/optional.ts new file mode 100644 index 000000000000..ba0cb60e4c57 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/optional.ts @@ -0,0 +1,319 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '1bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test updateMany operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('updateMany > optional', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'France', + content: { + set: null, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'France', + content: null, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple update + */ + test('update', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + content: { + upsert: { + update: { + text: 'Goodbye World', + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Update push nested list + */ + test('update push nested list', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + upsert: { + update: { + upvotes: { + push: [{ userId: '11', vote: true }], + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Update push nested list + */ + test('update set nested list', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + upsert: { + update: { + upvotes: { + set: [{ userId: '11', vote: true }], + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + content: { + unset: true, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + content: { + upsert: { + update: { + // TODO: validation error if removed + text: 'Hello World', + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = await prisma.commentOptionalProp.updateMany({ + where: { id }, + data: { + content: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/required.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/required.ts new file mode 100644 index 000000000000..0c99fe7e360d --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/updateMany/required.ts @@ -0,0 +1,318 @@ +import { getTestClient } from '../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = 'dddddddddddddddddddddddd' + +/** + * Test updateMany operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('updateMany > required', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('..') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + content: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for data.content.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'France', + // @-ts-expect-error + content: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument content for data.content must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple update + */ + test('update', async () => { + const comment = await prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + content: { + update: { + text: 'Goodbye World', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Update push nested list + */ + test('update push nested list', async () => { + const comment = await prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + update: { + upvotes: { + push: [{ userId: '11', vote: true }], + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Update push nested list + */ + test('update set nested list', async () => { + const comment = await prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + country: 'Mars', + content: { + update: { + upvotes: { + set: [{ userId: '11', vote: true }], + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + count: 1, + } + `) + }) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + content: { + // @-ts-expect-error + unset: true, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `unset` in data.content.unset for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + content: { + upsert: { + update: {}, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.content.upsert for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = prisma.commentRequiredProp.updateMany({ + where: { id }, + data: { + content: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in data.content.upsert for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/list/create.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/list/create.ts new file mode 100644 index 000000000000..4c180aef7c92 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/list/create.ts @@ -0,0 +1,196 @@ +import { getTestClient } from '../../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '2ccccccccccccccccccccccc' + +/** + * Test upsert create operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('upsert > list > create', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + contents: { + set: [ + { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + ], + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 2ccccccccccccccccccccccc, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + contents: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + ], + country: France, + id: 2ccccccccccccccccccccccc, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + update: {}, + create: { + country: 'France', + // @-ts-expect-error + contents: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for create.contents.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + update: {}, + create: { + country: 'France', + // @-ts-expect-error + contents: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument contents for create.contents must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + ], + country: France, + id: 2ccccccccccccccccccccccc, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/list/update.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/list/update.ts new file mode 100644 index 000000000000..ad6248040152 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/list/update.ts @@ -0,0 +1,345 @@ +import { getTestClient } from '../../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '3ccccccccccccccccccccccc' + +/** + * Test update operations on list composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('update > list', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredList.deleteMany({ where: { id } }) + await prisma.commentRequiredList.create({ + data: { + id, + country: 'France', + contents: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + contents: { + set: [ + { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + ], + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + ], + country: Mars, + id: 3ccccccccccccccccccccccc, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + contents: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + ], + country: Mars, + id: 3ccccccccccccccccccccccc, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + country: 'France', + // @-ts-expect-error + contents: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for update.contents.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + country: 'France', + // @-ts-expect-error + contents: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument contents for update.contents must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + contents: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: false, + }, + Object { + userId: 11, + vote: false, + }, + ], + }, + ], + country: Mars, + id: 3ccccccccccccccccccccccc, + } + `) + }) + + /** + * Simple push + */ + test('push', async () => { + const comment = await prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + contents: { + push: { + text: 'Goodbye World', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + contents: Array [ + Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + Object { + text: Goodbye World, + upvotes: Array [], + }, + ], + country: France, + id: 3ccccccccccccccccccccccc, + } + `) + }) + + /** + * Simple updateMany + */ + test.skip('updateMany', async () => {}) + + /** + * Simple deleteMany + */ + test.skip('deleteMany', async () => {}) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + contents: { + // @-ts-expect-error + unset: true, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `unset` in update.contents.unset for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + contents: { + upsert: { + update: {}, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in update.contents.upsert for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = prisma.commentRequiredList.upsert({ + where: { id }, + create: {}, + update: { + contents: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in update.contents.upsert for type CommentContentListUpdateEnvelopeInput', + ), + }), + ) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/optional/create.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/optional/create.ts new file mode 100644 index 000000000000..2a3a596e0869 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/optional/create.ts @@ -0,0 +1,192 @@ +import { getTestClient } from '../../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '2bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test upsert create operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('upsert > optional > create', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 2bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 2bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + set: null, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 2bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: null, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 2bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: France, + id: 2bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/optional/update.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/optional/update.ts new file mode 100644 index 000000000000..7bf4b023e0a0 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/optional/update.ts @@ -0,0 +1,428 @@ +import { getTestClient } from '../../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = '3bbbbbbbbbbbbbbbbbbbbbbb' + +/** + * Test upsert update operations on optional composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('upsert > optional > update', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentOptionalProp.deleteMany({ where: { id } }) + await prisma.commentOptionalProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + content: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'France', + content: { + set: null, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'France', + content: null, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: false, + }, + Object { + userId: 11, + vote: false, + }, + ], + }, + country: Mars, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple update + */ + test('update', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + content: { + upsert: { + update: { + text: 'Goodbye World', + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Update push nested list + */ + test('update push nested list', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + content: { + upsert: { + update: { + upvotes: { + push: [{ userId: '11', vote: true }], + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Update push nested list + */ + test('update set nested list', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + country: 'Mars', + content: { + upsert: { + update: { + upvotes: { + set: [{ userId: '11', vote: true }], + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + content: { + unset: true, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: null, + country: France, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + content: { + upsert: { + update: { + // TODO: validation error if removed + text: 'Hello World', + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = await prisma.commentOptionalProp.upsert({ + where: { id }, + create: {}, + update: { + content: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: null, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: 3bbbbbbbbbbbbbbbbbbbbbbb, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/required/create.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/required/create.ts new file mode 100644 index 000000000000..98269562a02f --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/required/create.ts @@ -0,0 +1,188 @@ +import { getTestClient } from '../../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = 'eeeeeeeeeeeeeeeeeeeeeeee' + +/** + * Test upsert create operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('upsert > required > create', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: eeeeeeeeeeeeeeeeeeeeeeee, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: eeeeeeeeeeeeeeeeeeeeeeee, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + update: {}, + create: { + country: 'France', + // @-ts-expect-error + content: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for create.content.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + update: {}, + create: { + country: 'France', + // @-ts-expect-error + content: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Got invalid value null on prisma.upsertOneCommentRequiredProp'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + update: {}, + create: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: [ + { userId: '10', vote: true }, + { userId: '11', vote: true }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: France, + id: eeeeeeeeeeeeeeeeeeeeeeee, + } + `) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/required/update.ts b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/required/update.ts new file mode 100644 index 000000000000..0f923866e1b1 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/composites-mongo/upsert/required/update.ts @@ -0,0 +1,441 @@ +import { getTestClient } from '../../../../../../utils/getTestClient' + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +let PrismaClient, prisma + +const id = 'ffffffffffffffffffffffff' + +/** + * Test upsert update operations on required composite fields + */ +describeIf(!process.env.TEST_SKIP_MONGODB)('upsert > required > update', () => { + beforeAll(async () => { + PrismaClient = await getTestClient('../../') + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.commentRequiredProp.deleteMany({ where: { id } }) + await prisma.commentRequiredProp.create({ + data: { + id, + country: 'France', + content: { + set: { + text: 'Hello World', + upvotes: { + vote: true, + userId: '10', + }, + }, + }, + }, + }) + }) + + afterEach(async () => { + await prisma.$disconnect() + }) + + /** + * Simple set + */ + test('set', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: ffffffffffffffffffffffff, + } + `) + }) + + /** + * Set shorthand + */ + test('set shorthand', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'Mars', + content: { + text: 'Goodbye World', + upvotes: { + vote: false, + userId: '42', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 42, + vote: false, + }, + ], + }, + country: Mars, + id: ffffffffffffffffffffffff, + } + `) + }) + + /** + * Set null + */ + test('set null', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'France', + // @-ts-expect-error + content: { + set: null, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument set for update.content.set must not be null'), + }), + ) + }) + + /** + * Set null shorthand + */ + test('set null shorthand', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'France', + // @-ts-expect-error + content: null, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining('Argument content for update.content must not be null'), + }), + ) + }) + + /** + * Set nested list + */ + test('set nested list', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'Mars', + content: { + set: { + text: 'Goodbye World', + upvotes: [ + { userId: '10', vote: false }, + { userId: '11', vote: false }, + ], + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: false, + }, + Object { + userId: 11, + vote: false, + }, + ], + }, + country: Mars, + id: ffffffffffffffffffffffff, + } + `) + }) + + /** + * Simple update + */ + test('update', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + content: { + update: { + text: 'Goodbye World', + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Goodbye World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + ], + }, + country: France, + id: ffffffffffffffffffffffff, + } + `) + }) + + /** + * Update push nested list + */ + test('update push nested list', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'Mars', + content: { + update: { + upvotes: { + push: [{ userId: '11', vote: true }], + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 10, + vote: true, + }, + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: ffffffffffffffffffffffff, + } + `) + }) + + /** + * Update push nested list + */ + test('update set nested list', async () => { + const comment = await prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + country: 'Mars', + content: { + update: { + upvotes: { + set: [{ userId: '11', vote: true }], + }, + }, + }, + }, + }) + + expect(comment).toMatchInlineSnapshot(` + Object { + content: Object { + text: Hello World, + upvotes: Array [ + Object { + userId: 11, + vote: true, + }, + ], + }, + country: Mars, + id: ffffffffffffffffffffffff, + } + `) + }) + + /** + * Simple unset + */ + test('unset', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + content: { + // @-ts-expect-error + unset: true, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `unset` in update.content.unset for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - set + */ + test('upsert set', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + content: { + upsert: { + update: {}, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in update.content.upsert for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) + + /** + * Simple upsert - update + */ + test('upsert update', async () => { + const comment = prisma.commentRequiredProp.upsert({ + where: { id }, + create: { + content: { + text: 'Hello World', + }, + }, + update: { + content: { + upsert: { + update: { + text: 'Hello World', + upvotes: { + push: { + userId: '10', + vote: true, + }, + }, + }, + set: { + text: 'Hello World', + }, + }, + }, + }, + }) + + await expect(comment).rejects.toThrowError( + expect.objectContaining({ + message: expect.stringContaining( + 'Unknown arg `upsert` in update.content.upsert for type CommentContentUpdateEnvelopeInput', + ), + }), + ) + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/count/test.ts b/packages/client/src/__tests__/integration/happy/count/test.ts index f03c48c1560a..df0c393db21d 100644 --- a/packages/client/src/__tests__/integration/happy/count/test.ts +++ b/packages/client/src/__tests__/integration/happy/count/test.ts @@ -1,64 +1,142 @@ import { getTestClient } from '../../../../utils/getTestClient' -test('count', async () => { - const PrismaClient = await getTestClient() - const prisma = new PrismaClient() - const result = await prisma.user.count() - expect.assertions(4) - expect(result).toMatchInlineSnapshot(`10`) - - const result2 = await prisma.user.count({ - select: true, +let PrismaClient, prisma + +describe('count', () => { + beforeAll(async () => { + PrismaClient = await getTestClient() }) - expect(result2).toMatchInlineSnapshot(`10`) - - const result3 = await prisma.user.count({ - select: { - _all: true, - email: true, - age: true, - name: true, - }, + + beforeEach(() => { + prisma = new PrismaClient() }) - expect(result3).toMatchInlineSnapshot(` - Object { - _all: 10, - age: 10, - email: 10, - name: 10, - } - `) - try { - await prisma.user.count({ + + afterEach(() => { + prisma.$disconnect() + }) + + test('simple', async () => { + const value = await prisma.user.count() + + expect(value).toMatchInlineSnapshot(`10`) + }) + + test('where', async () => { + const value = await prisma.user.count({ + where: { + age: 84, + }, + }) + + expect(value).toMatchInlineSnapshot(`1`) + }) + + test('select where', async () => { + const value = await prisma.user.count({ + select: true, + where: { + age: 84, + }, + }) + + expect(value).toMatchInlineSnapshot(`1`) + }) + + test('select mixed where', async () => { + const value = await prisma.user.count({ select: { _all: true, email: true, age: true, name: true, - posts: true, + }, + where: { + age: 84, }, }) - } catch (err) { - expect(err.message).toMatchInlineSnapshot(` - - Invalid \`prisma.user.aggregate()\` invocation: - { - _count: { - ? _all?: true, - ? email?: true, - ? age?: true, - ? name?: true, - posts: true, - ~~~~~ - ? id?: true - } + expect(value).toMatchInlineSnapshot(` + Object { + _all: 1, + age: 1, + email: 1, + name: 1, } + `) + }) + test('select all true', async () => { + const value = await prisma.user.count({ + select: true, // count with a selection + }) - Unknown field \`posts\` for select statement on model UserCountAggregateOutputType. Available options are listed in green. Did you mean \`id\`? + expect(value).toMatchInlineSnapshot(`10`) + }) + + test('select all false', async () => { + const value = await prisma.user.count({ + select: false, // count with no selection + }) + + expect(value).toMatchInlineSnapshot(`10`) + }) + + test('select mixed', async () => { + const value = await prisma.user.count({ + select: { + _all: true, + email: true, + age: true, + name: true, + }, + }) + expect(value).toMatchInlineSnapshot(` + Object { + _all: 10, + age: 10, + email: 10, + name: 10, + } `) - } - await prisma.$disconnect() + }) + + test('bad prop', async () => { + try { + await prisma.user.count({ + select: { + _all: true, + email: true, + age: true, + name: true, + posts: true, + }, + }) + } catch (err) { + expect(err.message).toMatchInlineSnapshot(` + + Invalid \`prisma.user.count()\` invocation: + + { + select: { + _count: { + select: { + ? _all?: true, + ? email?: true, + ? age?: true, + ? name?: true, + posts: true, + ~~~~~ + ? id?: true + } + } + } + } + + + Unknown field \`posts\` for select statement on model UserCountAggregateOutputType. Available options are listed in green. Did you mean \`id\`? + + `) + } + }) }) diff --git a/packages/client/src/__tests__/integration/happy/createMany-mysql/test.ts b/packages/client/src/__tests__/integration/happy/createMany-mysql/test.ts index 4c727618065e..d18f4a144834 100644 --- a/packages/client/src/__tests__/integration/happy/createMany-mysql/test.ts +++ b/packages/client/src/__tests__/integration/happy/createMany-mysql/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/createMany-postgresql/test.ts b/packages/client/src/__tests__/integration/happy/createMany-postgresql/test.ts index 695c60278464..40af00fff86f 100644 --- a/packages/client/src/__tests__/integration/happy/createMany-postgresql/test.ts +++ b/packages/client/src/__tests__/integration/happy/createMany-postgresql/test.ts @@ -1,7 +1,9 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' + describe('createMany(postgres)', () => { beforeAll(async () => { process.env.TEST_POSTGRES_URI += '-createMany' diff --git a/packages/client/src/__tests__/integration/happy/custom-engine-binary/test.ts b/packages/client/src/__tests__/integration/happy/custom-engine-binary/test.ts index dd16aab8bf2f..723c1dd76df6 100644 --- a/packages/client/src/__tests__/integration/happy/custom-engine-binary/test.ts +++ b/packages/client/src/__tests__/integration/happy/custom-engine-binary/test.ts @@ -2,6 +2,7 @@ import { getNodeAPIName, getPlatform } from '@prisma/get-platform' import { ClientEngineType, getClientEngineType } from '@prisma/sdk' import fs from 'fs' import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' if (getClientEngineType() === ClientEngineType.DataProxy) { diff --git a/packages/client/src/__tests__/integration/happy/disconnect-finally/test.ts b/packages/client/src/__tests__/integration/happy/disconnect-finally/test.ts index 725a9d320da4..f228b1d807e1 100644 --- a/packages/client/src/__tests__/integration/happy/disconnect-finally/test.ts +++ b/packages/client/src/__tests__/integration/happy/disconnect-finally/test.ts @@ -15,7 +15,7 @@ test('disconnect-finally', async () => { return new Promise((resolve) => { main().finally(async () => { await prisma.$disconnect() - await res + await res // re-wakes the engine prisma.$disconnect() resolve(await res) }) @@ -24,4 +24,6 @@ test('disconnect-finally', async () => { const data = await run() expect(data).toMatchSnapshot() + + await prisma.$disconnect() }) diff --git a/packages/client/src/__tests__/integration/happy/disconnect-while-query/test.ts b/packages/client/src/__tests__/integration/happy/disconnect-while-query/test.ts index a41cfd0442d8..aa846b966574 100644 --- a/packages/client/src/__tests__/integration/happy/disconnect-while-query/test.ts +++ b/packages/client/src/__tests__/integration/happy/disconnect-while-query/test.ts @@ -6,10 +6,12 @@ test('disconnect-while-query', async () => { await prisma.user.findMany() const a = prisma.user.findMany() - prisma.$disconnect() - await a + prisma.$disconnect() + await a // re-wakes the engine await prisma.$disconnect() expect(await a).toMatchInlineSnapshot(`Array []`) + + await prisma.$disconnect() }) diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/.gitignore b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/.gitignore new file mode 100644 index 000000000000..6ab275cf57c2 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/.gitignore @@ -0,0 +1 @@ +generated-dmmf.ts diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/__snapshots__/test.ts.snap b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/__snapshots__/test.ts.snap new file mode 100644 index 000000000000..b496634e6354 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/__snapshots__/test.ts.snap @@ -0,0 +1,20925 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`exhaustive-schema: generatedBrowserJS 1`] = ` + +Object.defineProperty(exports, "__esModule", { value: true }); + +const { + Decimal +} = require('@prisma/client/runtime/index-browser') + + +const Prisma = {} + +exports.Prisma = Prisma + +/** + * Prisma Client JS version: local + * Query Engine version: local + */ +Prisma.prismaVersion = { + client: "local", + engine: "local" +} + +Prisma.PrismaClientKnownRequestError = () => { + throw new Error(\`PrismaClientKnownRequestError is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)}; +Prisma.PrismaClientUnknownRequestError = () => { + throw new Error(\`PrismaClientUnknownRequestError is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.PrismaClientRustPanicError = () => { + throw new Error(\`PrismaClientRustPanicError is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.PrismaClientInitializationError = () => { + throw new Error(\`PrismaClientInitializationError is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.PrismaClientValidationError = () => { + throw new Error(\`PrismaClientValidationError is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.Decimal = Decimal + +/** + * Re-export of sql-template-tag + */ +Prisma.sql = () => { + throw new Error(\`sqltag is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.empty = () => { + throw new Error(\`empty is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.join = () => { + throw new Error(\`join is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.raw = () => { + throw new Error(\`raw is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, +)} +Prisma.validator = () => (val) => val + +/** + * Shorthand utilities for JSON filtering + */ +Prisma.DbNull = 'DbNull' +Prisma.JsonNull = 'JsonNull' +Prisma.AnyNull = 'AnyNull' + +/** + * Enums + */ +// Based on +// https://github.com/microsoft/TypeScript/issues/3192#issuecomment-261720275 +function makeEnum(x) { return x; } + +exports.Prisma.PostScalarFieldEnum = makeEnum({ + id: 'id', + createdAt: 'createdAt', + title: 'title', + content: 'content', + published: 'published', + authorId: 'authorId' +}); + +exports.Prisma.UserScalarFieldEnum = makeEnum({ + id: 'id', + email: 'email', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean', + embedHolderId: 'embedHolderId' +}); + +exports.Prisma.EmbedHolderScalarFieldEnum = makeEnum({ + id: 'id', + time: 'time', + text: 'text', + boolean: 'boolean' +}); + +exports.Prisma.MScalarFieldEnum = makeEnum({ + id: 'id', + n_ids: 'n_ids', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' +}); + +exports.Prisma.NScalarFieldEnum = makeEnum({ + id: 'id', + m_ids: 'm_ids', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' +}); + +exports.Prisma.OneOptionalScalarFieldEnum = makeEnum({ + id: 'id', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' +}); + +exports.Prisma.ManyRequiredScalarFieldEnum = makeEnum({ + id: 'id', + oneOptionalId: 'oneOptionalId', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' +}); + +exports.Prisma.OptionalSide1ScalarFieldEnum = makeEnum({ + id: 'id', + optionalSide2Id: 'optionalSide2Id', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' +}); + +exports.Prisma.OptionalSide2ScalarFieldEnum = makeEnum({ + id: 'id', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' +}); + +exports.Prisma.AScalarFieldEnum = makeEnum({ + id: 'id', + email: 'email', + name: 'name', + int: 'int', + sInt: 'sInt', + bInt: 'bInt' +}); + +exports.Prisma.BScalarFieldEnum = makeEnum({ + id: 'id', + float: 'float', + dFloat: 'dFloat', + decFloat: 'decFloat', + numFloat: 'numFloat' +}); + +exports.Prisma.CScalarFieldEnum = makeEnum({ + id: 'id', + char: 'char', + vChar: 'vChar', + text: 'text', + bit: 'bit', + vBit: 'vBit', + uuid: 'uuid' +}); + +exports.Prisma.DScalarFieldEnum = makeEnum({ + id: 'id', + bool: 'bool', + byteA: 'byteA', + xml: 'xml', + json: 'json', + jsonb: 'jsonb' +}); + +exports.Prisma.EScalarFieldEnum = makeEnum({ + id: 'id', + date: 'date', + time: 'time', + ts: 'ts' +}); + +exports.Prisma.SortOrder = makeEnum({ + asc: 'asc', + desc: 'desc' +}); + +exports.Prisma.QueryMode = makeEnum({ + default: 'default', + insensitive: 'insensitive' +}); +exports.ABeautifulEnum = makeEnum({ + A: 'A', + B: 'B', + C: 'C' +}); + +exports.Prisma.ModelName = makeEnum({ + Post: 'Post', + User: 'User', + EmbedHolder: 'EmbedHolder', + M: 'M', + N: 'N', + OneOptional: 'OneOptional', + ManyRequired: 'ManyRequired', + OptionalSide1: 'OptionalSide1', + OptionalSide2: 'OptionalSide2', + A: 'A', + B: 'B', + C: 'C', + D: 'D', + E: 'E' +}); + +/** + * Create the Client + */ +class PrismaClient { + constructor() { + throw new Error( + \`PrismaClient is unable to be run in the browser. +In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues\`, + ) + } +} +exports.PrismaClient = PrismaClient + +Object.assign(exports, Prisma) + +`; + +exports[`exhaustive-schema: generatedTypeScript 1`] = ` + +/** + * Client +**/ + +import * as runtime from '@prisma/client/runtime/index'; +declare const prisma: unique symbol +export type PrismaPromise = Promise & {[prisma]: true} +type UnwrapPromise

= P extends Promise ? R : P +type UnwrapTuple = { + [K in keyof Tuple]: K extends \`\${number}\` ? Tuple[K] extends PrismaPromise ? X : UnwrapPromise : UnwrapPromise +}; + + +/** + * Model Embed + * + */ +export type Embed = { + text: string + boolean: boolean + embedEmbedList: EmbedEmbed[] + requiredEmbedEmbed: EmbedEmbed + optionalEmbedEmbed: EmbedEmbed | null +} + +/** + * Model EmbedEmbed + * + */ +export type EmbedEmbed = { + text: string + boolean: boolean +} + +/** + * Model Post + * + */ +export type Post = { + id: string + createdAt: Date + title: string + content: string | null + published: boolean + authorId: number +} + +/** + * Model User + * + */ +export type User = { + id: string + email: string + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + embedHolderId: string +} + +/** + * Model EmbedHolder + * + */ +export type EmbedHolder = { + embedList: Embed[] + requiredEmbed: Embed + optionalEmbed: Embed | null + id: string + time: Date + text: string + boolean: boolean +} + +/** + * Model M + * + */ +export type M = { + id: string + n_ids: string[] + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null +} + +/** + * Model N + * + */ +export type N = { + id: string + m_ids: string[] + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null +} + +/** + * Model OneOptional + * + */ +export type OneOptional = { + id: string + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null +} + +/** + * Model ManyRequired + * + */ +export type ManyRequired = { + id: string + oneOptionalId: number | null + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null +} + +/** + * Model OptionalSide1 + * + */ +export type OptionalSide1 = { + id: string + optionalSide2Id: number | null + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null +} + +/** + * Model OptionalSide2 + * + */ +export type OptionalSide2 = { + id: string + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: Prisma.JsonValue + optionalJson: Prisma.JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null +} + +/** + * Model A + * model comment + */ +export type A = { + /** + * field comment 1 + */ + id: string + email: string + name: string | null + /** + * field comment 2 + */ + int: number + sInt: number + bInt: bigint +} + +/** + * Model B + * + */ +export type B = { + id: string + float: number + dFloat: number + decFloat: Prisma.Decimal + numFloat: Prisma.Decimal +} + +/** + * Model C + * + */ +export type C = { + id: string + char: string + vChar: string + text: string + bit: string + vBit: string + uuid: string +} + +/** + * Model D + * + */ +export type D = { + id: string + bool: boolean + byteA: Buffer + xml: string + json: Prisma.JsonValue + jsonb: Prisma.JsonValue +} + +/** + * Model E + * + */ +export type E = { + id: string + date: Date + time: Date + ts: Date +} + + +/** + * Enums + */ + +// Based on +// https://github.com/microsoft/TypeScript/issues/3192#issuecomment-261720275 + +export const ABeautifulEnum: { + A: 'A', + B: 'B', + C: 'C' +}; + +export type ABeautifulEnum = (typeof ABeautifulEnum)[keyof typeof ABeautifulEnum] + + +/** + * ## Prisma Client ʲˢ + * + * Type-safe database client for TypeScript & Node.js + * @example + * \`\`\` + * const prisma = new PrismaClient() + * // Fetch zero or more Posts + * const posts = await prisma.post.findMany() + * \`\`\` + * + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client). + */ +export class PrismaClient< + T extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions, + U = 'log' extends keyof T ? T['log'] extends Array ? Prisma.GetEvents : never : never, + GlobalReject = 'rejectOnNotFound' extends keyof T + ? T['rejectOnNotFound'] + : false + > { + /** + * @private + */ + private fetcher; + /** + * @private + */ + private readonly dmmf; + /** + * @private + */ + private connectionPromise?; + /** + * @private + */ + private disconnectionPromise?; + /** + * @private + */ + private readonly engineConfig; + /** + * @private + */ + private readonly measurePerformance; + + /** + * ## Prisma Client ʲˢ + * + * Type-safe database client for TypeScript & Node.js + * @example + * \`\`\` + * const prisma = new PrismaClient() + * // Fetch zero or more Posts + * const posts = await prisma.post.findMany() + * \`\`\` + * + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client). + */ + + constructor(optionsArg ?: Prisma.Subset); + $on(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : V extends 'beforeExit' ? () => Promise : Prisma.LogEvent) => void): void; + + /** + * Connect with the database + */ + $connect(): Promise; + + /** + * Disconnect from the database + */ + $disconnect(): Promise; + + /** + * Add a middleware + */ + $use(cb: Prisma.Middleware): void + +/** + * Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole. + * @example + * \`\`\` + * const [george, bob, alice] = await prisma.$transaction([ + * prisma.user.create({ data: { name: 'George' } }), + * prisma.user.create({ data: { name: 'Bob' } }), + * prisma.user.create({ data: { name: 'Alice' } }), + * ]) + * \`\`\` + * + * Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions). + */ + $transaction

[]>(arg: [...P]): Promise>; + + + /** + * Executes a raw MongoDB command and returns the result of it. + * @example + * \`\`\` + * const user = await prisma.$runCommandRaw({ + * aggregate: 'User', + * pipeline: [{ $match: { name: 'Bob' } }, { $project: { email: true, _id: false } }], + * explain: false, + * }) + * \`\`\` + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access). + */ + $runCommandRaw(command: Prisma.InputJsonObject): PrismaPromise; + + /** + * \`prisma.post\`: Exposes CRUD operations for the **Post** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Posts + * const posts = await prisma.post.findMany() + * \`\`\` + */ + get post(): Prisma.PostDelegate; + + /** + * \`prisma.user\`: Exposes CRUD operations for the **User** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * \`\`\` + */ + get user(): Prisma.UserDelegate; + + /** + * \`prisma.embedHolder\`: Exposes CRUD operations for the **EmbedHolder** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more EmbedHolders + * const embedHolders = await prisma.embedHolder.findMany() + * \`\`\` + */ + get embedHolder(): Prisma.EmbedHolderDelegate; + + /** + * \`prisma.m\`: Exposes CRUD operations for the **M** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Ms + * const ms = await prisma.m.findMany() + * \`\`\` + */ + get m(): Prisma.MDelegate; + + /** + * \`prisma.n\`: Exposes CRUD operations for the **N** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Ns + * const ns = await prisma.n.findMany() + * \`\`\` + */ + get n(): Prisma.NDelegate; + + /** + * \`prisma.oneOptional\`: Exposes CRUD operations for the **OneOptional** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more OneOptionals + * const oneOptionals = await prisma.oneOptional.findMany() + * \`\`\` + */ + get oneOptional(): Prisma.OneOptionalDelegate; + + /** + * \`prisma.manyRequired\`: Exposes CRUD operations for the **ManyRequired** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more ManyRequireds + * const manyRequireds = await prisma.manyRequired.findMany() + * \`\`\` + */ + get manyRequired(): Prisma.ManyRequiredDelegate; + + /** + * \`prisma.optionalSide1\`: Exposes CRUD operations for the **OptionalSide1** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more OptionalSide1s + * const optionalSide1s = await prisma.optionalSide1.findMany() + * \`\`\` + */ + get optionalSide1(): Prisma.OptionalSide1Delegate; + + /** + * \`prisma.optionalSide2\`: Exposes CRUD operations for the **OptionalSide2** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more OptionalSide2s + * const optionalSide2s = await prisma.optionalSide2.findMany() + * \`\`\` + */ + get optionalSide2(): Prisma.OptionalSide2Delegate; + + /** + * \`prisma.a\`: Exposes CRUD operations for the **A** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more As + * const as = await prisma.a.findMany() + * \`\`\` + */ + get a(): Prisma.ADelegate; + + /** + * \`prisma.b\`: Exposes CRUD operations for the **B** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Bs + * const bs = await prisma.b.findMany() + * \`\`\` + */ + get b(): Prisma.BDelegate; + + /** + * \`prisma.c\`: Exposes CRUD operations for the **C** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Cs + * const cs = await prisma.c.findMany() + * \`\`\` + */ + get c(): Prisma.CDelegate; + + /** + * \`prisma.d\`: Exposes CRUD operations for the **D** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Ds + * const ds = await prisma.d.findMany() + * \`\`\` + */ + get d(): Prisma.DDelegate; + + /** + * \`prisma.e\`: Exposes CRUD operations for the **E** model. + * Example usage: + * \`\`\`ts + * // Fetch zero or more Es + * const es = await prisma.e.findMany() + * \`\`\` + */ + get e(): Prisma.EDelegate; +} + +export namespace Prisma { + export import DMMF = runtime.DMMF + + /** + * Prisma Errors + */ + export import PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError + export import PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError + export import PrismaClientRustPanicError = runtime.PrismaClientRustPanicError + export import PrismaClientInitializationError = runtime.PrismaClientInitializationError + export import PrismaClientValidationError = runtime.PrismaClientValidationError + + /** + * Re-export of sql-template-tag + */ + export import sql = runtime.sqltag + export import empty = runtime.empty + export import join = runtime.join + export import raw = runtime.raw + export import Sql = runtime.Sql + + /** + * Decimal.js + */ + export import Decimal = runtime.Decimal + + /** + * Prisma Client JS version: local + * Query Engine version: local + */ + export type PrismaVersion = { + client: string + } + + export const prismaVersion: PrismaVersion + + /** + * Utility Types + */ + + /** + * From https://github.com/sindresorhus/type-fest/ + * Matches a JSON object. + * This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. + */ + export type JsonObject = {[Key in string]?: JsonValue} + + /** + * From https://github.com/sindresorhus/type-fest/ + * Matches a JSON array. + */ + export interface JsonArray extends Array {} + + /** + * From https://github.com/sindresorhus/type-fest/ + * Matches any valid JSON value. + */ + export type JsonValue = string | number | boolean | JsonObject | JsonArray | null + + /** + * Matches a JSON object. + * Unlike \`JsonObject\`, this type allows undefined and read-only properties. + */ + export type InputJsonObject = {readonly [Key in string]?: InputJsonValue | null} + + /** + * Matches a JSON array. + * Unlike \`JsonArray\`, readonly arrays are assignable to this type. + */ + export interface InputJsonArray extends ReadonlyArray {} + + /** + * Matches any valid value that can be used as an input for operations like + * create and update as the value of a JSON field. Unlike \`JsonValue\`, this + * type allows read-only arrays and read-only object properties and disallows + * \`null\` at the top level. + * + * \`null\` cannot be used as the value of a JSON field because its meaning + * would be ambiguous. Use \`Prisma.JsonNull\` to store the JSON null value or + * \`Prisma.DbNull\` to clear the JSON value and set the field to the database + * NULL value instead. + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-by-null-values + */ + export type InputJsonValue = string | number | boolean | InputJsonObject | InputJsonArray + + /** + * Helper for filtering JSON entries that have \`null\` on the database (empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + export const DbNull: 'DbNull' + + /** + * Helper for filtering JSON entries that have JSON \`null\` values (not empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + export const JsonNull: 'JsonNull' + + /** + * Helper for filtering JSON entries that are \`Prisma.DbNull\` or \`Prisma.JsonNull\` + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + export const AnyNull: 'AnyNull' + + type SelectAndInclude = { + select: any + include: any + } + type HasSelect = { + select: any + } + type HasInclude = { + include: any + } + type CheckSelect = T extends SelectAndInclude + ? 'Please either choose \`select\` or \`include\`' + : T extends HasSelect + ? U + : T extends HasInclude + ? U + : S + + /** + * Get the type of the value, that the Promise holds. + */ + export type PromiseType> = T extends PromiseLike ? U : T; + + /** + * Get the return type of a function which returns a Promise. + */ + export type PromiseReturnType Promise> = PromiseType> + + /** + * From T, pick a set of properties whose keys are in the union K + */ + type Prisma__Pick = { + [P in K]: T[P]; + }; + + + export type Enumerable = T | Array; + + export type RequiredKeys = { + [K in keyof T]-?: {} extends Prisma__Pick ? never : K + }[keyof T] + + export type TruthyKeys = { + [key in keyof T]: T[key] extends false | undefined | null ? never : key + }[keyof T] + + export type TrueKeys = TruthyKeys>> + + /** + * Subset + * @desc From \`T\` pick properties that exist in \`U\`. Simple version of Intersection + */ + export type Subset = { + [key in keyof T]: key extends keyof U ? T[key] : never; + }; + + /** + * SelectSubset + * @desc From \`T\` pick properties that exist in \`U\`. Simple version of Intersection. + * Additionally, it validates, if both select and include are present. If the case, it errors. + */ + export type SelectSubset = { + [key in keyof T]: key extends keyof U ? T[key] : never + } & + (T extends SelectAndInclude + ? 'Please either choose \`select\` or \`include\`.' + : {}) + + /** + * Subset + Intersection + * @desc From \`T\` pick properties that exist in \`U\` and intersect \`K\` + */ + export type SubsetIntersection = { + [key in keyof T]: key extends keyof U ? T[key] : never + } & + K + + type Without = { [P in Exclude]?: never }; + + /** + * XOR is needed to have a real mutually exclusive union type + * https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types + */ + type XOR = + T extends object ? + U extends object ? + (Without & U) | (Without & T) + : U : T + + + /** + * Is T a Record? + */ + type IsObject = T extends Array + ? False + : T extends Date + ? False + : T extends Buffer + ? False + : T extends BigInt + ? False + : T extends object + ? True + : False + + + /** + * If it's T[], return T + */ + export type UnEnumerate = T extends Array ? U : T + + /** + * From ts-toolbelt + */ + + type __Either = Omit & + { + // Merge all but K + [P in K]: Prisma__Pick // With K possibilities + }[K] + + type EitherStrict = Strict<__Either> + + type EitherLoose = ComputeRaw<__Either> + + type _Either< + O extends object, + K extends Key, + strict extends Boolean + > = { + 1: EitherStrict + 0: EitherLoose + }[strict] + + type Either< + O extends object, + K extends Key, + strict extends Boolean = 1 + > = O extends unknown ? _Either : never + + export type Union = any + + type PatchUndefined = { + [K in keyof O]: O[K] extends undefined ? At : O[K] + } & {} + + /** Helper Types for "Merge" **/ + export type IntersectOf = ( + U extends unknown ? (k: U) => void : never + ) extends (k: infer I) => void + ? I + : never + + export type Overwrite = { + [K in keyof O]: K extends keyof O1 ? O1[K] : O[K]; + } & {}; + + type _Merge = IntersectOf; + }>>; + + type Key = string | number | symbol; + type AtBasic = K extends keyof O ? O[K] : never; + type AtStrict = O[K & keyof O]; + type AtLoose = O extends unknown ? AtStrict : never; + export type At = { + 1: AtStrict; + 0: AtLoose; + }[strict]; + + export type ComputeRaw = A extends Function ? A : { + [K in keyof A]: A[K]; + } & {}; + + export type OptionalFlat = { + [K in keyof O]?: O[K]; + } & {}; + + type _Record = { + [P in K]: T; + }; + + type _Strict = U extends unknown ? U & OptionalFlat<_Record, keyof U>, never>> : never; + + export type Strict = ComputeRaw<_Strict>; + /** End Helper Types for "Merge" **/ + + export type Merge = ComputeRaw<_Merge>>; + + /** + A [[Boolean]] + */ + export type Boolean = True | False + + // /** + // 1 + // */ + export type True = 1 + + /** + 0 + */ + export type False = 0 + + export type Not = { + 0: 1 + 1: 0 + }[B] + + export type Extends = [A1] extends [never] + ? 0 // anything \`never\` is false + : A1 extends A2 + ? 1 + : 0 + + export type Has = Not< + Extends, U1> + > + + export type Or = { + 0: { + 0: 0 + 1: 1 + } + 1: { + 0: 1 + 1: 1 + } + }[B1][B2] + + export type Keys = U extends unknown ? keyof U : never + + type Exact = + W extends unknown ? A extends Narrowable ? Cast : Cast< + {[K in keyof A]: K extends keyof W ? Exact : never}, + {[K in keyof W]: K extends keyof A ? Exact : W[K]}> + : never; + + type Narrowable = string | number | boolean | bigint; + + type Cast = A extends B ? A : B; + + export const type: unique symbol; + + export function validator(): (select: Exact) => S; + + /** + * Used by group by + */ + + export type GetScalarType = O extends object ? { + [P in keyof T]: P extends keyof O + ? O[P] + : never + } : never + + type FieldPaths< + T, + U = Omit + > = IsObject extends True ? U : T + + type GetHavingFields = { + [K in keyof T]: Or< + Or, Extends<'AND', K>>, + Extends<'NOT', K> + > extends True + ? // infer is only needed to not hit TS limit + // based on the brilliant idea of Pierre-Antoine Mills + // https://github.com/microsoft/TypeScript/issues/30188#issuecomment-478938437 + T[K] extends infer TK + ? GetHavingFields extends object ? Merge> : never> + : never + : {} extends FieldPaths + ? never + : K + }[keyof T] + + /** + * Convert tuple to union + */ + type _TupleToUnion = T extends (infer E)[] ? E : never + type TupleToUnion = _TupleToUnion + type MaybeTupleToUnion = T extends any[] ? TupleToUnion : T + + /** + * Like \`Pick\`, but with an array + */ + type PickArray> = Prisma__Pick> + + /** + * Exclude all keys with underscores + */ + type ExcludeUnderscoreKeys = T extends \`_\${string}\` ? never : T + + class PrismaClientFetcher { + private readonly prisma; + private readonly debug; + private readonly hooks?; + constructor(prisma: PrismaClient, debug?: boolean, hooks?: Hooks | undefined); + request(document: any, dataPath?: string[], rootField?: string, typeName?: string, isList?: boolean, callsite?: string): Promise; + sanitizeMessage(message: string): string; + protected unpack(document: any, data: any, path: string[], rootField?: string, isList?: boolean): any; + } + + export const ModelName: { + Post: 'Post', + User: 'User', + EmbedHolder: 'EmbedHolder', + M: 'M', + N: 'N', + OneOptional: 'OneOptional', + ManyRequired: 'ManyRequired', + OptionalSide1: 'OptionalSide1', + OptionalSide2: 'OptionalSide2', + A: 'A', + B: 'B', + C: 'C', + D: 'D', + E: 'E' + }; + + export type ModelName = (typeof ModelName)[keyof typeof ModelName] + + + export type Datasources = { + db?: Datasource + } + + export type RejectOnNotFound = boolean | ((error: Error) => Error) + export type RejectPerModel = { [P in ModelName]?: RejectOnNotFound } + export type RejectPerOperation = { [P in "findUnique" | "findFirst"]?: RejectPerModel | RejectOnNotFound } + type IsReject = T extends true ? True : T extends (err: Error) => Error ? True : False + export type HasReject< + GlobalRejectSettings extends Prisma.PrismaClientOptions['rejectOnNotFound'], + LocalRejectSettings, + Action extends PrismaAction, + Model extends ModelName + > = LocalRejectSettings extends RejectOnNotFound + ? IsReject + : GlobalRejectSettings extends RejectPerOperation + ? Action extends keyof GlobalRejectSettings + ? GlobalRejectSettings[Action] extends RejectOnNotFound + ? IsReject + : GlobalRejectSettings[Action] extends RejectPerModel + ? Model extends keyof GlobalRejectSettings[Action] + ? IsReject + : False + : False + : False + : IsReject + export type ErrorFormat = 'pretty' | 'colorless' | 'minimal' + + export interface PrismaClientOptions { + /** + * Configure findUnique/findFirst to throw an error if the query returns null. + * * @example + * \`\`\` + * // Reject on both findUnique/findFirst + * rejectOnNotFound: true + * // Reject only on findFirst with a custom error + * rejectOnNotFound: { findFirst: (err) => new Error("Custom Error")} + * // Reject on user.findUnique with a custom error + * rejectOnNotFound: { findUnique: {User: (err) => new Error("User not found")}} + * \`\`\` + */ + rejectOnNotFound?: RejectOnNotFound | RejectPerOperation + /** + * Overwrites the datasource url from your prisma.schema file + */ + datasources?: Datasources + + /** + * @default "colorless" + */ + errorFormat?: ErrorFormat + + /** + * @example + * \`\`\` + * // Defaults to stdout + * log: ['query', 'info', 'warn', 'error'] + * + * // Emit as events + * log: [ + * { emit: 'stdout', level: 'query' }, + * { emit: 'stdout', level: 'info' }, + * { emit: 'stdout', level: 'warn' } + * { emit: 'stdout', level: 'error' } + * ] + * \`\`\` + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/logging#the-log-option). + */ + log?: Array + } + + export type Hooks = { + beforeRequest?: (options: { query: string, path: string[], rootField?: string, typeName?: string, document: any }) => any + } + + /* Types for Logging */ + export type LogLevel = 'info' | 'query' | 'warn' | 'error' + export type LogDefinition = { + level: LogLevel + emit: 'stdout' | 'event' + } + + export type GetLogType = T extends LogDefinition ? T['emit'] extends 'event' ? T['level'] : never : never + export type GetEvents = T extends Array ? + GetLogType | GetLogType | GetLogType | GetLogType + : never + + export type QueryEvent = { + timestamp: Date + query: string + params: string + duration: number + target: string + } + + export type LogEvent = { + timestamp: Date + message: string + target: string + } + /* End Types for Logging */ + + + export type PrismaAction = + | 'findUnique' + | 'findMany' + | 'findFirst' + | 'create' + | 'createMany' + | 'update' + | 'updateMany' + | 'upsert' + | 'delete' + | 'deleteMany' + | 'executeRaw' + | 'queryRaw' + | 'aggregate' + | 'count' + | 'runCommandRaw' + + /** + * These options are being passed in to the middleware as "params" + */ + export type MiddlewareParams = { + model?: ModelName + action: PrismaAction + args: any + dataPath: string[] + runInTransaction: boolean + } + + /** + * The \`T\` type makes sure, that the \`return proceed\` is not forgotten in the middleware implementation + */ + export type Middleware = ( + params: MiddlewareParams, + next: (params: MiddlewareParams) => Promise, + ) => Promise + + // tested in getLogLevel.test.ts + export function getLogLevel(log: Array): LogLevel | undefined; + export type Datasource = { + url?: string + } + + /** + * Count Types + */ + + + /** + * Count Type UserCountOutputType + */ + + + export type UserCountOutputType = { + posts: number + } + + export type UserCountOutputTypeSelect = { + posts?: boolean + } + + export type UserCountOutputTypeGetPayload< + S extends boolean | null | undefined | UserCountOutputTypeArgs, + U = keyof S + > = S extends true + ? UserCountOutputType + : S extends undefined + ? never + : S extends UserCountOutputTypeArgs + ?'include' extends U + ? UserCountOutputType + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof UserCountOutputType ? UserCountOutputType[P] : never + } + : UserCountOutputType + : UserCountOutputType + + + + + // Custom InputTypes + + /** + * UserCountOutputType without action + */ + export type UserCountOutputTypeArgs = { + /** + * Select specific fields to fetch from the UserCountOutputType + * + **/ + select?: UserCountOutputTypeSelect | null + } + + + + /** + * Count Type EmbedHolderCountOutputType + */ + + + export type EmbedHolderCountOutputType = { + User: number + } + + export type EmbedHolderCountOutputTypeSelect = { + User?: boolean + } + + export type EmbedHolderCountOutputTypeGetPayload< + S extends boolean | null | undefined | EmbedHolderCountOutputTypeArgs, + U = keyof S + > = S extends true + ? EmbedHolderCountOutputType + : S extends undefined + ? never + : S extends EmbedHolderCountOutputTypeArgs + ?'include' extends U + ? EmbedHolderCountOutputType + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof EmbedHolderCountOutputType ? EmbedHolderCountOutputType[P] : never + } + : EmbedHolderCountOutputType + : EmbedHolderCountOutputType + + + + + // Custom InputTypes + + /** + * EmbedHolderCountOutputType without action + */ + export type EmbedHolderCountOutputTypeArgs = { + /** + * Select specific fields to fetch from the EmbedHolderCountOutputType + * + **/ + select?: EmbedHolderCountOutputTypeSelect | null + } + + + + /** + * Count Type MCountOutputType + */ + + + export type MCountOutputType = { + n: number + } + + export type MCountOutputTypeSelect = { + n?: boolean + } + + export type MCountOutputTypeGetPayload< + S extends boolean | null | undefined | MCountOutputTypeArgs, + U = keyof S + > = S extends true + ? MCountOutputType + : S extends undefined + ? never + : S extends MCountOutputTypeArgs + ?'include' extends U + ? MCountOutputType + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof MCountOutputType ? MCountOutputType[P] : never + } + : MCountOutputType + : MCountOutputType + + + + + // Custom InputTypes + + /** + * MCountOutputType without action + */ + export type MCountOutputTypeArgs = { + /** + * Select specific fields to fetch from the MCountOutputType + * + **/ + select?: MCountOutputTypeSelect | null + } + + + + /** + * Count Type NCountOutputType + */ + + + export type NCountOutputType = { + m: number + } + + export type NCountOutputTypeSelect = { + m?: boolean + } + + export type NCountOutputTypeGetPayload< + S extends boolean | null | undefined | NCountOutputTypeArgs, + U = keyof S + > = S extends true + ? NCountOutputType + : S extends undefined + ? never + : S extends NCountOutputTypeArgs + ?'include' extends U + ? NCountOutputType + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof NCountOutputType ? NCountOutputType[P] : never + } + : NCountOutputType + : NCountOutputType + + + + + // Custom InputTypes + + /** + * NCountOutputType without action + */ + export type NCountOutputTypeArgs = { + /** + * Select specific fields to fetch from the NCountOutputType + * + **/ + select?: NCountOutputTypeSelect | null + } + + + + /** + * Count Type OneOptionalCountOutputType + */ + + + export type OneOptionalCountOutputType = { + many: number + } + + export type OneOptionalCountOutputTypeSelect = { + many?: boolean + } + + export type OneOptionalCountOutputTypeGetPayload< + S extends boolean | null | undefined | OneOptionalCountOutputTypeArgs, + U = keyof S + > = S extends true + ? OneOptionalCountOutputType + : S extends undefined + ? never + : S extends OneOptionalCountOutputTypeArgs + ?'include' extends U + ? OneOptionalCountOutputType + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof OneOptionalCountOutputType ? OneOptionalCountOutputType[P] : never + } + : OneOptionalCountOutputType + : OneOptionalCountOutputType + + + + + // Custom InputTypes + + /** + * OneOptionalCountOutputType without action + */ + export type OneOptionalCountOutputTypeArgs = { + /** + * Select specific fields to fetch from the OneOptionalCountOutputType + * + **/ + select?: OneOptionalCountOutputTypeSelect | null + } + + + + /** + * Models + */ + + /** + * Model Embed + */ + + + + + + export type EmbedSelect = { + text?: boolean + boolean?: boolean + embedEmbedList?: boolean | EmbedEmbedArgs + requiredEmbedEmbed?: boolean | EmbedEmbedArgs + optionalEmbedEmbed?: boolean | EmbedEmbedArgs + } + + export type EmbedInclude = { + + } + + export type EmbedGetPayload< + S extends boolean | null | undefined | EmbedArgs, + U = keyof S + > = S extends true + ? Embed + : S extends undefined + ? never + : S extends EmbedArgs + ?'include' extends U + ? Embed & { + [P in TrueKeys]: + P extends 'embedEmbedList' ? Array < EmbedEmbedGetPayload> : + P extends 'requiredEmbedEmbed' ? EmbedEmbedGetPayload : + P extends 'optionalEmbedEmbed' ? EmbedEmbedGetPayload | null : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'embedEmbedList' ? Array < EmbedEmbedGetPayload> : + P extends 'requiredEmbedEmbed' ? EmbedEmbedGetPayload : + P extends 'optionalEmbedEmbed' ? EmbedEmbedGetPayload | null : P extends keyof Embed ? Embed[P] : never + } + : Embed + : Embed + + + + export interface EmbedDelegate { + + + + + + } + + /** + * The delegate class that acts as a "Promise-like" for Embed. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__EmbedClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + embedEmbedList(args?: Subset): CheckSelect>, PrismaPromise>>>; + + requiredEmbedEmbed(args?: Subset): CheckSelect, Prisma__EmbedEmbedClient | null >>; + + optionalEmbedEmbed(args?: Subset): CheckSelect, Prisma__EmbedEmbedClient | null >>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * Embed without action + */ + export type EmbedArgs = { + /** + * Select specific fields to fetch from the Embed + * + **/ + select?: EmbedSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedInclude | null + } + + + + /** + * Model EmbedEmbed + */ + + + + + + export type EmbedEmbedSelect = { + text?: boolean + boolean?: boolean + } + + export type EmbedEmbedGetPayload< + S extends boolean | null | undefined | EmbedEmbedArgs, + U = keyof S + > = S extends true + ? EmbedEmbed + : S extends undefined + ? never + : S extends EmbedEmbedArgs + ?'include' extends U + ? EmbedEmbed + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof EmbedEmbed ? EmbedEmbed[P] : never + } + : EmbedEmbed + : EmbedEmbed + + + + export interface EmbedEmbedDelegate { + + + + + + } + + /** + * The delegate class that acts as a "Promise-like" for EmbedEmbed. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__EmbedEmbedClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * EmbedEmbed without action + */ + export type EmbedEmbedArgs = { + /** + * Select specific fields to fetch from the EmbedEmbed + * + **/ + select?: EmbedEmbedSelect | null + } + + + + /** + * Model Post + */ + + + export type AggregatePost = { + _count: PostCountAggregateOutputType | null + _avg: PostAvgAggregateOutputType | null + _sum: PostSumAggregateOutputType | null + _min: PostMinAggregateOutputType | null + _max: PostMaxAggregateOutputType | null + } + + export type PostAvgAggregateOutputType = { + authorId: number | null + } + + export type PostSumAggregateOutputType = { + authorId: number | null + } + + export type PostMinAggregateOutputType = { + id: string | null + createdAt: Date | null + title: string | null + content: string | null + published: boolean | null + authorId: number | null + } + + export type PostMaxAggregateOutputType = { + id: string | null + createdAt: Date | null + title: string | null + content: string | null + published: boolean | null + authorId: number | null + } + + export type PostCountAggregateOutputType = { + id: number + createdAt: number + title: number + content: number + published: number + authorId: number + _all: number + } + + + export type PostAvgAggregateInputType = { + authorId?: true + } + + export type PostSumAggregateInputType = { + authorId?: true + } + + export type PostMinAggregateInputType = { + id?: true + createdAt?: true + title?: true + content?: true + published?: true + authorId?: true + } + + export type PostMaxAggregateInputType = { + id?: true + createdAt?: true + title?: true + content?: true + published?: true + authorId?: true + } + + export type PostCountAggregateInputType = { + id?: true + createdAt?: true + title?: true + content?: true + published?: true + authorId?: true + _all?: true + } + + export type PostAggregateArgs = { + /** + * Filter which Post to aggregate. + * + **/ + where?: PostWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Posts to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: PostWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` Posts from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` Posts. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Posts + **/ + _count?: true | PostCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: PostAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: PostSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: PostMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: PostMaxAggregateInputType + } + + export type GetPostAggregateType = { + [P in keyof T & keyof AggregatePost]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type PostGroupByArgs = { + where?: PostWhereInput + orderBy?: Enumerable + by: Array + having?: PostScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: PostCountAggregateInputType | true + _avg?: PostAvgAggregateInputType + _sum?: PostSumAggregateInputType + _min?: PostMinAggregateInputType + _max?: PostMaxAggregateInputType + } + + + export type PostGroupByOutputType = { + id: string + createdAt: Date + title: string + content: string | null + published: boolean + authorId: number + _count: PostCountAggregateOutputType | null + _avg: PostAvgAggregateOutputType | null + _sum: PostSumAggregateOutputType | null + _min: PostMinAggregateOutputType | null + _max: PostMaxAggregateOutputType | null + } + + type GetPostGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof PostGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type PostSelect = { + id?: boolean + createdAt?: boolean + title?: boolean + content?: boolean + published?: boolean + author?: boolean | UserArgs + authorId?: boolean + } + + export type PostInclude = { + author?: boolean | UserArgs + } + + export type PostGetPayload< + S extends boolean | null | undefined | PostArgs, + U = keyof S + > = S extends true + ? Post + : S extends undefined + ? never + : S extends PostArgs | PostFindManyArgs + ?'include' extends U + ? Post & { + [P in TrueKeys]: + P extends 'author' ? UserGetPayload : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'author' ? UserGetPayload : P extends keyof Post ? Post[P] : never + } + : Post + : Post + + + type PostCountArgs = Merge< + Omit & { + select?: PostCountAggregateInputType | true + } + > + + export interface PostDelegate { + /** + * Find zero or one Post that matches the filter. + * @param {PostFindUniqueArgs} args - Arguments to find a Post + * @example + * // Get one Post + * const post = await prisma.post.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__PostClient>> : CheckSelect, Prisma__PostClient | null >> + + /** + * Find the first Post that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PostFindFirstArgs} args - Arguments to find a Post + * @example + * // Get one Post + * const post = await prisma.post.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__PostClient>> : CheckSelect, Prisma__PostClient | null >> + + /** + * Find zero or more Posts that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PostFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Posts + * const posts = await prisma.post.findMany() + * + * // Get first 10 Posts + * const posts = await prisma.post.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const postWithIdOnly = await prisma.post.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a Post. + * @param {PostCreateArgs} args - Arguments to create a Post. + * @example + * // Create one Post + * const Post = await prisma.post.create({ + * data: { + * // ... data to create a Post + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__PostClient>> + + /** + * Create many Posts. + * @param {PostCreateManyArgs} args - Arguments to create many Posts. + * @example + * // Create many Posts + * const post = await prisma.post.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a Post. + * @param {PostDeleteArgs} args - Arguments to delete one Post. + * @example + * // Delete one Post + * const Post = await prisma.post.delete({ + * where: { + * // ... filter to delete one Post + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__PostClient>> + + /** + * Update one Post. + * @param {PostUpdateArgs} args - Arguments to update one Post. + * @example + * // Update one Post + * const post = await prisma.post.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__PostClient>> + + /** + * Delete zero or more Posts. + * @param {PostDeleteManyArgs} args - Arguments to filter Posts to delete. + * @example + * // Delete a few Posts + * const { count } = await prisma.post.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Posts. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PostUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Posts + * const post = await prisma.post.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one Post. + * @param {PostUpsertArgs} args - Arguments to update or create a Post. + * @example + * // Update or create a Post + * const post = await prisma.post.upsert({ + * create: { + * // ... data to create a Post + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Post we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__PostClient>> + + /** + * Find zero or more Posts that matches the filter. + * @param {PostFindRawArgs} args - Select which filters you would like to apply. + * @example + * const post = await prisma.post.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: PostFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a Post. + * @param {PostAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const post = await prisma.post.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: PostAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Posts. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PostCountArgs} args - Arguments to filter Posts to count. + * @example + * // Count the number of Posts + * const count = await prisma.post.count({ + * where: { + * // ... the filter for the Posts we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Post. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PostAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by Post. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PostGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends PostGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: PostGroupByArgs['orderBy'] } + : { orderBy?: PostGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetPostGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for Post. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__PostClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + author(args?: Subset): CheckSelect, Prisma__UserClient | null >>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * Post findUnique + */ + export type PostFindUniqueArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * Throw an Error if a Post can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which Post to fetch. + * + **/ + where: PostWhereUniqueInput + } + + + /** + * Post findFirst + */ + export type PostFindFirstArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * Throw an Error if a Post can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which Post to fetch. + * + **/ + where?: PostWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Posts to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Posts. + * + **/ + cursor?: PostWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` Posts from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` Posts. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Posts. + * + **/ + distinct?: Enumerable + } + + + /** + * Post findMany + */ + export type PostFindManyArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * Filter, which Posts to fetch. + * + **/ + where?: PostWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Posts to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Posts. + * + **/ + cursor?: PostWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` Posts from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` Posts. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * Post create + */ + export type PostCreateArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * The data needed to create a Post. + * + **/ + data: XOR + } + + + /** + * Post createMany + */ + export type PostCreateManyArgs = { + /** + * The data used to create many Posts. + * + **/ + data: Enumerable + } + + + /** + * Post update + */ + export type PostUpdateArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * The data needed to update a Post. + * + **/ + data: XOR + /** + * Choose, which Post to update. + * + **/ + where: PostWhereUniqueInput + } + + + /** + * Post updateMany + */ + export type PostUpdateManyArgs = { + /** + * The data used to update Posts. + * + **/ + data: XOR + /** + * Filter which Posts to update + * + **/ + where?: PostWhereInput + } + + + /** + * Post upsert + */ + export type PostUpsertArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * The filter to search for the Post to update in case it exists. + * + **/ + where: PostWhereUniqueInput + /** + * In case the Post found by the \`where\` argument doesn't exist, create a new Post with this data. + * + **/ + create: XOR + /** + * In case the Post was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * Post delete + */ + export type PostDeleteArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + /** + * Filter which Post to delete. + * + **/ + where: PostWhereUniqueInput + } + + + /** + * Post deleteMany + */ + export type PostDeleteManyArgs = { + /** + * Filter which Posts to delete + * + **/ + where?: PostWhereInput + } + + + /** + * Post findRaw + */ + export type PostFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * Post aggregateRaw + */ + export type PostAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * Post without action + */ + export type PostArgs = { + /** + * Select specific fields to fetch from the Post + * + **/ + select?: PostSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: PostInclude | null + } + + + + /** + * Model User + */ + + + export type AggregateUser = { + _count: UserCountAggregateOutputType | null + _avg: UserAvgAggregateOutputType | null + _sum: UserSumAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null + } + + export type UserAvgAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type UserSumAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type UserMinAggregateOutputType = { + id: string | null + email: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + embedHolderId: string | null + } + + export type UserMaxAggregateOutputType = { + id: string | null + email: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + embedHolderId: string | null + } + + export type UserCountAggregateOutputType = { + id: number + email: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + embedHolderId: number + _all: number + } + + + export type UserAvgAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type UserSumAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type UserMinAggregateInputType = { + id?: true + email?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + embedHolderId?: true + } + + export type UserMaxAggregateInputType = { + id?: true + email?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + embedHolderId?: true + } + + export type UserCountAggregateInputType = { + id?: true + email?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + embedHolderId?: true + _all?: true + } + + export type UserAggregateArgs = { + /** + * Filter which User to aggregate. + * + **/ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` Users from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` Users. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Users + **/ + _count?: true | UserCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: UserAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: UserSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: UserMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: UserMaxAggregateInputType + } + + export type GetUserAggregateType = { + [P in keyof T & keyof AggregateUser]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type UserGroupByArgs = { + where?: UserWhereInput + orderBy?: Enumerable + by: Array + having?: UserScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: UserCountAggregateInputType | true + _avg?: UserAvgAggregateInputType + _sum?: UserSumAggregateInputType + _min?: UserMinAggregateInputType + _max?: UserMaxAggregateInputType + } + + + export type UserGroupByOutputType = { + id: string + email: string + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + embedHolderId: string + _count: UserCountAggregateOutputType | null + _avg: UserAvgAggregateOutputType | null + _sum: UserSumAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null + } + + type GetUserGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof UserGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type UserSelect = { + id?: boolean + email?: boolean + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + posts?: boolean | PostFindManyArgs + embedHolder?: boolean | EmbedHolderArgs + embedHolderId?: boolean + _count?: boolean | UserCountOutputTypeArgs + } + + export type UserInclude = { + posts?: boolean | PostFindManyArgs + embedHolder?: boolean | EmbedHolderArgs + _count?: boolean | UserCountOutputTypeArgs + } + + export type UserGetPayload< + S extends boolean | null | undefined | UserArgs, + U = keyof S + > = S extends true + ? User + : S extends undefined + ? never + : S extends UserArgs | UserFindManyArgs + ?'include' extends U + ? User & { + [P in TrueKeys]: + P extends 'posts' ? Array < PostGetPayload> : + P extends 'embedHolder' ? EmbedHolderGetPayload : + P extends '_count' ? UserCountOutputTypeGetPayload : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'posts' ? Array < PostGetPayload> : + P extends 'embedHolder' ? EmbedHolderGetPayload : + P extends '_count' ? UserCountOutputTypeGetPayload : P extends keyof User ? User[P] : never + } + : User + : User + + + type UserCountArgs = Merge< + Omit & { + select?: UserCountAggregateInputType | true + } + > + + export interface UserDelegate { + /** + * Find zero or one User that matches the filter. + * @param {UserFindUniqueArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__UserClient>> : CheckSelect, Prisma__UserClient | null >> + + /** + * Find the first User that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__UserClient>> : CheckSelect, Prisma__UserClient | null >> + + /** + * Find zero or more Users that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Users + * const users = await prisma.user.findMany() + * + * // Get first 10 Users + * const users = await prisma.user.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const userWithIdOnly = await prisma.user.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a User. + * @param {UserCreateArgs} args - Arguments to create a User. + * @example + * // Create one User + * const User = await prisma.user.create({ + * data: { + * // ... data to create a User + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__UserClient>> + + /** + * Create many Users. + * @param {UserCreateManyArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a User. + * @param {UserDeleteArgs} args - Arguments to delete one User. + * @example + * // Delete one User + * const User = await prisma.user.delete({ + * where: { + * // ... filter to delete one User + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__UserClient>> + + /** + * Update one User. + * @param {UserUpdateArgs} args - Arguments to update one User. + * @example + * // Update one User + * const user = await prisma.user.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__UserClient>> + + /** + * Delete zero or more Users. + * @param {UserDeleteManyArgs} args - Arguments to filter Users to delete. + * @example + * // Delete a few Users + * const { count } = await prisma.user.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Users. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Users + * const user = await prisma.user.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one User. + * @param {UserUpsertArgs} args - Arguments to update or create a User. + * @example + * // Update or create a User + * const user = await prisma.user.upsert({ + * create: { + * // ... data to create a User + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the User we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__UserClient>> + + /** + * Find zero or more Users that matches the filter. + * @param {UserFindRawArgs} args - Select which filters you would like to apply. + * @example + * const user = await prisma.user.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: UserFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a User. + * @param {UserAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const user = await prisma.user.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: UserAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Users. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserCountArgs} args - Arguments to filter Users to count. + * @example + * // Count the number of Users + * const count = await prisma.user.count({ + * where: { + * // ... the filter for the Users we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a User. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by User. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends UserGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: UserGroupByArgs['orderBy'] } + : { orderBy?: UserGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for User. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__UserClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + posts(args?: Subset): CheckSelect>, PrismaPromise>>>; + + embedHolder(args?: Subset): CheckSelect, Prisma__EmbedHolderClient | null >>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * User findUnique + */ + export type UserFindUniqueArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * Throw an Error if a User can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which User to fetch. + * + **/ + where: UserWhereUniqueInput + } + + + /** + * User findFirst + */ + export type UserFindFirstArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * Throw an Error if a User can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which User to fetch. + * + **/ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + * + **/ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` Users from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` Users. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + * + **/ + distinct?: Enumerable + } + + + /** + * User findMany + */ + export type UserFindManyArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * Filter, which Users to fetch. + * + **/ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Users. + * + **/ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` Users from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` Users. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * User create + */ + export type UserCreateArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * The data needed to create a User. + * + **/ + data: XOR + } + + + /** + * User createMany + */ + export type UserCreateManyArgs = { + /** + * The data used to create many Users. + * + **/ + data: Enumerable + } + + + /** + * User update + */ + export type UserUpdateArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * The data needed to update a User. + * + **/ + data: XOR + /** + * Choose, which User to update. + * + **/ + where: UserWhereUniqueInput + } + + + /** + * User updateMany + */ + export type UserUpdateManyArgs = { + /** + * The data used to update Users. + * + **/ + data: XOR + /** + * Filter which Users to update + * + **/ + where?: UserWhereInput + } + + + /** + * User upsert + */ + export type UserUpsertArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * The filter to search for the User to update in case it exists. + * + **/ + where: UserWhereUniqueInput + /** + * In case the User found by the \`where\` argument doesn't exist, create a new User with this data. + * + **/ + create: XOR + /** + * In case the User was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * User delete + */ + export type UserDeleteArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + /** + * Filter which User to delete. + * + **/ + where: UserWhereUniqueInput + } + + + /** + * User deleteMany + */ + export type UserDeleteManyArgs = { + /** + * Filter which Users to delete + * + **/ + where?: UserWhereInput + } + + + /** + * User findRaw + */ + export type UserFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * User aggregateRaw + */ + export type UserAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * User without action + */ + export type UserArgs = { + /** + * Select specific fields to fetch from the User + * + **/ + select?: UserSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: UserInclude | null + } + + + + /** + * Model EmbedHolder + */ + + + export type AggregateEmbedHolder = { + _count: EmbedHolderCountAggregateOutputType | null + _min: EmbedHolderMinAggregateOutputType | null + _max: EmbedHolderMaxAggregateOutputType | null + } + + export type EmbedHolderMinAggregateOutputType = { + id: string | null + time: Date | null + text: string | null + boolean: boolean | null + } + + export type EmbedHolderMaxAggregateOutputType = { + id: string | null + time: Date | null + text: string | null + boolean: boolean | null + } + + export type EmbedHolderCountAggregateOutputType = { + id: number + time: number + text: number + boolean: number + _all: number + } + + + export type EmbedHolderMinAggregateInputType = { + id?: true + time?: true + text?: true + boolean?: true + } + + export type EmbedHolderMaxAggregateInputType = { + id?: true + time?: true + text?: true + boolean?: true + } + + export type EmbedHolderCountAggregateInputType = { + id?: true + time?: true + text?: true + boolean?: true + _all?: true + } + + export type EmbedHolderAggregateArgs = { + /** + * Filter which EmbedHolder to aggregate. + * + **/ + where?: EmbedHolderWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of EmbedHolders to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: EmbedHolderWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` EmbedHolders from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` EmbedHolders. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned EmbedHolders + **/ + _count?: true | EmbedHolderCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: EmbedHolderMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: EmbedHolderMaxAggregateInputType + } + + export type GetEmbedHolderAggregateType = { + [P in keyof T & keyof AggregateEmbedHolder]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type EmbedHolderGroupByArgs = { + where?: EmbedHolderWhereInput + orderBy?: Enumerable + by: Array + having?: EmbedHolderScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: EmbedHolderCountAggregateInputType | true + _min?: EmbedHolderMinAggregateInputType + _max?: EmbedHolderMaxAggregateInputType + } + + + export type EmbedHolderGroupByOutputType = { + id: string + time: Date + text: string + boolean: boolean + _count: EmbedHolderCountAggregateOutputType | null + _min: EmbedHolderMinAggregateOutputType | null + _max: EmbedHolderMaxAggregateOutputType | null + } + + type GetEmbedHolderGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof EmbedHolderGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type EmbedHolderSelect = { + embedList?: boolean | EmbedArgs + requiredEmbed?: boolean | EmbedArgs + optionalEmbed?: boolean | EmbedArgs + id?: boolean + time?: boolean + text?: boolean + boolean?: boolean + User?: boolean | UserFindManyArgs + _count?: boolean | EmbedHolderCountOutputTypeArgs + } + + export type EmbedHolderInclude = { + User?: boolean | UserFindManyArgs + _count?: boolean | EmbedHolderCountOutputTypeArgs + } + + export type EmbedHolderGetPayload< + S extends boolean | null | undefined | EmbedHolderArgs, + U = keyof S + > = S extends true + ? EmbedHolder + : S extends undefined + ? never + : S extends EmbedHolderArgs | EmbedHolderFindManyArgs + ?'include' extends U + ? EmbedHolder & { + [P in TrueKeys]: + P extends 'embedList' ? Array < EmbedGetPayload> : + P extends 'requiredEmbed' ? EmbedGetPayload : + P extends 'optionalEmbed' ? EmbedGetPayload | null : + P extends 'User' ? Array < UserGetPayload> : + P extends '_count' ? EmbedHolderCountOutputTypeGetPayload : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'embedList' ? Array < EmbedGetPayload> : + P extends 'requiredEmbed' ? EmbedGetPayload : + P extends 'optionalEmbed' ? EmbedGetPayload | null : + P extends 'User' ? Array < UserGetPayload> : + P extends '_count' ? EmbedHolderCountOutputTypeGetPayload : P extends keyof EmbedHolder ? EmbedHolder[P] : never + } + : EmbedHolder + : EmbedHolder + + + type EmbedHolderCountArgs = Merge< + Omit & { + select?: EmbedHolderCountAggregateInputType | true + } + > + + export interface EmbedHolderDelegate { + /** + * Find zero or one EmbedHolder that matches the filter. + * @param {EmbedHolderFindUniqueArgs} args - Arguments to find a EmbedHolder + * @example + * // Get one EmbedHolder + * const embedHolder = await prisma.embedHolder.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__EmbedHolderClient>> : CheckSelect, Prisma__EmbedHolderClient | null >> + + /** + * Find the first EmbedHolder that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EmbedHolderFindFirstArgs} args - Arguments to find a EmbedHolder + * @example + * // Get one EmbedHolder + * const embedHolder = await prisma.embedHolder.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__EmbedHolderClient>> : CheckSelect, Prisma__EmbedHolderClient | null >> + + /** + * Find zero or more EmbedHolders that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EmbedHolderFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all EmbedHolders + * const embedHolders = await prisma.embedHolder.findMany() + * + * // Get first 10 EmbedHolders + * const embedHolders = await prisma.embedHolder.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const embedHolderWithIdOnly = await prisma.embedHolder.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a EmbedHolder. + * @param {EmbedHolderCreateArgs} args - Arguments to create a EmbedHolder. + * @example + * // Create one EmbedHolder + * const EmbedHolder = await prisma.embedHolder.create({ + * data: { + * // ... data to create a EmbedHolder + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__EmbedHolderClient>> + + /** + * Create many EmbedHolders. + * @param {EmbedHolderCreateManyArgs} args - Arguments to create many EmbedHolders. + * @example + * // Create many EmbedHolders + * const embedHolder = await prisma.embedHolder.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a EmbedHolder. + * @param {EmbedHolderDeleteArgs} args - Arguments to delete one EmbedHolder. + * @example + * // Delete one EmbedHolder + * const EmbedHolder = await prisma.embedHolder.delete({ + * where: { + * // ... filter to delete one EmbedHolder + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__EmbedHolderClient>> + + /** + * Update one EmbedHolder. + * @param {EmbedHolderUpdateArgs} args - Arguments to update one EmbedHolder. + * @example + * // Update one EmbedHolder + * const embedHolder = await prisma.embedHolder.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__EmbedHolderClient>> + + /** + * Delete zero or more EmbedHolders. + * @param {EmbedHolderDeleteManyArgs} args - Arguments to filter EmbedHolders to delete. + * @example + * // Delete a few EmbedHolders + * const { count } = await prisma.embedHolder.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more EmbedHolders. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EmbedHolderUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many EmbedHolders + * const embedHolder = await prisma.embedHolder.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one EmbedHolder. + * @param {EmbedHolderUpsertArgs} args - Arguments to update or create a EmbedHolder. + * @example + * // Update or create a EmbedHolder + * const embedHolder = await prisma.embedHolder.upsert({ + * create: { + * // ... data to create a EmbedHolder + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the EmbedHolder we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__EmbedHolderClient>> + + /** + * Find zero or more EmbedHolders that matches the filter. + * @param {EmbedHolderFindRawArgs} args - Select which filters you would like to apply. + * @example + * const embedHolder = await prisma.embedHolder.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: EmbedHolderFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a EmbedHolder. + * @param {EmbedHolderAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const embedHolder = await prisma.embedHolder.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: EmbedHolderAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of EmbedHolders. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EmbedHolderCountArgs} args - Arguments to filter EmbedHolders to count. + * @example + * // Count the number of EmbedHolders + * const count = await prisma.embedHolder.count({ + * where: { + * // ... the filter for the EmbedHolders we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a EmbedHolder. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EmbedHolderAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by EmbedHolder. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EmbedHolderGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends EmbedHolderGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: EmbedHolderGroupByArgs['orderBy'] } + : { orderBy?: EmbedHolderGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetEmbedHolderGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for EmbedHolder. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__EmbedHolderClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + embedList(args?: Subset): CheckSelect>, PrismaPromise>>>; + + requiredEmbed(args?: Subset): CheckSelect, Prisma__EmbedClient | null >>; + + optionalEmbed(args?: Subset): CheckSelect, Prisma__EmbedClient | null >>; + + User(args?: Subset): CheckSelect>, PrismaPromise>>>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * EmbedHolder findUnique + */ + export type EmbedHolderFindUniqueArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * Throw an Error if a EmbedHolder can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which EmbedHolder to fetch. + * + **/ + where: EmbedHolderWhereUniqueInput + } + + + /** + * EmbedHolder findFirst + */ + export type EmbedHolderFindFirstArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * Throw an Error if a EmbedHolder can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which EmbedHolder to fetch. + * + **/ + where?: EmbedHolderWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of EmbedHolders to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for EmbedHolders. + * + **/ + cursor?: EmbedHolderWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` EmbedHolders from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` EmbedHolders. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of EmbedHolders. + * + **/ + distinct?: Enumerable + } + + + /** + * EmbedHolder findMany + */ + export type EmbedHolderFindManyArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * Filter, which EmbedHolders to fetch. + * + **/ + where?: EmbedHolderWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of EmbedHolders to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing EmbedHolders. + * + **/ + cursor?: EmbedHolderWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` EmbedHolders from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` EmbedHolders. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * EmbedHolder create + */ + export type EmbedHolderCreateArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * The data needed to create a EmbedHolder. + * + **/ + data: XOR + } + + + /** + * EmbedHolder createMany + */ + export type EmbedHolderCreateManyArgs = { + /** + * The data used to create many EmbedHolders. + * + **/ + data: Enumerable + } + + + /** + * EmbedHolder update + */ + export type EmbedHolderUpdateArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * The data needed to update a EmbedHolder. + * + **/ + data: XOR + /** + * Choose, which EmbedHolder to update. + * + **/ + where: EmbedHolderWhereUniqueInput + } + + + /** + * EmbedHolder updateMany + */ + export type EmbedHolderUpdateManyArgs = { + /** + * The data used to update EmbedHolders. + * + **/ + data: XOR + /** + * Filter which EmbedHolders to update + * + **/ + where?: EmbedHolderWhereInput + } + + + /** + * EmbedHolder upsert + */ + export type EmbedHolderUpsertArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * The filter to search for the EmbedHolder to update in case it exists. + * + **/ + where: EmbedHolderWhereUniqueInput + /** + * In case the EmbedHolder found by the \`where\` argument doesn't exist, create a new EmbedHolder with this data. + * + **/ + create: XOR + /** + * In case the EmbedHolder was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * EmbedHolder delete + */ + export type EmbedHolderDeleteArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + /** + * Filter which EmbedHolder to delete. + * + **/ + where: EmbedHolderWhereUniqueInput + } + + + /** + * EmbedHolder deleteMany + */ + export type EmbedHolderDeleteManyArgs = { + /** + * Filter which EmbedHolders to delete + * + **/ + where?: EmbedHolderWhereInput + } + + + /** + * EmbedHolder findRaw + */ + export type EmbedHolderFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * EmbedHolder aggregateRaw + */ + export type EmbedHolderAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * EmbedHolder without action + */ + export type EmbedHolderArgs = { + /** + * Select specific fields to fetch from the EmbedHolder + * + **/ + select?: EmbedHolderSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: EmbedHolderInclude | null + } + + + + /** + * Model M + */ + + + export type AggregateM = { + _count: MCountAggregateOutputType | null + _avg: MAvgAggregateOutputType | null + _sum: MSumAggregateOutputType | null + _min: MMinAggregateOutputType | null + _max: MMaxAggregateOutputType | null + } + + export type MAvgAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type MSumAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type MMinAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type MMaxAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type MCountAggregateOutputType = { + id: number + n_ids: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + _all: number + } + + + export type MAvgAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type MSumAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type MMinAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type MMaxAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type MCountAggregateInputType = { + id?: true + n_ids?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + _all?: true + } + + export type MAggregateArgs = { + /** + * Filter which M to aggregate. + * + **/ + where?: MWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: MWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` MS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` MS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned MS + **/ + _count?: true | MCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: MAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: MSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: MMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: MMaxAggregateInputType + } + + export type GetMAggregateType = { + [P in keyof T & keyof AggregateM]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type MGroupByArgs = { + where?: MWhereInput + orderBy?: Enumerable + by: Array + having?: MScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: MCountAggregateInputType | true + _avg?: MAvgAggregateInputType + _sum?: MSumAggregateInputType + _min?: MMinAggregateInputType + _max?: MMaxAggregateInputType + } + + + export type MGroupByOutputType = { + id: string + n_ids: string[] + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + _count: MCountAggregateOutputType | null + _avg: MAvgAggregateOutputType | null + _sum: MSumAggregateOutputType | null + _min: MMinAggregateOutputType | null + _max: MMaxAggregateOutputType | null + } + + type GetMGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof MGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type MSelect = { + id?: boolean + n_ids?: boolean + n?: boolean | NFindManyArgs + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + _count?: boolean | MCountOutputTypeArgs + } + + export type MInclude = { + n?: boolean | NFindManyArgs + _count?: boolean | MCountOutputTypeArgs + } + + export type MGetPayload< + S extends boolean | null | undefined | MArgs, + U = keyof S + > = S extends true + ? M + : S extends undefined + ? never + : S extends MArgs | MFindManyArgs + ?'include' extends U + ? M & { + [P in TrueKeys]: + P extends 'n' ? Array < NGetPayload> : + P extends '_count' ? MCountOutputTypeGetPayload : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'n' ? Array < NGetPayload> : + P extends '_count' ? MCountOutputTypeGetPayload : P extends keyof M ? M[P] : never + } + : M + : M + + + type MCountArgs = Merge< + Omit & { + select?: MCountAggregateInputType | true + } + > + + export interface MDelegate { + /** + * Find zero or one M that matches the filter. + * @param {MFindUniqueArgs} args - Arguments to find a M + * @example + * // Get one M + * const m = await prisma.m.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__MClient>> : CheckSelect, Prisma__MClient | null >> + + /** + * Find the first M that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MFindFirstArgs} args - Arguments to find a M + * @example + * // Get one M + * const m = await prisma.m.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__MClient>> : CheckSelect, Prisma__MClient | null >> + + /** + * Find zero or more Ms that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Ms + * const ms = await prisma.m.findMany() + * + * // Get first 10 Ms + * const ms = await prisma.m.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const mWithIdOnly = await prisma.m.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a M. + * @param {MCreateArgs} args - Arguments to create a M. + * @example + * // Create one M + * const M = await prisma.m.create({ + * data: { + * // ... data to create a M + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__MClient>> + + /** + * Create many Ms. + * @param {MCreateManyArgs} args - Arguments to create many Ms. + * @example + * // Create many Ms + * const m = await prisma.m.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a M. + * @param {MDeleteArgs} args - Arguments to delete one M. + * @example + * // Delete one M + * const M = await prisma.m.delete({ + * where: { + * // ... filter to delete one M + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__MClient>> + + /** + * Update one M. + * @param {MUpdateArgs} args - Arguments to update one M. + * @example + * // Update one M + * const m = await prisma.m.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__MClient>> + + /** + * Delete zero or more Ms. + * @param {MDeleteManyArgs} args - Arguments to filter Ms to delete. + * @example + * // Delete a few Ms + * const { count } = await prisma.m.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Ms. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Ms + * const m = await prisma.m.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one M. + * @param {MUpsertArgs} args - Arguments to update or create a M. + * @example + * // Update or create a M + * const m = await prisma.m.upsert({ + * create: { + * // ... data to create a M + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the M we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__MClient>> + + /** + * Find zero or more Ms that matches the filter. + * @param {MFindRawArgs} args - Select which filters you would like to apply. + * @example + * const m = await prisma.m.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: MFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a M. + * @param {MAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const m = await prisma.m.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: MAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Ms. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MCountArgs} args - Arguments to filter Ms to count. + * @example + * // Count the number of Ms + * const count = await prisma.m.count({ + * where: { + * // ... the filter for the Ms we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a M. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by M. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends MGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: MGroupByArgs['orderBy'] } + : { orderBy?: MGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetMGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for M. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__MClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + n(args?: Subset): CheckSelect>, PrismaPromise>>>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * M findUnique + */ + export type MFindUniqueArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * Throw an Error if a M can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which M to fetch. + * + **/ + where: MWhereUniqueInput + } + + + /** + * M findFirst + */ + export type MFindFirstArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * Throw an Error if a M can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which M to fetch. + * + **/ + where?: MWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for MS. + * + **/ + cursor?: MWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` MS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` MS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of MS. + * + **/ + distinct?: Enumerable + } + + + /** + * M findMany + */ + export type MFindManyArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * Filter, which MS to fetch. + * + **/ + where?: MWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing MS. + * + **/ + cursor?: MWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` MS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` MS. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * M create + */ + export type MCreateArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * The data needed to create a M. + * + **/ + data: XOR + } + + + /** + * M createMany + */ + export type MCreateManyArgs = { + /** + * The data used to create many MS. + * + **/ + data: Enumerable + } + + + /** + * M update + */ + export type MUpdateArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * The data needed to update a M. + * + **/ + data: XOR + /** + * Choose, which M to update. + * + **/ + where: MWhereUniqueInput + } + + + /** + * M updateMany + */ + export type MUpdateManyArgs = { + /** + * The data used to update MS. + * + **/ + data: XOR + /** + * Filter which MS to update + * + **/ + where?: MWhereInput + } + + + /** + * M upsert + */ + export type MUpsertArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * The filter to search for the M to update in case it exists. + * + **/ + where: MWhereUniqueInput + /** + * In case the M found by the \`where\` argument doesn't exist, create a new M with this data. + * + **/ + create: XOR + /** + * In case the M was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * M delete + */ + export type MDeleteArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + /** + * Filter which M to delete. + * + **/ + where: MWhereUniqueInput + } + + + /** + * M deleteMany + */ + export type MDeleteManyArgs = { + /** + * Filter which MS to delete + * + **/ + where?: MWhereInput + } + + + /** + * M findRaw + */ + export type MFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * M aggregateRaw + */ + export type MAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * M without action + */ + export type MArgs = { + /** + * Select specific fields to fetch from the M + * + **/ + select?: MSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: MInclude | null + } + + + + /** + * Model N + */ + + + export type AggregateN = { + _count: NCountAggregateOutputType | null + _avg: NAvgAggregateOutputType | null + _sum: NSumAggregateOutputType | null + _min: NMinAggregateOutputType | null + _max: NMaxAggregateOutputType | null + } + + export type NAvgAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type NSumAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type NMinAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type NMaxAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type NCountAggregateOutputType = { + id: number + m_ids: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + _all: number + } + + + export type NAvgAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type NSumAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type NMinAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type NMaxAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type NCountAggregateInputType = { + id?: true + m_ids?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + _all?: true + } + + export type NAggregateArgs = { + /** + * Filter which N to aggregate. + * + **/ + where?: NWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of NS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: NWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` NS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` NS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned NS + **/ + _count?: true | NCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: NAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: NSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: NMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: NMaxAggregateInputType + } + + export type GetNAggregateType = { + [P in keyof T & keyof AggregateN]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type NGroupByArgs = { + where?: NWhereInput + orderBy?: Enumerable + by: Array + having?: NScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: NCountAggregateInputType | true + _avg?: NAvgAggregateInputType + _sum?: NSumAggregateInputType + _min?: NMinAggregateInputType + _max?: NMaxAggregateInputType + } + + + export type NGroupByOutputType = { + id: string + m_ids: string[] + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + _count: NCountAggregateOutputType | null + _avg: NAvgAggregateOutputType | null + _sum: NSumAggregateOutputType | null + _min: NMinAggregateOutputType | null + _max: NMaxAggregateOutputType | null + } + + type GetNGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof NGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type NSelect = { + id?: boolean + m_ids?: boolean + m?: boolean | MFindManyArgs + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + _count?: boolean | NCountOutputTypeArgs + } + + export type NInclude = { + m?: boolean | MFindManyArgs + _count?: boolean | NCountOutputTypeArgs + } + + export type NGetPayload< + S extends boolean | null | undefined | NArgs, + U = keyof S + > = S extends true + ? N + : S extends undefined + ? never + : S extends NArgs | NFindManyArgs + ?'include' extends U + ? N & { + [P in TrueKeys]: + P extends 'm' ? Array < MGetPayload> : + P extends '_count' ? NCountOutputTypeGetPayload : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'm' ? Array < MGetPayload> : + P extends '_count' ? NCountOutputTypeGetPayload : P extends keyof N ? N[P] : never + } + : N + : N + + + type NCountArgs = Merge< + Omit & { + select?: NCountAggregateInputType | true + } + > + + export interface NDelegate { + /** + * Find zero or one N that matches the filter. + * @param {NFindUniqueArgs} args - Arguments to find a N + * @example + * // Get one N + * const n = await prisma.n.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__NClient>> : CheckSelect, Prisma__NClient | null >> + + /** + * Find the first N that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {NFindFirstArgs} args - Arguments to find a N + * @example + * // Get one N + * const n = await prisma.n.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__NClient>> : CheckSelect, Prisma__NClient | null >> + + /** + * Find zero or more Ns that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {NFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Ns + * const ns = await prisma.n.findMany() + * + * // Get first 10 Ns + * const ns = await prisma.n.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const nWithIdOnly = await prisma.n.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a N. + * @param {NCreateArgs} args - Arguments to create a N. + * @example + * // Create one N + * const N = await prisma.n.create({ + * data: { + * // ... data to create a N + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__NClient>> + + /** + * Create many Ns. + * @param {NCreateManyArgs} args - Arguments to create many Ns. + * @example + * // Create many Ns + * const n = await prisma.n.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a N. + * @param {NDeleteArgs} args - Arguments to delete one N. + * @example + * // Delete one N + * const N = await prisma.n.delete({ + * where: { + * // ... filter to delete one N + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__NClient>> + + /** + * Update one N. + * @param {NUpdateArgs} args - Arguments to update one N. + * @example + * // Update one N + * const n = await prisma.n.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__NClient>> + + /** + * Delete zero or more Ns. + * @param {NDeleteManyArgs} args - Arguments to filter Ns to delete. + * @example + * // Delete a few Ns + * const { count } = await prisma.n.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Ns. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {NUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Ns + * const n = await prisma.n.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one N. + * @param {NUpsertArgs} args - Arguments to update or create a N. + * @example + * // Update or create a N + * const n = await prisma.n.upsert({ + * create: { + * // ... data to create a N + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the N we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__NClient>> + + /** + * Find zero or more Ns that matches the filter. + * @param {NFindRawArgs} args - Select which filters you would like to apply. + * @example + * const n = await prisma.n.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: NFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a N. + * @param {NAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const n = await prisma.n.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: NAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Ns. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {NCountArgs} args - Arguments to filter Ns to count. + * @example + * // Count the number of Ns + * const count = await prisma.n.count({ + * where: { + * // ... the filter for the Ns we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a N. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {NAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by N. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {NGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends NGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: NGroupByArgs['orderBy'] } + : { orderBy?: NGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetNGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for N. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__NClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + m(args?: Subset): CheckSelect>, PrismaPromise>>>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * N findUnique + */ + export type NFindUniqueArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * Throw an Error if a N can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which N to fetch. + * + **/ + where: NWhereUniqueInput + } + + + /** + * N findFirst + */ + export type NFindFirstArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * Throw an Error if a N can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which N to fetch. + * + **/ + where?: NWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of NS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for NS. + * + **/ + cursor?: NWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` NS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` NS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of NS. + * + **/ + distinct?: Enumerable + } + + + /** + * N findMany + */ + export type NFindManyArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * Filter, which NS to fetch. + * + **/ + where?: NWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of NS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing NS. + * + **/ + cursor?: NWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` NS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` NS. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * N create + */ + export type NCreateArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * The data needed to create a N. + * + **/ + data: XOR + } + + + /** + * N createMany + */ + export type NCreateManyArgs = { + /** + * The data used to create many NS. + * + **/ + data: Enumerable + } + + + /** + * N update + */ + export type NUpdateArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * The data needed to update a N. + * + **/ + data: XOR + /** + * Choose, which N to update. + * + **/ + where: NWhereUniqueInput + } + + + /** + * N updateMany + */ + export type NUpdateManyArgs = { + /** + * The data used to update NS. + * + **/ + data: XOR + /** + * Filter which NS to update + * + **/ + where?: NWhereInput + } + + + /** + * N upsert + */ + export type NUpsertArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * The filter to search for the N to update in case it exists. + * + **/ + where: NWhereUniqueInput + /** + * In case the N found by the \`where\` argument doesn't exist, create a new N with this data. + * + **/ + create: XOR + /** + * In case the N was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * N delete + */ + export type NDeleteArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + /** + * Filter which N to delete. + * + **/ + where: NWhereUniqueInput + } + + + /** + * N deleteMany + */ + export type NDeleteManyArgs = { + /** + * Filter which NS to delete + * + **/ + where?: NWhereInput + } + + + /** + * N findRaw + */ + export type NFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * N aggregateRaw + */ + export type NAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * N without action + */ + export type NArgs = { + /** + * Select specific fields to fetch from the N + * + **/ + select?: NSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: NInclude | null + } + + + + /** + * Model OneOptional + */ + + + export type AggregateOneOptional = { + _count: OneOptionalCountAggregateOutputType | null + _avg: OneOptionalAvgAggregateOutputType | null + _sum: OneOptionalSumAggregateOutputType | null + _min: OneOptionalMinAggregateOutputType | null + _max: OneOptionalMaxAggregateOutputType | null + } + + export type OneOptionalAvgAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type OneOptionalSumAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type OneOptionalMinAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type OneOptionalMaxAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type OneOptionalCountAggregateOutputType = { + id: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + _all: number + } + + + export type OneOptionalAvgAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type OneOptionalSumAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type OneOptionalMinAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type OneOptionalMaxAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type OneOptionalCountAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + _all?: true + } + + export type OneOptionalAggregateArgs = { + /** + * Filter which OneOptional to aggregate. + * + **/ + where?: OneOptionalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OneOptionals to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: OneOptionalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OneOptionals from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OneOptionals. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned OneOptionals + **/ + _count?: true | OneOptionalCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: OneOptionalAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: OneOptionalSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: OneOptionalMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: OneOptionalMaxAggregateInputType + } + + export type GetOneOptionalAggregateType = { + [P in keyof T & keyof AggregateOneOptional]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type OneOptionalGroupByArgs = { + where?: OneOptionalWhereInput + orderBy?: Enumerable + by: Array + having?: OneOptionalScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: OneOptionalCountAggregateInputType | true + _avg?: OneOptionalAvgAggregateInputType + _sum?: OneOptionalSumAggregateInputType + _min?: OneOptionalMinAggregateInputType + _max?: OneOptionalMaxAggregateInputType + } + + + export type OneOptionalGroupByOutputType = { + id: string + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + _count: OneOptionalCountAggregateOutputType | null + _avg: OneOptionalAvgAggregateOutputType | null + _sum: OneOptionalSumAggregateOutputType | null + _min: OneOptionalMinAggregateOutputType | null + _max: OneOptionalMaxAggregateOutputType | null + } + + type GetOneOptionalGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof OneOptionalGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type OneOptionalSelect = { + id?: boolean + many?: boolean | ManyRequiredFindManyArgs + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + _count?: boolean | OneOptionalCountOutputTypeArgs + } + + export type OneOptionalInclude = { + many?: boolean | ManyRequiredFindManyArgs + _count?: boolean | OneOptionalCountOutputTypeArgs + } + + export type OneOptionalGetPayload< + S extends boolean | null | undefined | OneOptionalArgs, + U = keyof S + > = S extends true + ? OneOptional + : S extends undefined + ? never + : S extends OneOptionalArgs | OneOptionalFindManyArgs + ?'include' extends U + ? OneOptional & { + [P in TrueKeys]: + P extends 'many' ? Array < ManyRequiredGetPayload> : + P extends '_count' ? OneOptionalCountOutputTypeGetPayload : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'many' ? Array < ManyRequiredGetPayload> : + P extends '_count' ? OneOptionalCountOutputTypeGetPayload : P extends keyof OneOptional ? OneOptional[P] : never + } + : OneOptional + : OneOptional + + + type OneOptionalCountArgs = Merge< + Omit & { + select?: OneOptionalCountAggregateInputType | true + } + > + + export interface OneOptionalDelegate { + /** + * Find zero or one OneOptional that matches the filter. + * @param {OneOptionalFindUniqueArgs} args - Arguments to find a OneOptional + * @example + * // Get one OneOptional + * const oneOptional = await prisma.oneOptional.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__OneOptionalClient>> : CheckSelect, Prisma__OneOptionalClient | null >> + + /** + * Find the first OneOptional that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OneOptionalFindFirstArgs} args - Arguments to find a OneOptional + * @example + * // Get one OneOptional + * const oneOptional = await prisma.oneOptional.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__OneOptionalClient>> : CheckSelect, Prisma__OneOptionalClient | null >> + + /** + * Find zero or more OneOptionals that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OneOptionalFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all OneOptionals + * const oneOptionals = await prisma.oneOptional.findMany() + * + * // Get first 10 OneOptionals + * const oneOptionals = await prisma.oneOptional.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const oneOptionalWithIdOnly = await prisma.oneOptional.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a OneOptional. + * @param {OneOptionalCreateArgs} args - Arguments to create a OneOptional. + * @example + * // Create one OneOptional + * const OneOptional = await prisma.oneOptional.create({ + * data: { + * // ... data to create a OneOptional + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__OneOptionalClient>> + + /** + * Create many OneOptionals. + * @param {OneOptionalCreateManyArgs} args - Arguments to create many OneOptionals. + * @example + * // Create many OneOptionals + * const oneOptional = await prisma.oneOptional.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a OneOptional. + * @param {OneOptionalDeleteArgs} args - Arguments to delete one OneOptional. + * @example + * // Delete one OneOptional + * const OneOptional = await prisma.oneOptional.delete({ + * where: { + * // ... filter to delete one OneOptional + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__OneOptionalClient>> + + /** + * Update one OneOptional. + * @param {OneOptionalUpdateArgs} args - Arguments to update one OneOptional. + * @example + * // Update one OneOptional + * const oneOptional = await prisma.oneOptional.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__OneOptionalClient>> + + /** + * Delete zero or more OneOptionals. + * @param {OneOptionalDeleteManyArgs} args - Arguments to filter OneOptionals to delete. + * @example + * // Delete a few OneOptionals + * const { count } = await prisma.oneOptional.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more OneOptionals. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OneOptionalUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many OneOptionals + * const oneOptional = await prisma.oneOptional.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one OneOptional. + * @param {OneOptionalUpsertArgs} args - Arguments to update or create a OneOptional. + * @example + * // Update or create a OneOptional + * const oneOptional = await prisma.oneOptional.upsert({ + * create: { + * // ... data to create a OneOptional + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the OneOptional we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__OneOptionalClient>> + + /** + * Find zero or more OneOptionals that matches the filter. + * @param {OneOptionalFindRawArgs} args - Select which filters you would like to apply. + * @example + * const oneOptional = await prisma.oneOptional.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: OneOptionalFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a OneOptional. + * @param {OneOptionalAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const oneOptional = await prisma.oneOptional.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: OneOptionalAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of OneOptionals. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OneOptionalCountArgs} args - Arguments to filter OneOptionals to count. + * @example + * // Count the number of OneOptionals + * const count = await prisma.oneOptional.count({ + * where: { + * // ... the filter for the OneOptionals we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a OneOptional. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OneOptionalAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by OneOptional. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OneOptionalGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends OneOptionalGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: OneOptionalGroupByArgs['orderBy'] } + : { orderBy?: OneOptionalGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOneOptionalGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for OneOptional. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__OneOptionalClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + many(args?: Subset): CheckSelect>, PrismaPromise>>>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * OneOptional findUnique + */ + export type OneOptionalFindUniqueArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * Throw an Error if a OneOptional can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which OneOptional to fetch. + * + **/ + where: OneOptionalWhereUniqueInput + } + + + /** + * OneOptional findFirst + */ + export type OneOptionalFindFirstArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * Throw an Error if a OneOptional can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which OneOptional to fetch. + * + **/ + where?: OneOptionalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OneOptionals to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for OneOptionals. + * + **/ + cursor?: OneOptionalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OneOptionals from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OneOptionals. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of OneOptionals. + * + **/ + distinct?: Enumerable + } + + + /** + * OneOptional findMany + */ + export type OneOptionalFindManyArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * Filter, which OneOptionals to fetch. + * + **/ + where?: OneOptionalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OneOptionals to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing OneOptionals. + * + **/ + cursor?: OneOptionalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OneOptionals from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OneOptionals. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * OneOptional create + */ + export type OneOptionalCreateArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * The data needed to create a OneOptional. + * + **/ + data: XOR + } + + + /** + * OneOptional createMany + */ + export type OneOptionalCreateManyArgs = { + /** + * The data used to create many OneOptionals. + * + **/ + data: Enumerable + } + + + /** + * OneOptional update + */ + export type OneOptionalUpdateArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * The data needed to update a OneOptional. + * + **/ + data: XOR + /** + * Choose, which OneOptional to update. + * + **/ + where: OneOptionalWhereUniqueInput + } + + + /** + * OneOptional updateMany + */ + export type OneOptionalUpdateManyArgs = { + /** + * The data used to update OneOptionals. + * + **/ + data: XOR + /** + * Filter which OneOptionals to update + * + **/ + where?: OneOptionalWhereInput + } + + + /** + * OneOptional upsert + */ + export type OneOptionalUpsertArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * The filter to search for the OneOptional to update in case it exists. + * + **/ + where: OneOptionalWhereUniqueInput + /** + * In case the OneOptional found by the \`where\` argument doesn't exist, create a new OneOptional with this data. + * + **/ + create: XOR + /** + * In case the OneOptional was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * OneOptional delete + */ + export type OneOptionalDeleteArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + /** + * Filter which OneOptional to delete. + * + **/ + where: OneOptionalWhereUniqueInput + } + + + /** + * OneOptional deleteMany + */ + export type OneOptionalDeleteManyArgs = { + /** + * Filter which OneOptionals to delete + * + **/ + where?: OneOptionalWhereInput + } + + + /** + * OneOptional findRaw + */ + export type OneOptionalFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * OneOptional aggregateRaw + */ + export type OneOptionalAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * OneOptional without action + */ + export type OneOptionalArgs = { + /** + * Select specific fields to fetch from the OneOptional + * + **/ + select?: OneOptionalSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OneOptionalInclude | null + } + + + + /** + * Model ManyRequired + */ + + + export type AggregateManyRequired = { + _count: ManyRequiredCountAggregateOutputType | null + _avg: ManyRequiredAvgAggregateOutputType | null + _sum: ManyRequiredSumAggregateOutputType | null + _min: ManyRequiredMinAggregateOutputType | null + _max: ManyRequiredMaxAggregateOutputType | null + } + + export type ManyRequiredAvgAggregateOutputType = { + oneOptionalId: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type ManyRequiredSumAggregateOutputType = { + oneOptionalId: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type ManyRequiredMinAggregateOutputType = { + id: string | null + oneOptionalId: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type ManyRequiredMaxAggregateOutputType = { + id: string | null + oneOptionalId: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type ManyRequiredCountAggregateOutputType = { + id: number + oneOptionalId: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + _all: number + } + + + export type ManyRequiredAvgAggregateInputType = { + oneOptionalId?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type ManyRequiredSumAggregateInputType = { + oneOptionalId?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type ManyRequiredMinAggregateInputType = { + id?: true + oneOptionalId?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type ManyRequiredMaxAggregateInputType = { + id?: true + oneOptionalId?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type ManyRequiredCountAggregateInputType = { + id?: true + oneOptionalId?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + _all?: true + } + + export type ManyRequiredAggregateArgs = { + /** + * Filter which ManyRequired to aggregate. + * + **/ + where?: ManyRequiredWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ManyRequireds to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: ManyRequiredWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` ManyRequireds from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` ManyRequireds. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned ManyRequireds + **/ + _count?: true | ManyRequiredCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: ManyRequiredAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: ManyRequiredSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: ManyRequiredMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: ManyRequiredMaxAggregateInputType + } + + export type GetManyRequiredAggregateType = { + [P in keyof T & keyof AggregateManyRequired]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type ManyRequiredGroupByArgs = { + where?: ManyRequiredWhereInput + orderBy?: Enumerable + by: Array + having?: ManyRequiredScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: ManyRequiredCountAggregateInputType | true + _avg?: ManyRequiredAvgAggregateInputType + _sum?: ManyRequiredSumAggregateInputType + _min?: ManyRequiredMinAggregateInputType + _max?: ManyRequiredMaxAggregateInputType + } + + + export type ManyRequiredGroupByOutputType = { + id: string + oneOptionalId: number | null + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + _count: ManyRequiredCountAggregateOutputType | null + _avg: ManyRequiredAvgAggregateOutputType | null + _sum: ManyRequiredSumAggregateOutputType | null + _min: ManyRequiredMinAggregateOutputType | null + _max: ManyRequiredMaxAggregateOutputType | null + } + + type GetManyRequiredGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof ManyRequiredGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type ManyRequiredSelect = { + id?: boolean + one?: boolean | OneOptionalArgs + oneOptionalId?: boolean + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + } + + export type ManyRequiredInclude = { + one?: boolean | OneOptionalArgs + } + + export type ManyRequiredGetPayload< + S extends boolean | null | undefined | ManyRequiredArgs, + U = keyof S + > = S extends true + ? ManyRequired + : S extends undefined + ? never + : S extends ManyRequiredArgs | ManyRequiredFindManyArgs + ?'include' extends U + ? ManyRequired & { + [P in TrueKeys]: + P extends 'one' ? OneOptionalGetPayload | null : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'one' ? OneOptionalGetPayload | null : P extends keyof ManyRequired ? ManyRequired[P] : never + } + : ManyRequired + : ManyRequired + + + type ManyRequiredCountArgs = Merge< + Omit & { + select?: ManyRequiredCountAggregateInputType | true + } + > + + export interface ManyRequiredDelegate { + /** + * Find zero or one ManyRequired that matches the filter. + * @param {ManyRequiredFindUniqueArgs} args - Arguments to find a ManyRequired + * @example + * // Get one ManyRequired + * const manyRequired = await prisma.manyRequired.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__ManyRequiredClient>> : CheckSelect, Prisma__ManyRequiredClient | null >> + + /** + * Find the first ManyRequired that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ManyRequiredFindFirstArgs} args - Arguments to find a ManyRequired + * @example + * // Get one ManyRequired + * const manyRequired = await prisma.manyRequired.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__ManyRequiredClient>> : CheckSelect, Prisma__ManyRequiredClient | null >> + + /** + * Find zero or more ManyRequireds that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ManyRequiredFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all ManyRequireds + * const manyRequireds = await prisma.manyRequired.findMany() + * + * // Get first 10 ManyRequireds + * const manyRequireds = await prisma.manyRequired.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const manyRequiredWithIdOnly = await prisma.manyRequired.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a ManyRequired. + * @param {ManyRequiredCreateArgs} args - Arguments to create a ManyRequired. + * @example + * // Create one ManyRequired + * const ManyRequired = await prisma.manyRequired.create({ + * data: { + * // ... data to create a ManyRequired + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__ManyRequiredClient>> + + /** + * Create many ManyRequireds. + * @param {ManyRequiredCreateManyArgs} args - Arguments to create many ManyRequireds. + * @example + * // Create many ManyRequireds + * const manyRequired = await prisma.manyRequired.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a ManyRequired. + * @param {ManyRequiredDeleteArgs} args - Arguments to delete one ManyRequired. + * @example + * // Delete one ManyRequired + * const ManyRequired = await prisma.manyRequired.delete({ + * where: { + * // ... filter to delete one ManyRequired + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__ManyRequiredClient>> + + /** + * Update one ManyRequired. + * @param {ManyRequiredUpdateArgs} args - Arguments to update one ManyRequired. + * @example + * // Update one ManyRequired + * const manyRequired = await prisma.manyRequired.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__ManyRequiredClient>> + + /** + * Delete zero or more ManyRequireds. + * @param {ManyRequiredDeleteManyArgs} args - Arguments to filter ManyRequireds to delete. + * @example + * // Delete a few ManyRequireds + * const { count } = await prisma.manyRequired.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more ManyRequireds. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ManyRequiredUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many ManyRequireds + * const manyRequired = await prisma.manyRequired.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one ManyRequired. + * @param {ManyRequiredUpsertArgs} args - Arguments to update or create a ManyRequired. + * @example + * // Update or create a ManyRequired + * const manyRequired = await prisma.manyRequired.upsert({ + * create: { + * // ... data to create a ManyRequired + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the ManyRequired we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__ManyRequiredClient>> + + /** + * Find zero or more ManyRequireds that matches the filter. + * @param {ManyRequiredFindRawArgs} args - Select which filters you would like to apply. + * @example + * const manyRequired = await prisma.manyRequired.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: ManyRequiredFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a ManyRequired. + * @param {ManyRequiredAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const manyRequired = await prisma.manyRequired.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: ManyRequiredAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of ManyRequireds. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ManyRequiredCountArgs} args - Arguments to filter ManyRequireds to count. + * @example + * // Count the number of ManyRequireds + * const count = await prisma.manyRequired.count({ + * where: { + * // ... the filter for the ManyRequireds we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a ManyRequired. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ManyRequiredAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by ManyRequired. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ManyRequiredGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends ManyRequiredGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: ManyRequiredGroupByArgs['orderBy'] } + : { orderBy?: ManyRequiredGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetManyRequiredGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for ManyRequired. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__ManyRequiredClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + one(args?: Subset): CheckSelect, Prisma__OneOptionalClient | null >>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * ManyRequired findUnique + */ + export type ManyRequiredFindUniqueArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * Throw an Error if a ManyRequired can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which ManyRequired to fetch. + * + **/ + where: ManyRequiredWhereUniqueInput + } + + + /** + * ManyRequired findFirst + */ + export type ManyRequiredFindFirstArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * Throw an Error if a ManyRequired can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which ManyRequired to fetch. + * + **/ + where?: ManyRequiredWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ManyRequireds to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for ManyRequireds. + * + **/ + cursor?: ManyRequiredWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` ManyRequireds from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` ManyRequireds. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of ManyRequireds. + * + **/ + distinct?: Enumerable + } + + + /** + * ManyRequired findMany + */ + export type ManyRequiredFindManyArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * Filter, which ManyRequireds to fetch. + * + **/ + where?: ManyRequiredWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ManyRequireds to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing ManyRequireds. + * + **/ + cursor?: ManyRequiredWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` ManyRequireds from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` ManyRequireds. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * ManyRequired create + */ + export type ManyRequiredCreateArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * The data needed to create a ManyRequired. + * + **/ + data: XOR + } + + + /** + * ManyRequired createMany + */ + export type ManyRequiredCreateManyArgs = { + /** + * The data used to create many ManyRequireds. + * + **/ + data: Enumerable + } + + + /** + * ManyRequired update + */ + export type ManyRequiredUpdateArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * The data needed to update a ManyRequired. + * + **/ + data: XOR + /** + * Choose, which ManyRequired to update. + * + **/ + where: ManyRequiredWhereUniqueInput + } + + + /** + * ManyRequired updateMany + */ + export type ManyRequiredUpdateManyArgs = { + /** + * The data used to update ManyRequireds. + * + **/ + data: XOR + /** + * Filter which ManyRequireds to update + * + **/ + where?: ManyRequiredWhereInput + } + + + /** + * ManyRequired upsert + */ + export type ManyRequiredUpsertArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * The filter to search for the ManyRequired to update in case it exists. + * + **/ + where: ManyRequiredWhereUniqueInput + /** + * In case the ManyRequired found by the \`where\` argument doesn't exist, create a new ManyRequired with this data. + * + **/ + create: XOR + /** + * In case the ManyRequired was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * ManyRequired delete + */ + export type ManyRequiredDeleteArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + /** + * Filter which ManyRequired to delete. + * + **/ + where: ManyRequiredWhereUniqueInput + } + + + /** + * ManyRequired deleteMany + */ + export type ManyRequiredDeleteManyArgs = { + /** + * Filter which ManyRequireds to delete + * + **/ + where?: ManyRequiredWhereInput + } + + + /** + * ManyRequired findRaw + */ + export type ManyRequiredFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * ManyRequired aggregateRaw + */ + export type ManyRequiredAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * ManyRequired without action + */ + export type ManyRequiredArgs = { + /** + * Select specific fields to fetch from the ManyRequired + * + **/ + select?: ManyRequiredSelect | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: ManyRequiredInclude | null + } + + + + /** + * Model OptionalSide1 + */ + + + export type AggregateOptionalSide1 = { + _count: OptionalSide1CountAggregateOutputType | null + _avg: OptionalSide1AvgAggregateOutputType | null + _sum: OptionalSide1SumAggregateOutputType | null + _min: OptionalSide1MinAggregateOutputType | null + _max: OptionalSide1MaxAggregateOutputType | null + } + + export type OptionalSide1AvgAggregateOutputType = { + optionalSide2Id: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type OptionalSide1SumAggregateOutputType = { + optionalSide2Id: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type OptionalSide1MinAggregateOutputType = { + id: string | null + optionalSide2Id: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type OptionalSide1MaxAggregateOutputType = { + id: string | null + optionalSide2Id: number | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type OptionalSide1CountAggregateOutputType = { + id: number + optionalSide2Id: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + _all: number + } + + + export type OptionalSide1AvgAggregateInputType = { + optionalSide2Id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type OptionalSide1SumAggregateInputType = { + optionalSide2Id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type OptionalSide1MinAggregateInputType = { + id?: true + optionalSide2Id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type OptionalSide1MaxAggregateInputType = { + id?: true + optionalSide2Id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type OptionalSide1CountAggregateInputType = { + id?: true + optionalSide2Id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + _all?: true + } + + export type OptionalSide1AggregateArgs = { + /** + * Filter which OptionalSide1 to aggregate. + * + **/ + where?: OptionalSide1WhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OptionalSide1s to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: OptionalSide1WhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OptionalSide1s from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OptionalSide1s. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned OptionalSide1s + **/ + _count?: true | OptionalSide1CountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: OptionalSide1AvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: OptionalSide1SumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: OptionalSide1MinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: OptionalSide1MaxAggregateInputType + } + + export type GetOptionalSide1AggregateType = { + [P in keyof T & keyof AggregateOptionalSide1]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type OptionalSide1GroupByArgs = { + where?: OptionalSide1WhereInput + orderBy?: Enumerable + by: Array + having?: OptionalSide1ScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: OptionalSide1CountAggregateInputType | true + _avg?: OptionalSide1AvgAggregateInputType + _sum?: OptionalSide1SumAggregateInputType + _min?: OptionalSide1MinAggregateInputType + _max?: OptionalSide1MaxAggregateInputType + } + + + export type OptionalSide1GroupByOutputType = { + id: string + optionalSide2Id: number | null + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + _count: OptionalSide1CountAggregateOutputType | null + _avg: OptionalSide1AvgAggregateOutputType | null + _sum: OptionalSide1SumAggregateOutputType | null + _min: OptionalSide1MinAggregateOutputType | null + _max: OptionalSide1MaxAggregateOutputType | null + } + + type GetOptionalSide1GroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof OptionalSide1GroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type OptionalSide1Select = { + id?: boolean + opti?: boolean | OptionalSide2Args + optionalSide2Id?: boolean + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + } + + export type OptionalSide1Include = { + opti?: boolean | OptionalSide2Args + } + + export type OptionalSide1GetPayload< + S extends boolean | null | undefined | OptionalSide1Args, + U = keyof S + > = S extends true + ? OptionalSide1 + : S extends undefined + ? never + : S extends OptionalSide1Args | OptionalSide1FindManyArgs + ?'include' extends U + ? OptionalSide1 & { + [P in TrueKeys]: + P extends 'opti' ? OptionalSide2GetPayload | null : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'opti' ? OptionalSide2GetPayload | null : P extends keyof OptionalSide1 ? OptionalSide1[P] : never + } + : OptionalSide1 + : OptionalSide1 + + + type OptionalSide1CountArgs = Merge< + Omit & { + select?: OptionalSide1CountAggregateInputType | true + } + > + + export interface OptionalSide1Delegate { + /** + * Find zero or one OptionalSide1 that matches the filter. + * @param {OptionalSide1FindUniqueArgs} args - Arguments to find a OptionalSide1 + * @example + * // Get one OptionalSide1 + * const optionalSide1 = await prisma.optionalSide1.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__OptionalSide1Client>> : CheckSelect, Prisma__OptionalSide1Client | null >> + + /** + * Find the first OptionalSide1 that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide1FindFirstArgs} args - Arguments to find a OptionalSide1 + * @example + * // Get one OptionalSide1 + * const optionalSide1 = await prisma.optionalSide1.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__OptionalSide1Client>> : CheckSelect, Prisma__OptionalSide1Client | null >> + + /** + * Find zero or more OptionalSide1s that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide1FindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all OptionalSide1s + * const optionalSide1s = await prisma.optionalSide1.findMany() + * + * // Get first 10 OptionalSide1s + * const optionalSide1s = await prisma.optionalSide1.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const optionalSide1WithIdOnly = await prisma.optionalSide1.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a OptionalSide1. + * @param {OptionalSide1CreateArgs} args - Arguments to create a OptionalSide1. + * @example + * // Create one OptionalSide1 + * const OptionalSide1 = await prisma.optionalSide1.create({ + * data: { + * // ... data to create a OptionalSide1 + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide1Client>> + + /** + * Create many OptionalSide1s. + * @param {OptionalSide1CreateManyArgs} args - Arguments to create many OptionalSide1s. + * @example + * // Create many OptionalSide1s + * const optionalSide1 = await prisma.optionalSide1.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a OptionalSide1. + * @param {OptionalSide1DeleteArgs} args - Arguments to delete one OptionalSide1. + * @example + * // Delete one OptionalSide1 + * const OptionalSide1 = await prisma.optionalSide1.delete({ + * where: { + * // ... filter to delete one OptionalSide1 + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide1Client>> + + /** + * Update one OptionalSide1. + * @param {OptionalSide1UpdateArgs} args - Arguments to update one OptionalSide1. + * @example + * // Update one OptionalSide1 + * const optionalSide1 = await prisma.optionalSide1.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide1Client>> + + /** + * Delete zero or more OptionalSide1s. + * @param {OptionalSide1DeleteManyArgs} args - Arguments to filter OptionalSide1s to delete. + * @example + * // Delete a few OptionalSide1s + * const { count } = await prisma.optionalSide1.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more OptionalSide1s. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide1UpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many OptionalSide1s + * const optionalSide1 = await prisma.optionalSide1.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one OptionalSide1. + * @param {OptionalSide1UpsertArgs} args - Arguments to update or create a OptionalSide1. + * @example + * // Update or create a OptionalSide1 + * const optionalSide1 = await prisma.optionalSide1.upsert({ + * create: { + * // ... data to create a OptionalSide1 + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the OptionalSide1 we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide1Client>> + + /** + * Find zero or more OptionalSide1s that matches the filter. + * @param {OptionalSide1FindRawArgs} args - Select which filters you would like to apply. + * @example + * const optionalSide1 = await prisma.optionalSide1.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: OptionalSide1FindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a OptionalSide1. + * @param {OptionalSide1AggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const optionalSide1 = await prisma.optionalSide1.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: OptionalSide1AggregateRawArgs + ): PrismaPromise + + /** + * Count the number of OptionalSide1s. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide1CountArgs} args - Arguments to filter OptionalSide1s to count. + * @example + * // Count the number of OptionalSide1s + * const count = await prisma.optionalSide1.count({ + * where: { + * // ... the filter for the OptionalSide1s we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a OptionalSide1. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide1AggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by OptionalSide1. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide1GroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends OptionalSide1GroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: OptionalSide1GroupByArgs['orderBy'] } + : { orderBy?: OptionalSide1GroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOptionalSide1GroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for OptionalSide1. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__OptionalSide1Client implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + opti(args?: Subset): CheckSelect, Prisma__OptionalSide2Client | null >>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * OptionalSide1 findUnique + */ + export type OptionalSide1FindUniqueArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * Throw an Error if a OptionalSide1 can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which OptionalSide1 to fetch. + * + **/ + where: OptionalSide1WhereUniqueInput + } + + + /** + * OptionalSide1 findFirst + */ + export type OptionalSide1FindFirstArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * Throw an Error if a OptionalSide1 can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which OptionalSide1 to fetch. + * + **/ + where?: OptionalSide1WhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OptionalSide1s to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for OptionalSide1s. + * + **/ + cursor?: OptionalSide1WhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OptionalSide1s from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OptionalSide1s. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of OptionalSide1s. + * + **/ + distinct?: Enumerable + } + + + /** + * OptionalSide1 findMany + */ + export type OptionalSide1FindManyArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * Filter, which OptionalSide1s to fetch. + * + **/ + where?: OptionalSide1WhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OptionalSide1s to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing OptionalSide1s. + * + **/ + cursor?: OptionalSide1WhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OptionalSide1s from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OptionalSide1s. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * OptionalSide1 create + */ + export type OptionalSide1CreateArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * The data needed to create a OptionalSide1. + * + **/ + data: XOR + } + + + /** + * OptionalSide1 createMany + */ + export type OptionalSide1CreateManyArgs = { + /** + * The data used to create many OptionalSide1s. + * + **/ + data: Enumerable + } + + + /** + * OptionalSide1 update + */ + export type OptionalSide1UpdateArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * The data needed to update a OptionalSide1. + * + **/ + data: XOR + /** + * Choose, which OptionalSide1 to update. + * + **/ + where: OptionalSide1WhereUniqueInput + } + + + /** + * OptionalSide1 updateMany + */ + export type OptionalSide1UpdateManyArgs = { + /** + * The data used to update OptionalSide1s. + * + **/ + data: XOR + /** + * Filter which OptionalSide1s to update + * + **/ + where?: OptionalSide1WhereInput + } + + + /** + * OptionalSide1 upsert + */ + export type OptionalSide1UpsertArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * The filter to search for the OptionalSide1 to update in case it exists. + * + **/ + where: OptionalSide1WhereUniqueInput + /** + * In case the OptionalSide1 found by the \`where\` argument doesn't exist, create a new OptionalSide1 with this data. + * + **/ + create: XOR + /** + * In case the OptionalSide1 was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * OptionalSide1 delete + */ + export type OptionalSide1DeleteArgs = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + /** + * Filter which OptionalSide1 to delete. + * + **/ + where: OptionalSide1WhereUniqueInput + } + + + /** + * OptionalSide1 deleteMany + */ + export type OptionalSide1DeleteManyArgs = { + /** + * Filter which OptionalSide1s to delete + * + **/ + where?: OptionalSide1WhereInput + } + + + /** + * OptionalSide1 findRaw + */ + export type OptionalSide1FindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * OptionalSide1 aggregateRaw + */ + export type OptionalSide1AggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * OptionalSide1 without action + */ + export type OptionalSide1Args = { + /** + * Select specific fields to fetch from the OptionalSide1 + * + **/ + select?: OptionalSide1Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide1Include | null + } + + + + /** + * Model OptionalSide2 + */ + + + export type AggregateOptionalSide2 = { + _count: OptionalSide2CountAggregateOutputType | null + _avg: OptionalSide2AvgAggregateOutputType | null + _sum: OptionalSide2SumAggregateOutputType | null + _min: OptionalSide2MinAggregateOutputType | null + _max: OptionalSide2MaxAggregateOutputType | null + } + + export type OptionalSide2AvgAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type OptionalSide2SumAggregateOutputType = { + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + } + + export type OptionalSide2MinAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type OptionalSide2MaxAggregateOutputType = { + id: string | null + int: number | null + optionalInt: number | null + float: number | null + optionalFloat: number | null + string: string | null + optionalString: string | null + enum: ABeautifulEnum | null + optionalEnum: ABeautifulEnum | null + boolean: boolean | null + optionalBoolean: boolean | null + } + + export type OptionalSide2CountAggregateOutputType = { + id: number + int: number + optionalInt: number + float: number + optionalFloat: number + string: number + optionalString: number + json: number + optionalJson: number + enum: number + optionalEnum: number + boolean: number + optionalBoolean: number + _all: number + } + + + export type OptionalSide2AvgAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type OptionalSide2SumAggregateInputType = { + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + } + + export type OptionalSide2MinAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type OptionalSide2MaxAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + } + + export type OptionalSide2CountAggregateInputType = { + id?: true + int?: true + optionalInt?: true + float?: true + optionalFloat?: true + string?: true + optionalString?: true + json?: true + optionalJson?: true + enum?: true + optionalEnum?: true + boolean?: true + optionalBoolean?: true + _all?: true + } + + export type OptionalSide2AggregateArgs = { + /** + * Filter which OptionalSide2 to aggregate. + * + **/ + where?: OptionalSide2WhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OptionalSide2s to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: OptionalSide2WhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OptionalSide2s from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OptionalSide2s. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned OptionalSide2s + **/ + _count?: true | OptionalSide2CountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: OptionalSide2AvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: OptionalSide2SumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: OptionalSide2MinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: OptionalSide2MaxAggregateInputType + } + + export type GetOptionalSide2AggregateType = { + [P in keyof T & keyof AggregateOptionalSide2]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type OptionalSide2GroupByArgs = { + where?: OptionalSide2WhereInput + orderBy?: Enumerable + by: Array + having?: OptionalSide2ScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: OptionalSide2CountAggregateInputType | true + _avg?: OptionalSide2AvgAggregateInputType + _sum?: OptionalSide2SumAggregateInputType + _min?: OptionalSide2MinAggregateInputType + _max?: OptionalSide2MaxAggregateInputType + } + + + export type OptionalSide2GroupByOutputType = { + id: string + int: number + optionalInt: number | null + float: number + optionalFloat: number | null + string: string + optionalString: string | null + json: JsonValue + optionalJson: JsonValue | null + enum: ABeautifulEnum + optionalEnum: ABeautifulEnum | null + boolean: boolean + optionalBoolean: boolean | null + _count: OptionalSide2CountAggregateOutputType | null + _avg: OptionalSide2AvgAggregateOutputType | null + _sum: OptionalSide2SumAggregateOutputType | null + _min: OptionalSide2MinAggregateOutputType | null + _max: OptionalSide2MaxAggregateOutputType | null + } + + type GetOptionalSide2GroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof OptionalSide2GroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type OptionalSide2Select = { + id?: boolean + opti?: boolean | OptionalSide1Args + int?: boolean + optionalInt?: boolean + float?: boolean + optionalFloat?: boolean + string?: boolean + optionalString?: boolean + json?: boolean + optionalJson?: boolean + enum?: boolean + optionalEnum?: boolean + boolean?: boolean + optionalBoolean?: boolean + } + + export type OptionalSide2Include = { + opti?: boolean | OptionalSide1Args + } + + export type OptionalSide2GetPayload< + S extends boolean | null | undefined | OptionalSide2Args, + U = keyof S + > = S extends true + ? OptionalSide2 + : S extends undefined + ? never + : S extends OptionalSide2Args | OptionalSide2FindManyArgs + ?'include' extends U + ? OptionalSide2 & { + [P in TrueKeys]: + P extends 'opti' ? OptionalSide1GetPayload | null : never + } + : 'select' extends U + ? { + [P in TrueKeys]: + P extends 'opti' ? OptionalSide1GetPayload | null : P extends keyof OptionalSide2 ? OptionalSide2[P] : never + } + : OptionalSide2 + : OptionalSide2 + + + type OptionalSide2CountArgs = Merge< + Omit & { + select?: OptionalSide2CountAggregateInputType | true + } + > + + export interface OptionalSide2Delegate { + /** + * Find zero or one OptionalSide2 that matches the filter. + * @param {OptionalSide2FindUniqueArgs} args - Arguments to find a OptionalSide2 + * @example + * // Get one OptionalSide2 + * const optionalSide2 = await prisma.optionalSide2.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__OptionalSide2Client>> : CheckSelect, Prisma__OptionalSide2Client | null >> + + /** + * Find the first OptionalSide2 that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide2FindFirstArgs} args - Arguments to find a OptionalSide2 + * @example + * // Get one OptionalSide2 + * const optionalSide2 = await prisma.optionalSide2.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__OptionalSide2Client>> : CheckSelect, Prisma__OptionalSide2Client | null >> + + /** + * Find zero or more OptionalSide2s that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide2FindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all OptionalSide2s + * const optionalSide2s = await prisma.optionalSide2.findMany() + * + * // Get first 10 OptionalSide2s + * const optionalSide2s = await prisma.optionalSide2.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const optionalSide2WithIdOnly = await prisma.optionalSide2.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a OptionalSide2. + * @param {OptionalSide2CreateArgs} args - Arguments to create a OptionalSide2. + * @example + * // Create one OptionalSide2 + * const OptionalSide2 = await prisma.optionalSide2.create({ + * data: { + * // ... data to create a OptionalSide2 + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide2Client>> + + /** + * Create many OptionalSide2s. + * @param {OptionalSide2CreateManyArgs} args - Arguments to create many OptionalSide2s. + * @example + * // Create many OptionalSide2s + * const optionalSide2 = await prisma.optionalSide2.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a OptionalSide2. + * @param {OptionalSide2DeleteArgs} args - Arguments to delete one OptionalSide2. + * @example + * // Delete one OptionalSide2 + * const OptionalSide2 = await prisma.optionalSide2.delete({ + * where: { + * // ... filter to delete one OptionalSide2 + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide2Client>> + + /** + * Update one OptionalSide2. + * @param {OptionalSide2UpdateArgs} args - Arguments to update one OptionalSide2. + * @example + * // Update one OptionalSide2 + * const optionalSide2 = await prisma.optionalSide2.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide2Client>> + + /** + * Delete zero or more OptionalSide2s. + * @param {OptionalSide2DeleteManyArgs} args - Arguments to filter OptionalSide2s to delete. + * @example + * // Delete a few OptionalSide2s + * const { count } = await prisma.optionalSide2.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more OptionalSide2s. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide2UpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many OptionalSide2s + * const optionalSide2 = await prisma.optionalSide2.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one OptionalSide2. + * @param {OptionalSide2UpsertArgs} args - Arguments to update or create a OptionalSide2. + * @example + * // Update or create a OptionalSide2 + * const optionalSide2 = await prisma.optionalSide2.upsert({ + * create: { + * // ... data to create a OptionalSide2 + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the OptionalSide2 we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__OptionalSide2Client>> + + /** + * Find zero or more OptionalSide2s that matches the filter. + * @param {OptionalSide2FindRawArgs} args - Select which filters you would like to apply. + * @example + * const optionalSide2 = await prisma.optionalSide2.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: OptionalSide2FindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a OptionalSide2. + * @param {OptionalSide2AggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const optionalSide2 = await prisma.optionalSide2.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: OptionalSide2AggregateRawArgs + ): PrismaPromise + + /** + * Count the number of OptionalSide2s. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide2CountArgs} args - Arguments to filter OptionalSide2s to count. + * @example + * // Count the number of OptionalSide2s + * const count = await prisma.optionalSide2.count({ + * where: { + * // ... the filter for the OptionalSide2s we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a OptionalSide2. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide2AggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by OptionalSide2. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {OptionalSide2GroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends OptionalSide2GroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: OptionalSide2GroupByArgs['orderBy'] } + : { orderBy?: OptionalSide2GroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOptionalSide2GroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for OptionalSide2. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__OptionalSide2Client implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + opti(args?: Subset): CheckSelect, Prisma__OptionalSide1Client | null >>; + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * OptionalSide2 findUnique + */ + export type OptionalSide2FindUniqueArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * Throw an Error if a OptionalSide2 can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which OptionalSide2 to fetch. + * + **/ + where: OptionalSide2WhereUniqueInput + } + + + /** + * OptionalSide2 findFirst + */ + export type OptionalSide2FindFirstArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * Throw an Error if a OptionalSide2 can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which OptionalSide2 to fetch. + * + **/ + where?: OptionalSide2WhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OptionalSide2s to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for OptionalSide2s. + * + **/ + cursor?: OptionalSide2WhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OptionalSide2s from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OptionalSide2s. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of OptionalSide2s. + * + **/ + distinct?: Enumerable + } + + + /** + * OptionalSide2 findMany + */ + export type OptionalSide2FindManyArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * Filter, which OptionalSide2s to fetch. + * + **/ + where?: OptionalSide2WhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of OptionalSide2s to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing OptionalSide2s. + * + **/ + cursor?: OptionalSide2WhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` OptionalSide2s from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` OptionalSide2s. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * OptionalSide2 create + */ + export type OptionalSide2CreateArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * The data needed to create a OptionalSide2. + * + **/ + data: XOR + } + + + /** + * OptionalSide2 createMany + */ + export type OptionalSide2CreateManyArgs = { + /** + * The data used to create many OptionalSide2s. + * + **/ + data: Enumerable + } + + + /** + * OptionalSide2 update + */ + export type OptionalSide2UpdateArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * The data needed to update a OptionalSide2. + * + **/ + data: XOR + /** + * Choose, which OptionalSide2 to update. + * + **/ + where: OptionalSide2WhereUniqueInput + } + + + /** + * OptionalSide2 updateMany + */ + export type OptionalSide2UpdateManyArgs = { + /** + * The data used to update OptionalSide2s. + * + **/ + data: XOR + /** + * Filter which OptionalSide2s to update + * + **/ + where?: OptionalSide2WhereInput + } + + + /** + * OptionalSide2 upsert + */ + export type OptionalSide2UpsertArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * The filter to search for the OptionalSide2 to update in case it exists. + * + **/ + where: OptionalSide2WhereUniqueInput + /** + * In case the OptionalSide2 found by the \`where\` argument doesn't exist, create a new OptionalSide2 with this data. + * + **/ + create: XOR + /** + * In case the OptionalSide2 was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * OptionalSide2 delete + */ + export type OptionalSide2DeleteArgs = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + /** + * Filter which OptionalSide2 to delete. + * + **/ + where: OptionalSide2WhereUniqueInput + } + + + /** + * OptionalSide2 deleteMany + */ + export type OptionalSide2DeleteManyArgs = { + /** + * Filter which OptionalSide2s to delete + * + **/ + where?: OptionalSide2WhereInput + } + + + /** + * OptionalSide2 findRaw + */ + export type OptionalSide2FindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * OptionalSide2 aggregateRaw + */ + export type OptionalSide2AggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * OptionalSide2 without action + */ + export type OptionalSide2Args = { + /** + * Select specific fields to fetch from the OptionalSide2 + * + **/ + select?: OptionalSide2Select | null + /** + * Choose, which related nodes to fetch as well. + * + **/ + include?: OptionalSide2Include | null + } + + + + /** + * Model A + */ + + + export type AggregateA = { + _count: ACountAggregateOutputType | null + _avg: AAvgAggregateOutputType | null + _sum: ASumAggregateOutputType | null + _min: AMinAggregateOutputType | null + _max: AMaxAggregateOutputType | null + } + + export type AAvgAggregateOutputType = { + int: number | null + sInt: number | null + bInt: number | null + } + + export type ASumAggregateOutputType = { + int: number | null + sInt: number | null + bInt: bigint | null + } + + export type AMinAggregateOutputType = { + id: string | null + email: string | null + name: string | null + int: number | null + sInt: number | null + bInt: bigint | null + } + + export type AMaxAggregateOutputType = { + id: string | null + email: string | null + name: string | null + int: number | null + sInt: number | null + bInt: bigint | null + } + + export type ACountAggregateOutputType = { + id: number + email: number + name: number + int: number + sInt: number + bInt: number + _all: number + } + + + export type AAvgAggregateInputType = { + int?: true + sInt?: true + bInt?: true + } + + export type ASumAggregateInputType = { + int?: true + sInt?: true + bInt?: true + } + + export type AMinAggregateInputType = { + id?: true + email?: true + name?: true + int?: true + sInt?: true + bInt?: true + } + + export type AMaxAggregateInputType = { + id?: true + email?: true + name?: true + int?: true + sInt?: true + bInt?: true + } + + export type ACountAggregateInputType = { + id?: true + email?: true + name?: true + int?: true + sInt?: true + bInt?: true + _all?: true + } + + export type AAggregateArgs = { + /** + * Filter which A to aggregate. + * + **/ + where?: AWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: AWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` AS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` AS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned AS + **/ + _count?: true | ACountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: AAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: ASumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AMaxAggregateInputType + } + + export type GetAAggregateType = { + [P in keyof T & keyof AggregateA]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type AGroupByArgs = { + where?: AWhereInput + orderBy?: Enumerable + by: Array + having?: AScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: ACountAggregateInputType | true + _avg?: AAvgAggregateInputType + _sum?: ASumAggregateInputType + _min?: AMinAggregateInputType + _max?: AMaxAggregateInputType + } + + + export type AGroupByOutputType = { + id: string + email: string + name: string | null + int: number + sInt: number + bInt: bigint + _count: ACountAggregateOutputType | null + _avg: AAvgAggregateOutputType | null + _sum: ASumAggregateOutputType | null + _min: AMinAggregateOutputType | null + _max: AMaxAggregateOutputType | null + } + + type GetAGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof AGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type ASelect = { + id?: boolean + email?: boolean + name?: boolean + int?: boolean + sInt?: boolean + bInt?: boolean + } + + export type AGetPayload< + S extends boolean | null | undefined | AArgs, + U = keyof S + > = S extends true + ? A + : S extends undefined + ? never + : S extends AArgs | AFindManyArgs + ?'include' extends U + ? A + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof A ? A[P] : never + } + : A + : A + + + type ACountArgs = Merge< + Omit & { + select?: ACountAggregateInputType | true + } + > + + export interface ADelegate { + /** + * Find zero or one A that matches the filter. + * @param {AFindUniqueArgs} args - Arguments to find a A + * @example + * // Get one A + * const a = await prisma.a.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__AClient>> : CheckSelect, Prisma__AClient | null >> + + /** + * Find the first A that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AFindFirstArgs} args - Arguments to find a A + * @example + * // Get one A + * const a = await prisma.a.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__AClient>> : CheckSelect, Prisma__AClient | null >> + + /** + * Find zero or more As that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all As + * const as = await prisma.a.findMany() + * + * // Get first 10 As + * const as = await prisma.a.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const aWithIdOnly = await prisma.a.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a A. + * @param {ACreateArgs} args - Arguments to create a A. + * @example + * // Create one A + * const A = await prisma.a.create({ + * data: { + * // ... data to create a A + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__AClient>> + + /** + * Create many As. + * @param {ACreateManyArgs} args - Arguments to create many As. + * @example + * // Create many As + * const a = await prisma.a.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a A. + * @param {ADeleteArgs} args - Arguments to delete one A. + * @example + * // Delete one A + * const A = await prisma.a.delete({ + * where: { + * // ... filter to delete one A + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__AClient>> + + /** + * Update one A. + * @param {AUpdateArgs} args - Arguments to update one A. + * @example + * // Update one A + * const a = await prisma.a.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__AClient>> + + /** + * Delete zero or more As. + * @param {ADeleteManyArgs} args - Arguments to filter As to delete. + * @example + * // Delete a few As + * const { count } = await prisma.a.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more As. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many As + * const a = await prisma.a.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one A. + * @param {AUpsertArgs} args - Arguments to update or create a A. + * @example + * // Update or create a A + * const a = await prisma.a.upsert({ + * create: { + * // ... data to create a A + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the A we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__AClient>> + + /** + * Find zero or more As that matches the filter. + * @param {AFindRawArgs} args - Select which filters you would like to apply. + * @example + * const a = await prisma.a.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: AFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a A. + * @param {AAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const a = await prisma.a.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: AAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of As. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ACountArgs} args - Arguments to filter As to count. + * @example + * // Count the number of As + * const count = await prisma.a.count({ + * where: { + * // ... the filter for the As we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a A. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by A. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: AGroupByArgs['orderBy'] } + : { orderBy?: AGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetAGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for A. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__AClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * A findUnique + */ + export type AFindUniqueArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * Throw an Error if a A can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which A to fetch. + * + **/ + where: AWhereUniqueInput + } + + + /** + * A findFirst + */ + export type AFindFirstArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * Throw an Error if a A can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which A to fetch. + * + **/ + where?: AWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AS. + * + **/ + cursor?: AWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` AS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` AS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AS. + * + **/ + distinct?: Enumerable + } + + + /** + * A findMany + */ + export type AFindManyArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * Filter, which AS to fetch. + * + **/ + where?: AWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing AS. + * + **/ + cursor?: AWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` AS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` AS. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * A create + */ + export type ACreateArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * The data needed to create a A. + * + **/ + data: XOR + } + + + /** + * A createMany + */ + export type ACreateManyArgs = { + /** + * The data used to create many AS. + * + **/ + data: Enumerable + } + + + /** + * A update + */ + export type AUpdateArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * The data needed to update a A. + * + **/ + data: XOR + /** + * Choose, which A to update. + * + **/ + where: AWhereUniqueInput + } + + + /** + * A updateMany + */ + export type AUpdateManyArgs = { + /** + * The data used to update AS. + * + **/ + data: XOR + /** + * Filter which AS to update + * + **/ + where?: AWhereInput + } + + + /** + * A upsert + */ + export type AUpsertArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * The filter to search for the A to update in case it exists. + * + **/ + where: AWhereUniqueInput + /** + * In case the A found by the \`where\` argument doesn't exist, create a new A with this data. + * + **/ + create: XOR + /** + * In case the A was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * A delete + */ + export type ADeleteArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + /** + * Filter which A to delete. + * + **/ + where: AWhereUniqueInput + } + + + /** + * A deleteMany + */ + export type ADeleteManyArgs = { + /** + * Filter which AS to delete + * + **/ + where?: AWhereInput + } + + + /** + * A findRaw + */ + export type AFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * A aggregateRaw + */ + export type AAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * A without action + */ + export type AArgs = { + /** + * Select specific fields to fetch from the A + * + **/ + select?: ASelect | null + } + + + + /** + * Model B + */ + + + export type AggregateB = { + _count: BCountAggregateOutputType | null + _avg: BAvgAggregateOutputType | null + _sum: BSumAggregateOutputType | null + _min: BMinAggregateOutputType | null + _max: BMaxAggregateOutputType | null + } + + export type BAvgAggregateOutputType = { + float: number | null + dFloat: number | null + decFloat: Decimal | null + numFloat: Decimal | null + } + + export type BSumAggregateOutputType = { + float: number | null + dFloat: number | null + decFloat: Decimal | null + numFloat: Decimal | null + } + + export type BMinAggregateOutputType = { + id: string | null + float: number | null + dFloat: number | null + decFloat: Decimal | null + numFloat: Decimal | null + } + + export type BMaxAggregateOutputType = { + id: string | null + float: number | null + dFloat: number | null + decFloat: Decimal | null + numFloat: Decimal | null + } + + export type BCountAggregateOutputType = { + id: number + float: number + dFloat: number + decFloat: number + numFloat: number + _all: number + } + + + export type BAvgAggregateInputType = { + float?: true + dFloat?: true + decFloat?: true + numFloat?: true + } + + export type BSumAggregateInputType = { + float?: true + dFloat?: true + decFloat?: true + numFloat?: true + } + + export type BMinAggregateInputType = { + id?: true + float?: true + dFloat?: true + decFloat?: true + numFloat?: true + } + + export type BMaxAggregateInputType = { + id?: true + float?: true + dFloat?: true + decFloat?: true + numFloat?: true + } + + export type BCountAggregateInputType = { + id?: true + float?: true + dFloat?: true + decFloat?: true + numFloat?: true + _all?: true + } + + export type BAggregateArgs = { + /** + * Filter which B to aggregate. + * + **/ + where?: BWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of BS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: BWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` BS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` BS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned BS + **/ + _count?: true | BCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: BAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: BSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: BMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: BMaxAggregateInputType + } + + export type GetBAggregateType = { + [P in keyof T & keyof AggregateB]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type BGroupByArgs = { + where?: BWhereInput + orderBy?: Enumerable + by: Array + having?: BScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: BCountAggregateInputType | true + _avg?: BAvgAggregateInputType + _sum?: BSumAggregateInputType + _min?: BMinAggregateInputType + _max?: BMaxAggregateInputType + } + + + export type BGroupByOutputType = { + id: string + float: number + dFloat: number + decFloat: Decimal + numFloat: Decimal + _count: BCountAggregateOutputType | null + _avg: BAvgAggregateOutputType | null + _sum: BSumAggregateOutputType | null + _min: BMinAggregateOutputType | null + _max: BMaxAggregateOutputType | null + } + + type GetBGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof BGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type BSelect = { + id?: boolean + float?: boolean + dFloat?: boolean + decFloat?: boolean + numFloat?: boolean + } + + export type BGetPayload< + S extends boolean | null | undefined | BArgs, + U = keyof S + > = S extends true + ? B + : S extends undefined + ? never + : S extends BArgs | BFindManyArgs + ?'include' extends U + ? B + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof B ? B[P] : never + } + : B + : B + + + type BCountArgs = Merge< + Omit & { + select?: BCountAggregateInputType | true + } + > + + export interface BDelegate { + /** + * Find zero or one B that matches the filter. + * @param {BFindUniqueArgs} args - Arguments to find a B + * @example + * // Get one B + * const b = await prisma.b.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__BClient>> : CheckSelect, Prisma__BClient | null >> + + /** + * Find the first B that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {BFindFirstArgs} args - Arguments to find a B + * @example + * // Get one B + * const b = await prisma.b.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__BClient>> : CheckSelect, Prisma__BClient | null >> + + /** + * Find zero or more Bs that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {BFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Bs + * const bs = await prisma.b.findMany() + * + * // Get first 10 Bs + * const bs = await prisma.b.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const bWithIdOnly = await prisma.b.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a B. + * @param {BCreateArgs} args - Arguments to create a B. + * @example + * // Create one B + * const B = await prisma.b.create({ + * data: { + * // ... data to create a B + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__BClient>> + + /** + * Create many Bs. + * @param {BCreateManyArgs} args - Arguments to create many Bs. + * @example + * // Create many Bs + * const b = await prisma.b.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a B. + * @param {BDeleteArgs} args - Arguments to delete one B. + * @example + * // Delete one B + * const B = await prisma.b.delete({ + * where: { + * // ... filter to delete one B + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__BClient>> + + /** + * Update one B. + * @param {BUpdateArgs} args - Arguments to update one B. + * @example + * // Update one B + * const b = await prisma.b.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__BClient>> + + /** + * Delete zero or more Bs. + * @param {BDeleteManyArgs} args - Arguments to filter Bs to delete. + * @example + * // Delete a few Bs + * const { count } = await prisma.b.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Bs. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {BUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Bs + * const b = await prisma.b.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one B. + * @param {BUpsertArgs} args - Arguments to update or create a B. + * @example + * // Update or create a B + * const b = await prisma.b.upsert({ + * create: { + * // ... data to create a B + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the B we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__BClient>> + + /** + * Find zero or more Bs that matches the filter. + * @param {BFindRawArgs} args - Select which filters you would like to apply. + * @example + * const b = await prisma.b.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: BFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a B. + * @param {BAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const b = await prisma.b.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: BAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Bs. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {BCountArgs} args - Arguments to filter Bs to count. + * @example + * // Count the number of Bs + * const count = await prisma.b.count({ + * where: { + * // ... the filter for the Bs we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a B. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {BAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by B. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {BGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends BGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: BGroupByArgs['orderBy'] } + : { orderBy?: BGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetBGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for B. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__BClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * B findUnique + */ + export type BFindUniqueArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * Throw an Error if a B can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which B to fetch. + * + **/ + where: BWhereUniqueInput + } + + + /** + * B findFirst + */ + export type BFindFirstArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * Throw an Error if a B can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which B to fetch. + * + **/ + where?: BWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of BS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for BS. + * + **/ + cursor?: BWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` BS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` BS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of BS. + * + **/ + distinct?: Enumerable + } + + + /** + * B findMany + */ + export type BFindManyArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * Filter, which BS to fetch. + * + **/ + where?: BWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of BS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing BS. + * + **/ + cursor?: BWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` BS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` BS. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * B create + */ + export type BCreateArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * The data needed to create a B. + * + **/ + data: XOR + } + + + /** + * B createMany + */ + export type BCreateManyArgs = { + /** + * The data used to create many BS. + * + **/ + data: Enumerable + } + + + /** + * B update + */ + export type BUpdateArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * The data needed to update a B. + * + **/ + data: XOR + /** + * Choose, which B to update. + * + **/ + where: BWhereUniqueInput + } + + + /** + * B updateMany + */ + export type BUpdateManyArgs = { + /** + * The data used to update BS. + * + **/ + data: XOR + /** + * Filter which BS to update + * + **/ + where?: BWhereInput + } + + + /** + * B upsert + */ + export type BUpsertArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * The filter to search for the B to update in case it exists. + * + **/ + where: BWhereUniqueInput + /** + * In case the B found by the \`where\` argument doesn't exist, create a new B with this data. + * + **/ + create: XOR + /** + * In case the B was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * B delete + */ + export type BDeleteArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + /** + * Filter which B to delete. + * + **/ + where: BWhereUniqueInput + } + + + /** + * B deleteMany + */ + export type BDeleteManyArgs = { + /** + * Filter which BS to delete + * + **/ + where?: BWhereInput + } + + + /** + * B findRaw + */ + export type BFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * B aggregateRaw + */ + export type BAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * B without action + */ + export type BArgs = { + /** + * Select specific fields to fetch from the B + * + **/ + select?: BSelect | null + } + + + + /** + * Model C + */ + + + export type AggregateC = { + _count: CCountAggregateOutputType | null + _min: CMinAggregateOutputType | null + _max: CMaxAggregateOutputType | null + } + + export type CMinAggregateOutputType = { + id: string | null + char: string | null + vChar: string | null + text: string | null + bit: string | null + vBit: string | null + uuid: string | null + } + + export type CMaxAggregateOutputType = { + id: string | null + char: string | null + vChar: string | null + text: string | null + bit: string | null + vBit: string | null + uuid: string | null + } + + export type CCountAggregateOutputType = { + id: number + char: number + vChar: number + text: number + bit: number + vBit: number + uuid: number + _all: number + } + + + export type CMinAggregateInputType = { + id?: true + char?: true + vChar?: true + text?: true + bit?: true + vBit?: true + uuid?: true + } + + export type CMaxAggregateInputType = { + id?: true + char?: true + vChar?: true + text?: true + bit?: true + vBit?: true + uuid?: true + } + + export type CCountAggregateInputType = { + id?: true + char?: true + vChar?: true + text?: true + bit?: true + vBit?: true + uuid?: true + _all?: true + } + + export type CAggregateArgs = { + /** + * Filter which C to aggregate. + * + **/ + where?: CWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of CS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: CWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` CS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` CS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned CS + **/ + _count?: true | CCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: CMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: CMaxAggregateInputType + } + + export type GetCAggregateType = { + [P in keyof T & keyof AggregateC]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type CGroupByArgs = { + where?: CWhereInput + orderBy?: Enumerable + by: Array + having?: CScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: CCountAggregateInputType | true + _min?: CMinAggregateInputType + _max?: CMaxAggregateInputType + } + + + export type CGroupByOutputType = { + id: string + char: string + vChar: string + text: string + bit: string + vBit: string + uuid: string + _count: CCountAggregateOutputType | null + _min: CMinAggregateOutputType | null + _max: CMaxAggregateOutputType | null + } + + type GetCGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof CGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type CSelect = { + id?: boolean + char?: boolean + vChar?: boolean + text?: boolean + bit?: boolean + vBit?: boolean + uuid?: boolean + } + + export type CGetPayload< + S extends boolean | null | undefined | CArgs, + U = keyof S + > = S extends true + ? C + : S extends undefined + ? never + : S extends CArgs | CFindManyArgs + ?'include' extends U + ? C + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof C ? C[P] : never + } + : C + : C + + + type CCountArgs = Merge< + Omit & { + select?: CCountAggregateInputType | true + } + > + + export interface CDelegate { + /** + * Find zero or one C that matches the filter. + * @param {CFindUniqueArgs} args - Arguments to find a C + * @example + * // Get one C + * const c = await prisma.c.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__CClient>> : CheckSelect, Prisma__CClient | null >> + + /** + * Find the first C that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CFindFirstArgs} args - Arguments to find a C + * @example + * // Get one C + * const c = await prisma.c.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__CClient>> : CheckSelect, Prisma__CClient | null >> + + /** + * Find zero or more Cs that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Cs + * const cs = await prisma.c.findMany() + * + * // Get first 10 Cs + * const cs = await prisma.c.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const cWithIdOnly = await prisma.c.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a C. + * @param {CCreateArgs} args - Arguments to create a C. + * @example + * // Create one C + * const C = await prisma.c.create({ + * data: { + * // ... data to create a C + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__CClient>> + + /** + * Create many Cs. + * @param {CCreateManyArgs} args - Arguments to create many Cs. + * @example + * // Create many Cs + * const c = await prisma.c.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a C. + * @param {CDeleteArgs} args - Arguments to delete one C. + * @example + * // Delete one C + * const C = await prisma.c.delete({ + * where: { + * // ... filter to delete one C + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__CClient>> + + /** + * Update one C. + * @param {CUpdateArgs} args - Arguments to update one C. + * @example + * // Update one C + * const c = await prisma.c.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__CClient>> + + /** + * Delete zero or more Cs. + * @param {CDeleteManyArgs} args - Arguments to filter Cs to delete. + * @example + * // Delete a few Cs + * const { count } = await prisma.c.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Cs. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Cs + * const c = await prisma.c.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one C. + * @param {CUpsertArgs} args - Arguments to update or create a C. + * @example + * // Update or create a C + * const c = await prisma.c.upsert({ + * create: { + * // ... data to create a C + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the C we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__CClient>> + + /** + * Find zero or more Cs that matches the filter. + * @param {CFindRawArgs} args - Select which filters you would like to apply. + * @example + * const c = await prisma.c.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: CFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a C. + * @param {CAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const c = await prisma.c.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: CAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Cs. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CCountArgs} args - Arguments to filter Cs to count. + * @example + * // Count the number of Cs + * const count = await prisma.c.count({ + * where: { + * // ... the filter for the Cs we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a C. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by C. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends CGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: CGroupByArgs['orderBy'] } + : { orderBy?: CGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetCGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for C. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__CClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * C findUnique + */ + export type CFindUniqueArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * Throw an Error if a C can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which C to fetch. + * + **/ + where: CWhereUniqueInput + } + + + /** + * C findFirst + */ + export type CFindFirstArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * Throw an Error if a C can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which C to fetch. + * + **/ + where?: CWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of CS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for CS. + * + **/ + cursor?: CWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` CS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` CS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of CS. + * + **/ + distinct?: Enumerable + } + + + /** + * C findMany + */ + export type CFindManyArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * Filter, which CS to fetch. + * + **/ + where?: CWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of CS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing CS. + * + **/ + cursor?: CWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` CS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` CS. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * C create + */ + export type CCreateArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * The data needed to create a C. + * + **/ + data: XOR + } + + + /** + * C createMany + */ + export type CCreateManyArgs = { + /** + * The data used to create many CS. + * + **/ + data: Enumerable + } + + + /** + * C update + */ + export type CUpdateArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * The data needed to update a C. + * + **/ + data: XOR + /** + * Choose, which C to update. + * + **/ + where: CWhereUniqueInput + } + + + /** + * C updateMany + */ + export type CUpdateManyArgs = { + /** + * The data used to update CS. + * + **/ + data: XOR + /** + * Filter which CS to update + * + **/ + where?: CWhereInput + } + + + /** + * C upsert + */ + export type CUpsertArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * The filter to search for the C to update in case it exists. + * + **/ + where: CWhereUniqueInput + /** + * In case the C found by the \`where\` argument doesn't exist, create a new C with this data. + * + **/ + create: XOR + /** + * In case the C was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * C delete + */ + export type CDeleteArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + /** + * Filter which C to delete. + * + **/ + where: CWhereUniqueInput + } + + + /** + * C deleteMany + */ + export type CDeleteManyArgs = { + /** + * Filter which CS to delete + * + **/ + where?: CWhereInput + } + + + /** + * C findRaw + */ + export type CFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * C aggregateRaw + */ + export type CAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * C without action + */ + export type CArgs = { + /** + * Select specific fields to fetch from the C + * + **/ + select?: CSelect | null + } + + + + /** + * Model D + */ + + + export type AggregateD = { + _count: DCountAggregateOutputType | null + _min: DMinAggregateOutputType | null + _max: DMaxAggregateOutputType | null + } + + export type DMinAggregateOutputType = { + id: string | null + bool: boolean | null + byteA: Buffer | null + xml: string | null + } + + export type DMaxAggregateOutputType = { + id: string | null + bool: boolean | null + byteA: Buffer | null + xml: string | null + } + + export type DCountAggregateOutputType = { + id: number + bool: number + byteA: number + xml: number + json: number + jsonb: number + _all: number + } + + + export type DMinAggregateInputType = { + id?: true + bool?: true + byteA?: true + xml?: true + } + + export type DMaxAggregateInputType = { + id?: true + bool?: true + byteA?: true + xml?: true + } + + export type DCountAggregateInputType = { + id?: true + bool?: true + byteA?: true + xml?: true + json?: true + jsonb?: true + _all?: true + } + + export type DAggregateArgs = { + /** + * Filter which D to aggregate. + * + **/ + where?: DWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of DS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: DWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` DS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` DS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned DS + **/ + _count?: true | DCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: DMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: DMaxAggregateInputType + } + + export type GetDAggregateType = { + [P in keyof T & keyof AggregateD]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type DGroupByArgs = { + where?: DWhereInput + orderBy?: Enumerable + by: Array + having?: DScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: DCountAggregateInputType | true + _min?: DMinAggregateInputType + _max?: DMaxAggregateInputType + } + + + export type DGroupByOutputType = { + id: string + bool: boolean + byteA: Buffer + xml: string + json: JsonValue + jsonb: JsonValue + _count: DCountAggregateOutputType | null + _min: DMinAggregateOutputType | null + _max: DMaxAggregateOutputType | null + } + + type GetDGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof DGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type DSelect = { + id?: boolean + bool?: boolean + byteA?: boolean + xml?: boolean + json?: boolean + jsonb?: boolean + } + + export type DGetPayload< + S extends boolean | null | undefined | DArgs, + U = keyof S + > = S extends true + ? D + : S extends undefined + ? never + : S extends DArgs | DFindManyArgs + ?'include' extends U + ? D + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof D ? D[P] : never + } + : D + : D + + + type DCountArgs = Merge< + Omit & { + select?: DCountAggregateInputType | true + } + > + + export interface DDelegate { + /** + * Find zero or one D that matches the filter. + * @param {DFindUniqueArgs} args - Arguments to find a D + * @example + * // Get one D + * const d = await prisma.d.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__DClient>> : CheckSelect, Prisma__DClient | null >> + + /** + * Find the first D that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {DFindFirstArgs} args - Arguments to find a D + * @example + * // Get one D + * const d = await prisma.d.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__DClient>> : CheckSelect, Prisma__DClient | null >> + + /** + * Find zero or more Ds that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {DFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Ds + * const ds = await prisma.d.findMany() + * + * // Get first 10 Ds + * const ds = await prisma.d.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const dWithIdOnly = await prisma.d.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a D. + * @param {DCreateArgs} args - Arguments to create a D. + * @example + * // Create one D + * const D = await prisma.d.create({ + * data: { + * // ... data to create a D + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__DClient>> + + /** + * Create many Ds. + * @param {DCreateManyArgs} args - Arguments to create many Ds. + * @example + * // Create many Ds + * const d = await prisma.d.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a D. + * @param {DDeleteArgs} args - Arguments to delete one D. + * @example + * // Delete one D + * const D = await prisma.d.delete({ + * where: { + * // ... filter to delete one D + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__DClient>> + + /** + * Update one D. + * @param {DUpdateArgs} args - Arguments to update one D. + * @example + * // Update one D + * const d = await prisma.d.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__DClient>> + + /** + * Delete zero or more Ds. + * @param {DDeleteManyArgs} args - Arguments to filter Ds to delete. + * @example + * // Delete a few Ds + * const { count } = await prisma.d.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Ds. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {DUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Ds + * const d = await prisma.d.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one D. + * @param {DUpsertArgs} args - Arguments to update or create a D. + * @example + * // Update or create a D + * const d = await prisma.d.upsert({ + * create: { + * // ... data to create a D + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the D we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__DClient>> + + /** + * Find zero or more Ds that matches the filter. + * @param {DFindRawArgs} args - Select which filters you would like to apply. + * @example + * const d = await prisma.d.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: DFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a D. + * @param {DAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const d = await prisma.d.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: DAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Ds. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {DCountArgs} args - Arguments to filter Ds to count. + * @example + * // Count the number of Ds + * const count = await prisma.d.count({ + * where: { + * // ... the filter for the Ds we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a D. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {DAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by D. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {DGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends DGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: DGroupByArgs['orderBy'] } + : { orderBy?: DGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetDGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for D. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__DClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * D findUnique + */ + export type DFindUniqueArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * Throw an Error if a D can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which D to fetch. + * + **/ + where: DWhereUniqueInput + } + + + /** + * D findFirst + */ + export type DFindFirstArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * Throw an Error if a D can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which D to fetch. + * + **/ + where?: DWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of DS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for DS. + * + **/ + cursor?: DWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` DS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` DS. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of DS. + * + **/ + distinct?: Enumerable + } + + + /** + * D findMany + */ + export type DFindManyArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * Filter, which DS to fetch. + * + **/ + where?: DWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of DS to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing DS. + * + **/ + cursor?: DWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` DS from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` DS. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * D create + */ + export type DCreateArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * The data needed to create a D. + * + **/ + data: XOR + } + + + /** + * D createMany + */ + export type DCreateManyArgs = { + /** + * The data used to create many DS. + * + **/ + data: Enumerable + } + + + /** + * D update + */ + export type DUpdateArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * The data needed to update a D. + * + **/ + data: XOR + /** + * Choose, which D to update. + * + **/ + where: DWhereUniqueInput + } + + + /** + * D updateMany + */ + export type DUpdateManyArgs = { + /** + * The data used to update DS. + * + **/ + data: XOR + /** + * Filter which DS to update + * + **/ + where?: DWhereInput + } + + + /** + * D upsert + */ + export type DUpsertArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * The filter to search for the D to update in case it exists. + * + **/ + where: DWhereUniqueInput + /** + * In case the D found by the \`where\` argument doesn't exist, create a new D with this data. + * + **/ + create: XOR + /** + * In case the D was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * D delete + */ + export type DDeleteArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + /** + * Filter which D to delete. + * + **/ + where: DWhereUniqueInput + } + + + /** + * D deleteMany + */ + export type DDeleteManyArgs = { + /** + * Filter which DS to delete + * + **/ + where?: DWhereInput + } + + + /** + * D findRaw + */ + export type DFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * D aggregateRaw + */ + export type DAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * D without action + */ + export type DArgs = { + /** + * Select specific fields to fetch from the D + * + **/ + select?: DSelect | null + } + + + + /** + * Model E + */ + + + export type AggregateE = { + _count: ECountAggregateOutputType | null + _min: EMinAggregateOutputType | null + _max: EMaxAggregateOutputType | null + } + + export type EMinAggregateOutputType = { + id: string | null + date: Date | null + time: Date | null + ts: Date | null + } + + export type EMaxAggregateOutputType = { + id: string | null + date: Date | null + time: Date | null + ts: Date | null + } + + export type ECountAggregateOutputType = { + id: number + date: number + time: number + ts: number + _all: number + } + + + export type EMinAggregateInputType = { + id?: true + date?: true + time?: true + ts?: true + } + + export type EMaxAggregateInputType = { + id?: true + date?: true + time?: true + ts?: true + } + + export type ECountAggregateInputType = { + id?: true + date?: true + time?: true + ts?: true + _all?: true + } + + export type EAggregateArgs = { + /** + * Filter which E to aggregate. + * + **/ + where?: EWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ES to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + * + **/ + cursor?: EWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` ES from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` ES. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned ES + **/ + _count?: true | ECountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: EMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: EMaxAggregateInputType + } + + export type GetEAggregateType = { + [P in keyof T & keyof AggregateE]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type EGroupByArgs = { + where?: EWhereInput + orderBy?: Enumerable + by: Array + having?: EScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: ECountAggregateInputType | true + _min?: EMinAggregateInputType + _max?: EMaxAggregateInputType + } + + + export type EGroupByOutputType = { + id: string + date: Date + time: Date + ts: Date + _count: ECountAggregateOutputType | null + _min: EMinAggregateOutputType | null + _max: EMaxAggregateOutputType | null + } + + type GetEGroupByPayload = PrismaPromise< + Array< + PickArray & + { + [P in ((keyof T) & (keyof EGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type ESelect = { + id?: boolean + date?: boolean + time?: boolean + ts?: boolean + } + + export type EGetPayload< + S extends boolean | null | undefined | EArgs, + U = keyof S + > = S extends true + ? E + : S extends undefined + ? never + : S extends EArgs | EFindManyArgs + ?'include' extends U + ? E + : 'select' extends U + ? { + [P in TrueKeys]: + P extends keyof E ? E[P] : never + } + : E + : E + + + type ECountArgs = Merge< + Omit & { + select?: ECountAggregateInputType | true + } + > + + export interface EDelegate { + /** + * Find zero or one E that matches the filter. + * @param {EFindUniqueArgs} args - Arguments to find a E + * @example + * // Get one E + * const e = await prisma.e.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findUnique( + args: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__EClient>> : CheckSelect, Prisma__EClient | null >> + + /** + * Find the first E that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EFindFirstArgs} args - Arguments to find a E + * @example + * // Get one E + * const e = await prisma.e.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + **/ + findFirst( + args?: SelectSubset + ): HasReject extends True ? CheckSelect, Prisma__EClient>> : CheckSelect, Prisma__EClient | null >> + + /** + * Find zero or more Es that matches the filter. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EFindManyArgs=} args - Arguments to filter and select certain fields only. + * @example + * // Get all Es + * const es = await prisma.e.findMany() + * + * // Get first 10 Es + * const es = await prisma.e.findMany({ take: 10 }) + * + * // Only select the \`id\` + * const eWithIdOnly = await prisma.e.findMany({ select: { id: true } }) + * + **/ + findMany( + args?: SelectSubset + ): CheckSelect>, PrismaPromise>>> + + /** + * Create a E. + * @param {ECreateArgs} args - Arguments to create a E. + * @example + * // Create one E + * const E = await prisma.e.create({ + * data: { + * // ... data to create a E + * } + * }) + * + **/ + create( + args: SelectSubset + ): CheckSelect, Prisma__EClient>> + + /** + * Create many Es. + * @param {ECreateManyArgs} args - Arguments to create many Es. + * @example + * // Create many Es + * const e = await prisma.e.createMany({ + * data: { + * // ... provide data here + * } + * }) + * + **/ + createMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Delete a E. + * @param {EDeleteArgs} args - Arguments to delete one E. + * @example + * // Delete one E + * const E = await prisma.e.delete({ + * where: { + * // ... filter to delete one E + * } + * }) + * + **/ + delete( + args: SelectSubset + ): CheckSelect, Prisma__EClient>> + + /** + * Update one E. + * @param {EUpdateArgs} args - Arguments to update one E. + * @example + * // Update one E + * const e = await prisma.e.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + update( + args: SelectSubset + ): CheckSelect, Prisma__EClient>> + + /** + * Delete zero or more Es. + * @param {EDeleteManyArgs} args - Arguments to filter Es to delete. + * @example + * // Delete a few Es + * const { count } = await prisma.e.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + **/ + deleteMany( + args?: SelectSubset + ): PrismaPromise + + /** + * Update zero or more Es. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Es + * const e = await prisma.e.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + **/ + updateMany( + args: SelectSubset + ): PrismaPromise + + /** + * Create or update one E. + * @param {EUpsertArgs} args - Arguments to update or create a E. + * @example + * // Update or create a E + * const e = await prisma.e.upsert({ + * create: { + * // ... data to create a E + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the E we want to update + * } + * }) + **/ + upsert( + args: SelectSubset + ): CheckSelect, Prisma__EClient>> + + /** + * Find zero or more Es that matches the filter. + * @param {EFindRawArgs} args - Select which filters you would like to apply. + * @example + * const e = await prisma.e.findRaw({ + * filter: { age: { $gt: 25 } } + * }) + **/ + findRaw( + args?: EFindRawArgs + ): PrismaPromise + + /** + * Perform aggregation operations on a E. + * @param {EAggregateRawArgs} args - Select which aggregations you would like to apply. + * @example + * const e = await prisma.e.aggregateRaw({ + * pipeline: [ + * { $match: { status: "registered" } }, + * { $group: { _id: "$country", total: { $sum: 1 } } } + * ] + * }) + **/ + aggregateRaw( + args?: EAggregateRawArgs + ): PrismaPromise + + /** + * Count the number of Es. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ECountArgs} args - Arguments to filter Es to count. + * @example + * // Count the number of Es + * const count = await prisma.e.count({ + * where: { + * // ... the filter for the Es we want to count + * } + * }) + **/ + count( + args?: Subset, + ): PrismaPromise< + T extends _Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a E. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): PrismaPromise> + + /** + * Group by E. + * Note, that providing \`undefined\` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {EGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends EGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: EGroupByArgs['orderBy'] } + : { orderBy?: EGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends TupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? \`Error: "by" must not be empty.\` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? \`Error: Field "\${P}" used in "having" needs to be provided in "by".\` + : [ + Error, + 'Field ', + P, + \` in "having" needs to be provided in "by"\`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetEGroupByPayload : PrismaPromise + } + + /** + * The delegate class that acts as a "Promise-like" for E. + * Why is this prefixed with \`Prisma__\`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export class Prisma__EClient implements PrismaPromise { + [prisma]: true; + private readonly _dmmf; + private readonly _fetcher; + private readonly _queryType; + private readonly _rootField; + private readonly _clientMethod; + private readonly _args; + private readonly _dataPath; + private readonly _errorFormat; + private readonly _measurePerformance?; + private _isList; + private _callsite; + private _requestPromise?; + constructor(_dmmf: runtime.DMMFClass, _fetcher: PrismaClientFetcher, _queryType: 'query' | 'mutation', _rootField: string, _clientMethod: string, _args: any, _dataPath: string[], _errorFormat: ErrorFormat, _measurePerformance?: boolean | undefined, _isList?: boolean); + readonly [Symbol.toStringTag]: 'PrismaClientPromise'; + + + private get _document(); + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): Promise; + } + + // Custom InputTypes + + /** + * E findUnique + */ + export type EFindUniqueArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * Throw an Error if a E can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which E to fetch. + * + **/ + where: EWhereUniqueInput + } + + + /** + * E findFirst + */ + export type EFindFirstArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * Throw an Error if a E can't be found + * + **/ + rejectOnNotFound?: RejectOnNotFound + /** + * Filter, which E to fetch. + * + **/ + where?: EWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ES to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for ES. + * + **/ + cursor?: EWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` ES from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` ES. + * + **/ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of ES. + * + **/ + distinct?: Enumerable + } + + + /** + * E findMany + */ + export type EFindManyArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * Filter, which ES to fetch. + * + **/ + where?: EWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ES to fetch. + * + **/ + orderBy?: Enumerable + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing ES. + * + **/ + cursor?: EWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take \`±n\` ES from the position of the cursor. + * + **/ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first \`n\` ES. + * + **/ + skip?: number + distinct?: Enumerable + } + + + /** + * E create + */ + export type ECreateArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * The data needed to create a E. + * + **/ + data: XOR + } + + + /** + * E createMany + */ + export type ECreateManyArgs = { + /** + * The data used to create many ES. + * + **/ + data: Enumerable + } + + + /** + * E update + */ + export type EUpdateArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * The data needed to update a E. + * + **/ + data: XOR + /** + * Choose, which E to update. + * + **/ + where: EWhereUniqueInput + } + + + /** + * E updateMany + */ + export type EUpdateManyArgs = { + /** + * The data used to update ES. + * + **/ + data: XOR + /** + * Filter which ES to update + * + **/ + where?: EWhereInput + } + + + /** + * E upsert + */ + export type EUpsertArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * The filter to search for the E to update in case it exists. + * + **/ + where: EWhereUniqueInput + /** + * In case the E found by the \`where\` argument doesn't exist, create a new E with this data. + * + **/ + create: XOR + /** + * In case the E was found with the provided \`where\` argument, update it with this data. + * + **/ + update: XOR + } + + + /** + * E delete + */ + export type EDeleteArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + /** + * Filter which E to delete. + * + **/ + where: EWhereUniqueInput + } + + + /** + * E deleteMany + */ + export type EDeleteManyArgs = { + /** + * Filter which ES to delete + * + **/ + where?: EWhereInput + } + + + /** + * E findRaw + */ + export type EFindRawArgs = { + /** + * The query predicate filter. If unspecified, then all documents in the collection will match the predicate. \${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}. + * + **/ + filter?: InputJsonValue + /** + * Additional options to pass to the \`find\` command \${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * E aggregateRaw + */ + export type EAggregateRawArgs = { + /** + * An array of aggregation stages to process and transform the document stream via the aggregation pipeline. \${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}. + * + **/ + pipeline?: Array + /** + * Additional options to pass to the \`aggregate\` command \${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}. + * + **/ + options?: InputJsonValue + } + + + /** + * E without action + */ + export type EArgs = { + /** + * Select specific fields to fetch from the E + * + **/ + select?: ESelect | null + } + + + + /** + * Enums + */ + + // Based on + // https://github.com/microsoft/TypeScript/issues/3192#issuecomment-261720275 + + export const PostScalarFieldEnum: { + id: 'id', + createdAt: 'createdAt', + title: 'title', + content: 'content', + published: 'published', + authorId: 'authorId' + }; + + export type PostScalarFieldEnum = (typeof PostScalarFieldEnum)[keyof typeof PostScalarFieldEnum] + + + export const UserScalarFieldEnum: { + id: 'id', + email: 'email', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean', + embedHolderId: 'embedHolderId' + }; + + export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] + + + export const EmbedHolderScalarFieldEnum: { + id: 'id', + time: 'time', + text: 'text', + boolean: 'boolean' + }; + + export type EmbedHolderScalarFieldEnum = (typeof EmbedHolderScalarFieldEnum)[keyof typeof EmbedHolderScalarFieldEnum] + + + export const MScalarFieldEnum: { + id: 'id', + n_ids: 'n_ids', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' + }; + + export type MScalarFieldEnum = (typeof MScalarFieldEnum)[keyof typeof MScalarFieldEnum] + + + export const NScalarFieldEnum: { + id: 'id', + m_ids: 'm_ids', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' + }; + + export type NScalarFieldEnum = (typeof NScalarFieldEnum)[keyof typeof NScalarFieldEnum] + + + export const OneOptionalScalarFieldEnum: { + id: 'id', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' + }; + + export type OneOptionalScalarFieldEnum = (typeof OneOptionalScalarFieldEnum)[keyof typeof OneOptionalScalarFieldEnum] + + + export const ManyRequiredScalarFieldEnum: { + id: 'id', + oneOptionalId: 'oneOptionalId', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' + }; + + export type ManyRequiredScalarFieldEnum = (typeof ManyRequiredScalarFieldEnum)[keyof typeof ManyRequiredScalarFieldEnum] + + + export const OptionalSide1ScalarFieldEnum: { + id: 'id', + optionalSide2Id: 'optionalSide2Id', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' + }; + + export type OptionalSide1ScalarFieldEnum = (typeof OptionalSide1ScalarFieldEnum)[keyof typeof OptionalSide1ScalarFieldEnum] + + + export const OptionalSide2ScalarFieldEnum: { + id: 'id', + int: 'int', + optionalInt: 'optionalInt', + float: 'float', + optionalFloat: 'optionalFloat', + string: 'string', + optionalString: 'optionalString', + json: 'json', + optionalJson: 'optionalJson', + enum: 'enum', + optionalEnum: 'optionalEnum', + boolean: 'boolean', + optionalBoolean: 'optionalBoolean' + }; + + export type OptionalSide2ScalarFieldEnum = (typeof OptionalSide2ScalarFieldEnum)[keyof typeof OptionalSide2ScalarFieldEnum] + + + export const AScalarFieldEnum: { + id: 'id', + email: 'email', + name: 'name', + int: 'int', + sInt: 'sInt', + bInt: 'bInt' + }; + + export type AScalarFieldEnum = (typeof AScalarFieldEnum)[keyof typeof AScalarFieldEnum] + + + export const BScalarFieldEnum: { + id: 'id', + float: 'float', + dFloat: 'dFloat', + decFloat: 'decFloat', + numFloat: 'numFloat' + }; + + export type BScalarFieldEnum = (typeof BScalarFieldEnum)[keyof typeof BScalarFieldEnum] + + + export const CScalarFieldEnum: { + id: 'id', + char: 'char', + vChar: 'vChar', + text: 'text', + bit: 'bit', + vBit: 'vBit', + uuid: 'uuid' + }; + + export type CScalarFieldEnum = (typeof CScalarFieldEnum)[keyof typeof CScalarFieldEnum] + + + export const DScalarFieldEnum: { + id: 'id', + bool: 'bool', + byteA: 'byteA', + xml: 'xml', + json: 'json', + jsonb: 'jsonb' + }; + + export type DScalarFieldEnum = (typeof DScalarFieldEnum)[keyof typeof DScalarFieldEnum] + + + export const EScalarFieldEnum: { + id: 'id', + date: 'date', + time: 'time', + ts: 'ts' + }; + + export type EScalarFieldEnum = (typeof EScalarFieldEnum)[keyof typeof EScalarFieldEnum] + + + export const SortOrder: { + asc: 'asc', + desc: 'desc' + }; + + export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder] + + + export const QueryMode: { + default: 'default', + insensitive: 'insensitive' + }; + + export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode] + + + /** + * Deep Input Types + */ + + + export type PostWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + createdAt?: DateTimeFilter | Date | string + title?: StringFilter | string + content?: StringNullableFilter | string | null + published?: BoolFilter | boolean + author?: XOR + authorId?: IntFilter | number + } + + export type PostOrderByWithRelationInput = { + id?: SortOrder + createdAt?: SortOrder + title?: SortOrder + content?: SortOrder + published?: SortOrder + author?: UserOrderByWithRelationInput + authorId?: SortOrder + } + + export type PostWhereUniqueInput = { + id?: string + } + + export type PostOrderByWithAggregationInput = { + id?: SortOrder + createdAt?: SortOrder + title?: SortOrder + content?: SortOrder + published?: SortOrder + authorId?: SortOrder + _count?: PostCountOrderByAggregateInput + _avg?: PostAvgOrderByAggregateInput + _max?: PostMaxOrderByAggregateInput + _min?: PostMinOrderByAggregateInput + _sum?: PostSumOrderByAggregateInput + } + + export type PostScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + createdAt?: DateTimeWithAggregatesFilter | Date | string + title?: StringWithAggregatesFilter | string + content?: StringNullableWithAggregatesFilter | string | null + published?: BoolWithAggregatesFilter | boolean + authorId?: IntWithAggregatesFilter | number + } + + export type UserWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + email?: StringFilter | string + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + posts?: PostListRelationFilter + embedHolder?: XOR + embedHolderId?: StringFilter | string + } + + export type UserOrderByWithRelationInput = { + id?: SortOrder + email?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + posts?: PostOrderByRelationAggregateInput + embedHolder?: EmbedHolderOrderByWithRelationInput + embedHolderId?: SortOrder + } + + export type UserWhereUniqueInput = { + id?: string + email?: string + } + + export type UserOrderByWithAggregationInput = { + id?: SortOrder + email?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + embedHolderId?: SortOrder + _count?: UserCountOrderByAggregateInput + _avg?: UserAvgOrderByAggregateInput + _max?: UserMaxOrderByAggregateInput + _min?: UserMinOrderByAggregateInput + _sum?: UserSumOrderByAggregateInput + } + + export type UserScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + email?: StringWithAggregatesFilter | string + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + embedHolderId?: StringWithAggregatesFilter | string + } + + export type EmbedHolderWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + id?: StringFilter | string + time?: DateTimeFilter | Date | string + text?: StringFilter | string + boolean?: BoolFilter | boolean + User?: UserListRelationFilter + } + + export type EmbedHolderOrderByWithRelationInput = { + embedList?: EmbedOrderByCompositeAggregateInput + requiredEmbed?: EmbedOrderByInput + optionalEmbed?: EmbedOrderByInput + id?: SortOrder + time?: SortOrder + text?: SortOrder + boolean?: SortOrder + User?: UserOrderByRelationAggregateInput + } + + export type EmbedHolderWhereUniqueInput = { + id?: string + } + + export type EmbedHolderOrderByWithAggregationInput = { + id?: SortOrder + time?: SortOrder + text?: SortOrder + boolean?: SortOrder + _count?: EmbedHolderCountOrderByAggregateInput + _max?: EmbedHolderMaxOrderByAggregateInput + _min?: EmbedHolderMinOrderByAggregateInput + } + + export type EmbedHolderScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + time?: DateTimeWithAggregatesFilter | Date | string + text?: StringWithAggregatesFilter | string + boolean?: BoolWithAggregatesFilter | boolean + } + + export type MWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + n_ids?: StringNullableListFilter + n?: NListRelationFilter + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type MOrderByWithRelationInput = { + id?: SortOrder + n_ids?: SortOrder + n?: NOrderByRelationAggregateInput + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type MWhereUniqueInput = { + id?: string + } + + export type MOrderByWithAggregationInput = { + id?: SortOrder + n_ids?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + _count?: MCountOrderByAggregateInput + _avg?: MAvgOrderByAggregateInput + _max?: MMaxOrderByAggregateInput + _min?: MMinOrderByAggregateInput + _sum?: MSumOrderByAggregateInput + } + + export type MScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + n_ids?: StringNullableListFilter + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + } + + export type NWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + m_ids?: StringNullableListFilter + m?: MListRelationFilter + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type NOrderByWithRelationInput = { + id?: SortOrder + m_ids?: SortOrder + m?: MOrderByRelationAggregateInput + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type NWhereUniqueInput = { + id?: string + } + + export type NOrderByWithAggregationInput = { + id?: SortOrder + m_ids?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + _count?: NCountOrderByAggregateInput + _avg?: NAvgOrderByAggregateInput + _max?: NMaxOrderByAggregateInput + _min?: NMinOrderByAggregateInput + _sum?: NSumOrderByAggregateInput + } + + export type NScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + m_ids?: StringNullableListFilter + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + } + + export type OneOptionalWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + many?: ManyRequiredListRelationFilter + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type OneOptionalOrderByWithRelationInput = { + id?: SortOrder + many?: ManyRequiredOrderByRelationAggregateInput + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OneOptionalWhereUniqueInput = { + id?: string + } + + export type OneOptionalOrderByWithAggregationInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + _count?: OneOptionalCountOrderByAggregateInput + _avg?: OneOptionalAvgOrderByAggregateInput + _max?: OneOptionalMaxOrderByAggregateInput + _min?: OneOptionalMinOrderByAggregateInput + _sum?: OneOptionalSumOrderByAggregateInput + } + + export type OneOptionalScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + } + + export type ManyRequiredWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + one?: XOR | null + oneOptionalId?: IntNullableFilter | number | null + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type ManyRequiredOrderByWithRelationInput = { + id?: SortOrder + one?: OneOptionalOrderByWithRelationInput + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type ManyRequiredWhereUniqueInput = { + id?: string + } + + export type ManyRequiredOrderByWithAggregationInput = { + id?: SortOrder + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + _count?: ManyRequiredCountOrderByAggregateInput + _avg?: ManyRequiredAvgOrderByAggregateInput + _max?: ManyRequiredMaxOrderByAggregateInput + _min?: ManyRequiredMinOrderByAggregateInput + _sum?: ManyRequiredSumOrderByAggregateInput + } + + export type ManyRequiredScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + oneOptionalId?: IntNullableWithAggregatesFilter | number | null + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + } + + export type OptionalSide1WhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + opti?: XOR | null + optionalSide2Id?: IntNullableFilter | number | null + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type OptionalSide1OrderByWithRelationInput = { + id?: SortOrder + opti?: OptionalSide2OrderByWithRelationInput + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide1WhereUniqueInput = { + id?: string + optionalSide2Id?: number + } + + export type OptionalSide1OrderByWithAggregationInput = { + id?: SortOrder + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + _count?: OptionalSide1CountOrderByAggregateInput + _avg?: OptionalSide1AvgOrderByAggregateInput + _max?: OptionalSide1MaxOrderByAggregateInput + _min?: OptionalSide1MinOrderByAggregateInput + _sum?: OptionalSide1SumOrderByAggregateInput + } + + export type OptionalSide1ScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + optionalSide2Id?: IntNullableWithAggregatesFilter | number | null + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + } + + export type OptionalSide2WhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + opti?: XOR | null + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type OptionalSide2OrderByWithRelationInput = { + id?: SortOrder + opti?: OptionalSide1OrderByWithRelationInput + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide2WhereUniqueInput = { + id?: string + } + + export type OptionalSide2OrderByWithAggregationInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + _count?: OptionalSide2CountOrderByAggregateInput + _avg?: OptionalSide2AvgOrderByAggregateInput + _max?: OptionalSide2MaxOrderByAggregateInput + _min?: OptionalSide2MinOrderByAggregateInput + _sum?: OptionalSide2SumOrderByAggregateInput + } + + export type OptionalSide2ScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + int?: IntWithAggregatesFilter | number + optionalInt?: IntNullableWithAggregatesFilter | number | null + float?: FloatWithAggregatesFilter | number + optionalFloat?: FloatNullableWithAggregatesFilter | number | null + string?: StringWithAggregatesFilter | string + optionalString?: StringNullableWithAggregatesFilter | string | null + json?: JsonWithAggregatesFilter + optionalJson?: JsonNullableWithAggregatesFilter + enum?: EnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + boolean?: BoolWithAggregatesFilter | boolean + optionalBoolean?: BoolNullableWithAggregatesFilter | boolean | null + } + + export type AWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + email?: StringFilter | string + name?: StringNullableFilter | string | null + int?: IntFilter | number + sInt?: IntFilter | number + bInt?: BigIntFilter | bigint | number + } + + export type AOrderByWithRelationInput = { + id?: SortOrder + email?: SortOrder + name?: SortOrder + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + } + + export type AWhereUniqueInput = { + id?: string + email?: string + } + + export type AOrderByWithAggregationInput = { + id?: SortOrder + email?: SortOrder + name?: SortOrder + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + _count?: ACountOrderByAggregateInput + _avg?: AAvgOrderByAggregateInput + _max?: AMaxOrderByAggregateInput + _min?: AMinOrderByAggregateInput + _sum?: ASumOrderByAggregateInput + } + + export type AScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + email?: StringWithAggregatesFilter | string + name?: StringNullableWithAggregatesFilter | string | null + int?: IntWithAggregatesFilter | number + sInt?: IntWithAggregatesFilter | number + bInt?: BigIntWithAggregatesFilter | bigint | number + } + + export type BWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + float?: FloatFilter | number + dFloat?: FloatFilter | number + decFloat?: DecimalFilter | Decimal | number | string + numFloat?: DecimalFilter | Decimal | number | string + } + + export type BOrderByWithRelationInput = { + id?: SortOrder + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + } + + export type BWhereUniqueInput = { + id?: string + } + + export type BOrderByWithAggregationInput = { + id?: SortOrder + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + _count?: BCountOrderByAggregateInput + _avg?: BAvgOrderByAggregateInput + _max?: BMaxOrderByAggregateInput + _min?: BMinOrderByAggregateInput + _sum?: BSumOrderByAggregateInput + } + + export type BScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + float?: FloatWithAggregatesFilter | number + dFloat?: FloatWithAggregatesFilter | number + decFloat?: DecimalWithAggregatesFilter | Decimal | number | string + numFloat?: DecimalWithAggregatesFilter | Decimal | number | string + } + + export type CWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + char?: StringFilter | string + vChar?: StringFilter | string + text?: StringFilter | string + bit?: StringFilter | string + vBit?: StringFilter | string + uuid?: StringFilter | string + } + + export type COrderByWithRelationInput = { + id?: SortOrder + char?: SortOrder + vChar?: SortOrder + text?: SortOrder + bit?: SortOrder + vBit?: SortOrder + uuid?: SortOrder + } + + export type CWhereUniqueInput = { + id?: string + } + + export type COrderByWithAggregationInput = { + id?: SortOrder + char?: SortOrder + vChar?: SortOrder + text?: SortOrder + bit?: SortOrder + vBit?: SortOrder + uuid?: SortOrder + _count?: CCountOrderByAggregateInput + _max?: CMaxOrderByAggregateInput + _min?: CMinOrderByAggregateInput + } + + export type CScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + char?: StringWithAggregatesFilter | string + vChar?: StringWithAggregatesFilter | string + text?: StringWithAggregatesFilter | string + bit?: StringWithAggregatesFilter | string + vBit?: StringWithAggregatesFilter | string + uuid?: StringWithAggregatesFilter | string + } + + export type DWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + bool?: BoolFilter | boolean + byteA?: BytesFilter | Buffer + xml?: StringFilter | string + json?: JsonFilter + jsonb?: JsonFilter + } + + export type DOrderByWithRelationInput = { + id?: SortOrder + bool?: SortOrder + byteA?: SortOrder + xml?: SortOrder + json?: SortOrder + jsonb?: SortOrder + } + + export type DWhereUniqueInput = { + id?: string + } + + export type DOrderByWithAggregationInput = { + id?: SortOrder + bool?: SortOrder + byteA?: SortOrder + xml?: SortOrder + json?: SortOrder + jsonb?: SortOrder + _count?: DCountOrderByAggregateInput + _max?: DMaxOrderByAggregateInput + _min?: DMinOrderByAggregateInput + } + + export type DScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + bool?: BoolWithAggregatesFilter | boolean + byteA?: BytesWithAggregatesFilter | Buffer + xml?: StringWithAggregatesFilter | string + json?: JsonWithAggregatesFilter + jsonb?: JsonWithAggregatesFilter + } + + export type EWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + date?: DateTimeFilter | Date | string + time?: DateTimeFilter | Date | string + ts?: DateTimeFilter | Date | string + } + + export type EOrderByWithRelationInput = { + id?: SortOrder + date?: SortOrder + time?: SortOrder + ts?: SortOrder + } + + export type EWhereUniqueInput = { + id?: string + } + + export type EOrderByWithAggregationInput = { + id?: SortOrder + date?: SortOrder + time?: SortOrder + ts?: SortOrder + _count?: ECountOrderByAggregateInput + _max?: EMaxOrderByAggregateInput + _min?: EMinOrderByAggregateInput + } + + export type EScalarWhereWithAggregatesInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringWithAggregatesFilter | string + date?: DateTimeWithAggregatesFilter | Date | string + time?: DateTimeWithAggregatesFilter | Date | string + ts?: DateTimeWithAggregatesFilter | Date | string + } + + export type PostCreateInput = { + id?: string + createdAt?: Date | string + title: string + content?: string | null + published?: boolean + author: UserCreateNestedOneWithoutPostsInput + } + + export type PostUncheckedCreateInput = { + id?: string + createdAt?: Date | string + title: string + content?: string | null + published?: boolean + authorId: number + } + + export type PostUpdateInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + author?: UserUpdateOneRequiredWithoutPostsInput + } + + export type PostUncheckedUpdateInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + authorId?: IntFieldUpdateOperationsInput | number + } + + export type PostCreateManyInput = { + id?: string + createdAt?: Date | string + title: string + content?: string | null + published?: boolean + authorId: number + } + + export type PostUpdateManyMutationInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + } + + export type PostUncheckedUpdateManyInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + authorId?: IntFieldUpdateOperationsInput | number + } + + export type UserCreateInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + posts?: PostCreateNestedManyWithoutAuthorInput + embedHolder: EmbedHolderCreateNestedOneWithoutUserInput + } + + export type UserUncheckedCreateInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + posts?: PostUncheckedCreateNestedManyWithoutAuthorInput + embedHolderId: string + } + + export type UserUpdateInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + posts?: PostUpdateManyWithoutAuthorInput + embedHolder?: EmbedHolderUpdateOneRequiredWithoutUserInput + } + + export type UserUncheckedUpdateInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + posts?: PostUncheckedUpdateManyWithoutAuthorInput + embedHolderId?: StringFieldUpdateOperationsInput | string + } + + export type UserCreateManyInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + embedHolderId: string + } + + export type UserUpdateManyMutationInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type UserUncheckedUpdateManyInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + embedHolderId?: StringFieldUpdateOperationsInput | string + } + + export type EmbedHolderCreateInput = { + embedList?: XOR> + requiredEmbed: XOR + optionalEmbed?: XOR | null + id?: string + time?: Date | string + text: string + boolean: boolean + User?: UserCreateNestedManyWithoutEmbedHolderInput + } + + export type EmbedHolderUncheckedCreateInput = { + embedList?: XOR> + requiredEmbed: XOR + optionalEmbed?: XOR | null + id?: string + time?: Date | string + text: string + boolean: boolean + User?: UserUncheckedCreateNestedManyWithoutEmbedHolderInput + } + + export type EmbedHolderUpdateInput = { + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + time?: DateTimeFieldUpdateOperationsInput | Date | string + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + User?: UserUpdateManyWithoutEmbedHolderInput + } + + export type EmbedHolderUncheckedUpdateInput = { + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + time?: DateTimeFieldUpdateOperationsInput | Date | string + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + User?: UserUncheckedUpdateManyWithoutEmbedHolderInput + } + + export type EmbedHolderCreateManyInput = { + embedList?: XOR> + requiredEmbed: XOR + optionalEmbed?: XOR | null + id?: string + time?: Date | string + text: string + boolean: boolean + } + + export type EmbedHolderUpdateManyMutationInput = { + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + time?: DateTimeFieldUpdateOperationsInput | Date | string + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + } + + export type EmbedHolderUncheckedUpdateManyInput = { + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + time?: DateTimeFieldUpdateOperationsInput | Date | string + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + } + + export type MCreateInput = { + id?: string + n_ids?: MCreaten_idsInput | Enumerable + n?: NCreateNestedManyWithoutMInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type MUncheckedCreateInput = { + id?: string + n_ids?: MCreaten_idsInput | Enumerable + n?: NUncheckedCreateNestedManyWithoutMInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type MUpdateInput = { + n_ids?: MUpdaten_idsInput | Enumerable + n?: NUpdateManyWithoutMInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type MUncheckedUpdateInput = { + n_ids?: MUpdaten_idsInput | Enumerable + n?: NUncheckedUpdateManyWithoutMInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type MCreateManyInput = { + id?: string + n_ids?: MCreaten_idsInput | Enumerable + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type MUpdateManyMutationInput = { + n_ids?: MUpdaten_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type MUncheckedUpdateManyInput = { + n_ids?: MUpdaten_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NCreateInput = { + id?: string + m_ids?: NCreatem_idsInput | Enumerable + m?: MCreateNestedManyWithoutNInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type NUncheckedCreateInput = { + id?: string + m_ids?: NCreatem_idsInput | Enumerable + m?: MUncheckedCreateNestedManyWithoutNInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type NUpdateInput = { + m_ids?: NUpdatem_idsInput | Enumerable + m?: MUpdateManyWithoutNInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NUncheckedUpdateInput = { + m_ids?: NUpdatem_idsInput | Enumerable + m?: MUncheckedUpdateManyWithoutNInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NCreateManyInput = { + id?: string + m_ids?: NCreatem_idsInput | Enumerable + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type NUpdateManyMutationInput = { + m_ids?: NUpdatem_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NUncheckedUpdateManyInput = { + m_ids?: NUpdatem_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OneOptionalCreateInput = { + id?: string + many?: ManyRequiredCreateNestedManyWithoutOneInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OneOptionalUncheckedCreateInput = { + id?: string + many?: ManyRequiredUncheckedCreateNestedManyWithoutOneInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OneOptionalUpdateInput = { + many?: ManyRequiredUpdateManyWithoutOneInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OneOptionalUncheckedUpdateInput = { + many?: ManyRequiredUncheckedUpdateManyWithoutOneInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OneOptionalCreateManyInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OneOptionalUpdateManyMutationInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OneOptionalUncheckedUpdateManyInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredCreateInput = { + id?: string + one?: OneOptionalCreateNestedOneWithoutManyInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type ManyRequiredUncheckedCreateInput = { + id?: string + oneOptionalId?: number | null + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type ManyRequiredUpdateInput = { + one?: OneOptionalUpdateOneWithoutManyInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredUncheckedUpdateInput = { + oneOptionalId?: NullableIntFieldUpdateOperationsInput | number | null + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredCreateManyInput = { + id?: string + oneOptionalId?: number | null + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type ManyRequiredUpdateManyMutationInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredUncheckedUpdateManyInput = { + oneOptionalId?: NullableIntFieldUpdateOperationsInput | number | null + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide1CreateInput = { + id?: string + opti?: OptionalSide2CreateNestedOneWithoutOptiInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide1UncheckedCreateInput = { + id?: string + optionalSide2Id?: number | null + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide1UpdateInput = { + opti?: OptionalSide2UpdateOneWithoutOptiInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide1UncheckedUpdateInput = { + optionalSide2Id?: NullableIntFieldUpdateOperationsInput | number | null + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide1CreateManyInput = { + id?: string + optionalSide2Id?: number | null + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide1UpdateManyMutationInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide1UncheckedUpdateManyInput = { + optionalSide2Id?: NullableIntFieldUpdateOperationsInput | number | null + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide2CreateInput = { + id?: string + opti?: OptionalSide1CreateNestedOneWithoutOptiInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide2UncheckedCreateInput = { + id?: string + opti?: OptionalSide1UncheckedCreateNestedOneWithoutOptiInput + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide2UpdateInput = { + opti?: OptionalSide1UpdateOneWithoutOptiInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide2UncheckedUpdateInput = { + opti?: OptionalSide1UncheckedUpdateOneWithoutOptiInput + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide2CreateManyInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide2UpdateManyMutationInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide2UncheckedUpdateManyInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ACreateInput = { + id?: string + email: string + name?: string | null + int: number + sInt: number + bInt: bigint | number + } + + export type AUncheckedCreateInput = { + id?: string + email: string + name?: string | null + int: number + sInt: number + bInt: bigint | number + } + + export type AUpdateInput = { + email?: StringFieldUpdateOperationsInput | string + name?: NullableStringFieldUpdateOperationsInput | string | null + int?: IntFieldUpdateOperationsInput | number + sInt?: IntFieldUpdateOperationsInput | number + bInt?: BigIntFieldUpdateOperationsInput | bigint | number + } + + export type AUncheckedUpdateInput = { + email?: StringFieldUpdateOperationsInput | string + name?: NullableStringFieldUpdateOperationsInput | string | null + int?: IntFieldUpdateOperationsInput | number + sInt?: IntFieldUpdateOperationsInput | number + bInt?: BigIntFieldUpdateOperationsInput | bigint | number + } + + export type ACreateManyInput = { + id?: string + email: string + name?: string | null + int: number + sInt: number + bInt: bigint | number + } + + export type AUpdateManyMutationInput = { + email?: StringFieldUpdateOperationsInput | string + name?: NullableStringFieldUpdateOperationsInput | string | null + int?: IntFieldUpdateOperationsInput | number + sInt?: IntFieldUpdateOperationsInput | number + bInt?: BigIntFieldUpdateOperationsInput | bigint | number + } + + export type AUncheckedUpdateManyInput = { + email?: StringFieldUpdateOperationsInput | string + name?: NullableStringFieldUpdateOperationsInput | string | null + int?: IntFieldUpdateOperationsInput | number + sInt?: IntFieldUpdateOperationsInput | number + bInt?: BigIntFieldUpdateOperationsInput | bigint | number + } + + export type BCreateInput = { + id?: string + float: number + dFloat: number + decFloat: Decimal | number | string + numFloat: Decimal | number | string + } + + export type BUncheckedCreateInput = { + id?: string + float: number + dFloat: number + decFloat: Decimal | number | string + numFloat: Decimal | number | string + } + + export type BUpdateInput = { + float?: FloatFieldUpdateOperationsInput | number + dFloat?: FloatFieldUpdateOperationsInput | number + decFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + numFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + } + + export type BUncheckedUpdateInput = { + float?: FloatFieldUpdateOperationsInput | number + dFloat?: FloatFieldUpdateOperationsInput | number + decFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + numFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + } + + export type BCreateManyInput = { + id?: string + float: number + dFloat: number + decFloat: Decimal | number | string + numFloat: Decimal | number | string + } + + export type BUpdateManyMutationInput = { + float?: FloatFieldUpdateOperationsInput | number + dFloat?: FloatFieldUpdateOperationsInput | number + decFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + numFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + } + + export type BUncheckedUpdateManyInput = { + float?: FloatFieldUpdateOperationsInput | number + dFloat?: FloatFieldUpdateOperationsInput | number + decFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + numFloat?: DecimalFieldUpdateOperationsInput | Decimal | number | string + } + + export type CCreateInput = { + id?: string + char: string + vChar: string + text: string + bit: string + vBit: string + uuid: string + } + + export type CUncheckedCreateInput = { + id?: string + char: string + vChar: string + text: string + bit: string + vBit: string + uuid: string + } + + export type CUpdateInput = { + char?: StringFieldUpdateOperationsInput | string + vChar?: StringFieldUpdateOperationsInput | string + text?: StringFieldUpdateOperationsInput | string + bit?: StringFieldUpdateOperationsInput | string + vBit?: StringFieldUpdateOperationsInput | string + uuid?: StringFieldUpdateOperationsInput | string + } + + export type CUncheckedUpdateInput = { + char?: StringFieldUpdateOperationsInput | string + vChar?: StringFieldUpdateOperationsInput | string + text?: StringFieldUpdateOperationsInput | string + bit?: StringFieldUpdateOperationsInput | string + vBit?: StringFieldUpdateOperationsInput | string + uuid?: StringFieldUpdateOperationsInput | string + } + + export type CCreateManyInput = { + id?: string + char: string + vChar: string + text: string + bit: string + vBit: string + uuid: string + } + + export type CUpdateManyMutationInput = { + char?: StringFieldUpdateOperationsInput | string + vChar?: StringFieldUpdateOperationsInput | string + text?: StringFieldUpdateOperationsInput | string + bit?: StringFieldUpdateOperationsInput | string + vBit?: StringFieldUpdateOperationsInput | string + uuid?: StringFieldUpdateOperationsInput | string + } + + export type CUncheckedUpdateManyInput = { + char?: StringFieldUpdateOperationsInput | string + vChar?: StringFieldUpdateOperationsInput | string + text?: StringFieldUpdateOperationsInput | string + bit?: StringFieldUpdateOperationsInput | string + vBit?: StringFieldUpdateOperationsInput | string + uuid?: StringFieldUpdateOperationsInput | string + } + + export type DCreateInput = { + id?: string + bool: boolean + byteA: Buffer + xml: string + json: InputJsonValue + jsonb: InputJsonValue + } + + export type DUncheckedCreateInput = { + id?: string + bool: boolean + byteA: Buffer + xml: string + json: InputJsonValue + jsonb: InputJsonValue + } + + export type DUpdateInput = { + bool?: BoolFieldUpdateOperationsInput | boolean + byteA?: BytesFieldUpdateOperationsInput | Buffer + xml?: StringFieldUpdateOperationsInput | string + json?: InputJsonValue | InputJsonValue + jsonb?: InputJsonValue | InputJsonValue + } + + export type DUncheckedUpdateInput = { + bool?: BoolFieldUpdateOperationsInput | boolean + byteA?: BytesFieldUpdateOperationsInput | Buffer + xml?: StringFieldUpdateOperationsInput | string + json?: InputJsonValue | InputJsonValue + jsonb?: InputJsonValue | InputJsonValue + } + + export type DCreateManyInput = { + id?: string + bool: boolean + byteA: Buffer + xml: string + json: InputJsonValue + jsonb: InputJsonValue + } + + export type DUpdateManyMutationInput = { + bool?: BoolFieldUpdateOperationsInput | boolean + byteA?: BytesFieldUpdateOperationsInput | Buffer + xml?: StringFieldUpdateOperationsInput | string + json?: InputJsonValue | InputJsonValue + jsonb?: InputJsonValue | InputJsonValue + } + + export type DUncheckedUpdateManyInput = { + bool?: BoolFieldUpdateOperationsInput | boolean + byteA?: BytesFieldUpdateOperationsInput | Buffer + xml?: StringFieldUpdateOperationsInput | string + json?: InputJsonValue | InputJsonValue + jsonb?: InputJsonValue | InputJsonValue + } + + export type ECreateInput = { + id?: string + date: Date | string + time: Date | string + ts: Date | string + } + + export type EUncheckedCreateInput = { + id?: string + date: Date | string + time: Date | string + ts: Date | string + } + + export type EUpdateInput = { + date?: DateTimeFieldUpdateOperationsInput | Date | string + time?: DateTimeFieldUpdateOperationsInput | Date | string + ts?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type EUncheckedUpdateInput = { + date?: DateTimeFieldUpdateOperationsInput | Date | string + time?: DateTimeFieldUpdateOperationsInput | Date | string + ts?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type ECreateManyInput = { + id?: string + date: Date | string + time: Date | string + ts: Date | string + } + + export type EUpdateManyMutationInput = { + date?: DateTimeFieldUpdateOperationsInput | Date | string + time?: DateTimeFieldUpdateOperationsInput | Date | string + ts?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type EUncheckedUpdateManyInput = { + date?: DateTimeFieldUpdateOperationsInput | Date | string + time?: DateTimeFieldUpdateOperationsInput | Date | string + ts?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type StringFilter = { + equals?: string + in?: Enumerable + notIn?: Enumerable + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + mode?: QueryMode + not?: NestedStringFilter | string + } + + export type DateTimeFilter = { + equals?: Date | string + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: Date | string + lte?: Date | string + gt?: Date | string + gte?: Date | string + not?: NestedDateTimeFilter | Date | string + } + + export type StringNullableFilter = { + equals?: string | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + mode?: QueryMode + not?: NestedStringNullableFilter | string | null + } + + export type BoolFilter = { + equals?: boolean + not?: NestedBoolFilter | boolean + } + + export type UserRelationFilter = { + is?: UserWhereInput + isNot?: UserWhereInput + } + + export type IntFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntFilter | number + } + + export type PostCountOrderByAggregateInput = { + id?: SortOrder + createdAt?: SortOrder + title?: SortOrder + content?: SortOrder + published?: SortOrder + authorId?: SortOrder + } + + export type PostAvgOrderByAggregateInput = { + authorId?: SortOrder + } + + export type PostMaxOrderByAggregateInput = { + id?: SortOrder + createdAt?: SortOrder + title?: SortOrder + content?: SortOrder + published?: SortOrder + authorId?: SortOrder + } + + export type PostMinOrderByAggregateInput = { + id?: SortOrder + createdAt?: SortOrder + title?: SortOrder + content?: SortOrder + published?: SortOrder + authorId?: SortOrder + } + + export type PostSumOrderByAggregateInput = { + authorId?: SortOrder + } + + export type StringWithAggregatesFilter = { + equals?: string + in?: Enumerable + notIn?: Enumerable + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + mode?: QueryMode + not?: NestedStringWithAggregatesFilter | string + _count?: NestedIntFilter + _min?: NestedStringFilter + _max?: NestedStringFilter + } + + export type DateTimeWithAggregatesFilter = { + equals?: Date | string + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: Date | string + lte?: Date | string + gt?: Date | string + gte?: Date | string + not?: NestedDateTimeWithAggregatesFilter | Date | string + _count?: NestedIntFilter + _min?: NestedDateTimeFilter + _max?: NestedDateTimeFilter + } + + export type StringNullableWithAggregatesFilter = { + equals?: string | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + mode?: QueryMode + not?: NestedStringNullableWithAggregatesFilter | string | null + _count?: NestedIntNullableFilter + _min?: NestedStringNullableFilter + _max?: NestedStringNullableFilter + } + + export type BoolWithAggregatesFilter = { + equals?: boolean + not?: NestedBoolWithAggregatesFilter | boolean + _count?: NestedIntFilter + _min?: NestedBoolFilter + _max?: NestedBoolFilter + } + + export type IntWithAggregatesFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntWithAggregatesFilter | number + _count?: NestedIntFilter + _avg?: NestedFloatFilter + _sum?: NestedIntFilter + _min?: NestedIntFilter + _max?: NestedIntFilter + } + + export type IntNullableFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntNullableFilter | number | null + } + + export type FloatFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatFilter | number + } + + export type FloatNullableFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatNullableFilter | number | null + } + export type JsonFilter = + | PatchUndefined< + Either, Exclude, 'path'>>, + Required + > + | OptionalFlat, 'path'>> + + export type JsonFilterBase = { + equals?: InputJsonValue + not?: InputJsonValue + } + export type JsonNullableFilter = + | PatchUndefined< + Either, Exclude, 'path'>>, + Required + > + | OptionalFlat, 'path'>> + + export type JsonNullableFilterBase = { + equals?: InputJsonValue | null + not?: InputJsonValue | null + } + + export type EnumABeautifulEnumFilter = { + equals?: ABeautifulEnum + in?: Enumerable + notIn?: Enumerable + not?: NestedEnumABeautifulEnumFilter | ABeautifulEnum + } + + export type EnumABeautifulEnumNullableFilter = { + equals?: ABeautifulEnum | null + in?: Enumerable | null + notIn?: Enumerable | null + not?: NestedEnumABeautifulEnumNullableFilter | ABeautifulEnum | null + } + + export type BoolNullableFilter = { + equals?: boolean | null + not?: NestedBoolNullableFilter | boolean | null + } + + export type PostListRelationFilter = { + every?: PostWhereInput + some?: PostWhereInput + none?: PostWhereInput + } + + export type EmbedHolderRelationFilter = { + is?: EmbedHolderWhereInput + isNot?: EmbedHolderWhereInput + } + + export type PostOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type UserCountOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + embedHolderId?: SortOrder + } + + export type UserAvgOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type UserMaxOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + embedHolderId?: SortOrder + } + + export type UserMinOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + embedHolderId?: SortOrder + } + + export type UserSumOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type IntNullableWithAggregatesFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntNullableWithAggregatesFilter | number | null + _count?: NestedIntNullableFilter + _avg?: NestedFloatNullableFilter + _sum?: NestedIntNullableFilter + _min?: NestedIntNullableFilter + _max?: NestedIntNullableFilter + } + + export type FloatWithAggregatesFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatWithAggregatesFilter | number + _count?: NestedIntFilter + _avg?: NestedFloatFilter + _sum?: NestedFloatFilter + _min?: NestedFloatFilter + _max?: NestedFloatFilter + } + + export type FloatNullableWithAggregatesFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatNullableWithAggregatesFilter | number | null + _count?: NestedIntNullableFilter + _avg?: NestedFloatNullableFilter + _sum?: NestedFloatNullableFilter + _min?: NestedFloatNullableFilter + _max?: NestedFloatNullableFilter + } + export type JsonWithAggregatesFilter = + | PatchUndefined< + Either, Exclude, 'path'>>, + Required + > + | OptionalFlat, 'path'>> + + export type JsonWithAggregatesFilterBase = { + equals?: InputJsonValue + not?: InputJsonValue + _count?: NestedIntFilter + _min?: NestedJsonFilter + _max?: NestedJsonFilter + } + export type JsonNullableWithAggregatesFilter = + | PatchUndefined< + Either, Exclude, 'path'>>, + Required + > + | OptionalFlat, 'path'>> + + export type JsonNullableWithAggregatesFilterBase = { + equals?: InputJsonValue | null + not?: InputJsonValue | null + _count?: NestedIntNullableFilter + _min?: NestedJsonNullableFilter + _max?: NestedJsonNullableFilter + } + + export type EnumABeautifulEnumWithAggregatesFilter = { + equals?: ABeautifulEnum + in?: Enumerable + notIn?: Enumerable + not?: NestedEnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + _count?: NestedIntFilter + _min?: NestedEnumABeautifulEnumFilter + _max?: NestedEnumABeautifulEnumFilter + } + + export type EnumABeautifulEnumNullableWithAggregatesFilter = { + equals?: ABeautifulEnum | null + in?: Enumerable | null + notIn?: Enumerable | null + not?: NestedEnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + _count?: NestedIntNullableFilter + _min?: NestedEnumABeautifulEnumNullableFilter + _max?: NestedEnumABeautifulEnumNullableFilter + } + + export type BoolNullableWithAggregatesFilter = { + equals?: boolean | null + not?: NestedBoolNullableWithAggregatesFilter | boolean | null + _count?: NestedIntNullableFilter + _min?: NestedBoolNullableFilter + _max?: NestedBoolNullableFilter + } + + export type EmbedCompositeListFilter = { + equals?: Enumerable + every?: EmbedWhereInput + some?: EmbedWhereInput + none?: EmbedWhereInput + isEmpty?: boolean + } + + export type EmbedObjectEqualityInput = { + text: string + boolean: boolean + embedEmbedList?: Enumerable + requiredEmbedEmbed: EmbedEmbedObjectEqualityInput + optionalEmbedEmbed?: EmbedEmbedObjectEqualityInput | null + } + + export type EmbedCompositeFilter = { + equals?: EmbedObjectEqualityInput + is?: EmbedWhereInput + isNot?: EmbedWhereInput + } + + export type UserListRelationFilter = { + every?: UserWhereInput + some?: UserWhereInput + none?: UserWhereInput + } + + export type EmbedOrderByCompositeAggregateInput = { + _count?: SortOrder + } + + export type EmbedOrderByInput = { + text?: SortOrder + boolean?: SortOrder + embedEmbedList?: EmbedEmbedOrderByCompositeAggregateInput + requiredEmbedEmbed?: EmbedEmbedOrderByInput + optionalEmbedEmbed?: EmbedEmbedOrderByInput + } + + export type UserOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type EmbedHolderCountOrderByAggregateInput = { + id?: SortOrder + time?: SortOrder + text?: SortOrder + boolean?: SortOrder + } + + export type EmbedHolderMaxOrderByAggregateInput = { + id?: SortOrder + time?: SortOrder + text?: SortOrder + boolean?: SortOrder + } + + export type EmbedHolderMinOrderByAggregateInput = { + id?: SortOrder + time?: SortOrder + text?: SortOrder + boolean?: SortOrder + } + + export type StringNullableListFilter = { + equals?: Enumerable | null + has?: string | null + hasEvery?: Enumerable + hasSome?: Enumerable + isEmpty?: boolean + } + + export type NListRelationFilter = { + every?: NWhereInput + some?: NWhereInput + none?: NWhereInput + } + + export type NOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type MCountOrderByAggregateInput = { + id?: SortOrder + n_ids?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type MAvgOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type MMaxOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type MMinOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type MSumOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type MListRelationFilter = { + every?: MWhereInput + some?: MWhereInput + none?: MWhereInput + } + + export type MOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type NCountOrderByAggregateInput = { + id?: SortOrder + m_ids?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type NAvgOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type NMaxOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type NMinOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type NSumOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type ManyRequiredListRelationFilter = { + every?: ManyRequiredWhereInput + some?: ManyRequiredWhereInput + none?: ManyRequiredWhereInput + } + + export type ManyRequiredOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type OneOptionalCountOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OneOptionalAvgOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type OneOptionalMaxOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OneOptionalMinOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OneOptionalSumOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type OneOptionalRelationFilter = { + is?: OneOptionalWhereInput | null + isNot?: OneOptionalWhereInput | null + } + + export type ManyRequiredCountOrderByAggregateInput = { + id?: SortOrder + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type ManyRequiredAvgOrderByAggregateInput = { + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type ManyRequiredMaxOrderByAggregateInput = { + id?: SortOrder + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type ManyRequiredMinOrderByAggregateInput = { + id?: SortOrder + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type ManyRequiredSumOrderByAggregateInput = { + oneOptionalId?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type OptionalSide2RelationFilter = { + is?: OptionalSide2WhereInput | null + isNot?: OptionalSide2WhereInput | null + } + + export type OptionalSide1CountOrderByAggregateInput = { + id?: SortOrder + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide1AvgOrderByAggregateInput = { + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type OptionalSide1MaxOrderByAggregateInput = { + id?: SortOrder + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide1MinOrderByAggregateInput = { + id?: SortOrder + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide1SumOrderByAggregateInput = { + optionalSide2Id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type OptionalSide1RelationFilter = { + is?: OptionalSide1WhereInput | null + isNot?: OptionalSide1WhereInput | null + } + + export type OptionalSide2CountOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + json?: SortOrder + optionalJson?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide2AvgOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type OptionalSide2MaxOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide2MinOrderByAggregateInput = { + id?: SortOrder + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + string?: SortOrder + optionalString?: SortOrder + enum?: SortOrder + optionalEnum?: SortOrder + boolean?: SortOrder + optionalBoolean?: SortOrder + } + + export type OptionalSide2SumOrderByAggregateInput = { + int?: SortOrder + optionalInt?: SortOrder + float?: SortOrder + optionalFloat?: SortOrder + } + + export type BigIntFilter = { + equals?: bigint | number + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: bigint | number + lte?: bigint | number + gt?: bigint | number + gte?: bigint | number + not?: NestedBigIntFilter | bigint | number + } + + export type ACountOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + name?: SortOrder + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + } + + export type AAvgOrderByAggregateInput = { + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + } + + export type AMaxOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + name?: SortOrder + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + } + + export type AMinOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + name?: SortOrder + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + } + + export type ASumOrderByAggregateInput = { + int?: SortOrder + sInt?: SortOrder + bInt?: SortOrder + } + + export type BigIntWithAggregatesFilter = { + equals?: bigint | number + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: bigint | number + lte?: bigint | number + gt?: bigint | number + gte?: bigint | number + not?: NestedBigIntWithAggregatesFilter | bigint | number + _count?: NestedIntFilter + _avg?: NestedFloatFilter + _sum?: NestedBigIntFilter + _min?: NestedBigIntFilter + _max?: NestedBigIntFilter + } + + export type DecimalFilter = { + equals?: Decimal | number | string + in?: Enumerable | Enumerable | Enumerable + notIn?: Enumerable | Enumerable | Enumerable + lt?: Decimal | number | string + lte?: Decimal | number | string + gt?: Decimal | number | string + gte?: Decimal | number | string + not?: NestedDecimalFilter | Decimal | number | string + } + + export type BCountOrderByAggregateInput = { + id?: SortOrder + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + } + + export type BAvgOrderByAggregateInput = { + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + } + + export type BMaxOrderByAggregateInput = { + id?: SortOrder + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + } + + export type BMinOrderByAggregateInput = { + id?: SortOrder + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + } + + export type BSumOrderByAggregateInput = { + float?: SortOrder + dFloat?: SortOrder + decFloat?: SortOrder + numFloat?: SortOrder + } + + export type DecimalWithAggregatesFilter = { + equals?: Decimal | number | string + in?: Enumerable | Enumerable | Enumerable + notIn?: Enumerable | Enumerable | Enumerable + lt?: Decimal | number | string + lte?: Decimal | number | string + gt?: Decimal | number | string + gte?: Decimal | number | string + not?: NestedDecimalWithAggregatesFilter | Decimal | number | string + _count?: NestedIntFilter + _avg?: NestedDecimalFilter + _sum?: NestedDecimalFilter + _min?: NestedDecimalFilter + _max?: NestedDecimalFilter + } + + export type CCountOrderByAggregateInput = { + id?: SortOrder + char?: SortOrder + vChar?: SortOrder + text?: SortOrder + bit?: SortOrder + vBit?: SortOrder + uuid?: SortOrder + } + + export type CMaxOrderByAggregateInput = { + id?: SortOrder + char?: SortOrder + vChar?: SortOrder + text?: SortOrder + bit?: SortOrder + vBit?: SortOrder + uuid?: SortOrder + } + + export type CMinOrderByAggregateInput = { + id?: SortOrder + char?: SortOrder + vChar?: SortOrder + text?: SortOrder + bit?: SortOrder + vBit?: SortOrder + uuid?: SortOrder + } + + export type BytesFilter = { + equals?: Buffer + in?: Enumerable + notIn?: Enumerable + not?: NestedBytesFilter | Buffer + } + + export type DCountOrderByAggregateInput = { + id?: SortOrder + bool?: SortOrder + byteA?: SortOrder + xml?: SortOrder + json?: SortOrder + jsonb?: SortOrder + } + + export type DMaxOrderByAggregateInput = { + id?: SortOrder + bool?: SortOrder + byteA?: SortOrder + xml?: SortOrder + } + + export type DMinOrderByAggregateInput = { + id?: SortOrder + bool?: SortOrder + byteA?: SortOrder + xml?: SortOrder + } + + export type BytesWithAggregatesFilter = { + equals?: Buffer + in?: Enumerable + notIn?: Enumerable + not?: NestedBytesWithAggregatesFilter | Buffer + _count?: NestedIntFilter + _min?: NestedBytesFilter + _max?: NestedBytesFilter + } + + export type ECountOrderByAggregateInput = { + id?: SortOrder + date?: SortOrder + time?: SortOrder + ts?: SortOrder + } + + export type EMaxOrderByAggregateInput = { + id?: SortOrder + date?: SortOrder + time?: SortOrder + ts?: SortOrder + } + + export type EMinOrderByAggregateInput = { + id?: SortOrder + date?: SortOrder + time?: SortOrder + ts?: SortOrder + } + + export type UserCreateNestedOneWithoutPostsInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutPostsInput + connect?: UserWhereUniqueInput + } + + export type DateTimeFieldUpdateOperationsInput = { + set?: Date | string + } + + export type StringFieldUpdateOperationsInput = { + set?: string + } + + export type NullableStringFieldUpdateOperationsInput = { + set?: string | null + } + + export type BoolFieldUpdateOperationsInput = { + set?: boolean + } + + export type UserUpdateOneRequiredWithoutPostsInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutPostsInput + upsert?: UserUpsertWithoutPostsInput + connect?: UserWhereUniqueInput + update?: XOR + } + + export type IntFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type PostCreateNestedManyWithoutAuthorInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + createMany?: PostCreateManyAuthorInputEnvelope + connect?: Enumerable + } + + export type EmbedHolderCreateNestedOneWithoutUserInput = { + create?: XOR + connectOrCreate?: EmbedHolderCreateOrConnectWithoutUserInput + connect?: EmbedHolderWhereUniqueInput + } + + export type PostUncheckedCreateNestedManyWithoutAuthorInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + createMany?: PostCreateManyAuthorInputEnvelope + connect?: Enumerable + } + + export type NullableIntFieldUpdateOperationsInput = { + set?: number | null + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type FloatFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type NullableFloatFieldUpdateOperationsInput = { + set?: number | null + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type EnumABeautifulEnumFieldUpdateOperationsInput = { + set?: ABeautifulEnum + } + + export type NullableEnumABeautifulEnumFieldUpdateOperationsInput = { + set?: ABeautifulEnum | null + } + + export type NullableBoolFieldUpdateOperationsInput = { + set?: boolean | null + } + + export type PostUpdateManyWithoutAuthorInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + createMany?: PostCreateManyAuthorInputEnvelope + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type EmbedHolderUpdateOneRequiredWithoutUserInput = { + create?: XOR + connectOrCreate?: EmbedHolderCreateOrConnectWithoutUserInput + upsert?: EmbedHolderUpsertWithoutUserInput + connect?: EmbedHolderWhereUniqueInput + update?: XOR + } + + export type PostUncheckedUpdateManyWithoutAuthorInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + createMany?: PostCreateManyAuthorInputEnvelope + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type EmbedListCreateEnvelopeInput = { + set?: Enumerable + } + + export type EmbedCreateInput = { + text: string + boolean: boolean + embedEmbedList?: Enumerable + requiredEmbedEmbed: EmbedEmbedCreateInput + optionalEmbedEmbed?: EmbedEmbedCreateInput | null + } + + export type EmbedCreateEnvelopeInput = { + set?: EmbedCreateInput + } + + export type EmbedNullableCreateEnvelopeInput = { + set?: EmbedCreateInput | null + } + + export type UserCreateNestedManyWithoutEmbedHolderInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + createMany?: UserCreateManyEmbedHolderInputEnvelope + connect?: Enumerable + } + + export type UserUncheckedCreateNestedManyWithoutEmbedHolderInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + createMany?: UserCreateManyEmbedHolderInputEnvelope + connect?: Enumerable + } + + export type EmbedListUpdateEnvelopeInput = { + set?: Enumerable + push?: Enumerable + } + + export type EmbedUpdateEnvelopeInput = { + set?: EmbedCreateInput + update?: EmbedUpdateInput + } + + export type EmbedNullableUpdateEnvelopeInput = { + set?: EmbedCreateInput | null + unset?: boolean + upsert?: EmbedUpsertInput + } + + export type UserUpdateManyWithoutEmbedHolderInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + createMany?: UserCreateManyEmbedHolderInputEnvelope + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type UserUncheckedUpdateManyWithoutEmbedHolderInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + createMany?: UserCreateManyEmbedHolderInputEnvelope + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type MCreaten_idsInput = { + set: Enumerable + } + + export type NCreateNestedManyWithoutMInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + connect?: Enumerable + } + + export type NUncheckedCreateNestedManyWithoutMInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + connect?: Enumerable + } + + export type MUpdaten_idsInput = { + set?: Enumerable + push?: string | Enumerable + } + + export type NUpdateManyWithoutMInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type NUncheckedUpdateManyWithoutMInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type NCreatem_idsInput = { + set: Enumerable + } + + export type MCreateNestedManyWithoutNInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + connect?: Enumerable + } + + export type MUncheckedCreateNestedManyWithoutNInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + connect?: Enumerable + } + + export type NUpdatem_idsInput = { + set?: Enumerable + push?: string | Enumerable + } + + export type MUpdateManyWithoutNInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type MUncheckedUpdateManyWithoutNInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type ManyRequiredCreateNestedManyWithoutOneInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + createMany?: ManyRequiredCreateManyOneInputEnvelope + connect?: Enumerable + } + + export type ManyRequiredUncheckedCreateNestedManyWithoutOneInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + createMany?: ManyRequiredCreateManyOneInputEnvelope + connect?: Enumerable + } + + export type ManyRequiredUpdateManyWithoutOneInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + createMany?: ManyRequiredCreateManyOneInputEnvelope + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type ManyRequiredUncheckedUpdateManyWithoutOneInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + createMany?: ManyRequiredCreateManyOneInputEnvelope + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + + export type OneOptionalCreateNestedOneWithoutManyInput = { + create?: XOR + connectOrCreate?: OneOptionalCreateOrConnectWithoutManyInput + connect?: OneOptionalWhereUniqueInput + } + + export type OneOptionalUpdateOneWithoutManyInput = { + create?: XOR + connectOrCreate?: OneOptionalCreateOrConnectWithoutManyInput + upsert?: OneOptionalUpsertWithoutManyInput + disconnect?: boolean + delete?: boolean + connect?: OneOptionalWhereUniqueInput + update?: XOR + } + + export type OptionalSide2CreateNestedOneWithoutOptiInput = { + create?: XOR + connectOrCreate?: OptionalSide2CreateOrConnectWithoutOptiInput + connect?: OptionalSide2WhereUniqueInput + } + + export type OptionalSide2UpdateOneWithoutOptiInput = { + create?: XOR + connectOrCreate?: OptionalSide2CreateOrConnectWithoutOptiInput + upsert?: OptionalSide2UpsertWithoutOptiInput + disconnect?: boolean + delete?: boolean + connect?: OptionalSide2WhereUniqueInput + update?: XOR + } + + export type OptionalSide1CreateNestedOneWithoutOptiInput = { + create?: XOR + connectOrCreate?: OptionalSide1CreateOrConnectWithoutOptiInput + connect?: OptionalSide1WhereUniqueInput + } + + export type OptionalSide1UncheckedCreateNestedOneWithoutOptiInput = { + create?: XOR + connectOrCreate?: OptionalSide1CreateOrConnectWithoutOptiInput + connect?: OptionalSide1WhereUniqueInput + } + + export type OptionalSide1UpdateOneWithoutOptiInput = { + create?: XOR + connectOrCreate?: OptionalSide1CreateOrConnectWithoutOptiInput + upsert?: OptionalSide1UpsertWithoutOptiInput + disconnect?: boolean + delete?: boolean + connect?: OptionalSide1WhereUniqueInput + update?: XOR + } + + export type OptionalSide1UncheckedUpdateOneWithoutOptiInput = { + create?: XOR + connectOrCreate?: OptionalSide1CreateOrConnectWithoutOptiInput + upsert?: OptionalSide1UpsertWithoutOptiInput + disconnect?: boolean + delete?: boolean + connect?: OptionalSide1WhereUniqueInput + update?: XOR + } + + export type BigIntFieldUpdateOperationsInput = { + set?: bigint | number + increment?: bigint | number + decrement?: bigint | number + multiply?: bigint | number + divide?: bigint | number + } + + export type DecimalFieldUpdateOperationsInput = { + set?: Decimal | number | string + increment?: Decimal | number | string + decrement?: Decimal | number | string + multiply?: Decimal | number | string + divide?: Decimal | number | string + } + + export type BytesFieldUpdateOperationsInput = { + set?: Buffer + } + + export type NestedStringFilter = { + equals?: string + in?: Enumerable + notIn?: Enumerable + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + not?: NestedStringFilter | string + } + + export type NestedDateTimeFilter = { + equals?: Date | string + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: Date | string + lte?: Date | string + gt?: Date | string + gte?: Date | string + not?: NestedDateTimeFilter | Date | string + } + + export type NestedStringNullableFilter = { + equals?: string | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + not?: NestedStringNullableFilter | string | null + } + + export type NestedBoolFilter = { + equals?: boolean + not?: NestedBoolFilter | boolean + } + + export type NestedIntFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntFilter | number + } + + export type NestedStringWithAggregatesFilter = { + equals?: string + in?: Enumerable + notIn?: Enumerable + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + not?: NestedStringWithAggregatesFilter | string + _count?: NestedIntFilter + _min?: NestedStringFilter + _max?: NestedStringFilter + } + + export type NestedDateTimeWithAggregatesFilter = { + equals?: Date | string + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: Date | string + lte?: Date | string + gt?: Date | string + gte?: Date | string + not?: NestedDateTimeWithAggregatesFilter | Date | string + _count?: NestedIntFilter + _min?: NestedDateTimeFilter + _max?: NestedDateTimeFilter + } + + export type NestedStringNullableWithAggregatesFilter = { + equals?: string | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: string + lte?: string + gt?: string + gte?: string + contains?: string + startsWith?: string + endsWith?: string + not?: NestedStringNullableWithAggregatesFilter | string | null + _count?: NestedIntNullableFilter + _min?: NestedStringNullableFilter + _max?: NestedStringNullableFilter + } + + export type NestedIntNullableFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntNullableFilter | number | null + } + + export type NestedBoolWithAggregatesFilter = { + equals?: boolean + not?: NestedBoolWithAggregatesFilter | boolean + _count?: NestedIntFilter + _min?: NestedBoolFilter + _max?: NestedBoolFilter + } + + export type NestedIntWithAggregatesFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntWithAggregatesFilter | number + _count?: NestedIntFilter + _avg?: NestedFloatFilter + _sum?: NestedIntFilter + _min?: NestedIntFilter + _max?: NestedIntFilter + } + + export type NestedFloatFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatFilter | number + } + + export type NestedFloatNullableFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatNullableFilter | number | null + } + + export type NestedEnumABeautifulEnumFilter = { + equals?: ABeautifulEnum + in?: Enumerable + notIn?: Enumerable + not?: NestedEnumABeautifulEnumFilter | ABeautifulEnum + } + + export type NestedEnumABeautifulEnumNullableFilter = { + equals?: ABeautifulEnum | null + in?: Enumerable | null + notIn?: Enumerable | null + not?: NestedEnumABeautifulEnumNullableFilter | ABeautifulEnum | null + } + + export type NestedBoolNullableFilter = { + equals?: boolean | null + not?: NestedBoolNullableFilter | boolean | null + } + + export type NestedIntNullableWithAggregatesFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedIntNullableWithAggregatesFilter | number | null + _count?: NestedIntNullableFilter + _avg?: NestedFloatNullableFilter + _sum?: NestedIntNullableFilter + _min?: NestedIntNullableFilter + _max?: NestedIntNullableFilter + } + + export type NestedFloatWithAggregatesFilter = { + equals?: number + in?: Enumerable + notIn?: Enumerable + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatWithAggregatesFilter | number + _count?: NestedIntFilter + _avg?: NestedFloatFilter + _sum?: NestedFloatFilter + _min?: NestedFloatFilter + _max?: NestedFloatFilter + } + + export type NestedFloatNullableWithAggregatesFilter = { + equals?: number | null + in?: Enumerable | null + notIn?: Enumerable | null + lt?: number + lte?: number + gt?: number + gte?: number + not?: NestedFloatNullableWithAggregatesFilter | number | null + _count?: NestedIntNullableFilter + _avg?: NestedFloatNullableFilter + _sum?: NestedFloatNullableFilter + _min?: NestedFloatNullableFilter + _max?: NestedFloatNullableFilter + } + export type NestedJsonFilter = + | PatchUndefined< + Either, Exclude, 'path'>>, + Required + > + | OptionalFlat, 'path'>> + + export type NestedJsonFilterBase = { + equals?: InputJsonValue + not?: InputJsonValue + } + export type NestedJsonNullableFilter = + | PatchUndefined< + Either, Exclude, 'path'>>, + Required + > + | OptionalFlat, 'path'>> + + export type NestedJsonNullableFilterBase = { + equals?: InputJsonValue | null + not?: InputJsonValue | null + } + + export type NestedEnumABeautifulEnumWithAggregatesFilter = { + equals?: ABeautifulEnum + in?: Enumerable + notIn?: Enumerable + not?: NestedEnumABeautifulEnumWithAggregatesFilter | ABeautifulEnum + _count?: NestedIntFilter + _min?: NestedEnumABeautifulEnumFilter + _max?: NestedEnumABeautifulEnumFilter + } + + export type NestedEnumABeautifulEnumNullableWithAggregatesFilter = { + equals?: ABeautifulEnum | null + in?: Enumerable | null + notIn?: Enumerable | null + not?: NestedEnumABeautifulEnumNullableWithAggregatesFilter | ABeautifulEnum | null + _count?: NestedIntNullableFilter + _min?: NestedEnumABeautifulEnumNullableFilter + _max?: NestedEnumABeautifulEnumNullableFilter + } + + export type NestedBoolNullableWithAggregatesFilter = { + equals?: boolean | null + not?: NestedBoolNullableWithAggregatesFilter | boolean | null + _count?: NestedIntNullableFilter + _min?: NestedBoolNullableFilter + _max?: NestedBoolNullableFilter + } + + export type EmbedWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + text?: StringFilter | string + boolean?: BoolFilter | boolean + embedEmbedList?: XOR> + requiredEmbedEmbed?: XOR + optionalEmbedEmbed?: XOR | null + } + + export type EmbedEmbedObjectEqualityInput = { + text: string + boolean: boolean + } + + export type EmbedEmbedOrderByCompositeAggregateInput = { + _count?: SortOrder + } + + export type EmbedEmbedOrderByInput = { + text?: SortOrder + boolean?: SortOrder + } + + export type NestedBigIntFilter = { + equals?: bigint | number + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: bigint | number + lte?: bigint | number + gt?: bigint | number + gte?: bigint | number + not?: NestedBigIntFilter | bigint | number + } + + export type NestedBigIntWithAggregatesFilter = { + equals?: bigint | number + in?: Enumerable | Enumerable + notIn?: Enumerable | Enumerable + lt?: bigint | number + lte?: bigint | number + gt?: bigint | number + gte?: bigint | number + not?: NestedBigIntWithAggregatesFilter | bigint | number + _count?: NestedIntFilter + _avg?: NestedFloatFilter + _sum?: NestedBigIntFilter + _min?: NestedBigIntFilter + _max?: NestedBigIntFilter + } + + export type NestedDecimalFilter = { + equals?: Decimal | number | string + in?: Enumerable | Enumerable | Enumerable + notIn?: Enumerable | Enumerable | Enumerable + lt?: Decimal | number | string + lte?: Decimal | number | string + gt?: Decimal | number | string + gte?: Decimal | number | string + not?: NestedDecimalFilter | Decimal | number | string + } + + export type NestedDecimalWithAggregatesFilter = { + equals?: Decimal | number | string + in?: Enumerable | Enumerable | Enumerable + notIn?: Enumerable | Enumerable | Enumerable + lt?: Decimal | number | string + lte?: Decimal | number | string + gt?: Decimal | number | string + gte?: Decimal | number | string + not?: NestedDecimalWithAggregatesFilter | Decimal | number | string + _count?: NestedIntFilter + _avg?: NestedDecimalFilter + _sum?: NestedDecimalFilter + _min?: NestedDecimalFilter + _max?: NestedDecimalFilter + } + + export type NestedBytesFilter = { + equals?: Buffer + in?: Enumerable + notIn?: Enumerable + not?: NestedBytesFilter | Buffer + } + + export type NestedBytesWithAggregatesFilter = { + equals?: Buffer + in?: Enumerable + notIn?: Enumerable + not?: NestedBytesWithAggregatesFilter | Buffer + _count?: NestedIntFilter + _min?: NestedBytesFilter + _max?: NestedBytesFilter + } + + export type UserCreateWithoutPostsInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + embedHolder: EmbedHolderCreateNestedOneWithoutUserInput + } + + export type UserUncheckedCreateWithoutPostsInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + embedHolderId: string + } + + export type UserCreateOrConnectWithoutPostsInput = { + where: UserWhereUniqueInput + create: XOR + } + + export type UserUpsertWithoutPostsInput = { + update: XOR + create: XOR + } + + export type UserUpdateWithoutPostsInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + embedHolder?: EmbedHolderUpdateOneRequiredWithoutUserInput + } + + export type UserUncheckedUpdateWithoutPostsInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + embedHolderId?: StringFieldUpdateOperationsInput | string + } + + export type PostCreateWithoutAuthorInput = { + id?: string + createdAt?: Date | string + title: string + content?: string | null + published?: boolean + } + + export type PostUncheckedCreateWithoutAuthorInput = { + id?: string + createdAt?: Date | string + title: string + content?: string | null + published?: boolean + } + + export type PostCreateOrConnectWithoutAuthorInput = { + where: PostWhereUniqueInput + create: XOR + } + + export type PostCreateManyAuthorInputEnvelope = { + data: Enumerable + } + + export type EmbedHolderCreateWithoutUserInput = { + embedList?: XOR> + requiredEmbed: XOR + optionalEmbed?: XOR | null + id?: string + time?: Date | string + text: string + boolean: boolean + } + + export type EmbedHolderUncheckedCreateWithoutUserInput = { + embedList?: XOR> + requiredEmbed: XOR + optionalEmbed?: XOR | null + id?: string + time?: Date | string + text: string + boolean: boolean + } + + export type EmbedHolderCreateOrConnectWithoutUserInput = { + where: EmbedHolderWhereUniqueInput + create: XOR + } + + export type PostUpsertWithWhereUniqueWithoutAuthorInput = { + where: PostWhereUniqueInput + update: XOR + create: XOR + } + + export type PostUpdateWithWhereUniqueWithoutAuthorInput = { + where: PostWhereUniqueInput + data: XOR + } + + export type PostUpdateManyWithWhereWithoutAuthorInput = { + where: PostScalarWhereInput + data: XOR + } + + export type PostScalarWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + createdAt?: DateTimeFilter | Date | string + title?: StringFilter | string + content?: StringNullableFilter | string | null + published?: BoolFilter | boolean + authorId?: IntFilter | number + } + + export type EmbedHolderUpsertWithoutUserInput = { + update: XOR + create: XOR + } + + export type EmbedHolderUpdateWithoutUserInput = { + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + time?: DateTimeFieldUpdateOperationsInput | Date | string + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + } + + export type EmbedHolderUncheckedUpdateWithoutUserInput = { + embedList?: XOR> + requiredEmbed?: XOR + optionalEmbed?: XOR | null + time?: DateTimeFieldUpdateOperationsInput | Date | string + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + } + + export type EmbedEmbedCreateInput = { + text: string + boolean: boolean + } + + export type UserCreateWithoutEmbedHolderInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + posts?: PostCreateNestedManyWithoutAuthorInput + } + + export type UserUncheckedCreateWithoutEmbedHolderInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + posts?: PostUncheckedCreateNestedManyWithoutAuthorInput + } + + export type UserCreateOrConnectWithoutEmbedHolderInput = { + where: UserWhereUniqueInput + create: XOR + } + + export type UserCreateManyEmbedHolderInputEnvelope = { + data: Enumerable + } + + export type EmbedUpdateInput = { + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + embedEmbedList?: XOR> + requiredEmbedEmbed?: XOR + optionalEmbedEmbed?: XOR | null + } + + export type EmbedUpsertInput = { + set: EmbedCreateInput | null + update: EmbedUpdateInput + } + + export type UserUpsertWithWhereUniqueWithoutEmbedHolderInput = { + where: UserWhereUniqueInput + update: XOR + create: XOR + } + + export type UserUpdateWithWhereUniqueWithoutEmbedHolderInput = { + where: UserWhereUniqueInput + data: XOR + } + + export type UserUpdateManyWithWhereWithoutEmbedHolderInput = { + where: UserScalarWhereInput + data: XOR + } + + export type UserScalarWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + email?: StringFilter | string + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + embedHolderId?: StringFilter | string + } + + export type NCreateWithoutMInput = { + id?: string + m_ids?: NCreatem_idsInput | Enumerable + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type NUncheckedCreateWithoutMInput = { + id?: string + m_ids?: NCreatem_idsInput | Enumerable + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type NCreateOrConnectWithoutMInput = { + where: NWhereUniqueInput + create: XOR + } + + export type NUpsertWithWhereUniqueWithoutMInput = { + where: NWhereUniqueInput + update: XOR + create: XOR + } + + export type NUpdateWithWhereUniqueWithoutMInput = { + where: NWhereUniqueInput + data: XOR + } + + export type NUpdateManyWithWhereWithoutMInput = { + where: NScalarWhereInput + data: XOR + } + + export type NScalarWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + m_ids?: StringNullableListFilter + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type MCreateWithoutNInput = { + id?: string + n_ids?: MCreaten_idsInput | Enumerable + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type MUncheckedCreateWithoutNInput = { + id?: string + n_ids?: MCreaten_idsInput | Enumerable + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type MCreateOrConnectWithoutNInput = { + where: MWhereUniqueInput + create: XOR + } + + export type MUpsertWithWhereUniqueWithoutNInput = { + where: MWhereUniqueInput + update: XOR + create: XOR + } + + export type MUpdateWithWhereUniqueWithoutNInput = { + where: MWhereUniqueInput + data: XOR + } + + export type MUpdateManyWithWhereWithoutNInput = { + where: MScalarWhereInput + data: XOR + } + + export type MScalarWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + n_ids?: StringNullableListFilter + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type ManyRequiredCreateWithoutOneInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type ManyRequiredUncheckedCreateWithoutOneInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type ManyRequiredCreateOrConnectWithoutOneInput = { + where: ManyRequiredWhereUniqueInput + create: XOR + } + + export type ManyRequiredCreateManyOneInputEnvelope = { + data: Enumerable + } + + export type ManyRequiredUpsertWithWhereUniqueWithoutOneInput = { + where: ManyRequiredWhereUniqueInput + update: XOR + create: XOR + } + + export type ManyRequiredUpdateWithWhereUniqueWithoutOneInput = { + where: ManyRequiredWhereUniqueInput + data: XOR + } + + export type ManyRequiredUpdateManyWithWhereWithoutOneInput = { + where: ManyRequiredScalarWhereInput + data: XOR + } + + export type ManyRequiredScalarWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + id?: StringFilter | string + oneOptionalId?: IntNullableFilter | number | null + int?: IntFilter | number + optionalInt?: IntNullableFilter | number | null + float?: FloatFilter | number + optionalFloat?: FloatNullableFilter | number | null + string?: StringFilter | string + optionalString?: StringNullableFilter | string | null + json?: JsonFilter + optionalJson?: JsonNullableFilter + enum?: EnumABeautifulEnumFilter | ABeautifulEnum + optionalEnum?: EnumABeautifulEnumNullableFilter | ABeautifulEnum | null + boolean?: BoolFilter | boolean + optionalBoolean?: BoolNullableFilter | boolean | null + } + + export type OneOptionalCreateWithoutManyInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OneOptionalUncheckedCreateWithoutManyInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OneOptionalCreateOrConnectWithoutManyInput = { + where: OneOptionalWhereUniqueInput + create: XOR + } + + export type OneOptionalUpsertWithoutManyInput = { + update: XOR + create: XOR + } + + export type OneOptionalUpdateWithoutManyInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OneOptionalUncheckedUpdateWithoutManyInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide2CreateWithoutOptiInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide2UncheckedCreateWithoutOptiInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide2CreateOrConnectWithoutOptiInput = { + where: OptionalSide2WhereUniqueInput + create: XOR + } + + export type OptionalSide2UpsertWithoutOptiInput = { + update: XOR + create: XOR + } + + export type OptionalSide2UpdateWithoutOptiInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide2UncheckedUpdateWithoutOptiInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide1CreateWithoutOptiInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide1UncheckedCreateWithoutOptiInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type OptionalSide1CreateOrConnectWithoutOptiInput = { + where: OptionalSide1WhereUniqueInput + create: XOR + } + + export type OptionalSide1UpsertWithoutOptiInput = { + update: XOR + create: XOR + } + + export type OptionalSide1UpdateWithoutOptiInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type OptionalSide1UncheckedUpdateWithoutOptiInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type EmbedEmbedCompositeListFilter = { + equals?: Enumerable + every?: EmbedEmbedWhereInput + some?: EmbedEmbedWhereInput + none?: EmbedEmbedWhereInput + isEmpty?: boolean + } + + export type EmbedEmbedCompositeFilter = { + equals?: EmbedEmbedObjectEqualityInput + is?: EmbedEmbedWhereInput + isNot?: EmbedEmbedWhereInput + } + + export type PostCreateManyAuthorInput = { + id?: string + createdAt?: Date | string + title: string + content?: string | null + published?: boolean + } + + export type PostUpdateWithoutAuthorInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + } + + export type PostUncheckedUpdateWithoutAuthorInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + } + + export type PostUncheckedUpdateManyWithoutPostsInput = { + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + title?: StringFieldUpdateOperationsInput | string + content?: NullableStringFieldUpdateOperationsInput | string | null + published?: BoolFieldUpdateOperationsInput | boolean + } + + export type UserCreateManyEmbedHolderInput = { + id?: string + email: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type EmbedEmbedListUpdateEnvelopeInput = { + set?: Enumerable + push?: Enumerable + } + + export type EmbedEmbedUpdateEnvelopeInput = { + set?: EmbedEmbedCreateInput + update?: EmbedEmbedUpdateInput + } + + export type EmbedEmbedNullableUpdateEnvelopeInput = { + set?: EmbedEmbedCreateInput | null + unset?: boolean + upsert?: EmbedEmbedUpsertInput + } + + export type UserUpdateWithoutEmbedHolderInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + posts?: PostUpdateManyWithoutAuthorInput + } + + export type UserUncheckedUpdateWithoutEmbedHolderInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + posts?: PostUncheckedUpdateManyWithoutAuthorInput + } + + export type UserUncheckedUpdateManyWithoutUserInput = { + email?: StringFieldUpdateOperationsInput | string + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NUpdateWithoutMInput = { + m_ids?: NUpdatem_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NUncheckedUpdateWithoutMInput = { + m_ids?: NUpdatem_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type NUncheckedUpdateManyWithoutNInput = { + m_ids?: NUpdatem_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type MUpdateWithoutNInput = { + n_ids?: MUpdaten_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type MUncheckedUpdateWithoutNInput = { + n_ids?: MUpdaten_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type MUncheckedUpdateManyWithoutMInput = { + n_ids?: MUpdaten_idsInput | Enumerable + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredCreateManyOneInput = { + id?: string + int: number + optionalInt?: number | null + float: number + optionalFloat?: number | null + string: string + optionalString?: string | null + json: InputJsonValue + optionalJson?: InputJsonValue | null + enum: ABeautifulEnum + optionalEnum?: ABeautifulEnum | null + boolean: boolean + optionalBoolean?: boolean | null + } + + export type ManyRequiredUpdateWithoutOneInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredUncheckedUpdateWithoutOneInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type ManyRequiredUncheckedUpdateManyWithoutManyInput = { + int?: IntFieldUpdateOperationsInput | number + optionalInt?: NullableIntFieldUpdateOperationsInput | number | null + float?: FloatFieldUpdateOperationsInput | number + optionalFloat?: NullableFloatFieldUpdateOperationsInput | number | null + string?: StringFieldUpdateOperationsInput | string + optionalString?: NullableStringFieldUpdateOperationsInput | string | null + json?: InputJsonValue | InputJsonValue + optionalJson?: InputJsonValue | InputJsonValue | null + enum?: EnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum + optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null + boolean?: BoolFieldUpdateOperationsInput | boolean + optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null + } + + export type EmbedEmbedWhereInput = { + AND?: Enumerable + OR?: Enumerable + NOT?: Enumerable + text?: StringFilter | string + boolean?: BoolFilter | boolean + } + + export type EmbedEmbedUpdateInput = { + text?: StringFieldUpdateOperationsInput | string + boolean?: BoolFieldUpdateOperationsInput | boolean + } + + export type EmbedEmbedUpsertInput = { + set: EmbedEmbedCreateInput | null + update: EmbedEmbedUpdateInput + } + + + + /** + * Batch Payload for updateMany & deleteMany & createMany + */ + + export type BatchPayload = { + count: number + } + + /** + * DMMF + */ + export const dmmf: runtime.DMMF.Document; +} +`; diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/dmmf-types.test.ts b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/dmmf-types.test.ts new file mode 100644 index 000000000000..73c6dc90d22a --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/dmmf-types.test.ts @@ -0,0 +1,25 @@ +import fs from 'fs' +import path from 'path' + +import { getDMMF } from '../../../../generation/getDMMF' +import { compileFile } from '../../../../utils/compileFile' + +/** + * Makes sure, that the actual dmmf value and types are in match + */ +test('dmmf-types', async () => { + const datamodel = fs.readFileSync(path.join(__dirname, 'schema.prisma'), 'utf-8') + const dmmf = await getDMMF({ + datamodel, + }) + const dmmfFile = path.join(__dirname, 'generated-dmmf.ts') + + fs.writeFileSync( + dmmfFile, + `import { DMMF } from '@prisma/generator-helper' + + const dmmf: DMMF.Document = ${JSON.stringify(dmmf, null, 2)}`, + ) + + await expect(compileFile(dmmfFile)).resolves.not.toThrow() +}) diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/schema.prisma b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/schema.prisma new file mode 100644 index 000000000000..198c7591bb77 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/schema.prisma @@ -0,0 +1,226 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["mongodb"] +} + +datasource db { + provider = "mongodb" + url = env("DATABASE_URL") +} + +model Post { + id String @id @default(auto()) @map("_id") @db.ObjectId + createdAt DateTime @default(now()) + title String + content String? + published Boolean @default(false) + author User @relation(fields: [authorId], references: [id]) + authorId Int +} + +model User { + id String @id @default(auto()) @map("_id") @db.ObjectId + email String @unique + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? + posts Post[] + + embedHolder EmbedHolder @relation(fields: [embedHolderId], references: [id]) + embedHolderId String +} + +model EmbedHolder { + id String @id @default(auto()) @map("_id") @db.ObjectId + time DateTime @default(now()) + text String + boolean Boolean + embedList Embed[] + requiredEmbed Embed + optionalEmbed Embed? + User User[] +} + +type Embed { + text String + boolean Boolean + embedEmbedList EmbedEmbed[] + requiredEmbedEmbed EmbedEmbed + optionalEmbedEmbed EmbedEmbed? +} + +type EmbedEmbed { + text String + boolean Boolean +} + +model M { + id String @id @default(auto()) @map("_id") @db.ObjectId + n_ids String[] @db.ObjectId + n N[] @relation(fields: [n_ids], references: [id]) + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? +} + +model N { + id String @id @default(auto()) @map("_id") @db.ObjectId + m_ids String[] @db.ObjectId + m M[] @relation(fields: [m_ids], references: [id]) + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? +} + +model OneOptional { + id String @id @default(auto()) @map("_id") @db.ObjectId + many ManyRequired[] + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? +} + +model ManyRequired { + id String @id @default(auto()) @map("_id") @db.ObjectId + one OneOptional? @relation(fields: [oneOptionalId], references: [id]) + + oneOptionalId Int? + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? +} + +model OptionalSide1 { + id String @id @default(auto()) @map("_id") @db.ObjectId + opti OptionalSide2? @relation(fields: [optionalSide2Id], references: [id]) + + optionalSide2Id Int? @unique + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? +} + +model OptionalSide2 { + id String @id @default(auto()) @map("_id") @db.ObjectId + opti OptionalSide1? + int Int + optionalInt Int? + float Float + optionalFloat Float? + string String + optionalString String? + json Json + optionalJson Json? + enum ABeautifulEnum + optionalEnum ABeautifulEnum? + boolean Boolean + optionalBoolean Boolean? + +} + +enum ABeautifulEnum { + A + B + C +} + +/// model comment +model A { + /// field comment 1 + id String @id @default(auto()) @map("_id") @db.ObjectId + email String @unique + name String? + + /// field comment 2 + int Int // @db.Integer + sInt Int // @db.SmallInt + bInt BigInt // @db.BigInt +} + +model B { + id String @id @default(auto()) @map("_id") @db.ObjectId + float Float // @db.Real + dFloat Float // @db.DoublePrecision + decFloat Decimal // @db.Decimal(2, 1) + numFloat Decimal // @db.Decimal(10, 6) +} + +model C { + id String @id @default(auto()) @map("_id") @db.ObjectId + char String // @db.Char(10) + vChar String // @db.VarChar(11) + text String // @db.Text + bit String // @db.Bit(4) + vBit String // @db.VarBit(5) + uuid String // @db.Uuid +} + +model D { + id String @id @default(auto()) @map("_id") @db.ObjectId + bool Boolean // @db.Boolean + byteA Bytes // @db.ByteA + xml String // @db.Xml + json Json // @db.Json + jsonb Json // @db.JsonB +} + +model E { + id String @id @default(auto()) @map("_id") @db.ObjectId + date DateTime @db.Date + time DateTime // @db.Time(3) + ts DateTime // @db.Timestamp(3) +} diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/test.ts b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/test.ts new file mode 100644 index 000000000000..e68e3d38723a --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema-mongo/test.ts @@ -0,0 +1,17 @@ +import fs from 'fs' +import path from 'path' + +import { generateTestClient } from '../../../../utils/getTestClient' + +test('exhaustive-schema', async () => { + await generateTestClient() + + const generatedTypeScript = fs.readFileSync(path.join(__dirname, './node_modules/.prisma/client/index.d.ts'), 'utf-8') + const generatedBrowserJS = fs.readFileSync( + path.join(__dirname, './node_modules/.prisma/client/index-browser.js'), + 'utf-8', + ) + + expect(generatedTypeScript).toMatchSnapshot('generatedTypeScript') + expect(generatedBrowserJS).toMatchSnapshot('generatedBrowserJS') +}) diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema/__snapshots__/test.ts.snap b/packages/client/src/__tests__/integration/happy/exhaustive-schema/__snapshots__/test.ts.snap index 145b4fe7d412..abfc2bc808f3 100644 --- a/packages/client/src/__tests__/integration/happy/exhaustive-schema/__snapshots__/test.ts.snap +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema/__snapshots__/test.ts.snap @@ -651,7 +651,7 @@ export class PrismaClient< */ $use(cb: Prisma.Middleware): void - /** +/** * Executes a prepared raw query and returns the number of affected rows. * @example * \`\`\` @@ -712,7 +712,6 @@ export class PrismaClient< */ $transaction

[]>(arg: [...P]): Promise>; - /** * \`prisma.post\`: Exposes CRUD operations for the **Post** model. * Example usage: @@ -1034,7 +1033,11 @@ export namespace Prisma { * XOR is needed to have a real mutually exclusive union type * https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types */ - type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; + type XOR = + T extends object ? + U extends object ? + (Without & U) | (Without & T) + : U : T /** @@ -1287,7 +1290,7 @@ export namespace Prisma { ? IsReject : GlobalRejectSettings extends RejectPerOperation ? Action extends keyof GlobalRejectSettings - ? GlobalRejectSettings[Action] extends boolean + ? GlobalRejectSettings[Action] extends RejectOnNotFound ? IsReject : GlobalRejectSettings[Action] extends RejectPerModel ? Model extends keyof GlobalRejectSettings[Action] @@ -1388,6 +1391,7 @@ export namespace Prisma { | 'queryRaw' | 'aggregate' | 'count' + | 'runCommandRaw' /** * These options are being passed in to the middleware as "params" @@ -1444,9 +1448,8 @@ export namespace Prisma { ? UserCountOutputType : 'select' extends U ? { - [P in TrueKeys]: P extends keyof UserCountOutputType ?UserCountOutputType [P] - : - never + [P in TrueKeys]: + P extends keyof UserCountOutputType ? UserCountOutputType[P] : never } : UserCountOutputType : UserCountOutputType @@ -1494,9 +1497,8 @@ export namespace Prisma { ? MCountOutputType : 'select' extends U ? { - [P in TrueKeys]: P extends keyof MCountOutputType ?MCountOutputType [P] - : - never + [P in TrueKeys]: + P extends keyof MCountOutputType ? MCountOutputType[P] : never } : MCountOutputType : MCountOutputType @@ -1544,9 +1546,8 @@ export namespace Prisma { ? NCountOutputType : 'select' extends U ? { - [P in TrueKeys]: P extends keyof NCountOutputType ?NCountOutputType [P] - : - never + [P in TrueKeys]: + P extends keyof NCountOutputType ? NCountOutputType[P] : never } : NCountOutputType : NCountOutputType @@ -1594,9 +1595,8 @@ export namespace Prisma { ? OneOptionalCountOutputType : 'select' extends U ? { - [P in TrueKeys]: P extends keyof OneOptionalCountOutputType ?OneOptionalCountOutputType [P] - : - never + [P in TrueKeys]: + P extends keyof OneOptionalCountOutputType ? OneOptionalCountOutputType[P] : never } : OneOptionalCountOutputType : OneOptionalCountOutputType @@ -1819,7 +1819,7 @@ export namespace Prisma { _max: PostMaxAggregateOutputType | null } - type GetPostGroupByPayload = Promise< + type GetPostGroupByPayload = PrismaPromise< Array< PickArray & { @@ -1857,16 +1857,13 @@ export namespace Prisma { : S extends PostArgs | PostFindManyArgs ?'include' extends U ? Post & { - [P in TrueKeys]: - P extends 'author' - ? UserGetPayload : never + [P in TrueKeys]: + P extends 'author' ? UserGetPayload : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof Post ?Post [P] - : - P extends 'author' - ? UserGetPayload : never + [P in TrueKeys]: + P extends 'author' ? UserGetPayload : P extends keyof Post ? Post[P] : never } : Post : Post @@ -2180,14 +2177,14 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetPostGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetPostGroupByPayload : PrismaPromise } /** * The delegate class that acts as a "Promise-like" for Post. * Why is this prefixed with \`Prisma__\`? * Because we want to prevent naming conflicts as mentioned in - * TEST_GITHUB_LINK + * https://github.com/prisma/prisma-client-js/issues/707 */ export class Prisma__PostClient implements PrismaPromise { [prisma]: true; @@ -2399,6 +2396,10 @@ export namespace Prisma { * Post createMany */ export type PostCreateManyArgs = { + /** + * The data used to create many Posts. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -2435,7 +2436,15 @@ export namespace Prisma { * Post updateMany */ export type PostUpdateManyArgs = { + /** + * The data used to update Posts. + * + **/ data: XOR + /** + * Filter which Posts to update + * + **/ where?: PostWhereInput } @@ -2498,6 +2507,10 @@ export namespace Prisma { * Post deleteMany */ export type PostDeleteManyArgs = { + /** + * Filter which Posts to delete + * + **/ where?: PostWhereInput } @@ -2776,7 +2789,7 @@ export namespace Prisma { _max: UserMaxAggregateOutputType | null } - type GetUserGroupByPayload = Promise< + type GetUserGroupByPayload = PrismaPromise< Array< PickArray & { @@ -2824,20 +2837,15 @@ export namespace Prisma { : S extends UserArgs | UserFindManyArgs ?'include' extends U ? User & { - [P in TrueKeys]: - P extends 'posts' - ? Array < PostGetPayload> : - P extends '_count' - ? UserCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'posts' ? Array < PostGetPayload> : + P extends '_count' ? UserCountOutputTypeGetPayload : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof User ?User [P] - : - P extends 'posts' - ? Array < PostGetPayload> : - P extends '_count' - ? UserCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'posts' ? Array < PostGetPayload> : + P extends '_count' ? UserCountOutputTypeGetPayload : P extends keyof User ? User[P] : never } : User : User @@ -3151,7 +3159,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserGroupByPayload : PrismaPromise } /** @@ -3370,6 +3378,10 @@ export namespace Prisma { * User createMany */ export type UserCreateManyArgs = { + /** + * The data used to create many Users. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -3406,7 +3418,15 @@ export namespace Prisma { * User updateMany */ export type UserUpdateManyArgs = { + /** + * The data used to update Users. + * + **/ data: XOR + /** + * Filter which Users to update + * + **/ where?: UserWhereInput } @@ -3469,6 +3489,10 @@ export namespace Prisma { * User deleteMany */ export type UserDeleteManyArgs = { + /** + * Filter which Users to delete + * + **/ where?: UserWhereInput } @@ -3740,7 +3764,7 @@ export namespace Prisma { _max: MMaxAggregateOutputType | null } - type GetMGroupByPayload = Promise< + type GetMGroupByPayload = PrismaPromise< Array< PickArray & { @@ -3787,20 +3811,15 @@ export namespace Prisma { : S extends MArgs | MFindManyArgs ?'include' extends U ? M & { - [P in TrueKeys]: - P extends 'n' - ? Array < NGetPayload> : - P extends '_count' - ? MCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'n' ? Array < NGetPayload> : + P extends '_count' ? MCountOutputTypeGetPayload : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof M ?M [P] - : - P extends 'n' - ? Array < NGetPayload> : - P extends '_count' - ? MCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'n' ? Array < NGetPayload> : + P extends '_count' ? MCountOutputTypeGetPayload : P extends keyof M ? M[P] : never } : M : M @@ -4114,7 +4133,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetMGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetMGroupByPayload : PrismaPromise } /** @@ -4333,6 +4352,10 @@ export namespace Prisma { * M createMany */ export type MCreateManyArgs = { + /** + * The data used to create many MS. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -4369,7 +4392,15 @@ export namespace Prisma { * M updateMany */ export type MUpdateManyArgs = { + /** + * The data used to update MS. + * + **/ data: XOR + /** + * Filter which MS to update + * + **/ where?: MWhereInput } @@ -4432,6 +4463,10 @@ export namespace Prisma { * M deleteMany */ export type MDeleteManyArgs = { + /** + * Filter which MS to delete + * + **/ where?: MWhereInput } @@ -4703,7 +4738,7 @@ export namespace Prisma { _max: NMaxAggregateOutputType | null } - type GetNGroupByPayload = Promise< + type GetNGroupByPayload = PrismaPromise< Array< PickArray & { @@ -4750,20 +4785,15 @@ export namespace Prisma { : S extends NArgs | NFindManyArgs ?'include' extends U ? N & { - [P in TrueKeys]: - P extends 'm' - ? Array < MGetPayload> : - P extends '_count' - ? NCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'm' ? Array < MGetPayload> : + P extends '_count' ? NCountOutputTypeGetPayload : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof N ?N [P] - : - P extends 'm' - ? Array < MGetPayload> : - P extends '_count' - ? NCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'm' ? Array < MGetPayload> : + P extends '_count' ? NCountOutputTypeGetPayload : P extends keyof N ? N[P] : never } : N : N @@ -5077,7 +5107,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetNGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetNGroupByPayload : PrismaPromise } /** @@ -5296,6 +5326,10 @@ export namespace Prisma { * N createMany */ export type NCreateManyArgs = { + /** + * The data used to create many NS. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -5332,7 +5366,15 @@ export namespace Prisma { * N updateMany */ export type NUpdateManyArgs = { + /** + * The data used to update NS. + * + **/ data: XOR + /** + * Filter which NS to update + * + **/ where?: NWhereInput } @@ -5395,6 +5437,10 @@ export namespace Prisma { * N deleteMany */ export type NDeleteManyArgs = { + /** + * Filter which NS to delete + * + **/ where?: NWhereInput } @@ -5666,7 +5712,7 @@ export namespace Prisma { _max: OneOptionalMaxAggregateOutputType | null } - type GetOneOptionalGroupByPayload = Promise< + type GetOneOptionalGroupByPayload = PrismaPromise< Array< PickArray & { @@ -5713,20 +5759,15 @@ export namespace Prisma { : S extends OneOptionalArgs | OneOptionalFindManyArgs ?'include' extends U ? OneOptional & { - [P in TrueKeys]: - P extends 'many' - ? Array < ManyRequiredGetPayload> : - P extends '_count' - ? OneOptionalCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'many' ? Array < ManyRequiredGetPayload> : + P extends '_count' ? OneOptionalCountOutputTypeGetPayload : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof OneOptional ?OneOptional [P] - : - P extends 'many' - ? Array < ManyRequiredGetPayload> : - P extends '_count' - ? OneOptionalCountOutputTypeGetPayload : never + [P in TrueKeys]: + P extends 'many' ? Array < ManyRequiredGetPayload> : + P extends '_count' ? OneOptionalCountOutputTypeGetPayload : P extends keyof OneOptional ? OneOptional[P] : never } : OneOptional : OneOptional @@ -6040,7 +6081,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOneOptionalGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOneOptionalGroupByPayload : PrismaPromise } /** @@ -6259,6 +6300,10 @@ export namespace Prisma { * OneOptional createMany */ export type OneOptionalCreateManyArgs = { + /** + * The data used to create many OneOptionals. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -6295,7 +6340,15 @@ export namespace Prisma { * OneOptional updateMany */ export type OneOptionalUpdateManyArgs = { + /** + * The data used to update OneOptionals. + * + **/ data: XOR + /** + * Filter which OneOptionals to update + * + **/ where?: OneOptionalWhereInput } @@ -6358,6 +6411,10 @@ export namespace Prisma { * OneOptional deleteMany */ export type OneOptionalDeleteManyArgs = { + /** + * Filter which OneOptionals to delete + * + **/ where?: OneOptionalWhereInput } @@ -6640,7 +6697,7 @@ export namespace Prisma { _max: ManyRequiredMaxAggregateOutputType | null } - type GetManyRequiredGroupByPayload = Promise< + type GetManyRequiredGroupByPayload = PrismaPromise< Array< PickArray & { @@ -6686,16 +6743,13 @@ export namespace Prisma { : S extends ManyRequiredArgs | ManyRequiredFindManyArgs ?'include' extends U ? ManyRequired & { - [P in TrueKeys]: - P extends 'one' - ? OneOptionalGetPayload | null : never + [P in TrueKeys]: + P extends 'one' ? OneOptionalGetPayload | null : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof ManyRequired ?ManyRequired [P] - : - P extends 'one' - ? OneOptionalGetPayload | null : never + [P in TrueKeys]: + P extends 'one' ? OneOptionalGetPayload | null : P extends keyof ManyRequired ? ManyRequired[P] : never } : ManyRequired : ManyRequired @@ -7009,7 +7063,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetManyRequiredGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetManyRequiredGroupByPayload : PrismaPromise } /** @@ -7228,6 +7282,10 @@ export namespace Prisma { * ManyRequired createMany */ export type ManyRequiredCreateManyArgs = { + /** + * The data used to create many ManyRequireds. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -7264,7 +7322,15 @@ export namespace Prisma { * ManyRequired updateMany */ export type ManyRequiredUpdateManyArgs = { + /** + * The data used to update ManyRequireds. + * + **/ data: XOR + /** + * Filter which ManyRequireds to update + * + **/ where?: ManyRequiredWhereInput } @@ -7327,6 +7393,10 @@ export namespace Prisma { * ManyRequired deleteMany */ export type ManyRequiredDeleteManyArgs = { + /** + * Filter which ManyRequireds to delete + * + **/ where?: ManyRequiredWhereInput } @@ -7609,7 +7679,7 @@ export namespace Prisma { _max: OptionalSide1MaxAggregateOutputType | null } - type GetOptionalSide1GroupByPayload = Promise< + type GetOptionalSide1GroupByPayload = PrismaPromise< Array< PickArray & { @@ -7655,16 +7725,13 @@ export namespace Prisma { : S extends OptionalSide1Args | OptionalSide1FindManyArgs ?'include' extends U ? OptionalSide1 & { - [P in TrueKeys]: - P extends 'opti' - ? OptionalSide2GetPayload | null : never + [P in TrueKeys]: + P extends 'opti' ? OptionalSide2GetPayload | null : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof OptionalSide1 ?OptionalSide1 [P] - : - P extends 'opti' - ? OptionalSide2GetPayload | null : never + [P in TrueKeys]: + P extends 'opti' ? OptionalSide2GetPayload | null : P extends keyof OptionalSide1 ? OptionalSide1[P] : never } : OptionalSide1 : OptionalSide1 @@ -7978,7 +8045,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOptionalSide1GroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOptionalSide1GroupByPayload : PrismaPromise } /** @@ -8197,6 +8264,10 @@ export namespace Prisma { * OptionalSide1 createMany */ export type OptionalSide1CreateManyArgs = { + /** + * The data used to create many OptionalSide1s. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -8233,7 +8304,15 @@ export namespace Prisma { * OptionalSide1 updateMany */ export type OptionalSide1UpdateManyArgs = { + /** + * The data used to update OptionalSide1s. + * + **/ data: XOR + /** + * Filter which OptionalSide1s to update + * + **/ where?: OptionalSide1WhereInput } @@ -8296,6 +8375,10 @@ export namespace Prisma { * OptionalSide1 deleteMany */ export type OptionalSide1DeleteManyArgs = { + /** + * Filter which OptionalSide1s to delete + * + **/ where?: OptionalSide1WhereInput } @@ -8567,7 +8650,7 @@ export namespace Prisma { _max: OptionalSide2MaxAggregateOutputType | null } - type GetOptionalSide2GroupByPayload = Promise< + type GetOptionalSide2GroupByPayload = PrismaPromise< Array< PickArray & { @@ -8612,16 +8695,13 @@ export namespace Prisma { : S extends OptionalSide2Args | OptionalSide2FindManyArgs ?'include' extends U ? OptionalSide2 & { - [P in TrueKeys]: - P extends 'opti' - ? OptionalSide1GetPayload | null : never + [P in TrueKeys]: + P extends 'opti' ? OptionalSide1GetPayload | null : never } : 'select' extends U ? { - [P in TrueKeys]: P extends keyof OptionalSide2 ?OptionalSide2 [P] - : - P extends 'opti' - ? OptionalSide1GetPayload | null : never + [P in TrueKeys]: + P extends 'opti' ? OptionalSide1GetPayload | null : P extends keyof OptionalSide2 ? OptionalSide2[P] : never } : OptionalSide2 : OptionalSide2 @@ -8935,7 +9015,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOptionalSide2GroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetOptionalSide2GroupByPayload : PrismaPromise } /** @@ -9154,6 +9234,10 @@ export namespace Prisma { * OptionalSide2 createMany */ export type OptionalSide2CreateManyArgs = { + /** + * The data used to create many OptionalSide2s. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -9190,7 +9274,15 @@ export namespace Prisma { * OptionalSide2 updateMany */ export type OptionalSide2UpdateManyArgs = { + /** + * The data used to update OptionalSide2s. + * + **/ data: XOR + /** + * Filter which OptionalSide2s to update + * + **/ where?: OptionalSide2WhereInput } @@ -9253,6 +9345,10 @@ export namespace Prisma { * OptionalSide2 deleteMany */ export type OptionalSide2DeleteManyArgs = { + /** + * Filter which OptionalSide2s to delete + * + **/ where?: OptionalSide2WhereInput } @@ -9508,7 +9604,7 @@ export namespace Prisma { _max: AMaxAggregateOutputType | null } - type GetAGroupByPayload = Promise< + type GetAGroupByPayload = PrismaPromise< Array< PickArray & { @@ -9546,9 +9642,8 @@ export namespace Prisma { ? A : 'select' extends U ? { - [P in TrueKeys]: P extends keyof A ?A [P] - : - never + [P in TrueKeys]: + P extends keyof A ? A[P] : never } : A : A @@ -9862,7 +9957,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetAGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetAGroupByPayload : PrismaPromise } /** @@ -10060,6 +10155,10 @@ export namespace Prisma { * A createMany */ export type ACreateManyArgs = { + /** + * The data used to create many AS. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -10091,7 +10190,15 @@ export namespace Prisma { * A updateMany */ export type AUpdateManyArgs = { + /** + * The data used to update AS. + * + **/ data: XOR + /** + * Filter which AS to update + * + **/ where?: AWhereInput } @@ -10144,6 +10251,10 @@ export namespace Prisma { * A deleteMany */ export type ADeleteManyArgs = { + /** + * Filter which AS to delete + * + **/ where?: AWhereInput } @@ -10358,7 +10469,7 @@ export namespace Prisma { _max: BMaxAggregateOutputType | null } - type GetBGroupByPayload = Promise< + type GetBGroupByPayload = PrismaPromise< Array< PickArray & { @@ -10392,9 +10503,8 @@ export namespace Prisma { ? B : 'select' extends U ? { - [P in TrueKeys]: P extends keyof B ?B [P] - : - never + [P in TrueKeys]: + P extends keyof B ? B[P] : never } : B : B @@ -10708,7 +10818,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetBGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetBGroupByPayload : PrismaPromise } /** @@ -10906,6 +11016,10 @@ export namespace Prisma { * B createMany */ export type BCreateManyArgs = { + /** + * The data used to create many BS. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -10937,7 +11051,15 @@ export namespace Prisma { * B updateMany */ export type BUpdateManyArgs = { + /** + * The data used to update BS. + * + **/ data: XOR + /** + * Filter which BS to update + * + **/ where?: BWhereInput } @@ -10990,6 +11112,10 @@ export namespace Prisma { * B deleteMany */ export type BDeleteManyArgs = { + /** + * Filter which BS to delete + * + **/ where?: BWhereInput } @@ -11172,7 +11298,7 @@ export namespace Prisma { _max: CMaxAggregateOutputType | null } - type GetCGroupByPayload = Promise< + type GetCGroupByPayload = PrismaPromise< Array< PickArray & { @@ -11208,9 +11334,8 @@ export namespace Prisma { ? C : 'select' extends U ? { - [P in TrueKeys]: P extends keyof C ?C [P] - : - never + [P in TrueKeys]: + P extends keyof C ? C[P] : never } : C : C @@ -11524,7 +11649,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetCGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetCGroupByPayload : PrismaPromise } /** @@ -11722,6 +11847,10 @@ export namespace Prisma { * C createMany */ export type CCreateManyArgs = { + /** + * The data used to create many CS. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -11753,7 +11882,15 @@ export namespace Prisma { * C updateMany */ export type CUpdateManyArgs = { + /** + * The data used to update CS. + * + **/ data: XOR + /** + * Filter which CS to update + * + **/ where?: CWhereInput } @@ -11806,6 +11943,10 @@ export namespace Prisma { * C deleteMany */ export type CDeleteManyArgs = { + /** + * Filter which CS to delete + * + **/ where?: CWhereInput } @@ -11973,7 +12114,7 @@ export namespace Prisma { _max: DMaxAggregateOutputType | null } - type GetDGroupByPayload = Promise< + type GetDGroupByPayload = PrismaPromise< Array< PickArray & { @@ -12008,9 +12149,8 @@ export namespace Prisma { ? D : 'select' extends U ? { - [P in TrueKeys]: P extends keyof D ?D [P] - : - never + [P in TrueKeys]: + P extends keyof D ? D[P] : never } : D : D @@ -12324,7 +12464,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetDGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetDGroupByPayload : PrismaPromise } /** @@ -12522,6 +12662,10 @@ export namespace Prisma { * D createMany */ export type DCreateManyArgs = { + /** + * The data used to create many DS. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -12553,7 +12697,15 @@ export namespace Prisma { * D updateMany */ export type DUpdateManyArgs = { + /** + * The data used to update DS. + * + **/ data: XOR + /** + * Filter which DS to update + * + **/ where?: DWhereInput } @@ -12606,6 +12758,10 @@ export namespace Prisma { * D deleteMany */ export type DDeleteManyArgs = { + /** + * Filter which DS to delete + * + **/ where?: DWhereInput } @@ -12767,7 +12923,7 @@ export namespace Prisma { _max: EMaxAggregateOutputType | null } - type GetEGroupByPayload = Promise< + type GetEGroupByPayload = PrismaPromise< Array< PickArray & { @@ -12800,9 +12956,8 @@ export namespace Prisma { ? E : 'select' extends U ? { - [P in TrueKeys]: P extends keyof E ?E [P] - : - never + [P in TrueKeys]: + P extends keyof E ? E[P] : never } : E : E @@ -13116,7 +13271,7 @@ export namespace Prisma { ? never : \`Error: Field "\${P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] - >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetEGroupByPayload : Promise + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetEGroupByPayload : PrismaPromise } /** @@ -13314,6 +13469,10 @@ export namespace Prisma { * E createMany */ export type ECreateManyArgs = { + /** + * The data used to create many ES. + * + **/ data: Enumerable skipDuplicates?: boolean } @@ -13345,7 +13504,15 @@ export namespace Prisma { * E updateMany */ export type EUpdateManyArgs = { + /** + * The data used to update ES. + * + **/ data: XOR + /** + * Filter which ES to update + * + **/ where?: EWhereInput } @@ -13398,6 +13565,10 @@ export namespace Prisma { * E deleteMany */ export type EDeleteManyArgs = { + /** + * Filter which ES to delete + * + **/ where?: EWhereInput } @@ -14744,6 +14915,7 @@ export namespace Prisma { } export type MCreateInput = { + n?: NCreateNestedManyWithoutMInput int: number optionalInt?: number | null float: number @@ -14756,11 +14928,11 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - n?: NCreateNestedManyWithoutMInput } export type MUncheckedCreateInput = { id?: number + n?: NUncheckedCreateNestedManyWithoutMInput int: number optionalInt?: number | null float: number @@ -14776,6 +14948,7 @@ export namespace Prisma { } export type MUpdateInput = { + n?: NUpdateManyWithoutMInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -14788,11 +14961,11 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - n?: NUpdateManyWithoutMInput } export type MUncheckedUpdateInput = { id?: IntFieldUpdateOperationsInput | number + n?: NUncheckedUpdateManyWithoutMInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -14855,6 +15028,7 @@ export namespace Prisma { } export type NCreateInput = { + m?: MCreateNestedManyWithoutNInput int: number optionalInt?: number | null float: number @@ -14867,11 +15041,11 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - m?: MCreateNestedManyWithoutNInput } export type NUncheckedCreateInput = { id?: number + m?: MUncheckedCreateNestedManyWithoutNInput int: number optionalInt?: number | null float: number @@ -14887,6 +15061,7 @@ export namespace Prisma { } export type NUpdateInput = { + m?: MUpdateManyWithoutNInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -14899,11 +15074,11 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - m?: MUpdateManyWithoutNInput } export type NUncheckedUpdateInput = { id?: IntFieldUpdateOperationsInput | number + m?: MUncheckedUpdateManyWithoutNInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -14966,6 +15141,7 @@ export namespace Prisma { } export type OneOptionalCreateInput = { + many?: ManyRequiredCreateNestedManyWithoutOneInput int: number optionalInt?: number | null float: number @@ -14978,11 +15154,11 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - many?: ManyRequiredCreateNestedManyWithoutOneInput } export type OneOptionalUncheckedCreateInput = { id?: number + many?: ManyRequiredUncheckedCreateNestedManyWithoutOneInput int: number optionalInt?: number | null float: number @@ -14995,10 +15171,10 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - many?: ManyRequiredUncheckedCreateNestedManyWithoutOneInput } export type OneOptionalUpdateInput = { + many?: ManyRequiredUpdateManyWithoutOneInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -15011,11 +15187,11 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - many?: ManyRequiredUpdateManyWithoutOneInput } export type OneOptionalUncheckedUpdateInput = { id?: IntFieldUpdateOperationsInput | number + many?: ManyRequiredUncheckedUpdateManyWithoutOneInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -15028,7 +15204,6 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - many?: ManyRequiredUncheckedUpdateManyWithoutOneInput } export type OneOptionalCreateManyInput = { @@ -15079,6 +15254,7 @@ export namespace Prisma { } export type ManyRequiredCreateInput = { + one?: OneOptionalCreateNestedOneWithoutManyInput int: number optionalInt?: number | null float: number @@ -15091,7 +15267,6 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - one?: OneOptionalCreateNestedOneWithoutManyInput } export type ManyRequiredUncheckedCreateInput = { @@ -15112,6 +15287,7 @@ export namespace Prisma { } export type ManyRequiredUpdateInput = { + one?: OneOptionalUpdateOneWithoutManyInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -15124,7 +15300,6 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - one?: OneOptionalUpdateOneWithoutManyInput } export type ManyRequiredUncheckedUpdateInput = { @@ -15194,6 +15369,7 @@ export namespace Prisma { } export type OptionalSide1CreateInput = { + opti?: OptionalSide2CreateNestedOneWithoutOptiInput int: number optionalInt?: number | null float: number @@ -15206,7 +15382,6 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - opti?: OptionalSide2CreateNestedOneWithoutOptiInput } export type OptionalSide1UncheckedCreateInput = { @@ -15227,6 +15402,7 @@ export namespace Prisma { } export type OptionalSide1UpdateInput = { + opti?: OptionalSide2UpdateOneWithoutOptiInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -15239,7 +15415,6 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - opti?: OptionalSide2UpdateOneWithoutOptiInput } export type OptionalSide1UncheckedUpdateInput = { @@ -15309,6 +15484,7 @@ export namespace Prisma { } export type OptionalSide2CreateInput = { + opti?: OptionalSide1CreateNestedOneWithoutOptiInput int: number optionalInt?: number | null float: number @@ -15321,11 +15497,11 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - opti?: OptionalSide1CreateNestedOneWithoutOptiInput } export type OptionalSide2UncheckedCreateInput = { id?: number + opti?: OptionalSide1UncheckedCreateNestedOneWithoutOptiInput int: number optionalInt?: number | null float: number @@ -15338,10 +15514,10 @@ export namespace Prisma { optionalEnum?: ABeautifulEnum | null boolean: boolean optionalBoolean?: boolean | null - opti?: OptionalSide1UncheckedCreateNestedOneWithoutOptiInput } export type OptionalSide2UpdateInput = { + opti?: OptionalSide1UpdateOneWithoutOptiInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -15354,11 +15530,11 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - opti?: OptionalSide1UpdateOneWithoutOptiInput } export type OptionalSide2UncheckedUpdateInput = { id?: IntFieldUpdateOperationsInput | number + opti?: OptionalSide1UncheckedUpdateOneWithoutOptiInput int?: IntFieldUpdateOperationsInput | number optionalInt?: NullableIntFieldUpdateOperationsInput | number | null float?: FloatFieldUpdateOperationsInput | number @@ -15371,7 +15547,6 @@ export namespace Prisma { optionalEnum?: NullableEnumABeautifulEnumFieldUpdateOperationsInput | ABeautifulEnum | null boolean?: BoolFieldUpdateOperationsInput | boolean optionalBoolean?: NullableBoolFieldUpdateOperationsInput | boolean | null - opti?: OptionalSide1UncheckedUpdateOneWithoutOptiInput } export type OptionalSide2CreateManyInput = { @@ -16985,6 +17160,12 @@ export namespace Prisma { connect?: Enumerable } + export type NUncheckedCreateNestedManyWithoutMInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + connect?: Enumerable + } + export type NUpdateManyWithoutMInput = { create?: XOR, Enumerable> connectOrCreate?: Enumerable @@ -16998,12 +17179,31 @@ export namespace Prisma { deleteMany?: Enumerable } + export type NUncheckedUpdateManyWithoutMInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + export type MCreateNestedManyWithoutNInput = { create?: XOR, Enumerable> connectOrCreate?: Enumerable connect?: Enumerable } + export type MUncheckedCreateNestedManyWithoutNInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + connect?: Enumerable + } + export type MUpdateManyWithoutNInput = { create?: XOR, Enumerable> connectOrCreate?: Enumerable @@ -17017,6 +17217,19 @@ export namespace Prisma { deleteMany?: Enumerable } + export type MUncheckedUpdateManyWithoutNInput = { + create?: XOR, Enumerable> + connectOrCreate?: Enumerable + upsert?: Enumerable + set?: Enumerable + disconnect?: Enumerable + delete?: Enumerable + connect?: Enumerable + update?: Enumerable + updateMany?: Enumerable + deleteMany?: Enumerable + } + export type ManyRequiredCreateNestedManyWithoutOneInput = { create?: XOR, Enumerable> connectOrCreate?: Enumerable diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema/dmmf-types.test.ts b/packages/client/src/__tests__/integration/happy/exhaustive-schema/dmmf-types.test.ts index 22da2e8ccb1b..73c6dc90d22a 100644 --- a/packages/client/src/__tests__/integration/happy/exhaustive-schema/dmmf-types.test.ts +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema/dmmf-types.test.ts @@ -1,5 +1,6 @@ -import path from 'path' import fs from 'fs' +import path from 'path' + import { getDMMF } from '../../../../generation/getDMMF' import { compileFile } from '../../../../utils/compileFile' diff --git a/packages/client/src/__tests__/integration/happy/exhaustive-schema/test.ts b/packages/client/src/__tests__/integration/happy/exhaustive-schema/test.ts index 16f4ebf3c070..e68e3d38723a 100644 --- a/packages/client/src/__tests__/integration/happy/exhaustive-schema/test.ts +++ b/packages/client/src/__tests__/integration/happy/exhaustive-schema/test.ts @@ -1,7 +1,8 @@ -import { generateTestClient } from '../../../../utils/getTestClient' import fs from 'fs' import path from 'path' +import { generateTestClient } from '../../../../utils/getTestClient' + test('exhaustive-schema', async () => { await generateTestClient() diff --git a/packages/client/src/__tests__/integration/happy/full-text-search-mysql/test.ts b/packages/client/src/__tests__/integration/happy/full-text-search-mysql/test.ts index bea9a00ad173..22581a4f9e79 100644 --- a/packages/client/src/__tests__/integration/happy/full-text-search-mysql/test.ts +++ b/packages/client/src/__tests__/integration/happy/full-text-search-mysql/test.ts @@ -1,12 +1,19 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' +// @ts-ignore trick to get typings at dev time +import type { PrismaClient } from './node_modules/@prisma/client' const testIf = (condition: boolean) => (condition ? test : test.skip) -// @ts-ignore trick to get typings at dev time -import type { PrismaClient } from './node_modules/@prisma/client' +if (process.env.CI) { + // to avoid timeouts on macOS and Windows + jest.setTimeout(100_000) +} else { + jest.setTimeout(10_000) +} let prisma: PrismaClient const baseUri = process.env.TEST_MYSQL_URI @@ -172,16 +179,16 @@ describe('full-text-search (mysql)', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Invalid \`.findMany()\` invocation in - /client/src/__tests__/integration/happy/full-text-search-mysql/test.ts:0:0 + Invalid \`.findMany()\` invocation in + /client/src/__tests__/integration/happy/full-text-search-mysql/test.ts:0:0 - 157 */ - 158 testIf(process.platform !== 'win32')('bad operator', async () => { - 159 const result = prisma.user - → 160 .findMany( - Error occurred during query execution: - ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Server(ServerError { code: 1064, message: "syntax error, unexpected '-'", state: "42000" })) }) - `) + 164 */ + 165 testIf(process.platform !== 'win32')('bad operator', async () => { + 166 const result = prisma.user + → 167 .findMany( + Error occurred during query execution: + ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Server(ServerError { code: 1064, message: "syntax error, unexpected '-'", state: "42000" })) }) + `) }) test('order by relevance on a single field', async () => { diff --git a/packages/client/src/__tests__/integration/happy/full-text-search-postgres/test.ts b/packages/client/src/__tests__/integration/happy/full-text-search-postgres/test.ts index 3ca6328bd9f7..2377436de6e2 100644 --- a/packages/client/src/__tests__/integration/happy/full-text-search-postgres/test.ts +++ b/packages/client/src/__tests__/integration/happy/full-text-search-postgres/test.ts @@ -1,12 +1,19 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' +// @ts-ignore trick to get typings at dev time +import type { PrismaClient } from './node_modules/@prisma/client' const testIf = (condition: boolean) => (condition ? test : test.skip) -// @ts-ignore trick to get typings at dev time -import type { PrismaClient } from './node_modules/@prisma/client' +if (process.env.CI) { + // to avoid timeouts on macOS and Windows + jest.setTimeout(100_000) +} else { + jest.setTimeout(10_000) +} let prisma: PrismaClient const baseUri = process.env.TEST_POSTGRES_URI @@ -223,16 +230,16 @@ describe('full-text-search (postgres)', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Invalid \`.findMany()\` invocation in - /client/src/__tests__/integration/happy/full-text-search-postgres/test.ts:0:0 + Invalid \`.findMany()\` invocation in + /client/src/__tests__/integration/happy/full-text-search-postgres/test.ts:0:0 - 208 */ - 209 testIf(process.platform !== 'win32')('bad operator', async () => { - 210 const result = prisma.user - → 211 .findMany( - Error occurred during query execution: - ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("42601"), message: "syntax error in tsquery: \\"0 1\\"", detail: None, hint: None, position: None, where_: None, schema: None, table: None, column: None, datatype: None, constraint: None, file: Some("tsquery.c"), line: Some(0), routine: Some("makepol") }) }) }) - `) + 215 */ + 216 testIf(process.platform !== 'win32')('bad operator', async () => { + 217 const result = prisma.user + → 218 .findMany( + Error occurred during query execution: + ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState("42601"), message: "syntax error in tsquery: \\"0 1\\"", detail: None, hint: None, position: None, where_: None, schema: None, table: None, column: None, datatype: None, constraint: None, file: Some("tsquery.c"), line: Some(0), routine: Some("makepol") }) }) }) + `) }) test('order by relevance on a single field', async () => { diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions-concurrent-postgres/test.ts b/packages/client/src/__tests__/integration/happy/interactive-transactions-concurrent-postgres/test.ts deleted file mode 100644 index 857e1d4477a3..000000000000 --- a/packages/client/src/__tests__/integration/happy/interactive-transactions-concurrent-postgres/test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import path from 'path' -import { getTestClient } from '../../../../utils/getTestClient' -import { tearDownPostgres } from '../../../../utils/setupPostgres' -import { migrateDb } from '../../__helpers__/migrateDb' - -let PrismaClient, prisma - -describe('interactive transaction', () => { - /** - * Two concurrent transactions should work - */ - test('concurrent', async () => { - await Promise.all([ - prisma.$transaction([ - prisma.user.create({ - data: { - email: 'user_1@website.com', - }, - }), - ]), - prisma.$transaction([ - prisma.user.create({ - data: { - email: 'user_2@website.com', - }, - }), - ]), - ]) - - const users = await prisma.user.findMany() - - expect(users.length).toBe(2) - }) -}) - -beforeAll(async () => { - if (!process.env.TEST_POSTGRES_URI) { - throw new Error('TEST_POSTGRES_URI must be provided for this test') - } - - process.env.TEST_POSTGRES_URI += '-interactive-transactions-concurrent-postgres' - - await tearDownPostgres(process.env.TEST_POSTGRES_URI) - await migrateDb({ - connectionString: process.env.TEST_POSTGRES_URI, - schemaPath: path.join(__dirname, 'schema.prisma'), - }) - - PrismaClient = await getTestClient() -}) - -beforeEach(async () => { - prisma = new PrismaClient() - - await prisma.user.deleteMany() -}) - -afterEach(async () => { - await prisma.$disconnect() -}) diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions-concurrent-postgres/schema.prisma b/packages/client/src/__tests__/integration/happy/interactive-transactions-postgres/schema.prisma similarity index 100% rename from packages/client/src/__tests__/integration/happy/interactive-transactions-concurrent-postgres/schema.prisma rename to packages/client/src/__tests__/integration/happy/interactive-transactions-postgres/schema.prisma diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts b/packages/client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts new file mode 100644 index 000000000000..dd0801ad2b4d --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts @@ -0,0 +1,604 @@ +import { ClientEngineType, getClientEngineType } from '@prisma/sdk' +import path from 'path' + +import { getTestClient } from '../../../../utils/getTestClient' +import { tearDownPostgres } from '../../../../utils/setupPostgres' +import { migrateDb } from '../../__helpers__/migrateDb' + +const testIf = (condition: boolean) => (condition ? test : test.skip) + +let PrismaClient, prisma + +describe('interactive transactions', () => { + /** + * Minimal example of an interactive transaction + */ + test('basic', async () => { + const result = await prisma.$transaction(async (prisma) => { + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + await prisma.user.create({ + data: { + email: 'user_2@website.com', + }, + }) + + return prisma.user.findMany() + }) + + expect(result.length).toBe(2) + }) + + /** + * Transactions should fail after the default timeout + */ + test('timeout default', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + await new Promise((res) => setTimeout(res, 6000)) + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'.`, + ) + + expect(await prisma.user.findMany()).toHaveLength(0) + }) + + /** + * Transactions should fail if they time out on `timeout` + */ + test('timeout override', async () => { + const result = prisma.$transaction( + async (prisma) => { + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + await new Promise((res) => setTimeout(res, 6000)) + }, + { + maxWait: 200, + timeout: 500, + }, + ) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'.`, + ) + + expect(await prisma.user.findMany()).toHaveLength(0) + }) + + /** + * Transactions should fail if they time out on `maxWait` + */ + test.skip('maxWait override', async () => { + const result = prisma.$transaction( + async (prisma) => { + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + await new Promise((res) => setTimeout(res, 5)) + + return prisma.user.findMany() + }, + { + maxWait: 0, + }, + ) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.user.findMany()\` invocation: + + + Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'. + `) + }) + + /** + * Transactions should fail and rollback if thrown within + */ + test('rollback throw', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + throw new Error('you better rollback now') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`you better rollback now`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * A transaction might fail if it's called inside another transaction + * //! this does not behave the same for all dbs (sqlite) + */ + test('nested create', async () => { + const result = prisma.$transaction(async (tx) => { + await tx.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + await prisma.$transaction(async (tx) => { + await tx.user.create({ + data: { + email: 'user_2@website.com', + }, + }) + }) + + return tx.user.findMany() + }) + + await expect(result).resolves.toHaveLength(2) + }) + + /** + * We don't allow certain methods to be called in a transaction + */ + test('forbidden', async () => { + const forbidden = ['$connect', '$disconnect', '$on', '$transaction', '$use'] + + const result = prisma.$transaction((prisma) => { + // we accumulate all the forbidden methods and expect to be undefined + return forbidden.reduce((acc, item) => acc ?? prisma[item], undefined) + }) + + await expect(result).resolves.toBe(undefined) + }) + + /** + * If one of the query fails, all queries should cancel + */ + test('rollback query', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + + await prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.user.create()\` invocation in + /client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts:0:0 + + 183 }, + 184 }) + 185 + → 186 await prisma.user.create( + Unique constraint failed on the fields: (\`email\`) + `) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * A transaction that is already 'commit' cannot be reused + */ + test('already committed', async () => { + let transactionBoundPrisma + await prisma.$transaction((prisma) => { + transactionBoundPrisma = prisma + }) + + const result = prisma.$transaction(async () => { + await transactionBoundPrisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`transactionBoundPrisma.user.create()\` invocation in + /client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts:0:0 + + 217 }) + 218 + 219 const result = prisma.$transaction(async () => { + → 220 await transactionBoundPrisma.user.create( + Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Committed'. + `) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * Batching should work with using the interactive transaction logic + */ + test('batching', async () => { + await prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + prisma.user.create({ + data: { + email: 'user_2@website.com', + }, + }), + ]) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(2) + }) + + /** + * A bad batch should rollback using the interactive transaction logic + * // TODO: skipped because output differs from binary to library + */ + testIf(getClientEngineType() === ClientEngineType.Library)('batching rollback', async () => { + const result = prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + ]) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.user.create()\` invocation in + /client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts:0:0 + + 269 */ + 270 testIf(getClientEngineType() === ClientEngineType.Library)('batching rollback', async () => { + 271 const result = prisma.$transaction([ + → 272 prisma.user.create( + Unique constraint failed on the fields: (\`email\`) + `) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * A bad batch should rollback using the interactive transaction logic + * // TODO: skipped because output differs from binary to library + */ + testIf(getClientEngineType() === ClientEngineType.Library)('batching raw rollback', async () => { + await prisma.user.create({ + data: { + id: '1', + email: 'user_1@website.com', + }, + }) + + const result = prisma.$transaction([ + prisma.$executeRaw`INSERT INTO "public"."User" (id, email) VALUES (${'2'}, ${'user_2@website.com'})`, + prisma.$queryRaw`DELETE FROM "public"."User"`, + prisma.$executeRaw`INSERT INTO "public"."User" (id, email) VALUES (${'1'}, ${'user_1@website.com'})`, + prisma.$executeRaw`INSERT INTO "public"."User" (id, email) VALUES (${'1'}, ${'user_1@website.com'})`, + ]) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.executeRaw()\` invocation: + + + Raw query failed. Code: \`23505\`. Message: \`Key (id)=(1) already exists.\` + `) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(1) + }) + + /** + * Middlewares should work normally on batches + */ + test('middlewares batching', async () => { + prisma.$use(async (params, next) => { + const result = await next(params) + + return result + }) + + await prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + prisma.user.create({ + data: { + email: 'user_2@website.com', + }, + }), + ]) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(2) + }) + + /** + * Middlewares should not prevent a rollback + * // TODO: skipped because output differs from binary to library + */ + testIf(getClientEngineType() === ClientEngineType.Library)('middlewares batching rollback', async () => { + prisma.$use(async (params, next) => { + const result = await next(params) + + return result + }) + + const result = prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + ]) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + + Invalid \`prisma.user.create()\` invocation in + /client/src/__tests__/integration/happy/interactive-transactions-postgres/test.ts:0:0 + + 370 }) + 371 + 372 const result = prisma.$transaction([ + → 373 prisma.user.create( + Unique constraint failed on the fields: (\`email\`) + `) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * Minimal example of a interactive transaction & middleware + */ + test('middleware basic', async () => { + let runInTransaction = false + + prisma.$use(async (params, next) => { + await next(params) + + runInTransaction = params.runInTransaction + + return 'result' + }) + + const result = await prisma.$transaction((prisma) => { + return prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }) + }) + + expect(result).toBe('result') + expect(runInTransaction).toBe(true) + }) + + /** + * Two concurrent transactions should work + */ + test('concurrent', async () => { + await Promise.all([ + prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + ]), + prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_2@website.com', + }, + }), + ]), + ]) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(2) + }) + + /** + * Makes sure that the engine does not deadlock + */ + test('high concurrency', async () => { + jest.setTimeout(20000) + + await prisma.user.create({ + data: { + email: 'x', + name: 'y', + }, + }) + + for (let i = 0; i < 5; i++) { + await Promise.allSettled([ + prisma.$transaction((tx) => tx.user.update({ data: { name: 'a' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'b' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'c' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'd' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'e' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'f' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'g' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'h' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'i' }, where: { email: 'x' } }), { timeout: 25 }), + prisma.$transaction((tx) => tx.user.update({ data: { name: 'j' }, where: { email: 'x' } }), { timeout: 25 }), + ]).catch(() => {}) // we don't care for errors, there will be + } + }) + + /** + * Rollback should happen even with `then` calls + */ + test('rollback with then calls', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user + .create({ + data: { + email: 'user_1@website.com', + }, + }) + .then() + + await prisma.user + .create({ + data: { + email: 'user_2@website.com', + }, + }) + .then() + .then() + + throw new Error('rollback') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`rollback`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * Rollback should happen even with `catch` calls + */ + test('rollback with catch calls', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user + .create({ + data: { + email: 'user_1@website.com', + }, + }) + .catch() + await prisma.user + .create({ + data: { + email: 'user_2@website.com', + }, + }) + .catch() + .then() + + throw new Error('rollback') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`rollback`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * Rollback should happen even with `finally` calls + */ + test('rollback with finally calls', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user + .create({ + data: { + email: 'user_1@website.com', + }, + }) + .finally() + + await prisma.user + .create({ + data: { + email: 'user_2@website.com', + }, + }) + .then() + .catch() + .finally() + + throw new Error('rollback') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`rollback`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) +}) + +beforeAll(async () => { + if (!process.env.TEST_POSTGRES_URI) { + throw new Error('TEST_POSTGRES_URI must be provided for this test') + } + + process.env.TEST_POSTGRES_URI += '-interactive-transactions-concurrent-postgres' + + await tearDownPostgres(process.env.TEST_POSTGRES_URI) + await migrateDb({ + connectionString: process.env.TEST_POSTGRES_URI, + schemaPath: path.join(__dirname, 'schema.prisma'), + }) + + PrismaClient = await getTestClient() +}) + +beforeEach(async () => { + prisma = new PrismaClient() + + await prisma.user.deleteMany() +}) + +afterEach(async () => { + await prisma.$disconnect() +}) diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions/.gitignore b/packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/.gitignore similarity index 100% rename from packages/client/src/__tests__/integration/happy/interactive-transactions/.gitignore rename to packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/.gitignore diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions/dev.db b/packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/dev.db similarity index 98% rename from packages/client/src/__tests__/integration/happy/interactive-transactions/dev.db rename to packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/dev.db index ad9766fc1b00..389f9f4c371f 100644 Binary files a/packages/client/src/__tests__/integration/happy/interactive-transactions/dev.db and b/packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/dev.db differ diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions/schema.prisma b/packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/schema.prisma similarity index 100% rename from packages/client/src/__tests__/integration/happy/interactive-transactions/schema.prisma rename to packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/schema.prisma diff --git a/packages/client/src/__tests__/integration/happy/interactive-transactions/test.ts b/packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts similarity index 62% rename from packages/client/src/__tests__/integration/happy/interactive-transactions/test.ts rename to packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts index bff69e0d27dc..5b8d4b573c78 100644 --- a/packages/client/src/__tests__/integration/happy/interactive-transactions/test.ts +++ b/packages/client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts @@ -1,12 +1,10 @@ import { getTestClient } from '../../../../utils/getTestClient' -const testIf = (condition: boolean) => (condition ? test : test.skip) - let PrismaClient, prisma -describe('interactive transaction', () => { +describe('interactive transactions', () => { /** - * Minimal example of a interactive transaction + * Minimal example of an interactive transaction */ test('basic', async () => { const result = await prisma.$transaction(async (prisma) => { @@ -40,31 +38,19 @@ describe('interactive transaction', () => { }) await new Promise((res) => setTimeout(res, 6000)) - - return prisma.user.findMany() }) - await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - - Invalid \`prisma.user.findMany()\` invocation in - /client/src/__tests__/integration/happy/interactive-transactions/test.ts:0:0 + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'.`, + ) - 41 - 42 await new Promise((res) => setTimeout(res, 6000)) - 43 - → 44 return prisma.user.findMany( - Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'. - `) + expect(await prisma.user.findMany()).toHaveLength(0) }) /** * Transactions should fail if they time out on `timeout` - * - * TODO: macOS: this test is flaky on CI on macOS and often fails with: - * Received promise resolved instead of rejected - * Resolved to value: [{"email": "user_1@website.com", "id": "0d258eae-1c22-4af1-8c95-68a17e995c2e", "name": null}] */ - testIf(process.platform !== 'darwin' || !process.env.CI)('timeout override', async () => { + test('timeout override', async () => { const result = prisma.$transaction( async (prisma) => { await prisma.user.create({ @@ -73,9 +59,7 @@ describe('interactive transaction', () => { }, }) - await new Promise((res) => setTimeout(res, 600)) - - return prisma.user.findMany() + await new Promise((res) => setTimeout(res, 6000)) }, { maxWait: 200, @@ -83,17 +67,11 @@ describe('interactive transaction', () => { }, ) - await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - - Invalid \`prisma.user.findMany()\` invocation in - /client/src/__tests__/integration/happy/interactive-transactions/test.ts:0:0 + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'.`, + ) - 75 - 76 await new Promise((res) => setTimeout(res, 600)) - 77 - → 78 return prisma.user.findMany( - Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'. - `) + expect(await prisma.user.findMany()).toHaveLength(0) }) /** @@ -149,7 +127,8 @@ describe('interactive transaction', () => { /** * A transaction might fail if it's called inside another transaction - * // TODO this does not behave the same for all dbs (sqlite) + * //! this does not behave the same for all dbs (sqlite) + * //! Disabled because results are very volatile on CI */ test.skip('nested create', async () => { const result = prisma.$transaction(async (tx) => { @@ -159,29 +138,20 @@ describe('interactive transaction', () => { }, }) - await prisma.$transaction( - async (prisma) => { - await prisma.user.create({ - data: { - email: 'user_2@website.com', - }, - }) - }, - { - timeout: 1000, - }, - ) + await prisma.$transaction(async (tx) => { + await tx.user.create({ + data: { + email: 'user_2@website.com', + }, + }) + }) return tx.user.findMany() }) - await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - - Invalid \`prisma.user.findMany()\` invocation: - - - Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'. - `) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Expired'.`, + ) const users = await prisma.user.findMany() @@ -222,15 +192,15 @@ describe('interactive transaction', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Invalid \`prisma.user.create()\` invocation in - /client/src/__tests__/integration/happy/interactive-transactions/test.ts:0:0 + Invalid \`prisma.user.create()\` invocation in + /client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts:0:0 - 213 }, - 214 }) - 215 - → 216 await prisma.user.create( - Unique constraint failed on the fields: (\`email\`) - `) + 183 }, + 184 }) + 185 + → 186 await prisma.user.create( + Unique constraint failed on the fields: (\`email\`) + `) const users = await prisma.user.findMany() @@ -257,12 +227,12 @@ describe('interactive transaction', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` Invalid \`transactionBoundPrisma.user.create()\` invocation in - /client/src/__tests__/integration/happy/interactive-transactions/test.ts:0:0 + /client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts:0:0 - 247 }) - 248 - 249 const result = prisma.$transaction(async () => { - → 250 await transactionBoundPrisma.user.create( + 217 }) + 218 + 219 const result = prisma.$transaction(async () => { + → 220 await transactionBoundPrisma.user.create( Transaction API error: Transaction already closed: Transaction is no longer valid. Last state: 'Committed'. `) @@ -313,12 +283,12 @@ describe('interactive transaction', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` Invalid \`prisma.user.create()\` invocation in - /client/src/__tests__/integration/happy/interactive-transactions/test.ts:0:0 + /client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts:0:0 - 298 */ - 299 test('batching rollback', async () => { - 300 const result = prisma.$transaction([ - → 301 prisma.user.create( + 268 */ + 269 test('batching rollback', async () => { + 270 const result = prisma.$transaction([ + → 271 prisma.user.create( Unique constraint failed on the fields: (\`email\`) `) @@ -333,6 +303,7 @@ describe('interactive transaction', () => { test('batching raw rollback', async () => { await prisma.user.create({ data: { + id: '1', email: 'user_1@website.com', }, }) @@ -346,11 +317,11 @@ describe('interactive transaction', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Invalid \`prisma.executeRaw()\` invocation: + Invalid \`prisma.executeRaw()\` invocation: - Raw query failed. Code: \`2067\`. Message: \`UNIQUE constraint failed: User.email\` - `) + Raw query failed. Code: \`2067\`. Message: \`UNIQUE constraint failed: User.email\` + `) const users = await prisma.user.findMany() @@ -411,12 +382,12 @@ describe('interactive transaction', () => { await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` Invalid \`prisma.user.create()\` invocation in - /client/src/__tests__/integration/happy/interactive-transactions/test.ts:0:0 + /client/src/__tests__/integration/happy/interactive-transactions-sqlite/test.ts:0:0 - 396 }) - 397 - 398 const result = prisma.$transaction([ - → 399 prisma.user.create( + 367 }) + 368 + 369 const result = prisma.$transaction([ + → 370 prisma.user.create( Unique constraint failed on the fields: (\`email\`) `) @@ -425,13 +396,14 @@ describe('interactive transaction', () => { expect(users.length).toBe(0) }) - /** - * Minimal example of a interactive transaction & middleware - */ test('middleware basic', async () => { + let runInTransaction = false + prisma.$use(async (params, next) => { await next(params) + runInTransaction = params.runInTransaction + return 'result' }) @@ -444,6 +416,129 @@ describe('interactive transaction', () => { }) expect(result).toBe('result') + expect(runInTransaction).toBe(true) + }) + /** + * Two concurrent transactions should work + */ + test('concurrent', async () => { + await Promise.all([ + prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_1@website.com', + }, + }), + ]), + prisma.$transaction([ + prisma.user.create({ + data: { + email: 'user_2@website.com', + }, + }), + ]), + ]) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(2) + }) + + /** + * Rollback should happen even with `then` calls + */ + test('rollback with then calls', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user + .create({ + data: { + email: 'user_1@website.com', + }, + }) + .then() + + await prisma.user + .create({ + data: { + email: 'user_2@website.com', + }, + }) + .then() + .then() + + throw new Error('rollback') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`rollback`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * Rollback should happen even with `catch` calls + */ + test('rollback with catch calls', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user + .create({ + data: { + email: 'user_1@website.com', + }, + }) + .catch() + + await prisma.user + .create({ + data: { + email: 'user_2@website.com', + }, + }) + .catch() + .then() + + throw new Error('rollback') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`rollback`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) + }) + + /** + * Rollback should happen even with `finally` calls + */ + test('rollback with finally calls', async () => { + const result = prisma.$transaction(async (prisma) => { + await prisma.user + .create({ + data: { + email: 'user_1@website.com', + }, + }) + .finally() + + await prisma.user + .create({ + data: { + email: 'user_2@website.com', + }, + }) + .then() + .catch() + .finally() + + throw new Error('rollback') + }) + + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`rollback`) + + const users = await prisma.user.findMany() + + expect(users.length).toBe(0) }) }) diff --git a/packages/client/src/__tests__/integration/happy/json-filtering-mysql/test.ts b/packages/client/src/__tests__/integration/happy/json-filtering-mysql/test.ts index c6493dc50311..14e14b4b45b9 100644 --- a/packages/client/src/__tests__/integration/happy/json-filtering-mysql/test.ts +++ b/packages/client/src/__tests__/integration/happy/json-filtering-mysql/test.ts @@ -1,10 +1,10 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' - // @ts-ignore trick to get typings at dev time -import type { PrismaClient, Prisma } from './node_modules/.prisma/client' +import type { Prisma, PrismaClient } from './node_modules/.prisma/client' let prisma: PrismaClient let PrismaUtil: typeof Prisma diff --git a/packages/client/src/__tests__/integration/happy/json-filtering-postgres/test.ts b/packages/client/src/__tests__/integration/happy/json-filtering-postgres/test.ts index 3131aee407ae..7cd6abd9f613 100644 --- a/packages/client/src/__tests__/integration/happy/json-filtering-postgres/test.ts +++ b/packages/client/src/__tests__/integration/happy/json-filtering-postgres/test.ts @@ -1,14 +1,20 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' - // @ts-ignore trick to get typings at dev time -import type { PrismaClient, Prisma } from './node_modules/.prisma/client' +import type { Prisma, PrismaClient } from './node_modules/.prisma/client' let prisma: PrismaClient let PrismaUtil: typeof Prisma const baseUri = process.env.TEST_POSTGRES_URI + +const isMacOrWindowsCI = Boolean(process.env.CI) && ['darwin', 'win32'].includes(process.platform) +if (isMacOrWindowsCI) { + jest.setTimeout(100_000) +} + describe('json-filtering(postgres)', () => { beforeAll(async () => { process.env.TEST_POSTGRES_URI += '-json-filtering' diff --git a/packages/client/src/__tests__/integration/happy/logging/__helpers__/replaceTimeValues.ts b/packages/client/src/__tests__/integration/happy/logging/__helpers__/replaceTimeValues.ts new file mode 100644 index 000000000000..55d23d571a13 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/logging/__helpers__/replaceTimeValues.ts @@ -0,0 +1,17 @@ +/** + * Replace unstable time values (duration and timestamp) if their types are correct. + * + * @param fn Jest mock function passed as the log callback. + */ +export function replaceTimeValues(fn: jest.Mock) { + for (const [event] of fn.mock.calls) { + if (typeof event.duration === 'number') { + event.duration = 0 + } + + // Only replace valid dates. Dates with valueOf() equal to NaN should fail the snaphots. + if (event.timestamp instanceof Date && !Number.isNaN(event.timestamp.valueOf())) { + event.timestamp = new Date(0) + } + } +} diff --git a/packages/client/src/__tests__/integration/happy/logging/binary.ts b/packages/client/src/__tests__/integration/happy/logging/binary.ts new file mode 100644 index 000000000000..67813fca138e --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/logging/binary.ts @@ -0,0 +1,83 @@ +import { getClientEngineType } from '@prisma/sdk' +import path from 'path' + +import { getTestClient } from '../../../../utils/getTestClient' +import { tearDownPostgres } from '../../../../utils/setupPostgres' +import { migrateDb } from '../../__helpers__/migrateDb' +import { replaceTimeValues } from './__helpers__/replaceTimeValues' + +beforeEach(async () => { + process.env.TEST_POSTGRES_URI += '-logging-binary' + await tearDownPostgres(process.env.TEST_POSTGRES_URI!) + await migrateDb({ + connectionString: process.env.TEST_POSTGRES_URI!, + schemaPath: path.join(__dirname, 'schema.prisma'), + }) +}) + +test('basic event logging - binary', async () => { + if (getClientEngineType() !== 'binary') { + return + } + + const PrismaClient = await getTestClient() + + const prisma = new PrismaClient({ + log: [ + { + emit: 'event', + level: 'info', + }, + { + emit: 'event', + level: 'query', + }, + ], + }) + + const onInfo = jest.fn() + const onQuery = jest.fn() + + prisma.$on('info', onInfo) + prisma.$on('query', onQuery) + + await prisma.user.findMany() + + await prisma.$disconnect() + + replaceTimeValues(onInfo) + replaceTimeValues(onQuery) + + expect(onInfo.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + message: Starting a postgresql pool with XX connections., + target: quaint::pooled, + timestamp: 1970-01-01T00:00:00.000Z, + }, + ], + Array [ + Object { + message: Started query engine http server on http://127.0.0.1:00000, + target: query_engine::server, + timestamp: 1970-01-01T00:00:00.000Z, + }, + ], + ] + `) + + expect(onQuery.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + duration: 0, + params: [0], + query: SELECT "public"."User"."id" FROM "public"."User" WHERE 1=1 OFFSET $1, + target: quaint::connector::metrics, + timestamp: 1970-01-01T00:00:00.000Z, + }, + ], + ] + `) +}) diff --git a/packages/client/src/__tests__/integration/happy/logging/library.ts b/packages/client/src/__tests__/integration/happy/logging/library.ts new file mode 100644 index 000000000000..e796b2c24918 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/logging/library.ts @@ -0,0 +1,76 @@ +import { getClientEngineType } from '@prisma/sdk' +import path from 'path' + +import { getTestClient } from '../../../../utils/getTestClient' +import { tearDownPostgres } from '../../../../utils/setupPostgres' +import { migrateDb } from '../../__helpers__/migrateDb' +import { replaceTimeValues } from './__helpers__/replaceTimeValues' + +beforeEach(async () => { + process.env.TEST_POSTGRES_URI += '-logging-library' + await tearDownPostgres(process.env.TEST_POSTGRES_URI!) + await migrateDb({ + connectionString: process.env.TEST_POSTGRES_URI!, + schemaPath: path.join(__dirname, 'schema.prisma'), + }) +}) + +test('basic event logging - library', async () => { + if (getClientEngineType() !== 'library') { + return + } + + const PrismaClient = await getTestClient() + + const prisma = new PrismaClient({ + log: [ + { + emit: 'event', + level: 'info', + }, + { + emit: 'event', + level: 'query', + }, + ], + }) + + const onInfo = jest.fn() + const onQuery = jest.fn() + + prisma.$on('info', onInfo) + prisma.$on('query', onQuery) + + await prisma.user.findMany() + + await prisma.$disconnect() + + replaceTimeValues(onInfo) + replaceTimeValues(onQuery) + + expect(onInfo.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + message: Starting a postgresql pool with XX connections., + target: quaint::pooled, + timestamp: 1970-01-01T00:00:00.000Z, + }, + ], + ] + `) + + expect(onQuery.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + duration: 0, + params: [0], + query: SELECT "public"."User"."id" FROM "public"."User" WHERE 1=1 OFFSET $1, + target: quaint::connector::metrics, + timestamp: 1970-01-01T00:00:00.000Z, + }, + ], + ] + `) +}) diff --git a/packages/client/src/__tests__/integration/happy/logging/schema.prisma b/packages/client/src/__tests__/integration/happy/logging/schema.prisma new file mode 100644 index 000000000000..7a76545d2a7b --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/logging/schema.prisma @@ -0,0 +1,12 @@ +datasource db { + provider = "postgres" + url = env("TEST_POSTGRES_URI") +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id String @id @default(uuid()) +} diff --git a/packages/client/src/__tests__/integration/happy/uds/.gitignore b/packages/client/src/__tests__/integration/happy/modify-client/.gitignore similarity index 100% rename from packages/client/src/__tests__/integration/happy/uds/.gitignore rename to packages/client/src/__tests__/integration/happy/modify-client/.gitignore diff --git a/packages/client/src/__tests__/integration/happy/uds/dev.db b/packages/client/src/__tests__/integration/happy/modify-client/dev.db similarity index 91% rename from packages/client/src/__tests__/integration/happy/uds/dev.db rename to packages/client/src/__tests__/integration/happy/modify-client/dev.db index c2fc096df547..8d4aac3739ae 100644 Binary files a/packages/client/src/__tests__/integration/happy/uds/dev.db and b/packages/client/src/__tests__/integration/happy/modify-client/dev.db differ diff --git a/packages/client/src/__tests__/integration/happy/uds/schema.prisma b/packages/client/src/__tests__/integration/happy/modify-client/schema.prisma similarity index 100% rename from packages/client/src/__tests__/integration/happy/uds/schema.prisma rename to packages/client/src/__tests__/integration/happy/modify-client/schema.prisma diff --git a/packages/client/src/__tests__/integration/happy/modify-client/test.ts b/packages/client/src/__tests__/integration/happy/modify-client/test.ts new file mode 100644 index 000000000000..2f0ded75f52a --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/modify-client/test.ts @@ -0,0 +1,89 @@ +import { getTestClient } from '../../../../utils/getTestClient' + +let prisma, PrismaClient +describe('modify-client', () => { + test('override method', async () => { + prisma.user.findMany = () => ['override'] + const users = await prisma.user.findMany() + + expect(users).toMatchInlineSnapshot(` + Array [ + override, + ] + `) + }) + + test('override model', () => { + prisma.profile = ['override'] + + expect(prisma.profile).toMatchInlineSnapshot(` + Array [ + override, + ] + `) + }) + + test('class extends', async () => { + class ExtendedClient extends PrismaClient { + prop = 'a value' + } + const client = new ExtendedClient() + const users = await client.user.findMany() + client.prop = 'another value' + + expect(users).toMatchInlineSnapshot(`Array []`) + expect(client.prop).toMatchInlineSnapshot(`another value`) + + await client.$disconnect() + }) + + test('class extends keys', async () => { + class ExtendedClient extends PrismaClient { + prop = 'a value' + } + const client = new ExtendedClient() + client.prop2 = 'another value' + + expect(Object.keys(client).filter((k) => !k.startsWith('_'))).toMatchInlineSnapshot(` + Array [ + user, + profile, + post, + prop, + prop2, + ] + `) + + await client.$disconnect() + }) + + test('class extends override', async () => { + class ExtendedClient extends PrismaClient { + $connect() { + return ['override'] + } + } + const client = new ExtendedClient() + + expect(client.$connect()).toMatchInlineSnapshot(` + Array [ + override, + ] + `) + + await client.$disconnect() + }) + + beforeAll(async () => { + PrismaClient = await getTestClient() + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.user.deleteMany() + }) + + afterAll(async () => { + await prisma.$disconnect() + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/mysql-binary-id/test.ts b/packages/client/src/__tests__/integration/happy/mysql-binary-id/test.ts index c0fff57d4470..4badcffe53ed 100644 --- a/packages/client/src/__tests__/integration/happy/mysql-binary-id/test.ts +++ b/packages/client/src/__tests__/integration/happy/mysql-binary-id/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/namedConstraints/test.ts b/packages/client/src/__tests__/integration/happy/namedConstraints/test.ts index 87aabeec1f52..9b725d9ac523 100644 --- a/packages/client/src/__tests__/integration/happy/namedConstraints/test.ts +++ b/packages/client/src/__tests__/integration/happy/namedConstraints/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/native-types-mysql/test.ts b/packages/client/src/__tests__/integration/happy/native-types-mysql/test.ts index 1f7b544368d5..731d070eb1ee 100644 --- a/packages/client/src/__tests__/integration/happy/native-types-mysql/test.ts +++ b/packages/client/src/__tests__/integration/happy/native-types-mysql/test.ts @@ -1,5 +1,6 @@ import Decimal from 'decimal.js' import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/native-types-postgres/test.ts b/packages/client/src/__tests__/integration/happy/native-types-postgres/test.ts index 6c7060ff7bfc..49c7f665beda 100644 --- a/packages/client/src/__tests__/integration/happy/native-types-postgres/test.ts +++ b/packages/client/src/__tests__/integration/happy/native-types-postgres/test.ts @@ -1,5 +1,6 @@ import Decimal from 'decimal.js' import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/postgres-json-list/test.ts b/packages/client/src/__tests__/integration/happy/postgres-json-list/test.ts index fe19f739c622..cc61176fbad6 100644 --- a/packages/client/src/__tests__/integration/happy/postgres-json-list/test.ts +++ b/packages/client/src/__tests__/integration/happy/postgres-json-list/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/prisma-promises/test.ts b/packages/client/src/__tests__/integration/happy/prisma-promises/test.ts index e28f1745b073..918df019d2d1 100644 --- a/packages/client/src/__tests__/integration/happy/prisma-promises/test.ts +++ b/packages/client/src/__tests__/integration/happy/prisma-promises/test.ts @@ -1,4 +1,5 @@ import { getTestClient } from '../../../../utils/getTestClient' + describe('prisma promises', () => { /** * Requests must get sent if we call `.catch` diff --git a/packages/client/src/__tests__/integration/happy/prismaPromise/.gitignore b/packages/client/src/__tests__/integration/happy/prismaPromise/.gitignore new file mode 100644 index 000000000000..97952752a72b --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/prismaPromise/.gitignore @@ -0,0 +1 @@ +!dev.db \ No newline at end of file diff --git a/packages/client/src/__tests__/integration/happy/prismaPromise/dev.db b/packages/client/src/__tests__/integration/happy/prismaPromise/dev.db new file mode 100644 index 000000000000..09b6082e5a81 Binary files /dev/null and b/packages/client/src/__tests__/integration/happy/prismaPromise/dev.db differ diff --git a/packages/client/src/__tests__/integration/happy/prismaPromise/schema.prisma b/packages/client/src/__tests__/integration/happy/prismaPromise/schema.prisma new file mode 100644 index 000000000000..469fcd2b3a6a --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/prismaPromise/schema.prisma @@ -0,0 +1,66 @@ +datasource db { + provider = "sqlite" + url = "file:dev.db" +} + +generator client { + provider = "prisma-client-js" + binaryTargets = ["native"] +} + +model User { + id String @id @default(cuid()) + email String @unique + name String? + age Int? + posts Post[] + likes Like[] + property Property? @relation(fields: [propertyId], references: [id]) + propertyId String? + Banking Banking? +} + +model Property { + id String @id @default(cuid()) + house House @relation(fields: [houseId], references: [id]) + users User[] + houseId String +} + +model House { + id String @id @default(cuid()) + like Like @relation(fields: [likeId], references: [id]) + properties Property[] + likeId String +} + +model Post { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + published Boolean + title String + content String? + authorId String? + author User? @relation(fields: [authorId], references: [id]) + Like Like[] +} + +model Like { + id String @id @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id]) + postId String + post Post @relation(fields: [postId], references: [id]) + + House House[] + @@unique([userId, postId]) +} + +model Banking { + id String @id @default(cuid()) + userId String + user User? @relation(fields: [userId], references: [id]) + iban String + bic String +} \ No newline at end of file diff --git a/packages/client/src/__tests__/integration/happy/prismaPromise/test.ts b/packages/client/src/__tests__/integration/happy/prismaPromise/test.ts new file mode 100644 index 000000000000..1e3805afe672 --- /dev/null +++ b/packages/client/src/__tests__/integration/happy/prismaPromise/test.ts @@ -0,0 +1,101 @@ +import { getTestClient } from '../../../../utils/getTestClient' + +let prisma +describe('prismaPromise', () => { + test('repeated calls to .then', async () => { + const createPromise = prisma.user.create({ + data: { + email: 'email@email.em', + }, + }) + + // repeated calls to then should not change the result + const createResult1 = await createPromise.then() + const createResult2 = await createPromise.then() + + expect(createResult1).toStrictEqual(createResult2) + }) + + test('repeated calls to .catch', async () => { + const createPromise = prisma.user.create({ + data: { + email: 'email@email.em', + }, + }) + + // repeated calls to catch should not change the result + const createResult1 = await createPromise.catch() + const createResult2 = await createPromise.catch() + + expect(createResult1).toStrictEqual(createResult2) + }) + + test('repeated calls to .finally', async () => { + const createPromise = prisma.user.create({ + data: { + email: 'email@email.em', + }, + }) + + // repeated calls to finally should not change the result + const createResult1 = await createPromise.finally() + const createResult2 = await createPromise.finally() + + expect(createResult1).toStrictEqual(createResult2) + }) + + test('repeated mixed calls to .then, .catch, .finally', async () => { + const createPromise = prisma.user.create({ + data: { + email: 'email@email.em', + }, + }) + + // repeated calls to then & co should not change the result + const createResult1 = await createPromise.finally().then().catch() + const createResult2 = await createPromise.catch().finally().then() + + expect(createResult1).toStrictEqual(createResult2) + }) + + test('repeated calls to .requestTransaction', async () => { + const createPromise = prisma.user.create({ + data: { + email: 'email@email.em', + }, + }) + + // repeated calls to then & co should not change the result + const createResult1 = await createPromise.requestTransaction(1) + const createResult2 = await createPromise.requestTransaction(1) + + expect(createResult1).toStrictEqual(createResult2) + }) + + test('fluent promises should have promise properties', async () => { + const findUniquePromise = prisma.user.findUnique({ + where: { + email: 'email@email.em', + }, + }) + + expect('then' in findUniquePromise).toBe(true) + expect('finally' in findUniquePromise).toBe(true) + expect('catch' in findUniquePromise).toBe(true) + + await findUniquePromise.finally() + }) + + beforeAll(async () => { + const PrismaClient = await getTestClient() + prisma = new PrismaClient() + }) + + beforeEach(async () => { + await prisma.user.deleteMany() + }) + + afterAll(async () => { + await prisma.$disconnect() + }) +}) diff --git a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-mysql/test.ts b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-mysql/test.ts index 4eb59f3281e1..ac282bb28c14 100644 --- a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-mysql/test.ts +++ b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-mysql/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownMysql } from '../../../../utils/setupMysql' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-postgresql/test.ts b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-postgresql/test.ts index 8386dcb376a7..9296d088afa6 100644 --- a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-postgresql/test.ts +++ b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-postgresql/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlite/test.ts b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlite/test.ts index f56d3df2994a..3752ca2322a9 100644 --- a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlite/test.ts +++ b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlite/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlserver/test.ts b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlserver/test.ts index 43cdbb9343b3..5bbfe2694e4e 100644 --- a/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlserver/test.ts +++ b/packages/client/src/__tests__/integration/happy/referentialActions-onDelete-cascade-sqlserver/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { generateTestClient } from '../../../../utils/getTestClient' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/rejectNotFound/test.ts b/packages/client/src/__tests__/integration/happy/rejectNotFound/test.ts index abb0bf419eb2..1f3b5179a015 100644 --- a/packages/client/src/__tests__/integration/happy/rejectNotFound/test.ts +++ b/packages/client/src/__tests__/integration/happy/rejectNotFound/test.ts @@ -1,4 +1,5 @@ import { getTestClient } from '../../../../utils/getTestClient' + const cases = { constructor: { customError: () => new Error('Constructor Custom Error'), diff --git a/packages/client/src/__tests__/integration/happy/restart/test.ts b/packages/client/src/__tests__/integration/happy/restart/test.ts index ec1d68f30349..3cff5f55ee79 100644 --- a/packages/client/src/__tests__/integration/happy/restart/test.ts +++ b/packages/client/src/__tests__/integration/happy/restart/test.ts @@ -1,4 +1,5 @@ import { ClientEngineType, getClientEngineType } from '@prisma/sdk' + import { getTestClient } from '../../../../utils/getTestClient' // Does Prisma Client restart the QE when it is killed for some reason? diff --git a/packages/client/src/__tests__/integration/happy/scalar-list/test.ts b/packages/client/src/__tests__/integration/happy/scalar-list/test.ts index d6038516094e..c835e98b0abe 100644 --- a/packages/client/src/__tests__/integration/happy/scalar-list/test.ts +++ b/packages/client/src/__tests__/integration/happy/scalar-list/test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getTestClient } from '../../../../utils/getTestClient' import { tearDownPostgres } from '../../../../utils/setupPostgres' import { migrateDb } from '../../__helpers__/migrateDb' diff --git a/packages/client/src/__tests__/integration/happy/signals/test.ts b/packages/client/src/__tests__/integration/happy/signals/test.ts index e25dc39476f0..ef6249537f0a 100644 --- a/packages/client/src/__tests__/integration/happy/signals/test.ts +++ b/packages/client/src/__tests__/integration/happy/signals/test.ts @@ -2,6 +2,7 @@ import events from 'events' import type { ExecaChildProcess } from 'execa' import execa from 'execa' import path from 'path' + import { EXIT_MESSAGE, READY_MESSAGE } from './__helpers__/constants' const testIf = (condition: boolean) => (condition ? test : test.skip) diff --git a/packages/client/src/__tests__/integration/happy/sqlite-variable-limit/test.ts b/packages/client/src/__tests__/integration/happy/sqlite-variable-limit/test.ts index f1c758d5ea79..e9c1dbe3f2b0 100644 --- a/packages/client/src/__tests__/integration/happy/sqlite-variable-limit/test.ts +++ b/packages/client/src/__tests__/integration/happy/sqlite-variable-limit/test.ts @@ -1,8 +1,9 @@ // const pMap = require('p-map') +import { getTestClient } from '../../../../utils/getTestClient' + const zlib = require('zlib') const fs = require('fs') const path = require('path') -import { getTestClient } from '../../../../utils/getTestClient' jest.setTimeout(50000) diff --git a/packages/client/src/__tests__/integration/happy/transaction/test.ts b/packages/client/src/__tests__/integration/happy/transaction/test.ts index f9f3afae5240..12b16e7d90c2 100644 --- a/packages/client/src/__tests__/integration/happy/transaction/test.ts +++ b/packages/client/src/__tests__/integration/happy/transaction/test.ts @@ -43,6 +43,7 @@ test('transaction', async () => { }, }), db.user.findMany(), + db.user.count(), db.user.delete({ where: { email: 'test@hey.com' } }), ]) expect(clean(result)).toMatchInlineSnapshot(` @@ -71,6 +72,7 @@ test('transaction', async () => { name: null, }, ], + 2, Object { email: test@hey.com, id: REMOVED, diff --git a/packages/client/src/__tests__/integration/happy/uds/package.json b/packages/client/src/__tests__/integration/happy/uds/package.json deleted file mode 100644 index b6f763d66294..000000000000 --- a/packages/client/src/__tests__/integration/happy/uds/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "uds", - "version": "0.0.0" -} diff --git a/packages/client/src/__tests__/integration/happy/uds/test.ts b/packages/client/src/__tests__/integration/happy/uds/test.ts deleted file mode 100644 index dc7e315aefd7..000000000000 --- a/packages/client/src/__tests__/integration/happy/uds/test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { generateTestClient } from '../../../../utils/getTestClient' - -const testIf = (condition: boolean) => (condition ? test : test.skip) - -const udsSupportedByOperatingSystem = process.platform !== 'win32' - -testIf(udsSupportedByOperatingSystem)('blog', async () => { - await generateTestClient() - - const { PrismaClient, Prisma } = require('./node_modules/@prisma/client') - - const { prismaVersion, sql, raw, join, empty, PrismaClientValidationError, PrismaClientKnownRequestError } = Prisma - - const requests: any[] = [] - const db = new PrismaClient({ - __internal: { - useUds: true, - hooks: { - beforeRequest: (request) => requests.push(request), - }, - }, - } as any) - - if (!prismaVersion || !prismaVersion.client) { - throw new Error(`prismaVersion missing: ${JSON.stringify(prismaVersion)}`) - } - - // Test connecting and disconnecting all the time - await db.user.findMany() - const posts = await db.user - .findUnique({ - where: { - email: 'a@a.de', - }, - }) - .posts() - - expect(posts.length).toBe(0) - db.$disconnect() - expect(requests.length).toBe(2) - - await db.user.findMany() - db.$disconnect() - expect(requests.length).toBe(3) - - const count = await db.user.count() - expect(typeof count === 'number').toBe(true) - - const paramCount = await db.user.count({ - take: 10000, - }) - - expect(typeof paramCount === 'number').toBe(true) - - db.$connect() - await db.$disconnect() - - await new Promise((r) => setTimeout(r, 200)) - db.$connect() - - const userPromise = db.user.findMany() - await userPromise - // @ts-ignore - - await db.$disconnect() - - await db.$connect() - - /** - * queryRaw - */ - - // Test queryRaw(string) - const rawQuery = await db.$queryRawUnsafe('SELECT 1') - expect(rawQuery[0]['1']).toBe(1) - - // Test queryRaw(string, values) - const rawQueryWithValues = await db.$queryRawUnsafe('SELECT $1 AS name, $2 AS id', 'Alice', 42) - - expect(rawQueryWithValues[0]).toEqual({ - name: 'Alice', - id: 42, - }) - - // Test queryRaw`` - const rawQueryTemplate = await db.$queryRaw`SELECT 1` - expect(rawQueryTemplate[0]['1']).toBe(1) - - // Test queryRaw`` with ${param} - const rawQueryTemplateWithParams = await db.$queryRaw`SELECT * FROM User WHERE name = ${'Alice'}` - expect(rawQueryTemplateWithParams[0].name).toBe('Alice') - - // Test queryRaw`` with prisma.sql`` - const rawQueryTemplateFromSqlTemplate = await db.$queryRaw( - sql` - SELECT ${join([raw('email'), raw('id'), raw('name')])} - FROM ${raw('User')} - ${sql`WHERE name = ${'Alice'}`} - ${empty} - `, - ) - expect(rawQueryTemplateFromSqlTemplate[0].name).toBe('Alice') - - /** - * .$executeRaw( - */ - - // Test .$executeRaw((string) - const executeRaw = await db.$executeRawUnsafe('UPDATE User SET name = $1 WHERE id = $2', 'name', 'id') - expect(executeRaw).toBe(0) - - // Test .$executeRaw((string, values) - const executeRawWithValues = await db.$executeRawUnsafe('UPDATE User SET name = $1 WHERE id = $2', 'Alice', 'id') - expect(executeRawWithValues).toBe(0) - - // Test $executeRaw - const $executeRawTemplate = await db.$executeRaw`UPDATE User SET name = ${'name'} WHERE id = ${'id'}` - expect($executeRawTemplate).toBe(0) - - // Test validation errors - let validationError - try { - await db.post.create({ - data: {}, - }) - } catch (e) { - validationError = e - } - if (!validationError || !(validationError instanceof PrismaClientValidationError)) { - throw new Error(`Validation error is incorrect`) - } - - // Test known request error - let knownRequestError - try { - await db.user.create({ - data: { - email: 'a@a.de', - name: 'Alice', - }, - }) - } catch (e) { - knownRequestError = e - } - if (!knownRequestError || !(knownRequestError instanceof PrismaClientKnownRequestError)) { - throw new Error(`Known request error is incorrect`) - } else { - if (!knownRequestError.message.includes('.user.create()')) { - throw new Error(`Invalid error: ${knownRequestError.message}`) - } - } - - // relation query where not null - const relationWhereNotNull = await db.user.findMany({ - where: { - profile: { - bio: { not: null }, - }, - }, - }) - expect(relationWhereNotNull).toEqual([]) - - db.$disconnect() -}) diff --git a/packages/client/src/__tests__/integration/happy/uncheckedScalarInputs/test.ts b/packages/client/src/__tests__/integration/happy/uncheckedScalarInputs/test.ts index f8c5c337d688..d978cfd18b5c 100644 --- a/packages/client/src/__tests__/integration/happy/uncheckedScalarInputs/test.ts +++ b/packages/client/src/__tests__/integration/happy/uncheckedScalarInputs/test.ts @@ -1,7 +1,9 @@ import fs from 'fs' import path from 'path' import { promisify } from 'util' + import { getTestClient } from '../../../../utils/getTestClient' + const copyFile = promisify(fs.copyFile) test('uncheckedScalarInputs', async () => { diff --git a/packages/client/src/__tests__/json.test.ts b/packages/client/src/__tests__/json.test.ts index 182fc7f2af98..ff6b15c4c74b 100644 --- a/packages/client/src/__tests__/json.test.ts +++ b/packages/client/src/__tests__/json.test.ts @@ -1,5 +1,6 @@ -import { getDMMF } from '../generation/getDMMF' import chalk from 'chalk' + +import { getDMMF } from '../generation/getDMMF' import { DMMFClass, makeDocument, transformDocument } from '../runtime' const describeIf = (condition: boolean) => (condition ? describe : describe.skip) diff --git a/packages/client/src/__tests__/minimalWhereTransformation.test.ts b/packages/client/src/__tests__/minimalWhereTransformation.test.ts index 3a9105e851be..8d476ea8946c 100644 --- a/packages/client/src/__tests__/minimalWhereTransformation.test.ts +++ b/packages/client/src/__tests__/minimalWhereTransformation.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { blog } from '../fixtures/blog' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 let dmmf @@ -218,7 +220,7 @@ describe('minimal where transformation', () => { title content authorId - optionnal + optional } } } @@ -259,7 +261,7 @@ describe('minimal where transformation', () => { title content authorId - optionnal + optional } } } @@ -290,7 +292,7 @@ describe('minimal where transformation', () => { title content authorId - optionnal + optional } } } diff --git a/packages/client/src/__tests__/optionalRelation.test.ts b/packages/client/src/__tests__/optionalRelation.test.ts index 30b5d5780eba..43027873585d 100644 --- a/packages/client/src/__tests__/optionalRelation.test.ts +++ b/packages/client/src/__tests__/optionalRelation.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { blog } from '../fixtures/blog' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 describe('optional to one relation', () => { @@ -35,7 +37,7 @@ describe('optional to one relation', () => { title content authorId - optionnal + optional } } `) diff --git a/packages/client/src/__tests__/or.test.ts b/packages/client/src/__tests__/or.test.ts index 70e1a9ffb0ce..9e435762ce8a 100644 --- a/packages/client/src/__tests__/or.test.ts +++ b/packages/client/src/__tests__/or.test.ts @@ -1,7 +1,8 @@ import stripAnsi from 'strip-ansi' + import { enums } from '../fixtures/enums' -import { DMMFClass, makeDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument } from '../runtime' describe('at least one validation', () => { let dmmf diff --git a/packages/client/src/__tests__/orderTransformation.test.ts b/packages/client/src/__tests__/orderTransformation.test.ts index 7e0c24069dc2..7114cbf9fb50 100644 --- a/packages/client/src/__tests__/orderTransformation.test.ts +++ b/packages/client/src/__tests__/orderTransformation.test.ts @@ -1,7 +1,8 @@ import stripAnsi from 'strip-ansi' + import { enums } from '../fixtures/enums' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' describe('where transformation', () => { let dmmf diff --git a/packages/client/src/__tests__/relationWhereORNotNullTransformation.test.ts b/packages/client/src/__tests__/relationWhereORNotNullTransformation.test.ts index f101829ab7f8..5340f9b69605 100644 --- a/packages/client/src/__tests__/relationWhereORNotNullTransformation.test.ts +++ b/packages/client/src/__tests__/relationWhereORNotNullTransformation.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { saleBuyers } from '../fixtures/saleBuyers' -import { DMMFClass, makeDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument } from '../runtime' + chalk.level = 0 let dmmf diff --git a/packages/client/src/__tests__/relationWhereTransformation.test.ts b/packages/client/src/__tests__/relationWhereTransformation.test.ts index 1af636535c54..021eb1c47df6 100644 --- a/packages/client/src/__tests__/relationWhereTransformation.test.ts +++ b/packages/client/src/__tests__/relationWhereTransformation.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { chinook } from '../fixtures/chinook' -import { DMMFClass, makeDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument } from '../runtime' + chalk.level = 0 describe('relation where transformation', () => { diff --git a/packages/client/src/__tests__/resolveDatasources.test.ts b/packages/client/src/__tests__/resolveDatasources.test.ts index 42f00b6a85d1..60be4898e461 100644 --- a/packages/client/src/__tests__/resolveDatasources.test.ts +++ b/packages/client/src/__tests__/resolveDatasources.test.ts @@ -1,4 +1,5 @@ import type { DataSource } from '@prisma/generator-helper' + import { datasourceToDatasourceOverwrite, serializeDatasources } from '../generation/serializeDatasources' import { absolutizeRelativePath } from '../utils/resolveDatasources' diff --git a/packages/client/src/__tests__/scalarListCreate.test.ts b/packages/client/src/__tests__/scalarListCreate.test.ts index 8f5aa5e5e150..3fe24c0b8564 100644 --- a/packages/client/src/__tests__/scalarListCreate.test.ts +++ b/packages/client/src/__tests__/scalarListCreate.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { enums } from '../fixtures/enums' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 describe('scalar where transformation', () => { diff --git a/packages/client/src/__tests__/scalarWhereTransformation.test.ts b/packages/client/src/__tests__/scalarWhereTransformation.test.ts index f2ecf0af2b7b..964226b05f1e 100644 --- a/packages/client/src/__tests__/scalarWhereTransformation.test.ts +++ b/packages/client/src/__tests__/scalarWhereTransformation.test.ts @@ -1,8 +1,10 @@ -import stripAnsi from 'strip-ansi' import chalk from 'chalk' +import stripAnsi from 'strip-ansi' + import { enums } from '../fixtures/enums' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 describe('scalar where transformation', () => { diff --git a/packages/client/src/__tests__/scripts/postinstall.test.ts b/packages/client/src/__tests__/scripts/postinstall.test.ts index 71572419e0fe..c11d673f02e1 100644 --- a/packages/client/src/__tests__/scripts/postinstall.test.ts +++ b/packages/client/src/__tests__/scripts/postinstall.test.ts @@ -1,13 +1,13 @@ // Prevent postinstall script from running -process.env.PRISMA_SKIP_POSTINSTALL_GENERATE = 'true' - import { getPostInstallTrigger, + UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING, UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_PARSE_ERROR, UNABLE_TO_FIND_POSTINSTALL_TRIGGER_JSON_SCHEMA_ERROR, - UNABLE_TO_FIND_POSTINSTALL_TRIGGER__ENVAR_MISSING, } from '../../../scripts/postinstall' +process.env.PRISMA_SKIP_POSTINSTALL_GENERATE = 'true' + beforeEach(() => { process.env.npm_config_user_agent = 'npm/1.2.3' process.env.npm_config_argv = '{"original":["foo", "bar"]}' diff --git a/packages/client/src/__tests__/select.test.ts b/packages/client/src/__tests__/select.test.ts index d58bb7b032c5..a47b91f3df73 100644 --- a/packages/client/src/__tests__/select.test.ts +++ b/packages/client/src/__tests__/select.test.ts @@ -1,13 +1,14 @@ import stripAnsi from 'strip-ansi' + import { blog } from '../fixtures/blog' import { getDMMF } from '../generation/getDMMF' -import { DMMFClass } from '../runtime/dmmf' +import { DMMFHelper } from '../runtime/dmmf' import { makeDocument } from '../runtime/query' let dmmf beforeAll(async () => { const dmmfDocument = await getDMMF({ datamodel: blog }) - dmmf = new DMMFClass(dmmfDocument) + dmmf = new DMMFHelper(dmmfDocument) }) describe('select validation', () => { diff --git a/packages/client/src/__tests__/serializeRawParameters.test.ts b/packages/client/src/__tests__/serializeRawParameters.test.ts index 663184b3ad47..216db527f21d 100644 --- a/packages/client/src/__tests__/serializeRawParameters.test.ts +++ b/packages/client/src/__tests__/serializeRawParameters.test.ts @@ -1,4 +1,5 @@ import { serializeRawParameters } from '../runtime/utils/serializeRawParameters' + function serializeHelper(data: any) { return JSON.parse(serializeRawParameters(data)) } @@ -11,7 +12,7 @@ describe('serializeRawParemeters', () => { expect(serializeHelper(data)).toMatchInlineSnapshot(` Object { - bigInt: 321804719213721, + bigInt: 202012310000001, date: Object { prisma__type: date, prisma__value: 2020-06-22T17:07:16.348Z, @@ -29,7 +30,7 @@ describe('serializeRawParemeters', () => { expect(serializeHelper(data)).toMatchInlineSnapshot(` Object { bigInt: Array [ - 321804719213721, + 202012310000001, ], date: Array [ Object { @@ -55,7 +56,7 @@ describe('serializeRawParemeters', () => { test('scalar bigInt', () => { const data = BigInt('321804719213721') - expect(serializeHelper(data)).toMatchInlineSnapshot(`321804719213721`) + expect(serializeHelper(data)).toMatchInlineSnapshot(`202012310000001`) }) test('nested', () => { @@ -70,8 +71,8 @@ describe('serializeRawParemeters', () => { Object { deep: Object { bigInt: Array [ - 321804719213721, - 321804719213721, + 202012310000001, + 202012310000001, ], date: Array [ Object { diff --git a/packages/client/src/__tests__/singularRelationWhereTransformation.test.ts b/packages/client/src/__tests__/singularRelationWhereTransformation.test.ts index 5aff26a30c8e..dc5d2e7abcf6 100644 --- a/packages/client/src/__tests__/singularRelationWhereTransformation.test.ts +++ b/packages/client/src/__tests__/singularRelationWhereTransformation.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { singularRelation } from '../fixtures/singularRelation' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 let dmmf diff --git a/packages/client/src/__tests__/types/$transaction/index.test-d.ts b/packages/client/src/__tests__/types/$transaction/index.test-d.ts index e0cb28f26722..40db7d40ee2a 100644 --- a/packages/client/src/__tests__/types/$transaction/index.test-d.ts +++ b/packages/client/src/__tests__/types/$transaction/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { @@ -12,19 +11,10 @@ const prisma = new PrismaClient({ }) ;(async () => { - expectError( - await prisma.$transaction( - [prisma.user.findMany(), prisma.$queryRaw`SELECT 1`, 'random string'], - {}, - ), - ) + expectError(await prisma.$transaction([prisma.user.findMany(), prisma.$queryRaw`SELECT 1`, 'random string'], {})) expectError(await prisma.$transaction([prisma.$connect()])) expectError(await prisma.$transaction([prisma.$disconnect()])) - expectError( - await prisma.$transaction([ - new Promise((res) => res('You Shall Not Pass')), - ]), - ) + expectError(await prisma.$transaction([new Promise((res) => res('You Shall Not Pass'))])) expectError(await prisma.$transaction([5])) expectError(await prisma.$transaction(['str'])) expectError(await prisma.$transaction([{}])) diff --git a/packages/client/src/__tests__/types/$transaction/test.ts b/packages/client/src/__tests__/types/$transaction/test.ts index 32a3260e9385..8134a982d4ac 100644 --- a/packages/client/src/__tests__/types/$transaction/test.ts +++ b/packages/client/src/__tests__/types/$transaction/test.ts @@ -1,6 +1,5 @@ -import { PrismaClient, User } from '@prisma/client' - -// tslint:disable +import type { User } from '@prisma/client' +import { PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/accounts/index.test-d.ts b/packages/client/src/__tests__/types/accounts/index.test-d.ts index 4fd6452067e2..c419a8461ca4 100644 --- a/packages/client/src/__tests__/types/accounts/index.test-d.ts +++ b/packages/client/src/__tests__/types/accounts/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/accounts/test.ts b/packages/client/src/__tests__/types/accounts/test.ts index 84de839a0b54..e32fed40b93f 100644 --- a/packages/client/src/__tests__/types/accounts/test.ts +++ b/packages/client/src/__tests__/types/accounts/test.ts @@ -1,6 +1,5 @@ -import { AccountData, PrismaClient, RandomModel } from '@prisma/client' - -// tslint:disable +import type { AccountData, RandomModel } from '@prisma/client' +import { PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/aggregate/index.test-d.ts b/packages/client/src/__tests__/types/aggregate/index.test-d.ts index 7c2b58c8bf98..c6c78f6251eb 100644 --- a/packages/client/src/__tests__/types/aggregate/index.test-d.ts +++ b/packages/client/src/__tests__/types/aggregate/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/aggregate/test.ts b/packages/client/src/__tests__/types/aggregate/test.ts index 88c3111756f7..28036da4ed65 100644 --- a/packages/client/src/__tests__/types/aggregate/test.ts +++ b/packages/client/src/__tests__/types/aggregate/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/blog/index.test-d.ts b/packages/client/src/__tests__/types/blog/index.test-d.ts index 9cbb79957893..54eee641926c 100644 --- a/packages/client/src/__tests__/types/blog/index.test-d.ts +++ b/packages/client/src/__tests__/types/blog/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/blog/test.ts b/packages/client/src/__tests__/types/blog/test.ts index 4bcc98bf6906..94212a407f7f 100644 --- a/packages/client/src/__tests__/types/blog/test.ts +++ b/packages/client/src/__tests__/types/blog/test.ts @@ -1,6 +1,5 @@ -import { Post, Prisma, PrismaClient, User } from '@prisma/client' - -// tslint:disable +import type { Post, User } from '@prisma/client' +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/chaining/index.d.ts b/packages/client/src/__tests__/types/chaining/index.d.ts new file mode 100644 index 000000000000..fe9905a9d640 --- /dev/null +++ b/packages/client/src/__tests__/types/chaining/index.d.ts @@ -0,0 +1 @@ +export { PrismaClient, User } from '@prisma/client' diff --git a/packages/client/src/__tests__/types/chaining/index.test-d.ts b/packages/client/src/__tests__/types/chaining/index.test-d.ts new file mode 100644 index 000000000000..a5cd7eb32f3d --- /dev/null +++ b/packages/client/src/__tests__/types/chaining/index.test-d.ts @@ -0,0 +1,24 @@ +import { PrismaClient, User } from '.' +import { expectError } from 'tsd' + +const prisma = new PrismaClient() + +;(async () => { + expectError( + await prisma.user.findFirst().posts({ + extraField: {}, + }), + ) + + // Can't use select and include at the same time + expectError(async () => { + let author: User = await prisma.post.findFirst().author({ + select: { + name: true, + }, + include: { + posts: true, + }, + }) + }) +})() diff --git a/packages/client/src/__tests__/types/chaining/schema.prisma b/packages/client/src/__tests__/types/chaining/schema.prisma new file mode 100644 index 000000000000..b98d50b535fd --- /dev/null +++ b/packages/client/src/__tests__/types/chaining/schema.prisma @@ -0,0 +1,27 @@ +datasource db { + provider = "postgres" + url = env("TEST_POSTGRES_URI") +} + +generator client { + provider = "prisma-client-js" + output = "@prisma/client" +} + +model User { + id String @id @default(uuid()) + email String @unique + name String? + posts Post[] +} + +model Post { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + published Boolean + title String + content String? + authorId String? + author User? @relation(fields: [authorId], references: [id]) +} diff --git a/packages/client/src/__tests__/types/chaining/test.ts b/packages/client/src/__tests__/types/chaining/test.ts new file mode 100644 index 000000000000..23ce10cf4554 --- /dev/null +++ b/packages/client/src/__tests__/types/chaining/test.ts @@ -0,0 +1,23 @@ +import { PrismaClient } from '@prisma/client' + +async function main() { + const prisma = new PrismaClient() + + await prisma.user.findFirst().posts() + + await prisma.user.findFirst().posts({ + where: { + published: true, + }, + }) + + await prisma.post.findFirst().author() + + await prisma.post.findFirst().author({ + select: { + email: true, + }, + }) +} + +main().catch(console.error) diff --git a/packages/client/src/__tests__/types/chaining/tsconfig.json b/packages/client/src/__tests__/types/chaining/tsconfig.json new file mode 100644 index 000000000000..3a56b3b24fe1 --- /dev/null +++ b/packages/client/src/__tests__/types/chaining/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es2018", + "module": "commonjs", + "strict": true, + "esModuleInterop": true + } +} diff --git a/packages/client/src/__tests__/types/connectOrCreate/index.test-d.ts b/packages/client/src/__tests__/types/connectOrCreate/index.test-d.ts index 5bf84da4ceb8..44bd47ea71a7 100644 --- a/packages/client/src/__tests__/types/connectOrCreate/index.test-d.ts +++ b/packages/client/src/__tests__/types/connectOrCreate/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/connectOrCreate/test.ts b/packages/client/src/__tests__/types/connectOrCreate/test.ts index b036086eb8a9..6e9cddfd99c2 100644 --- a/packages/client/src/__tests__/types/connectOrCreate/test.ts +++ b/packages/client/src/__tests__/types/connectOrCreate/test.ts @@ -1,15 +1,11 @@ -import { PrismaClient, Prisma } from '@prisma/client' - -// tslint:disable +import type { Prisma } from '@prisma/client' +import { PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() - type Check = - 'connectOrCreate' extends keyof Prisma.UserCreateNestedOneWithoutPostsInput - ? number - : string + type Check = 'connectOrCreate' extends keyof Prisma.UserCreateNestedOneWithoutPostsInput ? number : string const str: Check = 12345 } diff --git a/packages/client/src/__tests__/types/count/index.test-d.ts b/packages/client/src/__tests__/types/count/index.test-d.ts index 6be67d2fc8ee..557140c2d181 100644 --- a/packages/client/src/__tests__/types/count/index.test-d.ts +++ b/packages/client/src/__tests__/types/count/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/count/test.ts b/packages/client/src/__tests__/types/count/test.ts index 970947f6b954..bdf87ab53c05 100644 --- a/packages/client/src/__tests__/types/count/test.ts +++ b/packages/client/src/__tests__/types/count/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/createMany/index.test-d.ts b/packages/client/src/__tests__/types/createMany/index.test-d.ts index 1ee3a8a6b097..aea6638ccff8 100644 --- a/packages/client/src/__tests__/types/createMany/index.test-d.ts +++ b/packages/client/src/__tests__/types/createMany/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/createMany/test.ts b/packages/client/src/__tests__/types/createMany/test.ts index bca011e8901e..6fc0b5f1083c 100644 --- a/packages/client/src/__tests__/types/createMany/test.ts +++ b/packages/client/src/__tests__/types/createMany/test.ts @@ -1,7 +1,5 @@ import { PrismaClient, user } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/deleteMany/index.test-d.ts b/packages/client/src/__tests__/types/deleteMany/index.test-d.ts index a5a673c11283..5129dad14a28 100644 --- a/packages/client/src/__tests__/types/deleteMany/index.test-d.ts +++ b/packages/client/src/__tests__/types/deleteMany/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/deleteMany/test.ts b/packages/client/src/__tests__/types/deleteMany/test.ts index aed354d6e9b3..e53c2a70c819 100644 --- a/packages/client/src/__tests__/types/deleteMany/test.ts +++ b/packages/client/src/__tests__/types/deleteMany/test.ts @@ -1,7 +1,5 @@ import { PrismaClient, user } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/deprecation/test.ts b/packages/client/src/__tests__/types/deprecation/test.ts index ef6403bf161d..a500ba7ecbc3 100644 --- a/packages/client/src/__tests__/types/deprecation/test.ts +++ b/packages/client/src/__tests__/types/deprecation/test.ts @@ -1,6 +1,5 @@ -import { Post, Prisma, PrismaClient, User } from '@prisma/client' - -// tslint:disable +import type { Post, User } from '@prisma/client' +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/distinct/index.test-d.ts b/packages/client/src/__tests__/types/distinct/index.test-d.ts index ab5b275552f4..599f49f2a19c 100644 --- a/packages/client/src/__tests__/types/distinct/index.test-d.ts +++ b/packages/client/src/__tests__/types/distinct/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/distinct/test.ts b/packages/client/src/__tests__/types/distinct/test.ts index 8d0be6a090be..7e8c698199e2 100644 --- a/packages/client/src/__tests__/types/distinct/test.ts +++ b/packages/client/src/__tests__/types/distinct/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/findFirst/index.test-d.ts b/packages/client/src/__tests__/types/findFirst/index.test-d.ts index 46018dff84da..ed5020d2ed94 100644 --- a/packages/client/src/__tests__/types/findFirst/index.test-d.ts +++ b/packages/client/src/__tests__/types/findFirst/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/findFirst/test.ts b/packages/client/src/__tests__/types/findFirst/test.ts index 514a8dec44cb..7b1b9a5ecf2b 100644 --- a/packages/client/src/__tests__/types/findFirst/test.ts +++ b/packages/client/src/__tests__/types/findFirst/test.ts @@ -1,6 +1,5 @@ -import { PrismaClient, user } from '@prisma/client' - -// tslint:disable +import type { user } from '@prisma/client' +import { PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/groupBy/index.test-d.ts b/packages/client/src/__tests__/types/groupBy/index.test-d.ts index 3fb8d14bcf24..d80312d13a0a 100644 --- a/packages/client/src/__tests__/types/groupBy/index.test-d.ts +++ b/packages/client/src/__tests__/types/groupBy/index.test-d.ts @@ -1,7 +1,6 @@ import { expectError } from 'tsd' -import { PrismaClient } from '.' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/groupBy/test.ts b/packages/client/src/__tests__/types/groupBy/test.ts index 8e5d6a7babfa..1d044d71d4e2 100644 --- a/packages/client/src/__tests__/types/groupBy/test.ts +++ b/packages/client/src/__tests__/types/groupBy/test.ts @@ -1,8 +1,6 @@ import { PrismaClient } from '@prisma/client' import { expectType } from 'tsd' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/ignore/test.ts b/packages/client/src/__tests__/types/ignore/test.ts index 4cbc7413e262..55017a812d71 100644 --- a/packages/client/src/__tests__/types/ignore/test.ts +++ b/packages/client/src/__tests__/types/ignore/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // just make sure the client types compile async function main() { const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/imports/test.ts b/packages/client/src/__tests__/types/imports/test.ts index 1bc92ecd9bc8..86da11e12f12 100644 --- a/packages/client/src/__tests__/types/imports/test.ts +++ b/packages/client/src/__tests__/types/imports/test.ts @@ -1,6 +1,4 @@ -import { PrismaClient, Prisma } from '@prisma/client' - -// tslint:disable +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/json-filtering-mysql/index.test-d.ts b/packages/client/src/__tests__/types/json-filtering-mysql/index.test-d.ts index a72cdf0cb143..b95bc9b51ae1 100644 --- a/packages/client/src/__tests__/types/json-filtering-mysql/index.test-d.ts +++ b/packages/client/src/__tests__/types/json-filtering-mysql/index.test-d.ts @@ -1,4 +1,5 @@ import { expectError } from 'tsd' + import { PrismaClient } from '.' const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/json-filtering-mysql/test.ts b/packages/client/src/__tests__/types/json-filtering-mysql/test.ts index 945a20410ae1..63c2e4119d1f 100644 --- a/packages/client/src/__tests__/types/json-filtering-mysql/test.ts +++ b/packages/client/src/__tests__/types/json-filtering-mysql/test.ts @@ -1,4 +1,4 @@ -import { PrismaClient, Prisma } from '@prisma/client' +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/json-filtering-postgres/index.test-d.ts b/packages/client/src/__tests__/types/json-filtering-postgres/index.test-d.ts index 152c8f5e870c..a4c11e2a1633 100644 --- a/packages/client/src/__tests__/types/json-filtering-postgres/index.test-d.ts +++ b/packages/client/src/__tests__/types/json-filtering-postgres/index.test-d.ts @@ -1,4 +1,5 @@ import { expectError } from 'tsd' + import { PrismaClient } from '.' const prisma = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/json-filtering-postgres/test.ts b/packages/client/src/__tests__/types/json-filtering-postgres/test.ts index bd2eee5cee5c..d1059f595876 100644 --- a/packages/client/src/__tests__/types/json-filtering-postgres/test.ts +++ b/packages/client/src/__tests__/types/json-filtering-postgres/test.ts @@ -1,4 +1,4 @@ -import { PrismaClient, Prisma } from '@prisma/client' +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/json/index.test-d.ts b/packages/client/src/__tests__/types/json/index.test-d.ts index 10a14fab2ae1..4d647697fed0 100644 --- a/packages/client/src/__tests__/types/json/index.test-d.ts +++ b/packages/client/src/__tests__/types/json/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/json/test.ts b/packages/client/src/__tests__/types/json/test.ts index 9c4f87271002..acbfa6dc1562 100644 --- a/packages/client/src/__tests__/types/json/test.ts +++ b/packages/client/src/__tests__/types/json/test.ts @@ -1,6 +1,4 @@ -import { PrismaClient, Prisma } from '@prisma/client' - -// tslint:disable +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/types/middlewares/index.test-d.ts b/packages/client/src/__tests__/types/middlewares/index.test-d.ts index f745ecafa8ac..4c20afe5aa48 100644 --- a/packages/client/src/__tests__/types/middlewares/index.test-d.ts +++ b/packages/client/src/__tests__/types/middlewares/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/middlewares/test.ts b/packages/client/src/__tests__/types/middlewares/test.ts index 1a1e6cd20ae0..e44d96629ab5 100644 --- a/packages/client/src/__tests__/types/middlewares/test.ts +++ b/packages/client/src/__tests__/types/middlewares/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/namedConstraints/test.ts b/packages/client/src/__tests__/types/namedConstraints/test.ts index d65a2b7f306a..e58346c9fc1a 100644 --- a/packages/client/src/__tests__/types/namedConstraints/test.ts +++ b/packages/client/src/__tests__/types/namedConstraints/test.ts @@ -1,30 +1,26 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() // @@id - const result: { key1: string; key2: number } | null = - await prisma.atAtIdNamed.findUnique({ - where: { - namedConstraintId: { - key1: 'data', - key2: 2, - }, + const result: { key1: string; key2: number } | null = await prisma.atAtIdNamed.findUnique({ + where: { + namedConstraintId: { + key1: 'data', + key2: 2, }, - }) - const result2: { key1: string; key2: number } | null = - await prisma.atAtId.findUnique({ - where: { - key1_key2: { - key1: 'data', - key2: 2, - }, + }, + }) + const result2: { key1: string; key2: number } | null = await prisma.atAtId.findUnique({ + where: { + key1_key2: { + key1: 'data', + key2: 2, }, - }) + }, + }) // @@unique const result3 = await prisma.atAtUniqueNamed.findUnique({ @@ -35,15 +31,14 @@ async function main() { }, }, }) - const result4: { key1: string; key2: number } | null = - await prisma.atAtUnique.findUnique({ - where: { - key1_key2: { - key1: 'data', - key2: 2, - }, + const result4: { key1: string; key2: number } | null = await prisma.atAtUnique.findUnique({ + where: { + key1_key2: { + key1: 'data', + key2: 2, }, - }) + }, + }) } main().catch((e) => { diff --git a/packages/client/src/__tests__/types/native-types/index.test-d.ts b/packages/client/src/__tests__/types/native-types/index.test-d.ts index a958dab13a10..bb140253f95d 100644 --- a/packages/client/src/__tests__/types/native-types/index.test-d.ts +++ b/packages/client/src/__tests__/types/native-types/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/native-types/test.ts b/packages/client/src/__tests__/types/native-types/test.ts index 4b4f0368ea0f..3c6705c138aa 100644 --- a/packages/client/src/__tests__/types/native-types/test.ts +++ b/packages/client/src/__tests__/types/native-types/test.ts @@ -1,9 +1,9 @@ -import { PrismaClient, Prisma } from '@prisma/client' +import { Prisma, PrismaClient } from '@prisma/client' async function main() { const prisma = new PrismaClient() - const bint: bigint = BigInt(0) + const bint = BigInt(0) const a: null | { id: string diff --git a/packages/client/src/__tests__/types/rejectOnNotFound/index.test-d.ts b/packages/client/src/__tests__/types/rejectOnNotFound/index.test-d.ts index 8e3478b21973..58be307b54fc 100644 --- a/packages/client/src/__tests__/types/rejectOnNotFound/index.test-d.ts +++ b/packages/client/src/__tests__/types/rejectOnNotFound/index.test-d.ts @@ -1,7 +1,6 @@ import { expectError } from 'tsd' -import { PrismaClient } from '.' -// tslint:disable +import { PrismaClient } from '.' const p1 = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/rejectOnNotFound/test.ts b/packages/client/src/__tests__/types/rejectOnNotFound/test.ts index b9ba2b80b35d..4be1b0448d9c 100644 --- a/packages/client/src/__tests__/types/rejectOnNotFound/test.ts +++ b/packages/client/src/__tests__/types/rejectOnNotFound/test.ts @@ -1,6 +1,5 @@ -import { MachineData, Post, PrismaClient, User } from '@prisma/client' - -// tslint:disable +import type { MachineData, Post, User } from '@prisma/client' +import { PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { @@ -64,8 +63,8 @@ async function main() { findFirst: true, }, }) - const r1p4: User = await p3.user.findUnique({ where: { id: '' } }) - const r2p4: User = await p3.user.findFirst({ + const r1p4: User = await p4.user.findUnique({ where: { id: '' } }) + const r2p4: User = await p4.user.findFirst({ rejectOnNotFound: true, }) const p5 = new PrismaClient({ diff --git a/packages/client/src/__tests__/types/scalarList/index.test-d.ts b/packages/client/src/__tests__/types/scalarList/index.test-d.ts index 08dd1489d59a..c7f31eefb9fe 100644 --- a/packages/client/src/__tests__/types/scalarList/index.test-d.ts +++ b/packages/client/src/__tests__/types/scalarList/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/scalarList/test.ts b/packages/client/src/__tests__/types/scalarList/test.ts index 0bdc223330f1..845dc0577c50 100644 --- a/packages/client/src/__tests__/types/scalarList/test.ts +++ b/packages/client/src/__tests__/types/scalarList/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/selectRelationCount/index.test-d.ts b/packages/client/src/__tests__/types/selectRelationCount/index.test-d.ts index 9062ec9555cc..4f90bf908f6c 100644 --- a/packages/client/src/__tests__/types/selectRelationCount/index.test-d.ts +++ b/packages/client/src/__tests__/types/selectRelationCount/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError, expectType } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/selectRelationCount/test.ts b/packages/client/src/__tests__/types/selectRelationCount/test.ts index 924e1cfa87f2..f8a8ebbefd33 100644 --- a/packages/client/src/__tests__/types/selectRelationCount/test.ts +++ b/packages/client/src/__tests__/types/selectRelationCount/test.ts @@ -1,7 +1,5 @@ import { PrismaClient, User } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/types.test.ts b/packages/client/src/__tests__/types/types.test.ts index b6896f4de2b4..2e513bad484f 100644 --- a/packages/client/src/__tests__/types/types.test.ts +++ b/packages/client/src/__tests__/types/types.test.ts @@ -1,12 +1,14 @@ +import { getPackedPackage } from '@prisma/sdk' import fs from 'fs' import path from 'path' -import { generateInFolder } from '../../utils/generateInFolder' import rimraf from 'rimraf' -import { promisify } from 'util' -import { getPackedPackage } from '@prisma/sdk' -import { compileFile } from '../../utils/compileFile' import tsd from 'tsd' import formatter from 'tsd/dist/lib/formatter' +import { promisify } from 'util' + +import { compileFile } from '../../utils/compileFile' +import { generateInFolder } from '../../utils/generateInFolder' + const del = promisify(rimraf) jest.setTimeout(300_000) @@ -57,7 +59,5 @@ async function runTsd(dir: string) { function getSubDirs(dir: string): string[] { const files = fs.readdirSync(dir) - return files - .map((file) => path.join(dir, file)) - .filter((file) => fs.lstatSync(file).isDirectory()) + return files.map((file) => path.join(dir, file)).filter((file) => fs.lstatSync(file).isDirectory()) } diff --git a/packages/client/src/__tests__/types/uncheckedScalarInputs/index.test-d.ts b/packages/client/src/__tests__/types/uncheckedScalarInputs/index.test-d.ts index 928a6a37120b..a7813b06674e 100644 --- a/packages/client/src/__tests__/types/uncheckedScalarInputs/index.test-d.ts +++ b/packages/client/src/__tests__/types/uncheckedScalarInputs/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/uncheckedScalarInputs/test.ts b/packages/client/src/__tests__/types/uncheckedScalarInputs/test.ts index 246f1e339cc7..ff8a745174b3 100644 --- a/packages/client/src/__tests__/types/uncheckedScalarInputs/test.ts +++ b/packages/client/src/__tests__/types/uncheckedScalarInputs/test.ts @@ -1,7 +1,5 @@ import { PrismaClient } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/unhappy-nested-or/index.test-d.ts b/packages/client/src/__tests__/types/unhappy-nested-or/index.test-d.ts index 10a01eeefa3d..10dadd49697d 100644 --- a/packages/client/src/__tests__/types/unhappy-nested-or/index.test-d.ts +++ b/packages/client/src/__tests__/types/unhappy-nested-or/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient } from '.' import { expectError } from 'tsd' -// tslint:disable +import { PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/unhappy-nested-or/test.ts b/packages/client/src/__tests__/types/unhappy-nested-or/test.ts index 04efa08e60fc..b5c50fa62896 100644 --- a/packages/client/src/__tests__/types/unhappy-nested-or/test.ts +++ b/packages/client/src/__tests__/types/unhappy-nested-or/test.ts @@ -1,7 +1,5 @@ import { PrismaClient, PrismaClientKnownRequestError } from '@prisma/client' -// tslint:disable - // This file will not be executed, just compiled to check if the typings are valid async function main() { const prisma = new PrismaClient() diff --git a/packages/client/src/__tests__/types/validator/index.d.ts b/packages/client/src/__tests__/types/validator/index.d.ts index 2fe0f910f828..22d627a72274 100644 --- a/packages/client/src/__tests__/types/validator/index.d.ts +++ b/packages/client/src/__tests__/types/validator/index.d.ts @@ -1 +1 @@ -export { PrismaClient, Prisma } from '@prisma/client' +export { Prisma, PrismaClient } from '@prisma/client' diff --git a/packages/client/src/__tests__/types/validator/index.test-d.ts b/packages/client/src/__tests__/types/validator/index.test-d.ts index 84875d5d9575..916ae37bb921 100644 --- a/packages/client/src/__tests__/types/validator/index.test-d.ts +++ b/packages/client/src/__tests__/types/validator/index.test-d.ts @@ -1,7 +1,6 @@ -import { PrismaClient, Prisma } from '.' import { expectError } from 'tsd' -// tslint:disable +import { Prisma, PrismaClient } from '.' const prisma = new PrismaClient({ datasources: { diff --git a/packages/client/src/__tests__/types/validator/test.ts b/packages/client/src/__tests__/types/validator/test.ts index db54dc8af4d1..fc416b481fcb 100644 --- a/packages/client/src/__tests__/types/validator/test.ts +++ b/packages/client/src/__tests__/types/validator/test.ts @@ -1,6 +1,4 @@ -import { PrismaClient, Prisma } from '@prisma/client' - -// tslint:disable +import { Prisma, PrismaClient } from '@prisma/client' // This file will not be executed, just compiled to check if the typings are valid async function main() { diff --git a/packages/client/src/__tests__/undefined-vs-null.test.ts b/packages/client/src/__tests__/undefined-vs-null.test.ts index 060ab99b5688..5676e07829d4 100644 --- a/packages/client/src/__tests__/undefined-vs-null.test.ts +++ b/packages/client/src/__tests__/undefined-vs-null.test.ts @@ -1,13 +1,14 @@ import stripAnsi from 'strip-ansi' + import { blog } from '../fixtures/blog' -import { DMMFClass } from '../runtime/dmmf' -import { makeDocument } from '../runtime/query' import { getDMMF } from '../generation/getDMMF' +import { DMMFHelper } from '../runtime/dmmf' +import { makeDocument } from '../runtime/query' let dmmf beforeAll(async () => { const dmmfDocument = await getDMMF({ datamodel: blog }) - dmmf = new DMMFClass(dmmfDocument) + dmmf = new DMMFHelper(dmmfDocument) }) describe('select validation', () => { diff --git a/packages/client/src/__tests__/update.test.ts b/packages/client/src/__tests__/update.test.ts index 889bd1f28309..245c6a97b0a5 100644 --- a/packages/client/src/__tests__/update.test.ts +++ b/packages/client/src/__tests__/update.test.ts @@ -1,7 +1,9 @@ import chalk from 'chalk' + import { blog } from '../fixtures/blog' -import { DMMFClass, makeDocument, transformDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument, transformDocument } from '../runtime' + chalk.level = 0 let dmmf @@ -31,7 +33,7 @@ describe('minimal update transformation', () => { posts: { updateMany: { data: { - optionnal: null, + optional: null, content: { set: null, }, @@ -55,7 +57,7 @@ describe('minimal update transformation', () => { posts: { updateMany: { data: { - optionnal: null + optional: null content: { set: null } diff --git a/packages/client/src/__tests__/uuid.test.ts b/packages/client/src/__tests__/uuid.test.ts index 0c3ace4b1edf..144a7b5dcba5 100644 --- a/packages/client/src/__tests__/uuid.test.ts +++ b/packages/client/src/__tests__/uuid.test.ts @@ -1,5 +1,5 @@ -import { DMMFClass, makeDocument } from '../runtime' import { getDMMF } from '../generation/getDMMF' +import { DMMFClass, makeDocument } from '../runtime' const datamodel = `datasource my_db { provider = "postgres" diff --git a/packages/client/src/byline.ts b/packages/client/src/byline.ts index 68b2c5b1e6ba..42fb240bed9b 100644 --- a/packages/client/src/byline.ts +++ b/packages/client/src/byline.ts @@ -20,12 +20,11 @@ // IN THE SOFTWARE. // @ts-ignore -/* tslint:disable */ import stream from 'stream' import util from 'util' -// convinience API +// convenience API export default function byline(readStream, options?: any) { return module.exports.createStream(readStream, options) } @@ -62,7 +61,7 @@ function LineStream(this: any, options) { options = options || {} // use objectMode to stop the output from being buffered - // which re-concatanates the lines, just without newlines. + // which re-concatenates the lines, just without newlines. this._readableState.objectMode = true this._lineBuffer = [] this._keepEmptyLines = options.keepEmptyLines || false diff --git a/packages/client/src/fixtures/blog.ts b/packages/client/src/fixtures/blog.ts index 5cb1645c799e..2e9e31363793 100644 --- a/packages/client/src/fixtures/blog.ts +++ b/packages/client/src/fixtures/blog.ts @@ -45,7 +45,7 @@ model Post { title String content String? authorId String? - optionnal Float? + optional Float? author User? @relation(fields: [authorId], references: [id]) categories Category[] @relation("MyPostCatRelationTable") } diff --git a/packages/client/src/generation/TSClient/Args.ts b/packages/client/src/generation/TSClient/Args.ts index d965007d9177..57cebe9ff0ef 100644 --- a/packages/client/src/generation/TSClient/Args.ts +++ b/packages/client/src/generation/TSClient/Args.ts @@ -1,4 +1,5 @@ import indent from 'indent-string' + import { DMMF } from '../../runtime/dmmf-types' import { getIncludeName, getModelArgName, getSelectName } from '../utils' import { TAB_SIZE } from './constants' @@ -104,13 +105,17 @@ ${indent(bothArgsOptional.map((arg) => new InputField(arg).toTS()).join('\n'), T export class MinimalArgsType implements Generatable { constructor( protected readonly args: DMMF.SchemaArg[], - protected readonly model: DMMF.Model, + protected readonly type: DMMF.OutputType, protected readonly action?: DMMF.ModelAction, protected readonly collector?: ExportCollector, ) {} public toTS(): string { const { action, args } = this - const { name } = this.model + const { name } = this.type + + for (const arg of args) { + arg.comment = getArgFieldJSDoc(this.type, action, arg) + } const typeName = getModelArgName(name, action) @@ -121,7 +126,15 @@ export class MinimalArgsType implements Generatable { * ${name} ${action ? action : 'without action'} */ export type ${typeName} = { -${indent(args.map((arg) => new InputField(arg).toTS()).join('\n'), TAB_SIZE)} +${indent( + args + .map((arg) => { + const noEnumerable = arg.inputTypes.some((input) => input.type === 'Json') && arg.name === 'pipeline' + return new InputField(arg, false, noEnumerable).toTS() + }) + .join('\n'), + TAB_SIZE, +)} } ` } diff --git a/packages/client/src/generation/TSClient/Count.ts b/packages/client/src/generation/TSClient/Count.ts index d84263890251..4772763350c9 100644 --- a/packages/client/src/generation/TSClient/Count.ts +++ b/packages/client/src/generation/TSClient/Count.ts @@ -1,6 +1,7 @@ import type { GeneratorConfig } from '@prisma/generator-helper' import indent from 'indent-string' -import type { DMMFClass } from '../../runtime/dmmf' + +import type { DMMFHelper } from '../../runtime/dmmf' import { DMMF } from '../../runtime/dmmf-types' import { getAggregateArgsName, @@ -11,8 +12,8 @@ import { getGroupByArgsName, getGroupByPayloadName, getModelArgName, + getReturnType, getSelectName, - getSelectReturnType, Projection, } from '../utils' import { ArgsType } from './Args' @@ -27,7 +28,7 @@ import { PayloadType } from './Payload' export class Count implements Generatable { constructor( protected readonly type: DMMF.OutputType, - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly generator?: GeneratorConfig, protected readonly collector?: ExportCollector, ) {} @@ -62,7 +63,7 @@ ${indent( )} } -${new PayloadType(outputType, true).toTS()} +${new PayloadType(outputType, false).toTS()} ${/*new CountDelegate(outputType, this.dmmf, this.generator).toTS()*/ ''} @@ -75,7 +76,7 @@ ${this.argsTypes.map(TS).join('\n')} class CountDelegate implements Generatable { constructor( protected readonly outputType: OutputType, - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly generator?: GeneratorConfig, ) {} public toTS(): string { @@ -84,7 +85,7 @@ class CountDelegate implements Generatable { if (!mapping) { return '' } - const model = this.dmmf.modelMap[name] + const modelOrType = this.dmmf.typeAndModelMap[name] const actions = Object.entries(mapping).filter( ([key, value]) => key !== 'model' && key !== 'plural' && key !== 'aggregate' && key !== 'groupBy' && value, @@ -103,16 +104,16 @@ ${indent( actions .map( ([actionName]: [any, any]): string => - `${getMethodJSDoc(actionName, mapping, model)} + `${getMethodJSDoc(actionName, mapping, modelOrType)} ${actionName}${getGenericMethod(name, actionName)}( ${getArgs(name, actionName)} -): ${getSelectReturnType({ name, actionName, projection: Projection.select })}`, +): ${getReturnType({ name, actionName, projection: Projection.select })}`, ) .join('\n\n'), TAB_SIZE, )} -${indent(getMethodJSDoc(DMMF.ModelAction.count, mapping, model), TAB_SIZE)} +${indent(getMethodJSDoc(DMMF.ModelAction.count, mapping, modelOrType), TAB_SIZE)} count( args?: Subset, ): PrismaPromise< @@ -123,12 +124,12 @@ ${indent(getMethodJSDoc(DMMF.ModelAction.count, mapping, model), TAB_SIZE)} : number > -${indent(getMethodJSDoc(DMMF.ModelAction.aggregate, mapping, model), TAB_SIZE)} +${indent(getMethodJSDoc(DMMF.ModelAction.aggregate, mapping, modelOrType), TAB_SIZE)} aggregate(args: Subset): PrismaPromise<${getAggregateGetName(name)}> -${indent(getMethodJSDoc(DMMF.ModelAction.groupBy, mapping, model), TAB_SIZE)} +${indent(getMethodJSDoc(DMMF.ModelAction.groupBy, mapping, modelOrType), TAB_SIZE)} groupBy< T extends ${groupByArgsName}, HasSelectOrTake extends Or< @@ -219,7 +220,7 @@ ${indent( .map((f) => { const fieldTypeName = (f.outputType.type as DMMF.OutputType).name return ` -${f.name}(args?: Subset): ${getSelectReturnType({ +${f.name}(args?: Subset): ${getReturnType({ name: fieldTypeName, actionName: f.outputType.isList ? DMMF.ModelAction.findMany : DMMF.ModelAction.findUnique, hideCondition: false, diff --git a/packages/client/src/generation/TSClient/Datasources.ts b/packages/client/src/generation/TSClient/Datasources.ts index e6199396a520..224110c30049 100644 --- a/packages/client/src/generation/TSClient/Datasources.ts +++ b/packages/client/src/generation/TSClient/Datasources.ts @@ -1,6 +1,7 @@ import indent from 'indent-string' -import type { Generatable } from './Generatable' + import type { InternalDatasource } from '../../runtime/utils/printDatasources' +import type { Generatable } from './Generatable' export class Datasources implements Generatable { constructor(protected readonly internalDatasources: InternalDatasource[]) {} diff --git a/packages/client/src/generation/TSClient/Enum.ts b/packages/client/src/generation/TSClient/Enum.ts index e76e8100f1c8..181fbd16132f 100644 --- a/packages/client/src/generation/TSClient/Enum.ts +++ b/packages/client/src/generation/TSClient/Enum.ts @@ -1,8 +1,9 @@ import indent from 'indent-string' -import type { Generatable } from './Generatable' + import type { DMMF } from '../../runtime/dmmf-types' -import type { ExportCollector } from './helpers' import { TAB_SIZE } from './constants' +import type { Generatable } from './Generatable' +import type { ExportCollector } from './helpers' export class Enum implements Generatable { constructor( diff --git a/packages/client/src/generation/TSClient/Input.ts b/packages/client/src/generation/TSClient/Input.ts index 7184bba46747..0f09964db904 100644 --- a/packages/client/src/generation/TSClient/Input.ts +++ b/packages/client/src/generation/TSClient/Input.ts @@ -1,4 +1,5 @@ import indent from 'indent-string' + import type { DMMF } from '../../runtime/dmmf-types' import { argIsInputType, GraphQLScalarToJSTypeTable, JSOutputTypeToInputType } from '../../runtime/utils/common' import { uniqueBy } from '../../runtime/utils/uniqueBy' diff --git a/packages/client/src/generation/TSClient/Model.ts b/packages/client/src/generation/TSClient/Model.ts index 4e93660eeec4..b3051ae19777 100644 --- a/packages/client/src/generation/TSClient/Model.ts +++ b/packages/client/src/generation/TSClient/Model.ts @@ -1,7 +1,8 @@ import type { GeneratorConfig } from '@prisma/generator-helper' import indent from 'indent-string' import { klona } from 'klona' -import type { DMMFClass } from '../../runtime/dmmf' + +import type { DMMFHelper } from '../../runtime/dmmf' import { DMMF } from '../../runtime/dmmf-types' import { getAggregateArgsName, @@ -19,8 +20,8 @@ import { getMaxAggregateName, getMinAggregateName, getModelArgName, + getReturnType, getSelectName, - getSelectReturnType, getSumAggregateName, Projection, } from '../utils' @@ -43,7 +44,7 @@ export class Model implements Generatable { protected mapping?: DMMF.ModelMapping constructor( protected readonly model: DMMF.Model, - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly generator?: GeneratorConfig, protected readonly collector?: ExportCollector, ) { @@ -52,14 +53,11 @@ export class Model implements Generatable { this.mapping = dmmf.mappings.modelOperations.find((m) => m.model === model.name)! } protected get argsTypes(): Generatable[] { - const { mapping, model } = this - if (!mapping) { - return [] - } + const { mapping } = this const argsTypes: Generatable[] = [] for (const action in DMMF.ModelAction) { - const fieldName = mapping[action] + const fieldName = mapping?.[action] if (!fieldName) { continue } @@ -67,8 +65,11 @@ export class Model implements Generatable { if (!field) { throw new Error(`Oops this must not happen. Could not find field ${fieldName} on either Query or Mutation`) } + if (action === 'updateMany' || action === 'deleteMany' || action === 'createMany') { - argsTypes.push(new MinimalArgsType(field.args, model, action as DMMF.ModelAction, this.collector)) + argsTypes.push(new MinimalArgsType(field.args, this.type, action as DMMF.ModelAction, this.collector)) + } else if (action === 'findRaw' || action === 'aggregateRaw') { + argsTypes.push(new MinimalArgsType(field.args, this.type, action as DMMF.ModelAction, this.collector)) } else if (action !== 'groupBy' && action !== 'aggregate') { argsTypes.push(new ArgsType(field.args, this.type, action as DMMF.ModelAction, this.collector)) } @@ -124,7 +125,7 @@ ${indent( ${new OutputType(this.dmmf, groupByType).toTS()} -type ${getGroupByPayloadName(model.name)} = Promise< +type ${getGroupByPayloadName(model.name)} = PrismaPromise< Array< PickArray<${groupByType.name}, T['by']> & { @@ -260,8 +261,8 @@ export type ${getAggregateGetName(model.name)} f.kind !== 'object' && f.kind !== 'unsupported') - .map((field) => new ModelOutputField(this.dmmf, field, true).toTS()) + .filter((f) => (f.kind !== 'object' && f.kind !== 'unsupported') || this.dmmf.typeMap[f.type]) + .map((field) => new ModelOutputField(this.dmmf, field, !this.dmmf.typeMap[field.type]).toTS()) .join('\n'), TAB_SIZE, )} @@ -280,10 +281,19 @@ ${indent( ? `\nexport type ${getIncludeName(model.name)} = { ${indent( outputType.fields - .filter((f) => f.outputType.location === 'outputObjectTypes') - .map( - (f) => `${f.name}?: boolean` + (f.outputType.location === 'outputObjectTypes' ? ` | ${getFieldArgName(f)}` : ''), - ) + .filter((f) => { + const fieldTypeName = (f.outputType.type as DMMF.OutputType).name + return f.outputType.location === 'outputObjectTypes' && !this.dmmf.typeMap[fieldTypeName] + }) + .map((f) => { + const fieldTypeName = (f.outputType.type as DMMF.OutputType).name + return ( + `${f.name}?: boolean` + + (f.outputType.location === 'outputObjectTypes' + ? ` | ${getFieldArgName(f, !this.dmmf.typeMap[fieldTypeName])}` + : '') + ) + }) .join('\n'), TAB_SIZE, )} @@ -295,22 +305,28 @@ ${indent( * Model ${model.name} */ -${this.getAggregationTypes()} +${!this.dmmf.typeMap[model.name] ? this.getAggregationTypes() : ''} -${this.getGroupByTypes()} +${!this.dmmf.typeMap[model.name] ? this.getGroupByTypes() : ''} export type ${getSelectName(model.name)} = { ${indent( outputType.fields - .map( - (f) => `${f.name}?: boolean` + (f.outputType.location === 'outputObjectTypes' ? ` | ${getFieldArgName(f)}` : ''), - ) + .map((f) => { + const fieldTypeName = (f.outputType.type as DMMF.OutputType).name + return ( + `${f.name}?: boolean` + + (f.outputType.location === 'outputObjectTypes' + ? ` | ${getFieldArgName(f, !this.dmmf.typeMap[fieldTypeName])}` + : '') + ) + }) .join('\n'), TAB_SIZE, )} } ${includeType} -${new PayloadType(this.outputType!).toTS()} +${new PayloadType(this.outputType!, !this.dmmf.typeMap[model.name]).toTS()} ${new ModelDelegate(this.outputType!, this.dmmf, this.generator).toTS()} @@ -322,44 +338,53 @@ ${this.argsTypes.map(TS).join('\n')} export class ModelDelegate implements Generatable { constructor( protected readonly outputType: OutputType, - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly generator?: GeneratorConfig, ) {} public toTS(): string { const { fields, name } = this.outputType - const mapping = this.dmmf.mappingsMap[name] - if (!mapping) { - return '' - } - const model = this.dmmf.modelMap[name] - const actions = Object.entries(mapping).filter( - ([key, value]) => key !== 'model' && key !== 'plural' && key !== 'aggregate' && key !== 'groupBy' && value, - ) + const mapping = this.dmmf.mappingsMap[name] ?? { model: name, plural: `${name}s` } + const modelOrType = this.dmmf.typeAndModelMap[name] + + const mappingKeys = Object.keys(mapping) + const availableActions = mappingKeys.filter( + (key) => key !== 'model' && key !== 'plural' && mapping[key], + ) as DMMF.ModelAction[] + const filteredActions = availableActions.filter( + (key) => key !== 'aggregate' && key !== 'groupBy', + ) as DMMF.ModelAction[] + const groupByArgsName = getGroupByArgsName(name) const countArgsName = getModelArgName(name, DMMF.ModelAction.count) return `\ -type ${countArgsName} = Merge< +${ + availableActions.includes(DMMF.ModelAction.aggregate) + ? `type ${countArgsName} = Merge< Omit<${getModelArgName(name, DMMF.ModelAction.findMany)}, 'select' | 'include'> & { select?: ${getCountAggregateInputName(name)} | true } > - +` + : '' +} export interface ${name}Delegate { ${indent( - actions + filteredActions .map( - ([actionName]: [any, any]): string => - `${getMethodJSDoc(actionName, mapping, model)} + (actionName): string => + `${getMethodJSDoc(actionName, mapping, modelOrType)} ${actionName}${getGenericMethod(name, actionName)}( ${getArgs(name, actionName)} -): ${getSelectReturnType({ name, actionName, projection: Projection.select })}`, +): ${getReturnType({ name, actionName, projection: Projection.select })}`, ) .join('\n\n'), TAB_SIZE, )} -${indent(getMethodJSDoc(DMMF.ModelAction.count, mapping, model), TAB_SIZE)} +${ + availableActions.includes(DMMF.ModelAction.aggregate) + ? `${indent(getMethodJSDoc(DMMF.ModelAction.count, mapping, modelOrType), TAB_SIZE)} count( args?: Subset, ): PrismaPromise< @@ -369,13 +394,21 @@ ${indent(getMethodJSDoc(DMMF.ModelAction.count, mapping, model), TAB_SIZE)} : GetScalarType : number > - -${indent(getMethodJSDoc(DMMF.ModelAction.aggregate, mapping, model), TAB_SIZE)} +` + : '' +} +${ + availableActions.includes(DMMF.ModelAction.aggregate) + ? `${indent(getMethodJSDoc(DMMF.ModelAction.aggregate, mapping, modelOrType), TAB_SIZE)} aggregate(args: Subset): PrismaPromise<${getAggregateGetName(name)}> - -${indent(getMethodJSDoc(DMMF.ModelAction.groupBy, mapping, model), TAB_SIZE)} + name, + )}>): PrismaPromise<${getAggregateGetName(name)}> +` + : '' +} +${ + availableActions.includes(DMMF.ModelAction.groupBy) + ? `${indent(getMethodJSDoc(DMMF.ModelAction.groupBy, mapping, modelOrType), TAB_SIZE)} groupBy< T extends ${groupByArgsName}, HasSelectOrTake extends Or< @@ -434,8 +467,10 @@ ${indent(getMethodJSDoc(DMMF.ModelAction.groupBy, mapping, model), TAB_SIZE)} : \`Error: Field "$\{P}" in "orderBy" needs to be provided in "by"\` }[OrderFields] >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? ${getGroupByPayloadName( - name, - )} : Promise + name, + )} : PrismaPromise` + : '' +} } /** @@ -466,7 +501,10 @@ ${indent( .map((f) => { const fieldTypeName = (f.outputType.type as DMMF.OutputType).name return ` -${f.name}(args?: Subset): ${getSelectReturnType({ +${f.name}(args?: Subset): ${getReturnType({ name: fieldTypeName, actionName: f.outputType.isList ? DMMF.ModelAction.findMany : DMMF.ModelAction.findUnique, hideCondition: false, diff --git a/packages/client/src/generation/TSClient/Output.ts b/packages/client/src/generation/TSClient/Output.ts index 65329a18f8ff..7c28a187e881 100644 --- a/packages/client/src/generation/TSClient/Output.ts +++ b/packages/client/src/generation/TSClient/Output.ts @@ -1,5 +1,6 @@ import indent from 'indent-string' -import type { DMMFClass } from '../../runtime/dmmf' + +import type { DMMFHelper } from '../../runtime/dmmf' import type { DMMF } from '../../runtime/dmmf-types' import { GraphQLScalarToJSTypeTable, isSchemaEnum, needsNamespace } from '../../runtime/utils/common' import { buildComment } from '../utils/types/buildComment' @@ -10,15 +11,14 @@ import { wrapComment } from './helpers' export class ModelOutputField implements Generatable { constructor( - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly field: DMMF.Field, protected readonly useNamespace = false, ) {} public toTS(): string { const { field, useNamespace } = this // ENUMTODO - let fieldType = - typeof field.type === 'string' ? GraphQLScalarToJSTypeTable[field.type] || field.type : field.type[0].name + let fieldType = GraphQLScalarToJSTypeTable[field.type] || field.type if (Array.isArray(fieldType)) { fieldType = fieldType[0] } @@ -32,7 +32,7 @@ export class ModelOutputField implements Generatable { export class OutputField implements Generatable { constructor( - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly field: DMMF.SchemaField, protected readonly useNamespace = false, ) {} @@ -70,7 +70,7 @@ export class OutputType implements Generatable { public name: string public fields: DMMF.SchemaField[] constructor( - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly type: DMMF.OutputType, protected readonly collector?: ExportCollector, ) { diff --git a/packages/client/src/generation/TSClient/Payload.ts b/packages/client/src/generation/TSClient/Payload.ts index 9170992f9a21..623186e60f72 100644 --- a/packages/client/src/generation/TSClient/Payload.ts +++ b/packages/client/src/generation/TSClient/Payload.ts @@ -1,12 +1,12 @@ -import type { OutputType } from './Output' import indent from 'indent-string' -import { DMMF } from '../../runtime/dmmf-types' -import { getModelArgName, getPayloadName, Projection, getArgName } from '../utils' +import { DMMF } from '../../runtime/dmmf-types' +import { getArgName, getModelArgName, getPayloadName, Projection } from '../utils' import type { Generatable } from './Generatable' +import type { OutputType } from './Output' export class PayloadType implements Generatable { - constructor(protected readonly type: OutputType, protected readonly skipFindMany = false) {} + constructor(protected readonly type: OutputType, protected readonly findMany = true) {} public toTS(): string { const { type } = this @@ -17,7 +17,7 @@ export class PayloadType implements Generatable { const include = this.renderRelations(Projection.include) const select = this.renderRelations(Projection.select) - const findManyArg = this.skipFindMany ? '' : ` | ${getModelArgName(name, DMMF.ModelAction.findMany)}` + const findManyArg = this.findMany ? ` | ${getModelArgName(name, DMMF.ModelAction.findMany)}` : '' return `\ export type ${getPayloadName(name)}< @@ -43,22 +43,22 @@ export type ${getPayloadName(name)}< if (relations.length === 0 && projection === Projection.include) { return '' } - const selectPrefix = - projection === Projection.select - ? `P extends keyof ${type.name} ?${type.name} [P] -: ` - : '' + const selectPrefix = projection === Projection.select ? ` P extends keyof ${type.name} ? ${type.name}[P] :` : '' + return `{ - [P in TrueKeys]: ${selectPrefix} - ${indent( - relations - .map( - (f) => `P extends '${f.name}' -? ${this.wrapType(f, `${getPayloadName((f.outputType.type as DMMF.OutputType).name)}`)} :`, - ) - .join('\n'), - 6, - )} never + [P in TrueKeys]: +${indent( + relations + .map( + (f) => + `P extends '${f.name}' ? ${this.wrapType( + f, + `${getPayloadName((f.outputType.type as DMMF.OutputType).name)}`, + )} :`, + ) + .join('\n'), + 6, +)} ${selectPrefix} never } ` } private wrapType(field: DMMF.SchemaField, str: string): string { diff --git a/packages/client/src/generation/TSClient/PrismaClient.ts b/packages/client/src/generation/TSClient/PrismaClient.ts index d8d3c6777e19..0400249b4583 100644 --- a/packages/client/src/generation/TSClient/PrismaClient.ts +++ b/packages/client/src/generation/TSClient/PrismaClient.ts @@ -1,6 +1,7 @@ import type { GeneratorConfig } from '@prisma/generator-helper' import indent from 'indent-string' -import type { DMMFClass } from '../../runtime/dmmf' + +import type { DMMFHelper } from '../../runtime/dmmf' import { capitalize, lowerCase } from '../../runtime/utils/common' import type { InternalDatasource } from '../../runtime/utils/printDatasources' import type { DatasourceOverwrite } from './../extractSqliteSources' @@ -100,9 +101,32 @@ function executeRawDefinition(this: PrismaClientClass) { $executeRawUnsafe(query: string, ...values: any[]): PrismaPromise;` } +function runCommandRawDefinition(this: PrismaClientClass) { + // we do not generate `$runCommandRaw` definitions if not supported + if (!this.dmmf.mappings.otherOperations.write.includes('runCommandRaw')) { + return '' // https://github.com/prisma/prisma/issues/8189 + } + + return ` + /** + * Executes a raw MongoDB command and returns the result of it. + * @example + * \`\`\` + * const user = await prisma.$runCommandRaw({ + * aggregate: 'User', + * pipeline: [{ $match: { name: 'Bob' } }, { $project: { email: true, _id: false } }], + * explain: false, + * }) + * \`\`\` + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access). + */ + $runCommandRaw(command: Prisma.InputJsonObject): PrismaPromise;` +} + export class PrismaClientClass implements Generatable { constructor( - protected readonly dmmf: DMMFClass, + protected readonly dmmf: DMMFHelper, protected readonly internalDatasources: InternalDatasource[], protected readonly outputDir: string, protected readonly browser?: boolean, @@ -183,12 +207,16 @@ export class PrismaClient< * Add a middleware */ $use(cb: Prisma.Middleware): void + ${[ executeRawDefinition.bind(this)(), queryRawDefinition.bind(this)(), batchingTransactionDefinition.bind(this)(), interactiveTransactionDefinition.bind(this)(), -].join('\n')} + runCommandRawDefinition.bind(this)(), +] + .join('\n') + .trim()} ${indent( dmmf.mappings.modelOperations @@ -227,7 +255,7 @@ export type HasReject< ? IsReject : GlobalRejectSettings extends RejectPerOperation ? Action extends keyof GlobalRejectSettings - ? GlobalRejectSettings[Action] extends boolean + ? GlobalRejectSettings[Action] extends RejectOnNotFound ? IsReject : GlobalRejectSettings[Action] extends RejectPerModel ? Model extends keyof GlobalRejectSettings[Action] @@ -328,6 +356,7 @@ export type PrismaAction = | 'queryRaw' | 'aggregate' | 'count' + | 'runCommandRaw' /** * These options are being passed in to the middleware as "params" diff --git a/packages/client/src/generation/TSClient/SchemaOutput.ts b/packages/client/src/generation/TSClient/SchemaOutput.ts index 1ae17e682f28..5e309eac1a5f 100644 --- a/packages/client/src/generation/TSClient/SchemaOutput.ts +++ b/packages/client/src/generation/TSClient/SchemaOutput.ts @@ -1,4 +1,5 @@ import indent from 'indent-string' + import type { DMMF } from '../../runtime/dmmf-types' import { GraphQLScalarToJSTypeTable } from '../../runtime/utils/common' import { TAB_SIZE } from './constants' diff --git a/packages/client/src/generation/TSClient/TSClient.ts b/packages/client/src/generation/TSClient/TSClient.ts index 4327f01683d5..8b01197e1e06 100644 --- a/packages/client/src/generation/TSClient/TSClient.ts +++ b/packages/client/src/generation/TSClient/TSClient.ts @@ -1,14 +1,22 @@ import type { GeneratorConfig } from '@prisma/generator-helper' import type { Platform } from '@prisma/get-platform' -import { getEnvPaths, getClientEngineType } from '@prisma/sdk' +import { getClientEngineType, getEnvPaths } from '@prisma/sdk' import indent from 'indent-string' import { klona } from 'klona' import path from 'path' -import { DMMFClass } from '../../runtime/dmmf' + +import { DMMFHelper } from '../../runtime/dmmf' import type { DMMF } from '../../runtime/dmmf-types' import type { GetPrismaClientConfig } from '../../runtime/getPrismaClient' import type { InternalDatasource } from '../../runtime/utils/printDatasources' +import { buildDirname } from '../utils/buildDirname' +import { buildDMMF } from '../utils/buildDMMF' +import { buildInlineDatasource } from '../utils/buildInlineDatasources' +import { buildInlineEnv } from '../utils/buildInlineEnv' +import { buildInlineSchema } from '../utils/buildInlineSchema' import { buildNFTAnnotations } from '../utils/buildNFTAnnotations' +import { buildRequirePath } from '../utils/buildRequirePath' +import { buildWarnEnvConflicts } from '../utils/buildWarnEnvConflicts' import type { DatasourceOverwrite } from './../extractSqliteSources' import { commonCodeJS, commonCodeTS } from './common' import { Count } from './Count' @@ -18,13 +26,6 @@ import { escapeJson, ExportCollector } from './helpers' import { InputType } from './Input' import { Model } from './Model' import { PrismaClientClass } from './PrismaClient' -import { buildDirname } from '../utils/buildDirname' -import { buildRequirePath } from '../utils/buildRequirePath' -import { buildWarnEnvConflicts } from '../utils/buildWarnEnvConflicts' -import { buildInlineSchema } from '../utils/buildInlineSchema' -import { buildInlineEnv } from '../utils/buildInlineEnv' -import { buildDMMF } from '../utils/buildDMMF' -import { buildInlineDatasource } from '../utils/buildInlineDatasources' export interface TSClientOptions { projectRoot: string @@ -36,7 +37,7 @@ export interface TSClientOptions { browser?: boolean datasources: InternalDatasource[] generator?: GeneratorConfig - platforms?: Platform[] + platforms?: Platform[] // TODO: consider making it non-nullable sqliteDatasourceOverrides?: DatasourceOverwrite[] schemaDir: string outputDir: string @@ -44,11 +45,11 @@ export interface TSClientOptions { } export class TSClient implements Generatable { - protected readonly dmmf: DMMFClass + protected readonly dmmf: DMMFHelper protected readonly dmmfString: string constructor(protected readonly options: TSClientOptions) { this.dmmfString = escapeJson(JSON.stringify(options.document)) - this.dmmf = new DMMFClass(klona(options.document)) + this.dmmf = new DMMFHelper(klona(options.document)) } public async toJS(): Promise { @@ -144,9 +145,9 @@ ${buildNFTAnnotations(engineType, platforms, relativeOutdir)} const collector = new ExportCollector() const commonCode = commonCodeTS(this.options) - const models = Object.values(this.dmmf.modelMap).reduce((acc, model) => { - if (this.dmmf.outputTypeMap[model.name]) { - acc.push(new Model(model, this.dmmf, this.options.generator, collector)) + const modelAndTypes = Object.values(this.dmmf.typeAndModelMap).reduce((acc, modelOrType) => { + if (this.dmmf.outputTypeMap[modelOrType.name]) { + acc.push(new Model(modelOrType, this.dmmf, this.options.generator, collector)) } return acc }, [] as Model[]) @@ -168,7 +169,7 @@ ${buildNFTAnnotations(engineType, platforms, relativeOutdir)} ${commonCode.tsWithoutNamespace()} -${models.map((m) => m.toTSWithoutNamespace()).join('\n')} +${modelAndTypes.map((m) => m.toTSWithoutNamespace()).join('\n')} ${ modelEnums && modelEnums.length > 0 ? ` @@ -211,7 +212,7 @@ ${countTypes.map((t) => t.toTS()).join('\n')} /** * Models */ -${models.map((model) => model.toTS()).join('\n')} +${modelAndTypes.map((model) => model.toTS()).join('\n')} /** * Enums diff --git a/packages/client/src/generation/TSClient/common.ts b/packages/client/src/generation/TSClient/common.ts index dce0b3a12cab..2e675f34594a 100644 --- a/packages/client/src/generation/TSClient/common.ts +++ b/packages/client/src/generation/TSClient/common.ts @@ -277,7 +277,11 @@ type Without = { [P in Exclude]?: never }; * XOR is needed to have a real mutually exclusive union type * https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types */ -type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; +type XOR = + T extends object ? + U extends object ? + (Without & U) | (Without & T) + : U : T /** diff --git a/packages/client/src/generation/TSClient/helpers.ts b/packages/client/src/generation/TSClient/helpers.ts index 4ac066c52d89..ba31ac5a4df6 100644 --- a/packages/client/src/generation/TSClient/helpers.ts +++ b/packages/client/src/generation/TSClient/helpers.ts @@ -1,4 +1,5 @@ import pluralize from 'pluralize' + import { DMMF } from '../../runtime/dmmf-types' import { capitalize, lowerCase } from '../../runtime/utils/common' import { getAggregateArgsName, getModelArgName, unique } from '../utils' @@ -30,6 +31,9 @@ export function getGenericMethod(name: string, actionName: DMMF.ModelAction) { if (actionName === 'aggregate') { return `` } + if (actionName === 'findRaw' || actionName === 'aggregateRaw') { + return '' + } if (actionName === 'findFirst' || actionName === 'findUnique') { return `` } const modelArgName = getModelArgName(name, actionName) + if (!modelArgName) { console.log({ name, actionName }) } return `` } -export function getArgs(name: string, actionName: DMMF.ModelAction) { +export function getArgs(modelName: string, actionName: DMMF.ModelAction) { if (actionName === 'count') { - return `args?: Omit<${getModelArgName(name, DMMF.ModelAction.findMany)}, 'select' | 'include'>` + return `args?: Omit<${getModelArgName(modelName, DMMF.ModelAction.findMany)}, 'select' | 'include'>` } if (actionName === 'aggregate') { - return `args: Subset` + return `args: Subset` + } + if (actionName === 'findRaw' || actionName === 'aggregateRaw') { + return `args?: ${getModelArgName(modelName, actionName)}` } return `args${ actionName === DMMF.ModelAction.findMany || @@ -56,7 +64,7 @@ export function getArgs(name: string, actionName: DMMF.ModelAction) { actionName === DMMF.ModelAction.createMany ? '?' : '' - }: SelectSubset` + }: SelectSubset` } export function wrapComment(str: string): string { return `/**\n${str diff --git a/packages/client/src/generation/TSClient/index.ts b/packages/client/src/generation/TSClient/index.ts index 2d49b1d3c3c9..9c83fd885110 100644 --- a/packages/client/src/generation/TSClient/index.ts +++ b/packages/client/src/generation/TSClient/index.ts @@ -1,6 +1,6 @@ import 'flat-map-polyfill' // unfortunately needed as it's not properly polyfilled in TypeScript -export { MinimalArgsType, ArgsType } from './Args' +export { ArgsType, MinimalArgsType } from './Args' export { Enum } from './Enum' export { JS, TS } from './Generatable' export { InputField, InputType } from './Input' diff --git a/packages/client/src/generation/TSClient/jsdoc.ts b/packages/client/src/generation/TSClient/jsdoc.ts index 8f6714f152ee..8727c99873b3 100644 --- a/packages/client/src/generation/TSClient/jsdoc.ts +++ b/packages/client/src/generation/TSClient/jsdoc.ts @@ -1,4 +1,5 @@ import type { DMMF } from '@prisma/generator-helper' + import { capitalize, lowerCase } from '../../runtime/utils/common' import { getGroupByArgsName, getModelArgName } from '../utils' @@ -326,4 +327,37 @@ const { count } = await ${ctx.method}({ where: (singular, plural) => `Filter which ${plural} to delete`, }, }, + aggregateRaw: { + body: (ctx) => + `Perform aggregation operations on a ${ctx.singular}. +@param {${getModelArgName(ctx.model.name, ctx.action)}} args - Select which aggregations you would like to apply. +@example +const ${lowerCase(ctx.mapping.model)} = await ${ctx.method}({ + pipeline: [ + { $match: { status: "registered" } }, + { $group: { _id: "$country", total: { $sum: 1 } } } + ] +})`, + fields: { + pipeline: () => + 'An array of aggregation stages to process and transform the document stream via the aggregation pipeline. ${@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline MongoDB Docs}.', + options: () => + 'Additional options to pass to the `aggregate` command ${@link https://docs.mongodb.com/manual/reference/command/aggregate/#command-fields MongoDB Docs}.', + }, + }, + findRaw: { + body: (ctx) => + `Find zero or more ${ctx.plural} that matches the filter. +@param {${getModelArgName(ctx.model.name, ctx.action)}} args - Select which filters you would like to apply. +@example +const ${lowerCase(ctx.mapping.model)} = await ${ctx.method}({ + filter: { age: { $gt: 25 } } +})`, + fields: { + filter: () => + 'The query predicate filter. If unspecified, then all documents in the collection will match the predicate. ${@link https://docs.mongodb.com/manual/reference/operator/query MongoDB Docs}.', + options: () => + 'Additional options to pass to the `find` command ${@link https://docs.mongodb.com/manual/reference/command/find/#command-fields MongoDB Docs}.', + }, + }, } diff --git a/packages/client/src/generation/generateClient.ts b/packages/client/src/generation/generateClient.ts index 93fcb17a6ac5..6833376056d3 100644 --- a/packages/client/src/generation/generateClient.ts +++ b/packages/client/src/generation/generateClient.ts @@ -1,7 +1,7 @@ import { BinaryType } from '@prisma/fetch-engine' import type { BinaryPaths, DataSource, DMMF, GeneratorConfig } from '@prisma/generator-helper' import type { Platform } from '@prisma/sdk' -import { getVersion, ClientEngineType, getClientEngineType } from '@prisma/sdk' +import { ClientEngineType, getClientEngineType, getVersion } from '@prisma/sdk' import copy from '@timsuchanek/copy' import chalk from 'chalk' import fs from 'fs' @@ -9,6 +9,7 @@ import makeDir from 'make-dir' import path from 'path' import pkgUp from 'pkg-up' import { promisify } from 'util' + import type { DMMF as PrismaClientDMMF } from '../runtime/dmmf-types' import type { Dictionary } from '../runtime/utils/common' import { getPrismaClientDMMF } from './getDMMF' @@ -208,8 +209,8 @@ export async function generateClient({ }), ) const runtimeSourceDir = testMode - ? eval(`require('path').join(__dirname, '../../runtime')`) // tslint:disable-line - : eval(`require('path').join(__dirname, '../runtime')`) // tslint:disable-line + ? eval(`require('path').join(__dirname, '../../runtime')`) + : eval(`require('path').join(__dirname, '../runtime')`) // if users use a custom output dir if (copyRuntime || !path.resolve(outputDir).endsWith(`@prisma${path.sep}client`)) { @@ -345,7 +346,7 @@ function validateDmmfAgainstDenylists(prismaClientDmmf: PrismaClientDMMF.Documen const denylists = { // A copy of this list is also in prisma-engines. Any edit should be done in both places. - // https://github.com/prisma/prisma-engines/blob/master/libs/datamodel/core/src/transform/ast_to_dml/reserved_model_names.rs + // https://github.com/prisma/prisma-engines/blob/main/libs/datamodel/core/src/transform/ast_to_dml/reserved_model_names.rs models: [ // Reserved Prisma keywords 'PrismaClient', diff --git a/packages/client/src/generation/generator.ts b/packages/client/src/generation/generator.ts index 4eb9bfbc2c4b..35fce5b80e73 100755 --- a/packages/client/src/generation/generator.ts +++ b/packages/client/src/generation/generator.ts @@ -1,15 +1,19 @@ import Debug from '@prisma/debug' import { enginesVersion } from '@prisma/engines-version' import { generatorHandler } from '@prisma/generator-helper' -import { parseEnvValue, ClientEngineType, getClientEngineType } from '@prisma/sdk' +import { ClientEngineType, getClientEngineType, parseEnvValue } from '@prisma/sdk' + +import { externalToInternalDmmf } from '../runtime/externalToInternalDmmf' import { generateClient } from './generateClient' import { getDMMF } from './getDMMF' -import { externalToInternalDmmf } from '../runtime/externalToInternalDmmf' +import { dmmfToTypes } from './utils/types/dmmfToTypes' + const debug = Debug('prisma:client:generator') // As specced in https://github.com/prisma/specs/tree/master/generators const pkg = require('../../package.json') + const clientVersion = pkg.version // if the file has been run as a CLI @@ -52,4 +56,4 @@ if (process.argv[1] === __filename) { }) } -export { getDMMF, externalToInternalDmmf } +export { dmmfToTypes, externalToInternalDmmf, getDMMF } diff --git a/packages/client/src/generation/getDMMF.ts b/packages/client/src/generation/getDMMF.ts index d1a7e7365d24..21d5582daf10 100644 --- a/packages/client/src/generation/getDMMF.ts +++ b/packages/client/src/generation/getDMMF.ts @@ -1,6 +1,7 @@ import type { DMMF } from '@prisma/generator-helper' import type { GetDMMFOptions } from '@prisma/sdk' import { getDMMF as getRawDMMF } from '@prisma/sdk' + import type { DMMF as PrismaClientDMMF } from '../runtime/dmmf-types' import { externalToInternalDmmf } from '../runtime/externalToInternalDmmf' diff --git a/packages/client/src/generation/serializeDatasources.ts b/packages/client/src/generation/serializeDatasources.ts index 017254ca56b0..ada3abc14f7a 100644 --- a/packages/client/src/generation/serializeDatasources.ts +++ b/packages/client/src/generation/serializeDatasources.ts @@ -1,4 +1,5 @@ import type { DataSource } from '@prisma/generator-helper' + import type { DatasourceOverwrite } from './extractSqliteSources' // this is NOT printing datasources, but just serializing the data source diff --git a/packages/client/src/generation/utils.ts b/packages/client/src/generation/utils.ts index c9531684a225..094429ae1f45 100644 --- a/packages/client/src/generation/utils.ts +++ b/packages/client/src/generation/utils.ts @@ -1,6 +1,7 @@ import indent from 'indent-string' import path from 'path' -import type { DMMFClass } from '../runtime/dmmf' + +import type { DMMFHelper } from '../runtime/dmmf' import { DMMF } from '../runtime/dmmf-types' export enum Projection { @@ -88,12 +89,12 @@ export function getDefaultName(modelName: string): string { return `${modelName}Default` } -export function getFieldArgName(field: DMMF.SchemaField): string { - return getArgName((field.outputType.type as DMMF.OutputType).name, field.outputType.isList) +export function getFieldArgName(field: DMMF.SchemaField, findMany = true): string { + return getArgName((field.outputType.type as DMMF.OutputType).name, findMany && field.outputType.isList) } -export function getArgName(name: string, isList: boolean): string { - if (!isList) { +export function getArgName(name: string, findMany: boolean): string { + if (!findMany) { return `${name}Args` } @@ -133,10 +134,14 @@ export function getModelArgName(modelName: string, action?: DMMF.ModelAction): s return getAggregateArgsName(modelName) case DMMF.ModelAction.count: return `${modelName}CountArgs` + case DMMF.ModelAction.findRaw: + return `${modelName}FindRawArgs` + case DMMF.ModelAction.aggregateRaw: + return `${modelName}AggregateRawArgs` } } -export function getDefaultArgName(dmmf: DMMFClass, modelName: string, action: DMMF.ModelAction): string { +export function getDefaultArgName(dmmf: DMMFHelper, modelName: string, action: DMMF.ModelAction): string { const mapping = dmmf.mappings.modelOperations.find((m) => m.model === modelName)! const fieldName = mapping[action] @@ -159,7 +164,7 @@ export function getOperation(action: DMMF.ModelAction): 'query' | 'mutation' { * @param fieldName * @param mapping */ -export function renderInitialClientArgs( +export function renderInitialClientArgs( // TODO: dead code actionName: DMMF.ModelAction, fieldName: string, mapping: DMMF.ModelMapping, @@ -207,7 +212,7 @@ interface SelectReturnTypeOptions { * @param name Model name * @param actionName action name */ -export function getSelectReturnType({ +export function getReturnType({ name, actionName, renderPromise = true, @@ -219,6 +224,10 @@ export function getSelectReturnType({ } if (actionName === 'aggregate') return `Promise<${getAggregateGetName(name)}>` + if (actionName === 'findRaw' || actionName === 'aggregateRaw') { + return `PrismaPromise` + } + const isList = actionName === DMMF.ModelAction.findMany if (actionName === 'deleteMany' || actionName === 'updateMany' || actionName === 'createMany') { diff --git a/packages/client/src/generation/utils/buildDirname.ts b/packages/client/src/generation/utils/buildDirname.ts index 566350178e69..5b448d0b7666 100644 --- a/packages/client/src/generation/utils/buildDirname.ts +++ b/packages/client/src/generation/utils/buildDirname.ts @@ -24,20 +24,20 @@ export function buildDirname(clientEngineType: ClientEngineType, relativeOutdir: * feature is especially useful for Next.js/Webpack users since the client gets * moved and copied out of its original spot. It all fails, it falls-back to * `__dirname`, which is never available on bundles. - * @param relativeOutdir + * @param defaultRelativeOutdir * @param runtimePath * @returns */ -function buildDirnameFind(relativeOutdir: string, runtimePath: string) { +function buildDirnameFind(defaultRelativeOutdir: string, runtimePath: string) { // potential client location on serverless envs - const slsRelativeOutputDir = relativeOutdir.split(path.sep).slice(1).join(path.sep) + const serverlessRelativeOutdir = defaultRelativeOutdir.split(path.sep).slice(1).join(path.sep) return ` const { findSync } = require('${runtimePath}') const dirname = findSync(process.cwd(), [ - ${JSON.stringify(relativeOutdir)}, - ${JSON.stringify(slsRelativeOutputDir)}, + ${defaultRelativeOutdir ? `${JSON.stringify(defaultRelativeOutdir)},` : ''} + ${serverlessRelativeOutdir ? `${JSON.stringify(serverlessRelativeOutdir)},` : ''} ], ['d'], ['d'], 1)[0] || __dirname` } diff --git a/packages/client/src/generation/utils/buildInlineDatasources.ts b/packages/client/src/generation/utils/buildInlineDatasources.ts index 3d02bdeac7bf..665d21faf2a4 100644 --- a/packages/client/src/generation/utils/buildInlineDatasources.ts +++ b/packages/client/src/generation/utils/buildInlineDatasources.ts @@ -1,4 +1,5 @@ import { ClientEngineType } from '@prisma/sdk' + import type { InternalDatasource } from '../../runtime/utils/printDatasources' // that is all we need for the data proxy diff --git a/packages/client/src/generation/utils/buildInlineEnv.ts b/packages/client/src/generation/utils/buildInlineEnv.ts index 867425d88999..6296beac38e3 100644 --- a/packages/client/src/generation/utils/buildInlineEnv.ts +++ b/packages/client/src/generation/utils/buildInlineEnv.ts @@ -1,5 +1,6 @@ -import { tryLoadEnvs, ClientEngineType } from '@prisma/sdk' import type { EnvPaths } from '@prisma/sdk' +import { ClientEngineType, tryLoadEnvs } from '@prisma/sdk' + import type { InternalDatasource } from '../../runtime/utils/printDatasources' type LoadedEnv = { diff --git a/packages/client/src/generation/utils/buildInlineSchema.ts b/packages/client/src/generation/utils/buildInlineSchema.ts index 14644e1914a8..f9666c24e181 100644 --- a/packages/client/src/generation/utils/buildInlineSchema.ts +++ b/packages/client/src/generation/utils/buildInlineSchema.ts @@ -1,6 +1,6 @@ -import fs from 'fs' -import crypto from 'crypto' import { ClientEngineType } from '@prisma/sdk' +import crypto from 'crypto' +import fs from 'fs' const readFile = fs.promises.readFile diff --git a/packages/client/src/generation/utils/buildNFTAnnotations.ts b/packages/client/src/generation/utils/buildNFTAnnotations.ts index 3f9d082186d8..509edbfd9af0 100644 --- a/packages/client/src/generation/utils/buildNFTAnnotations.ts +++ b/packages/client/src/generation/utils/buildNFTAnnotations.ts @@ -2,6 +2,7 @@ import type { Platform } from '@prisma/get-platform' import { getNodeAPIName } from '@prisma/get-platform' import { ClientEngineType } from '@prisma/sdk' import path from 'path' + import { map } from '../../../../../helpers/blaze/map' // NFT is the Node File Trace utility by Vercel https://github.com/vercel/nft @@ -20,6 +21,8 @@ export function buildNFTAnnotations( relativeOutdir: string, ) { if (platforms === undefined) { + // TODO: should we still build the schema annotations in this case? + // Or, even better, make platforms non-nullable in TSClientOptions to avoid this check. return '' } @@ -63,9 +66,11 @@ function getQueryEngineFilename(engineType: ClientEngineType, platform: Platform * @returns */ function buildNFTAnnotation(fileName: string, relativeOutdir: string) { + const relativeFilePath = path.join(relativeOutdir, fileName) + return ` -path.join(__dirname, '${fileName}'); -path.join(process.cwd(), './${path.join(relativeOutdir, fileName)}')` +path.join(__dirname, ${JSON.stringify(fileName)}); +path.join(process.cwd(), ${JSON.stringify(relativeFilePath)})` } /** diff --git a/packages/client/src/generation/utils/types/dmmfToTypes.ts b/packages/client/src/generation/utils/types/dmmfToTypes.ts new file mode 100644 index 000000000000..1764d8b2cf00 --- /dev/null +++ b/packages/client/src/generation/utils/types/dmmfToTypes.ts @@ -0,0 +1,22 @@ +import type { DMMF } from '../../../runtime/dmmf-types' +import { TSClient } from '../../TSClient/TSClient' + +/** + * @internal + * + * @privateRemarks Used by, for example, the PDP to avoid child process calls to the CLI. + */ +export function dmmfToTypes(document: DMMF.Document) { + return new TSClient({ + document: document, + datasources: [], + projectRoot: '', + clientVersion: '', + engineVersion: '', + runtimeDir: '', + runtimeName: '', + schemaDir: '', + outputDir: '', + activeProvider: '', + }).toTS() +} diff --git a/packages/client/src/runtime/PrismaClientFetcher.ts b/packages/client/src/runtime/PrismaClientFetcher.ts deleted file mode 100644 index ed10807cf06b..000000000000 --- a/packages/client/src/runtime/PrismaClientFetcher.ts +++ /dev/null @@ -1,220 +0,0 @@ -import Debug from '@prisma/debug' -import stripAnsi from 'strip-ansi' -import { - PrismaClientInitializationError, - PrismaClientKnownRequestError, - PrismaClientRustPanicError, - PrismaClientUnknownRequestError, -} from '.' -import { DataLoader } from './DataLoader' -import type { Unpacker } from './getPrismaClient' -import type { EngineMiddleware } from './MiddlewareHandler' -import type { Document } from './query' -import { Args, unpack } from './query' -import { printStack } from './utils/printStack' -import type { RejectOnNotFound } from './utils/rejectOnNotFound' -import { throwIfNotFound } from './utils/rejectOnNotFound' -const debug = Debug('prisma:client:fetcher') - -export type RequestParams = { - document: Document - dataPath: string[] - rootField: string - typeName: string - isList: boolean - clientMethod: string - callsite?: string - rejectOnNotFound?: RejectOnNotFound - runInTransaction?: boolean - showColors?: boolean - engineHook?: EngineMiddleware - args: any - headers?: Record - transactionId?: number - unpacker?: Unpacker -} - -export class PrismaClientFetcher { - prisma: any - debug: boolean - hooks: any - dataloader: DataLoader<{ - document: Document - runInTransaction?: boolean - transactionId?: number - headers?: Record - }> - - constructor(prisma, enableDebug = false, hooks?: any) { - this.prisma = prisma - this.debug = enableDebug - this.hooks = hooks - this.dataloader = new DataLoader({ - batchLoader: (requests) => { - const queries = requests.map((r) => String(r.document)) - const runTransaction = requests[0].runInTransaction - return this.prisma._engine.requestBatch(queries, {}, runTransaction) - }, - singleLoader: (request) => { - const query = String(request.document) - return this.prisma._engine.request(query, request.headers) - }, - batchBy: (request) => { - if (request.runInTransaction) { - if (request.transactionId) { - return `transaction-batch-${request.transactionId}` - } - return 'transaction-batch' - } - - if (!request.document.children[0].name.startsWith('findUnique')) { - return undefined - } - - const selectionSet = request.document.children[0].children!.join(',') - - const args = request.document.children[0].args?.args - .map((a) => { - if (a.value instanceof Args) { - return `${a.key}-${a.value.args.map((a) => a.key).join(',')}` - } - return a.key - }) - .join(',') - - return `${request.document.children[0].name}|${args}|${selectionSet}` - }, - }) - } - get [Symbol.toStringTag]() { - return 'PrismaClientFetcher' - } - - async request({ - document, - dataPath = [], - rootField, - typeName, - isList, - callsite, - rejectOnNotFound, - clientMethod, - runInTransaction, - showColors, - engineHook, - args, - headers, - transactionId, - unpacker, - }: RequestParams) { - const cb = async () => { - if (this.hooks && this.hooks.beforeRequest) { - const query = String(document) - this.hooks.beforeRequest({ - query, - path: dataPath, - rootField, - typeName, - document, - isList, - clientMethod, - args, - }) - } - try { - /** - * If there's an engine hook, use it here - */ - let data, elapsed - if (engineHook) { - const result = await engineHook( - { - document, - runInTransaction, - }, - (params) => this.dataloader.request(params), - ) - data = result.data - elapsed = result.elapsed - } else { - const result = await this.dataloader.request({ - document, - runInTransaction, - headers, - transactionId, - }) - data = result?.data - elapsed = result?.elapsed - } - - /** - * Unpack - */ - const unpackResult = this.unpack(document, data, dataPath, rootField, unpacker) - throwIfNotFound(unpackResult, clientMethod, typeName, rejectOnNotFound) - if (process.env.PRISMA_CLIENT_GET_TIME) { - return { data: unpackResult, elapsed } - } - return unpackResult - } catch (e: any) { - debug(e) - let message = e.message - if (callsite) { - const { stack } = printStack({ - callsite, - originalMethod: clientMethod, - onUs: e.isPanic, - showColors, - }) - message = `${stack}\n ${e.message}` - } - - message = this.sanitizeMessage(message) - // TODO: Do request with callsite instead, so we don't need to rethrow - if (e.code) { - throw new PrismaClientKnownRequestError(message, e.code, this.prisma._clientVersion, e.meta) - } else if (e.isPanic) { - throw new PrismaClientRustPanicError(message, this.prisma._clientVersion) - } else if (e instanceof PrismaClientUnknownRequestError) { - throw new PrismaClientUnknownRequestError(message, this.prisma._clientVersion) - } else if (e instanceof PrismaClientInitializationError) { - throw new PrismaClientInitializationError(message, this.prisma._clientVersion) - } else if (e instanceof PrismaClientRustPanicError) { - throw new PrismaClientRustPanicError(message, this.prisma._clientVersion) - } - - e.clientVersion = this.prisma._clientVersion - - throw e - } - } - if (transactionId) { - return cb - } else { - return cb() - } - } - - sanitizeMessage(message) { - if (this.prisma._errorFormat && this.prisma._errorFormat !== 'pretty') { - return stripAnsi(message) - } - return message - } - unpack(document, data, path, rootField, unpacker?: Unpacker) { - if (data?.data) { - data = data.data - } - // to lift up _all in count - if (unpacker) { - data[rootField] = unpacker(data[rootField]) - } - - const getPath: any[] = [] - if (rootField) { - getPath.push(rootField) - } - getPath.push(...path.filter((p) => p !== 'select' && p !== 'include')) - return unpack({ document, data, path: getPath }) - } -} diff --git a/packages/client/src/runtime/RequestHandler.ts b/packages/client/src/runtime/RequestHandler.ts index 88c9d5478be5..0ea03e54ef83 100644 --- a/packages/client/src/runtime/RequestHandler.ts +++ b/packages/client/src/runtime/RequestHandler.ts @@ -1,5 +1,6 @@ import Debug from '@prisma/debug' import stripAnsi from 'strip-ansi' + import { PrismaClientInitializationError, PrismaClientKnownRequestError, @@ -14,6 +15,7 @@ import { Args, unpack } from './query' import { printStack } from './utils/printStack' import type { RejectOnNotFound } from './utils/rejectOnNotFound' import { throwIfNotFound } from './utils/rejectOnNotFound' + const debug = Debug('prisma:client:request_handler') export type RequestParams = { @@ -30,17 +32,30 @@ export type RequestParams = { engineHook?: EngineMiddleware args: any headers?: Record - transactionId?: string + transactionId?: string | number unpacker?: Unpacker } export type Request = { document: Document runInTransaction?: boolean - transactionId?: string + transactionId?: string | number headers?: Record } +function getRequestInfo(requests: Request[]) { + const txId = requests[0].transactionId + const inTx = requests[0].runInTransaction + const headers = requests[0].headers + + // if the tx has a number for an id, then it's a regular batch tx + const _inTx = typeof txId === 'number' && inTx ? true : undefined + // if the tx has a string for id, it's an interactive transaction + const _txId = typeof txId === 'string' && inTx ? txId : undefined + + return { inTx: _inTx, headers: { transactionId: _txId, ...headers } } +} + export class RequestHandler { client: Client hooks: any @@ -51,19 +66,16 @@ export class RequestHandler { this.hooks = hooks this.dataloader = new DataLoader({ batchLoader: (requests) => { + const info = getRequestInfo(requests) const queries = requests.map((r) => String(r.document)) - return this.client._engine.requestBatch(queries, { - transactionId: requests[0].transactionId, - }) + return this.client._engine.requestBatch(queries, info.headers, info.inTx) }, singleLoader: (request) => { + const info = getRequestInfo([request]) const query = String(request.document) - return this.client._engine.request(query, { - transactionId: request.transactionId, - ...request.headers, - }) + return this.client._engine.request(query, info.headers) }, batchBy: (request) => { if (request.transactionId) { diff --git a/packages/client/src/runtime/core/model/UserArgs.ts b/packages/client/src/runtime/core/model/UserArgs.ts new file mode 100644 index 000000000000..033721d2ce11 --- /dev/null +++ b/packages/client/src/runtime/core/model/UserArgs.ts @@ -0,0 +1,8 @@ +/** + * Input that flows from the user into the Client. + */ +export type UserArgs = { + [K in string]: UserArgsProp | UserArgsProp[] +} + +type UserArgsProp = UserArgs | string | number | boolean | bigint | null | undefined diff --git a/packages/client/src/runtime/core/model/aggregates/aggregate.ts b/packages/client/src/runtime/core/model/aggregates/aggregate.ts new file mode 100644 index 000000000000..e78b3b42411e --- /dev/null +++ b/packages/client/src/runtime/core/model/aggregates/aggregate.ts @@ -0,0 +1,77 @@ +import type { Client } from '../../../getPrismaClient' +import type { ModelAction } from '../applyModel' +import type { UserArgs } from '../UserArgs' +import { aggregateMap } from './utils/aggregateMap' + +/** + * Transforms the `userArgs` for the `.aggregate` shorthand. It is an API sugar + * for not having to do things like: `{select: {_avg: {select: {age: true}}}}`. + * The goal here is to desugar it into something that is understood by the QE. + * @param userArgs to transform + * @returns + */ +export function desugarUserArgs(userArgs: UserArgs) { + const _userArgs = desugarCountInUserArgs(userArgs) + const userArgsEntries = Object.entries(_userArgs) + + return userArgsEntries.reduce( + (aggregateArgs, [key, value]) => { + if (aggregateMap[key] !== undefined) { + // if it's an aggregate, we re-wrap into select + aggregateArgs['select']![key] = { select: value } + } else { + aggregateArgs[key] = value // or leave it alone + } + + return aggregateArgs + }, + { select: {} } as UserArgs & { select: UserArgs }, + ) +} + +/** + * Desugar `userArgs` when it contains `{_count: true}`. + * @param userArgs the user input + * @returns + */ +function desugarCountInUserArgs(userArgs: UserArgs) { + if (typeof userArgs['_count'] === 'boolean') { + return { ...userArgs, _count: { _all: userArgs['_count'] } } + } + + return userArgs +} + +/** + * Creates an unpacker that adds sugar to the basic result of the QE. An + * unpacker helps to transform a result before returning it to the user. + * @param userArgs the user input + * @returns + */ +export function createUnpacker(userArgs: UserArgs) { + return (data: object) => { + if (typeof userArgs['_count'] === 'boolean') { + data['_count'] = data['_count']['_all'] + } + + return data + } +} + +/** + * Executes the `.aggregate` action on a model. + * @see {desugarUserArgs} + * @param client to provide dmmf information + * @param userArgs the user input to desugar + * @param modelAction a callback action that triggers request execution + * @returns + */ +export function aggregate(client: Client, userArgs: UserArgs | undefined, modelAction: ModelAction) { + const aggregateArgs = desugarUserArgs(userArgs ?? {}) + const aggregateUnpacker = createUnpacker(userArgs ?? {}) + + return modelAction({ + action: 'aggregate', + unpacker: aggregateUnpacker, + })(aggregateArgs) +} diff --git a/packages/client/src/runtime/core/model/aggregates/count.ts b/packages/client/src/runtime/core/model/aggregates/count.ts new file mode 100644 index 000000000000..07a6fcff860b --- /dev/null +++ b/packages/client/src/runtime/core/model/aggregates/count.ts @@ -0,0 +1,27 @@ +import type { Client } from '../../../getPrismaClient' +import type { ModelAction } from '../applyModel' +import type { UserArgs } from '../UserArgs' +import { aggregate } from './aggregate' + +/** + * Executes the `.count` action on a model via {@link aggregate}. + * @param client to provide dmmf information + * @param userArgs the user input to desugar + * @param modelAction a callback action that triggers request execution + * @returns + */ +export function count(client: Client, userArgs: UserArgs | undefined, modelAction: ModelAction) { + const { select, ..._userArgs } = userArgs ?? {} // exclude select + + // count is an aggregate, we reuse that but hijack its unpacker + if (typeof select === 'object') { + // we transpose the original select field into the _count field + return aggregate(client, { ..._userArgs, _count: select }, (p) => + modelAction({ ...p, unpacker: (data) => p.unpacker?.(data)['_count'] }), + ) // for count selects, return the relevant part of the result + } else { + return aggregate(client, { ..._userArgs, _count: { _all: true } }, (p) => + modelAction({ ...p, unpacker: (data) => p.unpacker?.(data)['_count']['_all'] }), + ) // for simple counts, just return the result that is a number + } +} diff --git a/packages/client/src/runtime/core/model/aggregates/groupBy.ts b/packages/client/src/runtime/core/model/aggregates/groupBy.ts new file mode 100644 index 000000000000..1847fdea380f --- /dev/null +++ b/packages/client/src/runtime/core/model/aggregates/groupBy.ts @@ -0,0 +1,62 @@ +import type { Client } from '../../../getPrismaClient' +import type { ModelAction } from '../applyModel' +import type { UserArgs } from '../UserArgs' +import { desugarUserArgs as desugarUserArgsAggregate } from './aggregate' + +/** + * Transforms the `userArgs` for the `.groupBy` shorthand. It is an API sugar. + * It reuses the logic from the `.aggregate` shorthand and adds additional + * handling for the `by` clause. The goal here is to desugar it into something + * that is understood by the QE. + * @param userArgs to transform + * @returns + */ +function desugarUserArgs(userArgs: UserArgs) { + const _userArgs = desugarUserArgsAggregate(userArgs) + + // we desugar the array into { [key]: boolean } + if (Array.isArray(userArgs['by'])) { + for (const key of userArgs['by']) { + if (typeof key === 'string') { + _userArgs['select'][key] = true + } + } + } + + return _userArgs +} + +/** + * Creates an unpacker that adds sugar to the basic result of the QE. An + * unpacker helps to transform a result before returning it to the user. + * @param userArgs the user input + * @returns + */ +export function createUnpacker(userArgs: UserArgs) { + return (data: object[]) => { + if (typeof userArgs['_count'] === 'boolean') { + data.forEach((row) => { + row['_count'] = row['_count']['_all'] + }) + } + + return data + } +} + +/** + * Executes the `.groupBy` action on a model by reusing {@link aggregate}. + * @param client to provide dmmf information + * @param userArgs the user input to desugar + * @param modelAction a callback action that triggers request execution + * @returns + */ +export function groupBy(client: Client, userArgs: UserArgs | undefined, modelAction: ModelAction) { + const groupByArgs = desugarUserArgs(userArgs ?? {}) + const groupByUnpacker = createUnpacker(userArgs ?? {}) + + return modelAction({ + action: 'groupBy', + unpacker: groupByUnpacker, + })(groupByArgs) +} diff --git a/packages/client/src/runtime/core/model/aggregates/utils/aggregateMap.ts b/packages/client/src/runtime/core/model/aggregates/utils/aggregateMap.ts new file mode 100644 index 000000000000..fa98cb0c3548 --- /dev/null +++ b/packages/client/src/runtime/core/model/aggregates/utils/aggregateMap.ts @@ -0,0 +1,7 @@ +export const aggregateMap = { + _avg: true, + _count: true, + _sum: true, + _min: true, + _max: true, +} diff --git a/packages/client/src/runtime/core/model/applyAggregates.ts b/packages/client/src/runtime/core/model/applyAggregates.ts new file mode 100644 index 000000000000..081889991156 --- /dev/null +++ b/packages/client/src/runtime/core/model/applyAggregates.ts @@ -0,0 +1,26 @@ +import type { Action, Client } from '../../getPrismaClient' +import { aggregate } from './aggregates/aggregate' +import { count } from './aggregates/count' +import { groupBy } from './aggregates/groupBy' +import type { ModelAction } from './applyModel' +import type { UserArgs } from './UserArgs' + +/** + * Dynamically returns the appropriate aggregate action for a given `action`. + * With this, we are able to provide an aggregate api that has a better DX. In + * short, we manipulate the user input which is designed to have DX to transform + * it into something that the engines understand. Similarly, we take the engine + * output for that input and produce something that is easier to work with. + * @param client to provide dmmf information + * @param action that tells which aggregate action to execute + * @param modelAction a callback action that triggers request execution + * @returns + */ +export function applyAggregates(client: Client, action: Action, modelAction: ModelAction) { + // we effectively take over the aggregate api to perform data changes + if (action === 'aggregate') return (userArgs?: UserArgs) => aggregate(client, userArgs, modelAction) + if (action === 'count') return (userArgs?: UserArgs) => count(client, userArgs, modelAction) + if (action === 'groupBy') return (userArgs?: UserArgs) => groupBy(client, userArgs, modelAction) + + return undefined +} diff --git a/packages/client/src/runtime/core/model/applyFluent.ts b/packages/client/src/runtime/core/model/applyFluent.ts new file mode 100644 index 000000000000..909af8bfc04e --- /dev/null +++ b/packages/client/src/runtime/core/model/applyFluent.ts @@ -0,0 +1,132 @@ +import type { DMMF } from '@prisma/generator-helper' + +import type { Client } from '../../getPrismaClient' +import { deepSet } from '../../utils/deep-set' +import { getCallSite } from '../utils/getCallSite' +import type { ModelAction } from './applyModel' +import type { UserArgs } from './UserArgs' +import { defaultProxyHandlers } from './utils/defaultProxyHandlers' + +/** + * The fluent API makes that nested relations can be retrieved at once. It's a + * helper for writing `select` statements on relations with a chaining api. + * Because of this, we automatically add `select` statements to the query, that + * also means that we need to provide a `dataPath` for unpacking nested values. + * @see {getNextUserArgs} + * @param dmmfModelName + * @param prevDataPath + * @returns + */ +function getNextDataPath(fluentPropName?: string, prevDataPath?: string[]) { + if (fluentPropName === undefined || prevDataPath === undefined) return [] + + return [...prevDataPath, 'select', fluentPropName] +} + +/** + * @see {getNextDataPath} for introduction. The goal of the fluent API is to + * make it easy to retrieve nested relations. For this, we construct the query + * args that are necessary to retrieve the nested relations. It consists of + * nesting `select` statements each time that we access a relation. + * @param callArgs usually passed on the last call of the chaining api + * @param prevArgs when multiple chaining occurs, they are the previous + * @param nextDataPath path where to set `callArgs` in `prevArgs` + * @example + * ```ts + * prisma.user.findUnique().link().user() + * + * // will end up with an args like this: + * // args { + * // "where": { + * // "email": "1639498523518@gmail.com" + * // }, + * // "select": { + * // "link": { + * // "select": { + * // "user": true + * // } + * // } + * // } + * // } + * ``` + */ +function getNextUserArgs( + callArgs: UserArgs | undefined, + prevArgs: UserArgs | undefined, + nextDataPath: string[], +): UserArgs { + if (prevArgs === undefined) return callArgs ?? {} + + return deepSet(prevArgs, nextDataPath, callArgs || true) +} + +/** + * Dynamically creates a fluent API from a `modelAction` and a `dmmfModelName`. + * We use the current `dmmfModelName` to determine what can be chained on next. + * The fluent API allows to chain on model relations to provide an alternative + * way to fetch and access nested data all at once. When triggered, it calls + * `modelActions` after having accumulated `prevDataPath` and `prevUserArgs` + * with the chaining. You can find an example of usage at {@link applyModel}. + * @param client to provide dmmf information + * @param dmmfModelName the dmmf name of the model to apply the api to + * @param modelAction a callback action that triggers request execution + * @param fluentPropName the name of the api link that was just called + * @param prevDataPath the dataPath from the previous api link + * @param prevUserArgs the userArgs from the previous api link + * @remarks optional parameters are empty on the first call via + * {@link applyModel} + * @returns + */ +export function applyFluent( + client: Client, + dmmfModelName: string, + modelAction: ModelAction, + fluentPropName?: string, + prevDataPath?: string[], + prevUserArgs?: UserArgs, +) { + // we retrieve the model that is described from the DMMF + const dmmfModel = client._dmmf.modelMap[dmmfModelName] + + // map[field.name] === field, basically for quick access + const dmmfModelFieldMap = dmmfModel.fields.reduce( + (acc, field) => ({ ...acc, [field.name]: field }), + {} as { [dmmfModelFieldName: string]: DMMF.Field }, + ) + + // we return a regular model action but proxy its return + return (userArgs?: UserArgs) => { + const callsite = getCallSite() + // ! first call: nextDataPath => [], nextUserArgs => userArgs + const nextDataPath = getNextDataPath(fluentPropName, prevDataPath) + const nextUserArgs = getNextUserArgs(userArgs, prevUserArgs, nextDataPath) + const prismaPromise = modelAction({ dataPath: nextDataPath, callsite })(nextUserArgs) + // TODO: use an unpacker here instead of ClientFetcher logic + // TODO: once it's done we can deprecate the use of dataPath + const ownKeys = getOwnKeys(client, dmmfModelName) + + // we take control of the return promise to allow chaining + return new Proxy(prismaPromise, { + get(target, prop: string) { + // fluent api only works on fields that are relational + if (!ownKeys.includes(prop)) return target[prop] + + // here we are sure that prop is a field of type object + const dmmfModelName = dmmfModelFieldMap[prop].type + const modelArgs = [dmmfModelName, modelAction, prop] as const + const dataArgs = [nextDataPath, nextUserArgs] as const + + // we allow for chaining more with this recursive call + return applyFluent(client, ...modelArgs, ...dataArgs) + }, + ...defaultProxyHandlers([...ownKeys, ...Object.getOwnPropertyNames(prismaPromise)]), + }) + } +} + +// the only accessible fields are relations to be chained on +function getOwnKeys(client: Client, dmmfModelName: string) { + return client._dmmf.modelMap[dmmfModelName].fields + .filter((field) => field.kind === 'object') // relations + .map((field) => field.name) +} diff --git a/packages/client/src/runtime/core/model/applyModel.ts b/packages/client/src/runtime/core/model/applyModel.ts new file mode 100644 index 000000000000..f6899193fa13 --- /dev/null +++ b/packages/client/src/runtime/core/model/applyModel.ts @@ -0,0 +1,82 @@ +import type { F, O } from 'ts-toolbelt' + +import type { Action, Client, InternalRequestParams } from '../../getPrismaClient' +import { createPrismaPromise } from '../request/createPrismaPromise' +import type { PrismaPromise } from '../request/PrismaPromise' +import { getCallSite } from '../utils/getCallSite' +import { applyAggregates } from './applyAggregates' +import { applyFluent } from './applyFluent' +import type { UserArgs } from './UserArgs' +import { defaultProxyHandlers } from './utils/defaultProxyHandlers' +import { dmmfToJSModelName } from './utils/dmmfToJSModelName' + +export type ModelAction = ( + paramOverrides: O.Optional, +) => (userArgs?: UserArgs) => PrismaPromise + +const fluentProps = ['findUnique', 'findFirst', 'create', 'update', 'upsert', 'delete'] as const +const aggregateProps = ['aggregate', 'count', 'groupBy'] as const + +/** + * Dynamically creates a model interface via a proxy. + * @param client to trigger the request execution + * @param dmmfModelName the dmmf name of the model + * @returns + */ +export function applyModel(client: Client, dmmfModelName: string) { + // we use the javascript model name for display purposes + const jsModelName = dmmfToJSModelName(dmmfModelName) + const ownKeys = getOwnKeys(client, dmmfModelName) + const baseObject = {} // <-- user mutations go in there + + // we construct a proxy that acts as the model interface + return new Proxy(baseObject, { + get(target, prop: string): F.Return | undefined { + // only allow actions that are valid and available for this model + if (prop in target || typeof prop === 'symbol') return target[prop] + if (!isValidActionName(client, dmmfModelName, prop)) return undefined + + // we return a function as the model action that we want to expose + // it takes user args and executes the request in a Prisma Promise + const action = (paramOverrides: O.Optional) => (userArgs?: UserArgs) => { + const callSite = getCallSite(client._errorFormat) // used for showing better errors + + return createPrismaPromise((txId, lock, otelCtx) => { + const data = { args: userArgs, dataPath: [] } // data and its dataPath for nested results + const action = { action: prop, model: dmmfModelName } // action name and its related model + const method = { clientMethod: `${jsModelName}.${prop}` } // method name for display only + const tx = { runInTransaction: !!txId, transactionId: txId, lock } // transaction information + const trace = { callsite: callSite, otelCtx: otelCtx } // stack trace and opentelemetry + const params = { ...data, ...action, ...method, ...tx, ...trace } + + return client._request({ ...params, ...paramOverrides }) + }) + } + + // we give the control over action for building the fluent api + if (fluentProps.includes(prop as typeof fluentProps[number])) { + return applyFluent(client, dmmfModelName, action) + } + + // we handle the edge case of aggregates that need extra steps + if (aggregateProps.includes(prop as typeof aggregateProps[number])) { + return applyAggregates(client, prop, action) + } + + return action({}) // and by default, don't override any params + }, + ...defaultProxyHandlers(ownKeys), + }) +} + +// the only accessible fields are the ones that are actions +function getOwnKeys(client: Client, dmmfModelName: string) { + return [...Object.keys(client._dmmf.mappingsMap[dmmfModelName]), 'count'].filter( + (key) => !['model', 'plural'].includes(key), + ) +} + +// tells if a given `action` is valid & available for a `model` +function isValidActionName(client: Client, dmmfModelName: string, action: string): action is Action { + return getOwnKeys(client, dmmfModelName).includes(action) +} diff --git a/packages/client/src/runtime/core/model/applyModels.ts b/packages/client/src/runtime/core/model/applyModels.ts new file mode 100644 index 000000000000..160f65862752 --- /dev/null +++ b/packages/client/src/runtime/core/model/applyModels.ts @@ -0,0 +1,48 @@ +import type { Client } from '../../getPrismaClient' +import { applyModel } from './applyModel' +import { defaultProxyHandlers } from './utils/defaultProxyHandlers' +import { dmmfToJSModelName } from './utils/dmmfToJSModelName' +import { jsToDMMFModelName } from './utils/jsToDMMFModelName' + +/** + * Dynamically creates a model proxy interface for a give name. For each prop + * accessed on this proxy, it will lookup the dmmf to find if that model exists. + * If it is the case, it will create a proxy for that model via {@link applyModel}. + * @param client to create the proxy around + * @returns a proxy to access models + */ +export function applyModels(client: C) { + // we don't want to create a new proxy on each prop access + const modelCache = {} as { [key: string]: object } + const ownKeys = getOwnKeys(client) + + return new Proxy(client, { + get(target, prop) { + // return base property if it already exists in client + if (prop in target || typeof prop === 'symbol') return target[prop] + + const dmmfModelName = jsToDMMFModelName(prop) + + // see if a model proxy has already been created before + if (modelCache[dmmfModelName] !== undefined) { + return modelCache[dmmfModelName] + } + + // creates a new model proxy on the fly and caches it + if (client._dmmf.modelMap[dmmfModelName] !== undefined) { + return (modelCache[dmmfModelName] = applyModel(client, dmmfModelName)) + } + + // above silently failed if model name is lower cased + if (client._dmmf.modelMap[prop] !== undefined) { + return (modelCache[dmmfModelName] = applyModel(client, prop)) + } + }, + ...defaultProxyHandlers(ownKeys), + }) +} + +// the only accessible fields are the ones that are models +function getOwnKeys(client: Client) { + return [...Object.keys(client._dmmf.modelMap).map(dmmfToJSModelName), ...Object.keys(client)] +} diff --git a/packages/client/src/runtime/core/model/utils/defaultProxyHandlers.ts b/packages/client/src/runtime/core/model/utils/defaultProxyHandlers.ts new file mode 100644 index 000000000000..d319fb1294f2 --- /dev/null +++ b/packages/client/src/runtime/core/model/utils/defaultProxyHandlers.ts @@ -0,0 +1,17 @@ +const defaultPropertyDescriptor = { + enumerable: true, + configurable: true, + writable: true, +} + +export function defaultProxyHandlers(ownKeys: (string | symbol)[]) { + const _ownKeys = new Set(ownKeys) + return { + getOwnPropertyDescriptor: () => defaultPropertyDescriptor, + has: (target: never, prop: string | symbol) => _ownKeys.has(prop), + set: (target: never, prop: string | symbol, value: any) => { + return _ownKeys.add(prop) && Reflect.set(target, prop, value) + }, + ownKeys: () => [..._ownKeys], + } as const +} diff --git a/packages/client/src/runtime/core/model/utils/dmmfToJSModelName.ts b/packages/client/src/runtime/core/model/utils/dmmfToJSModelName.ts new file mode 100644 index 000000000000..8d5efc5cbf27 --- /dev/null +++ b/packages/client/src/runtime/core/model/utils/dmmfToJSModelName.ts @@ -0,0 +1,8 @@ +/** + * Transforms a model name coming from the DMMF to a runtime model name. + * @param name + * @returns + */ +export function dmmfToJSModelName(name: string) { + return name.replace(/^./, (str) => str.toLowerCase()) +} diff --git a/packages/client/src/runtime/core/model/utils/jsToDMMFModelName.ts b/packages/client/src/runtime/core/model/utils/jsToDMMFModelName.ts new file mode 100644 index 000000000000..a6a7c378f4cf --- /dev/null +++ b/packages/client/src/runtime/core/model/utils/jsToDMMFModelName.ts @@ -0,0 +1,8 @@ +/** + * Transforms a model name coming from the runtime to a DMMF model name. + * @param name + * @returns + */ +export function jsToDMMFModelName(name: string) { + return name.replace(/^./, (str) => str.toUpperCase()) +} diff --git a/packages/client/src/runtime/core/request/PrismaPromise.ts b/packages/client/src/runtime/core/request/PrismaPromise.ts new file mode 100644 index 000000000000..0334384955f8 --- /dev/null +++ b/packages/client/src/runtime/core/request/PrismaPromise.ts @@ -0,0 +1,38 @@ +/** + * Prisma's `Promise` that is backwards-compatible. All additions on top of the + * original `Promise` are optional so that it can be backwards-compatible. + * @see [[createPrismaPromise]] + */ +export interface PrismaPromise extends Promise { + /** + * Extension of the original `.then` function + * @param onfulfilled same as regular promises + * @param onrejected same as regular promises + * @param txId GUID for interactive txs + */ + then( + onfulfilled?: (value: A) => R1 | PromiseLike, + onrejected?: (error: unknown) => R2 | PromiseLike, + txId?: string, + ): Promise + + /** + * Extension of the original `.catch` function + * @param onrejected same as regular promises + * @param txId GUID for interactive txs + */ + catch(onrejected?: ((reason: any) => R | PromiseLike) | undefined | null, txId?: string): Promise + + /** + * Extension of the original `.finally` function + * @param onfinally same as regular promises + * @param txId GUID for interactive txs + */ + finally(onfinally?: (() => void) | undefined | null, txId?: string): Promise + + /** + * Called when executing a batch of regular tx + * @param txId for regular tx ids + */ + requestTransaction?(txId: number, lock?: PromiseLike): PromiseLike +} diff --git a/packages/client/src/runtime/core/request/createPrismaPromise.ts b/packages/client/src/runtime/core/request/createPrismaPromise.ts new file mode 100644 index 000000000000..58837de6e99b --- /dev/null +++ b/packages/client/src/runtime/core/request/createPrismaPromise.ts @@ -0,0 +1,55 @@ +import type { Context } from '@opentelemetry/api' +import { context } from '@opentelemetry/api' + +import type { PrismaPromise } from './PrismaPromise' + +/** + * Creates a [[PrismaPromise]]. It is Prisma's implementation of `Promise` which + * is essentially a proxy for `Promise`. All the transaction-compatible client + * methods return one, this allows for pre-preparing queries without executing + * them until `.then` is called. It's the foundation of Prisma's query batching. + * @param callback that will be wrapped within our promise implementation + * @see [[PrismaPromise]] + * @returns + */ +export function createPrismaPromise( + callback: (txId?: string | number, lock?: PromiseLike, otelCtx?: Context) => PrismaPromise, +): PrismaPromise { + const otelCtx = context.active() // get the context at time of creation + // because otel isn't able to propagate context when inside of a promise + + let promise: PrismaPromise | undefined + const _callback = (txId?: string | number, lock?: PromiseLike) => { + try { + // we allow the callback to be executed only one time + return (promise ??= callback(txId, lock, otelCtx)) + } catch (error) { + // if the callback throws, then we reject the promise + // and that is because exceptions are not always async + return Promise.reject(error) as PrismaPromise + } + } + + return { + then(onFulfilled, onRejected, txId?: string) { + return _callback(txId).then(onFulfilled, onRejected, txId) + }, + catch(onRejected, txId?: string) { + return _callback(txId).catch(onRejected, txId) + }, + finally(onFinally, txId?: string) { + return _callback(txId).finally(onFinally, txId) + }, + requestTransaction(txId: number, lock?: PromiseLike) { + const promise = _callback(txId, lock) + + if (promise.requestTransaction) { + // we want to have support for nested promises + return promise.requestTransaction(txId, lock) + } + + return promise + }, + [Symbol.toStringTag]: 'PrismaPromise', + } +} diff --git a/packages/client/src/runtime/core/transaction/utils/createLockCountPromise.ts b/packages/client/src/runtime/core/transaction/utils/createLockCountPromise.ts new file mode 100644 index 000000000000..868bc35a945f --- /dev/null +++ b/packages/client/src/runtime/core/transaction/utils/createLockCountPromise.ts @@ -0,0 +1,22 @@ +/** + * Creates an exotic promise that opens after x `await`s. + * @remarks + * This is currently used for locking regular transactions. + * This ensures that all queries are executed at once/batched. + * Even if middlewares are in use, they'll all execute at once. + * @param knock the amount of awaits to open the promise + * @param cb the callback to execute and value to return + * @returns + */ +export function getLockCountPromise(knock: number, cb: () => V | void = () => {}) { + let resolve: (v: V | void) => void + const lock = new Promise((res) => (resolve = res)) + + return { + then(onFulfilled) { + if (--knock === 0) resolve(cb()) + + return onFulfilled?.(lock as unknown as V | void) + }, + } as PromiseLike +} diff --git a/packages/client/src/runtime/core/utils/getCallSite.ts b/packages/client/src/runtime/core/utils/getCallSite.ts new file mode 100644 index 000000000000..fe6794cb34f8 --- /dev/null +++ b/packages/client/src/runtime/core/utils/getCallSite.ts @@ -0,0 +1,12 @@ +/** + * Gets information about where this was called from. + * @param errorFormat + * @returns + */ +export function getCallSite(errorFormat?: string) { + if (errorFormat === 'minimal') { + return undefined + } + + return new Error().stack +} diff --git a/packages/client/src/runtime/dmmf.ts b/packages/client/src/runtime/dmmf.ts index e8714c0e12f8..3762b59c69ff 100644 --- a/packages/client/src/runtime/dmmf.ts +++ b/packages/client/src/runtime/dmmf.ts @@ -1,8 +1,9 @@ import type { DMMF } from '@prisma/generator-helper' + import type { Dictionary } from './utils/common' -import { keyBy, keyBy2, ScalarTypeTable } from './utils/common' +import { keyBy, ScalarTypeTable } from './utils/common' -export class DMMFClass implements DMMF.Document { +export class DMMFHelper implements DMMF.Document { public datamodel: DMMF.Datamodel public schema: DMMF.Schema public mappings: DMMF.Mappings @@ -22,6 +23,8 @@ export class DMMFClass implements DMMF.Document { public datamodelEnumMap: Dictionary public modelMap: Dictionary + public typeMap: Dictionary + public typeAndModelMap: Dictionary public mappingsMap: Dictionary public rootFieldMap: Dictionary constructor({ datamodel, schema, mappings }: DMMF.Document) { @@ -34,6 +37,8 @@ export class DMMFClass implements DMMF.Document { this.queryType = this.getQueryType() this.mutationType = this.getMutationType() this.modelMap = this.getModelMap() + this.typeMap = this.getTypeMap() + this.typeAndModelMap = this.getTypeModelMap() this.outputTypes = this.getOutputTypes() @@ -159,7 +164,13 @@ export class DMMFClass implements DMMF.Document { } } protected getModelMap(): Dictionary { - return keyBy(this.datamodel.models, 'name') + return { ...keyBy(this.datamodel.models, 'name') } + } + protected getTypeMap(): Dictionary { + return { ...keyBy(this.datamodel.types, 'name') } + } + protected getTypeModelMap(): Dictionary { + return { ...this.getTypeMap(), ...this.getModelMap() } } protected getMergedOutputTypeMap(): Dictionary { return { @@ -177,6 +188,6 @@ export class DMMFClass implements DMMF.Document { return keyBy(this.mappings.modelOperations, 'model') } protected getRootFieldMap(): Dictionary { - return keyBy2(this.queryType.fields, this.mutationType.fields, 'name') + return { ...keyBy(this.queryType.fields, 'name'), ...keyBy(this.mutationType.fields, 'name') } } } diff --git a/packages/client/src/runtime/externalToInternalDmmf.ts b/packages/client/src/runtime/externalToInternalDmmf.ts index a26239654454..fc63d61fd7f2 100644 --- a/packages/client/src/runtime/externalToInternalDmmf.ts +++ b/packages/client/src/runtime/externalToInternalDmmf.ts @@ -1,5 +1,6 @@ import type { DMMF as ExternalDMMF } from '@prisma/generator-helper' import pluralize from 'pluralize' + import type { DMMF } from './dmmf-types' import { capitalize, lowerCase } from './utils/common' @@ -27,9 +28,10 @@ function getMappings(mappings: ExternalDMMF.Mappings, datamodel: DMMF.Datamodel) } return model.fields.some((f) => f.kind !== 'object') }) + // TODO most of this is probably not needed anymore .map((mapping: any) => ({ model: mapping.model, - plural: pluralize(lowerCase(mapping.model)), + plural: pluralize(lowerCase(mapping.model)), // TODO not needed anymore findUnique: mapping.findUnique || mapping.findSingle, findFirst: mapping.findFirst, findMany: mapping.findMany, @@ -42,6 +44,8 @@ function getMappings(mappings: ExternalDMMF.Mappings, datamodel: DMMF.Datamodel) upsert: mapping.upsertOne || mapping.upsertSingle || mapping.upsert, aggregate: mapping.aggregate, groupBy: mapping.groupBy, + findRaw: mapping.findRaw, + aggregateRaw: mapping.aggregateRaw, })) return { diff --git a/packages/client/src/runtime/getPrismaClient.ts b/packages/client/src/runtime/getPrismaClient.ts index fb5fa34fbf96..ebced57e3ff3 100644 --- a/packages/client/src/runtime/getPrismaClient.ts +++ b/packages/client/src/runtime/getPrismaClient.ts @@ -1,38 +1,40 @@ +import type { Context } from '@opentelemetry/api' import Debug from '@prisma/debug' import type { DatasourceOverwrite, Engine, EngineConfig, EngineEventType } from '@prisma/engine-core' -import { LibraryEngine } from '@prisma/engine-core' -import { BinaryEngine } from '@prisma/engine-core' -import { DataProxyEngine } from '@prisma/engine-core' +import { BinaryEngine, DataProxyEngine, LibraryEngine } from '@prisma/engine-core' import type { DataSource, GeneratorConfig } from '@prisma/generator-helper' -import { logger } from '@prisma/sdk' -import { mapPreviewFeatures } from '@prisma/sdk' -import { tryLoadEnvs } from '@prisma/sdk' -import { ClientEngineType, getClientEngineType } from '@prisma/sdk' +import { ClientEngineType, getClientEngineType, logger, mapPreviewFeatures, tryLoadEnvs } from '@prisma/sdk' +import type { LoadedEnv } from '@prisma/sdk/dist/utils/tryLoadEnvs' import { AsyncResource } from 'async_hooks' import fs from 'fs' import path from 'path' import * as sqlTemplateTag from 'sql-template-tag' -import { DMMFClass } from './dmmf' + +import type { InlineDatasources } from '../generation/utils/buildInlineDatasources' +import { PrismaClientValidationError } from '.' +import { applyModels } from './core/model/applyModels' +import { createPrismaPromise } from './core/request/createPrismaPromise' +import type { PrismaPromise } from './core/request/PrismaPromise' +import { getLockCountPromise } from './core/transaction/utils/createLockCountPromise' +import { getCallSite } from './core/utils/getCallSite' +import { DMMFHelper } from './dmmf' import { DMMF } from './dmmf-types' import { getLogLevel } from './getLogLevel' import { mergeBy } from './mergeBy' import type { EngineMiddleware, Namespace, QueryMiddleware, QueryMiddlewareParams } from './MiddlewareHandler' import { Middlewares } from './MiddlewareHandler' -import { PrismaClientFetcher } from './PrismaClientFetcher' import { makeDocument, transformDocument } from './query' +import { RequestHandler } from './RequestHandler' import { clientVersion } from './utils/clientVersion' -import { getOutputTypeName, lowerCase } from './utils/common' -import { deepSet } from './utils/deep-set' +import { getOutputTypeName } from './utils/common' import { mssqlPreparedStatement } from './utils/mssqlPreparedStatement' +import { applyTracingHeaders } from './utils/otel/applyTracingHeaders' +import { runInChildSpan } from './utils/otel/runInChildSpan' import { printJsonWithErrors } from './utils/printJsonErrors' import type { InstanceRejectOnNotFound, RejectOnNotFound } from './utils/rejectOnNotFound' import { getRejectOnNotFound } from './utils/rejectOnNotFound' import { serializeRawParameters } from './utils/serializeRawParameters' import { validatePrismaClientOptions } from './utils/validatePrismaClientOptions' -import { RequestHandler } from './RequestHandler' -import { PrismaClientValidationError } from '.' -import type { LoadedEnv } from '@prisma/sdk/dist/utils/tryLoadEnvs' -import type { InlineDatasources } from '../generation/utils/buildInlineDatasources' const debug = Debug('prisma:client') const ALTER_RE = /^(\s*alter\s)/i @@ -117,7 +119,6 @@ export interface PrismaClientOptions { __internal?: { debug?: boolean hooks?: Hooks - useUds?: boolean engine?: { cwd?: string binaryPath?: string @@ -139,7 +140,7 @@ export type HookParams = { args: any } -export type Action = DMMF.ModelAction | 'executeRaw' | 'queryRaw' +export type Action = keyof typeof DMMF.ModelAction | 'executeRaw' | 'queryRaw' | 'runCommandRaw' export type InternalRequestParams = { /** @@ -150,9 +151,12 @@ export type InternalRequestParams = { */ clientMethod: string // TODO what is this callsite?: string // TODO what is this + /** Headers metadata that will be passed to the Engine */ headers?: Record // TODO what is this - transactionId?: number // TODO what is this + transactionId?: string | number unpacker?: Unpacker // TODO what is this + otelCtx?: Context // an otel context + lock?: PromiseLike } & QueryMiddlewareParams // only used by the .use() hooks @@ -260,22 +264,21 @@ const actionOperationMap = { queryRaw: 'mutation', aggregate: 'query', groupBy: 'query', + runCommandRaw: 'mutation', + findRaw: 'query', + aggregateRaw: 'query', } -const aggregateKeys = { - _avg: true, - _count: true, - _sum: true, - _min: true, - _max: true, -} +const TX_ID = Symbol.for('prisma.client.transaction.id') // TODO improve all these types, need a common place to share them between type // gen and this. This will be relevant relevant for type gen tech debt refactor export interface Client { - _dmmf: DMMFClass + /** Only via tx proxy */ + [TX_ID]?: string + _dmmf: DMMFHelper _engine: Engine - _fetcher: PrismaClientFetcher + _fetcher: RequestHandler _connectionPromise?: Promise _disconnectionPromise?: Promise _engineConfig: EngineConfig @@ -290,13 +293,14 @@ export interface Client { $queryRaw(query: TemplateStringsArray | sqlTemplateTag.Sql, ...values: any[]) __internal_triggerPanic(fatal: boolean) $transaction(input: any, options?: any) + _request(internalParams: InternalRequestParams): Promise } export function getPrismaClient(config: GetPrismaClientConfig) { class PrismaClient implements Client { - _dmmf: DMMFClass + _dmmf: DMMFHelper _engine: Engine - _fetcher: PrismaClientFetcher + _fetcher: RequestHandler _connectionPromise?: Promise _disconnectionPromise?: Promise _engineConfig: EngineConfig @@ -377,7 +381,7 @@ export function getPrismaClient(config: GetPrismaClientConfig) { this._errorFormat = 'colorless' // default errorFormat } - this._dmmf = new DMMFClass(config.document) + this._dmmf = new DMMFHelper(config.document) this._previewFeatures = config.generator?.previewFeatures ?? [] @@ -405,7 +409,6 @@ export function getPrismaClient(config: GetPrismaClientConfig) { flags: [], clientVersion: config.clientVersion, previewFeatures: mapPreviewFeatures(this._previewFeatures), - useUds: internal.useUds, activeProvider: config.activeProvider, inlineSchema: config.inlineSchema, inlineDatasources: config.inlineDatasources, @@ -426,12 +429,7 @@ export function getPrismaClient(config: GetPrismaClientConfig) { this._engine = this.getEngine() void this._getActiveProvider() - // eslint-disable-next-line prettier/prettier - if (!this._hasPreviewFlag('interactiveTransactions')) { - this._fetcher = new PrismaClientFetcher(this, false, this._hooks) - } else { - this._fetcher = new RequestHandler(this, this._hooks) as any - } + this._fetcher = new RequestHandler(this, this._hooks) as any if (options.log) { for (const log of options.log) { @@ -443,12 +441,12 @@ export function getPrismaClient(config: GetPrismaClientConfig) { } } } - - this._bootstrapClient() } catch (e: any) { e.clientVersion = this._clientVersion throw e } + + return applyModels(this) // custom constructor return value } get [Symbol.toStringTag]() { return 'PrismaClient' @@ -556,11 +554,12 @@ export function getPrismaClient(config: GetPrismaClientConfig) { } /** - * Executes a raw query. Always returns a number + * Executes a raw query and always returns a number */ private $executeRawInternal( - runInTransaction: boolean, - transactionId: number | undefined, + txId: string | number | undefined, + lock: PromiseLike | undefined, + otelCtx: Context | undefined, query: string | TemplateStringsArray | sqlTemplateTag.Sql, ...values: sqlTemplateTag.RawValue[] ) { @@ -653,33 +652,14 @@ export function getPrismaClient(config: GetPrismaClientConfig) { clientMethod: 'executeRaw', dataPath: [], action: 'executeRaw', - callsite: this._getCallsite(), - runInTransaction, - transactionId: transactionId, + callsite: getCallSite(this._errorFormat), + runInTransaction: !!txId, + transactionId: txId, + otelCtx: otelCtx, + lock, }) } - /** - * Executes a raw query and always returns a number - */ - private $executeRawRequest( - query: string | TemplateStringsArray | sqlTemplateTag.Sql, - ...values: sqlTemplateTag.RawValue[] - ) { - const request = (transactionId?: number, runInTransaction?: boolean) => { - try { - const promise = this.$executeRawInternal(runInTransaction ?? false, transactionId, query, ...values) - ;(promise as any).isExecuteRaw = true - return promise - } catch (e: any) { - e.clientVersion = this._clientVersion - throw e - } - } - - return createPrismaPromise(request) - } - /** * Executes a raw query provided through a safe tag function * @see https://github.com/prisma/prisma/issues/7142 @@ -689,9 +669,9 @@ export function getPrismaClient(config: GetPrismaClientConfig) { * @returns */ $executeRaw(query: TemplateStringsArray | sqlTemplateTag.Sql, ...values: any[]) { - return createPrismaPromise(() => { + return createPrismaPromise((txId, lock, otelCtx) => { if ((query as TemplateStringsArray).raw || (query as sqlTemplateTag.Sql).sql) { - return this.$executeRawRequest(query, ...values) + return this.$executeRawInternal(txId, lock, otelCtx, query, ...values) } throw new PrismaClientValidationError(`\`$executeRaw\` is a tag function, please use it like the following: @@ -713,22 +693,46 @@ Or read our docs at https://www.prisma.io/docs/concepts/components/prisma-client * @returns */ $executeRawUnsafe(query: string, ...values: sqlTemplateTag.RawValue[]) { - return this.$executeRawRequest(query, ...values) + return createPrismaPromise((txId, lock, otelCtx) => { + return this.$executeRawInternal(txId, lock, otelCtx, query, ...values) + }) } - private _getCallsite() { - if (this._errorFormat !== 'minimal') { - return new Error().stack + /** + * Executes a raw command only for MongoDB + * + * @param command + * @returns + */ + $runCommandRaw(command: object) { + if (config.activeProvider !== 'mongodb') { + throw new PrismaClientValidationError( + `The ${config.activeProvider} provider does not support $runCommandRaw. Use the mongodb provider.`, + ) } - return undefined + + return createPrismaPromise((txId, lock, otelCtx) => { + return this._request({ + args: { command: command }, + clientMethod: 'runCommandRaw', + dataPath: [], + action: 'runCommandRaw', + callsite: getCallSite(), + runInTransaction: !!txId, + transactionId: txId, + otelCtx: otelCtx, + lock, + }) + }) } /** * Executes a raw query and returns selected data */ private $queryRawInternal( - runInTransaction: boolean, - transactionId: number | undefined, + txId: string | number | undefined, + lock: PromiseLike | undefined, + otelCtx: Context | undefined, query: string | TemplateStringsArray | sqlTemplateTag.Sql, ...values: sqlTemplateTag.RawValue[] ) { @@ -824,33 +828,14 @@ Or read our docs at https://www.prisma.io/docs/concepts/components/prisma-client clientMethod: 'queryRaw', dataPath: [], action: 'queryRaw', - callsite: this._getCallsite(), - runInTransaction, - transactionId: transactionId, + callsite: getCallSite(this._errorFormat), + runInTransaction: !!txId, + transactionId: txId, + otelCtx: otelCtx, + lock, }) } - /** - * Executes a raw query and returns selected data - */ - private $queryRawRequest( - query: string | TemplateStringsArray | sqlTemplateTag.Sql, - ...values: sqlTemplateTag.RawValue[] - ) { - const request = (transactionId?: number, runInTransaction?: boolean) => { - try { - const promise = this.$queryRawInternal(runInTransaction ?? false, transactionId, query, ...values) - ;(promise as any).isQueryRaw = true - return promise - } catch (e: any) { - e.clientVersion = this._clientVersion - throw e - } - } - - return createPrismaPromise(request) - } - /** * Executes a raw query provided through a safe tag function * @see https://github.com/prisma/prisma/issues/7142 @@ -860,9 +845,9 @@ Or read our docs at https://www.prisma.io/docs/concepts/components/prisma-client * @returns */ $queryRaw(query: TemplateStringsArray | sqlTemplateTag.Sql, ...values: any[]) { - return createPrismaPromise(() => { + return createPrismaPromise((txId, lock, otelCtx) => { if ((query as TemplateStringsArray).raw || (query as sqlTemplateTag.Sql).sql) { - return this.$queryRawRequest(query, ...values) + return this.$queryRawInternal(txId, lock, otelCtx, query, ...values) } throw new PrismaClientValidationError(`\`$queryRaw\` is a tag function, please use it like the following: @@ -884,7 +869,9 @@ Or read our docs at https://www.prisma.io/docs/concepts/components/prisma-client * @returns */ $queryRawUnsafe(query: string, ...values: sqlTemplateTag.RawValue[]) { - return this.$queryRawRequest(query, ...values) + return createPrismaPromise((txId, lock, otelCtx) => { + return this.$queryRawInternal(txId, lock, otelCtx, query, ...values) + }) } __internal_triggerPanic(fatal: boolean) { @@ -913,107 +900,30 @@ new PrismaClient({ dataPath: [], runInTransaction: false, headers, - callsite: this._getCallsite(), + callsite: getCallSite(this._errorFormat), }) } /** - * @deprecated + * Execute a batch of requests in a transaction + * @param requests + * @param options */ - private ___getTransactionId() { - return this._transactionId++ - } + private _transactionWithArray(promises: Array>): Promise { + const txId = this._transactionId++ + const lock = getLockCountPromise(promises.length) - /** - * @deprecated - */ - private async $___transactionInternal(promises: Array): Promise { - for (const p of promises) { - if (!p) { + const _requests = promises.map((request) => { + if (request?.[Symbol.toStringTag] !== 'PrismaPromise') { throw new Error( `All elements of the array need to be Prisma Client promises. Hint: Please make sure you are not awaiting the Prisma client calls you intended to pass in the $transaction function.`, ) } - if ( - (!p.requestTransaction || typeof p.requestTransaction !== 'function') && - !p?.isQueryRaw && - !p?.isExecuteRaw - ) { - throw new Error( - `All elements of the array need to be Prisma Client promises. Hint: Please make sure you are not awaiting the Prisma client calls you intended to pass in the $transaction function.`, - ) - } - } - - const transactionId = this.___getTransactionId() - - const requests = await Promise.all( - promises.map((p) => { - if (p.requestTransaction) { - return p.requestTransaction(transactionId) - } else { - } - return p - }), - ) - - return Promise.all( - requests.map((r) => { - if (Object.prototype.toString.call(r) === '[object Promise]') { - return r - } - if (r && typeof r === 'function') { - return r() - } - return r - }), - ) - } - - /** - * @deprecated - */ - private async $___transaction(promises: Array): Promise { - try { - return this.$___transactionInternal(promises) - } catch (e: any) { - e.clientVersion = this._clientVersion - throw e - } - } - /** - * Execute queries within a transaction - * @param input a callback or a query list - * @param options to set timeouts - * @returns - */ - $transaction(input: any, options?: any) { - // eslint-disable-next-line prettier/prettier - if (!this._hasPreviewFlag('interactiveTransactions')) { - return this.$___transaction(input) - } - - try { - return this._transaction(input, options) - } catch (e: any) { - e.clientVersion = this._clientVersion - throw e - } - } - - /** - * Decide upon which transaction logic to use - * @param input - * @param options - * @returns - */ - private async _transaction(input: any, options?: any) { - if (typeof input === 'function') { - return this._transactionWithCallback(input, options) - } + return request.requestTransaction?.(txId, lock) + }) - return this._transactionWithRequests(input, options) + return Promise.all(_requests) } /** @@ -1038,36 +948,32 @@ new PrismaClient({ await this._engine.transaction('commit', info) } catch (e: any) { // it went bad, then we rollback the transaction - await this._engine.transaction('rollback', info) + await this._engine.transaction('rollback', info).catch(() => {}) - throw e + e.clientVersion = this._clientVersion + throw e // silent rollback, throw original error } return result } /** - * Execute a batch of requests in a transaction - * @param requests - * @param options + * Execute queries within a transaction + * @param input a callback or a query list + * @param options to set timeouts (callback) + * @returns */ - private async _transactionWithRequests( - requests: Array>, - options?: { maxWait: number; timeout: number }, - ) { - return this._transactionWithCallback(async (prisma) => { - const transactionId: string = prisma[TX_ID] // some proxy magic - - const _requests = requests.map((request) => { - return new Promise((resolve, reject) => { - // each request has already been called with `prisma.` - // so we inject `transactionId` by intercepting that promise - ;(request as any).then(resolve, reject, transactionId) - }) - }) + async $transaction(input: any, options?: any) { + // TODO: remove this once interactive tx became GA + if (!this._hasPreviewFlag('interactiveTransactions')) { + return this._transactionWithArray(input) + } + + if (typeof input === 'function') { + return this._transactionWithCallback(input, options) + } - return Promise.all(_requests) // get results from `BatchLoader` - }, options) + return this._transactionWithArray(input) } /** @@ -1076,7 +982,10 @@ new PrismaClient({ * @param middlewareIndex * @returns */ - private _request(internalParams: InternalRequestParams): Promise { + async _request(internalParams: InternalRequestParams): Promise { + // TODO remove this check once tracing is no longer in preview + if (!this._hasPreviewFlag('tracing')) delete internalParams['otelCtx'] + try { // make sure that we don't leak extra properties to users const params: QueryMiddlewareParams = { @@ -1093,36 +1002,33 @@ new PrismaClient({ // if this `next` was called and there's some more middlewares const nextMiddleware = this._middlewares.query.get(++index) - if (nextMiddleware) { - // we pass the modified params down to the next one, & repeat - return nextMiddleware(changedParams, consumer) - } + // we pass the modified params down to the next one, & repeat + // calling `next` calls the consumer again with the new params + if (nextMiddleware) return nextMiddleware(changedParams, consumer) + // before we send the execution request, we use the changed params const changedInternalParams = { ...internalParams, ...changedParams } - // TODO remove this once LRT is the default transaction mode - if (index > 0 && !this._hasPreviewFlag('interactiveTransactions')) { - delete changedInternalParams['transactionId'] - } - // no middleware? then we just proceed with request execution return this._executeRequest(changedInternalParams) } if (globalThis.NOT_PRISMA_DATA_PROXY) { - // async scope https://github.com/prisma/prisma/issues/3148 - const resource = new AsyncResource('prisma-client-request') - return resource.runInAsyncScope(() => consumer(params)) + // https://github.com/prisma/prisma/issues/3148 not for the data proxy + return await new AsyncResource('prisma-client-request').runInAsyncScope(() => { + return runInChildSpan('request', internalParams.otelCtx, () => consumer(params)) + }) } - return consumer(params) + // we execute the middleware consumer and wrap the call for otel + return await runInChildSpan('request', internalParams.otelCtx, () => consumer(params)) } catch (e: any) { e.clientVersion = this._clientVersion throw e } } - private _executeRequest({ + private async _executeRequest({ args, clientMethod, dataPath, @@ -1132,21 +1038,14 @@ new PrismaClient({ model, headers, transactionId, + otelCtx, + lock, unpacker, }: InternalRequestParams) { - if (action !== 'executeRaw' && action !== 'queryRaw' && !model) { - throw new Error(`Model missing for action ${action}`) - } - - if ((action === 'executeRaw' || action === 'queryRaw') && model) { - throw new Error( - `executeRaw and queryRaw can't be executed on a model basis. The model ${model} has been provided`, - ) - } let rootField: string | undefined const operation = actionOperationMap[action] - if (action === 'executeRaw' || action === 'queryRaw') { + if (action === 'executeRaw' || action === 'queryRaw' || action === 'runCommandRaw') { rootField = action } @@ -1205,6 +1104,10 @@ new PrismaClient({ debug(query + '\n') } + headers = applyTracingHeaders(headers, otelCtx) + + await lock /** @see {@link getLockCountPromise} */ + return this._fetcher.request({ document, clientMethod, @@ -1224,253 +1127,6 @@ new PrismaClient({ }) } - private _bootstrapClient() { - const modelClientBuilders = this._dmmf.mappings.modelOperations.reduce((modelClientBuilders, modelMapping) => { - const lowerCaseModel = lowerCase(modelMapping.model) - const model = this._dmmf.modelMap[modelMapping.model] - - if (!model) { - throw new Error(`Invalid mapping ${modelMapping.model}, can't find model`) - } - - // creates a builder for `prisma...` in the runtime so that - // all models will get their own sub-"client" for query execution - const ModelClientBuilder = ({ - operation, - actionName, - args, - dataPath, - modelName, - unpacker, - }: { - operation: string - actionName: Action - args: any - dataPath: string[] - modelName: string - unpacker?: Unpacker - }) => { - let requestPromise: Promise | undefined - - // prepare a request with current context & prevent multi-calls we - // save it into `requestPromise` to allow one request per promise - const callsite = this._getCallsite() - const request = (transactionId?: number, runInTransaction?: boolean) => { - requestPromise = - requestPromise ?? - this._request({ - args, - model: modelName ?? model.name, - action: actionName, - clientMethod: `${lowerCaseModel}.${actionName}`, - dataPath: dataPath, - callsite: callsite, - runInTransaction: runInTransaction ?? false, - transactionId: transactionId, - unpacker, - }) - - return requestPromise - } - - // `modelClient` implements promises to have deferred actions that - // will be called later on through model delegated functions - const modelClient = createPrismaPromise(request) - - // add relation fields - for (const field of model.fields.filter((f) => f.kind === 'object')) { - modelClient[field.name] = (fieldArgs) => { - const prefix = dataPath.includes('select') - ? 'select' - : dataPath.includes('include') - ? 'include' - : 'select' - const newDataPath = [...dataPath, prefix, field.name] - const newArgs = deepSet(args, newDataPath, fieldArgs || true) - - // TODO: ask dom if it can be anything else than a string - return modelClientBuilders[field.type as string]({ - operation, - actionName, - args: newArgs, - dataPath: newDataPath, - isList: field.isList, - /* - * necessary for user.posts() calls -> the original model name needs to be preserved - */ - modelName: modelName || model.name, - }) - } - } - - return modelClient - } - - modelClientBuilders[model.name] = ModelClientBuilder - - return modelClientBuilders - }, {}) - - for (const mapping of this._dmmf.mappings.modelOperations) { - const lowerCaseModel = lowerCase(mapping.model) - - const filteredActionsList = { - model: true, - plural: true, - aggregate: true, - groupBy: true, - } - - // here we call the `modelClientBuilder` inside of each delegate function - // once triggered, the function will return the `modelClient` from above - const delegate: any = Object.keys(mapping).reduce((acc, actionName) => { - if (!filteredActionsList[actionName]) { - const operation = getOperation(actionName as any) - acc[actionName] = (args) => - modelClientBuilders[mapping.model]({ - operation, - actionName, - dataPath: [], - args, - }) - } - - return acc - }, {}) - - delegate.count = (args) => { - let select - let unpacker: Unpacker | undefined - if (args?.select && typeof args?.select === 'object') { - select = { _count: { select: args.select } } - } else { - select = { _count: { select: { _all: true } } } - unpacker = (data) => { - data._count = data._count?._all - return data - } - } - - return modelClientBuilders[mapping.model]({ - operation: 'query', - actionName: `aggregate`, - args: { - ...(args ?? {}), - select, - }, - dataPath: ['_count'], - unpacker, - }) - } - - delegate.aggregate = (args) => { - /** - * _avg, _count, _sum, _min, _max need to go into select - * For speed reasons we can go with "for in " - */ - let unpacker: Unpacker | undefined = undefined - const select = Object.entries(args).reduce((acc, [key, value]) => { - // if it is an aggregate like "_avg", wrap it with "select" - if (aggregateKeys[key]) { - if (!acc.select) { - acc.select = {} - } - // `_count` doesn't have a sub-selection - if (key === '_count' || key === 'count') { - if (typeof value === 'object' && value) { - acc.select[key] = { select: value } - } else { - acc.select[key] = { select: { _all: value } } - unpacker = (data) => { - if (data._count) { - data._count = data._count?._all - } else if (data.count) { - data.count = data.count?._all - } - return data - } - } - } else { - acc.select[key] = { select: value } - } - } else { - acc[key] = value - } - return acc - }, {} as any) - - return modelClientBuilders[mapping.model]({ - operation: 'query', - actionName: 'aggregate', // actionName is just cosmetics 💅🏽 - rootField: mapping.aggregate, - args: select, - dataPath: [], - unpacker, - }) - } - - delegate.groupBy = (args) => { - let unpacker: Unpacker | undefined = undefined - - /** - * _avg, _count, _sum, _min, _max need to go into select - * For speed reasons we can go with "for in " - */ - const select = Object.entries(args).reduce((acc, [key, value]) => { - // if it is an aggregate like "_avg", wrap it with "select" - if (aggregateKeys[key]) { - if (!acc.select) { - acc.select = {} - } - - acc.select[key] = { select: value } - // otherwise leave it alone - } else { - acc[key] = value - } - if (key === '_count') { - if (typeof value === 'object' && value) { - acc.select[key] = { select: value } - } else if (typeof value === 'boolean') { - acc.select[key] = { select: { _all: value } } - unpacker = (data) => { - if (Array.isArray(data)) { - data = data.map((row) => { - if (row && typeof row._count === 'object' && row._count?._all) { - row._count = row._count?._all - } - return row - }) - } - return data - } - } - } - if (key === 'by' && Array.isArray(value) && value.length > 0) { - if (!acc.select) { - acc.select = {} - } - for (const by of value) { - acc.select[by] = true - } - } - return acc - }, {} as any) - - return modelClientBuilders[mapping.model]({ - operation: 'query', - actionName: 'groupBy', // actionName is just cosmetics 💅🏽 - rootField: mapping.groupBy, - args: select, - dataPath: [], - unpacker, - }) - } - - this[lowerCaseModel] = delegate - } - } - /** * Shortcut for checking a preview flag * @param feature preview flag @@ -1484,16 +1140,15 @@ new PrismaClient({ return PrismaClient as new (optionsArg?: PrismaClientOptions) => Client } -const TX_ID = Symbol.for('prisma.client.transaction.id') const forbidden = ['$connect', '$disconnect', '$on', '$transaction', '$use'] /** - * Proxy that takes over client promises to pass `transactionId` + * Proxy that takes over the client promises to pass `txId` * @param thing to be proxied - * @param transactionId to be passed down to `_query` + * @param txId to be passed down to {@link RequestHandler} * @returns */ -function transactionProxy(thing: T, transactionId: string): T { +function transactionProxy(thing: T, txId: string): T { // we only wrap within a proxy if it's possible: if it's an object if (typeof thing !== 'object') return thing @@ -1502,102 +1157,27 @@ function transactionProxy(thing: T, transactionId: string): T { // we don't want to allow any calls to our `forbidden` methods if (forbidden.includes(prop as string)) return undefined - // secret accessor to get the `transactionId` in a transaction - if (prop === TX_ID) return transactionId + if (prop === TX_ID) return txId // secret accessor to the txId + // we override and handle every function call within the proxy if (typeof target[prop] === 'function') { - // we override & handle every function call within the proxy return (...args: unknown[]) => { - if (prop === 'then') { - // this is our promise, we pass it an extra info argument - // this will call "our" `then` which will call `_request` - return target[prop](...args, transactionId) - } + // we hijack promise calls to pass txId to prisma promises + if (prop === 'then') return target[prop](args[0], args[1], txId) + if (prop === 'catch') return target[prop](args[0], txId) + if (prop === 'finally') return target[prop](args[0], txId) - // if it's not the end promise, continue wrapping as it goes - return transactionProxy(target[prop](...args), transactionId) + // if it's not the end promise, result is also tx-proxied + return transactionProxy(target[prop](...args), txId) } } - // probably an object, not the end, continue wrapping as it goes - return transactionProxy(target[prop], transactionId) + // if it's an object prop, then we keep on making it proxied + return transactionProxy(target[prop], txId) }, }) as any as T } -/** - * Prisma's `Promise` that is backwards-compatible. All additions on top of the - * original `Promise` are optional so that it can be backwards-compatible. - * @see [[createPrismaPromise]] - */ -interface PrismaPromise extends Promise { - /** - * Extension of the original `.then` function - * @param onfulfilled same as regular promises - * @param onrejected same as regular promises - * @param transactionId for interactive tx ids - */ - then( - onfulfilled?: (value: A) => R1 | PromiseLike, - onrejected?: (error: unknown) => R2 | PromiseLike, - transactionId?: number, - ): Promise - - /** - * Called when executing a batch of regular tx - * @param id for regular tx ids - */ - requestTransaction?(id: number): PromiseLike -} - -/** - * Creates a [[PrismaPromise]]. It is Prisma's implementation of `Promise` which - * is essentially a proxy for `Promise`. All the transaction-compatible client - * methods return one, this allows for pre-preparing queries without executing - * them until `.then` is called. It's the foundation of Prisma's query batching. - * @param callback that will be wrapped within our promise implementation - * @see [[PrismaPromise]] - * @returns - */ -function createPrismaPromise( - callback: (transactionId?: number, runInTransaction?: boolean) => PrismaPromise, -): PrismaPromise { - // we handle exceptions that happen in the scope as `Promise` rejections - const _callback = (transactionId?: number, runInTransaction?: boolean) => { - try { - return callback(transactionId, runInTransaction) - } catch (error) { - // and that is because exceptions are not always async - return Promise.reject(error) as PrismaPromise - } - } - - return { - then(onFulfilled, onRejected, transactionId?: number) { - const promise = _callback(transactionId, false) - - return promise.then(onFulfilled, onRejected, transactionId) - }, - catch(onRejected) { - return _callback().catch(onRejected) - }, - finally(onFinally) { - return _callback().finally(onFinally) - }, - requestTransaction(transactionId: number) { - const promise = _callback(transactionId, true) - - if (promise.requestTransaction) { - // requestTransaction support for nested promises - return promise.requestTransaction(transactionId) - } - - return promise - }, - [Symbol.toStringTag]: 'PrismaPromise', - } -} - export function getOperation(action: DMMF.ModelAction): 'query' | 'mutation' { if ( action === DMMF.ModelAction.findMany || diff --git a/packages/client/src/runtime/highlight/prism.ts b/packages/client/src/runtime/highlight/prism.ts index d77301c2bdc3..aff0a65a7737 100644 --- a/packages/client/src/runtime/highlight/prism.ts +++ b/packages/client/src/runtime/highlight/prism.ts @@ -19,17 +19,12 @@ let uniqueId = 0 export var Prism: any = { manual: _self.Prism && _self.Prism.manual, - disableWorkerMessageHandler: - _self.Prism && _self.Prism.disableWorkerMessageHandler, + disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, util: { encode: function (tokens: any) { if (tokens instanceof Token) { const anyTokens: any = tokens - return new Token( - anyTokens.type, - Prism.util.encode(anyTokens.content), - anyTokens.alias, - ) + return new Token(anyTokens.type, Prism.util.encode(anyTokens.content), anyTokens.alias) } else if (Array.isArray(tokens)) { return tokens.map(Prism.util.encode) } else { @@ -188,15 +183,7 @@ export var Prism: any = { return Token.stringify(Prism.util.encode(env.tokens), env.language) }, - matchGrammar: function ( - text, - strarr, - grammar, - index, - startPos, - oneshot, - target?: any, - ) { + matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target?: any) { for (const token in grammar) { if (!grammar.hasOwnProperty(token) || !grammar[token]) { continue @@ -226,11 +213,7 @@ export var Prism: any = { pattern = pattern.pattern || pattern // Don’t cache length as it changes during the loop - for ( - let i = index, pos = startPos; - i < strarr.length; - pos += strarr[i].length, ++i - ) { + for (let i = index, pos = startPos; i < strarr.length; pos += strarr[i].length, ++i) { let str = strarr[i] if (strarr.length > text.length) { @@ -254,11 +237,7 @@ export var Prism: any = { k = i, p = pos - for ( - let len = strarr.length; - k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); - ++k - ) { + for (let len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) { p += strarr[k].length // Move the index i to the element in strarr that is closest to from if (from >= p) { @@ -309,13 +288,7 @@ export var Prism: any = { args.push(before) } - const wrapped = new Token( - token, - inside ? Prism.tokenize(match, inside) : match, - alias, - match, - greedy, - ) + const wrapped = new Token(token, inside ? Prism.tokenize(match, inside) : match, alias, match, greedy) args.push(wrapped) @@ -325,8 +298,7 @@ export var Prism: any = { Array.prototype.splice.apply(strarr, args) - if (delNum != 1) - Prism.matchGrammar(text, strarr, grammar, i, pos, true, token) + if (delNum != 1) Prism.matchGrammar(text, strarr, grammar, i, pos, true, token) if (oneshot) break } @@ -396,15 +368,13 @@ Prism.languages.clike = { greedy: true, }, 'class-name': { - pattern: - /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i, + pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i, lookbehind: true, inside: { punctuation: /[.\\]/, }, }, - keyword: - /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, + keyword: /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, boolean: /\b(?:true|false)\b/, function: /\w+(?=\()/, number: /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, @@ -416,8 +386,7 @@ Prism.languages.javascript = Prism.languages.extend('clike', { 'class-name': [ Prism.languages.clike['class-name'], { - pattern: - /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, + pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, lookbehind: true, }, ], @@ -435,10 +404,8 @@ Prism.languages.javascript = Prism.languages.extend('clike', { number: /\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/, // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) - function: - /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, - operator: - /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/, + function: /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, + operator: /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/, }) Prism.languages.javascript['class-name'][0].pattern = @@ -459,8 +426,7 @@ Prism.languages.insertBefore('javascript', 'keyword', { }, parameter: [ { - pattern: - /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, + pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, lookbehind: true, inside: Prism.languages.javascript, }, @@ -493,20 +459,12 @@ Prism.languages.typescript = Prism.languages.extend('javascript', { // From JavaScript Prism keyword list and TypeScript language spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words keyword: /\b(?:abstract|as|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|var|void|while|with|yield)\b/, - builtin: - /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/, + builtin: /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/, }) Prism.languages.ts = Prism.languages.typescript -export function Token( - this: any, - type, - content, - alias, - matchedStr?: any, - greedy?: any, -) { +export function Token(this: any, type, content, alias, matchedStr?: any, greedy?: any) { this.type = type this.content = content this.alias = alias diff --git a/packages/client/src/runtime/highlight/theme.ts b/packages/client/src/runtime/highlight/theme.ts index 4b4b3b35147c..0ee83401cb9c 100644 --- a/packages/client/src/runtime/highlight/theme.ts +++ b/packages/client/src/runtime/highlight/theme.ts @@ -1,4 +1,5 @@ import chalk from 'chalk' + import type { Theme } from './types' export const orange = chalk.rgb(246, 145, 95) diff --git a/packages/client/src/runtime/index.ts b/packages/client/src/runtime/index.ts index 493aee373cfc..4b65160e455b 100644 --- a/packages/client/src/runtime/index.ts +++ b/packages/client/src/runtime/index.ts @@ -1,27 +1,22 @@ -export { DMMF } from './dmmf-types' -export { DMMFClass } from './dmmf' -export { makeDocument, transformDocument, unpack, PrismaClientValidationError } from './query' +import * as lzString from 'lz-string' +export { DMMFHelper as DMMFClass } from './dmmf' +export { DMMF } from './dmmf-types' +export type { PrismaClientOptions } from './getPrismaClient' +export { getPrismaClient } from './getPrismaClient' +export { makeDocument, PrismaClientValidationError, transformDocument, unpack } from './query' +export { findSync } from './utils/find' +export { warnEnvConflicts } from './warnEnvConflicts' export { Engine, - PrismaClientKnownRequestError, - PrismaClientUnknownRequestError, PrismaClientInitializationError, + PrismaClientKnownRequestError, PrismaClientRustPanicError, + PrismaClientUnknownRequestError, } from '@prisma/engine-core' -export { getPrismaClient } from './getPrismaClient' -export type { PrismaClientOptions } from './getPrismaClient' - -export { Sql, empty, join, raw, sqltag } from 'sql-template-tag' -export type { RawValue, Value } from 'sql-template-tag' - -export { warnEnvConflicts } from './warnEnvConflicts' - export { default as Decimal } from 'decimal.js' - -export { findSync } from './utils/find' - -import * as lzString from 'lz-string' +export type { RawValue, Value } from 'sql-template-tag' +export { empty, join, raw, Sql, sqltag } from 'sql-template-tag' // ! export bundling fails for this dep, we work around it const decompressFromBase64 = lzString.decompressFromBase64 export { decompressFromBase64 } diff --git a/packages/client/src/runtime/query.ts b/packages/client/src/runtime/query.ts index cf95b5022423..255ad4532eb5 100644 --- a/packages/client/src/runtime/query.ts +++ b/packages/client/src/runtime/query.ts @@ -2,7 +2,8 @@ import chalk from 'chalk' import Decimal from 'decimal.js' import indent from 'indent-string' import stripAnsi from 'strip-ansi' -import type { /*dmmf, */ DMMFClass } from './dmmf' + +import type { /*dmmf, */ DMMFHelper } from './dmmf' import type { DMMF } from './dmmf-types' import type { ArgError, @@ -434,7 +435,6 @@ ${errorMessages}${missingArgsLegend}\n` const newPath: Array = [] let key: undefined | string | number let pointer = select - // tslint:disable-next-line:no-conditional-assignment while ((key = path.shift()) !== undefined) { if (!Array.isArray(pointer) && key === 0) { continue @@ -768,7 +768,7 @@ ${indent(value.toString(), 2)} export type ArgValue = string | boolean | number | undefined | Args | string[] | boolean[] | number[] | Args[] | null export interface DocumentInput { - dmmf: DMMFClass + dmmf: DMMFHelper rootTypeName: 'query' | 'mutation' rootField: string select?: any @@ -799,7 +799,7 @@ export function transformDocument(document: Document): Document { } export function selectionToFields( - dmmf: DMMFClass, + dmmf: DMMFHelper, selection: any, schemaField: DMMF.SchemaField, path: string[], @@ -836,6 +836,7 @@ export function selectionToFields( field.outputType.location === 'scalar' && field.name !== 'executeRaw' && field.name !== 'queryRaw' && + field.name !== 'runCommandRaw' && outputType.name !== 'Query' && !name.startsWith('aggregate') && field.name !== 'count' // TODO: Find a cleaner solution @@ -1005,7 +1006,7 @@ export function selectionToFields( } } // either use select or default selection, but not both at the same time - const defaultSelection = isRelation ? getDefaultSelection(field.outputType.type as DMMF.OutputType) : null + const defaultSelection = isRelation ? getDefaultSelection(dmmf, field.outputType.type as DMMF.OutputType) : null let select = defaultSelection if (value) { @@ -1050,12 +1051,15 @@ function byToSelect(by: string[]): Record { return obj } -function getDefaultSelection(outputType: DMMF.OutputType) { +function getDefaultSelection(dmmf: DMMFHelper, outputType: DMMF.OutputType) { const acc = Object.create(null) for (const f of outputType.fields) { + if (dmmf.typeMap[(f.outputType.type as DMMF.OutputType).name] !== undefined) { + acc[f.name] = true // by default, we load composite fields + } if (f.outputType.location === 'scalar' || f.outputType.location === 'enumTypes') { - acc[f.name] = true + acc[f.name] = true // by default, we load all scalar fields } } @@ -1184,9 +1188,10 @@ function hasCorrectScalarType(value: any, arg: DMMF.SchemaArg, inputType: DMMF.S return true } - if (!arg.isRequired && value === null) { + if (value === null) { return true } + return false } diff --git a/packages/client/src/runtime/utils/common.ts b/packages/client/src/runtime/utils/common.ts index ebf2e1697697..f23e8bd34674 100644 --- a/packages/client/src/runtime/utils/common.ts +++ b/packages/client/src/runtime/utils/common.ts @@ -1,9 +1,10 @@ import chalk from 'chalk' +import Decimal from 'decimal.js' import indent from 'indent-string' import leven from 'js-levenshtein' + +import type { DMMFHelper } from '../dmmf' import type { DMMF } from '../dmmf-types' -import Decimal from 'decimal.js' -import type { DMMFClass } from '../dmmf' export interface Dictionary { [key: string]: T @@ -19,25 +20,6 @@ export const keyBy: (collection: T[], prop: string) => Dictionary = (colle return acc } -export const keyBy2: (collection1: T[], collection2: T[], prop: string) => Dictionary = ( - collection1, - collection2, - prop, -) => { - const acc = {} - - for (const obj of collection1) { - const key = obj[prop] - acc[key] = obj - } - - for (const obj of collection2) { - const key = obj[prop] - acc[key] = obj - } - return acc -} - export const ScalarTypeTable = { String: true, Int: true, @@ -65,7 +47,7 @@ export const needNamespace = { Decimal: 'Decimal', } -export function needsNamespace(fieldType: DMMF.Field['type'], dmmf: DMMFClass): boolean { +export function needsNamespace(fieldType: DMMF.SchemaField['outputType']['type'], dmmf: DMMFHelper): boolean { if (typeof fieldType === 'string') { if (dmmf.datamodelEnumMap[fieldType]) { return false diff --git a/packages/client/src/runtime/utils/dedent.ts b/packages/client/src/runtime/utils/dedent.ts index 9f53cb941187..9285ad3dce74 100644 --- a/packages/client/src/runtime/utils/dedent.ts +++ b/packages/client/src/runtime/utils/dedent.ts @@ -1,4 +1,5 @@ import strip from 'strip-indent' + export function dedent(str: string): string { return strip(str) } diff --git a/packages/client/src/runtime/utils/deep-extend.ts b/packages/client/src/runtime/utils/deep-extend.ts index d4c636bbc408..749775c44ad2 100644 --- a/packages/client/src/runtime/utils/deep-extend.ts +++ b/packages/client/src/runtime/utils/deep-extend.ts @@ -27,8 +27,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* tslint:disable */ - function isSpecificValue(val) { return val instanceof Buffer || val instanceof Date || val instanceof RegExp ? true : false } diff --git a/packages/client/src/runtime/utils/deep-set.ts b/packages/client/src/runtime/utils/deep-set.ts index b8f769e389f7..4ad79f1a577f 100644 --- a/packages/client/src/runtime/utils/deep-set.ts +++ b/packages/client/src/runtime/utils/deep-set.ts @@ -1,5 +1,4 @@ // Taken from https://gist.github.com/LukeChannings/15c92cef5a016a8b21a0 -/* tslint:disable */ // ensure the keys being passed is an array of key paths // example: 'a.b' becomes ['a', 'b'] unless it was already ['a', 'b'] diff --git a/packages/client/src/runtime/utils/otel/applyTracingHeaders.ts b/packages/client/src/runtime/utils/otel/applyTracingHeaders.ts new file mode 100644 index 000000000000..df02e588a5b6 --- /dev/null +++ b/packages/client/src/runtime/utils/otel/applyTracingHeaders.ts @@ -0,0 +1,20 @@ +import type { Context } from '@opentelemetry/api' +import { trace } from '@opentelemetry/api' + +/** + * Adds the open telemetry span context to the Engine headers. + * @param headers to add traceparent to + * @param otelCtx to get the active span + */ +export function applyTracingHeaders(headers: Record | undefined, otelCtx: Context | undefined) { + const span = otelCtx && trace.getSpanContext(otelCtx) + + if (span?.traceFlags === 1 /** if we are tracing */) { + return { + traceparent: `00-${span.traceId}-${span.spanId}-01`, + ...headers, + } + } + + return headers ?? {} +} diff --git a/packages/client/src/runtime/utils/otel/runInChildSpan.ts b/packages/client/src/runtime/utils/otel/runInChildSpan.ts new file mode 100644 index 000000000000..ee2a44cd494e --- /dev/null +++ b/packages/client/src/runtime/utils/otel/runInChildSpan.ts @@ -0,0 +1,26 @@ +import type { Context, Span, Tracer } from '@opentelemetry/api' +import { context, trace } from '@opentelemetry/api' + +/** + * Executes and traces a function inside of a child span. + * @param name of the child span + * @param parentCtx parent ctx for the child span + * @param cb to trace in the child span + * @returns + */ +export async function runInChildSpan( + name: string, + parentCtx: Context | undefined, + cb: (child: Span | undefined) => Promise, +) { + if (parentCtx === undefined) return cb(undefined) + + const tracer = trace.getTracer('prisma') // it's prisma tracing + const childSpan = tracer.startSpan(name, undefined, parentCtx) + const childCtx = trace.setSpan(parentCtx, childSpan) + const result = await context.with(childCtx, () => cb(childSpan)) + + childSpan?.end() + + return result +} diff --git a/packages/client/src/runtime/utils/printDatasources.ts b/packages/client/src/runtime/utils/printDatasources.ts index 3bec008b56f1..419117d8651f 100644 --- a/packages/client/src/runtime/utils/printDatasources.ts +++ b/packages/client/src/runtime/utils/printDatasources.ts @@ -1,6 +1,13 @@ import type { Dictionary } from './common' -export type ConnectorType = 'mysql' | 'mongodb' | 'sqlite' | 'postgresql' | 'sqlserver' | 'jdbc:sqlserver' +export type ConnectorType = + | 'mysql' + | 'mongodb' + | 'sqlite' + | 'postgresql' + | 'sqlserver' + | 'jdbc:sqlserver' + | 'cockroachdb' export interface GeneratorConfig { name: string diff --git a/packages/client/src/runtime/utils/printJsonErrors.ts b/packages/client/src/runtime/utils/printJsonErrors.ts index ebcf2760235c..dbc30933a1fa 100644 --- a/packages/client/src/runtime/utils/printJsonErrors.ts +++ b/packages/client/src/runtime/utils/printJsonErrors.ts @@ -1,5 +1,6 @@ import chalk from 'chalk' import stripAnsi from 'strip-ansi' + import { deepSet } from './deep-set' import stringifyObject from './stringifyObject' diff --git a/packages/client/src/runtime/utils/printStack.ts b/packages/client/src/runtime/utils/printStack.ts index f8b09a85b12c..22290ac9fd89 100644 --- a/packages/client/src/runtime/utils/printStack.ts +++ b/packages/client/src/runtime/utils/printStack.ts @@ -1,5 +1,6 @@ import chalk from 'chalk' import * as stackTraceParser from 'stacktrace-parser' + import { highlightTS } from '../highlight/highlight' import { dedent } from './dedent' @@ -83,7 +84,8 @@ function parseStack({ !t.file.includes('getPrismaClient') && !t.file.startsWith('internal/') && // We don't want internal nodejs files !t.methodName.includes('new ') && - !t.methodName.includes('_getCallsite') && + !t.methodName.includes('getCallSite') && + !t.methodName.includes('Proxy.') && t.methodName.split('.').length < 4 ) }) diff --git a/packages/client/src/runtime/utils/rejectOnNotFound.ts b/packages/client/src/runtime/utils/rejectOnNotFound.ts index 35c1a443ebd7..732be407d2e8 100644 --- a/packages/client/src/runtime/utils/rejectOnNotFound.ts +++ b/packages/client/src/runtime/utils/rejectOnNotFound.ts @@ -1,4 +1,5 @@ import { isError } from '@prisma/sdk' + import type { Action } from '../getPrismaClient' export type RejectOnNotFound = boolean | ((error: Error) => Error) | undefined diff --git a/packages/client/src/runtime/utils/stringifyObject.ts b/packages/client/src/runtime/utils/stringifyObject.ts index 6d5fe01fb574..eb2ff75d2cf6 100644 --- a/packages/client/src/runtime/utils/stringifyObject.ts +++ b/packages/client/src/runtime/utils/stringifyObject.ts @@ -6,8 +6,6 @@ const getOwnEnumPropSymbols = require('get-own-enumerable-property-symbols').def // Fork of https://github.com/yeoman/stringify-object/blob/master/index.js // with possibility to overwrite the whole key-value pair (options.transformLine) -/* tslint:disable */ - const stringifyObject = (input, options?: any, pad?: any) => { const seen: any[] = [] diff --git a/packages/client/src/runtime/utils/validatePrismaClientOptions.ts b/packages/client/src/runtime/utils/validatePrismaClientOptions.ts index 491545c2a747..698f7f5c7e22 100644 --- a/packages/client/src/runtime/utils/validatePrismaClientOptions.ts +++ b/packages/client/src/runtime/utils/validatePrismaClientOptions.ts @@ -1,5 +1,6 @@ import { isError } from '@prisma/sdk' import leven from 'js-levenshtein' + import type { ErrorFormat, LogLevel, PrismaClientOptions } from '../getPrismaClient' import { PrismaClientConstructorValidationError } from '../query' @@ -121,7 +122,7 @@ It should have this form: { url: "CONNECTION_STRING" }`, if (!value) { return } - const knownKeys = ['debug', 'hooks', 'useUds', 'engine', 'measurePerformance'] + const knownKeys = ['debug', 'hooks', 'engine', 'measurePerformance'] if (typeof value !== 'object') { throw new PrismaClientConstructorValidationError( `Invalid value ${JSON.stringify(value)} for "__internal" to PrismaClient constructor`, diff --git a/packages/client/src/utils/compilerWorker.js b/packages/client/src/utils/compilerWorker.js index d9d4c700fd9c..28786c8df90b 100644 --- a/packages/client/src/utils/compilerWorker.js +++ b/packages/client/src/utils/compilerWorker.js @@ -1,9 +1,4 @@ -const { - createCompilerHost, - createProgram, - ModuleKind, - ScriptTarget, -} = require('typescript') +const { createCompilerHost, createProgram, ModuleKind, ScriptTarget } = require('typescript') const ts = require('typescript') function compileFile(filePath) { diff --git a/packages/client/src/utils/generateInFolder.ts b/packages/client/src/utils/generateInFolder.ts index c4a818c1558d..d889581944b2 100644 --- a/packages/client/src/utils/generateInFolder.ts +++ b/packages/client/src/utils/generateInFolder.ts @@ -1,16 +1,25 @@ import Debug from '@prisma/debug' import { getEnginesPath } from '@prisma/engines' import { getNodeAPIName, getPlatform } from '@prisma/get-platform' -import { extractPreviewFeatures, getConfig, getDMMF, getPackedPackage, mapPreviewFeatures } from '@prisma/sdk' -import { ClientEngineType, getClientEngineType } from '@prisma/sdk' +import { + ClientEngineType, + extractPreviewFeatures, + getClientEngineType, + getConfig, + getDMMF, + getPackedPackage, + mapPreviewFeatures, +} from '@prisma/sdk' import copy from '@timsuchanek/copy' import fs from 'fs' import path from 'path' import { performance } from 'perf_hooks' import rimraf from 'rimraf' import { promisify } from 'util' + import { generateClient } from '../generation/generateClient' import { ensureTestClientQueryEngine } from './ensureTestClientQueryEngine' + const debug = Debug('prisma:generateInFolder') const del = promisify(rimraf) diff --git a/packages/client/src/utils/getTestClient.ts b/packages/client/src/utils/getTestClient.ts index 19f47d5bea7b..a0fedb1abad5 100644 --- a/packages/client/src/utils/getTestClient.ts +++ b/packages/client/src/utils/getTestClient.ts @@ -1,18 +1,19 @@ import { getPlatform } from '@prisma/get-platform' import { extractPreviewFeatures, + getClientEngineType, getConfig, getEnvPaths, getRelativeSchemaPath, mapPreviewFeatures, parseEnvValue, printConfigWarnings, - getClientEngineType, } from '@prisma/sdk' import fs from 'fs' import path from 'path' import { parse } from 'stacktrace-parser' import { promisify } from 'util' + import { getDMMF } from '../generation/getDMMF' import type { GetPrismaClientConfig } from '../runtime/getPrismaClient' import { getPrismaClient } from '../runtime/getPrismaClient' @@ -26,11 +27,9 @@ const readFile = promisify(fs.readFile) * Returns an in-memory client for testing */ export async function getTestClient(schemaDir?: string, printWarnings?: boolean): Promise { - if (!schemaDir) { - const callsite = parse(new Error('').stack!) - schemaDir = path.dirname(callsite[1].file!) - } - const schemaPath = await getRelativeSchemaPath(schemaDir) + const callSite = path.dirname(require.main?.filename ?? '') + const absSchemaDir = path.resolve(callSite, schemaDir ?? '') + const schemaPath = await getRelativeSchemaPath(absSchemaDir) const datamodel = await readFile(schemaPath!, 'utf-8') const config = await getConfig({ datamodel, ignoreEnvVarErrors: true }) if (printWarnings) { @@ -48,14 +47,14 @@ export async function getTestClient(schemaDir?: string, printWarnings?: boolean) datamodel, previewFeatures, }) - const outputDir = schemaDir - const relativeEnvPaths = getEnvPaths(schemaPath, { cwd: schemaDir }) + const outputDir = absSchemaDir + const relativeEnvPaths = getEnvPaths(schemaPath, { cwd: absSchemaDir }) const activeProvider = config.datasources[0].activeProvider const options: GetPrismaClientConfig = { document, generator, - dirname: schemaDir, - relativePath: path.relative(outputDir, schemaDir), + dirname: absSchemaDir, + relativePath: path.relative(outputDir, absSchemaDir), clientVersion: 'client-test-version', engineVersion: 'engine-test-version', relativeEnvPaths, diff --git a/packages/client/src/utils/setupMysql.ts b/packages/client/src/utils/setupMysql.ts index 08ad950f1164..aae88b70205d 100644 --- a/packages/client/src/utils/setupMysql.ts +++ b/packages/client/src/utils/setupMysql.ts @@ -1,7 +1,7 @@ -import fs from 'fs' -import path from 'path' import { createDatabase, uriToCredentials } from '@prisma/sdk' +import fs from 'fs' import mariadb from 'mariadb' +import path from 'path' export type SetupParams = { connectionString: string diff --git a/packages/client/src/utils/setupPostgres.ts b/packages/client/src/utils/setupPostgres.ts index 2826c281c9fc..3b194e69e742 100644 --- a/packages/client/src/utils/setupPostgres.ts +++ b/packages/client/src/utils/setupPostgres.ts @@ -1,6 +1,6 @@ +import { createDatabase, credentialsToUri, uriToCredentials } from '@prisma/sdk' import fs from 'fs' import path from 'path' -import { createDatabase, uriToCredentials, credentialsToUri } from '@prisma/sdk' import { Client } from 'pg' export type SetupParams = { diff --git a/packages/client/src/utilsdmmf.json b/packages/client/src/utilsdmmf.json index 2ea3b0fc6a28..58e63e8449c5 100644 --- a/packages/client/src/utilsdmmf.json +++ b/packages/client/src/utilsdmmf.json @@ -2334,14 +2334,7 @@ "enums": [ { "name": "BlogOrderByInput", - "values": [ - "id_ASC", - "id_DESC", - "name_ASC", - "name_DESC", - "viewCount_ASC", - "viewCount_DESC" - ] + "values": ["id_ASC", "id_DESC", "name_ASC", "name_DESC", "viewCount_ASC", "viewCount_DESC"] }, { "name": "AuthorOrderByInput", diff --git a/packages/client/tsconfig.build.json b/packages/client/tsconfig.build.json index 8d0663f9999d..05e900d10910 100644 --- a/packages/client/tsconfig.build.json +++ b/packages/client/tsconfig.build.json @@ -4,5 +4,5 @@ "outDir": "declaration", "emitDeclarationOnly": true }, - "include": ["src/runtime"], + "include": ["src/runtime"] } diff --git a/packages/client/tsconfig.eslint.json b/packages/client/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/client/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index c3a3fc68528f..66bcc692d04c 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -1,9 +1,4 @@ { "extends": "../../tsconfig.json", - "exclude": [ - "node_modules", - "declaration", - "generator-build", - "runtime" - ] -} \ No newline at end of file + "exclude": ["node_modules", "declaration", "generator-build", "runtime"] +} diff --git a/packages/debug/.eslintignore b/packages/debug/.eslintignore deleted file mode 100644 index 76add878f8dd..000000000000 --- a/packages/debug/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/packages/debug/.eslintrc.js b/packages/debug/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/debug/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/debug/jest.config.js b/packages/debug/jest.config.js index 90066d6b0b74..1376a7a2e051 100644 --- a/packages/debug/jest.config.js +++ b/packages/debug/jest.config.js @@ -1,9 +1,21 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', + testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], - testMatch: ['**/src/__tests__/**/*.test.ts'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/debug/package.json b/packages/debug/package.json index 2cdf9cfa5489..1f1e50dafbb5 100644 --- a/packages/debug/package.json +++ b/packages/debug/package.json @@ -18,33 +18,19 @@ ], "bugs": "https://github.com/prisma/prisma/issues", "devDependencies": { - "@types/jest": "27.4.0", - "@types/node": "12.20.39", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", + "@types/jest": "27.4.1", + "@types/node": "12.20.47", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", - "prettier": "2.5.1", - "strip-ansi": "6.0.1", - "ts-jest": "27.1.2", + "jest": "27.5.1", + "jest-junit": "13.0.0", + "ts-jest": "27.1.3", "typescript": "4.5.4" }, "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "prepublishOnly": "pnpm run build", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", - "test": "jest", - "precommit": "lint-staged" + "test": "jest" }, "files": [ "README.md", @@ -52,13 +38,8 @@ ], "dependencies": { "@types/debug": "4.1.7", - "ms": "2.1.3" - }, - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] + "ms": "2.1.3", + "strip-ansi": "6.0.1" }, "sideEffects": true } diff --git a/packages/debug/src/__tests__/basic.test.ts b/packages/debug/src/__tests__/basic.test.ts index 7c91ef97bb55..191bbf0f87f8 100644 --- a/packages/debug/src/__tests__/basic.test.ts +++ b/packages/debug/src/__tests__/basic.test.ts @@ -1,5 +1,6 @@ -import Debug, { getLogs } from '..' import stripAnsi from 'strip-ansi' + +import Debug, { getLogs } from '..' import { removeISODate, sanitizeTestLogs } from '../util' describe('debug', () => { diff --git a/packages/debug/src/__tests__/env-disabled.test.ts b/packages/debug/src/__tests__/env-disabled.test.ts index e4603c54a8be..d47f33f2a9bd 100644 --- a/packages/debug/src/__tests__/env-disabled.test.ts +++ b/packages/debug/src/__tests__/env-disabled.test.ts @@ -1,10 +1,14 @@ -process.env.DEBUG = '' - -import Debug, { getLogs } from '..' import stripAnsi from 'strip-ansi' + +import { getLogs } from '..' import { sanitizeTestLogs } from '../util' describe('debug', () => { + process.env.DEBUG = '' + const DebugLib = require('../') + const Debug = DebugLib.Debug + const getLogs = DebugLib.getLogs + test('* works as expected', () => { const debug = Debug('my-namespace') const logs: string[] = [] diff --git a/packages/debug/src/__tests__/env-enabled.test.ts b/packages/debug/src/__tests__/env-enabled.test.ts index 91365d071bfd..8fae2c9ffc69 100644 --- a/packages/debug/src/__tests__/env-enabled.test.ts +++ b/packages/debug/src/__tests__/env-enabled.test.ts @@ -1,10 +1,13 @@ -process.env.DEBUG = 'my-namespace' - -import Debug, { getLogs } from '..' import stripAnsi from 'strip-ansi' + import { removeISODate, sanitizeTestLogs } from '../util' describe('debug', () => { + process.env.DEBUG = 'my-namespace' + const DebugLib = require('../') + const Debug = DebugLib.Debug + const getLogs = DebugLib.getLogs + test('env vars work as expected', () => { const debug = Debug('my-namespace') const logs: string[] = [] diff --git a/packages/debug/src/node.ts b/packages/debug/src/node.ts index 503f331bfd87..9bf8be09786c 100644 --- a/packages/debug/src/node.ts +++ b/packages/debug/src/node.ts @@ -6,6 +6,8 @@ import tty from 'tty' import util from 'util' +import { setup } from './common' + /** * This is the Node.js implementation of `debug()`. */ @@ -146,8 +148,6 @@ function init(debug) { debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]] } } - -import { setup } from './common' const mod = setup(exports) module.exports = mod export default mod diff --git a/packages/debug/tsconfig.eslint.json b/packages/debug/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/debug/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/engine-core/.eslintignore b/packages/engine-core/.eslintignore deleted file mode 100644 index ea84755c73f2..000000000000 --- a/packages/engine-core/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -src/byline.ts -src/__tests__ diff --git a/packages/engine-core/.eslintrc.js b/packages/engine-core/.eslintrc.js deleted file mode 100644 index 918e4dc27d51..000000000000 --- a/packages/engine-core/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) -module.exports = config diff --git a/packages/engine-core/jest.config.js b/packages/engine-core/jest.config.js index 90066d6b0b74..b7b8fcebc09e 100644 --- a/packages/engine-core/jest.config.js +++ b/packages/engine-core/jest.config.js @@ -1,9 +1,23 @@ module.exports = { - preset: 'ts-jest', + transform: { + '^.+\\.ts$': '@swc/jest', + }, testEnvironment: 'node', + testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], - testMatch: ['**/src/__tests__/**/*.test.ts'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/engine-core/package.json b/packages/engine-core/package.json index cbfa870e9eff..21f4475af997 100644 --- a/packages/engine-core/package.json +++ b/packages/engine-core/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "license": "Apache-2.0", "main": "dist/index.js", - "module": "dist/esm/index.mjs", + "module": "esm/dist/index.mjs", "types": "dist/index.d.ts", "author": "Tim Suchanek ", "homepage": "https://www.prisma.io", @@ -19,57 +19,39 @@ ], "bugs": "https://github.com/prisma/prisma/issues", "devDependencies": { - "@types/jest": "27.4.0", + "@swc/core": "1.2.141", + "@swc/jest": "0.2.17", + "@types/jest": "27.4.1", "@types/node": "16.6.2", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", - "prettier": "2.5.1", - "strip-ansi": "6.0.1", - "ts-jest": "27.1.2", + "jest": "27.5.1", + "jest-junit": "13.0.0", "typescript": "4.5.4" }, "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "prepublishOnly": "npm run build", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", - "test": "jest", - "precommit": "lint-staged" + "test": "jest" }, "dependencies": { "@prisma/debug": "workspace:*", - "@prisma/engines": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/engines": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/generator-helper": "workspace:*", - "@prisma/get-platform": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/get-platform": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "chalk": "4.1.2", "execa": "5.1.1", "get-stream": "6.0.1", "indent-string": "4.0.0", "new-github-issue-url": "0.2.1", "p-retry": "4.6.1", + "strip-ansi": "6.0.1", "terminal-link": "2.1.1", - "undici": "4.12.1" + "undici": "4.16.0" }, "files": [ "README.md", "dist" ], - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] - }, "sideEffects": false } diff --git a/packages/engine-core/src/__tests__/errors.test.ts b/packages/engine-core/src/__tests__/errors.test.ts index 4d644642d8bb..4c0c319411a9 100644 --- a/packages/engine-core/src/__tests__/errors.test.ts +++ b/packages/engine-core/src/__tests__/errors.test.ts @@ -1,7 +1,8 @@ -import { getErrorMessageWithLink } from '../common/errors/utils/getErrorMessageWithLink' import Debug from '@prisma/debug' import stripAnsi from 'strip-ansi' +import { getErrorMessageWithLink } from '../common/errors/utils/getErrorMessageWithLink' + describe('getErrorMessageWithLink', () => { test('basic serialization', () => { const debug = Debug('test-namespace') diff --git a/packages/engine-core/src/binary/BinaryEngine.ts b/packages/engine-core/src/binary/BinaryEngine.ts index 9d6fb7909ffe..b0537240d03b 100644 --- a/packages/engine-core/src/binary/BinaryEngine.ts +++ b/packages/engine-core/src/binary/BinaryEngine.ts @@ -9,33 +9,34 @@ import { spawn } from 'child_process' import EventEmitter from 'events' import execa from 'execa' import fs from 'fs' +import type { IncomingHttpHeaders } from 'http' import net from 'net' import pRetry from 'p-retry' import path from 'path' import type { Readable } from 'stream' import { URL } from 'url' import { promisify } from 'util' -import byline from '../tools/byline' + import type { DatasourceOverwrite, EngineConfig, EngineEventType, GetConfigResult } from '../common/Engine' import { Engine } from '../common/Engine' -import type { RequestError } from '../common/errors/types/RequestError' -import { PrismaClientKnownRequestError } from '../common/errors/PrismaClientKnownRequestError' import { PrismaClientInitializationError } from '../common/errors/PrismaClientInitializationError' +import { PrismaClientKnownRequestError } from '../common/errors/PrismaClientKnownRequestError' import { PrismaClientRustError } from '../common/errors/PrismaClientRustError' import { PrismaClientRustPanicError } from '../common/errors/PrismaClientRustPanicError' import { PrismaClientUnknownRequestError } from '../common/errors/PrismaClientUnknownRequestError' +import type { RequestError } from '../common/errors/types/RequestError' import { getErrorMessageWithLink } from '../common/errors/utils/getErrorMessageWithLink' import type { RustError, RustLog } from '../common/errors/utils/log' import { convertLog, getMessage, isRustError, isRustErrorLog } from '../common/errors/utils/log' -import { omit } from '../tools/omit' +import { prismaGraphQLToJSError } from '../common/errors/utils/prismaGraphQLToJSError' +import type { QueryEngineRequestHeaders, QueryEngineResult } from '../common/types/QueryEngine' +import type * as Tx from '../common/types/Transaction' import { printGeneratorConfig } from '../common/utils/printGeneratorConfig' +import { fixBinaryTargets, getRandomString, plusX } from '../common/utils/util' +import byline from '../tools/byline' +import { omit } from '../tools/omit' import type { Result } from './Connection' import { Connection } from './Connection' -import { fixBinaryTargets, getRandomString, plusX } from '../common/utils/util' -import type * as Tx from '../common/types/Transaction' -import type { QueryEngineRequestHeaders, QueryEngineResult } from '../common/types/QueryEngine' -import type { IncomingHttpHeaders } from 'http' -import { prismaGraphQLToJSError } from '../common/errors/utils/prismaGraphQLToJSError' const debug = Debug('prisma:engine') const exists = promisify(fs.exists) @@ -86,7 +87,6 @@ export class BinaryEngine extends Engine { private engineEndpoint?: string private lastErrorLog?: RustLog private lastRustError?: RustError - private useUds = false private socketPath?: string private getConfigPromise?: Promise private stopPromise?: Promise @@ -132,13 +132,11 @@ export class BinaryEngine extends Engine { enableDebugLogs, allowTriggerPanic, dirname, - useUds, activeProvider, }: EngineConfig) { super() this.dirname = dirname - this.useUds = useUds ?? false // === undefined ? process.platform !== 'win32' : useUds this.env = env this.cwd = this.resolveCwd(cwd) this.enableDebugLogs = enableDebugLogs ?? false @@ -541,11 +539,6 @@ ${chalk.dim("In case we're mistaken, please report this to us 🙏.")}`) logger('startin & resettin') this.globalKillSignalReceived = undefined - if (this.useUds) { - this.socketPath = `/tmp/prisma-${getRandomString()}.sock` - socketPaths.push(this.socketPath) - } - debug({ cwd: this.cwd }) const prismaPath = await this.getPrismaPath() @@ -554,12 +547,8 @@ ${chalk.dim("In case we're mistaken, please report this to us 🙏.")}`) const flags = ['--enable-raw-queries', ...this.flags, ...additionalFlag] - if (this.useUds) { - flags.push('--unix-path', this.socketPath!) - } else { - this.port = await this.getFreePort() - flags.push('--port', String(this.port)) - } + this.port = await this.getFreePort() + flags.push('--port', String(this.port)) debug({ flags }) @@ -602,13 +591,9 @@ ${chalk.dim("In case we're mistaken, please report this to us 🙏.")}`) this.engineStartDeferred && json.level === 'INFO' && json.target === 'query_engine::server' && - json.fields?.message?.startsWith('Started http server') + json.fields?.message?.startsWith('Started query engine http server') ) { - if (this.useUds) { - this.connection.open('http://127.0.0.1', { connect: { socketPath: this.socketPath } }) - } else { - this.connection.open(`http://127.0.0.1:${this.port}`) - } + this.connection.open(`http://127.0.0.1:${this.port}`) this.engineStartDeferred.resolve() this.engineStartDeferred = undefined } @@ -975,29 +960,22 @@ You very likely have the wrong "binaryTarget" defined in the schema.prisma file. async transaction(action: any, arg?: any) { await this.start() - try { - if (action === 'start') { - const jsonOptions = JSON.stringify({ - max_wait: arg?.maxWait ?? 2000, // default - timeout: arg?.timeout ?? 5000, // default - }) + if (action === 'start') { + const jsonOptions = JSON.stringify({ + max_wait: arg?.maxWait ?? 2000, // default + timeout: arg?.timeout ?? 5000, // default + }) - const result = await Connection.onHttpError( - this.connection.post('/transaction/start', jsonOptions), - transactionHttpErrorHandler, - ) + const result = await Connection.onHttpError( + this.connection.post('/transaction/start', jsonOptions), + transactionHttpErrorHandler, + ) - return result.data - } else if (action === 'commit') { - await Connection.onHttpError(this.connection.post(`/transaction/${arg.id}/commit`), transactionHttpErrorHandler) - } else if (action === 'rollback') { - await Connection.onHttpError( - this.connection.post(`/transaction/${arg.id}/rollback`), - transactionHttpErrorHandler, - ) - } - } catch (e: any) { - this.setError(e) + return result.data + } else if (action === 'commit') { + await Connection.onHttpError(this.connection.post(`/transaction/${arg.id}/commit`), transactionHttpErrorHandler) + } else if (action === 'rollback') { + await Connection.onHttpError(this.connection.post(`/transaction/${arg.id}/rollback`), transactionHttpErrorHandler) } return undefined @@ -1157,7 +1135,7 @@ function initHooks() { } /** - * Decides how to handle error reponses for transactions + * Decides how to handle error responses for transactions * @param result */ function transactionHttpErrorHandler(result: Result): never { @@ -1176,8 +1154,8 @@ function runtimeHeadersToHttpHeaders(headers: QueryEngineRequestHeaders): Incomi if (runtimeHeaderKey === 'transactionId') { httpHeaderKey = 'X-transaction-id' } - // if header key isn't changed, a copy happens + // if header key isn't changed, a copy happens acc[httpHeaderKey] = headers[runtimeHeaderKey] return acc diff --git a/packages/engine-core/src/common/Engine.ts b/packages/engine-core/src/common/Engine.ts index e9d5a0aba91c..9b1b1c520faf 100644 --- a/packages/engine-core/src/common/Engine.ts +++ b/packages/engine-core/src/common/Engine.ts @@ -1,6 +1,7 @@ import type { DataSource, GeneratorConfig } from '@prisma/generator-helper' -import type * as Transaction from './types/Transaction' + import type { QueryEngineRequestHeaders, QueryEngineResult } from './types/QueryEngine' +import type * as Transaction from './types/Transaction' // import type { InlineDatasources } from '../../../client/src/generation/utils/buildInlineDatasources' export interface FilterConstructor { @@ -53,7 +54,6 @@ export interface EngineConfig { logLevel?: 'info' | 'warn' env?: Record flags?: string[] - useUds?: boolean clientVersion?: string previewFeatures?: string[] engineEndpoint?: string diff --git a/packages/engine-core/src/common/errors/PrismaClientRustError.ts b/packages/engine-core/src/common/errors/PrismaClientRustError.ts index e2a6a8f386db..3d18bea6dda8 100644 --- a/packages/engine-core/src/common/errors/PrismaClientRustError.ts +++ b/packages/engine-core/src/common/errors/PrismaClientRustError.ts @@ -1,5 +1,5 @@ -import { getBacktraceFromLog, getBacktraceFromRustError } from './utils/log' import type { PrismaClientRustErrorArgs } from './types/PrismaClientRustErrorArgs' +import { getBacktraceFromLog, getBacktraceFromRustError } from './utils/log' /** * A generic Prisma Client Rust error. diff --git a/packages/engine-core/src/common/errors/types/PrismaClientRustErrorArgs.ts b/packages/engine-core/src/common/errors/types/PrismaClientRustErrorArgs.ts index e7a839b91a55..67b6bb55187e 100644 --- a/packages/engine-core/src/common/errors/types/PrismaClientRustErrorArgs.ts +++ b/packages/engine-core/src/common/errors/types/PrismaClientRustErrorArgs.ts @@ -1,4 +1,4 @@ -import type { RustLog, RustError } from '../utils/log' +import type { RustError, RustLog } from '../utils/log' export type PrismaClientRustErrorArgs = { clientVersion: string diff --git a/packages/engine-core/src/common/errors/utils/getErrorMessageWithLink.ts b/packages/engine-core/src/common/errors/utils/getErrorMessageWithLink.ts index 389f1ee59ae9..0da2dd9d8388 100644 --- a/packages/engine-core/src/common/errors/utils/getErrorMessageWithLink.ts +++ b/packages/engine-core/src/common/errors/utils/getErrorMessageWithLink.ts @@ -1,9 +1,10 @@ import { getLogs } from '@prisma/debug' -import { getGithubIssueUrl, link } from '../../utils/util' import stripAnsi from 'strip-ansi' + +import { getGithubIssueUrl, link } from '../../utils/util' +import type { ErrorWithLinkInput } from '../types/ErrorWithLinkInput' import { maskQuery } from './maskQuery' import { normalizeLogs } from './normalizeLogs' -import type { ErrorWithLinkInput } from '../types/ErrorWithLinkInput' export function getErrorMessageWithLink({ version, diff --git a/packages/engine-core/src/common/errors/utils/log.ts b/packages/engine-core/src/common/errors/utils/log.ts index 3e94be99bad3..70e830177e4a 100644 --- a/packages/engine-core/src/common/errors/utils/log.ts +++ b/packages/engine-core/src/common/errors/utils/log.ts @@ -119,7 +119,7 @@ export function convertLog(rustLog: RawRustLog): RustLog { return { ...rustLog, level, - timestamp: new Date(new Date().getFullYear() + ' ' + rustLog.timestamp), + timestamp: new Date(rustLog.timestamp), } } diff --git a/packages/engine-core/src/common/utils/getInternalDatamodelJson.ts b/packages/engine-core/src/common/utils/getInternalDatamodelJson.ts index 9aac6187d0f1..5b2c370f622f 100644 --- a/packages/engine-core/src/common/utils/getInternalDatamodelJson.ts +++ b/packages/engine-core/src/common/utils/getInternalDatamodelJson.ts @@ -1,5 +1,6 @@ -import path from 'path' import { spawn } from 'child_process' +import path from 'path' + import byline from '../../tools/byline' export function getInternalDatamodelJson( diff --git a/packages/engine-core/src/common/utils/printGeneratorConfig.ts b/packages/engine-core/src/common/utils/printGeneratorConfig.ts index 9dd7e53de797..c8bcca5a6d7c 100644 --- a/packages/engine-core/src/common/utils/printGeneratorConfig.ts +++ b/packages/engine-core/src/common/utils/printGeneratorConfig.ts @@ -1,4 +1,4 @@ -import type { GeneratorConfig, BinaryTargetsEnvValue } from '@prisma/generator-helper' +import type { BinaryTargetsEnvValue, GeneratorConfig } from '@prisma/generator-helper' import indent from 'indent-string' export function printGeneratorConfig(config: GeneratorConfig): string { diff --git a/packages/engine-core/src/common/utils/util.ts b/packages/engine-core/src/common/utils/util.ts index 46d2fe53f0a4..1bc7659b05a2 100644 --- a/packages/engine-core/src/common/utils/util.ts +++ b/packages/engine-core/src/common/utils/util.ts @@ -1,11 +1,11 @@ -import fs from 'fs' -import type { Platform } from '@prisma/get-platform' +import Debug from '@prisma/debug' import type { BinaryTargetsEnvValue } from '@prisma/generator-helper' -import terminalLink from 'terminal-link' -import newGithubIssueUrl from 'new-github-issue-url' +import type { Platform } from '@prisma/get-platform' import chalk from 'chalk' -import Debug from '@prisma/debug' import crypto from 'crypto' +import fs from 'fs' +import newGithubIssueUrl from 'new-github-issue-url' +import terminalLink from 'terminal-link' const debug = Debug('plusX') diff --git a/packages/engine-core/src/data-proxy/DataProxyEngine.ts b/packages/engine-core/src/data-proxy/DataProxyEngine.ts index 0c3c1b1c0bf9..b2c040027b08 100644 --- a/packages/engine-core/src/data-proxy/DataProxyEngine.ts +++ b/packages/engine-core/src/data-proxy/DataProxyEngine.ts @@ -1,18 +1,20 @@ /// +// TODO: this is a problem because it propagates everywhere -import { Engine } from '../common/Engine' -import type { EngineConfig, EngineEventType, GetConfigResult } from '../common/Engine' -import { request } from './utils/request' import EventEmitter from 'events' -import { backOff } from './utils/backOff' -import { getClientVersion } from './utils/getClientVersion' -import { responseToError } from './errors/utils/responseToError' + +import type { EngineConfig, EngineEventType, GetConfigResult } from '../common/Engine' +import { Engine } from '../common/Engine' +import { prismaGraphQLToJSError } from '../common/errors/utils/prismaGraphQLToJSError' +import { DataProxyError } from './errors/DataProxyError' +import { ForcedRetryError } from './errors/ForcedRetryError' import { InvalidDatasourceError } from './errors/InvalidDatasourceError' import { NotImplementedYetError } from './errors/NotImplementedYetError' -import { ForcedRetryError } from './errors/ForcedRetryError' import { SchemaMissingError } from './errors/SchemaMissingError' -import { DataProxyError } from './errors/DataProxyError' -import { prismaGraphQLToJSError } from '../common/errors/utils/prismaGraphQLToJSError' +import { responseToError } from './errors/utils/responseToError' +import { backOff } from './utils/backOff' +import { getClientVersion } from './utils/getClientVersion' +import { request } from './utils/request' // import type { InlineDatasources } from '../../../client/src/generation/utils/buildInlineDatasources' // TODO this is an issue that we cannot share types from the client to other packages diff --git a/packages/engine-core/src/data-proxy/errors/DataProxyAPIError.ts b/packages/engine-core/src/data-proxy/errors/DataProxyAPIError.ts index 1bf917905251..29fb490cccb2 100644 --- a/packages/engine-core/src/data-proxy/errors/DataProxyAPIError.ts +++ b/packages/engine-core/src/data-proxy/errors/DataProxyAPIError.ts @@ -1,6 +1,6 @@ +import type { RequestResponse } from '../utils/request' import type { DataProxyErrorInfo } from './DataProxyError' import { DataProxyError } from './DataProxyError' -import type { RequestResponse } from '../utils/request' export interface DataProxyAPIErrorInfo extends DataProxyErrorInfo { response: RequestResponse diff --git a/packages/engine-core/src/data-proxy/errors/NotFoundError.ts b/packages/engine-core/src/data-proxy/errors/NotFoundError.ts index 80ed64ae89e5..6b30b80fded4 100644 --- a/packages/engine-core/src/data-proxy/errors/NotFoundError.ts +++ b/packages/engine-core/src/data-proxy/errors/NotFoundError.ts @@ -1,6 +1,6 @@ +import type { RequestResponse } from '../utils/request' import type { DataProxyAPIErrorInfo } from './DataProxyAPIError' import { DataProxyAPIError } from './DataProxyAPIError' -import type { RequestResponse } from '../utils/request' import { setRetryable } from './utils/setRetryable' export interface NotFoundErrorInfo extends DataProxyAPIErrorInfo { diff --git a/packages/engine-core/src/data-proxy/errors/utils/responseToError.ts b/packages/engine-core/src/data-proxy/errors/utils/responseToError.ts index 9ae0bc45e11b..6c61981ee5d8 100644 --- a/packages/engine-core/src/data-proxy/errors/utils/responseToError.ts +++ b/packages/engine-core/src/data-proxy/errors/utils/responseToError.ts @@ -1,7 +1,7 @@ +import type { RequestResponse } from '../../utils/request' import { BadRequestError } from '../BadRequestError' import type { DataProxyError } from '../DataProxyError' import { NotFoundError } from '../NotFoundError' -import type { RequestResponse } from '../../utils/request' import { SchemaMissingError } from '../SchemaMissingError' import { ServerError } from '../ServerError' import { UnauthorizedError } from '../UnauthorizedError' diff --git a/packages/engine-core/src/data-proxy/utils/request.ts b/packages/engine-core/src/data-proxy/utils/request.ts index bb96ae2a05b1..2db9136703aa 100644 --- a/packages/engine-core/src/data-proxy/utils/request.ts +++ b/packages/engine-core/src/data-proxy/utils/request.ts @@ -1,7 +1,8 @@ +import type { IncomingMessage } from 'http' import type _https from 'https' -import { getJSRuntimeName } from './getJSRuntimeName' import type { O } from 'ts-toolbelt' -import type { IncomingMessage } from 'http' + +import { getJSRuntimeName } from './getJSRuntimeName' // our implementation handles less export type RequestOptions = O.Patch< @@ -38,7 +39,8 @@ export async function request(url: string, options: RequestOptions = {}): Promis */ function buildHeaders(options: RequestOptions): RequestOptions['headers'] { return { - ...options.headers, + // this ensures headers will always be valid + ...JSON.parse(JSON.stringify(options.headers)), 'Content-Type': 'application/json', } } diff --git a/packages/engine-core/src/index.ts b/packages/engine-core/src/index.ts index 32e072d46fae..a176ce328155 100644 --- a/packages/engine-core/src/index.ts +++ b/packages/engine-core/src/index.ts @@ -1,18 +1,16 @@ +export { BinaryEngine } from './binary/BinaryEngine' +export type { EngineConfig } from './common/Engine' +export type { EngineEventType } from './common/Engine' +export type { DatasourceOverwrite } from './common/Engine' +export { Engine } from './common/Engine' export { PrismaClientInitializationError } from './common/errors/PrismaClientInitializationError' export { PrismaClientKnownRequestError } from './common/errors/PrismaClientKnownRequestError' export { PrismaClientRustPanicError } from './common/errors/PrismaClientRustPanicError' export { PrismaClientUnknownRequestError } from './common/errors/PrismaClientUnknownRequestError' - -export { Engine } from './common/Engine' -export type { EngineConfig } from './common/Engine' -export type { EngineEventType } from './common/Engine' -export type { DatasourceOverwrite } from './common/Engine' -export { LibraryEngine } from './library/LibraryEngine' -export { BinaryEngine } from './binary/BinaryEngine' -export { DataProxyEngine } from './data-proxy/DataProxyEngine' -export * as NodeAPILibraryTypes from './library/types/Library' - -export { printGeneratorConfig, getOriginalBinaryTargetsValue } from './common/utils/printGeneratorConfig' export { getInternalDatamodelJson } from './common/utils/getInternalDatamodelJson' +export { getOriginalBinaryTargetsValue, printGeneratorConfig } from './common/utils/printGeneratorConfig' export { fixBinaryTargets } from './common/utils/util' export { plusX } from './common/utils/util' +export { DataProxyEngine } from './data-proxy/DataProxyEngine' +export { LibraryEngine } from './library/LibraryEngine' +export * as NodeAPILibraryTypes from './library/types/Library' diff --git a/packages/engine-core/src/library/LibraryEngine.ts b/packages/engine-core/src/library/LibraryEngine.ts index 8adaba4cfce8..e083d50dd410 100644 --- a/packages/engine-core/src/library/LibraryEngine.ts +++ b/packages/engine-core/src/library/LibraryEngine.ts @@ -6,6 +6,7 @@ import chalk from 'chalk' import EventEmitter from 'events' import fs from 'fs' import path from 'path' + import type { DatasourceOverwrite, EngineConfig, EngineEventType } from '../common/Engine' import { Engine } from '../common/Engine' import { PrismaClientInitializationError } from '../common/errors/PrismaClientInitializationError' @@ -108,21 +109,25 @@ export class LibraryEngine extends Engine { async transaction(action: any, arg?: any) { await this.start() + let result: string | undefined if (action === 'start') { const jsonOptions = JSON.stringify({ max_wait: arg?.maxWait ?? 2000, // default timeout: arg?.timeout ?? 5000, // default }) - const result = await this.engine?.startTransaction(jsonOptions, '{}') - return this.parseEngineResponse(result) + result = await this.engine?.startTransaction(jsonOptions, '{}') } else if (action === 'commit') { - await this.engine?.commitTransaction(arg.id, '{}') + result = await this.engine?.commitTransaction(arg.id, '{}') } else if (action === 'rollback') { - await this.engine?.rollbackTransaction(arg.id, '{}') + result = await this.engine?.rollbackTransaction(arg.id, '{}') } - return undefined + const response = this.parseEngineResponse<{ [K: string]: unknown }>(result) + + if (response.error_code) throw response + + return response as Tx.Info | undefined } private async instantiateLibrary(): Promise { @@ -143,7 +148,7 @@ export class LibraryEngine extends Engine { if (!knownPlatforms.includes(platform)) { throw new PrismaClientInitializationError( `Unknown ${chalk.red('PRISMA_QUERY_ENGINE_LIBRARY')} ${chalk.redBright.bold( - this.platform, + platform, )}. Possible binaryTargets: ${chalk.greenBright( knownPlatforms.join(', '), )} or a path to the query engine library. @@ -243,10 +248,10 @@ You may have to run ${chalk.greenBright('prisma generate')} for your changes to event.level = event?.level.toLowerCase() ?? 'unknown' if (isQueryEvent(event)) { this.logEmitter.emit('query', { - timestamp: Date.now(), + timestamp: new Date(), query: event.query, params: event.params, - duration: event.duration_ms, + duration: Number(event.duration_ms), target: event.module_path, }) } else if (isPanicEvent(event)) { @@ -258,7 +263,11 @@ You may have to run ${chalk.greenBright('prisma generate')} for your changes to ) this.logEmitter.emit('error', this.loggerRustPanic) } else { - this.logEmitter.emit(event.level, event) + this.logEmitter.emit(event.level, { + timestamp: new Date(), + message: event.message, + target: event.module_path, + }) } } @@ -393,8 +402,8 @@ You may have to run ${chalk.greenBright('prisma generate')} for your changes to ): Promise<{ data: T; elapsed: number }> { debug(`sending request, this.libraryStarted: ${this.libraryStarted}`) const request: QueryEngineRequest = { query, variables: {} } + const headerStr = JSON.stringify(headers) // object equivalent to http headers for the library const queryStr = JSON.stringify(request) - const headerStr = JSON.stringify(headers) try { await this.start() @@ -441,11 +450,7 @@ You may have to run ${chalk.greenBright('prisma generate')} for your changes to await this.start() this.lastQuery = JSON.stringify(request) - this.executingQueryPromise = this.engine!.query( - this.lastQuery, - JSON.stringify(headers), // TODO these aren't headers on the engine side - headers.transactionId, - ) + this.executingQueryPromise = this.engine!.query(this.lastQuery, JSON.stringify(headers), headers.transactionId) const result = await this.executingQueryPromise const data = this.parseEngineResponse(result) diff --git a/packages/engine-core/src/library/types/Library.ts b/packages/engine-core/src/library/types/Library.ts index c110427df692..be1a9be1f2e2 100644 --- a/packages/engine-core/src/library/types/Library.ts +++ b/packages/engine-core/src/library/types/Library.ts @@ -1,4 +1,4 @@ -import type { GetConfigOptions, ConfigMetaFormat, QueryEngineConfig } from '../../common/types/QueryEngine' +import type { ConfigMetaFormat, GetConfigOptions, QueryEngineConfig } from '../../common/types/QueryEngine' export type ConnectArgs = { enableRawQueries: boolean diff --git a/packages/engine-core/tsconfig.eslint.json b/packages/engine-core/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/engine-core/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/generator-helper/.eslintignore b/packages/generator-helper/.eslintignore deleted file mode 100644 index b036b6996094..000000000000 --- a/packages/generator-helper/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -src/byline.ts \ No newline at end of file diff --git a/packages/generator-helper/.eslintrc.js b/packages/generator-helper/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/generator-helper/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/generator-helper/jest.config.js b/packages/generator-helper/jest.config.js index aeafe4757a4e..b7b8fcebc09e 100644 --- a/packages/generator-helper/jest.config.js +++ b/packages/generator-helper/jest.config.js @@ -1,9 +1,23 @@ module.exports = { - preset: 'ts-jest', + transform: { + '^.+\\.ts$': '@swc/jest', + }, testEnvironment: 'node', testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/generator-helper/package.json b/packages/generator-helper/package.json index 68dc46e34a2c..1826658a7a45 100644 --- a/packages/generator-helper/package.json +++ b/packages/generator-helper/package.json @@ -2,7 +2,7 @@ "name": "@prisma/generator-helper", "version": "0.0.0", "main": "dist/index.js", - "module": "dist/esm/index.mjs", + "module": "esm/dist/index.mjs", "types": "dist/index.d.ts", "typings": "dist/index.d.ts", "license": "Apache-2.0", @@ -28,29 +28,17 @@ "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", - "prepublishOnly": "pnpm run build && pnpm run test", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", - "test": "jest", - "precommit": "lint-staged" + "prepublishOnly": "pnpm run build", + "test": "jest" }, "devDependencies": { - "@types/jest": "27.4.0", - "@types/node": "12.20.39", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", + "@swc/core": "1.2.141", + "@swc/jest": "0.2.17", + "@types/jest": "27.4.1", + "@types/node": "12.20.47", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", - "prettier": "2.5.1", - "ts-jest": "27.1.2", + "jest": "27.5.1", + "jest-junit": "13.0.0", "ts-node": "10.4.0", "typescript": "4.5.4" }, @@ -58,11 +46,5 @@ "README.md", "dist" ], - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] - }, "sideEffects": false } diff --git a/packages/generator-helper/src/GeneratorProcess.ts b/packages/generator-helper/src/GeneratorProcess.ts index a13a23ed0eaa..a60c4bac4c51 100644 --- a/packages/generator-helper/src/GeneratorProcess.ts +++ b/packages/generator-helper/src/GeneratorProcess.ts @@ -1,10 +1,11 @@ +import Debug from '@prisma/debug' +import chalk from 'chalk' import type { ChildProcessByStdio } from 'child_process' import { fork } from 'child_process' import { spawn } from 'cross-spawn' + import byline from './byline' import type { GeneratorConfig, GeneratorManifest, GeneratorOptions, JsonRPC } from './types' -import chalk from 'chalk' -import Debug from '@prisma/debug' const debug = Debug('prisma:GeneratorProcess') diff --git a/packages/generator-helper/src/__tests__/generatorHandler.test.ts b/packages/generator-helper/src/__tests__/generatorHandler.test.ts index e458e843d0ac..a4a1cae38ad8 100644 --- a/packages/generator-helper/src/__tests__/generatorHandler.test.ts +++ b/packages/generator-helper/src/__tests__/generatorHandler.test.ts @@ -1,5 +1,6 @@ -import { GeneratorProcess } from '../GeneratorProcess' import path from 'path' + +import { GeneratorProcess } from '../GeneratorProcess' import type { GeneratorOptions } from '../types' const testIf = (condition: boolean) => (condition ? test : test.skip) @@ -11,6 +12,7 @@ const stubOptions: GeneratorOptions = { datamodel: { enums: [], models: [], + types: [], }, mappings: { modelOperations: [], diff --git a/packages/generator-helper/src/byline.ts b/packages/generator-helper/src/byline.ts index a52ee717e94b..9a7b7bb9475e 100644 --- a/packages/generator-helper/src/byline.ts +++ b/packages/generator-helper/src/byline.ts @@ -19,7 +19,6 @@ // IN THE SOFTWARE. // @ts-ignore -/* tslint:disable */ import stream from 'stream' import util from 'util' diff --git a/packages/generator-helper/src/dmmf.ts b/packages/generator-helper/src/dmmf.ts index a9022e6c10f7..d6dbc95688d4 100644 --- a/packages/generator-helper/src/dmmf.ts +++ b/packages/generator-helper/src/dmmf.ts @@ -39,6 +39,7 @@ export namespace DMMF { export interface Datamodel { models: Model[] enums: DatamodelEnum[] + types: Model[] } export interface uniqueIndex { @@ -58,7 +59,7 @@ export namespace DMMF { uniqueIndexes: uniqueIndex[] documentation?: string primaryKey: PrimaryKey | null - [key: string]: any // safe net for additional new props + [key: string]: any // safe net for additional new props // TODO: remove this and the others, not safe } export type FieldKind = 'scalar' | 'object' | 'enum' | 'unsupported' @@ -74,9 +75,13 @@ export namespace DMMF { isUnique: boolean isId: boolean isReadOnly: boolean - isGenerated: boolean - isUpdatedAt: boolean - type: string | DMMF.SchemaEnum | DMMF.OutputType | DMMF.SchemaArg + isGenerated?: boolean // does not exist on 'type' but does on 'model' + isUpdatedAt?: boolean // does not exist on 'type' but does on 'model' + /** + * Describes the data type in the same the way is is defined in the Prisma schema: + * BigInt, Boolean, Bytes, DateTime, Decimal, Float, Int, JSON, String, $ModelName + */ + type: string dbNames?: string[] | null hasDefaultValue: boolean default?: FieldDefault | string | boolean | number @@ -193,6 +198,8 @@ export namespace DMMF { aggregate?: string | null groupBy?: string | null count?: string | null + findRaw?: string | null + aggregateRaw?: string | null } export enum ModelAction { @@ -207,7 +214,9 @@ export namespace DMMF { delete = 'delete', deleteMany = 'deleteMany', groupBy = 'groupBy', - count = 'count', + count = 'count', // TODO: count does not actually exist, why? aggregate = 'aggregate', + findRaw = 'findRaw', + aggregateRaw = 'aggregateRaw', } } diff --git a/packages/generator-helper/src/generatorHandler.ts b/packages/generator-helper/src/generatorHandler.ts index e2f5be98af3e..8ed3ac9ba423 100644 --- a/packages/generator-helper/src/generatorHandler.ts +++ b/packages/generator-helper/src/generatorHandler.ts @@ -1,5 +1,5 @@ -import type { GeneratorOptions, GeneratorManifest, JsonRPC, GeneratorConfig } from './types' import byline from './byline' +import type { GeneratorConfig, GeneratorManifest, GeneratorOptions, JsonRPC } from './types' export interface Handler { onGenerate(options: GeneratorOptions): Promise diff --git a/packages/generator-helper/src/index.ts b/packages/generator-helper/src/index.ts index 39a4166c3dfc..58cabdbc5bd2 100644 --- a/packages/generator-helper/src/index.ts +++ b/packages/generator-helper/src/index.ts @@ -1,4 +1,4 @@ -export { GeneratorProcess, GeneratorError } from './GeneratorProcess' +export * from './dmmf' export { generatorHandler } from './generatorHandler' +export { GeneratorError, GeneratorProcess } from './GeneratorProcess' export * from './types' -export * from './dmmf' diff --git a/packages/generator-helper/src/types.ts b/packages/generator-helper/src/types.ts index 2b80feb32fbf..fa8396b2984f 100644 --- a/packages/generator-helper/src/types.ts +++ b/packages/generator-helper/src/types.ts @@ -51,7 +51,14 @@ export interface BinaryTargetsEnvValue { value: string } -export type ConnectorType = 'mysql' | 'mongodb' | 'sqlite' | 'postgresql' | 'sqlserver' +export type ConnectorType = + | 'mysql' + | 'mongodb' + | 'sqlite' + | 'postgresql' + | 'sqlserver' + | 'jdbc:sqlserver' + | 'cockroachdb' export interface DataSource { name: string diff --git a/packages/generator-helper/tsconfig.eslint.json b/packages/generator-helper/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/generator-helper/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/integration-tests/.eslintignore b/packages/integration-tests/.eslintignore deleted file mode 100644 index 76add878f8dd..000000000000 --- a/packages/integration-tests/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/packages/integration-tests/.eslintrc.js b/packages/integration-tests/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/integration-tests/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/integration-tests/jest.config.js b/packages/integration-tests/jest.config.js index 840cc4a023d1..6871c05c3256 100644 --- a/packages/integration-tests/jest.config.js +++ b/packages/integration-tests/jest.config.js @@ -1,12 +1,24 @@ module.exports = { - preset: 'ts-jest', + transform: { + '^.+\\.ts$': '@swc/jest', + }, testEnvironment: 'node', testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], - // todo duplicated serializer from client package, should share - snapshotSerializers: ['./src/__tests__/__helpers__/snapshotSerializer.ts'], - setupFiles: [], + snapshotSerializers: ['@prisma/sdk/src/utils/jestSnapshotSerializer'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index 981cff031718..1d8744e76c0b 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "main": "dist/index.js", - "module": "dist/esm/index.mjs", + "module": "esm/dist/index.mjs", "types": "dist/index.d.ts", "license": "Apache-2.0", "author": "Tim Suchanek ", @@ -15,34 +15,27 @@ "devDependencies": { "@prisma/sdk": "workspace:*", "@sindresorhus/slugify": "1.1.2", - "@types/jest": "27.4.0", - "@types/mssql": "6.0.8", - "@types/node": "12.20.39", - "@types/pg": "8.6.3", + "@swc/core": "1.2.141", + "@swc/jest": "0.2.17", + "@types/jest": "27.4.1", + "@types/mssql": "7.1.5", + "@types/node": "12.20.47", + "@types/pg": "8.6.5", "@types/sqlite3": "3.1.8", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", "decimal.js": "10.3.1", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", "execa": "5.1.1", "fs-jetpack": "4.3.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", - "mariadb": "2.5.5", - "mssql": "7.3.0", + "jest": "27.5.1", + "jest-junit": "13.0.0", + "mariadb": "3.0.0", + "mssql": "8.0.1", "pg": "8.7.1", - "prettier": "2.5.1", "replace-string": "3.1.0", "sqlite-async": "1.1.2", "string-hash": "1.1.3", "strip-ansi": "6.0.1", "tempy": "1.0.1", - "ts-jest": "27.1.2", "ts-node": "10.4.0", "typescript": "4.5.4", "verror": "1.10.1" @@ -50,7 +43,6 @@ "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "test:integration": "jest integration --maxConcurrency=8 --verbose", "test:sqlite": "jest integration.sqlite --maxConcurrency=8 --verbose", "test:postgresql": "jest integration.postgresql --maxConcurrency=8 --verbose", @@ -58,22 +50,12 @@ "test:mariadb": "jest integration.mariadb --maxConcurrency=8 --verbose", "test:mssql": "jest integration.mssql --maxConcurrency=8 --verbose", "prepublishOnly": "pnpm run build", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", "jest": "jest", - "test": "jest --maxConcurrency=8 --verbose", - "precommit": "lint-staged" + "test": "jest --maxConcurrency=8 --verbose" }, "files": [ "README.md", "dist" ], - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] - }, "sideEffects": false } diff --git a/packages/integration-tests/src/__tests__/__helpers__/context.ts b/packages/integration-tests/src/__tests__/__helpers__/context.ts deleted file mode 100644 index b9cd3c490b3b..000000000000 --- a/packages/integration-tests/src/__tests__/__helpers__/context.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { ExecaChildProcess } from 'execa' -import execa from 'execa' -import fs from 'fs-jetpack' -import type { FSJetpack } from 'fs-jetpack/types' -import path from 'path' -import tempy from 'tempy' - -/** - * Base test context. - */ -type BaseContext = { - tmpDir: string - fs: FSJetpack - mocked: { - cwd: string - } - /** - * Setup the temporary directory based on the contents of some fixture. - */ - fixture: (name: string) => void - /** - * Spawn the Prisma cli using the temporary directory as the CWD. - * - * @remarks - * - * For this to work the source must be built! - */ - cli: (...input: string[]) => ExecaChildProcess -} - -/** - * Create test context to use in tests. Provides the following: - * - * - A temporary directory - * - an fs-jetpack instance bound to the temporary directory - * - Mocked process.cwd via Node process.chdir - * - Fixture loader for boostrapping the temporary directory with content - */ -export const Context = { - new: function (ctx: BaseContext = {} as any) { - const c = ctx as any - - beforeEach(() => { - c.tmpDir = tempy.directory() - c.fs = fs.cwd(c.tmpDir) - c.fixture = (name: string) => { - c.fs.copy(path.join(__dirname, '..', 'fixtures', name), '.', { - overwrite: true, - }) - } - c.mocked = c.mocked ?? {} - c.mocked.cwd = process.cwd() - c.cli = (...input) => { - return execa.node(path.join(__dirname, '../../../build/index.js'), input, { - cwd: c.fs.cwd(), - stdio: 'pipe', - }) - } - process.chdir(c.tmpDir) - }) - - afterEach(() => { - process.chdir(c.mocked.cwd) - }) - - return factory(ctx) - }, -} - -/** - * Factory for creating a context contributor possibly configured in some special way. - */ -type ContextContributorFactory = Settings extends {} - ? () => ContextContributor - : (settings: Settings) => ContextContributor - -/** - * A function that provides additonal test context. - */ -type ContextContributor = (ctx: Context) => NewContext - -/** - * Main context builder API that permits recursively building up context. - */ -function factory(ctx: Context) { - return { - add(contextContributor: ContextContributor) { - contextContributor(ctx) - return factory(ctx as any) - }, - assemble(): Context { - return ctx - }, - } -} - -/** - * Test context contributor. Mocks console.error with a Jest spy before each test. - */ -export const consoleContext: ContextContributorFactory< - {}, - BaseContext, - { - mocked: { - 'console.error': jest.SpyInstance - 'console.log': jest.SpyInstance - } - } -> = () => (ctx) => { - beforeEach(() => { - ctx.mocked['console.error'] = jest.spyOn(console, 'error').mockImplementation(() => {}) - ctx.mocked['console.log'] = jest.spyOn(console, 'log').mockImplementation(() => {}) - }) - - afterEach(() => { - ctx.mocked['console.error'].mockRestore() - ctx.mocked['console.log'].mockRestore() - }) - - return null as any -} diff --git a/packages/integration-tests/src/__tests__/__helpers__/integrationTest.ts b/packages/integration-tests/src/__tests__/__helpers__/integrationTest.ts index 0170d2c6bc3c..7ccb03461749 100644 --- a/packages/integration-tests/src/__tests__/__helpers__/integrationTest.ts +++ b/packages/integration-tests/src/__tests__/__helpers__/integrationTest.ts @@ -5,6 +5,7 @@ import type { FSJetpack } from 'fs-jetpack/types' import path from 'path' import hash from 'string-hash' import VError, { MultiError } from 'verror' + import { getTestClient } from '../../../../client/src/utils/getTestClient' process.setMaxListeners(200) diff --git a/packages/integration-tests/src/__tests__/__helpers__/snapshotSerializer.ts b/packages/integration-tests/src/__tests__/__helpers__/snapshotSerializer.ts deleted file mode 100644 index c392c2ccd51c..000000000000 --- a/packages/integration-tests/src/__tests__/__helpers__/snapshotSerializer.ts +++ /dev/null @@ -1,69 +0,0 @@ -import path from 'path' -import replaceAll from 'replace-string' // sindre's replaceAll polyfill -import stripAnsi from 'strip-ansi' -import { platformRegex } from '@prisma/sdk' - -function trimErrorPaths(str) { - const parentDir = path.dirname(path.dirname(__dirname)) - - return replaceAll(str, parentDir, '') -} - -function normalizeToUnixPaths(str) { - return replaceAll(str, path.sep, '/') -} - -function removePlatforms(str) { - return str.replace(platformRegex, 'TEST_PLATFORM') -} - -function normalizeGithubLinks(str) { - return str.replace(/https:\/\/github.com\/prisma\/prisma-client-js\/issues\/\S+/, 'TEST_GITHUB_LINK') -} - -function normalizeRustError(str) { - return str.replace(/\/rustc\/(.+)\//g, '/rustc/hash/').replace(/(\[.*)(:\d*:\d*)(\])/g, '[/some/rust/path:0:0$3') -} - -function normalizeTmpDir(str) { - return str.replace(/\/tmp\/([a-z0-9]+)\//g, '/tmp/dir/') -} - -/** - * Replace dynamic variable bits of Prisma Schema with static strings. - */ -function prepareSchemaForSnapshot(schema: string): string { - const urlRegex = /url\s*=\s*.+/ - const outputRegex = /output\s*=\s*.+/ - return schema - .split('\n') - .map((line) => { - const urlMatch = urlRegex.exec(line) - if (urlMatch) { - return `${line.slice(0, urlMatch.index)}url = "***"` - } - const outputMatch = outputRegex.exec(line) - if (outputMatch) { - return `${line.slice(0, outputMatch.index)}output = "***"` - } - return line - }) - .join('\n') -} - -export function test(value) { - return typeof value === 'string' || value instanceof Error -} - -export function serialize(value) { - const message = typeof value === 'string' ? value : value instanceof Error ? value.message : '' - return prepareSchemaForSnapshot( - normalizeGithubLinks( - normalizeRustError( - normalizeTmpDir( - normalizeGithubLinks(normalizeToUnixPaths(removePlatforms(trimErrorPaths(stripAnsi(message))))), - ), - ), - ), - ) -} diff --git a/packages/integration-tests/src/__tests__/integration/mariadb/__database.ts b/packages/integration-tests/src/__tests__/integration/mariadb/__database.ts index 321747323bb6..6ac6a07aca29 100644 --- a/packages/integration-tests/src/__tests__/integration/mariadb/__database.ts +++ b/packages/integration-tests/src/__tests__/integration/mariadb/__database.ts @@ -1,5 +1,6 @@ import { uriToCredentials } from '@prisma/sdk' import mariadb from 'mariadb' + import type { Context, Input } from '../../__helpers__/integrationTest' export const database = { diff --git a/packages/integration-tests/src/__tests__/integration/mariadb/__scenarios.ts b/packages/integration-tests/src/__tests__/integration/mariadb/__scenarios.ts index 43606196a1f9..59f5fc938d1d 100644 --- a/packages/integration-tests/src/__tests__/integration/mariadb/__scenarios.ts +++ b/packages/integration-tests/src/__tests__/integration/mariadb/__scenarios.ts @@ -1,6 +1,7 @@ -import type { Input } from '../../__helpers__/integrationTest' import { Decimal } from 'decimal.js' +import type { Input } from '../../__helpers__/integrationTest' + export const scenarios = [ { name: 'findUnique where PK', diff --git a/packages/integration-tests/src/__tests__/integration/mssql/__database.ts b/packages/integration-tests/src/__tests__/integration/mssql/__database.ts index 490e0641e9b5..1a1c35108560 100644 --- a/packages/integration-tests/src/__tests__/integration/mssql/__database.ts +++ b/packages/integration-tests/src/__tests__/integration/mssql/__database.ts @@ -1,8 +1,8 @@ +import type { Context, Input } from '../../__helpers__/integrationTest' + const sql = require('mssql') const url = require('url') -import type { Context, Input } from '../../__helpers__/integrationTest' - export const database = { name: 'sqlserver', datasource: { diff --git a/packages/integration-tests/src/__tests__/integration/mssql/__scenarios.ts b/packages/integration-tests/src/__tests__/integration/mssql/__scenarios.ts index 666654f8a58a..e606991f90b3 100644 --- a/packages/integration-tests/src/__tests__/integration/mssql/__scenarios.ts +++ b/packages/integration-tests/src/__tests__/integration/mssql/__scenarios.ts @@ -1,6 +1,7 @@ -import type { Input } from '../../__helpers__/integrationTest' import { Decimal } from 'decimal.js' +import type { Input } from '../../__helpers__/integrationTest' + export const scenarios = [ { name: 'findUnique where PK', diff --git a/packages/integration-tests/src/__tests__/integration/mssql/introspection.test.ts b/packages/integration-tests/src/__tests__/integration/mssql/introspection.test.ts index 982436d9d582..3a49f8808238 100644 --- a/packages/integration-tests/src/__tests__/integration/mssql/introspection.test.ts +++ b/packages/integration-tests/src/__tests__/integration/mssql/introspection.test.ts @@ -1,4 +1,4 @@ -import { introspectionIntegrationTest, Input } from '../../__helpers__/integrationTest' +import { Input, introspectionIntegrationTest } from '../../__helpers__/integrationTest' import { database } from './__database' import { scenarios } from './__scenarios' diff --git a/packages/integration-tests/src/__tests__/integration/mysql/__database.ts b/packages/integration-tests/src/__tests__/integration/mysql/__database.ts index fdae3ec50f4d..84e8fdf480ec 100644 --- a/packages/integration-tests/src/__tests__/integration/mysql/__database.ts +++ b/packages/integration-tests/src/__tests__/integration/mysql/__database.ts @@ -1,5 +1,6 @@ import { uriToCredentials } from '@prisma/sdk' import mariadb from 'mariadb' + import type { Context, Input } from '../../__helpers__/integrationTest' export const database = { diff --git a/packages/integration-tests/src/__tests__/integration/mysql/__scenarios.ts b/packages/integration-tests/src/__tests__/integration/mysql/__scenarios.ts index 120c2967f073..7c26bcd557d3 100644 --- a/packages/integration-tests/src/__tests__/integration/mysql/__scenarios.ts +++ b/packages/integration-tests/src/__tests__/integration/mysql/__scenarios.ts @@ -1,6 +1,7 @@ -import type { Input } from '../../__helpers__/integrationTest' import { Decimal } from 'decimal.js' +import type { Input } from '../../__helpers__/integrationTest' + export const scenarios = [ { name: 'findUnique where PK', diff --git a/packages/integration-tests/src/__tests__/integration/postgresql/__database.ts b/packages/integration-tests/src/__tests__/integration/postgresql/__database.ts index 510bd650fce6..56487e2077ec 100644 --- a/packages/integration-tests/src/__tests__/integration/postgresql/__database.ts +++ b/packages/integration-tests/src/__tests__/integration/postgresql/__database.ts @@ -1,4 +1,5 @@ import * as PG from 'pg' + import type { Context, Input } from '../../__helpers__/integrationTest' export const database = { diff --git a/packages/integration-tests/src/__tests__/integration/postgresql/__scenarios.ts b/packages/integration-tests/src/__tests__/integration/postgresql/__scenarios.ts index 49a0992f14d7..28db6b504a28 100644 --- a/packages/integration-tests/src/__tests__/integration/postgresql/__scenarios.ts +++ b/packages/integration-tests/src/__tests__/integration/postgresql/__scenarios.ts @@ -1,6 +1,7 @@ -import type { Input } from '../../__helpers__/integrationTest' import { Decimal } from 'decimal.js' +import type { Input } from '../../__helpers__/integrationTest' + export const scenarios = [ { name: 'findUnique where PK', diff --git a/packages/integration-tests/src/__tests__/integration/sqlite/__database.ts b/packages/integration-tests/src/__tests__/integration/sqlite/__database.ts index 5b87ddecb7fe..9838d286a5e2 100644 --- a/packages/integration-tests/src/__tests__/integration/sqlite/__database.ts +++ b/packages/integration-tests/src/__tests__/integration/sqlite/__database.ts @@ -1,4 +1,5 @@ import Database from 'sqlite-async' + import type { Input } from '../../__helpers__/integrationTest' export const database = { diff --git a/packages/integration-tests/src/__tests__/integration/sqlite/__scenarios.ts b/packages/integration-tests/src/__tests__/integration/sqlite/__scenarios.ts index be755eca5ad7..741a7a636b4f 100644 --- a/packages/integration-tests/src/__tests__/integration/sqlite/__scenarios.ts +++ b/packages/integration-tests/src/__tests__/integration/sqlite/__scenarios.ts @@ -1,6 +1,7 @@ -import type { Input } from '../../__helpers__/integrationTest' import { Decimal } from 'decimal.js' +import type { Input } from '../../__helpers__/integrationTest' + export const scenarios = [ { name: 'findUnique where PK', diff --git a/packages/integration-tests/src/index.ts b/packages/integration-tests/src/index.ts index 310d7d807122..336ce12bb910 100644 --- a/packages/integration-tests/src/index.ts +++ b/packages/integration-tests/src/index.ts @@ -1 +1 @@ -export { consoleContext, Context } from './__tests__/__helpers__/context' +export {} diff --git a/packages/integration-tests/tsconfig.eslint.json b/packages/integration-tests/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/integration-tests/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/migrate/.eslintignore b/packages/migrate/.eslintignore deleted file mode 100644 index b2052f4513f0..000000000000 --- a/packages/migrate/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules -dist -tmp -fixtures_old -src/utils/byline.ts -src/utils/charm -src/utils/charm.ts -*.test.ts diff --git a/packages/migrate/.eslintrc.js b/packages/migrate/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/migrate/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/migrate/.gitignore b/packages/migrate/.gitignore index 4bac77dfc7c0..1d794a93a39c 100644 --- a/packages/migrate/.gitignore +++ b/packages/migrate/.gitignore @@ -5,7 +5,6 @@ dist build .DS_Store tmp/ -.env* pnpm-debug.log write-test *.tsbuildinfo diff --git a/packages/migrate/jest.config.js b/packages/migrate/jest.config.js index 5cddf769aa04..f33488be969c 100644 --- a/packages/migrate/jest.config.js +++ b/packages/migrate/jest.config.js @@ -1,11 +1,14 @@ module.exports = { - preset: 'ts-jest', + transform: { + '^.+\\.ts$': '@swc/jest', + }, testEnvironment: 'node', testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], + snapshotSerializers: ['@prisma/sdk/src/utils/jestSnapshotSerializer'], coveragePathIgnorePatterns: [ 'bin.ts', 'setupMysql.ts', @@ -14,8 +17,18 @@ module.exports = { 'test-handlePanic.ts', 'test-interactivelyCreateDatabase.ts', ], - // todo duplicated serializer from client package, should share - snapshotSerializers: ['./src/__tests__/__helpers__/snapshotSerializer.ts'], // to get rid of "jest-haste-map: Haste module naming collision: package name" modulePathIgnorePatterns: ['/src/__tests__/fixtures/'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/migrate/package.json b/packages/migrate/package.json index 6dd66db1a3b4..c510da127ce3 100644 --- a/packages/migrate/package.json +++ b/packages/migrate/package.json @@ -2,7 +2,7 @@ "name": "@prisma/migrate", "version": "0.0.0", "main": "dist/index.js", - "module": "dist/esm/index.mjs", + "module": "esm/dist/index.mjs", "types": "dist/index.d.ts", "repository": { "type": "git", @@ -20,33 +20,23 @@ "version": "latest" }, "devDependencies": { - "@prisma/engines-version": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/engines-version": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/generator-helper": "workspace:*", "@prisma/sdk": "workspace:*", - "@types/jest": "27.4.0", - "@types/node": "12.20.39", - "@types/pg": "8.6.3", + "@swc/core": "1.2.141", + "@swc/jest": "0.2.17", + "@types/jest": "27.4.1", + "@types/node": "12.20.47", + "@types/pg": "8.6.5", "@types/prompts": "2.0.14", "@types/sqlite3": "3.1.8", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", - "chalk": "4.1.2", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", "fs-jetpack": "4.3.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", + "jest": "27.5.1", + "jest-junit": "13.0.0", "make-dir": "3.1.0", - "mariadb": "2.5.5", "mock-stdin": "1.0.0", - "pg": "8.7.1", - "prettier": "2.5.1", "tempy": "1.0.1", - "ts-jest": "27.1.2", "typescript": "4.5.4" }, "peerDependencies": { @@ -55,14 +45,19 @@ }, "dependencies": { "@prisma/debug": "workspace:*", - "@prisma/get-platform": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/get-platform": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@sindresorhus/slugify": "1.1.2", + "chalk": "4.1.2", "execa": "5.1.1", + "get-stdin": "8.0.0", "has-yarn": "2.1.0", "indent-string": "4.0.0", "log-update": "4.0.0", + "mariadb": "3.0.0", + "mssql": "8.0.2", "new-github-issue-url": "0.2.1", "open": "7.4.2", + "pg": "8.7.3", "pkg-up": "3.1.0", "prompts": "2.4.2", "strip-ansi": "6.0.1", @@ -71,12 +66,7 @@ "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "run": "node dist/bin.js", - "precommit": "lint-staged", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", "test": "jest --verbose", "prepublishOnly": "pnpm run build" }, @@ -84,11 +74,5 @@ "README.md", "dist" ], - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] - }, "sideEffects": false } diff --git a/packages/migrate/src/CLI.ts b/packages/migrate/src/CLI.ts new file mode 100644 index 000000000000..899801314597 --- /dev/null +++ b/packages/migrate/src/CLI.ts @@ -0,0 +1,63 @@ +import type { Command, Commands } from '@prisma/sdk' +import { arg, format, HelpError, isError, logger, unknownCommand } from '@prisma/sdk' +import chalk from 'chalk' + +/** + * CLI command + */ +export class CLI implements Command { + static new(cmds: Commands): CLI { + return new CLI(cmds) + } + private constructor(private readonly cmds: Commands) {} + + async parse(argv: string[]): Promise { + const args = arg(argv, { + '--help': Boolean, + '-h': '--help', + '--json': Boolean, // for -v + '--experimental': Boolean, + '--preview-feature': Boolean, + '--early-access-feature': Boolean, + '--telemetry-information': String, + }) + + if (isError(args)) { + return this.help(args.message) + } + + // display help for help flag or no subcommand + if (args._.length === 0 || args['--help']) { + return this.help() + } + + // check if we have that subcommand + const cmdName = args._[0] + const cmd = this.cmds[cmdName] + if (cmd) { + let argsForCmd: string[] + if (args['--experimental']) { + argsForCmd = [...args._.slice(1), `--experimental=${args['--experimental']}`] + } else if (args['--preview-feature']) { + argsForCmd = [...args._.slice(1), `--preview-feature=${args['--preview-feature']}`] + } else if (args['--early-access-feature']) { + argsForCmd = [...args._.slice(1), `--early-access-feature=${args['--early-access-feature']}`] + } else { + argsForCmd = args._.slice(1) + } + + return cmd.parse(argsForCmd) + } + // unknown command + return unknownCommand(this.help() as string, args._[0]) + } + + public help(error?: string) { + if (error) { + return new HelpError(`\n${chalk.bold.red(`!`)} ${error}\n${CLI.help}`) + } + return CLI.help + } + + private static help = format(`This is the internal CLI for @prisma/migrate`) +} diff --git a/packages/migrate/src/Migrate.ts b/packages/migrate/src/Migrate.ts index 3adc8cb6a25b..18a4eb180d17 100644 --- a/packages/migrate/src/Migrate.ts +++ b/packages/migrate/src/Migrate.ts @@ -1,32 +1,39 @@ -import { getGeneratorSuccessMessage, getSchemaPathSync, getGenerators } from '@prisma/sdk' -import chalk from 'chalk' import Debug from '@prisma/debug' +import { enginesVersion } from '@prisma/engines-version' +import { getGenerators, getGeneratorSuccessMessage, getSchemaPathSync } from '@prisma/sdk' +import chalk from 'chalk' import fs from 'fs' import logUpdate from 'log-update' import path from 'path' + import { MigrateEngine } from './MigrateEngine' -import type { EngineResults, EngineArgs } from './types' -import { enginesVersion } from '@prisma/engines-version' +import type { EngineArgs, EngineResults } from './types' import { NoSchemaFoundError } from './utils/errors' const debug = Debug('prisma:migrate') -const packageJson = eval(`require('../package.json')`) // tslint:disable-line +const packageJson = eval(`require('../package.json')`) export class Migrate { - get devMigrationsDir(): string { - return path.join(path.dirname(this.schemaPath), 'migrations/dev') - } public engine: MigrateEngine - private schemaPath: string - public migrationsDirectoryPath: string + private schemaPath?: string + public migrationsDirectoryPath?: string constructor(schemaPath?: string, enabledPreviewFeatures?: string[]) { - this.schemaPath = this.getSchemaPath(schemaPath) - this.migrationsDirectoryPath = path.join(path.dirname(this.schemaPath), 'migrations') - this.engine = new MigrateEngine({ - projectDir: path.dirname(this.schemaPath), - schemaPath: this.schemaPath, - enabledPreviewFeatures, - }) + // schemaPath and migrationsDirectoryPath is optionnal for primitives + // like migrate diff and db execute + if (schemaPath) { + this.schemaPath = this.getSchemaPath(schemaPath) + this.migrationsDirectoryPath = path.join(path.dirname(this.schemaPath), 'migrations') + this.engine = new MigrateEngine({ + projectDir: path.dirname(this.schemaPath), + schemaPath: this.schemaPath, + enabledPreviewFeatures, + }) + } else { + this.engine = new MigrateEngine({ + projectDir: process.cwd(), + enabledPreviewFeatures, + }) + } } public stop(): void { @@ -44,6 +51,8 @@ export class Migrate { } public getDatamodel(): string { + if (!this.schemaPath) throw new Error('this.schemaPath is undefined') + return fs.readFileSync(this.schemaPath, 'utf-8') } @@ -60,6 +69,8 @@ export class Migrate { }: { optInToShadowDatabase: boolean }): Promise { + if (!this.migrationsDirectoryPath) throw new Error('this.migrationsDirectoryPath is undefined') + return this.engine.diagnoseMigrationHistory({ migrationsDirectoryPath: this.migrationsDirectoryPath, optInToShadowDatabase, @@ -67,18 +78,24 @@ export class Migrate { } public listMigrationDirectories(): Promise { + if (!this.migrationsDirectoryPath) throw new Error('this.migrationsDirectoryPath is undefined') + return this.engine.listMigrationDirectories({ migrationsDirectoryPath: this.migrationsDirectoryPath, }) } public devDiagnostic(): Promise { + if (!this.migrationsDirectoryPath) throw new Error('this.migrationsDirectoryPath is undefined') + return this.engine.devDiagnostic({ migrationsDirectoryPath: this.migrationsDirectoryPath, }) } public async markMigrationApplied({ migrationId }: { migrationId: string }): Promise { + if (!this.migrationsDirectoryPath) throw new Error('this.migrationsDirectoryPath is undefined') + return await this.engine.markMigrationApplied({ migrationsDirectoryPath: this.migrationsDirectoryPath, migrationName: migrationId, @@ -92,12 +109,16 @@ export class Migrate { } public applyMigrations(): Promise { + if (!this.migrationsDirectoryPath) throw new Error('this.migrationsDirectoryPath is undefined') + return this.engine.applyMigrations({ migrationsDirectoryPath: this.migrationsDirectoryPath, }) } public evaluateDataLoss(): Promise { + if (!this.migrationsDirectoryPath) throw new Error('this.migrationsDirectoryPath is undefined') + const datamodel = this.getDatamodel() return this.engine.evaluateDataLoss({ @@ -122,6 +143,8 @@ export class Migrate { } public async tryToRunGenerate(): Promise { + if (!this.schemaPath) throw new Error('this.schemaPath is undefined') + const message: string[] = [] console.info() // empty line diff --git a/packages/migrate/src/MigrateEngine.ts b/packages/migrate/src/MigrateEngine.ts index 3745c917e13d..e5b16264ad49 100644 --- a/packages/migrate/src/MigrateEngine.ts +++ b/packages/migrate/src/MigrateEngine.ts @@ -1,29 +1,24 @@ import Debug from '@prisma/debug' import type { MigrateEngineLogLine } from '@prisma/sdk' -import { BinaryType, ErrorArea, resolveBinary, RustPanic, MigrateEngineExitCode } from '@prisma/sdk' +import { BinaryType, ErrorArea, MigrateEngineExitCode, resolveBinary, RustPanic } from '@prisma/sdk' import chalk from 'chalk' import type { ChildProcess } from 'child_process' import { spawn } from 'child_process' -import type { EngineArgs, EngineResults } from './types' + +import type { EngineArgs, EngineResults, RPCPayload, RpcSuccessResponse } from './types' import byline from './utils/byline' + const debugRpc = Debug('prisma:migrateEngine:rpc') const debugStderr = Debug('prisma:migrateEngine:stderr') const debugStdin = Debug('prisma:migrateEngine:stdin') export interface MigrateEngineOptions { projectDir: string - schemaPath: string + schemaPath?: string debug?: boolean enabledPreviewFeatures?: string[] } -export interface RPCPayload { - id: number - jsonrpc: string - method: string - params: any -} - export class EngineError extends Error { public code: number constructor(message: string, code: number) { @@ -34,12 +29,11 @@ export class EngineError extends Error { let messageId = 1 -/* tslint:disable */ export class MigrateEngine { private projectDir: string private debug: boolean private child?: ChildProcess - private schemaPath: string + private schemaPath?: string private listeners: { [key: string]: (result: any, err?: any) => any } = {} /** _All_ the logs from the engine process. */ private messages: string[] = [] @@ -103,6 +97,12 @@ export class MigrateEngine { public reset(): Promise { return this.runCommand(this.getRPCPayload('reset', undefined)) } + public dbExecute(args: EngineArgs.DbExecuteInput): Promise { + return this.runCommand(this.getRPCPayload('dbExecute', args)) + } + public migrateDiff(args: EngineArgs.MigrateDiffInput): Promise { + return this.runCommand(this.getRPCPayload('diff', args)) + } public getDatabaseVersion(): Promise { return this.runCommand(this.getRPCPayload('getDatabaseVersion', undefined)) } @@ -130,8 +130,11 @@ export class MigrateEngine { } catch (e) { console.error(`Could not parse migration engine response: ${response.slice(0, 200)}`) } + + // See https://www.jsonrpc.org/specification for the expected shape of messages. if (result) { - if (result.id) { + // It's a response + if (result.id && (result.result !== undefined || result.error !== undefined)) { if (!this.listeners[result.id]) { console.error(`Got result for unknown id ${result.id}`) } @@ -139,14 +142,20 @@ export class MigrateEngine { this.listeners[result.id](result) delete this.listeners[result.id] } - } else { - // If the error happens before the JSON-RPC sever starts, the error doesn't have an id - if (result.is_panic) { - throw new Error(`Response: ${result.message}`) - } else if (result.message) { - console.error(chalk.red(`Response: ${result.message}`)) - } else { - console.error(chalk.red(`Response: ${JSON.stringify(result)}`)) + } else if (result.method) { + // This is a request. + if (result.id !== undefined) { + if (result.method === 'print' && result.params?.content !== undefined) { + console.info(result.params.content) + + // Send an empty response back as ACK. + const response: RpcSuccessResponse<{}> = { + id: result.id, + jsonrpc: '2.0', + result: {}, + } + this.child!.stdin!.write(JSON.stringify(response) + '\n') + } } } } @@ -166,7 +175,12 @@ export class MigrateEngine { const { PWD, ...rest } = process.env const binaryPath = await resolveBinary(BinaryType.migrationEngine) debugRpc('starting migration engine with binary: ' + binaryPath) - const args = ['-d', this.schemaPath] + const args: string[] = [] + + if (this.schemaPath) { + args.push(...['-d', this.schemaPath]) + } + if ( this.enabledPreviewFeatures && Array.isArray(this.enabledPreviewFeatures) && @@ -229,6 +243,8 @@ export class MigrateEngine { debugStdin(err) }) + // logs (info, error) + // error can be a panic byline(this.child.stderr).on('data', (msg) => { const data = String(msg) debugStderr(data) @@ -236,10 +252,6 @@ export class MigrateEngine { try { const json: MigrateEngineLogLine = JSON.parse(data) - if (json.fields?.migrate_action === 'log') { - console.info(json.fields.message) - } - this.messages.push(json.fields.message) if (json.level === 'ERROR') { @@ -266,10 +278,13 @@ export class MigrateEngine { if (process.env.FORCE_PANIC_MIGRATION_ENGINE) { request = this.getRPCPayload('debugPanic', undefined) } + await this.init() + if (this.child?.killed) { throw new Error(`Can't execute ${JSON.stringify(request)} because migration engine already exited.`) } + return new Promise((resolve, reject) => { this.registerCallback(request.id, (response, err) => { if (err) { @@ -320,9 +335,11 @@ export class MigrateEngine { } } }) + if (this.child!.stdin!.destroyed) { throw new Error(`Can't execute ${JSON.stringify(request)} because migration engine is destroyed.`) } + debugRpc('SENDING RPC CALL', JSON.stringify(request)) this.child!.stdin!.write(JSON.stringify(request) + '\n') this.lastRequest = request diff --git a/packages/migrate/src/__tests__/DbDrop.test.ts b/packages/migrate/src/__tests__/DbDrop.test.ts index 7863dbba7a8c..09b659ecc355 100644 --- a/packages/migrate/src/__tests__/DbDrop.test.ts +++ b/packages/migrate/src/__tests__/DbDrop.test.ts @@ -1,13 +1,12 @@ -process.env.GITHUB_ACTIONS = '1' - +import { jestConsoleContext, jestContext } from '@prisma/sdk' import prompt from 'prompts' + import { DbDrop } from '../commands/DbDrop' -import { consoleContext, Context } from './__helpers__/context' // TODO: Windows: snapshot tests fail on Windows because of emoji and different error messages. const describeIf = (condition: boolean) => (condition ? describe : describe.skip) -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describeIf(process.platform !== 'win32')('drop', () => { it('requires --preview-feature flag', async () => { @@ -129,6 +128,8 @@ No such file or directory (os error 2) it('should ask for --force if not provided if CI', async () => { ctx.fixture('reset') + process.env.GITHUB_ACTIONS = '1' + const result = DbDrop.new().parse(['--preview-feature']) await expect(result).rejects.toMatchInlineSnapshot( `Use the --force flag to use the drop command in an unnattended environment like prisma db drop --force --preview-feature`, diff --git a/packages/migrate/src/__tests__/DbExecute.test.ts b/packages/migrate/src/__tests__/DbExecute.test.ts new file mode 100644 index 000000000000..6d2667d26763 --- /dev/null +++ b/packages/migrate/src/__tests__/DbExecute.test.ts @@ -0,0 +1,868 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' +import fs from 'fs' +import path from 'path' + +import { DbExecute } from '../commands/DbExecute' +import { setupMSSQL, tearDownMSSQL } from '../utils/setupMSSQL' +import { setupMysql, tearDownMysql } from '../utils/setupMysql' +import type { SetupParams } from '../utils/setupPostgres' +import { setupPostgres, tearDownPostgres } from '../utils/setupPostgres' + +const util = require('util') +const exec = util.promisify(require('child_process').exec) + +const ctx = jestContext.new().add(jestConsoleContext()).assemble() +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) +const testIf = (condition: boolean) => (condition ? test : test.skip) + +describe('db execute', () => { + describe('generic', () => { + it('--preview-feature flag is required', async () => { + ctx.fixture('empty') + + const result = DbExecute.new().parse([]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `This command is in Preview. Use the --preview-feature flag to use it like prisma db execute --preview-feature`, + ) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }) + + it('should fail if missing --file and --stdin', async () => { + ctx.fixture('empty') + + const result = DbExecute.new().parse(['--preview-feature']) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Either --stdin or --file must be provided. + See \`prisma db execute -h\` + `) + }) + + it('should fail if both --file and --stdin are provided', async () => { + ctx.fixture('empty') + + const result = DbExecute.new().parse(['--preview-feature', '--file=1', '--stdin']) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + --stdin and --file cannot be used at the same time. Only 1 must be provided. + See \`prisma db execute -h\` + `) + }) + + it('should fail if missing --schema and --url', async () => { + ctx.fixture('empty') + + const result = DbExecute.new().parse(['--preview-feature', '--file=1']) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Either --url or --schema must be provided. + See \`prisma db execute -h\` + `) + }) + + it('should fail if both --schema and --url are provided', async () => { + ctx.fixture('empty') + + const result = DbExecute.new().parse(['--preview-feature', '--stdin', '--schema=1', '--url=1']) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + --url and --schema cannot be used at the same time. Only 1 must be provided. + See \`prisma db execute -h\` + `) + }) + + it('should fail if --file does no exists', async () => { + ctx.fixture('empty') + expect.assertions(2) + + try { + await DbExecute.new().parse(['--preview-feature', '--file=./doesnotexists.sql', '--schema=1']) + } catch (e) { + expect(e.code).toEqual(undefined) + expect(e.message).toMatchInlineSnapshot(`Provided --file at ./doesnotexists.sql doesn't exist.`) + } + }) + + it('should fail if --schema does no exists', async () => { + ctx.fixture('empty') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse(['--preview-feature', '--file=./script.sql', '--schema=./doesnoexists.schema']) + } catch (e) { + expect(e.code).toEqual(undefined) + expect(e.message).toMatchInlineSnapshot(`Provided --schema at ./doesnoexists.schema doesn't exist.`) + } + }) + }) + + describe('mongodb', () => { + it('should fail with not supported error with --file --schema', async () => { + ctx.fixture('schema-only-mongodb') + + fs.writeFileSync('script.js', 'Something for MongoDB') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.js', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + dbExecute is not supported on MongoDB + + + `) + }) + }) + + describe('sqlite', () => { + const pathToBin = path.resolve('src/bin.ts') + const sqlScript = `-- Drop & Create & Drop +DROP TABLE IF EXISTS 'test-dbexecute'; +CREATE TABLE 'test-dbexecute' ("id" INTEGER PRIMARY KEY); +DROP TABLE 'test-dbexecute';` + + it('should pass if no schema file in directory with --file --url', async () => { + ctx.fixture('empty') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse(['--preview-feature', '--url=file:./dev.db', '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + // On Windows: snapshot output = "-- Drop & Create & Drop" + testIf(process.platform !== 'win32')( + 'should pass with --stdin --schema', + async () => { + ctx.fixture('schema-only-sqlite') + + const { stdout, stderr } = await exec( + `echo "${sqlScript}" | ${pathToBin} db execute --preview-feature --stdin --schema=./prisma/schema.prisma`, + ) + expect(stderr).toBeFalsy() + expect(stdout).toMatchInlineSnapshot(` + Script executed successfully. + + `) + }, + 20_000, + ) + + it('should pass with --file --schema', async () => { + ctx.fixture('schema-only-sqlite') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass using a transaction with --file --schema', async () => { + ctx.fixture('schema-only-sqlite') + + fs.writeFileSync( + 'script.sql', + `-- start a transaction +BEGIN; + +${sqlScript} + +-- commit changes +COMMIT;`, + ) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with --file --url=file:dev.db', async () => { + ctx.fixture('introspection/sqlite') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse(['--preview-feature', '--url=file:dev.db', '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with empty --file --url=file:dev.db', async () => { + ctx.fixture('introspection/sqlite') + + fs.writeFileSync('script.sql', '') + const result = DbExecute.new().parse(['--preview-feature', '--url=file:dev.db', '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should fail with P1013 error with invalid url with --file --url', async () => { + ctx.fixture('schema-only-sqlite') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse(['--preview-feature', '--url=invalidurl', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. \`invalidurl\` is not a known connection URL scheme. Prisma cannot determine the connector. in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + + // the default behavior with sqlite is to create the db if it doesn't exists, no failure expected + it('should pass with --file --url=file:doesnotexists.db', async () => { + ctx.fixture('introspection/sqlite') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse(['--preview-feature', '--url=file:doesnotexists.db', '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should fail with P1014 error with --file --schema', async () => { + ctx.fixture('schema-only-sqlite') + expect.assertions(2) + + fs.writeFileSync('script.sql', 'DROP TABLE "test-doesnotexists";') + try { + await DbExecute.new().parse(['--preview-feature', '--schema=./prisma/schema.prisma', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual('P1014') + expect(e.message).toMatchInlineSnapshot(` + P1014 + + The underlying table for model \`test-doesnotexists\` does not exist. + + `) + } + }) + + it('should fail with invalid SQL error from database with --file --schema', async () => { + ctx.fixture('schema-only-sqlite') + expect.assertions(2) + + fs.writeFileSync('script.sql', 'ThisisnotSQL,itshouldfail') + try { + await DbExecute.new().parse(['--preview-feature', '--schema=./prisma/schema.prisma', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual(undefined) + expect(e.message).toMatchInlineSnapshot(` + near "ThisisnotSQL": syntax error + + + `) + } + }) + }) + + describe('postgresql', () => { + const connectionString = ( + process.env.TEST_POSTGRES_URI_MIGRATE || 'postgres://prisma:prisma@localhost:5432/tests-migrate' + ).replace('tests-migrate', 'tests-migrate-db-execute') + + // Update env var because it's the one that is used in the schemas tested + process.env.TEST_POSTGRES_URI_MIGRATE = connectionString + + const setupParams: SetupParams = { + connectionString, + dirname: '', + } + + beforeAll(async () => { + await setupPostgres(setupParams).catch((e) => { + console.error(e) + }) + }) + + afterAll(async () => { + await tearDownPostgres(setupParams).catch((e) => { + console.error(e) + }) + }) + + const sqlScript = `-- Drop & Create & Drop +DROP SCHEMA IF EXISTS "test-dbexecute"; +CREATE SCHEMA "test-dbexecute"; +DROP SCHEMA "test-dbexecute";` + + it('should pass with --file --schema', async () => { + ctx.fixture('schema-only-postgresql') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should use env var from .env file', async () => { + ctx.fixture('schema-only-postgresql') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/using-dotenv.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toMatchInlineSnapshot(` + P1001 + + Can't reach database server at \`fromdotenvdoesnotexist\`:\`5432\` + + Please make sure your database server is running at \`fromdotenvdoesnotexist\`:\`5432\`. + + `) + }) + + it('should pass using a transaction with --file --schema', async () => { + ctx.fixture('schema-only-postgresql') + + fs.writeFileSync( + 'script.sql', + `-- start a transaction +BEGIN; + +${sqlScript} + +-- commit changes +COMMIT;`, + ) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with --file --url', async () => { + ctx.fixture('schema-only-postgresql') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse(['--preview-feature', '--url', connectionString, '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with empty --file --url', async () => { + ctx.fixture('schema-only-postgresql') + + fs.writeFileSync('script.sql', '') + const result = DbExecute.new().parse(['--preview-feature', '--url', connectionString, '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + // Limitation of postgresql + // DROP DATABASE cannot be executed from a function or multi-command string + // on GitHub Actions, for macOS and Windows it errors with + // DROP DATABASE cannot run inside a transaction block + it('should fail if DROP DATABASE with --file --schema', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(2) + + fs.writeFileSync( + 'script.sql', + `-- Drop & Create & Drop + DROP DATABASE IF EXISTS "test-dbexecute"; + CREATE DATABASE "test-dbexecute"; + DROP DATABASE "test-dbexecute";`, + ) + try { + await DbExecute.new().parse(['--preview-feature', '--schema=./prisma/schema.prisma', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual(undefined) + expect(e.message).toContain('ERROR: DROP DATABASE cannot') + } + }) + + it('should fail with P1013 error with invalid url with --file --url', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse([ + '--preview-feature', + '--url=postgresql://johndoe::::////::randompassword@doesnotexist/mydb', + '--file=./script.sql', + ]) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. invalid port number in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + it('should fail with P1013 error with invalid url provider with --file --url', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse(['--preview-feature', '--url=invalidurl', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. \`invalidurl\` is not a known connection URL scheme. Prisma cannot determine the connector. in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + + it('should fail with P1001 error with unreachable url with --file --url', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse([ + '--preview-feature', + '--url=postgresql://johndoe:randompassword@doesnotexist:5432/mydb?schema=public', + '--file=./script.sql', + ]) + } catch (e) { + expect(e.code).toEqual('P1001') + expect(e.message).toMatchInlineSnapshot(` + P1001 + + Can't reach database server at \`doesnotexist\`:\`5432\` + + Please make sure your database server is running at \`doesnotexist\`:\`5432\`. + + `) + } + }) + + it('should fail with P1003 error with --file --schema', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(2) + + fs.writeFileSync('script.sql', 'DROP DATABASE "test-doesnotexists";') + try { + await DbExecute.new().parse(['--preview-feature', '--schema=./prisma/schema.prisma', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual('P1003') + expect(e.message).toMatchInlineSnapshot(` + P1003 + + Database \`tests-migrate-db-execute.public\` does not exist on the database server at \`localhost:5432\`. + + `) + } + }) + + it('should fail with invalid SQL error from database with --file --schema', async () => { + ctx.fixture('schema-only-postgresql') + + fs.writeFileSync('script.sql', 'ThisisnotSQLitshouldfail') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + db error: ERROR: syntax error at or near "ThisisnotSQLitshouldfail" + + + `) + }) + }) + + describe('mysql', () => { + const connectionString = ( + process.env.TEST_MYSQL_URI_MIGRATE || 'mysql://root:root@localhost:3306/tests-migrate' + ).replace('tests-migrate', 'tests-migrate-db-execute') + + // Update env var because it's the one that is used in the schemas tested + process.env.TEST_MYSQL_URI_MIGRATE = connectionString + + const setupParams: SetupParams = { + connectionString, + dirname: '', + } + + beforeAll(async () => { + await setupMysql(setupParams).catch((e) => { + console.error(e) + }) + }) + + afterAll(async () => { + await tearDownMysql(setupParams).catch((e) => { + console.error(e) + }) + }) + + const sqlScript = `-- Drop & Create & Drop +DROP DATABASE IF EXISTS \`test-dbexecute\`; +CREATE DATABASE \`test-dbexecute\`; +DROP DATABASE \`test-dbexecute\`;` + + it('should pass with --file --schema', async () => { + ctx.fixture('schema-only-mysql') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + // Only fails on MySQL + it('should fail with empty --file --schema', async () => { + ctx.fixture('schema-only-mysql') + + fs.writeFileSync('script.sql', '') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Query was empty + + + `) + }) + + it('should pass using a transaction with --file --schema', async () => { + ctx.fixture('schema-only-mysql') + + fs.writeFileSync( + 'script.sql', + `-- start a transaction +START TRANSACTION; + +${sqlScript} + +-- commit changes +COMMIT;`, + ) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with --file --url', async () => { + ctx.fixture('schema-only-mysql') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse(['--preview-feature', '--url', connectionString, '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should fail with P1013 error with invalid url with --file --url', async () => { + ctx.fixture('schema-only-mysql') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse([ + '--preview-feature', + '--url=mysql://johndoe::::////::randompassword@doesnotexist:3306/mydb', + '--file=./script.sql', + ]) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. invalid port number in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + it('should fail with P1013 error with invalid url provider with --file --url', async () => { + ctx.fixture('schema-only-mysql') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse(['--preview-feature', '--url=invalidurl', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. \`invalidurl\` is not a known connection URL scheme. Prisma cannot determine the connector. in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + + it('should fail with P1001 error with unreachable url with --file --url', async () => { + ctx.fixture('schema-only-mysql') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse([ + '--preview-feature', + '--url=mysql://johndoe:randompassword@doesnotexist:3306/mydb', + '--file=./script.sql', + ]) + } catch (e) { + expect(e.code).toEqual('P1001') + expect(e.message).toMatchInlineSnapshot(` + P1001 + + Can't reach database server at \`doesnotexist\`:\`3306\` + + Please make sure your database server is running at \`doesnotexist\`:\`3306\`. + + `) + } + }) + + it('should fail with SQL error from database with --file --schema', async () => { + ctx.fixture('schema-only-mysql') + + fs.writeFileSync('script.sql', 'DROP DATABASE `test-doesnotexists`;') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Can't drop database 'test-doesnotexists'; database doesn't exist + + + `) + }) + + it('should fail with invalid SQL error from database with --file --schema', async () => { + ctx.fixture('schema-only-mysql') + + fs.writeFileSync('script.sql', 'This is not SQL, it should fail') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'This is not SQL, it should fail' at line 1 + + + `) + }) + }) + + describeIf(!process.env.TEST_SKIP_MSSQL)('sqlserver', () => { + const jdbcConnectionString = ( + process.env.TEST_MSSQL_JDBC_URI_MIGRATE || + 'sqlserver://mssql:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;' + ).replace('tests-migrate', 'tests-migrate-db-execute') + + // Update env var because it's the one that is used in the schemas tested + process.env.TEST_MSSQL_JDBC_URI_MIGRATE = jdbcConnectionString + + const setupParams: SetupParams = { + connectionString: process.env.TEST_MSSQL_URI!, + dirname: '', + } + + beforeAll(async () => { + await setupMSSQL(setupParams, 'tests-migrate-db-execute').catch((e) => { + console.error(e) + }) + }) + + afterAll(async () => { + await tearDownMSSQL(setupParams, 'tests-migrate-db-execute').catch((e) => { + console.error(e) + }) + }) + + const sqlScript = `-- Drop & Create & Drop +DROP DATABASE IF EXISTS "test-dbexecute"; +CREATE DATABASE "test-dbexecute"; +DROP DATABASE "test-dbexecute";` + + it('should pass with --file --schema', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with empty --file --schema', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync('script.sql', '') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass with --file --url', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync('script.sql', sqlScript) + const result = DbExecute.new().parse(['--preview-feature', '--url', jdbcConnectionString, '--file=./script.sql']) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + it('should pass using a transaction with --file --schema', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync( + 'script.sql', + `-- start a transaction +BEGIN TRANSACTION; + +SELECT 1 + +-- commit changes +COMMIT;`, + ) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).resolves.toMatchInlineSnapshot(`Script executed successfully.`) + }) + + // Limitation of sqlserver + // DROP DATABASE statement cannot be used inside a user transaction. + it('should fail if DROP DATABASE in a transaction with --file --schema', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync( + 'script.sql', + `-- start a transaction +BEGIN TRANSACTION; + +${sqlScript} + +-- commit changes +COMMIT;`, + ) + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + DROP DATABASE statement cannot be used inside a user transaction. + + + `) + }) + + it('should fail with P1013 error with invalid url with --file --url', async () => { + ctx.fixture('schema-only-sqlserver') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse([ + '--preview-feature', + '--url=sqlserver://doesnotexist:1433;;;;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;', + '--file=./script.sql', + ]) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. Error parsing connection string: Conversion error: Invalid property key in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + it('should fail with P1013 error with invalid url provider with --file --url', async () => { + ctx.fixture('schema-only-sqlserver') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse(['--preview-feature', '--url=invalidurl', '--file=./script.sql']) + } catch (e) { + expect(e.code).toEqual('P1013') + expect(e.message).toMatchInlineSnapshot(` + P1013 + + The provided database string is invalid. \`invalidurl\` is not a known connection URL scheme. Prisma cannot determine the connector. in database URL. Please refer to the documentation in https://www.prisma.io/docs/reference/database-reference/connection-urls for constructing a correct connection string. In some cases, certain characters must be escaped. Please check the string for any illegal characters. + + `) + } + }) + + it('should fail with P1001 error with unreachable url with --file --url', async () => { + ctx.fixture('schema-only-sqlserver') + expect.assertions(2) + + fs.writeFileSync('script.sql', '-- empty') + try { + await DbExecute.new().parse([ + '--preview-feature', + '--url=sqlserver://doesnotexist:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;', + '--file=./script.sql', + ]) + } catch (e) { + // It should error with P1001 but code is undefined + // Tracked in following issue: + // https://github.com/prisma/prisma/issues/11407 + expect(e.code).toEqual(undefined) + expect(e.message).toMatchInlineSnapshot(` + Error creating a database connection. + + + `) + } + }) + + it('should fail with SQL error from database with --file --schema', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync('script.sql', 'DROP DATABASE "test-doesnotexists";') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Cannot drop the database 'test-doesnotexists', because it does not exist or you do not have permission. + + + `) + }) + + it('should fail with invalid SQL error from database with --file --schema', async () => { + ctx.fixture('schema-only-sqlserver') + + fs.writeFileSync('script.sql', 'ThisisnotSQLitshouldfail') + const result = DbExecute.new().parse([ + '--preview-feature', + '--schema=./prisma/schema.prisma', + '--file=./script.sql', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Could not find stored procedure 'ThisisnotSQLitshouldfail'. + + + `) + }) + }) +}) diff --git a/packages/migrate/src/__tests__/DbPull.test.ts b/packages/migrate/src/__tests__/DbPull.test.ts index 23ef536efbba..bc954a9efe2f 100644 --- a/packages/migrate/src/__tests__/DbPull.test.ts +++ b/packages/migrate/src/__tests__/DbPull.test.ts @@ -1,9 +1,11 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' import path from 'path' + import { DbPull } from '../commands/DbPull' -import { consoleContext, Context } from './__helpers__/context' -import { SetupParams, setupPostgres, tearDownPostgres } from '../utils/setupPostgres' -import { setupMysql, tearDownMysql } from '../utils/setupMysql' import { setupMSSQL, tearDownMSSQL } from '../utils/setupMSSQL' +import { setupMysql, tearDownMysql } from '../utils/setupMysql' +import type { SetupParams } from '../utils/setupPostgres' +import { setupPostgres, tearDownPostgres } from '../utils/setupPostgres' const isMacOrWindowsCI = Boolean(process.env.CI) && ['darwin', 'win32'].includes(process.platform) @@ -14,13 +16,14 @@ if (isMacOrWindowsCI) { const describeIf = (condition: boolean) => (condition ? describe : describe.skip) const testIf = (condition: boolean) => (condition ? test : test.skip) -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('common/sqlite', () => { test('basic introspection', async () => { ctx.fixture('introspection/sqlite') const introspect = new DbPull() - await introspect.parse(['--print']) + const result = introspect.parse(['--print']) + await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -29,7 +32,8 @@ describe('common/sqlite', () => { test('introspection --force', async () => { ctx.fixture('introspection/sqlite') const introspect = new DbPull() - await introspect.parse(['--print', '--force']) + const result = introspect.parse(['--print', '--force']) + await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -53,7 +57,7 @@ describe('common/sqlite', () => { ctx.fixture('introspection/sqlite') const introspect = new DbPull() const result = introspect.parse(['--print', '--url', 'invalidstring']) - await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`Unknown database type invalidstring:`) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`Unknown protocol invalidstring:`) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -63,7 +67,6 @@ describe('common/sqlite', () => { ctx.fixture('introspect/prisma') const result = DbPull.new().parse([]) await expect(result).resolves.toMatchInlineSnapshot(``) - expect(ctx.mocked['console.log'].mock.calls.join('\n').replace(/\d{2,3}ms/, 'XXms')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from schema.prisma @@ -86,7 +89,6 @@ describe('common/sqlite', () => { ctx.fixture('introspect/prisma') const result = DbPull.new().parse(['--url=file:./dev.db']) await expect(result).resolves.toMatchInlineSnapshot(``) - expect(ctx.mocked['console.log'].mock.calls.join('\n').replace(/\d{2,3}ms/, 'XXms')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from schema.prisma @@ -105,9 +107,9 @@ describe('common/sqlite', () => { const introspect = new DbPull() const result = introspect.parse(['--print', '--url', 'postgresql://root:prisma@/prisma']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Error parsing connection string: empty host in database URL + Error parsing connection string: empty host in database URL - `) + `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -188,19 +190,18 @@ describe('common/sqlite', () => { const originalSchema = ctx.fs.read('prisma/reintrospection.prisma') const result = DbPull.new().parse(['--print', '--schema=./prisma/reintrospection.prisma']) await expect(result).resolves.toMatchInlineSnapshot(``) - expect(ctx.mocked['console.log'].mock.calls.join('\n').replace(/\d{2,3}ms/, 'in XXms')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` - // *** WARNING *** - // - // These models were enriched with \`@@map\` information taken from the previous Prisma schema. - // - Model "AwesomeNewPost" - // - Model "AwesomeProfile" - // - Model "AwesomeUser" - // - `) + // *** WARNING *** + // + // These models were enriched with \`@@map\` information taken from the previous Prisma schema. + // - Model "AwesomeNewPost" + // - Model "AwesomeProfile" + // - Model "AwesomeUser" + // + `) expect(ctx.fs.read('prisma/reintrospection.prisma')).toStrictEqual(originalSchema) }) @@ -209,7 +210,6 @@ describe('common/sqlite', () => { ctx.fixture('existing-db-histories-diverge') const result = DbPull.new().parse([]) await expect(result).resolves.toMatchInlineSnapshot(``) - expect(ctx.mocked['console.log'].mock.calls.join('\n').replace(/\d{2,3}ms/, 'in XXms')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma @@ -229,19 +229,18 @@ describe('common/sqlite', () => { const result = DbPull.new().parse([]) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - P4001 The introspected database was empty: - - prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. + P4001 The introspected database was empty: - To fix this, you have two options: + prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. - - manually create a table in your database. - - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). + To fix this, you have two options: - Then you can run prisma db pull again. + - manually create a table in your database. + - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). - `) + Then you can run prisma db pull again. + `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma @@ -258,19 +257,18 @@ describe('common/sqlite', () => { const result = DbPull.new().parse([]) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - P4001 The introspected database was empty: + P4001 The introspected database was empty: - prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. + prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. - To fix this, you have two options: + To fix this, you have two options: - - manually create a table in your database. - - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). + - manually create a table in your database. + - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). - Then you can run prisma db pull again. - - `) + Then you can run prisma db pull again. + `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma @@ -365,7 +363,8 @@ describe('postgresql', () => { test('basic introspection', async () => { ctx.fixture('introspection/postgresql') const introspect = new DbPull() - await introspect.parse(['--print']) + const result = introspect.parse(['--print']) + await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -379,6 +378,45 @@ describe('postgresql', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) + + test('introspection should load .env file with --print', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(5) + + try { + await DbPull.new().parse(['--print', '--schema=./prisma/using-dotenv.prisma']) + } catch (e) { + expect(e.code).toEqual('P1001') + expect(e.message).toContain(`fromdotenvdoesnotexist`) + } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }) + + test('introspection should load .env file without --print', async () => { + ctx.fixture('schema-only-postgresql') + expect.assertions(5) + + try { + await DbPull.new().parse(['--schema=./prisma/using-dotenv.prisma']) + } catch (e) { + expect(e.code).toEqual('P1001') + expect(e.message).toContain(`fromdotenvdoesnotexist`) + } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Prisma schema loaded from prisma/using-dotenv.prisma + Environment variables loaded from prisma/.env + Datasource "my_db": PostgreSQL database "mydb", schema "public" at "fromdotenvdoesnotexist:5432" + + Introspecting based on datasource defined in prisma/using-dotenv.prisma … + + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }) }) describe('mysql', () => { @@ -408,7 +446,8 @@ describe('mysql', () => { test('basic introspection', async () => { ctx.fixture('introspection/mysql') const introspect = new DbPull() - await introspect.parse(['--print']) + const result = introspect.parse(['--print']) + await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -440,19 +479,19 @@ describeIf(!process.env.TEST_SKIP_MSSQL)('SQL Server', () => { 'sqlserver://localhost:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;' beforeAll(async () => { - await tearDownMSSQL(setupParams).catch((e) => { + await tearDownMSSQL(setupParams, 'tests-migrate').catch((e) => { console.error(e) }) }) beforeEach(async () => { - await setupMSSQL(setupParams).catch((e) => { + await setupMSSQL(setupParams, 'tests-migrate').catch((e) => { console.error(e) }) }) afterEach(async () => { - await tearDownMSSQL(setupParams).catch((e) => { + await tearDownMSSQL(setupParams, 'tests-migrate').catch((e) => { console.error(e) }) }) @@ -460,7 +499,8 @@ describeIf(!process.env.TEST_SKIP_MSSQL)('SQL Server', () => { test('basic introspection', async () => { ctx.fixture('introspection/sqlserver') const introspect = new DbPull() - await introspect.parse(['--print']) + const result = introspect.parse(['--print']) + await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) @@ -480,118 +520,372 @@ describeIf(!process.env.TEST_SKIP_MSSQL)('SQL Server', () => { // TODO: macOS: disabled on CI because it fails with timeout. Somehow jest.setTimeout // doesn't seem to work in this test case particularly. describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { - const MONGO_URI = process.env.TEST_MONGO_URI || 'mongodb://root:prisma@localhost:27017/tests?authSource=admin' + const MONGO_URI = + process.env.TEST_MONGO_URI_MIGRATE || 'mongodb://root:prisma@localhost:27017/tests-migrate?authSource=admin' + // describeIf is making eslint not happy about the names + // eslint-disable-next-line jest/no-identical-title test('basic introspection', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() - await introspect.parse(['--schema=./prisma/no-model.prisma']) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + const result = introspect.parse(['--schema=./prisma/no-model.prisma']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/no-model.prisma Datasource "my_db" Introspecting based on datasource defined in prisma/no-model.prisma … - ✔ Introspected 1 model and wrote it into prisma/no-model.prisma in XXXms + ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/no-model.prisma in XXXms + *** WARNING *** + + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + - Model "users", field: "numberOrString1", chosen data type: "Json" + - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + Run prisma generate to generate Prisma Client. `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) - test('introspection --print', async () => { + test('introspection --force (existing models)', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() - await introspect.parse(['--print']) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() - expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + const result = introspect.parse(['--force']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Prisma schema loaded from prisma/schema.prisma + Datasource "my_db" + + Introspecting based on datasource defined in prisma/schema.prisma … + + ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/schema.prisma in XXXms + + *** WARNING *** + + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + - Model "users", field: "numberOrString1", chosen data type: "Json" + - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + + Run prisma generate to generate Prisma Client. + `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) - test('introspection --print --composite-type-depth=0', async () => { + test('introspection --print (no existing models)', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() - await introspect.parse(['--print', '--composite-type-depth=0']) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + const result = introspect.parse(['--schema=./prisma/no-model.prisma', '--print']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(` + generator client { + provider = "prisma-client-js" + previewFeatures = ["mongoDb"] + } + + datasource my_db { + provider = "mongodb" + url = env("TEST_MONGO_URI_MIGRATE") + } + + type UsersHobbies { + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString2 Json? + objects UsersHobbiesObjects[] + tags String[] + } + + type UsersHobbiesObjects { + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString3 Json + tags String[] + } + + model users { + id String @id @default(auto()) @map("_id") @my_db.ObjectId + admin Boolean + email String + hobbies UsersHobbies[] + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString1 Json + } + + + // introspectionSchemaVersion: NonPrisma, + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + // + `) }) - test('introspection --print --composite-type-depth=1', async () => { + test('introspection --print --composite-type-depth=0 (no existing models)', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() - await introspect.parse(['--print', '--composite-type-depth=1']) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + const result = introspect.parse(['--schema=./prisma/no-model.prisma', '--print', '--composite-type-depth=0']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(` + generator client { + provider = "prisma-client-js" + previewFeatures = ["mongoDb"] + } + + datasource my_db { + provider = "mongodb" + url = env("TEST_MONGO_URI_MIGRATE") + } + + model users { + id String @id @default(auto()) @map("_id") @my_db.ObjectId + admin Boolean + email String + hobbies Json[] + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString1 Json + } + + + // introspectionSchemaVersion: NonPrisma, + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // + `) }) - test('introspection --print --composite-type-depth=-1', async () => { + test('introspection --print --composite-type-depth=1 (no existing models)', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() - await introspect.parse(['--print', '--composite-type-depth=-1']) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + const result = introspect.parse(['--schema=./prisma/no-model.prisma', '--print', '--composite-type-depth=1']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(` + generator client { + provider = "prisma-client-js" + previewFeatures = ["mongoDb"] + } + + datasource my_db { + provider = "mongodb" + url = env("TEST_MONGO_URI_MIGRATE") + } + + type UsersHobbies { + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString2 Json? + objects Json[] + tags String[] + } + + model users { + id String @id @default(auto()) @map("_id") @my_db.ObjectId + admin Boolean + email String + hobbies UsersHobbies[] + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString1 Json + } + + + // introspectionSchemaVersion: NonPrisma, + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + // + `) + }) + + test('introspection --force --composite-type-depth=-1 (existing models)', async () => { + ctx.fixture('schema-only-mongodb') + const introspect = new DbPull() + const result = introspect.parse(['--force', '--composite-type-depth=-1']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Prisma schema loaded from prisma/schema.prisma + Datasource "my_db" + + Introspecting based on datasource defined in prisma/schema.prisma … + + ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/schema.prisma in XXXms + + *** WARNING *** + + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + - Model "users", field: "numberOrString1", chosen data type: "Json" + - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + + Run prisma generate to generate Prisma Client. + `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) + test('introspection --print --composite-type-depth=-1 (no existing models)', async () => { + ctx.fixture('schema-only-mongodb') + const introspect = new DbPull() + const result = introspect.parse(['--schema=./prisma/no-model.prisma', '--print', '--composite-type-depth=-1']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(` + generator client { + provider = "prisma-client-js" + previewFeatures = ["mongoDb"] + } + + datasource my_db { + provider = "mongodb" + url = env("TEST_MONGO_URI_MIGRATE") + } + + type UsersHobbies { + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString2 Json? + objects UsersHobbiesObjects[] + tags String[] + } + + type UsersHobbiesObjects { + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString3 Json + tags String[] + } + + model users { + id String @id @default(auto()) @map("_id") @my_db.ObjectId + admin Boolean + email String + hobbies UsersHobbies[] + name String + /// Multiple data types found: String: 50%, Int: 50% out of 2 sampled entries + numberOrString1 Json + } + + + // introspectionSchemaVersion: NonPrisma, + `) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + // + `) + }) + + // describeIf is making eslint not happy about the names + // eslint-disable-next-line jest/no-identical-title test('basic introspection --url', async () => { const introspect = new DbPull() const result = introspect.parse(['--print', '--url', MONGO_URI]) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Preview feature not enabled: MongoDB introspection connector (experimental feature, needs to be enabled) + Preview feature not enabled: MongoDB Introspection connector is a Preview feature and needs the \`mongoDb\` Preview feature flag. See https://www.prisma.io/docs/concepts/database-connectors/mongodb `) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) + // In this case it should not error and the line `Datasource "x"` not be printed + test('introspection --url - only generator defined', async () => { + ctx.fixture('schema-only-mongodb/only-generator') + const introspect = new DbPull() + const result = introspect.parse(['--url', MONGO_URI]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).not.toContain(`Datasource `) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Prisma schema loaded from schema.prisma + + Introspecting … + + ✔ Introspected 1 model and 2 embedded documents and wrote them into schema.prisma in XXXms + + *** WARNING *** + + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + - Model "users", field: "numberOrString1", chosen data type: "Json" + - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + + Run prisma generate to generate Prisma Client. + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }) + test('introspection with --force', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() const result = introspect.parse(['--force']) await expect(result).resolves.toMatchInlineSnapshot(``) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db" Introspecting based on datasource defined in prisma/schema.prisma … - ✔ Introspected 1 model and wrote it into prisma/schema.prisma in XXXms + ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/schema.prisma in XXXms + *** WARNING *** + + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + - Model "users", field: "numberOrString1", chosen data type: "Json" + - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + Run prisma generate to generate Prisma Client. `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) - test('re-introspection should error (not supported)', async () => { + test('re-introspection should error (not supported) (existing models)', async () => { ctx.fixture('schema-only-mongodb') const introspect = new DbPull() - await introspect.parse(['--schema=./prisma/no-model.prisma']) - // now re-introspection - const result = introspect.parse(['--schema=./prisma/no-model.prisma']) + const result = introspect.parse([]) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` Iterating on one schema using re-introspection with db pull is currently not supported with MongoDB provider (Preview). You can explicitely ignore and override your current local schema file with prisma db pull --force Some information will be lost (relations, comments, mapped fields, @ignore...), follow https://github.com/prisma/prisma/issues/9585 for more info. `) - expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` - Prisma schema loaded from prisma/no-model.prisma - Datasource "my_db" - - Introspecting based on datasource defined in prisma/no-model.prisma … - - ✔ Introspected 1 model and wrote it into prisma/no-model.prisma in XXXms - - Run prisma generate to generate Prisma Client. - Prisma schema loaded from prisma/no-model.prisma + Prisma schema loaded from prisma/schema.prisma Datasource "my_db" - - Introspecting based on datasource defined in prisma/no-model.prisma … `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) diff --git a/packages/migrate/src/__tests__/DbPush.test.ts b/packages/migrate/src/__tests__/DbPush.test.ts index edc9658a07d4..55238cdfc91d 100644 --- a/packages/migrate/src/__tests__/DbPush.test.ts +++ b/packages/migrate/src/__tests__/DbPush.test.ts @@ -1,14 +1,14 @@ -process.env.GITHUB_ACTIONS = '1' -process.env.PRISMA_MIGRATE_SKIP_GENERATE = '1' - +import { jestConsoleContext, jestContext } from '@prisma/sdk' import prompt from 'prompts' + import { DbPush } from '../commands/DbPush' -import { consoleContext, Context } from './__helpers__/context' + +process.env.PRISMA_MIGRATE_SKIP_GENERATE = '1' // TODO: Windows: a lot of snapshot tests here fail on Windows because of emoji. const describeIf = (condition: boolean) => (condition ? describe : describe.skip) -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describeIf(process.platform !== 'win32')('push', () => { it('--preview-feature flag is not required anymore', async () => { @@ -94,6 +94,8 @@ describeIf(process.platform !== 'win32')('push', () => { it('should ask for --accept-data-loss if not provided in CI', async () => { ctx.fixture('existing-db-warnings') + process.env.GITHUB_ACTIONS = '1' + const result = DbPush.new().parse([]) await expect(result).rejects.toMatchInlineSnapshot( `Use the --accept-data-loss flag to ignore the data loss warnings like prisma db push --accept-data-loss`, @@ -239,6 +241,8 @@ describeIf(process.platform !== 'win32')('push', () => { it('unexecutable - should ask for --force-reset in CI', async () => { ctx.fixture('existing-db-1-unexecutable-schema-change') + process.env.GITHUB_ACTIONS = '1' + const result = DbPush.new().parse([]) await expect(result).rejects.toMatchInlineSnapshot(` diff --git a/packages/migrate/src/__tests__/DbSeed.test.ts b/packages/migrate/src/__tests__/DbSeed.test.ts index 1853013ac107..08ab502bfc99 100644 --- a/packages/migrate/src/__tests__/DbSeed.test.ts +++ b/packages/migrate/src/__tests__/DbSeed.test.ts @@ -1,12 +1,13 @@ -import fs from 'fs-jetpack' +import { jestConsoleContext, jestContext } from '@prisma/sdk' import execa from 'execa' +import fs from 'fs-jetpack' + import { DbSeed } from '../commands/DbSeed' -import { consoleContext, Context } from './__helpers__/context' // TODO: Windows: snapshot tests fail on Windows because of emoji. const describeIf = (condition: boolean) => (condition ? describe : describe.skip) -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describeIf(process.platform !== 'win32')('seed', () => { it('seed.js', async () => { @@ -15,8 +16,8 @@ describeIf(process.platform !== 'win32')('seed', () => { const result = DbSeed.new().parse([]) await expect(result).resolves.toMatchInlineSnapshot(` - 🌱 The seed command has been executed. - `) + 🌱 The seed command has been executed. + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( `Running seed command \`node prisma/seed.js\` ...`, @@ -46,13 +47,13 @@ describeIf(process.platform !== 'win32')('seed', () => { const result = DbSeed.new().parse([]) await expect(result).resolves.toMatchInlineSnapshot(` - 🌱 The seed command has been executed. - `) + 🌱 The seed command has been executed. + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( `Running seed command \`ts-node prisma/seed.ts\` ...`, ) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) - }) + }, 10_000) it('seed.ts - ESM', async () => { ctx.fixture('seed-sqlite-ts-esm') @@ -63,15 +64,15 @@ describeIf(process.platform !== 'win32')('seed', () => { const result = DbSeed.new().parse([]) await expect(result).resolves.toMatchInlineSnapshot(` - 🌱 The seed command has been executed. - `) + 🌱 The seed command has been executed. + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( `Running seed command \`node --loader ts-node/esm prisma/seed.ts\` ...`, ) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) // "high" number since npm install can sometimes be slow - }, 20000) + }, 30_000) it('seed.sh', async () => { ctx.fixture('seed-sqlite-sh') @@ -79,8 +80,8 @@ describeIf(process.platform !== 'win32')('seed', () => { const result = DbSeed.new().parse([]) await expect(result).resolves.toMatchInlineSnapshot(` - 🌱 The seed command has been executed. - `) + 🌱 The seed command has been executed. + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( `Running seed command \`./prisma/seed.sh\` ...`, ) @@ -172,8 +173,8 @@ https://pris.ly/d/seeding const result = DbSeed.new().parse(['--preview-feature']) await expect(result).resolves.toMatchInlineSnapshot(` - 🌱 The seed command has been executed. - `) + 🌱 The seed command has been executed. + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( `Running seed command \`node prisma/seed.js\` ...`, ) @@ -191,8 +192,8 @@ https://pris.ly/d/seeding const result = DbSeed.new().parse(['--schema=./some-folder/schema.prisma']) await expect(result).resolves.toMatchInlineSnapshot(` - 🌱 The seed command has been executed. - `) + 🌱 The seed command has been executed. + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( `Running seed command \`node prisma/seed.js\` ...`, ) diff --git a/packages/migrate/src/__tests__/MigrateCommand.test.ts b/packages/migrate/src/__tests__/MigrateCommand.test.ts index 968550d7cb4b..03517963dcd3 100644 --- a/packages/migrate/src/__tests__/MigrateCommand.test.ts +++ b/packages/migrate/src/__tests__/MigrateCommand.test.ts @@ -3,9 +3,7 @@ import { MigrateDev } from '../commands/MigrateDev' it('no params should return help', async () => { const commandInstance = MigrateCommand.new({}) - const spy = jest - .spyOn(commandInstance, 'help') - .mockImplementation(() => 'Help Me') + const spy = jest.spyOn(commandInstance, 'help').mockImplementation(() => 'Help Me') await commandInstance.parse([]) expect(spy).toHaveBeenCalledTimes(1) @@ -14,9 +12,7 @@ it('no params should return help', async () => { it('wrong flag', async () => { const commandInstance = MigrateCommand.new({}) - const spy = jest - .spyOn(commandInstance, 'help') - .mockImplementation(() => 'Help Me') + const spy = jest.spyOn(commandInstance, 'help').mockImplementation(() => 'Help Me') await commandInstance.parse(['--something']) expect(spy).toHaveBeenCalledTimes(1) @@ -25,9 +21,7 @@ it('wrong flag', async () => { it('help flag', async () => { const commandInstance = MigrateCommand.new({}) - const spy = jest - .spyOn(commandInstance, 'help') - .mockImplementation(() => 'Help Me') + const spy = jest.spyOn(commandInstance, 'help').mockImplementation(() => 'Help Me') await commandInstance.parse(['--help']) expect(spy).toHaveBeenCalledTimes(1) @@ -35,9 +29,7 @@ it('help flag', async () => { }) it('unknown command', async () => { - await expect( - MigrateCommand.new({}).parse(['doesnotexist']), - ).resolves.toThrowError() + await expect(MigrateCommand.new({}).parse(['doesnotexist'])).resolves.toThrowError() }) it('dev with --preview-feature flag', async () => { @@ -53,32 +45,28 @@ it('dev with --preview-feature flag', async () => { describe('legacy', () => { it('experimental flag', async () => { - await expect(MigrateCommand.new({}).parse(['--experimental'])).rejects - .toMatchInlineSnapshot(` + await expect(MigrateCommand.new({}).parse(['--experimental'])).rejects.toMatchInlineSnapshot(` Prisma Migrate was Experimental and is now Generally Available. WARNING this new version has some breaking changes to use it it's recommended to read the documentation first and remove the --experimental flag. `) }) it('up command', async () => { - await expect(MigrateCommand.new({}).parse(['up'])).rejects - .toMatchInlineSnapshot(` + await expect(MigrateCommand.new({}).parse(['up'])).rejects.toMatchInlineSnapshot(` The current command "up" doesn't exist in the new version of Prisma Migrate. Read more about how to upgrade: https://pris.ly/d/migrate-upgrade `) }) it('down command', async () => { - await expect(MigrateCommand.new({}).parse(['down'])).rejects - .toMatchInlineSnapshot(` + await expect(MigrateCommand.new({}).parse(['down'])).rejects.toMatchInlineSnapshot(` The current command "down" doesn't exist in the new version of Prisma Migrate. Read more about how to upgrade: https://pris.ly/d/migrate-upgrade `) }) it('save command', async () => { - await expect(MigrateCommand.new({}).parse(['save'])).rejects - .toMatchInlineSnapshot(` + await expect(MigrateCommand.new({}).parse(['save'])).rejects.toMatchInlineSnapshot(` The current command "save" doesn't exist in the new version of Prisma Migrate. Read more about how to upgrade: https://pris.ly/d/migrate-upgrade `) diff --git a/packages/migrate/src/__tests__/MigrateDeploy.test.ts b/packages/migrate/src/__tests__/MigrateDeploy.test.ts index 66b4e1664a0e..be36c6b60b25 100644 --- a/packages/migrate/src/__tests__/MigrateDeploy.test.ts +++ b/packages/migrate/src/__tests__/MigrateDeploy.test.ts @@ -1,10 +1,9 @@ -process.env.GITHUB_ACTIONS = '1' - +import { jestConsoleContext, jestContext } from '@prisma/sdk' import fs from 'fs-jetpack' + import { MigrateDeploy } from '../commands/MigrateDeploy' -import { consoleContext, Context } from './__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('common', () => { it('should fail if no schema file', async () => { @@ -27,8 +26,8 @@ describe('common', () => { ctx.fixture('empty') const result = MigrateDeploy.new().parse(['--early-access-feature']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Prisma Migrate was in Early Access and is now in Preview. - Replace the --early-access-feature flag with --preview-feature. + Prisma Migrate was in Early Access and is now Generally Available. + Remove the --early-access-feature flag. `) }) }) @@ -100,7 +99,7 @@ describe('sqlite', () => { await expect(result).rejects.toMatchInlineSnapshot(` P3005 - The database schema for \`dev.db\` is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline + The database schema is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline `) diff --git a/packages/migrate/src/__tests__/MigrateDev.test.ts b/packages/migrate/src/__tests__/MigrateDev.test.ts index 59d83f17f761..08200279ebb0 100644 --- a/packages/migrate/src/__tests__/MigrateDev.test.ts +++ b/packages/migrate/src/__tests__/MigrateDev.test.ts @@ -1,18 +1,22 @@ -import prompt from 'prompts' +import { jestConsoleContext, jestContext } from '@prisma/sdk' import fs from 'fs-jetpack' import path from 'path' +import prompt from 'prompts' + import { MigrateDev } from '../commands/MigrateDev' -import { consoleContext, Context } from './__helpers__/context' -import { setupMysql, tearDownMysql } from '../utils/setupMysql' import { setupMSSQL, tearDownMSSQL } from '../utils/setupMSSQL' -import { SetupParams, setupPostgres, tearDownPostgres } from '../utils/setupPostgres' +import { setupMysql, tearDownMysql } from '../utils/setupMysql' +import type { SetupParams } from '../utils/setupPostgres' +import { setupPostgres, tearDownPostgres } from '../utils/setupPostgres' const describeIf = (condition: boolean) => (condition ? describe : describe.skip) const testIf = (condition: boolean) => (condition ? test : test.skip) -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() +// Disable prompts process.env.GITHUB_ACTIONS = '1' +// Disable generate process.env.PRISMA_MIGRATE_SKIP_GENERATE = '1' describe('common', () => { @@ -62,8 +66,8 @@ describe('common', () => { ctx.fixture('empty') const result = MigrateDev.new().parse(['--early-access-feature']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Prisma Migrate was in Early Access and is now in Preview. - Replace the --early-access-feature flag with --preview-feature. + Prisma Migrate was in Early Access and is now Generally Available. + Remove the --early-access-feature flag. `) }) it('dev should error in unattended environment', async () => { @@ -629,14 +633,14 @@ describe('sqlite', () => { await expect(result).rejects.toMatchInlineSnapshot(` - ⚠️ We found changes that cannot be executed: + ⚠️ We found changes that cannot be executed: - • Step 0 Made the column \`fullname\` on table \`Blog\` required, but there are 1 existing NULL values. + • Step 0 Made the column \`fullname\` on table \`Blog\` required, but there are 1 existing NULL values. - You can use prisma migrate dev --create-only to create the migration file, and manually modify it to address the underlying issue(s). - Then run prisma migrate dev to apply it and verify it works. + You can use prisma migrate dev --create-only to create the migration file, and manually modify it to address the underlying issue(s). + Then run prisma migrate dev to apply it and verify it works. - `) + `) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" @@ -690,10 +694,10 @@ describe('sqlite', () => { `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(` - ⚠️ Warnings for the current datasource: + ⚠️ Warnings for the current datasource: - • You are about to drop the \`Blog\` table, which is not empty (2 rows). - `) + • You are about to drop the \`Blog\` table, which is not empty (2 rows). + `) expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() }) @@ -712,10 +716,10 @@ describe('sqlite', () => { `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(` - ⚠️ Warnings for the current datasource: + ⚠️ Warnings for the current datasource: - • You are about to drop the \`Blog\` table, which is not empty (2 rows). - `) + • You are about to drop the \`Blog\` table, which is not empty (2 rows). + `) expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() }) @@ -891,28 +895,22 @@ describe('sqlite', () => { }) describe('postgresql', () => { + const connectionString = ( + process.env.TEST_POSTGRES_URI_MIGRATE || 'postgres://prisma:prisma@localhost:5432/tests-migrate' + ).replace('tests-migrate', 'tests-migrate-dev') + + // Update env var because it's the one that is used in the schemas tested + process.env.TEST_POSTGRES_URI_MIGRATE = connectionString + process.env.TEST_POSTGRES_SHADOWDB_URI_MIGRATE = connectionString.replace( + 'tests-migrate-dev', + 'tests-migrate-dev-shadowdb', + ) + const setupParams: SetupParams = { - connectionString: process.env.TEST_POSTGRES_URI_MIGRATE || 'postgres://prisma:prisma@localhost:5432/tests-migrate', + connectionString, dirname: '', } - beforeAll(async () => { - await tearDownPostgres(setupParams).catch((e) => { - console.error(e) - }) - - // Create shadowdb db - const SetupParamsShadowDb: SetupParams = { - connectionString: - process.env.TEST_POSTGRES_SHADOWDB_URI_MIGRATE || - 'postgres://prisma:prisma@localhost:5432/tests-migrate-shadowdb', - dirname: '', - } - await setupPostgres(SetupParamsShadowDb).catch((e) => { - console.error(e) - }) - }) - beforeEach(async () => { await setupPostgres(setupParams).catch((e) => { console.error(e) @@ -933,8 +931,9 @@ describe('postgresql', () => { expect(ctx.mocked['console.log'].mock.calls).toMatchSnapshot() expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "my_db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" Applying migration \`20201231000000_\` @@ -956,8 +955,9 @@ describe('postgresql', () => { expect(ctx.mocked['console.log'].mock.calls).toMatchSnapshot() expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/shadowdb.prisma - Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "my_db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" Applying migration \`20201231000000_\` @@ -977,8 +977,9 @@ describe('postgresql', () => { await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "my_db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" Applying migration \`20201231000000_\` @@ -1002,7 +1003,7 @@ describe('postgresql', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma - Datasource "db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" Applying migration \`20201231000000_first\` @@ -1058,11 +1059,13 @@ describe('postgresql', () => { expect((fs.list('prisma/migrations')?.length || 0) > 0).toMatchInlineSnapshot(`true`) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "my_db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "my_db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" Applying migration \`20201231000000_first\` @@ -1084,8 +1087,9 @@ describe('postgresql', () => { await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" + Datasource "my_db": PostgreSQL database "tests-migrate-dev", schema "public" at "localhost:5432" Applying migration \`20201231000000_first\` @@ -1126,17 +1130,22 @@ describe('postgresql', () => { }) describe('mysql', () => { + const connectionString = ( + process.env.TEST_MYSQL_URI_MIGRATE || 'mysql://root:root@localhost:3306/tests-migrate' + ).replace('tests-migrate', 'tests-migrate-dev') + + // Update env var because it's the one that is used in the schemas tested + process.env.TEST_MYSQL_URI_MIGRATE = connectionString + process.env.TEST_MYSQL_SHADOWDB_URI_MIGRATE = connectionString.replace( + 'tests-migrate-dev', + 'tests-migrate-dev-shadowdb', + ) + const setupParams: SetupParams = { - connectionString: process.env.TEST_MYSQL_URI_MIGRATE || 'mysql://root:root@localhost:3306/tests-migrate', + connectionString, dirname: '', } - beforeAll(async () => { - await tearDownMysql(setupParams).catch((e) => { - console.error(e) - }) - }) - beforeEach(async () => { await setupMysql(setupParams).catch((e) => { console.error(e) @@ -1158,7 +1167,7 @@ describe('mysql', () => { expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" + Datasource "my_db": MySQL database "tests-migrate-dev" at "localhost:3306" Applying migration \`20201231000000_\` @@ -1181,7 +1190,7 @@ describe('mysql', () => { expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/shadowdb.prisma - Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" + Datasource "my_db": MySQL database "tests-migrate-dev" at "localhost:3306" Applying migration \`20201231000000_\` @@ -1202,7 +1211,7 @@ describe('mysql', () => { await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" + Datasource "my_db": MySQL database "tests-migrate-dev" at "localhost:3306" Applying migration \`20201231000000_\` @@ -1284,10 +1293,10 @@ describe('mysql', () => { expect((fs.list('prisma/migrations')?.length || 0) > 0).toMatchInlineSnapshot(`true`) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" + Datasource "my_db": MySQL database "tests-migrate-dev" at "localhost:3306" Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" + Datasource "my_db": MySQL database "tests-migrate-dev" at "localhost:3306" Applying migration \`20201231000000_first\` @@ -1310,7 +1319,7 @@ describe('mysql', () => { await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma - Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" + Datasource "my_db": MySQL database "tests-migrate-dev" at "localhost:3306" Applying migration \`20201231000000_first\` @@ -1328,28 +1337,44 @@ describe('mysql', () => { }) describeIf(!process.env.TEST_SKIP_MSSQL)('SQL Server', () => { - jest.setTimeout(20000) + if (process.env.CI) { + // to avoid timeouts on macOS + jest.setTimeout(80_000) + } else { + jest.setTimeout(20_000) + } const connectionString = process.env.TEST_MSSQL_URI || 'mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/master' + + // Update env var because it's the one that is used in the schemas tested + process.env.TEST_MSSQL_JDBC_URI_MIGRATE = process.env.TEST_MSSQL_JDBC_URI_MIGRATE?.replace( + 'tests-migrate', + 'tests-migrate-dev', + ) + process.env.TEST_MSSQL_SHADOWDB_JDBC_URI_MIGRATE = process.env.TEST_MSSQL_SHADOWDB_JDBC_URI_MIGRATE?.replace( + 'tests-migrate-shadowdb', + 'tests-migrate-dev-shadowdb', + ) + const setupParams: SetupParams = { connectionString, dirname: '', } beforeAll(async () => { - await tearDownMSSQL(setupParams).catch((e) => { + await tearDownMSSQL(setupParams, 'tests-migrate-dev').catch((e) => { console.error(e) }) }) beforeEach(async () => { - await setupMSSQL(setupParams).catch((e) => { + await setupMSSQL(setupParams, 'tests-migrate-dev').catch((e) => { console.error(e) }) }) afterEach(async () => { - await tearDownMSSQL(setupParams).catch((e) => { + await tearDownMSSQL(setupParams, 'tests-migrate-dev').catch((e) => { console.error(e) }) }) diff --git a/packages/migrate/src/__tests__/MigrateDiff.test.ts b/packages/migrate/src/__tests__/MigrateDiff.test.ts new file mode 100644 index 000000000000..005964eb041b --- /dev/null +++ b/packages/migrate/src/__tests__/MigrateDiff.test.ts @@ -0,0 +1,586 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' + +import { MigrateDiff } from '../commands/MigrateDiff' +import { setupMSSQL, tearDownMSSQL } from '../utils/setupMSSQL' +import { setupMysql, tearDownMysql } from '../utils/setupMysql' +import type { SetupParams } from '../utils/setupPostgres' +import { setupPostgres, tearDownPostgres } from '../utils/setupPostgres' + +const ctx = jestContext.new().add(jestConsoleContext()).assemble() +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +describe('migrate diff', () => { + describe('generic', () => { + it('--preview-feature flag is required', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse([]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( + `This command is in Preview. Use the --preview-feature flag to use it like prisma migrate diff --preview-feature`, + ) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }) + + it('should fail if missing --from-... and --to-...', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse(['--preview-feature']) + await expect(result).rejects.toThrowError() + }) + + it('should fail if only --from-... is provided', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-empty']) + await expect(result).rejects.toThrowError() + }) + + it('should fail if only --to-... is provided', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse(['--preview-feature', '--to-empty']) + await expect(result).rejects.toThrowError() + }) + + it('should fail if more than 1 --from-... is provided', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-empty', '--from-url=file:dev.db']) + await expect(result).rejects.toThrowError() + }) + + it('should fail if more than 1 --to-... is provided', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse(['--preview-feature', '--to-empty', '--to-url=file:dev.db']) + await expect(result).rejects.toThrowError() + }) + + it('should fail if schema does no exists, --from-schema-datasource', async () => { + ctx.fixture('empty') + expect.assertions(2) + + try { + await MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datasource=./doesnoexists.prisma', + '--to-empty', + ]) + } catch (e) { + expect(e.code).toEqual(undefined) + expect(e.message).toContain(`Error trying to read Prisma schema file at`) + } + }) + + it('should fail for empty/empty', async () => { + ctx.fixture('empty') + expect.assertions(2) + + try { + await MigrateDiff.new().parse(['--preview-feature', '--from-empty', '--to-empty']) + } catch (e) { + expect(e.code).toEqual(undefined) + expect(e.message).toMatchInlineSnapshot(` + Could not determine the connector to use for diffing. + + + `) + } + }) + }) + + describe('sqlite', () => { + // TODO next 2 tests: is it expected to not fail when diffing from/to an unexisting sqlite db? + it('should diff --from-empty --to-url=file:doesnotexists.db', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-empty', '--to-url=file:doesnotexists.db']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`No difference detected.`) + }) + it('should diff --from-url=file:doesnotexists.db --to-empty ', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-url=file:doesnotexists.db', '--to-empty']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`No difference detected.`) + }) + it('should fail if path does not exist', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url=file:./something/doesnotexists.db', + '--to-empty', + ]) + await expect(result).rejects.toMatchInlineSnapshot(` + unable to open database file: ./something/doesnotexists.db + + + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }) + + it('should diff --from-empty --to-url=file:dev.db', async () => { + ctx.fixture('introspection/sqlite') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-empty', '--to-url=file:dev.db']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + [+] Added tables + - Post + - Profile + - User + - _Migration + + [*] Changed the \`Profile\` table + [+] Added unique index on columns (userId) + + [*] Changed the \`User\` table + [+] Added unique index on columns (email) + `) + }) + it('should diff --from-empty --to-url=file:dev.db --script', async () => { + ctx.fixture('introspection/sqlite') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-empty', '--to-url=file:dev.db', '--script']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchSnapshot() + }) + + it('should diff --from-empty --to-schema-datamodel=./prisma/schema.prisma', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-empty', + '--to-schema-datamodel=./prisma/schema.prisma', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + [+] Added tables + - Blog + `) + }) + it('should diff --from-empty --to-schema-datamodel=./prisma/schema.prisma --script', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-empty', + '--to-schema-datamodel=./prisma/schema.prisma', + '--script', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + -- CreateTable + CREATE TABLE "Blog" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "viewCount20" INTEGER NOT NULL + ); + `) + }) + + it('should diff --from-schema-datamodel=./prisma/schema.prisma --to-empty', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datamodel=./prisma/schema.prisma', + '--to-empty', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + [-] Removed tables + - Blog + `) + }) + it('should diff --from-schema-datamodel=./prisma/schema.prisma --to-empty --script', async () => { + ctx.fixture('schema-only-sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datamodel=./prisma/schema.prisma', + '--to-empty', + '--script', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + -- DropTable + PRAGMA foreign_keys=off; + DROP TABLE "Blog"; + PRAGMA foreign_keys=on; + `) + }) + + it('should pass if no schema file around', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse(['--preview-feature', '--from-url=file:dev.db', '--to-url=file:dev.db']) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`No difference detected.`) + }) + + describe('--exit-code', () => { + it('should exit with code 2 when diff is not empty without --script', async () => { + ctx.fixture('schema-only-sqlite') + + const mockExit = jest.spyOn(process, 'exit').mockImplementation() + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datamodel=./prisma/schema.prisma', + '--to-empty', + '--exit-code', + ]) + + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + [-] Removed tables + - Blog + `) + + expect(mockExit).toHaveBeenCalledTimes(1) + expect(mockExit).toHaveBeenCalledWith(2) + mockExit.mockRestore() + }) + + it('should exit with code 2 when diff is not empty with --script', async () => { + ctx.fixture('schema-only-sqlite') + + const mockExit = jest.spyOn(process, 'exit').mockImplementation() + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datamodel=./prisma/schema.prisma', + '--to-empty', + '--script', + '--exit-code', + ]) + + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + -- DropTable + PRAGMA foreign_keys=off; + DROP TABLE "Blog"; + PRAGMA foreign_keys=on; + `) + + expect(mockExit).toHaveBeenCalledTimes(1) + expect(mockExit).toHaveBeenCalledWith(2) + mockExit.mockRestore() + }) + + it('should exit with code 0 when diff is empty with --script', async () => { + ctx.fixture('empty') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-empty', + '--to-url=file:doesnotexists.db', + '--script', + '--exit-code', + ]) + + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`-- This is an empty migration.`) + }) + }) + }) + + describe('mongodb', () => { + // it('should diff --from-url=$TEST_MONGO_URI --to-schema-datamodel=./prisma/schema.prisma', async () => { + // ctx.fixture('schema-only-mongodb') + + // const result = MigrateDiff.new().parse([ + // '--preview-feature', + // '--from-url', + // process.env.TEST_MONGO_URI!, + // // '--to-empty', + // '--to-schema-datamodel=./prisma/schema.prisma', + // ]) + // await expect(result).resolves.toMatchInlineSnapshot(``) + // expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + // [+] Collection \`User\` + + // `) + // }) + + it('should diff --from-empty --to-schema-datamodel=./prisma/schema.prisma', async () => { + ctx.fixture('schema-only-mongodb') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-empty', + '--to-schema-datamodel=./prisma/schema.prisma', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`[+] Collection \`User\``) + }) + + it('should diff --from-schema-datamodel=./prisma/schema.prisma --to-empty', async () => { + ctx.fixture('schema-only-mongodb') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datamodel=./prisma/schema.prisma', + '--to-empty', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`No difference detected.`) + }) + + it('should fail with not supported error with --script', async () => { + ctx.fixture('schema-only-mongodb') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-empty', + '--to-schema-datamodel=./prisma/schema.prisma', + '--script', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Rendering to a script is not supported on MongoDB. + + + `) + }) + }) + + describe('postgresql', () => { + const connectionString = ( + process.env.TEST_POSTGRES_URI_MIGRATE || 'postgres://prisma:prisma@localhost:5432/tests-migrate' + ).replace('tests-migrate', 'tests-migrate-diff') + + const setupParams: SetupParams = { + connectionString, + dirname: '', + } + + beforeAll(async () => { + await setupPostgres(setupParams).catch((e) => { + console.error(e) + }) + }) + + afterAll(async () => { + await tearDownPostgres(setupParams).catch((e) => { + console.error(e) + }) + }) + + it('should diff --from-url=connectionString --to-schema-datamodel=./prisma/schema.prisma --script', async () => { + ctx.fixture('schema-only-postgresql') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url', + connectionString, + '--to-schema-datamodel=./prisma/schema.prisma', + '--script', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + -- CreateTable + CREATE TABLE "Blog" ( + "id" INTEGER NOT NULL, + "viewCount20" INTEGER NOT NULL, + + CONSTRAINT "Blog_pkey" PRIMARY KEY ("id") + ); + `) + }) + + it('should use env var from .env file with --from-schema-datasource', async () => { + ctx.fixture('schema-only-postgresql') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-schema-datasource=./prisma/using-dotenv.prisma', + '--to-schema-datamodel=./prisma/schema.prisma', + ]) + await expect(result).rejects.toMatchInlineSnapshot(` + P1001 + + Can't reach database server at \`fromdotenvdoesnotexist\`:\`5432\` + + Please make sure your database server is running at \`fromdotenvdoesnotexist\`:\`5432\`. + + `) + }) + + it('should fail for 2 different connectors --from-url=connectionString --to-url=file:dev.db --script', async () => { + ctx.fixture('introspection/sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url', + connectionString, + '--to-url=file:dev.db', + '--script', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Error in migration engine. + Reason: [/some/rust/path:0:0] Missing native type in postgres_renderer::render_column_type() + + Please create an issue with your \`schema.prisma\` at + https://github.com/prisma/prisma/issues/new + + `) + }) + }) + + describe('mysql', () => { + const connectionString = ( + process.env.TEST_MYSQL_URI_MIGRATE || 'mysql://root:root@localhost:3306/tests-migrate' + ).replace('tests-migrate', 'tests-migrate-diff') + + const setupParams: SetupParams = { + connectionString, + dirname: '', + } + + beforeAll(async () => { + await setupMysql(setupParams).catch((e) => { + console.error(e) + }) + }) + + afterAll(async () => { + await tearDownMysql(setupParams).catch((e) => { + console.error(e) + }) + }) + + it('should diff --from-url=connectionString --to-schema-datamodel=./prisma/schema.prisma --script', async () => { + ctx.fixture('schema-only-mysql') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url', + connectionString, + '--to-schema-datamodel=./prisma/schema.prisma', + '--script', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + -- CreateTable + CREATE TABLE \`Blog\` ( + \`id\` INTEGER NOT NULL, + \`viewCount20\` INTEGER NOT NULL, + + PRIMARY KEY (\`id\`) + ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + `) + }) + + it('should fail for 2 different connectors --from-url=connectionString --to-url=file:dev.db --script', async () => { + ctx.fixture('introspection/sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url', + connectionString, + '--to-url=file:dev.db', + '--script', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Error in migration engine. + Reason: [/some/rust/path:0:0] Column native type missing in mysql_renderer::render_column_type() + + Please create an issue with your \`schema.prisma\` at + https://github.com/prisma/prisma/issues/new + + `) + }) + }) + + describeIf(!process.env.TEST_SKIP_MSSQL)('sqlserver', () => { + const jdbcConnectionString = ( + process.env.TEST_MSSQL_JDBC_URI_MIGRATE || + 'sqlserver://mssql:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;' + ).replace('tests-migrate', 'tests-migrate-diff') + + const setupParams: SetupParams = { + connectionString: process.env.TEST_MSSQL_URI!, + dirname: '', + } + + beforeAll(async () => { + await setupMSSQL(setupParams, 'tests-migrate-diff').catch((e) => { + console.error(e) + }) + }) + + afterAll(async () => { + await tearDownMSSQL(setupParams, 'tests-migrate-diff').catch((e) => { + console.error(e) + }) + }) + + it('should diff --from-url=connectionString --to-schema-datamodel=./prisma/schema.prisma --script', async () => { + ctx.fixture('schema-only-sqlserver') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url', + jdbcConnectionString, + '--to-schema-datamodel=./prisma/schema.prisma', + '--script', + ]) + await expect(result).resolves.toMatchInlineSnapshot(``) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + BEGIN TRY + + BEGIN TRAN; + + -- CreateTable + CREATE TABLE [dbo].[Blog] ( + [id] INT NOT NULL, + [viewCount20] INT NOT NULL, + CONSTRAINT [Blog_pkey] PRIMARY KEY ([id]) + ); + + COMMIT TRAN; + + END TRY + BEGIN CATCH + + IF @@TRANCOUNT > 0 + BEGIN + ROLLBACK TRAN; + END; + THROW + + END CATCH + `) + }) + + it('should fail for 2 different connectors --from-url=jdbcConnectionString --to-url=file:dev.db --script', async () => { + ctx.fixture('introspection/sqlite') + + const result = MigrateDiff.new().parse([ + '--preview-feature', + '--from-url', + jdbcConnectionString, + '--to-url=file:dev.db', + '--script', + ]) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` + Error in migration engine. + Reason: [/some/rust/path:0:0] Missing column native type in mssql_renderer::render_column_type() + + Please create an issue with your \`schema.prisma\` at + https://github.com/prisma/prisma/issues/new + + `) + }) + }) +}) diff --git a/packages/migrate/src/__tests__/MigrateReset.test.ts b/packages/migrate/src/__tests__/MigrateReset.test.ts index 32ba2c8eda34..a1265af7efe8 100644 --- a/packages/migrate/src/__tests__/MigrateReset.test.ts +++ b/packages/migrate/src/__tests__/MigrateReset.test.ts @@ -1,14 +1,14 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' +import prompt from 'prompts' + +import { MigrateReset } from '../commands/MigrateReset' + process.env.PRISMA_MIGRATE_SKIP_GENERATE = '1' -process.env.GITHUB_ACTIONS = '1' // TODO: Windows: some snapshot tests fail on Windows because of emoji. const testIf = (condition: boolean) => (condition ? test : test.skip) -import prompt from 'prompts' -import { MigrateReset } from '../commands/MigrateReset' -import { consoleContext, Context } from './__helpers__/context' - -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('common', () => { it('wrong flag', async () => { @@ -57,8 +57,8 @@ describe('common', () => { ctx.fixture('empty') const result = MigrateReset.new().parse(['--early-access-feature']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Prisma Migrate was in Early Access and is now in Preview. - Replace the --early-access-feature flag with --preview-feature. + Prisma Migrate was in Early Access and is now Generally Available. + Remove the --early-access-feature flag. `) }) }) @@ -239,14 +239,16 @@ describe('reset', () => { expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) - testIf(process.platform !== 'win32')('reset - seed.ts', async () => { - ctx.fixture('seed-sqlite-ts') - prompt.inject(['y']) // simulate user yes input + testIf(process.platform !== 'win32')( + 'reset - seed.ts', + async () => { + ctx.fixture('seed-sqlite-ts') + prompt.inject(['y']) // simulate user yes input - const result = MigrateReset.new().parse([]) - await expect(result).resolves.toMatchInlineSnapshot(``) + const result = MigrateReset.new().parse([]) + await expect(result).resolves.toMatchInlineSnapshot(``) - expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "db": SQLite database "dev.db" at "file:./dev.db" @@ -260,9 +262,11 @@ describe('reset', () => { 🌱 The seed command has been executed. `) - expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(``) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) - }) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + }, + 10_000, + ) it('reset - legacy seed (no config in package.json)', async () => { ctx.fixture('seed-sqlite-legacy') diff --git a/packages/migrate/src/__tests__/MigrateResolve.test.ts b/packages/migrate/src/__tests__/MigrateResolve.test.ts index 955b4756b7ac..f842d71dec03 100644 --- a/packages/migrate/src/__tests__/MigrateResolve.test.ts +++ b/packages/migrate/src/__tests__/MigrateResolve.test.ts @@ -1,12 +1,8 @@ +import { jestConsoleContext, jestContext } from '@prisma/sdk' + import { MigrateResolve } from '../commands/MigrateResolve' -import { consoleContext, Context } from './__helpers__/context' -import { - SetupParams, - setupPostgres, - tearDownPostgres, -} from '../utils/setupPostgres' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('common', () => { it('should fail if no schema file', async () => { @@ -29,8 +25,8 @@ describe('common', () => { ctx.fixture('empty') const result = MigrateResolve.new().parse(['--early-access-feature']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Prisma Migrate was in Early Access and is now in Preview. - Replace the --early-access-feature flag with --preview-feature. + Prisma Migrate was in Early Access and is now Generally Available. + Remove the --early-access-feature flag. `) }) it('should fail if no --applied or --rolled-back', async () => { @@ -44,30 +40,18 @@ describe('common', () => { }) it('should fail if both --applied or --rolled-back', async () => { ctx.fixture('schema-only-sqlite') - const result = MigrateResolve.new().parse([ - '--applied=something_applied', - '--rolled-back=something_rolledback', - ]) - await expect(result).rejects.toThrowErrorMatchingInlineSnapshot( - `Pass either --applied or --rolled-back, not both.`, - ) + const result = MigrateResolve.new().parse(['--applied=something_applied', '--rolled-back=something_rolledback']) + await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(`Pass either --applied or --rolled-back, not both.`) }) }) describe('sqlite', () => { it('should fail if no sqlite db - empty schema', async () => { ctx.fixture('schema-only-sqlite') - const result = MigrateResolve.new().parse([ - '--schema=./prisma/empty.prisma', - - '--applied=something_applied', - ]) - await expect(result).rejects.toMatchInlineSnapshot( - `P1003: SQLite database file doesn't exist`, - ) + const result = MigrateResolve.new().parse(['--schema=./prisma/empty.prisma', '--applied=something_applied']) + await expect(result).rejects.toMatchInlineSnapshot(`P1003: SQLite database file doesn't exist`) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/empty.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" `) @@ -83,11 +67,11 @@ describe('sqlite', () => { ctx.fixture('existing-db-1-failed-migration') const result = MigrateResolve.new().parse(['--applied=does_not_exist']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` -P3017 + P3017 -The migration does_not_exist could not be found. Please make sure that the migration exists, and that you included the whole name of the directory. (example: "20201231000000_initial_migration") + The migration does_not_exist could not be found. Please make sure that the migration exists, and that you included the whole name of the directory. (example: "20201231000000_initial_migration") -`) + `) }) it('--applied should fail if migration is already applied', async () => { @@ -103,10 +87,7 @@ The migration does_not_exist could not be found. Please make sure that the migra it('--applied should fail if migration is not in a failed state', async () => { ctx.fixture('existing-db-1-migration') - const result = MigrateResolve.new().parse([ - '--applied', - '20201014154943_init', - ]) + const result = MigrateResolve.new().parse(['--applied', '20201014154943_init']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` P3008 @@ -117,15 +98,9 @@ The migration does_not_exist could not be found. Please make sure that the migra it('--applied should work on a failed migration', async () => { ctx.fixture('existing-db-1-failed-migration') - const result = MigrateResolve.new().parse([ - '--applied', - '20201106130852_failed', - ]) - await expect(result).resolves.toMatchInlineSnapshot( - `Migration 20201231000000_failed marked as applied.`, - ) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + const result = MigrateResolve.new().parse(['--applied', '20201106130852_failed']) + await expect(result).resolves.toMatchInlineSnapshot(`Migration 20201231000000_failed marked as applied.`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" `) @@ -150,10 +125,7 @@ The migration does_not_exist could not be found. Please make sure that the migra it('--rolled-back should fail if migration is not in a failed state', async () => { ctx.fixture('existing-db-1-migration') - const result = MigrateResolve.new().parse([ - '--rolled-back', - '20201014154943_init', - ]) + const result = MigrateResolve.new().parse(['--rolled-back', '20201014154943_init']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` P3012 @@ -164,15 +136,9 @@ The migration does_not_exist could not be found. Please make sure that the migra it('--rolled-back should work on a failed migration', async () => { ctx.fixture('existing-db-1-failed-migration') - const result = MigrateResolve.new().parse([ - '--rolled-back', - '20201106130852_failed', - ]) - await expect(result).resolves.toMatchInlineSnapshot( - `Migration 20201231000000_failed marked as rolled back.`, - ) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + const result = MigrateResolve.new().parse(['--rolled-back', '20201106130852_failed']) + await expect(result).resolves.toMatchInlineSnapshot(`Migration 20201231000000_failed marked as rolled back.`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" `) @@ -182,25 +148,14 @@ The migration does_not_exist could not be found. Please make sure that the migra it('--rolled-back works if migration is already rolled back', async () => { ctx.fixture('existing-db-1-failed-migration') - const result = MigrateResolve.new().parse([ - '--rolled-back', - '20201106130852_failed', - ]) - await expect(result).resolves.toMatchInlineSnapshot( - `Migration 20201231000000_failed marked as rolled back.`, - ) + const result = MigrateResolve.new().parse(['--rolled-back', '20201106130852_failed']) + await expect(result).resolves.toMatchInlineSnapshot(`Migration 20201231000000_failed marked as rolled back.`) // Try again - const result2 = MigrateResolve.new().parse([ - '--rolled-back', - '20201106130852_failed', - ]) - await expect(result2).resolves.toMatchInlineSnapshot( - `Migration 20201231000000_failed marked as rolled back.`, - ) - - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + const result2 = MigrateResolve.new().parse(['--rolled-back', '20201106130852_failed']) + await expect(result2).resolves.toMatchInlineSnapshot(`Migration 20201231000000_failed marked as rolled back.`) + + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" Prisma schema loaded from prisma/schema.prisma @@ -212,24 +167,19 @@ The migration does_not_exist could not be found. Please make sure that the migra }) describe('postgresql', () => { - // Skipping because timeout is now too long to wait for - it.skip('should fail if no postgres db - invalid url', async () => { + it('should fail if no db - invalid url', async () => { ctx.fixture('schema-only-postgresql') - jest.setTimeout(6000) - - const result = MigrateResolve.new().parse([ - '--schema=./prisma/invalid-url.prisma', + jest.setTimeout(10000) - '--applied=something_applied', - ]) + const result = MigrateResolve.new().parse(['--schema=./prisma/invalid-url.prisma', '--applied=something_applied']) await expect(result).rejects.toMatchInlineSnapshot(` P1001: Can't reach database server at \`doesnotexist\`:\`5432\` Please make sure your database server is running at \`doesnotexist\`:\`5432\`. `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Environment variables loaded from prisma/.env Prisma schema loaded from prisma/invalid-url.prisma Datasource "my_db": PostgreSQL database "mydb", schema "public" at "doesnotexist:5432" `) @@ -237,3 +187,26 @@ describe('postgresql', () => { expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() }) }) + +const describeIf = (condition: boolean) => (condition ? describe : describe.skip) + +describeIf(!process.env.TEST_SKIP_COCKROACHDB)('cockroachdb', () => { + it('should fail if no db - invalid url', async () => { + ctx.fixture('schema-only-cockroachdb') + jest.setTimeout(10000) + + const result = MigrateResolve.new().parse(['--schema=./prisma/invalid-url.prisma', '--applied=something_applied']) + await expect(result).rejects.toMatchInlineSnapshot(` + P1001: Can't reach database server at \`something.cockroachlabs.cloud\`:\`26257\` + + Please make sure your database server is running at \`something.cockroachlabs.cloud\`:\`26257\`. + `) + + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` + Prisma schema loaded from prisma/invalid-url.prisma + Datasource "db": CockroachDB database "clustername.defaultdb", schema "public" at "something.cockroachlabs.cloud:26257" + `) + expect(ctx.mocked['console.log'].mock.calls).toMatchSnapshot() + expect(ctx.mocked['console.error'].mock.calls).toMatchSnapshot() + }) +}) diff --git a/packages/migrate/src/__tests__/MigrateStatus.test.ts b/packages/migrate/src/__tests__/MigrateStatus.test.ts index 3f505c481ddc..16b59a0308e7 100644 --- a/packages/migrate/src/__tests__/MigrateStatus.test.ts +++ b/packages/migrate/src/__tests__/MigrateStatus.test.ts @@ -1,17 +1,8 @@ -import fs from 'fs-jetpack' -import path from 'path' -import { MigrateStatus } from '../commands/MigrateStatus' -import { consoleContext, Context } from './__helpers__/context' -import { tearDownMysql } from '../utils/setupMysql' -import { - SetupParams, - setupPostgres, - tearDownPostgres, -} from '../utils/setupPostgres' +import { jestConsoleContext, jestContext } from '@prisma/sdk' -const ctx = Context.new().add(consoleContext()).assemble() +import { MigrateStatus } from '../commands/MigrateStatus' -process.env.GITHUB_ACTIONS = '1' +const ctx = jestContext.new().add(jestConsoleContext()).assemble() describe('common', () => { it('should fail if no schema file', async () => { @@ -34,8 +25,8 @@ describe('common', () => { ctx.fixture('empty') const result = MigrateStatus.new().parse(['--early-access-feature']) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - Prisma Migrate was in Early Access and is now in Preview. - Replace the --early-access-feature flag with --preview-feature. + Prisma Migrate was in Early Access and is now Generally Available. + Remove the --early-access-feature flag. `) }) }) @@ -50,8 +41,7 @@ describe('sqlite', () => { P1003: SQLite database file doesn't exist `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/empty.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" @@ -77,8 +67,7 @@ describe('sqlite', () => { https://pris.ly/d/migrate-resolve `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" 1 migration found in prisma/migrations @@ -107,8 +96,7 @@ describe('sqlite', () => { https://pris.ly/d/migrate-baseline `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" 1 migration found in prisma/migrations @@ -126,12 +114,9 @@ describe('sqlite', () => { it('existing-db-1-migration', async () => { ctx.fixture('existing-db-1-migration') const result = MigrateStatus.new().parse([]) - await expect(result).resolves.toMatchInlineSnapshot( - `Database schema is up to date!`, - ) + await expect(result).resolves.toMatchInlineSnapshot(`Database schema is up to date!`) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" 1 migration found in prisma/migrations @@ -156,8 +141,7 @@ describe('sqlite', () => { https://pris.ly/d/migrate-baseline `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" 1 migration found in prisma/migrations @@ -180,8 +164,7 @@ describe('sqlite', () => { https://pris.ly/d/migrate-baseline `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" No migration found in prisma/migrations @@ -199,8 +182,7 @@ describe('sqlite', () => { https://pris.ly/d/migrate-baseline `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" No migration found in prisma/migrations @@ -220,8 +202,7 @@ describe('sqlite', () => { https://pris.ly/d/migrate-upgrade `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" `) @@ -232,12 +213,9 @@ describe('sqlite', () => { it('reset', async () => { ctx.fixture('reset') const result = MigrateStatus.new().parse([]) - await expect(result).resolves.toMatchInlineSnapshot( - `Database schema is up to date!`, - ) + await expect(result).resolves.toMatchInlineSnapshot(`Database schema is up to date!`) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" 1 migration found in prisma/migrations @@ -263,8 +241,7 @@ describe('sqlite', () => { 20201231000000_dogage `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')) - .toMatchInlineSnapshot(` + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" 2 migrations found in prisma/migrations diff --git a/packages/migrate/src/__tests__/__helpers__/snapshotSerializer.ts b/packages/migrate/src/__tests__/__helpers__/snapshotSerializer.ts deleted file mode 100644 index d890a3bae299..000000000000 --- a/packages/migrate/src/__tests__/__helpers__/snapshotSerializer.ts +++ /dev/null @@ -1,36 +0,0 @@ -import stripAnsi from 'strip-ansi' - -function normalizeMigrateTimestamps(str) { - return str.replace(/\d{14}/g, '20201231000000') -} - -function normalizeDbUrl(str) { - return str.replace(/(localhost|postgres|mysql|mssql):\d+/g, 'localhost:5432') -} - -function normalizeRustError(str) { - return str.replace(/\/rustc\/(.+)\//g, '/rustc/hash/').replace(/(\[.*)(:\d*:\d*)(\])/g, '[/some/rust/path:0:0$3') -} - -function normalizeTime(str: string): string { - // sometimes soneting can take a few seconds when usually it's less than 1s - return str.replace(/ \d+ms/g, ' XXXms').replace(/ \d+(.\d+)?s/g, ' XXXms') -} - -function normalizePaths(str: string): string { - return str - .replace(/prisma\\([\w-]+)\.prisma/g, 'prisma/$1.prisma') - .replace(/prisma\\seed\.ts/g, 'prisma/seed.ts') - .replace(/custom-folder\\seed\.js/g, 'custom-folder/seed.js') -} - -export function test(value) { - return typeof value === 'string' || value instanceof Error -} - -export function serialize(value) { - const message = typeof value === 'string' ? value : value instanceof Error ? value.message : '' - return normalizePaths( - normalizeDbUrl(normalizeTime(normalizeRustError(normalizeMigrateTimestamps(stripAnsi(message))))), - ) -} diff --git a/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap b/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap index cb148e0afa32..77993d4b0e60 100644 --- a/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap +++ b/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap @@ -1,126 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`MongoDB basic introspection --url 2`] = ``; - -exports[`MongoDB basic introspection 1`] = ``; - -exports[`MongoDB introspection --print --composite-type-depth=-1 1`] = ` -generator client { - provider = "prisma-client-js" - previewFeatures = ["mongoDb"] -} - -datasource my_db { - provider = "mongodb" - url = env("TEST_MONGO_URI") -} - -type UsersHobbies { - name String - objects UsersHobbiesObjects[] - tags String[] -} - -type UsersHobbiesObjects { - name String - tags String[] -} - -model users { - id String @id @default(dbgenerated()) @map("_id") @my_db.ObjectId - admin Boolean - email String - hobbies UsersHobbies[] - name String -} - - -// introspectionSchemaVersion: NonPrisma, -`; - -exports[`MongoDB introspection --print --composite-type-depth=0 1`] = ` -generator client { - provider = "prisma-client-js" - previewFeatures = ["mongoDb"] -} - -datasource my_db { - provider = "mongodb" - url = env("TEST_MONGO_URI") -} - -model users { - id String @id @default(dbgenerated()) @map("_id") @my_db.ObjectId - admin Boolean - email String - hobbies Json[] - name String -} - - -// introspectionSchemaVersion: NonPrisma, -`; - -exports[`MongoDB introspection --print --composite-type-depth=1 1`] = ` -generator client { - provider = "prisma-client-js" - previewFeatures = ["mongoDb"] -} - -datasource my_db { - provider = "mongodb" - url = env("TEST_MONGO_URI") -} - -type UsersHobbies { - name String - objects Json[] - tags String[] -} - -model users { - id String @id @default(dbgenerated()) @map("_id") @my_db.ObjectId - admin Boolean - email String - hobbies UsersHobbies[] - name String -} - - -// introspectionSchemaVersion: NonPrisma, -`; - -exports[`MongoDB introspection --print 1`] = ` -generator client { - provider = "prisma-client-js" - previewFeatures = ["mongoDb"] -} - -datasource my_db { - provider = "mongodb" - url = env("TEST_MONGO_URI") -} - -model users { - id String @id @default(dbgenerated()) @map("_id") @my_db.ObjectId - admin Boolean - email String - hobbies Json[] - name String -} - - -// introspectionSchemaVersion: NonPrisma, -`; - -exports[`MongoDB introspection with --force 2`] = ``; - -exports[`MongoDB re-introspection should error (not supported) 2`] = ``; - exports[`SQL Server basic introspection --url 2`] = ` datasource db { provider = "sqlserver" - url = "sqlserver://localhost:5432;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;" + url = "sqlserver://localhost:1433;database=tests-migrate;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;" } model jobs { @@ -134,7 +17,7 @@ model jobs { // introspectionSchemaVersion: NonPrisma, `; -exports[`SQL Server basic introspection 1`] = ` +exports[`SQL Server basic introspection 2`] = ` datasource db { provider = "sqlserver" url = env("TEST_MSSQL_JDBC_URI_MIGRATE") @@ -151,7 +34,7 @@ model jobs { // introspectionSchemaVersion: NonPrisma, `; -exports[`common/sqlite basic introspection 1`] = ` +exports[`common/sqlite basic introspection 2`] = ` generator client { provider = "prisma-client-js" } @@ -233,7 +116,7 @@ exports[`common/sqlite basic introspection with invalid --url - empty host 2`] = exports[`common/sqlite basic introspection with invalid --url 2`] = ``; -exports[`common/sqlite introspection --force 1`] = ` +exports[`common/sqlite introspection --force 2`] = ` generator client { provider = "prisma-client-js" } @@ -359,7 +242,7 @@ model User { exports[`mysql basic introspection --url 2`] = ` datasource db { provider = "mysql" - url = "mysql://root:root@localhost:5432/tests" + url = "mysql://root:root@localhost:3306/tests" } model your_log { @@ -399,7 +282,7 @@ model your_url { // introspectionSchemaVersion: NonPrisma, `; -exports[`mysql basic introspection 1`] = ` +exports[`mysql basic introspection 2`] = ` datasource db { provider = "mysql" url = env("TEST_MYSQL_URI") @@ -477,7 +360,7 @@ enum Role { // introspectionSchemaVersion: NonPrisma, `; -exports[`postgresql basic introspection 1`] = ` +exports[`postgresql basic introspection 2`] = ` datasource db { provider = "postgresql" url = env("TEST_POSTGRES_URI_MIGRATE") diff --git a/packages/migrate/src/__tests__/__snapshots__/MigrateDiff.test.ts.snap b/packages/migrate/src/__tests__/__snapshots__/MigrateDiff.test.ts.snap new file mode 100644 index 000000000000..7962f79e3136 --- /dev/null +++ b/packages/migrate/src/__tests__/__snapshots__/MigrateDiff.test.ts.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`migrate diff sqlite should diff --from-empty --to-url=file:dev.db --script 2`] = ` +-- CreateTable +CREATE TABLE "Post" ( + "authorId" INTEGER NOT NULL, + "content" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "published" BOOLEAN NOT NULL DEFAULT false, + "title" TEXT NOT NULL, + FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "Profile" ( + "bio" TEXT, + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "userId" INTEGER NOT NULL, + FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "User" ( + "email" TEXT NOT NULL, + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" TEXT +); + +-- CreateTable +CREATE TABLE "_Migration" ( + "revision" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL, + "datamodel" TEXT NOT NULL, + "status" TEXT NOT NULL, + "applied" INTEGER NOT NULL, + "rolled_back" INTEGER NOT NULL, + "datamodel_steps" TEXT NOT NULL, + "database_migration" TEXT NOT NULL, + "errors" TEXT NOT NULL, + "started_at" DATETIME NOT NULL, + "finished_at" DATETIME +); + +-- CreateIndex +CREATE UNIQUE INDEX "Profile.userId" ON "Profile"("userId" ASC); + +-- CreateIndex +CREATE UNIQUE INDEX "User.email" ON "User"("email" ASC); +`; diff --git a/packages/migrate/src/__tests__/__snapshots__/MigrateResolve.test.ts.snap b/packages/migrate/src/__tests__/__snapshots__/MigrateResolve.test.ts.snap index 20035734ce9c..f4bedfd98e0d 100644 --- a/packages/migrate/src/__tests__/__snapshots__/MigrateResolve.test.ts.snap +++ b/packages/migrate/src/__tests__/__snapshots__/MigrateResolve.test.ts.snap @@ -1,8 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`postgresql should fail if no postgres db - invalid url 3`] = `Array []`; +exports[`cockroachdb should fail if no db - invalid url 3`] = `Array []`; -exports[`postgresql should fail if no postgres db - invalid url 4`] = `Array []`; +exports[`cockroachdb should fail if no db - invalid url 4`] = `Array []`; + +exports[`postgresql should fail if no db - invalid url 3`] = `Array []`; + +exports[`postgresql should fail if no db - invalid url 4`] = `Array []`; exports[`sqlite --applied should work on a failed migration 3`] = `Array []`; diff --git a/packages/migrate/src/__tests__/ensureDatabaseExists.test.ts b/packages/migrate/src/__tests__/ensureDatabaseExists.test.ts index 6489f7046e16..fc6a97b79ea8 100644 --- a/packages/migrate/src/__tests__/ensureDatabaseExists.test.ts +++ b/packages/migrate/src/__tests__/ensureDatabaseExists.test.ts @@ -1,8 +1,8 @@ -import { getSchemaPath, getSchema, getConfig, createDatabase } from '@prisma/sdk' +import { createDatabase, getConfig, getSchema, getSchemaPath, jestConsoleContext, jestContext } from '@prisma/sdk' + import { ensureDatabaseExists } from '../utils/ensureDatabaseExists' -import { consoleContext, Context } from './__helpers__/context' -const ctx = Context.new().add(consoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).assemble() it('can create database - sqlite', async () => { ctx.fixture('schema-only-sqlite') diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/empty.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/empty.prisma new file mode 100644 index 000000000000..8bc4e8a1ce69 --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/empty.prisma @@ -0,0 +1,9 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["cockroachdb"] +} + +datasource db { + provider = "cockroachdb" + url = env("TEST_COCKROACHDB_URI_MIGRATE") +} diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/invalid-url.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/invalid-url.prisma new file mode 100644 index 000000000000..4e4e65ba7e13 --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/invalid-url.prisma @@ -0,0 +1,9 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["cockroachdb"] +} + +datasource db { + provider = "cockroachdb" + url = "postgres://user:password@something.cockroachlabs.cloud:26257/clustername.defaultdb?sslmode=verify-full&sslrootcert=$HOME/.postgresql/root.crt&options=--cluster%3Dclustername" +} diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/schema.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/schema.prisma new file mode 100644 index 000000000000..ec854b7551a4 --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/schema.prisma @@ -0,0 +1,14 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["cockroachdb"] +} + +datasource db { + provider = "cockroachdb" + url = env("TEST_COCKROACHDB_URI_MIGRATE") +} + +model User { + id BigInt @id(map: "primary") @default(autoincrement()) + name String? +} diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/shadowdb.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/shadowdb.prisma new file mode 100644 index 000000000000..8154fc5c8e62 --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-cockroachdb/prisma/shadowdb.prisma @@ -0,0 +1,15 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["cockroachdb"] +} + +datasource db { + provider = "cockroachdb" + url = env("TEST_COCKROACHDB_SHADOWDB_URI_MIGRATE") + shadowDatabaseUrl = env("TEST_COCKROACHDB_SHADOWDB_URI_MIGRATE") +} + +model User { + id BigInt @id(map: "primary") @default(autoincrement()) + name String? +} diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/only-generator/schema.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/only-generator/schema.prisma new file mode 100644 index 000000000000..733bfdc03a36 --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/only-generator/schema.prisma @@ -0,0 +1,4 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["mongoDb"] +} diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/no-model.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/no-model.prisma index d8b81f05504c..a0ca4a2ae0f0 100644 --- a/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/no-model.prisma +++ b/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/no-model.prisma @@ -1,6 +1,6 @@ datasource my_db { provider = "mongodb" - url = env("TEST_MONGO_URI") + url = env("TEST_MONGO_URI_MIGRATE") } generator client { diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/schema.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/schema.prisma index 400885af5601..204f33d224df 100644 --- a/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/schema.prisma +++ b/packages/migrate/src/__tests__/fixtures/schema-only-mongodb/prisma/schema.prisma @@ -1,6 +1,6 @@ datasource my_db { provider = "mongodb" - url = env("TEST_MONGO_URI") + url = env("TEST_MONGO_URI_MIGRATE") } generator client { diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-postgresql/prisma/.env b/packages/migrate/src/__tests__/fixtures/schema-only-postgresql/prisma/.env new file mode 100644 index 000000000000..47dc9686775d --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-postgresql/prisma/.env @@ -0,0 +1 @@ +FROM_DOTENV_FILE="postgresql://fromdotenvdoesnotexist:5432/mydb?schema=public" \ No newline at end of file diff --git a/packages/migrate/src/__tests__/fixtures/schema-only-postgresql/prisma/using-dotenv.prisma b/packages/migrate/src/__tests__/fixtures/schema-only-postgresql/prisma/using-dotenv.prisma new file mode 100644 index 000000000000..af7619967529 --- /dev/null +++ b/packages/migrate/src/__tests__/fixtures/schema-only-postgresql/prisma/using-dotenv.prisma @@ -0,0 +1,9 @@ +datasource my_db { + provider = "postgresql" + url = env("FROM_DOTENV_FILE") +} + +model Blog { + id Int @id + viewCount20 Int +} diff --git a/packages/migrate/src/__tests__/getGithubIssueUrl.test.ts b/packages/migrate/src/__tests__/getGithubIssueUrl.test.ts index 260e78a1d06b..ebf58933d684 100644 --- a/packages/migrate/src/__tests__/getGithubIssueUrl.test.ts +++ b/packages/migrate/src/__tests__/getGithubIssueUrl.test.ts @@ -1,6 +1,7 @@ -import { getGithubIssueUrl } from '../utils/getGithubIssueUrl' import stripAnsi from 'strip-ansi' +import { getGithubIssueUrl } from '../utils/getGithubIssueUrl' + describe('getErrorMessageWithLink', () => { test('basic serialization', () => { const message = getGithubIssueUrl({ @@ -8,8 +9,6 @@ describe('getErrorMessageWithLink', () => { body: 'This is a body', }) - expect(stripAnsi(message)).toMatchInlineSnapshot( - `https://github.com/prisma/prisma/issues/new?body=This+is+a+body&title=This+is+a+title&template=bug_report.md`, - ) + expect(stripAnsi(message)).toMatchInlineSnapshot(`TEST_GITHUB_LINK`) }) }) diff --git a/packages/migrate/src/__tests__/handlePanic.introspect.test.ts b/packages/migrate/src/__tests__/handlePanic.introspect.test.ts index a902a04aa4ec..2606b6ba5e57 100644 --- a/packages/migrate/src/__tests__/handlePanic.introspect.test.ts +++ b/packages/migrate/src/__tests__/handlePanic.introspect.test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { DbPull } from '../commands/DbPull' describe('introspection panic', () => { @@ -10,9 +11,7 @@ describe('introspection panic', () => { try { await introspect.parse(['--print']) } catch (e) { - expect(e).toMatchInlineSnapshot( - `[/some/rust/path:0:0] This is the debugPanic artificial panic`, - ) + expect(e).toMatchInlineSnapshot(`[/some/rust/path:0:0] This is the debugPanic artificial panic`) } }) }) diff --git a/packages/migrate/src/__tests__/handlePanic.test.ts b/packages/migrate/src/__tests__/handlePanic.test.ts index b8b276a3ca5e..7d8348e07647 100644 --- a/packages/migrate/src/__tests__/handlePanic.test.ts +++ b/packages/migrate/src/__tests__/handlePanic.test.ts @@ -1,13 +1,14 @@ -import { ErrorArea, RustPanic, isCi } from '@prisma/sdk' +import { ErrorArea, isCi, RustPanic } from '@prisma/sdk' import fs from 'fs' import mkdir from 'make-dir' import { stdin } from 'mock-stdin' import { dirname, join, resolve } from 'path' +import prompt from 'prompts' import stripAnsi from 'strip-ansi' import dedent from 'strip-indent' -import prompt from 'prompts' import tempy from 'tempy' import { promisify } from 'util' + import { Migrate } from '../Migrate' import { handlePanic } from '../utils/handlePanic' import CaptureStdout from './__helpers__/captureStdout' @@ -29,6 +30,7 @@ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) // Mock const writeFile = promisify(fs.writeFile) const testRootDir = tempy.directory() +// eslint-disable-next-line @typescript-eslint/unbound-method const oldProcessCwd = process.cwd // create a temporary set of files async function writeFiles( @@ -57,7 +59,7 @@ describe('handlePanic', () => { process.cwd = () => testRootDir await mkdir(testRootDir) }) - afterEach(async () => { + afterEach(() => { process.cwd = oldProcessCwd // await del(testRootDir, { force: true }) // Need force: true because `del` does not delete dirs outside the CWD }) @@ -101,7 +103,6 @@ describe('handlePanic', () => { }) it('no interactive mode in CI', async () => { - process.env.GITHUB_ACTIONS = 'maybe' try { await handlePanic(error, packageJsonVersion, engineVersion, command) } catch (error) { @@ -139,7 +140,7 @@ describe('handlePanic', () => { try { const migrate = new Migrate(schemaPath) await migrate.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: 'setup', draft: false, prismaSchema: migrate.getDatamodel(), @@ -159,41 +160,40 @@ describe('handlePanic', () => { // We use prompts.inject() for testing in our CI if (isCi() && Boolean((prompt as any)._injected?.length) === false) { expect(error).toMatchInlineSnapshot(` -Error in migration engine. -Reason: [/some/rust/path:0:0] This is the debugPanic artificial panic + Error in migration engine. + Reason: [/some/rust/path:0:0] This is the debugPanic artificial panic -Please create an issue with your \`schema.prisma\` at -https://github.com/prisma/prisma/issues/new + Please create an issue with your \`schema.prisma\` at + https://github.com/prisma/prisma/issues/new -`) + `) } else { const output = captureStdout.getCapturedText() expect(stripAnsi(output.join('\n'))).toMatchInlineSnapshot(` - console.log Oops, an unexpected error occured! Error in migration engine. Reason: [/some/rust/path:0:0] This is the debugPanic artificial panic Please create an issue with your \`schema.prisma\` at https://github.com/prisma/prisma/issues/new Please help us improve Prisma by submitting an error report. Error reports never contain personal or other sensitive information. Learn more: https://pris.ly/d/telemetry at panicDialog (src/utils/handlePanic.ts:25:11) + console.log Oops, an unexpected error occured! Error in migration engine. Reason: [/some/rust/path:0:0] This is the debugPanic artificial panic Please create an issue with your \`schema.prisma\` at https://github.com/prisma/prisma/issues/new Please help us improve Prisma by submitting an error report. Error reports never contain personal or other sensitive information. Learn more: https://pris.ly/d/telemetry at panicDialog (src/utils/handlePanic.ts:25:11) - ? Submit error report › - Use arrow-keys. Return to submit.❯ Yes - Send error report once No + ? Submit error report › - Use arrow-keys. Return to submit.❯ Yes - Send error report once No - ? Submit error report › - Use arrow-keys. Return to submit. Yes❯ No - Don't send error report + ? Submit error report › - Use arrow-keys. Return to submit. Yes❯ No - Don't send error report - ✔ Submit error report › No + ✔ Submit error report › No - ? Would you like to create a Github issue? › - Use arrow-keys. Return to submit.❯ Yes - Create a new GitHub issue No + ? Would you like to create a Github issue? › - Use arrow-keys. Return to submit.❯ Yes - Create a new GitHub issue No - ? Would you like to create a Github issue? › - Use arrow-keys. Return to submit. Yes❯ No - Don't create a new GitHub issue + ? Would you like to create a Github issue? › - Use arrow-keys. Return to submit. Yes❯ No - Don't create a new GitHub issue - ✔ Would you like to create a Github issue? › No + ✔ Would you like to create a Github issue? › No - `) + `) } captureStdout.stopCapture() }) it('engine panic no interactive mode in CI', async () => { - process.env.GITHUB_ACTIONS = 'maybe' process.env.FORCE_PANIC_MIGRATION_ENGINE = '1' const files = { @@ -216,7 +216,7 @@ https://github.com/prisma/prisma/issues/new try { const migrate = new Migrate(schemaPath) await migrate.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: 'setup', draft: false, prismaSchema: migrate.getDatamodel(), diff --git a/packages/migrate/src/__tests__/rpc.test.ts b/packages/migrate/src/__tests__/rpc.test.ts index 5c3b7462b1e1..d0bea1c2fd81 100644 --- a/packages/migrate/src/__tests__/rpc.test.ts +++ b/packages/migrate/src/__tests__/rpc.test.ts @@ -1,10 +1,10 @@ -import { getSchemaPath } from '@prisma/sdk' -import { Migrate } from '../Migrate' -import path from 'path' +import { getSchemaPath, jestConsoleContext, jestContext } from '@prisma/sdk' import fs from 'fs-jetpack' -import { consoleContext, Context } from './__helpers__/context' +import path from 'path' -const ctx = Context.new().add(consoleContext()).assemble() +import { Migrate } from '../Migrate' + +const ctx = jestContext.new().add(jestConsoleContext()).assemble() it('getDatabaseVersion', async () => { ctx.fixture('schema-only') @@ -22,7 +22,7 @@ it('evaluateDataLoss - schema-only-sqlite', async () => { const migrate = new Migrate(schemaPath) const datamodel = migrate.getDatamodel() const result = migrate.engine.evaluateDataLoss({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, prismaSchema: datamodel, }) @@ -43,7 +43,7 @@ it('evaluateDataLoss - existing-db-1-migration', async () => { const migrate = new Migrate(schemaPath) const datamodel = migrate.getDatamodel() const result = migrate.engine.evaluateDataLoss({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, prismaSchema: datamodel, }) @@ -63,7 +63,7 @@ it('createMigration - existing-db-1-migration', async () => { const migrate = new Migrate(schemaPath) const datamodel = migrate.getDatamodel() const result = migrate.engine.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: 'my_migration', draft: false, prismaSchema: datamodel, @@ -83,7 +83,7 @@ it('createMigration draft - existing-db-1-migration', async () => { const migrate = new Migrate(schemaPath) const datamodel = migrate.getDatamodel() const result = migrate.engine.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: 'draft_123', draft: true, prismaSchema: datamodel, @@ -102,7 +102,7 @@ it('diagnoseMigrationHistory - optInToShadowDatabase true - existing-db-1-migrat const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.diagnoseMigrationHistory({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, optInToShadowDatabase: true, }) @@ -122,7 +122,7 @@ it('diagnoseMigrationHistory - optInToShadowDatabase false - existing-db-1-migra const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.diagnoseMigrationHistory({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, optInToShadowDatabase: false, }) @@ -142,7 +142,7 @@ it('applyMigrations', async () => { const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.applyMigrations({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) await expect(result).resolves.toMatchInlineSnapshot(` @@ -159,13 +159,13 @@ it('applyMigrations - should fail on existing brownfield db', async () => { const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.applyMigrations({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) await expect(result).rejects.toMatchInlineSnapshot(` P3005 - The database schema for \`dev.db\` is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline + The database schema is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline `) migrate.stop() @@ -264,7 +264,7 @@ it('markMigrationRolledBack - existing-db-1-migration', async () => { const migrate = new Migrate(schemaPath) const datamodel = migrate.getDatamodel() const result = await migrate.engine.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: 'draft_123', draft: true, prismaSchema: datamodel, @@ -277,13 +277,13 @@ it('markMigrationRolledBack - existing-db-1-migration', async () => { `) fs.write( - path.join(migrate.migrationsDirectoryPath, result.generatedMigrationName!, 'migration.sql'), + path.join(migrate.migrationsDirectoryPath!, result.generatedMigrationName!, 'migration.sql'), 'SELECT SOMETHING_THAT_DOES_NOT_WORK', ) try { await migrate.engine.applyMigrations({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) } catch (e) { expect(e.message).toContain('no such column: SOMETHING_THAT_DOES_NOT_WORK') @@ -296,14 +296,14 @@ it('markMigrationRolledBack - existing-db-1-migration', async () => { await expect(resultMarkRolledBacked).resolves.toMatchSnapshot() const resultMarkAppliedFailed = migrate.engine.markMigrationApplied({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: result.generatedMigrationName!, }) await expect(resultMarkAppliedFailed).resolves.toMatchSnapshot() const resultMarkApplied = migrate.engine.markMigrationApplied({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: result.generatedMigrationName!, }) @@ -323,7 +323,7 @@ it('markMigrationApplied - existing-db-1-migration', async () => { const migrate = new Migrate(schemaPath) const datamodel = migrate.getDatamodel() const result = await migrate.engine.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: 'draft_123', draft: true, prismaSchema: datamodel, @@ -336,7 +336,7 @@ it('markMigrationApplied - existing-db-1-migration', async () => { `) const resultMarkApplied = migrate.engine.markMigrationApplied({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: result.generatedMigrationName!, }) @@ -350,7 +350,7 @@ it('listMigrationDirectories - existing-db-1-migration', async () => { const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.listMigrationDirectories({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) await expect(result).resolves.toMatchInlineSnapshot(` Object { @@ -368,7 +368,7 @@ it('listMigrationDirectories - schema-only-sqlite', async () => { const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.listMigrationDirectories({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) await expect(result).resolves.toMatchInlineSnapshot(` Object { @@ -384,7 +384,7 @@ it('devDiagnostic - createMigration', async () => { const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.devDiagnostic({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) await expect(result).resolves.toMatchInlineSnapshot(` Object { @@ -402,7 +402,7 @@ it('devDiagnostic - reset because drift', async () => { const schemaPath = (await getSchemaPath())! const migrate = new Migrate(schemaPath) const result = migrate.engine.devDiagnostic({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, }) await expect(result).resolves.toMatchInlineSnapshot(` Object { @@ -427,3 +427,20 @@ it('devDiagnostic - reset because drift', async () => { migrate.stop() }) + +it('dbExecute - sqlite', async () => { + ctx.fixture('schema-only-sqlite') + const migrate = new Migrate() + const result = migrate.engine.dbExecute({ + datasourceType: { + tag: 'url', + url: 'file:dev.db', + }, + script: `-- CreateTable + SELECT 1 + `, + }) + + await expect(result).resolves.toMatchInlineSnapshot(`null`) + migrate.stop() +}) diff --git a/packages/migrate/src/bin.ts b/packages/migrate/src/bin.ts index 9237d305a314..710cdc9c8a44 100755 --- a/packages/migrate/src/bin.ts +++ b/packages/migrate/src/bin.ts @@ -1,6 +1,25 @@ #!/usr/bin/env ts-node -process.env.NODE_NO_WARNINGS = '1' +import Debug from '@prisma/debug' +import { enginesVersion } from '@prisma/engines-version' +import { HelpError, isError } from '@prisma/sdk' +import chalk from 'chalk' + +import { CLI } from './CLI' +import { DbCommand } from './commands/DbCommand' +import { DbExecute } from './commands/DbExecute' +import { DbPull } from './commands/DbPull' +import { DbPush } from './commands/DbPush' +// import { DbDrop } from './commands/DbDrop' +import { DbSeed } from './commands/DbSeed' +import { MigrateCommand } from './commands/MigrateCommand' +import { MigrateDeploy } from './commands/MigrateDeploy' +import { MigrateDev } from './commands/MigrateDev' +import { MigrateDiff } from './commands/MigrateDiff' +import { MigrateReset } from './commands/MigrateReset' +import { MigrateResolve } from './commands/MigrateResolve' +import { MigrateStatus } from './commands/MigrateStatus' +import { handlePanic } from './utils/handlePanic' process.on('uncaughtException', (e) => { console.log(e) @@ -9,73 +28,33 @@ process.on('unhandledRejection', (e, promise) => { console.log(String(e), String(promise)) }) -import { HelpError, isError, tryLoadEnvs, arg, getEnvPaths } from '@prisma/sdk' - const commandArray = process.argv.slice(2) -// Parse CLI arguments -const args = arg( - commandArray, - { - '--schema': String, - '--telemetry-information': String, - }, - false, - true, -) - -// -// Read .env file only if next to schema.prisma -// -// if the CLI is called without any command like `dev` we can ignore .env loading -if (process.argv.length > 2) { - try { - const envPaths = getEnvPaths(args['--schema']) - const envData = tryLoadEnvs(envPaths, { conflictCheck: 'error' }) - envData && envData.message && console.log(envData.message) - } catch (e) { - console.log(e) - } -} - -/** - * Dependencies - */ -import chalk from 'chalk' -import Debug from '@prisma/debug' - -import { MigrateCommand } from './commands/MigrateCommand' -import { MigrateDev } from './commands/MigrateDev' -import { MigrateReset } from './commands/MigrateReset' -import { MigrateDeploy } from './commands/MigrateDeploy' -import { MigrateResolve } from './commands/MigrateResolve' -import { MigrateStatus } from './commands/MigrateStatus' -import { DbPush } from './commands/DbPush' -import { DbPull } from './commands/DbPull' -import { DbDrop } from './commands/DbDrop' -import { DbSeed } from './commands/DbSeed' -import { handlePanic } from './utils/handlePanic' -import { enginesVersion } from '@prisma/engines-version' - -const packageJson = eval(`require('../package.json')`) // tslint:disable-line +const packageJson = eval(`require('../package.json')`) /** * Main function */ async function main(): Promise { // create a new CLI with our subcommands - const cli = MigrateCommand.new({ - dev: MigrateDev.new(), - reset: MigrateReset.new(), - deploy: MigrateDeploy.new(), - status: MigrateStatus.new(), - resolve: MigrateResolve.new(), - // for convenient debugging - pull: DbPull.new(), - push: DbPush.new(), - drop: DbDrop.new(), - seed: DbSeed.new(), + const cli = CLI.new({ + migrate: MigrateCommand.new({ + dev: MigrateDev.new(), + status: MigrateStatus.new(), + resolve: MigrateResolve.new(), + reset: MigrateReset.new(), + deploy: MigrateDeploy.new(), + diff: MigrateDiff.new(), + }), + db: DbCommand.new({ + execute: DbExecute.new(), + pull: DbPull.new(), + push: DbPush.new(), + // drop: DbDrop.new(), + seed: DbSeed.new(), + }), }) + // parse the arguments const result = await cli.parse(commandArray) if (result instanceof HelpError) { diff --git a/packages/migrate/src/commands/DbCommand.ts b/packages/migrate/src/commands/DbCommand.ts index 63d877cd6e5d..9f19a10fd869 100644 --- a/packages/migrate/src/commands/DbCommand.ts +++ b/packages/migrate/src/commands/DbCommand.ts @@ -20,20 +20,28 @@ ${chalk.bold('Options')} --schema Custom path to your Prisma schema ${chalk.bold('Commands')} - pull Pull the state from the database to the Prisma schema using introspection - push Push the state from Prisma schema to the database during prototyping - seed Seed your database + pull Pull the state from the database to the Prisma schema using introspection + push Push the state from Prisma schema to the database during prototyping + seed Seed your database + execute Execute native commands to your database (Preview) + +${chalk.bold('Flag')} + + --preview-feature Run Preview Prisma commands ${chalk.bold('Examples')} - Using prisma db pull + Run \`prisma db pull\` ${chalk.dim('$')} prisma db pull - Using prisma db push + Run \`prisma db push\` ${chalk.dim('$')} prisma db push - Using prisma db seed + Run \`prisma db seed\` ${chalk.dim('$')} prisma db seed + + Run \`prisma db execute\` (Preview) + ${chalk.dim('$')} prisma db execute --preview-feature `) private constructor(private readonly cmds: Commands) {} diff --git a/packages/migrate/src/commands/DbDrop.ts b/packages/migrate/src/commands/DbDrop.ts index 6e8b855fea33..72b2b9efac6b 100644 --- a/packages/migrate/src/commands/DbDrop.ts +++ b/packages/migrate/src/commands/DbDrop.ts @@ -1,11 +1,12 @@ import type { Command } from '@prisma/sdk' -import { arg, format, getSchemaPath, getSchemaDir, HelpError, isError, isCi, dropDatabase, link } from '@prisma/sdk' -import path from 'path' +import { arg, dropDatabase, format, getSchemaDir, HelpError, isCi, isError, link, loadEnvFile } from '@prisma/sdk' import chalk from 'chalk' import prompt from 'prompts' + import { getDbInfo } from '../utils/ensureDatabaseExists' +import { DbNeedsForceError } from '../utils/errors' import { PreviewFlagError } from '../utils/flagErrors' -import { NoSchemaFoundError, DbNeedsForceError } from '../utils/errors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { printDatasource } from '../utils/printDatasource' export class DbDrop implements Command { @@ -67,17 +68,18 @@ ${chalk.bold('Examples')} throw new PreviewFlagError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) const dbInfo = await getDbInfo(schemaPath) + if (!dbInfo.url) { + // TODO better error + throw new Error('Connection url is undefined.') + } + const schemaDir = (await getSchemaDir(schemaPath))! console.info() // empty line diff --git a/packages/migrate/src/commands/DbExecute.ts b/packages/migrate/src/commands/DbExecute.ts new file mode 100644 index 000000000000..2a48e7bb924c --- /dev/null +++ b/packages/migrate/src/commands/DbExecute.ts @@ -0,0 +1,201 @@ +import type { Command } from '@prisma/sdk' +import { arg, format, getCommandWithExecutor, getSchemaPath, HelpError, isError, link, loadEnvFile } from '@prisma/sdk' +import chalk from 'chalk' +import fs from 'fs' +import getStdin from 'get-stdin' +import path from 'path' + +import { Migrate } from '../Migrate' +import type { EngineArgs } from '../types' +import { DbExecuteNeedsPreviewFeatureFlagError } from '../utils/errors' + +const helpOptions = format( + `${chalk.bold('Usage')} + +${chalk.dim('$')} prisma db execute --preview-feature [options] + +${chalk.bold('Options')} + +-h, --help Display this help message + +${chalk.italic('Datasource input, only 1 must be provided:')} +--url URL of the datasource to run the command on +--schema Path to your Prisma schema file to take the datasource URL from + +${chalk.italic('Script input, only 1 must be provided:')} +--file Path to a file. The content will be sent as the script to be executed + +${chalk.bold('Flags')} + +--preview-feature Run Preview Prisma commands +--stdin Use the terminal standard input as the script to be executed`, +) + +export class DbExecute implements Command { + public static new(): DbExecute { + return new DbExecute() + } + + private static help = format(` +${process.platform === 'win32' ? '' : chalk.bold('📝 ')}Execute native commands to your database + +${chalk.bold.yellow('WARNING')} ${chalk.bold( + `${chalk.green(`prisma db execute`)} is currently in Preview (${link('https://pris.ly/d/preview')}). +There may be bugs and it's not recommended to use it in production environments.`, + )} + +This command takes as input a datasource, using ${chalk.green(`--url`)} or ${chalk.green( + `--schema`, + )} and a script, using ${chalk.green(`--stdin`)} or ${chalk.green(`--file`)}. +The input parameters are mutually exclusive, only 1 of each (datasource & script) must be provided. + +The output of the command is connector-specific, and is not meant for returning data, but only to report success or failure. + +On SQL databases, this command takes as input a SQL script. +The whole script will be sent as a single command to the database. + +${chalk.italic(`This command is currently not supported on MongoDB.`)} + +${helpOptions} +${chalk.bold('Examples')} + + Execute the content of a SQL script file to the datasource URL taken from the schema + ${chalk.dim('$')} prisma db execute + --preview-feature \\ + --file ./script.sql \\ + --schema schema.prisma + + Execute the SQL script from stdin to the datasource URL specified via the \`DATABASE_URL\` environment variable + ${chalk.dim('$')} echo 'TRUNCATE TABLE dev;' | \\ + prisma db execute \\ + --preview-feature \\ + --stdin \\ + --url="$DATABASE_URL" + + Like previous example, but exposing the datasource url credentials to your terminal history + ${chalk.dim('$')} echo 'TRUNCATE TABLE dev;' | \\ + prisma db execute \\ + --preview-feature \\ + --stdin \\ + --url="mysql://root:root@localhost/mydb" +`) + + public async parse(argv: string[]): Promise { + const args = arg( + argv, + { + '--help': Boolean, + '-h': '--help', + '--stdin': Boolean, + '--file': String, + '--schema': String, + '--url': String, + '--preview-feature': Boolean, + '--telemetry-information': String, + }, + false, + ) + + if (isError(args)) { + return this.help(args.message) + } + + if (args['--help']) { + return this.help() + } + + if (!args['--preview-feature']) { + throw new DbExecuteNeedsPreviewFeatureFlagError() + } + + loadEnvFile(args['--schema'], false) + + // One of --stdin or --file is required + if (args['--stdin'] && args['--file']) { + throw new Error( + `--stdin and --file cannot be used at the same time. Only 1 must be provided. +See \`${chalk.green(getCommandWithExecutor('prisma db execute -h'))}\``, + ) + } else if (!args['--stdin'] && !args['--file']) { + throw new Error( + `Either --stdin or --file must be provided. +See \`${chalk.green(getCommandWithExecutor('prisma db execute -h'))}\``, + ) + } + + // One of --url or --schema is required + if (args['--url'] && args['--schema']) { + throw new Error( + `--url and --schema cannot be used at the same time. Only 1 must be provided. +See \`${chalk.green(getCommandWithExecutor('prisma db execute -h'))}\``, + ) + } else if (!args['--url'] && !args['--schema']) { + throw new Error( + `Either --url or --schema must be provided. +See \`${chalk.green(getCommandWithExecutor('prisma db execute -h'))}\``, + ) + } + + let script = '' + // Read file + if (args['--file']) { + try { + script = fs.readFileSync(path.resolve(args['--file']), 'utf-8') + } catch (e) { + if (e.code === 'ENOENT') { + throw new Error(`Provided --file at ${args['--file']} doesn't exist.`) + } else { + console.error(`An error occurred while reading the provided --file at ${args['--file']}`) + throw e + } + } + } + // Read stdin + if (args['--stdin']) { + script = await getStdin() + } + + let datasourceType: EngineArgs.DbExecuteDatasourceType + + // Execute command(s) to url passed + if (args['--url']) { + datasourceType = { + tag: 'url', + url: args['--url'], + } + } + // Execute command(s) to url from schema + else { + // validate that schema file exists + // throws an error if it doesn't + const schemaPath = await getSchemaPath(args['--schema']) + + // Execute command(s) to url from schema + datasourceType = { + tag: 'schema', + // if schemaPath is undefined, getSchemaPath will error + schema: schemaPath!, + } + } + + const migrate = new Migrate() + + try { + await migrate.engine.dbExecute({ + script, + datasourceType, + }) + } finally { + migrate.stop() + } + + return `Script executed successfully.` + } + + public help(error?: string): string | HelpError { + if (error) { + throw new HelpError(`\n${error}\n\n${helpOptions}`) + } + return DbExecute.help + } +} diff --git a/packages/migrate/src/commands/DbPull.ts b/packages/migrate/src/commands/DbPull.ts index dd1956a62f8e..e68c86fa652d 100644 --- a/packages/migrate/src/commands/DbPull.ts +++ b/packages/migrate/src/commands/DbPull.ts @@ -1,26 +1,27 @@ -import type { Command } from '@prisma/sdk' +import type { Command, IntrospectionSchemaVersion, IntrospectionWarnings } from '@prisma/sdk' import { + arg, + drawBox, format, formatms, - HelpError, + getCommandWithExecutor, + getConfig, + getSchema, getSchemaPath, - arg, + HelpError, + IntrospectionEngine, link, - drawBox, - getSchema, - getConfig, - getCommandWithExecutor, + loadEnvFile, + protocolToConnectorType, } from '@prisma/sdk' import chalk from 'chalk' -import path from 'path' -import type { IntrospectionWarnings, IntrospectionSchemaVersion } from '@prisma/sdk' -import { IntrospectionEngine } from '@prisma/sdk' import fs from 'fs' -import { protocolToConnectorType } from '@prisma/sdk/dist/convertCredentials' -import { printDatasources } from '../utils/printDatasources' -import { removeDatasource } from '../utils/removeDatasource' +import path from 'path' + import { NoSchemaFoundError } from '../utils/errors' import { printDatasource } from '../utils/printDatasource' +import { ConnectorType, printDatasources } from '../utils/printDatasources' +import { removeDatasource } from '../utils/removeDatasource' export class DbPull implements Command { public static new(): DbPull { @@ -32,14 +33,19 @@ Pull the state from the database to the Prisma schema using introspection ${chalk.bold('Usage')} - ${chalk.dim('$')} prisma db pull [options] + ${chalk.dim('$')} prisma db pull [flags/options] + +${chalk.bold('Flags')} + + -h, --help Display this help message + --force Ignore current Prisma schema file + --print Print the introspected Prisma schema to stdout ${chalk.bold('Options')} - -h, --help Display this help message - --schema Custom path to your Prisma schema - --force Ignore current Prisma schema file - --print Print the introspected Prisma schema to stdout + --schema Custom path to your Prisma schema + --composite-type-depth Specify the depth for introspecting composite types (e.g. Embedded Documents in MongoDB) + Number, default is -1 for infinite depth, 0 = off ${chalk.bold('Examples')} @@ -52,11 +58,16 @@ Or specify a Prisma schema path Instead of saving the result to the filesystem, you can also print it to stdout ${chalk.dim('$')} prisma db pull --print +Overwrite the current schema with the introspected schema instead of enriching it + ${chalk.dim('$')} prisma db pull --force + +Set composite types introspection depth to 2 levels + ${chalk.dim('$')} prisma db pull --composite-type-depth=2 + `) private urlToDatasource(url: string): string { const provider = protocolToConnectorType(`${url.split(':')[0]}:`) - return printDatasources([ { config: {}, @@ -83,6 +94,7 @@ Instead of saving the result to the filesystem, you can also print it to stdout const log = (...messages): void => { if (!args['--print']) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument console.info(...messages) } } @@ -116,13 +128,20 @@ Instead of saving the result to the filesystem, you can also print it to stdout } const url: string | undefined = args['--url'] + // getSchemaPathAndPrint is not flexible enough for this use case let schemaPath = await getSchemaPath(args['--schema']) - // Do not print if --print is passed to only have the schema in stdout + // Print to console if --print is not passed to only have the schema in stdout if (schemaPath && !args['--print']) { console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + // Load and print where the .env was loaded (if loaded) + loadEnvFile(args['--schema'], true) + await printDatasource(schemaPath) + } else { + // Load .env but don't print + loadEnvFile(args['--schema'], false) } if (!url && !schemaPath) { @@ -132,18 +151,43 @@ Instead of saving the result to the filesystem, you can also print it to stdout let schema: string | null = null // Makes sure we have a schema to pass to the engine - if (url && schemaPath) { - schema = this.urlToDatasource(url) - const rawSchema = fs.readFileSync(schemaPath, 'utf-8') - schema += removeDatasource(rawSchema) - } else if (url) { - schema = this.urlToDatasource(url) + if (url) { + if (schemaPath) { + schema = this.urlToDatasource(url) + const rawSchema = fs.readFileSync(schemaPath, 'utf-8') + schema += removeDatasource(rawSchema) + } else { + schema = this.urlToDatasource(url) + } } else if (schemaPath) { schema = fs.readFileSync(schemaPath, 'utf-8') } else { throw new Error('Could not find a `schema.prisma` file') } + // Re-Introspection is not supported on MongoDB + if (schemaPath) { + const schema = await getSchema(args['--schema']) + const config = await getConfig({ + datamodel: schema, + ignoreEnvVarErrors: true, + }) + + const modelRegex = /\s*model\s*(\w+)\s*{/ + const modelMatch = modelRegex.exec(schema) + const isReintrospection = modelMatch + + if (isReintrospection && !args['--force'] && config.datasources[0].provider === 'mongodb') { + throw new Error(`Iterating on one schema using re-introspection with db pull is currently not supported with MongoDB provider (Preview). +You can explicitely ignore and override your current local schema file with ${chalk.green( + getCommandWithExecutor('prisma db pull --force'), + )} +Some information will be lost (relations, comments, mapped fields, @ignore...), follow ${link( + 'https://github.com/prisma/prisma/issues/9585', + )} for more info.`) + } + } + const engine = new IntrospectionEngine({ cwd: schemaPath ? path.dirname(schemaPath) : undefined, }) @@ -204,66 +248,13 @@ Or run this command with the ${chalk.green( throw e } - function getWarningMessage(warnings: IntrospectionWarnings[]): string | undefined { - if (warnings.length > 0) { - let message = `\n*** WARNING ***\n` - - for (const warning of warnings) { - message += `\n${warning.message}\n` - - if (warning.code === 0) { - // affected === null - } else if (warning.code === 1) { - message += warning.affected.map((it) => `- "${it.model}"`).join('\n') - } else if (warning.code === 2) { - const modelsGrouped: { - [key: string]: string[] - } = warning.affected.reduce((acc, it) => { - if (!acc[it.model]) { - acc[it.model] = [] - } - acc[it.model].push(it.field) - return acc - }, {}) - message += Object.entries(modelsGrouped) - .map(([model, fields]) => `- Model: "${model}"\n Field(s): "${fields.join('", "')}"`) - .join('\n') - } else if (warning.code === 3) { - message += warning.affected - .map((it) => `- Model "${it.model}", field: "${it.field}", original data type: "${it.tpe}"`) - .join('\n') - } else if (warning.code === 4) { - message += warning.affected.map((it) => `- Enum "${it.enm}", value: "${it.value}"`).join('\n') - } else if ([5, 6, 8, 11, 12, 13].includes(warning.code)) { - message += warning.affected.map((it) => `- Model "${it.model}", field: "${it.field}"`).join('\n') - } else if (warning.code === 7) { - message += warning.affected.map((it) => `- Model "${it.model}"`).join('\n') - } else if ([9, 10].includes(warning.code)) { - message += warning.affected.map((it) => `- Enum "${it.enm}"`).join('\n') - } else if (warning.code === 101) { - message += warning.affected.name - .map((it) => `- Model "${it.model}", field: "${it.field}", chosen data type: "${it.tpe}"`) - .join('\n') - } else if (warning.affected) { - // Output unhandled warning - message += `Code ${warning.code}\n${JSON.stringify(warning.affected, null, 2)}` - } - - message += `\n` - } - return message - } - - return undefined - } - - const introspectionWarningsMessage = getWarningMessage(introspectionWarnings) || '' + const introspectionWarningsMessage = this.getWarningMessage(introspectionWarnings) || '' const prisma1UpgradeMessage = introspectionSchemaVersion.includes('Prisma1') - ? `\n${chalk.bold('Upgrading from Prisma 1 to Prisma 2?')} + ? `\n${chalk.bold('Upgrading from Prisma 1 to Prisma 2+?')} \nThe database you introspected could belong to a Prisma 1 project. -Please run the following command to upgrade to Prisma 2.0: +Please run the following command to upgrade to Prisma 2+: ${chalk.green('npx prisma-upgrade [path-to-prisma-yml] [path-to-schema-prisma]')} Note: \`prisma.yml\` and \`schema.prisma\` paths are optional. @@ -284,32 +275,23 @@ Learn more about the upgrade process in the docs:\n${link('https://pris.ly/d/upg console.error(introspectionWarningsMessage.replace(/(\n)/gm, '\n// ')) } } else { - if (schemaPath) { - const schema = await getSchema(args['--schema']) - const config = await getConfig({ - datamodel: schema, - ignoreEnvVarErrors: true, - }) - - const modelRegex = /\s*model\s*(\w+)\s*{/ - const modelMatch = modelRegex.exec(schema) - const isReintrospection = modelMatch - - if (isReintrospection && !args['--force'] && config.datasources[0].provider === 'mongodb') { - engine.stop() - throw new Error(`Iterating on one schema using re-introspection with db pull is currently not supported with MongoDB provider (Preview). -You can explicitely ignore and override your current local schema file with ${chalk.green( - getCommandWithExecutor('prisma db pull --force'), - )} -Some information will be lost (relations, comments, mapped fields, @ignore...), follow ${link( - 'https://github.com/prisma/prisma/issues/9585', - )} for more info.`) - } - } schemaPath = schemaPath || 'schema.prisma' fs.writeFileSync(schemaPath, introspectionSchema) const modelsCount = (introspectionSchema.match(/^model\s+/gm) || []).length + const modelsCountMessage = `${modelsCount} ${modelsCount > 1 ? 'models' : 'model'}` + const typesCount = (introspectionSchema.match(/^type\s+/gm) || []).length + const typesCountMessage = `${typesCount} ${typesCount > 1 ? 'embedded documents' : 'embedded document'}` + let modelsAndTypesMessage: string + if (typesCount > 0) { + modelsAndTypesMessage = `${modelsCountMessage} and ${typesCountMessage}` + } else { + modelsAndTypesMessage = `${modelsCountMessage}` + } + const modelsAndTypesCountMessage = + modelsCount + typesCount > 1 + ? `${modelsAndTypesMessage} and wrote them` + : `${modelsAndTypesMessage} and wrote it` const prisma1UpgradeMessageBox = prisma1UpgradeMessage ? '\n\n' + @@ -318,16 +300,14 @@ Some information will be lost (relations, comments, mapped fields, @ignore...), width: 74, str: prisma1UpgradeMessage + - '\nOnce you upgraded your database schema to Prisma 2.0, \ncontinue with the instructions below.\n', + '\nOnce you upgraded your database schema to Prisma 2+, \ncontinue with the instructions below.\n', horizontalPadding: 2, }) : '' - log(`\n✔ Introspected ${modelsCount} ${ - modelsCount > 1 ? 'models and wrote them' : 'model and wrote it' - } into ${chalk.underline(path.relative(process.cwd(), schemaPath))} in ${chalk.bold( - formatms(Date.now() - before), - )}${prisma1UpgradeMessageBox} + log(`\n✔ Introspected ${modelsAndTypesCountMessage} into ${chalk.underline( + path.relative(process.cwd(), schemaPath), + )} in ${chalk.bold(formatms(Date.now() - before))}${prisma1UpgradeMessageBox} ${chalk.keyword('orange')(introspectionWarningsMessage)} ${`Run ${chalk.green(getCommandWithExecutor('prisma generate'))} to generate Prisma Client.`}`) } @@ -337,6 +317,105 @@ ${`Run ${chalk.green(getCommandWithExecutor('prisma generate'))} to generate Pri return '' } + private getWarningMessage(warnings: IntrospectionWarnings[]): string | undefined { + if (warnings.length > 0) { + let message = `\n*** WARNING ***\n` + + for (const warning of warnings) { + message += `\n${warning.message}\n` + + if (warning.code === 0) { + // affected === null + } else if (warning.code === 1) { + message += warning.affected.map((it) => `- "${it.model}"`).join('\n') + } else if (warning.code === 2) { + const modelsGrouped: { + [key: string]: string[] + } = warning.affected.reduce((acc, it) => { + if (!acc[it.model]) { + acc[it.model] = [] + } + acc[it.model].push(it.field) + return acc + }, {}) + message += Object.entries(modelsGrouped) + .map(([model, fields]) => `- Model: "${model}"\n Field(s): "${fields.join('", "')}"`) + .join('\n') + } else if (warning.code === 3) { + message += warning.affected + .map((it) => `- Model "${it.model}", field: "${it.field}", original data type: "${it.tpe}"`) + .join('\n') + } else if (warning.code === 4) { + message += warning.affected.map((it) => `- Enum "${it.enm}", value: "${it.value}"`).join('\n') + } else if ( + warning.code === 5 || + warning.code === 6 || + warning.code === 8 || + warning.code === 11 || + warning.code === 12 || + warning.code === 13 || + warning.code === 16 + ) { + message += warning.affected.map((it) => `- Model "${it.model}", field: "${it.field}"`).join('\n') + } else if ( + warning.code === 7 || + warning.code === 14 || + warning.code === 15 || + warning.code === 18 || + warning.code === 19 + ) { + message += warning.affected.map((it) => `- Model "${it.model}"`).join('\n') + } else if (warning.code === 9 || warning.code === 10) { + message += warning.affected.map((it) => `- Enum "${it.enm}"`).join('\n') + } else if (warning.code === 17) { + message += warning.affected + .map((it) => `- Model "${it.model}", Index db name: "${it.index_db_name}"`) + .join('\n') + } else if (warning.code === 101) { + message += warning.affected + .map((it) => { + if (it.model) { + return `- Model "${it.model}", field: "${it.field}", chosen data type: "${it.tpe}"` + } else if (it.compositeType) { + return `- Type "${it.compositeType}", field: "${it.field}", chosen data type: "${it.tpe}"` + } else { + return `Code ${warning.code} - Properties model or compositeType don't exist in ${JSON.stringify( + warning.affected, + null, + 2, + )}` + } + }) + .join('\n') + } else if (warning.code === 102 || warning.code === 103 || warning.code === 104) { + message += warning.affected + .map((it) => { + if (it.model) { + return `- Model "${it.model}", field: "${it.field}"` + } else if (it.compositeType) { + return `- Type "${it.compositeType}", field: "${it.field}"` + } else { + return `Code ${warning.code} - Properties model or compositeType don't exist in ${JSON.stringify( + warning.affected, + null, + 2, + )}` + } + }) + .join('\n') + } else if (warning.affected) { + // Output unhandled warning + message += `Code ${warning.code}\n${JSON.stringify(warning.affected, null, 2)}` + } + + message += `\n` + } + return message + } + + return undefined + } + public help(error?: string): string | HelpError { if (error) { return new HelpError(`\n${chalk.bold.red(`!`)} ${error}\n${DbPull.help}`) diff --git a/packages/migrate/src/commands/DbPush.ts b/packages/migrate/src/commands/DbPush.ts index 7ce7c6716e00..ac864b00820e 100644 --- a/packages/migrate/src/commands/DbPush.ts +++ b/packages/migrate/src/commands/DbPush.ts @@ -3,21 +3,22 @@ import { arg, format, formatms, + getCommandWithExecutor, HelpError, + isCi, isError, - getSchemaPath, + loadEnvFile, logger, - isCi, - getCommandWithExecutor, } from '@prisma/sdk' -import path from 'path' import chalk from 'chalk' import prompt from 'prompts' + import { Migrate } from '../Migrate' +import type { EngineResults } from '../types' import { ensureDatabaseExists, getDbInfo } from '../utils/ensureDatabaseExists' -import { DbPushIgnoreWarningsWithFlagError, DbPushForceFlagRenamedError, NoSchemaFoundError } from '../utils/errors' +import { DbPushForceFlagRenamedError, DbPushIgnoreWarningsWithFlagError } from '../utils/errors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { printDatasource } from '../utils/printDatasource' -import type { EngineResults } from '../types' export class DbPush implements Command { public static new(): DbPush { @@ -88,13 +89,9 @@ You can now remove the ${chalk.red('--preview-feature')} flag.`) throw new DbPushForceFlagRenamedError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) diff --git a/packages/migrate/src/commands/DbSeed.ts b/packages/migrate/src/commands/DbSeed.ts index 71cdc7b002f1..a0d6c0b9bd4a 100644 --- a/packages/migrate/src/commands/DbSeed.ts +++ b/packages/migrate/src/commands/DbSeed.ts @@ -1,11 +1,12 @@ import type { Command } from '@prisma/sdk' -import { arg, format, HelpError, isError, getSchemaPath, logger } from '@prisma/sdk' +import { arg, format, getSchemaPath, HelpError, isError, loadEnvFile, logger } from '@prisma/sdk' import chalk from 'chalk' + import { - getSeedCommandFromPackageJson, executeSeedCommand, - verifySeedConfigAndReturnMessage, + getSeedCommandFromPackageJson, legacyTsNodeScriptWarning, + verifySeedConfigAndReturnMessage, } from '../utils/seed' export class DbSeed implements Command { @@ -54,6 +55,8 @@ You can now remove the ${chalk.red('--preview-feature')} flag.`) await legacyTsNodeScriptWarning() } + loadEnvFile(args['--schema'], true) + // Print warning if user is using --schema if (args['--schema']) { logger.warn( diff --git a/packages/migrate/src/commands/MigrateCommand.ts b/packages/migrate/src/commands/MigrateCommand.ts index 90463f859492..d4e83fad83fd 100644 --- a/packages/migrate/src/commands/MigrateCommand.ts +++ b/packages/migrate/src/commands/MigrateCommand.ts @@ -1,7 +1,8 @@ import type { Command, Commands } from '@prisma/sdk' -import { arg, format, HelpError, isError, logger, link, unknownCommand } from '@prisma/sdk' +import { arg, format, HelpError, isError, link, logger, unknownCommand } from '@prisma/sdk' import chalk from 'chalk' -import { ExperimentalFlagWithNewMigrateError } from '../utils/flagErrors' + +import { ExperimentalFlagWithMigrateError } from '../utils/flagErrors' export class MigrateCommand implements Command { public static new(cmds: Commands): MigrateCommand { @@ -27,6 +28,9 @@ ${chalk.bold('Commands for production/staging')} status Check the status of your database migrations resolve Resolve issues with database migrations, i.e. baseline, failed migration, hotfix +${chalk.bold('Command for any stage')} + diff Compare the database schema from two arbitrary sources (Preview) + ${chalk.bold('Options')} -h, --help Display this help message @@ -49,6 +53,12 @@ ${chalk.bold('Examples')} Specify a schema ${chalk.dim('$')} prisma migrate status --schema=./schema.prisma + Compare the database schema from two databases and render the diff as a SQL script (Preview) + ${chalk.dim('$')} prisma migrate diff \\ + --preview-feature \\ + --from-url "$DATABASE_URL" \\ + --to-url "postgresql://login:password@localhost:5432/db" \\ + --script `) private constructor(private readonly cmds: Commands) {} @@ -69,7 +79,7 @@ ${chalk.bold('Examples')} } if (args['--experimental']) { - throw new ExperimentalFlagWithNewMigrateError() + throw new ExperimentalFlagWithMigrateError() } // display help for help flag or no subcommand @@ -77,27 +87,38 @@ ${chalk.bold('Examples')} return this.help() } - if (['up', 'save', 'down'].includes(args._[0])) { + const commandName = args._[0] + + if (['up', 'save', 'down'].includes(commandName)) { throw new Error( `The current command "${args._[0]}" doesn't exist in the new version of Prisma Migrate. Read more about how to upgrade: ${link('https://pris.ly/d/migrate-upgrade')}`, ) } + // Legacy warning only if --preview-feature is place before the command like below + // prisma migrate --preview-feature command if (args['--preview-feature']) { logger.warn(`Prisma Migrate was in Preview and is now Generally Available. You can now remove the ${chalk.red('--preview-feature')} flag.`) } - const filteredArgs = args._.filter((item) => item !== '--preview-feature') - // check if we have that subcommand - const cmd = this.cmds[filteredArgs[0]] + const cmd = this.cmds[commandName] if (cmd) { - return cmd.parse(filteredArgs.slice(1)) + let argsForCmd: string[] + if (commandName === 'diff') { + argsForCmd = args['--preview-feature'] ? [...args._.slice(1), `--preview-feature`] : args._.slice(1) + } else { + // Filter our --preview-feature flag for other migrate commands that do not consider it valid + const filteredArgs = args._.filter((item) => item !== '--preview-feature') + argsForCmd = filteredArgs.slice(1) + } + + return cmd.parse(argsForCmd) } - return unknownCommand(MigrateCommand.help, args._[0]) + return unknownCommand(MigrateCommand.help, commandName) } public help(error?: string): string | HelpError { diff --git a/packages/migrate/src/commands/MigrateDeploy.ts b/packages/migrate/src/commands/MigrateDeploy.ts index 6aab257408df..97adc33938c0 100644 --- a/packages/migrate/src/commands/MigrateDeploy.ts +++ b/packages/migrate/src/commands/MigrateDeploy.ts @@ -1,15 +1,15 @@ +import Debug from '@prisma/debug' import type { Command } from '@prisma/sdk' -import { arg, format, getSchemaPath, HelpError, isError } from '@prisma/sdk' +import { arg, format, HelpError, isError, loadEnvFile } from '@prisma/sdk' import chalk from 'chalk' -import path from 'path' + import { Migrate } from '../Migrate' -import { ensureDatabaseExists } from '../utils/ensureDatabaseExists' -import { ExperimentalFlagWithNewMigrateError, EarlyAccessFeatureFlagWithNewMigrateError } from '../utils/flagErrors' -import { NoSchemaFoundError } from '../utils/errors' -import { printFilesFromMigrationIds } from '../utils/printFiles' import { throwUpgradeErrorIfOldMigrate } from '../utils/detectOldMigrate' +import { ensureDatabaseExists } from '../utils/ensureDatabaseExists' +import { EarlyAccessFeatureFlagWithMigrateError, ExperimentalFlagWithMigrateError } from '../utils/flagErrors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { printDatasource } from '../utils/printDatasource' -import Debug from '@prisma/debug' +import { printFilesFromMigrationIds } from '../utils/printFiles' const debug = Debug('prisma:migrate:deploy') @@ -63,20 +63,16 @@ ${chalk.bold('Examples')} } if (args['--experimental']) { - throw new ExperimentalFlagWithNewMigrateError() + throw new ExperimentalFlagWithMigrateError() } if (args['--early-access-feature']) { - throw new EarlyAccessFeatureFlagWithNewMigrateError() + throw new EarlyAccessFeatureFlagWithMigrateError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) @@ -96,10 +92,6 @@ ${chalk.bold('Examples')} throw e } - const diagnoseResult = await migrate.diagnoseMigrationHistory({ - optInToShadowDatabase: false, - }) - debug({ diagnoseResult: JSON.stringify(diagnoseResult, null, 2) }) const listMigrationDirectoriesResult = await migrate.listMigrationDirectories() debug({ listMigrationDirectoriesResult }) @@ -111,20 +103,13 @@ ${chalk.bold('Examples')} console.info(`No migration found in prisma/migrations`) } - const editedMigrationNames = diagnoseResult.editedMigrationNames - if (editedMigrationNames.length > 0) { - console.info( - `${chalk.yellow('WARNING The following migrations have been modified since they were applied:')} -${editedMigrationNames.join('\n')}`, - ) - } - let migrationIds: string[] try { console.info() // empty line const { appliedMigrationNames } = await migrate.applyMigrations() migrationIds = appliedMigrationNames } finally { + // Stop engine migrate.stop() } diff --git a/packages/migrate/src/commands/MigrateDev.ts b/packages/migrate/src/commands/MigrateDev.ts index f052a98037f3..9a6d5b3ce713 100644 --- a/packages/migrate/src/commands/MigrateDev.ts +++ b/packages/migrate/src/commands/MigrateDev.ts @@ -1,34 +1,35 @@ +import Debug from '@prisma/debug' import type { Command } from '@prisma/sdk' import { arg, format, - HelpError, - isError, - getSchemaPath, getCommandWithExecutor, - isCi, - logger, getConfig, getDMMF, + getSchemaPath, + HelpError, + isCi, + isError, + loadEnvFile, } from '@prisma/sdk' -import Debug from '@prisma/debug' import chalk from 'chalk' -import prompt from 'prompts' import fs from 'fs' -import path from 'path' +import prompt from 'prompts' + import { Migrate } from '../Migrate' +import type { EngineResults } from '../types' +import { throwUpgradeErrorIfOldMigrate } from '../utils/detectOldMigrate' import type { DbType } from '../utils/ensureDatabaseExists' import { ensureDatabaseExists, getDbInfo } from '../utils/ensureDatabaseExists' -import { ExperimentalFlagWithNewMigrateError, EarlyAccessFeatureFlagWithNewMigrateError } from '../utils/flagErrors' -import { NoSchemaFoundError, MigrateDevEnvNonInteractiveError } from '../utils/errors' -import { printMigrationId } from '../utils/printMigrationId' -import { printFilesFromMigrationIds } from '../utils/printFiles' +import { MigrateDevEnvNonInteractiveError } from '../utils/errors' +import { EarlyAccessFeatureFlagWithMigrateError, ExperimentalFlagWithMigrateError } from '../utils/flagErrors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { handleUnexecutableSteps } from '../utils/handleEvaluateDataloss' -import { getMigrationName } from '../utils/promptForMigrationName' -import { throwUpgradeErrorIfOldMigrate } from '../utils/detectOldMigrate' import { printDatasource } from '../utils/printDatasource' -import { executeSeedCommand, verifySeedConfigAndReturnMessage, getSeedCommandFromPackageJson } from '../utils/seed' -import type { EngineResults } from '../types' +import { printFilesFromMigrationIds } from '../utils/printFiles' +import { printMigrationId } from '../utils/printMigrationId' +import { getMigrationName } from '../utils/promptForMigrationName' +import { executeSeedCommand, getSeedCommandFromPackageJson, verifySeedConfigAndReturnMessage } from '../utils/seed' const debug = Debug('prisma:migrate:dev') @@ -94,20 +95,16 @@ ${chalk.bold('Examples')} } if (args['--experimental']) { - throw new ExperimentalFlagWithNewMigrateError() + throw new ExperimentalFlagWithMigrateError() } if (args['--early-access-feature']) { - throw new EarlyAccessFeatureFlagWithNewMigrateError() + throw new EarlyAccessFeatureFlagWithMigrateError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) @@ -261,7 +258,7 @@ ${chalk.bold('Examples')} let migrationIds: string[] try { const createMigrationResult = await migrate.createMigration({ - migrationsDirectoryPath: migrate.migrationsDirectoryPath, + migrationsDirectoryPath: migrate.migrationsDirectoryPath!, migrationName: migrationName || '', draft: args['--create-only'] ? true : false, prismaSchema: migrate.getDatamodel(), @@ -281,6 +278,7 @@ ${chalk.bold('Examples')} const { appliedMigrationNames } = await migrate.applyMigrations() migrationIds = appliedMigrationNames } finally { + // Stop engine migrate.stop() } diff --git a/packages/migrate/src/commands/MigrateDiff.ts b/packages/migrate/src/commands/MigrateDiff.ts new file mode 100644 index 000000000000..0134b3c64021 --- /dev/null +++ b/packages/migrate/src/commands/MigrateDiff.ts @@ -0,0 +1,273 @@ +import Debug from '@prisma/debug' +import type { Command } from '@prisma/sdk' +import { arg, format, HelpError, isError, link, loadEnvFile } from '@prisma/sdk' +import chalk from 'chalk' +import path from 'path' + +import { Migrate } from '../Migrate' +import type { EngineArgs, EngineResults } from '../types' +import { MigrateDiffNeedsPreviewFeatureFlagError } from '../utils/errors' + +const debug = Debug('prisma:migrate:diff') + +const helpOptions = format( + `${chalk.bold('Usage')} + +${chalk.dim('$')} prisma migrate diff --preview-feature [options] + +${chalk.bold('Options')} + +-h, --help Display this help message + +${chalk.italic('From and To inputs (1 `--from-...` and 1 `--to-...` must be provided):')} +--from-url / --to-url A datasource URL +--from-empty / --to-empty Flag to assume from or to is an empty datamodel +--from-schema-datamodel / --to-schema-datamodel Path to a Prisma schema file, uses the datamodel for the diff +--from-schema-datasource / --to-schema-datasource Path to a Prisma schema file, uses the datasource url for the diff +--from-migrations / --to-migrations Path to the Prisma Migrate migrations directory + +${chalk.italic('Shadow database (only required if using --from-migrations or --to-migrations):')} +--shadow-database-url URL for the shadow database + +${chalk.italic('Output format:')} +--script Render a SQL script to stdout instead of the default human readable summary (not supported on MongoDB) + +${chalk.bold('Flags')} + +--preview-feature Run Preview Prisma commands +--exit-code Change the exit code behavior to signal if diff is empty or not (Empty: 0, Error: 1, Not empty: 2)`, +) + +export class MigrateDiff implements Command { + public static new(): MigrateDiff { + return new MigrateDiff() + } + + private static help = format(` +${ + process.platform === 'win32' ? '' : chalk.bold('🔍 ') +}Compares the database schema from two arbitrary sources, and outputs the differences either as a human-readable summary (by default) or an executable script. + +${chalk.bold.yellow('WARNING')} ${chalk.bold( + `${chalk.green(`prisma migrate diff`)} is currently in Preview (${link('https://pris.ly/d/preview')}). +There may be bugs and it's not recommended to use it in production environments.`, + )} + +${chalk.green(`prisma migrate diff`)} is a read-only command that does not write to your datasource(s). +${chalk.green(`prisma db execute`)} can be used to execute its ${chalk.green(`--script`)} output. + +The command takes a source ${chalk.green(`--from-...`)} and a destination ${chalk.green(`--to-...`)}. +The source and destination must use the same provider, +e.g. a diff using 2 different providers like PostgreSQL and SQLite is not supported. + +It compares the source with the destination to generate a diff. +The diff can be interpreted as generating a migration that brings the source schema (from) to the shape of the destination schema (to). +The default output is a human readable diff, it can be rendered as SQL using \`--script\` on SQL databases. + +See the documentation for more information ${link('https://pris.ly/d/migrate-diff')} + +${helpOptions} +${chalk.bold('Examples')} + + From database to database as summary + e.g. compare two live databases + ${chalk.dim('$')} prisma migrate diff --preview-feature \\ + --from-url "$DATABASE_URL" \\ + --to-url "postgresql://login:password@localhost:5432/db2" + + From a live database to a Prisma datamodel + e.g. roll forward after a migration failed in the middle + ${chalk.dim('$')} prisma migrate diff --preview-feature \\ + --shadow-database-url "$SHADOW_DB" \\ + --from-url "$PROD_DB" \\ + --to-schema-datamodel=next_datamodel.prisma \\ + --script + + From a live database to a datamodel + e.g. roll backward after a migration failed in the middle + ${chalk.dim('$')} prisma migrate diff --preview-feature \\ + --shadow-database-url "$SHADOW_DB" \\ + --from-url "$PROD_DB" \\ + --to-schema-datamodel=previous_datamodel.prisma \\ + --script + + From a Prisma Migrate \`migrations\` directory to another database + e.g. generate a migration for a hotfix already applied on production + ${chalk.dim('$')} prisma migrate diff --preview-feature \\ + --shadow-database-url "$SHADOW_DB" \\ + --from-migrations ./migrations \\ + --to-url "$PROD_DB" \\ + --script + + Execute the --script output with \`prisma db execute\` using bash pipe \`|\` + ${chalk.dim('$')} prisma migrate diff --preview-feature \\ + --from-[...] \\ + --to-[...] \\ + --script | prisma db execute --preview-feature --stdin --url="$DATABASE_URL" + + Detect if both sources are in sync, it will exit with exit code 2 if changes are detected + ${chalk.dim('$')} prisma migrate diff --preview-feature \\ + --exit-code \\ + --from-[...] \\ + --to-[...] +`) + + public async parse(argv: string[]): Promise { + const args = arg( + argv, + { + '--help': Boolean, + '-h': '--help', + // From + '--from-empty': Boolean, + '--from-schema-datasource': String, + '--from-schema-datamodel': String, + '--from-url': String, + '--from-migrations': String, + // To + '--to-empty': Boolean, + '--to-schema-datasource': String, + '--to-schema-datamodel': String, + '--to-url': String, + '--to-migrations': String, + // Others + '--shadow-database-url': String, + '--script': Boolean, + '--exit-code': Boolean, + '--preview-feature': Boolean, + '--telemetry-information': String, + }, + false, + ) + + if (isError(args)) { + return this.help(args.message) + } + + if (args['--help']) { + return this.help() + } + + if (!args['--preview-feature']) { + throw new MigrateDiffNeedsPreviewFeatureFlagError() + } + + const numberOfFromParameterProvided = + Number(Boolean(args['--from-empty'])) + + Number(Boolean(args['--from-schema-datasource'])) + + Number(Boolean(args['--from-schema-datamodel'])) + + Number(Boolean(args['--from-url'])) + + Number(Boolean(args['--from-migrations'])) + + const numberOfToParameterProvided = + Number(Boolean(args['--to-empty'])) + + Number(Boolean(args['--to-schema-datasource'])) + + Number(Boolean(args['--to-schema-datamodel'])) + + Number(Boolean(args['--to-url'])) + + Number(Boolean(args['--to-migrations'])) + + // One of --to or --from is required + if (numberOfFromParameterProvided !== 1 || numberOfToParameterProvided !== 1) { + const errorMessages: string[] = [] + if (numberOfFromParameterProvided !== 1) { + errorMessages.push(`${numberOfFromParameterProvided} \`--from-...\` parameter(s) provided. 1 must be provided.`) + } + if (numberOfToParameterProvided !== 1) { + errorMessages.push(`${numberOfToParameterProvided} \`--to-...\` parameter(s) provided. 1 must be provided.`) + } + return this.help(`${errorMessages.join('\n')}`) + } + + let from: EngineArgs.MigrateDiffTarget + if (args['--from-empty']) { + from = { + tag: 'empty', + } + } else if (args['--from-schema-datasource']) { + // Load .env file that might be needed + loadEnvFile(args['--from-schema-datasource'], false) + + from = { + tag: 'schemaDatasource', + schema: path.resolve(args['--from-schema-datasource']), + } + } else if (args['--from-schema-datamodel']) { + from = { + tag: 'schemaDatamodel', + schema: path.resolve(args['--from-schema-datamodel']), + } + } else if (args['--from-url']) { + from = { + tag: 'url', + url: args['--from-url'], + } + } else if (args['--from-migrations']) { + from = { + tag: 'migrations', + path: path.resolve(args['--from-migrations']), + } + } + + let to: EngineArgs.MigrateDiffTarget + if (args['--to-empty']) { + to = { + tag: 'empty', + } + } else if (args['--to-schema-datasource']) { + // Load .env file that might be needed + loadEnvFile(args['--to-schema-datasource'], false) + + to = { + tag: 'schemaDatasource', + schema: path.resolve(args['--to-schema-datasource']), + } + } else if (args['--to-schema-datamodel']) { + to = { + tag: 'schemaDatamodel', + schema: path.resolve(args['--to-schema-datamodel']), + } + } else if (args['--to-url']) { + to = { + tag: 'url', + url: args['--to-url'], + } + } else if (args['--to-migrations']) { + to = { + tag: 'migrations', + path: path.resolve(args['--to-migrations']), + } + } + + const migrate = new Migrate() + + let result: EngineResults.MigrateDiffOutput + try { + result = await migrate.engine.migrateDiff({ + from: from!, + to: to!, + script: args['--script'] || false, // default is false + shadowDatabaseUrl: args['--shadow-database-url'], + exitCode: args['--exit-code'], + }) + } finally { + // Stop engine + migrate.stop() + } + + debug(result) + + if (args['--exit-code'] && result.exitCode) { + process.exit(result.exitCode) + } + + // Return nothing + return `` + } + + public help(error?: string): string | HelpError { + if (error) { + throw new HelpError(`\n${error}\n\n${helpOptions}`) + } + return MigrateDiff.help + } +} diff --git a/packages/migrate/src/commands/MigrateReset.ts b/packages/migrate/src/commands/MigrateReset.ts index 431ef3893957..0ccd72fe4a62 100644 --- a/packages/migrate/src/commands/MigrateReset.ts +++ b/packages/migrate/src/commands/MigrateReset.ts @@ -1,16 +1,17 @@ import type { Command } from '@prisma/sdk' -import { arg, format, getSchemaPath, HelpError, isError, isCi, logger } from '@prisma/sdk' +import { arg, format, getSchemaPath, HelpError, isCi, isError, loadEnvFile } from '@prisma/sdk' import chalk from 'chalk' -import path from 'path' import prompt from 'prompts' + import { Migrate } from '../Migrate' -import { ExperimentalFlagWithNewMigrateError, EarlyAccessFeatureFlagWithNewMigrateError } from '../utils/flagErrors' -import { NoSchemaFoundError, MigrateResetEnvNonInteractiveError } from '../utils/errors' -import { printFilesFromMigrationIds } from '../utils/printFiles' import { throwUpgradeErrorIfOldMigrate } from '../utils/detectOldMigrate' import { ensureDatabaseExists } from '../utils/ensureDatabaseExists' +import { MigrateResetEnvNonInteractiveError } from '../utils/errors' +import { EarlyAccessFeatureFlagWithMigrateError, ExperimentalFlagWithMigrateError } from '../utils/flagErrors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { printDatasource } from '../utils/printDatasource' -import { executeSeedCommand, verifySeedConfigAndReturnMessage, getSeedCommandFromPackageJson } from '../utils/seed' +import { printFilesFromMigrationIds } from '../utils/printFiles' +import { executeSeedCommand, getSeedCommandFromPackageJson, verifySeedConfigAndReturnMessage } from '../utils/seed' export class MigrateReset implements Command { public static new(): MigrateReset { @@ -67,20 +68,16 @@ ${chalk.bold('Examples')} } if (args['--experimental']) { - throw new ExperimentalFlagWithNewMigrateError() + throw new ExperimentalFlagWithMigrateError() } if (args['--early-access-feature']) { - throw new EarlyAccessFeatureFlagWithNewMigrateError() + throw new EarlyAccessFeatureFlagWithMigrateError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) @@ -125,6 +122,7 @@ ${chalk.bold('Examples')} const { appliedMigrationNames } = await migrate.applyMigrations() migrationIds = appliedMigrationNames } finally { + // Stop engine migrate.stop() } diff --git a/packages/migrate/src/commands/MigrateResolve.ts b/packages/migrate/src/commands/MigrateResolve.ts index 645a6efa4e16..41921b049d9c 100644 --- a/packages/migrate/src/commands/MigrateResolve.ts +++ b/packages/migrate/src/commands/MigrateResolve.ts @@ -1,13 +1,14 @@ import type { Command } from '@prisma/sdk' -import { arg, format, getSchemaPath, HelpError, isError, getCommandWithExecutor, link } from '@prisma/sdk' +import { arg, format, getCommandWithExecutor, HelpError, isError, link, loadEnvFile } from '@prisma/sdk' import chalk from 'chalk' -import path from 'path' -import { ensureCanConnectToDatabase } from '../utils/ensureDatabaseExists' + import { Migrate } from '../Migrate' -import { ExperimentalFlagWithNewMigrateError, EarlyAccessFeatureFlagWithNewMigrateError } from '../utils/flagErrors' -import { NoSchemaFoundError } from '../utils/errors' import { throwUpgradeErrorIfOldMigrate } from '../utils/detectOldMigrate' +import { ensureCanConnectToDatabase } from '../utils/ensureDatabaseExists' +import { EarlyAccessFeatureFlagWithMigrateError, ExperimentalFlagWithMigrateError } from '../utils/flagErrors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { printDatasource } from '../utils/printDatasource' + export class MigrateResolve implements Command { public static new(): MigrateResolve { return new MigrateResolve() @@ -71,20 +72,16 @@ ${chalk.bold('Examples')} } if (args['--experimental']) { - throw new ExperimentalFlagWithNewMigrateError() + throw new ExperimentalFlagWithMigrateError() } if (args['--early-access-feature']) { - throw new EarlyAccessFeatureFlagWithNewMigrateError() + throw new EarlyAccessFeatureFlagWithMigrateError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) diff --git a/packages/migrate/src/commands/MigrateStatus.ts b/packages/migrate/src/commands/MigrateStatus.ts index 0c3f4ea6710d..fea86ee5572f 100644 --- a/packages/migrate/src/commands/MigrateStatus.ts +++ b/packages/migrate/src/commands/MigrateStatus.ts @@ -1,15 +1,16 @@ +import Debug from '@prisma/debug' import type { Command } from '@prisma/sdk' -import { arg, format, getSchemaPath, HelpError, isError, getCommandWithExecutor } from '@prisma/sdk' +import { arg, format, getCommandWithExecutor, HelpError, isError, loadEnvFile } from '@prisma/sdk' import chalk from 'chalk' -import path from 'path' -import { ensureCanConnectToDatabase } from '../utils/ensureDatabaseExists' + import { Migrate } from '../Migrate' -import { ExperimentalFlagWithNewMigrateError, EarlyAccessFeatureFlagWithNewMigrateError } from '../utils/flagErrors' -import { HowToBaselineError, NoSchemaFoundError } from '../utils/errors' -import Debug from '@prisma/debug' +import type { EngineResults } from '../types' import { throwUpgradeErrorIfOldMigrate } from '../utils/detectOldMigrate' +import { ensureCanConnectToDatabase } from '../utils/ensureDatabaseExists' +import { HowToBaselineError } from '../utils/errors' +import { EarlyAccessFeatureFlagWithMigrateError, ExperimentalFlagWithMigrateError } from '../utils/flagErrors' +import { getSchemaPathAndPrint } from '../utils/getSchemaPathAndPrint' import { printDatasource } from '../utils/printDatasource' -import type { EngineResults } from '../types' const debug = Debug('prisma:migrate:status') @@ -62,20 +63,16 @@ Check the status of your database migrations } if (args['--experimental']) { - throw new ExperimentalFlagWithNewMigrateError() + throw new ExperimentalFlagWithMigrateError() } if (args['--early-access-feature']) { - throw new EarlyAccessFeatureFlagWithNewMigrateError() + throw new EarlyAccessFeatureFlagWithMigrateError() } - const schemaPath = await getSchemaPath(args['--schema']) - - if (!schemaPath) { - throw new NoSchemaFoundError() - } + loadEnvFile(args['--schema'], true) - console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + const schemaPath = await getSchemaPathAndPrint(args['--schema']) await printDatasource(schemaPath) diff --git a/packages/migrate/src/index.ts b/packages/migrate/src/index.ts index f96563d082d6..be31e464cdf4 100644 --- a/packages/migrate/src/index.ts +++ b/packages/migrate/src/index.ts @@ -1,17 +1,19 @@ -export { Migrate } from './Migrate' -export { MigrateEngine } from './MigrateEngine' -export { MigrateCommand } from './commands/MigrateCommand' -export { MigrateDev } from './commands/MigrateDev' -export { MigrateResolve } from './commands/MigrateResolve' -export { MigrateStatus } from './commands/MigrateStatus' -export { MigrateReset } from './commands/MigrateReset' -export { MigrateDeploy } from './commands/MigrateDeploy' export { DbCommand } from './commands/DbCommand' +export { DbDrop } from './commands/DbDrop' +export { DbExecute } from './commands/DbExecute' export { DbPull } from './commands/DbPull' export { DbPush } from './commands/DbPush' -export { DbDrop } from './commands/DbDrop' export { DbSeed } from './commands/DbSeed' +export { MigrateCommand } from './commands/MigrateCommand' +export { MigrateDeploy } from './commands/MigrateDeploy' +export { MigrateDev } from './commands/MigrateDev' +export { MigrateDiff } from './commands/MigrateDiff' +export { MigrateReset } from './commands/MigrateReset' +export { MigrateResolve } from './commands/MigrateResolve' +export { MigrateStatus } from './commands/MigrateStatus' +export { Migrate } from './Migrate' +export { MigrateEngine } from './MigrateEngine' +export * from './types' export { default as byline } from './utils/byline' +export { getSchemaPathAndPrint } from './utils/getSchemaPathAndPrint' export { handlePanic } from './utils/handlePanic' - -export * from './types' diff --git a/packages/migrate/src/types.ts b/packages/migrate/src/types.ts index 610d1d6d3594..475b9fbb2e1a 100644 --- a/packages/migrate/src/types.ts +++ b/packages/migrate/src/types.ts @@ -1,3 +1,29 @@ +// See engine's JSON RPC types +// https://prisma.github.io/prisma-engines/doc/migration_core/json_rpc/types/index.html + +// https://www.jsonrpc.org/specification +// A JSON-RPC request or response. +export interface RpcRequestResponse { + id: number + jsonrpc: '2.0' +} + +// should this be result: T; error: never? (and same below) +export interface RpcSuccessResponse extends RpcRequestResponse { + result: T +} + +interface RpcErrorResponse extends RpcRequestResponse { + error: T +} + +export type RpcResponse = RpcSuccessResponse | RpcErrorResponse + +export interface RPCPayload extends RpcRequestResponse { + method: string + params: any +} + interface UserFacingError { is_panic: boolean message: string @@ -90,6 +116,74 @@ export namespace EngineArgs { migrationsDirectoryPath: string } + type DbExecuteDatasourceTypeSchema = { + // Path to the Prisma schema file to take the datasource URL from. + tag: 'schema' + schema: string + } + type DbExecuteDatasourceTypeUrl = { + // The URL of the database to run the command on. + tag: 'url' + url: string + } + export type DbExecuteDatasourceType = DbExecuteDatasourceTypeSchema | DbExecuteDatasourceTypeUrl + + export interface DbExecuteInput { + // The location of the live database to connect to. + datasourceType: DbExecuteDatasourceType + // The input script. + script: string + } + + type MigrateDiffTargetUrl = { + // The url to a live database. Its schema will be considered. + // This will cause the migration engine to connect to the database and read from it. It will not write. + tag: 'url' + url: string + } + type MigrateDiffTargetEmpty = { + // An empty schema. + tag: 'empty' + } + type MigrateDiffTargetSchemaDatamodel = { + // Path to the Prisma schema file to take the datasource URL from. + tag: 'schemaDatamodel' + schema: string + } + type MigrateDiffTargetSchemaDatasource = { + // The path to a Prisma schema. + // The datasource url will be considered, and the live database it points to introspected for its schema. + tag: 'schemaDatasource' + schema: string + } + type MigrateDiffTargetMigrations = { + // The path to a migrations directory of the shape expected by Prisma Migrate. + // The migrations will be applied to a shadow database, and the resulting schema considered for diffing. + tag: 'migrations' + path: string + } + export type MigrateDiffTarget = + | MigrateDiffTargetUrl + | MigrateDiffTargetEmpty + | MigrateDiffTargetSchemaDatamodel + | MigrateDiffTargetSchemaDatasource + | MigrateDiffTargetMigrations + export interface MigrateDiffInput { + // The source of the schema to consider as a starting point. + from: MigrateDiffTarget + // The source of the schema to consider as a destination, or the desired end-state. + to: MigrateDiffTarget + // By default, the response will contain a human-readable diff. + // If you want an executable script, pass the "script": true param. + script: boolean + // The URL to a live database to use as a shadow database. The schema and data on that database will be wiped during diffing. + // This is only necessary when one of from or to is referencing a migrations directory as a source for the schema. + shadowDatabaseUrl?: string + // Change the exit code behaviour when diff is not empty + // Empty: 0, Error: 1, Non empty: 2 + exitCode?: boolean + } + export interface SchemaPush { schema: string force: boolean @@ -136,12 +230,26 @@ export namespace EngineResults { export interface ApplyMigrationsOutput { appliedMigrationNames: string[] } - export interface SchemaPush { executedSteps: number warnings: string[] unexecutable: string[] } + export interface DbExecuteOutput {} + + export enum MigrateDiffExitCode { + // 0 = success + // if --exit-code is passed + // 0 = success with empty diff (no changes) + SUCCESS = 0, + // 1 = Error + ERROR = 1, + // 2 = Succeeded with non-empty diff (changes present) + SUCCESS_NONEMPTY = 2, + } + export interface MigrateDiffOutput { + exitCode: MigrateDiffExitCode + } } export interface FileMap { diff --git a/packages/migrate/src/utils/byline.ts b/packages/migrate/src/utils/byline.ts index db85eea39f3d..0cafe7551686 100644 --- a/packages/migrate/src/utils/byline.ts +++ b/packages/migrate/src/utils/byline.ts @@ -44,7 +44,7 @@ export function createLineStream(readStream, options) { if (!readStream.readable) { throw new Error('readStream must be readable') } - var ls = new LineStream(options) + const ls = new LineStream(options) readStream.pipe(ls) return ls } @@ -92,7 +92,7 @@ LineStream.prototype._transform = function (chunk, encoding, done) { } this._chunkEncoding = encoding - var lines = chunk.split(/\r\n|\r|\n/g) + const lines = chunk.split(/\r\n|\r|\n/g) // don't split CRLF which spans chunks if (this._lastChunkEndedWithCR && chunk[0] == '\n') { @@ -112,7 +112,7 @@ LineStream.prototype._transform = function (chunk, encoding, done) { LineStream.prototype._pushBuffer = function (encoding, keep, done) { // always buffer the last (possibly partial) line while (this._lineBuffer.length > keep) { - var line = this._lineBuffer.shift() + const line = this._lineBuffer.shift() // skip empty lines if (this._keepEmptyLines || line.length > 0) { if (!this.push(this._reencode(line, encoding))) { diff --git a/packages/migrate/src/utils/detectOldMigrate.ts b/packages/migrate/src/utils/detectOldMigrate.ts index 9dcc1aa0774d..bd5bf0a09054 100644 --- a/packages/migrate/src/utils/detectOldMigrate.ts +++ b/packages/migrate/src/utils/detectOldMigrate.ts @@ -1,5 +1,6 @@ import fs from 'fs' import path from 'path' + import { OldMigrateDetectedError } from './errors' export function isOldMigrate(migrationDirPath: string): boolean { diff --git a/packages/migrate/src/utils/ensureDatabaseExists.ts b/packages/migrate/src/utils/ensureDatabaseExists.ts index 3b1bb3650593..71848b2ab6a0 100644 --- a/packages/migrate/src/utils/ensureDatabaseExists.ts +++ b/packages/migrate/src/utils/ensureDatabaseExists.ts @@ -1,20 +1,18 @@ -import { getSchema, getSchemaDir } from '@prisma/sdk' -import { getConfig } from '@prisma/sdk' -import chalk from 'chalk' import type { DatabaseCredentials } from '@prisma/sdk' -import { uriToCredentials, createDatabase, canConnectToDatabase } from '@prisma/sdk' -import prompt from 'prompts' +import { canConnectToDatabase, createDatabase, getConfig, getSchema, getSchemaDir, uriToCredentials } from '@prisma/sdk' +import chalk from 'chalk' import type execa from 'execa' +import prompt from 'prompts' export type MigrateAction = 'create' | 'apply' | 'unapply' | 'dev' | 'push' -export type DbType = 'MySQL' | 'PostgreSQL' | 'SQLite' | 'SQL Server' +export type DbType = 'MySQL' | 'PostgreSQL' | 'SQLite' | 'SQL Server' | 'CockroachDB' // TODO: extract functions in their own files? export async function getDbInfo(schemaPath?: string): Promise<{ - name: string // from datasource name - url: string // from getConfig schemaWord: 'database' // legacy? could be removed? + name?: string // from datasource name + url?: string // from getConfig dbLocation?: string // host without credentials dbType?: DbType // pretty name dbName?: string // database name @@ -22,7 +20,19 @@ export async function getDbInfo(schemaPath?: string): Promise<{ }> { const datamodel = await getSchema(schemaPath) const config = await getConfig({ datamodel }) - const activeDatasource = config.datasources[0] + const activeDatasource = config.datasources?.[0] + + if (!activeDatasource) { + return { + name: undefined, + schemaWord: 'database', + dbType: undefined, + dbName: undefined, + dbLocation: undefined, + url: undefined, + } + } + const url = activeDatasource.url.value if (activeDatasource.provider === 'sqlserver') { @@ -41,13 +51,20 @@ export async function getDbInfo(schemaPath?: string): Promise<{ const dbLocation = getDbLocation(credentials) const dbinfoFromCredentials = getDbinfoFromCredentials(credentials) - return { + const dbInfo = { name: activeDatasource.name, dbLocation, ...dbinfoFromCredentials, url, schema: credentials.schema, } + + // For CockroachDB we cannot rely on the connection URL, only on the provider + if (activeDatasource.provider === 'cockroachdb') { + dbInfo.dbType = 'CockroachDB' + } + + return dbInfo } catch (e) { return { name: activeDatasource.name, @@ -123,8 +140,14 @@ export async function ensureDatabaseExists(action: MigrateAction, forceCreate = // parse the url const credentials = uriToCredentials(activeDatasource.url.value) const { schemaWord, dbType, dbName } = getDbinfoFromCredentials(credentials) + let databaseProvider = dbType + // not needed to check for sql server here since we returned already earlier if provider = sqlserver if (dbType && dbType !== 'SQL Server') { + // For CockroachDB we cannot rely on the connection URL, only on the provider + if (activeDatasource.provider === 'cockroachdb') { + databaseProvider = 'CockroachDB' + } return `${dbType} ${schemaWord} ${chalk.bold(dbName)} created at ${chalk.bold(getDbLocation(credentials))}` } else { // SQL Server case, never reached? @@ -236,6 +259,9 @@ export function getDbinfoFromCredentials(credentials: DatabaseCredentials): { case 'sqlite': dbType = `SQLite` break + case 'cockroachdb': + dbType = `CockroachDB` + break // this is never reached as url parsing for sql server is not implemented case 'sqlserver': dbType = `SQL Server` diff --git a/packages/migrate/src/utils/errors.ts b/packages/migrate/src/utils/errors.ts index 2df35bc29f48..c4c0ad69cc00 100644 --- a/packages/migrate/src/utils/errors.ts +++ b/packages/migrate/src/utils/errors.ts @@ -1,5 +1,5 @@ -import chalk from 'chalk' import { getCommandWithExecutor, link } from '@prisma/sdk' +import chalk from 'chalk' export class NoSchemaFoundError extends Error { constructor() { @@ -96,3 +96,23 @@ export class DbNeedsForceError extends Error { ) } } + +export class DbExecuteNeedsPreviewFeatureFlagError extends Error { + constructor() { + super( + `This command is in Preview. Use the --preview-feature flag to use it like ${chalk.bold.greenBright( + getCommandWithExecutor(`prisma db execute --preview-feature`), + )}`, + ) + } +} + +export class MigrateDiffNeedsPreviewFeatureFlagError extends Error { + constructor() { + super( + `This command is in Preview. Use the --preview-feature flag to use it like ${chalk.bold.greenBright( + getCommandWithExecutor(`prisma migrate diff --preview-feature`), + )}`, + ) + } +} diff --git a/packages/migrate/src/utils/flagErrors.ts b/packages/migrate/src/utils/flagErrors.ts index c4c5c94d16e8..e049f5491f4a 100644 --- a/packages/migrate/src/utils/flagErrors.ts +++ b/packages/migrate/src/utils/flagErrors.ts @@ -24,7 +24,7 @@ Please provide the ${chalk.green('--early-access-feature')} flag to use this com } } -export class ExperimentalFlagWithNewMigrateError extends Error { +export class ExperimentalFlagWithMigrateError extends Error { constructor() { super( `Prisma Migrate was Experimental and is now Generally Available. @@ -35,11 +35,11 @@ ${chalk.yellow( } } -export class EarlyAccessFeatureFlagWithNewMigrateError extends Error { +export class EarlyAccessFeatureFlagWithMigrateError extends Error { constructor() { super( - `Prisma Migrate was in Early Access and is now in Preview. -Replace the ${chalk.red('--early-access-feature')} flag with ${chalk.green('--preview-feature')}.`, + `Prisma Migrate was in Early Access and is now Generally Available. +Remove the ${chalk.red('--early-access-feature')} flag.`, ) } } diff --git a/packages/migrate/src/utils/getGithubIssueUrl.ts b/packages/migrate/src/utils/getGithubIssueUrl.ts index ee489d88450a..29759a185c8e 100644 --- a/packages/migrate/src/utils/getGithubIssueUrl.ts +++ b/packages/migrate/src/utils/getGithubIssueUrl.ts @@ -1,8 +1,9 @@ +import { getPlatform } from '@prisma/get-platform' import newGithubIssueUrl from 'new-github-issue-url' import open from 'open' import prompt from 'prompts' import stripAnsi from 'strip-ansi' -import { getPlatform } from '@prisma/get-platform' + export function getGithubIssueUrl({ title, user = 'prisma', diff --git a/packages/migrate/src/utils/getSchemaPathAndPrint.ts b/packages/migrate/src/utils/getSchemaPathAndPrint.ts new file mode 100644 index 000000000000..b38f0d658595 --- /dev/null +++ b/packages/migrate/src/utils/getSchemaPathAndPrint.ts @@ -0,0 +1,37 @@ +import { getSchemaPath, logger } from '@prisma/sdk' +import chalk from 'chalk' +import path from 'path' + +import { NoSchemaFoundError } from './errors' + +// TODO move NoSchemaFoundError to sdk and this too +// then replace the 2 hardcoded errors to NoSchemaFoundError in +// https://github.com/prisma/prisma/blob/bbdf1c23653a77b0b5bf7d62efd243dcebea018b/packages/sdk/src/cli/getSchema.ts#L383:L383 + +/** + * If a path is provided checks that it exists or error + * If no path provided check in default location(s) or error + * Schema found: print to console it's relative path + * + * @returns {String} schemaPath + */ +export async function getSchemaPathAndPrint(schemaPathProvided?: string, postinstallCwd?: string) { + const cwdOptions = postinstallCwd ? { cwd: postinstallCwd } : undefined + const schemaPath = await getSchemaPath(schemaPathProvided, cwdOptions) + if (!schemaPath) { + // Special case for Generate command + if (postinstallCwd) { + logger.warn(`The postinstall script automatically ran \`prisma generate\` and did not find your \`prisma/schema.prisma\`. +If you have a Prisma schema file in a custom path, you will need to run +\`prisma generate --schema=./path/to/your/schema.prisma\` to generate Prisma Client. +If you do not have a Prisma schema file yet, you can ignore this message.`) + return '' + } + + throw new NoSchemaFoundError() + } + + console.info(chalk.dim(`Prisma schema loaded from ${path.relative(process.cwd(), schemaPath)}`)) + + return schemaPath +} diff --git a/packages/migrate/src/utils/handleEvaluateDataloss.ts b/packages/migrate/src/utils/handleEvaluateDataloss.ts index f737f7f80745..64929b7d3267 100644 --- a/packages/migrate/src/utils/handleEvaluateDataloss.ts +++ b/packages/migrate/src/utils/handleEvaluateDataloss.ts @@ -1,5 +1,6 @@ -import chalk from 'chalk' import { getCommandWithExecutor } from '@prisma/sdk' +import chalk from 'chalk' + import type { MigrationFeedback } from '../types' export function handleUnexecutableSteps(unexecutableSteps: MigrationFeedback[], createOnly = false) { diff --git a/packages/migrate/src/utils/handlePanic.ts b/packages/migrate/src/utils/handlePanic.ts index 203aa8f81896..b427f8ebed0d 100644 --- a/packages/migrate/src/utils/handlePanic.ts +++ b/packages/migrate/src/utils/handlePanic.ts @@ -1,7 +1,8 @@ -import chalk from 'chalk' import type { RustPanic } from '@prisma/sdk' -import { sendPanic, link, isCi } from '@prisma/sdk' +import { isCi, link, sendPanic } from '@prisma/sdk' +import chalk from 'chalk' import prompt from 'prompts' + import { wouldYouLikeToCreateANewIssue } from './getGithubIssueUrl' export async function handlePanic( diff --git a/packages/migrate/src/utils/printDatasource.ts b/packages/migrate/src/utils/printDatasource.ts index 7ef8d912c8cd..fa29634d106e 100644 --- a/packages/migrate/src/utils/printDatasource.ts +++ b/packages/migrate/src/utils/printDatasource.ts @@ -1,6 +1,7 @@ -import { getDbInfo } from '../utils/ensureDatabaseExists' import chalk from 'chalk' +import { getDbInfo } from '../utils/ensureDatabaseExists' + // Datasource "db": SQLite database "dev.db" at "file:./dev.db" // Datasource "my_db": PostgreSQL database "tests-migrate", schema "public" at "localhost:5432" // Datasource "my_db": MySQL database "tests-migrate" at "localhost:5432" @@ -24,7 +25,9 @@ export async function printDatasource(schemaPath: string): Promise { ), ) } - } else { + } else if (dbInfo.name) { console.info(chalk.dim(`Datasource "${dbInfo.name}"`)) + } else { + // Nothing } } diff --git a/packages/migrate/src/utils/printDatasources.ts b/packages/migrate/src/utils/printDatasources.ts index e95983629835..83f586ea1392 100644 --- a/packages/migrate/src/utils/printDatasources.ts +++ b/packages/migrate/src/utils/printDatasources.ts @@ -1,7 +1,14 @@ // This is copied from prisma-client-js/runtime/utils. It needs to be moved into a separate package import indent from 'indent-string' -export type ConnectorType = 'mysql' | 'mongodb' | 'sqlite' | 'postgresql' | 'sqlserver' | 'jdbc:sqlserver' +export type ConnectorType = + | 'mysql' + | 'mongodb' + | 'sqlite' + | 'postgresql' + | 'sqlserver' + | 'jdbc:sqlserver' + | 'cockroachdb' export interface GeneratorConfig { name: string diff --git a/packages/migrate/src/utils/printFiles.ts b/packages/migrate/src/utils/printFiles.ts index 7441aaaacc99..38080f690298 100644 --- a/packages/migrate/src/utils/printFiles.ts +++ b/packages/migrate/src/utils/printFiles.ts @@ -1,5 +1,6 @@ -import type { FileMap } from '../types' import indent from 'indent-string' + +import type { FileMap } from '../types' import { printMigrationId } from './printMigrationId' export function printFiles(printPath: string, files: FileMap): string { diff --git a/packages/migrate/src/utils/promptForMigrationName.ts b/packages/migrate/src/utils/promptForMigrationName.ts index 27a8915e0af0..d4fa3ceac4e1 100644 --- a/packages/migrate/src/utils/promptForMigrationName.ts +++ b/packages/migrate/src/utils/promptForMigrationName.ts @@ -1,6 +1,6 @@ -import { prompt } from 'prompts' import { isCi } from '@prisma/sdk' import slugify from '@sindresorhus/slugify' +import { prompt } from 'prompts' type getMigratioNameOutput = { name?: string diff --git a/packages/migrate/src/utils/seed.ts b/packages/migrate/src/utils/seed.ts index 8fb0d98ec9e1..0bdd753b36ee 100644 --- a/packages/migrate/src/utils/seed.ts +++ b/packages/migrate/src/utils/seed.ts @@ -1,12 +1,12 @@ -import fs from 'fs' -import path from 'path' +import Debug from '@prisma/debug' +import { getPrismaConfigFromPackageJson, link, logger } from '@prisma/sdk' +import chalk from 'chalk' import execa from 'execa' +import fs from 'fs' import hasYarn from 'has-yarn' -import chalk from 'chalk' +import path from 'path' import pkgUp from 'pkg-up' import { promisify } from 'util' -import { getPrismaConfigFromPackageJson, logger, link } from '@prisma/sdk' -import Debug from '@prisma/debug' const debug = Debug('prisma:migrate:seed') const readFileAsync = promisify(fs.readFile) diff --git a/packages/migrate/src/utils/setupMSSQL.ts b/packages/migrate/src/utils/setupMSSQL.ts index c62d2d73d6cc..f361a22af70c 100644 --- a/packages/migrate/src/utils/setupMSSQL.ts +++ b/packages/migrate/src/utils/setupMSSQL.ts @@ -25,7 +25,7 @@ function getMSSQLConfig(url: string): mssql.config { } } -export async function setupMSSQL(options: SetupParams): Promise { +export async function setupMSSQL(options: SetupParams, databaseName: string): Promise { const { connectionString } = options const { dirname } = options const config = getMSSQLConfig(connectionString) @@ -34,15 +34,15 @@ export async function setupMSSQL(options: SetupParams): Promise { try { await connection.query(` - CREATE DATABASE [tests-migrate-shadowdb] - CREATE DATABASE [tests-migrate] - `) +CREATE DATABASE [${databaseName}-shadowdb] +CREATE DATABASE [${databaseName}] +`) } catch (e) { console.warn(e) } if (dirname !== '') { - let schema = 'USE [tests-migrate]\n' + let schema = `USE [${databaseName}]\n` schema += fs.readFileSync(path.join(dirname, 'setup.sql'), 'utf-8') await connection.query(schema) } @@ -50,15 +50,15 @@ export async function setupMSSQL(options: SetupParams): Promise { await connection.close() } -export async function tearDownMSSQL(options: SetupParams) { +export async function tearDownMSSQL(options: SetupParams, databaseName: string) { const { connectionString } = options const config = getMSSQLConfig(connectionString) const connectionPool = new mssql.ConnectionPool(config) const connection = await connectionPool.connect() await connection.query(` - DROP DATABASE IF EXISTS "tests-migrate-shadowdb"; - DROP DATABASE IF EXISTS "tests-migrate"; +DROP DATABASE IF EXISTS "${databaseName}-shadowdb"; +DROP DATABASE IF EXISTS "${databaseName}"; `) await connection.close() } diff --git a/packages/migrate/src/utils/setupMysql.ts b/packages/migrate/src/utils/setupMysql.ts index 4c03e8448aa0..96ea836f784e 100644 --- a/packages/migrate/src/utils/setupMysql.ts +++ b/packages/migrate/src/utils/setupMysql.ts @@ -1,7 +1,7 @@ +import { uriToCredentials } from '@prisma/sdk' import fs from 'fs' -import path from 'path' -import { createDatabase, uriToCredentials } from '@prisma/sdk' import mariadb from 'mariadb' +import path from 'path' export type SetupParams = { connectionString: string @@ -13,27 +13,33 @@ export async function setupMysql(options: SetupParams): Promise { const { dirname } = options const credentials = uriToCredentials(connectionString) - let schema = ` - CREATE DATABASE IF NOT EXISTS \`tests-migrate-shadowdb\`; - CREATE DATABASE IF NOT EXISTS \`${credentials.database}\`; - ` - if (dirname !== '') { - schema += fs.readFileSync(path.join(dirname, 'setup.sql'), 'utf-8') - } - - await createDatabase(connectionString).catch((e) => console.error(e)) - - const db = await mariadb.createConnection({ + // Connect to default db + const dbDefault = await mariadb.createConnection({ host: credentials.host, port: credentials.port, - database: credentials.database, + // database: credentials.database, // use the default db user: credentials.user, password: credentials.password, multipleStatements: true, }) + await dbDefault.query(` +CREATE DATABASE IF NOT EXISTS \`${credentials.database}-shadowdb\`; +CREATE DATABASE IF NOT EXISTS \`${credentials.database}\`; +`) + await dbDefault.end() - await db.query(schema) - await db.end() + if (dirname !== '') { + const db = await mariadb.createConnection({ + host: credentials.host, + port: credentials.port, + database: credentials.database, // use final db + user: credentials.user, + password: credentials.password, + multipleStatements: true, + }) + await db.query(fs.readFileSync(path.join(dirname, 'setup.sql'), 'utf-8')) + await db.end() + } } export async function tearDownMysql(options: SetupParams) { diff --git a/packages/migrate/src/utils/setupPostgres.ts b/packages/migrate/src/utils/setupPostgres.ts index 5ae2e85f7e95..1bdcbf91789f 100644 --- a/packages/migrate/src/utils/setupPostgres.ts +++ b/packages/migrate/src/utils/setupPostgres.ts @@ -1,6 +1,6 @@ +import { credentialsToUri, uriToCredentials } from '@prisma/sdk' import fs from 'fs' import path from 'path' -import { createDatabase, uriToCredentials, credentialsToUri } from '@prisma/sdk' import { Client } from 'pg' export type SetupParams = { @@ -13,23 +13,26 @@ export async function setupPostgres(options: SetupParams): Promise { const { dirname } = options const credentials = uriToCredentials(connectionString) - let schema = ` - SELECT 'CREATE DATABASE tests-migrate-shadowdb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'tests-migrate-shadowdb'); - SELECT 'CREATE DATABASE ${credentials.database}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${credentials.database}'); - ` - if (dirname !== '') { - schema += fs.readFileSync(path.join(dirname, 'setup.sql'), 'utf-8') - } - - await createDatabase(connectionString).catch((e) => console.error(e)) - - const db = new Client({ - connectionString: connectionString, + // Connect to default db + const dbDefault = new Client({ + connectionString: connectionString.replace(credentials.database!, 'postgres'), }) + await dbDefault.connect() + await dbDefault.query(`DROP DATABASE IF EXISTS "${credentials.database}-shadowdb";`) + await dbDefault.query(`CREATE DATABASE "${credentials.database}-shadowdb";`) + await dbDefault.query(`DROP DATABASE IF EXISTS "${credentials.database}";`) + await dbDefault.query(`CREATE DATABASE "${credentials.database}";`) + await dbDefault.end() - await db.connect() - await db.query(schema) - await db.end() + if (dirname !== '') { + // Connect to final db and populate + const db = new Client({ + connectionString: connectionString, + }) + await db.connect() + await db.query(fs.readFileSync(path.join(dirname, 'setup.sql'), 'utf-8')) + await db.end() + } } export async function tearDownPostgres(options: SetupParams) { diff --git a/packages/migrate/src/utils/test-handlePanic.ts b/packages/migrate/src/utils/test-handlePanic.ts index fafa23282d77..d76d8394a26c 100644 --- a/packages/migrate/src/utils/test-handlePanic.ts +++ b/packages/migrate/src/utils/test-handlePanic.ts @@ -1,10 +1,9 @@ -import { RustPanic, ErrorArea } from '@prisma/sdk' -import { handlePanic } from '../utils/handlePanic' +import { ErrorArea, RustPanic } from '@prisma/sdk' import path from 'path' -async function main() { - // process.env.GITHUB_ACTIONS = 'maybe' +import { handlePanic } from '../utils/handlePanic' +async function main() { const error = new RustPanic( 'Some error message!\n'.repeat(23), '', diff --git a/packages/migrate/tsconfig.eslint.json b/packages/migrate/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/migrate/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/react-prisma/.eslintignore b/packages/react-prisma/.eslintignore deleted file mode 100644 index 76add878f8dd..000000000000 --- a/packages/react-prisma/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist \ No newline at end of file diff --git a/packages/react-prisma/.eslintrc.js b/packages/react-prisma/.eslintrc.js deleted file mode 100644 index 77529fcfc003..000000000000 --- a/packages/react-prisma/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) - -module.exports = config diff --git a/packages/react-prisma/jest.config.js b/packages/react-prisma/jest.config.js index 90066d6b0b74..1376a7a2e051 100644 --- a/packages/react-prisma/jest.config.js +++ b/packages/react-prisma/jest.config.js @@ -1,9 +1,21 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', + testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], - testMatch: ['**/src/__tests__/**/*.test.ts'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/react-prisma/package.json b/packages/react-prisma/package.json index 159511f21cfb..27d5f82ca9c2 100644 --- a/packages/react-prisma/package.json +++ b/packages/react-prisma/package.json @@ -2,7 +2,7 @@ "name": "react-prisma", "version": "0.0.5", "main": "dist/index.js", - "module": "dist/esm/index.mjs", + "module": "esm/dist/index.mjs", "types": "dist/index.d.ts", "license": "Apache-2.0", "author": "Tim Suchanek ", @@ -18,44 +18,25 @@ "homepage": "https://www.prisma.io", "devDependencies": { "@prisma/client": "workspace:*", - "@types/jest": "27.4.0", - "@types/node": "16.11.19", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", - "esbuild": "0.14.10", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", - "prettier": "2.5.1", + "@types/jest": "27.4.1", + "@types/node": "16.11.26", + "esbuild": "0.14.27", + "jest": "27.5.1", + "jest-junit": "13.0.0", "react": "17.0.2", - "ts-jest": "27.1.2", - "typescript": "4.5.4" + "ts-jest": "27.1.3", + "typescript": "4.6.2" }, "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", "prepublishOnly": "pnpm run build", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", - "test": "echo \"not yet\"", - "precommit": "lint-staged" + "test": "echo \"not yet\"" }, "files": [ "README.md", "dist" ], - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] - }, "peerDependencies": { "@prisma/client": "*", "react": "^17.0.0" diff --git a/packages/react-prisma/src/index.ts b/packages/react-prisma/src/index.ts index bb9a9825ae13..4028417b8603 100644 --- a/packages/react-prisma/src/index.ts +++ b/packages/react-prisma/src/index.ts @@ -1,7 +1,8 @@ import type { Wakeable } from 'react' import { unstable_getCacheForType } from 'react' + // @ts-ignore -import { PrismaClient as PrismaClientConstructor, dmmf } from '.prisma/client' +import { dmmf, PrismaClient as PrismaClientConstructor } from '.prisma/client' enum STATUS { Pending, diff --git a/packages/react-prisma/tsconfig.eslint.json b/packages/react-prisma/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/react-prisma/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/packages/sdk/.eslintignore b/packages/sdk/.eslintignore deleted file mode 100644 index 0960b933d1dd..000000000000 --- a/packages/sdk/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -/dist -src/utils/byline.ts -src/highlight/prism.ts \ No newline at end of file diff --git a/packages/sdk/.eslintrc.js b/packages/sdk/.eslintrc.js deleted file mode 100644 index 918e4dc27d51..000000000000 --- a/packages/sdk/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -const path = require('path') -const config = require('../../.eslintrc.js') - -config.parserOptions.project.push(path.join(__dirname, 'tsconfig.eslint.json')) -module.exports = config diff --git a/packages/sdk/jest.config.js b/packages/sdk/jest.config.js index aeafe4757a4e..65b60ccfe3dd 100644 --- a/packages/sdk/jest.config.js +++ b/packages/sdk/jest.config.js @@ -1,9 +1,24 @@ module.exports = { - preset: 'ts-jest', + transform: { + '^.+\\.ts$': '@swc/jest', + }, testEnvironment: 'node', testMatch: ['**/src/__tests__/**/*.test.ts'], collectCoverage: process.env.CI ? true : false, coverageReporters: ['clover'], coverageDirectory: 'src/__tests__/coverage', collectCoverageFrom: ['src/**/*.ts', '!**/__tests__/**/*'], + // snapshotSerializers: ['./src/utils/jestSnapshotSerializer'], + reporters: [ + 'default', + [ + 'jest-junit', + { + addFileAttribute: 'true', + ancestorSeparator: ' › ', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + }, + ], + ], } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 304dc733f9e4..f6e48594c657 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -2,7 +2,7 @@ "name": "@prisma/sdk", "version": "0.0.0", "main": "dist/index.js", - "module": "dist/esm/index.mjs", + "module": "esm/dist/index.mjs", "types": "dist/index.d.ts", "repository": { "type": "git", @@ -21,13 +21,8 @@ "scripts": { "dev": "DEV=true node -r esbuild-register helpers/build.ts", "build": "node -r esbuild-register helpers/build.ts", - "depcheck": "node -r esbuild-register ../../helpers/compile/depcheck.ts", - "prepublishOnly": "pnpm run build && pnpm run test", - "format": "prettier --write .", - "lint": "eslint --cache --fix --ext .ts .", - "lint-ci": "eslint --ext .ts .", - "test": "jest --verbose", - "precommit": "lint-staged" + "prepublishOnly": "pnpm run build", + "test": "jest --verbose" }, "files": [ "README.md", @@ -35,52 +30,47 @@ "scripts" ], "devDependencies": { - "@types/jest": "27.4.0", - "@types/node": "12.20.39", + "@swc/core": "1.2.141", + "@swc/jest": "0.2.17", + "@types/jest": "27.4.1", + "@types/node": "12.20.47", "@types/resolve": "1.20.1", "@types/shell-quote": "1.7.1", "@types/tar": "6.1.1", - "@typescript-eslint/eslint-plugin": "5.9.0", - "@typescript-eslint/parser": "5.9.0", "esbuild": "0.13.14", - "eslint": "8.6.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-eslint-comments": "3.2.0", - "eslint-plugin-jest": "25.3.4", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.4.6", - "lint-staged": "12.1.5", - "prettier": "2.5.1", - "ts-jest": "27.1.2", + "jest": "27.5.1", + "jest-junit": "13.0.0", "ts-node": "10.4.0", "typescript": "4.5.4" }, "dependencies": { "@prisma/debug": "workspace:*", "@prisma/engine-core": "workspace:*", - "@prisma/engines": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", - "@prisma/fetch-engine": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/engines": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", + "@prisma/fetch-engine": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@prisma/generator-helper": "workspace:*", - "@prisma/get-platform": "3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908", + "@prisma/get-platform": "3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77", "@timsuchanek/copy": "1.4.5", "archiver": "5.3.0", "arg": "5.0.1", "chalk": "4.1.2", - "checkpoint-client": "1.1.20", + "checkpoint-client": "1.1.21", "cli-truncate": "2.1.0", - "dotenv": "10.0.0", + "dotenv": "16.0.0", "escape-string-regexp": "4.0.0", "execa": "5.1.1", "find-up": "5.0.0", + "fs-jetpack": "4.3.1", "global-dirs": "3.0.0", - "globby": "11.0.4", + "globby": "11.1.0", "has-yarn": "2.1.0", "is-ci": "3.0.1", "make-dir": "3.1.0", - "node-fetch": "2.6.6", + "node-fetch": "2.6.7", "p-map": "4.0.0", "read-pkg-up": "7.0.1", - "resolve": "1.20.0", + "replace-string": "3.1.0", + "resolve": "1.22.0", "rimraf": "3.0.2", "shell-quote": "1.7.3", "string-width": "4.2.3", @@ -93,11 +83,5 @@ "terminal-link": "2.1.1", "tmp": "0.2.1" }, - "lint-staged": { - "*.ts": [ - "eslint", - "prettier --write" - ] - }, "sideEffects": false } diff --git a/packages/sdk/scripts/updateTag.js b/packages/sdk/scripts/updateTag.js index 9de891245daf..c2e903112416 100644 --- a/packages/sdk/scripts/updateTag.js +++ b/packages/sdk/scripts/updateTag.js @@ -11,10 +11,7 @@ async function main() { console.log('Updated local engines version to', tag) pkg.prisma = pkg.prisma || {} pkg.prisma.version = tag - fs.writeFileSync( - path.join(__dirname, '../package.json'), - JSON.stringify(pkg, null, 2), - ) + fs.writeFileSync(path.join(__dirname, '../package.json'), JSON.stringify(pkg, null, 2)) } main() diff --git a/packages/sdk/src/Generator.ts b/packages/sdk/src/Generator.ts index 11a4b16b16cc..013af12a1541 100644 --- a/packages/sdk/src/Generator.ts +++ b/packages/sdk/src/Generator.ts @@ -1,5 +1,6 @@ import type { BinaryPaths, GeneratorConfig, GeneratorManifest, GeneratorOptions } from '@prisma/generator-helper' import { GeneratorProcess } from '@prisma/generator-helper' + import { parseEnvValue } from './utils/parseEnvValue' export class Generator { diff --git a/packages/sdk/src/IntrospectionEngine.ts b/packages/sdk/src/IntrospectionEngine.ts index 2d70ef2bafce..2cfdaa0c997d 100644 --- a/packages/sdk/src/IntrospectionEngine.ts +++ b/packages/sdk/src/IntrospectionEngine.ts @@ -3,9 +3,11 @@ import { BinaryType } from '@prisma/fetch-engine' import chalk from 'chalk' import type { ChildProcess } from 'child_process' import { spawn } from 'child_process' + import { ErrorArea, RustPanic } from './panic' import { resolveBinary } from './resolveBinary' import byline from './utils/byline' + const debugCli = Debug('prisma:introspectionEngine:cli') const debugRpc = Debug('prisma:introspectionEngine:rpc') const debugStderr = Debug('prisma:introspectionEngine:stderr') @@ -43,8 +45,8 @@ export class IntrospectionError extends Error { } // See prisma-engines -// SQL https://github.com/prisma/prisma-engines/blob/master/introspection-engine/connectors/sql-introspection-connector/src/warnings.rs -// Mongo https://github.com/prisma/prisma-engines/blob/master/introspection-engine/connectors/mongodb-introspection-connector/src/warnings.rs +// SQL https://github.com/prisma/prisma-engines/blob/main/introspection-engine/connectors/sql-introspection-connector/src/warnings.rs +// Mongo https://github.com/prisma/prisma-engines/blob/main/introspection-engine/connectors/mongodb-introspection-connector/src/warnings.rs export type IntrospectionWarnings = | IntrospectionWarningsUnhandled | IntrospectionWarningsInvalidReintro @@ -61,32 +63,54 @@ export type IntrospectionWarnings = | IntrospectionWarningsCuidReintro | IntrospectionWarningsUuidReintro | IntrospectionWarningsUpdatedAtReintro + | IntrospectionWarningsWithoutColumns + | IntrospectionWarningsModelsWithIgnoreReintro + | IntrospectionWarningsFieldsWithIgnoreReintro + | IntrospectionWarningsCustomIndexNameReintro + | IntrospectionWarningsCustomPrimaryKeyNamesReintro + | IntrospectionWarningsRelationsReintro | IntrospectionWarningsMongoMultipleTypes + | IntrospectionWarningsMongoFieldsPointingToAnEmptyType + | IntrospectionWarningsMongoFieldsWithUnkownTypes + | IntrospectionWarningsMongoFieldsWithEmptyNames -type AffectedModel = { model: string }[] -type AffectedModelAndField = { model: string; field: string }[] +type AffectedModel = { model: string } +type AffectedModelAndIndex = { model: string; index_db_name: string } +type AffectedModelAndField = { model: string; field: string } type AffectedModelAndFieldAndType = { model: string field: string tpe: string -}[] -type AffectedEnum = { enm: string }[] -type AffectedEnumAndValue = { enm: string; value: string }[] +} +type AffectedModelOrCompositeTypeAndField = { + // Either compositeType or model is defined + compositeType?: string + model?: string + field: string +} +type AffectedModelOrCompositeTypeAndFieldAndType = AffectedModelOrCompositeTypeAndField & { + tpe: string +} +type AffectedEnum = { enm: string } +type AffectedEnumAndValue = { enm: string; value: string } interface IntrospectionWarning { code: number message: string affected: - | AffectedModel - | AffectedModelAndField - | AffectedModelAndFieldAndType - | AffectedEnum - | AffectedEnumAndValue + | AffectedModel[] + | AffectedModelAndIndex[] + | AffectedModelAndField[] + | AffectedModelAndFieldAndType[] + | AffectedModelOrCompositeTypeAndField[] + | AffectedModelOrCompositeTypeAndFieldAndType[] + | AffectedEnum[] + | AffectedEnumAndValue[] | null } interface IntrospectionWarningsUnhandled extends IntrospectionWarning { - code: number + code: -1 // -1 doesn't exist, it's just for the types affected: any } interface IntrospectionWarningsInvalidReintro extends IntrospectionWarning { @@ -95,73 +119,104 @@ interface IntrospectionWarningsInvalidReintro extends IntrospectionWarning { } interface IntrospectionWarningsMissingUnique extends IntrospectionWarning { code: 1 - affected: AffectedModel + affected: AffectedModel[] } interface IntrospectionWarningsEmptyFieldName extends IntrospectionWarning { code: 2 - affected: AffectedModelAndField + affected: AffectedModelAndField[] } interface IntrospectionWarningsUnsupportedType extends IntrospectionWarning { code: 3 - affected: AffectedModelAndFieldAndType + affected: AffectedModelAndFieldAndType[] } interface IntrospectionWarningsInvalidEnumName extends IntrospectionWarning { code: 4 - affected: AffectedEnumAndValue + affected: AffectedEnumAndValue[] } interface IntrospectionWarningsCuidPrisma1 extends IntrospectionWarning { code: 5 - affected: AffectedModelAndField + affected: AffectedModelAndField[] } interface IntrospectionWarningsUuidPrisma1 extends IntrospectionWarning { code: 6 - affected: AffectedModelAndField + affected: AffectedModelAndField[] } interface IntrospectionWarningsFieldModelReintro extends IntrospectionWarning { code: 7 - affected: AffectedModel + affected: AffectedModel[] } interface IntrospectionWarningsFieldMapReintro extends IntrospectionWarning { code: 8 - affected: AffectedModelAndField + affected: AffectedModelAndField[] } interface IntrospectionWarningsEnumMapReintro extends IntrospectionWarning { code: 9 - affected: AffectedEnum + affected: AffectedEnum[] } interface IntrospectionWarningsEnumValueMapReintro extends IntrospectionWarning { code: 10 - affected: AffectedEnum + affected: AffectedEnum[] } interface IntrospectionWarningsCuidReintro extends IntrospectionWarning { code: 11 - affected: AffectedModelAndField + affected: AffectedModelAndField[] } interface IntrospectionWarningsUuidReintro extends IntrospectionWarning { code: 12 - affected: AffectedModelAndField + affected: AffectedModelAndField[] } interface IntrospectionWarningsUpdatedAtReintro extends IntrospectionWarning { code: 13 - affected: AffectedModelAndField + affected: AffectedModelAndField[] +} +interface IntrospectionWarningsWithoutColumns extends IntrospectionWarning { + code: 14 + affected: AffectedModel[] +} +interface IntrospectionWarningsModelsWithIgnoreReintro extends IntrospectionWarning { + code: 15 + affected: AffectedModel[] +} +interface IntrospectionWarningsFieldsWithIgnoreReintro extends IntrospectionWarning { + code: 16 + affected: AffectedModelAndField[] +} +interface IntrospectionWarningsCustomIndexNameReintro extends IntrospectionWarning { + code: 17 + affected: AffectedModelAndIndex[] +} +interface IntrospectionWarningsCustomPrimaryKeyNamesReintro extends IntrospectionWarning { + code: 18 + affected: AffectedModel[] +} +interface IntrospectionWarningsRelationsReintro extends IntrospectionWarning { + code: 19 + affected: AffectedModel[] } // MongoDB starts at 101 see -// https://github.com/prisma/prisma-engines/blob/master/introspection-engine/connectors/mongodb-introspection-connector/src/warnings.rs#L39-L43 +// https://github.com/prisma/prisma-engines/blob/main/introspection-engine/connectors/mongodb-introspection-connector/src/warnings.rs#L39-L43 interface IntrospectionWarningsMongoMultipleTypes extends IntrospectionWarning { code: 101 - // TODO delete name and replace by affected when done in - // https://github.com/prisma/prisma-engines/blob/9649bb31b5d544122adb9ad21d40d9d1ae1448e6/introspection-engine/connectors/mongodb-introspection-connector/src/warnings.rs#L42 - // and adjust https://github.com/prisma/prisma/blob/main/packages/migrate/src/commands/DbPull.ts#L230 - name: [affected: AffectedModelAndFieldAndType] - // affected: AffectedModelAndFieldAndType + affected: AffectedModelOrCompositeTypeAndFieldAndType[] +} +interface IntrospectionWarningsMongoFieldsPointingToAnEmptyType extends IntrospectionWarning { + code: 102 + affected: AffectedModelOrCompositeTypeAndField[] +} +interface IntrospectionWarningsMongoFieldsWithUnkownTypes extends IntrospectionWarning { + code: 103 + affected: AffectedModelOrCompositeTypeAndField[] +} +interface IntrospectionWarningsMongoFieldsWithEmptyNames extends IntrospectionWarning { + code: 104 + affected: AffectedModelOrCompositeTypeAndField[] } export type IntrospectionSchemaVersion = 'Prisma2' | 'Prisma1' | 'Prisma11' | 'NonPrisma' let messageId = 1 -/* tslint:disable */ export class IntrospectionEngine { private debug: boolean private cwd: string @@ -209,7 +264,7 @@ export class IntrospectionEngine { public introspect( schema: string, force?: Boolean, - compositeTypeDepth?: number, // optional, only for mongodb + compositeTypeDepth = -1, // optional, only for mongodb ): Promise<{ datamodel: string warnings: IntrospectionWarnings[] diff --git a/packages/sdk/src/__tests__/__utils__/fixtures.ts b/packages/sdk/src/__tests__/__utils__/fixtures.ts index 63a72bfd0c7c..f2778b532c3a 100644 --- a/packages/sdk/src/__tests__/__utils__/fixtures.ts +++ b/packages/sdk/src/__tests__/__utils__/fixtures.ts @@ -1,2 +1,3 @@ import path from 'path' + export const fixturesPath = path.join(__dirname, '../__fixtures__/') diff --git a/packages/sdk/src/__tests__/convertCredentials.test.ts b/packages/sdk/src/__tests__/convertCredentials.test.ts index 46d97666817a..8a0ca6493a54 100644 --- a/packages/sdk/src/__tests__/convertCredentials.test.ts +++ b/packages/sdk/src/__tests__/convertCredentials.test.ts @@ -1,4 +1,4 @@ -import { uriToCredentials, credentialsToUri } from '../convertCredentials' +import { credentialsToUri, uriToCredentials } from '../convertCredentials' const uris = [ 'file:', diff --git a/packages/sdk/src/__tests__/dotenvExpand.test.ts b/packages/sdk/src/__tests__/dotenvExpand.test.ts index 98bb7e850bfb..1005b89998a5 100644 --- a/packages/sdk/src/__tests__/dotenvExpand.test.ts +++ b/packages/sdk/src/__tests__/dotenvExpand.test.ts @@ -1,5 +1,6 @@ -import { dotenvExpand } from '../dotenvExpand' import path from 'path' + +import { dotenvExpand } from '../dotenvExpand' import { fixturesPath } from './__utils__/fixtures' describe('dotenvExpand', () => { diff --git a/packages/sdk/src/__tests__/engine-commands/__snapshots__/getDmmf.test.ts.snap b/packages/sdk/src/__tests__/engine-commands/__snapshots__/getDmmf.test.ts.snap index 8874a65305eb..57d2f3854bb3 100644 --- a/packages/sdk/src/__tests__/engine-commands/__snapshots__/getDmmf.test.ts.snap +++ b/packages/sdk/src/__tests__/engine-commands/__snapshots__/getDmmf.test.ts.snap @@ -153,6 +153,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -6662,6 +6663,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -6711,6 +6713,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -10383,6 +10386,7 @@ Object { ], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -12369,38 +12373,38 @@ Object { "inputTypes": Array [ Object { "isList": false, - "location": "scalar", - "type": "String", + "location": "inputObjectTypes", + "namespace": "prisma", + "type": "UserCreateNestedOneWithoutPostsInput", }, ], "isNullable": false, "isRequired": true, - "name": "title", + "name": "author", }, Object { "inputTypes": Array [ Object { "isList": false, "location": "scalar", - "type": "Boolean", + "type": "String", }, ], "isNullable": false, - "isRequired": false, - "name": "published", + "isRequired": true, + "name": "title", }, Object { "inputTypes": Array [ Object { "isList": false, - "location": "inputObjectTypes", - "namespace": "prisma", - "type": "UserCreateNestedOneWithoutPostsInput", + "location": "scalar", + "type": "Boolean", }, ], "isNullable": false, - "isRequired": true, - "name": "author", + "isRequired": false, + "name": "published", }, ], "name": "PostCreateInput", @@ -12488,52 +12492,52 @@ Object { }, Object { "inputTypes": Array [ - Object { - "isList": false, - "location": "scalar", - "type": "String", - }, Object { "isList": false, "location": "inputObjectTypes", "namespace": "prisma", - "type": "StringFieldUpdateOperationsInput", + "type": "UserUpdateOneRequiredWithoutPostsInput", }, ], "isNullable": false, "isRequired": false, - "name": "title", + "name": "author", }, Object { "inputTypes": Array [ Object { "isList": false, "location": "scalar", - "type": "Boolean", + "type": "String", }, Object { "isList": false, "location": "inputObjectTypes", "namespace": "prisma", - "type": "BoolFieldUpdateOperationsInput", + "type": "StringFieldUpdateOperationsInput", }, ], "isNullable": false, "isRequired": false, - "name": "published", + "name": "title", }, Object { "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "Boolean", + }, Object { "isList": false, "location": "inputObjectTypes", "namespace": "prisma", - "type": "UserUpdateOneRequiredWithoutPostsInput", + "type": "BoolFieldUpdateOperationsInput", }, ], "isNullable": false, "isRequired": false, - "name": "author", + "name": "published", }, ], "name": "PostUpdateInput", @@ -16051,48 +16055,6 @@ Object { ], "name": "IntFieldUpdateOperationsInput", }, - Object { - "constraints": Object { - "maxNumFields": 1, - "minNumFields": 1, - }, - "fields": Array [ - Object { - "inputTypes": Array [ - Object { - "isList": false, - "location": "scalar", - "type": "String", - }, - ], - "isNullable": false, - "isRequired": false, - "name": "set", - }, - ], - "name": "StringFieldUpdateOperationsInput", - }, - Object { - "constraints": Object { - "maxNumFields": 1, - "minNumFields": 1, - }, - "fields": Array [ - Object { - "inputTypes": Array [ - Object { - "isList": false, - "location": "scalar", - "type": "Boolean", - }, - ], - "isNullable": false, - "isRequired": false, - "name": "set", - }, - ], - "name": "BoolFieldUpdateOperationsInput", - }, Object { "constraints": Object { "maxNumFields": null, @@ -16179,6 +16141,48 @@ Object { ], "name": "UserUpdateOneRequiredWithoutPostsInput", }, + Object { + "constraints": Object { + "maxNumFields": 1, + "minNumFields": 1, + }, + "fields": Array [ + Object { + "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "String", + }, + ], + "isNullable": false, + "isRequired": false, + "name": "set", + }, + ], + "name": "StringFieldUpdateOperationsInput", + }, + Object { + "constraints": Object { + "maxNumFields": 1, + "minNumFields": 1, + }, + "fields": Array [ + Object { + "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "Boolean", + }, + ], + "isNullable": false, + "isRequired": false, + "name": "set", + }, + ], + "name": "BoolFieldUpdateOperationsInput", + }, Object { "constraints": Object { "maxNumFields": null, @@ -22874,9 +22878,9 @@ Object { } `; -exports[`getDMMF big schema 1`] = `132028282`; +exports[`getDMMF big schema 1`] = `132028293`; -exports[`getDMMF chinook introspected schema 1`] = `883923`; +exports[`getDMMF chinook introspected schema 1`] = `883934`; exports[`getDMMF model with autoincrement should fail if mysql 1`] = ` "Schema parsing @@ -22952,6 +22956,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -22997,17 +23002,20 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ Object { "aggregate": "aggregateA", + "aggregateRaw": "aggregateARaw", "createMany": "createManyA", "createOne": "createOneA", "deleteMany": "deleteManyA", "deleteOne": "deleteOneA", "findFirst": "findFirstA", "findMany": "findManyA", + "findRaw": "findARaw", "findUnique": "findUniqueA", "groupBy": "groupByA", "model": "A", @@ -23018,7 +23026,9 @@ Object { ], "otherOperations": Object { "read": Array [], - "write": Array [], + "write": Array [ + "runCommandRaw", + ], }, }, "schema": Object { @@ -25578,6 +25588,76 @@ Object { "type": "A", }, }, + Object { + "args": Array [ + Object { + "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + ], + "isNullable": false, + "isRequired": false, + "name": "filter", + }, + Object { + "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + ], + "isNullable": false, + "isRequired": false, + "name": "options", + }, + ], + "isNullable": false, + "name": "findARaw", + "outputType": Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + }, + Object { + "args": Array [ + Object { + "inputTypes": Array [ + Object { + "isList": true, + "location": "scalar", + "type": "Json", + }, + ], + "isNullable": false, + "isRequired": false, + "name": "pipeline", + }, + Object { + "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + ], + "isNullable": false, + "isRequired": false, + "name": "options", + }, + ], + "isNullable": false, + "name": "aggregateARaw", + "outputType": Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + }, ], "name": "Query", }, @@ -25840,6 +25920,29 @@ Object { "type": "AffectedRowsOutput", }, }, + Object { + "args": Array [ + Object { + "inputTypes": Array [ + Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + ], + "isNullable": false, + "isRequired": true, + "name": "command", + }, + ], + "isNullable": false, + "name": "runCommandRaw", + "outputType": Object { + "isList": false, + "location": "scalar", + "type": "Json", + }, + }, ], "name": "Mutation", }, @@ -26160,6 +26263,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -26205,6 +26309,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -29561,6 +29666,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -29606,6 +29712,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -32677,6 +32784,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -32722,6 +32830,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -36111,6 +36220,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -36156,6 +36266,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ @@ -39500,6 +39611,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], } `; @@ -39545,6 +39657,7 @@ Object { "uniqueIndexes": Array [], }, ], + "types": Array [], }, "mappings": Object { "modelOperations": Array [ diff --git a/packages/sdk/src/__tests__/engine-commands/formatSchema.test.ts b/packages/sdk/src/__tests__/engine-commands/formatSchema.test.ts index b680ef300832..7eb0491ab0ce 100644 --- a/packages/sdk/src/__tests__/engine-commands/formatSchema.test.ts +++ b/packages/sdk/src/__tests__/engine-commands/formatSchema.test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { formatSchema } from '../..' import { fixturesPath } from '../__utils__/fixtures' diff --git a/packages/sdk/src/__tests__/engine-commands/getConfig.test.ts b/packages/sdk/src/__tests__/engine-commands/getConfig.test.ts index 315935941351..91739ff22604 100644 --- a/packages/sdk/src/__tests__/engine-commands/getConfig.test.ts +++ b/packages/sdk/src/__tests__/engine-commands/getConfig.test.ts @@ -1,4 +1,5 @@ import stripAnsi from 'strip-ansi' + import { getConfig } from '../..' describe('getConfig', () => { diff --git a/packages/sdk/src/__tests__/engine-commands/getDmmf.test.ts b/packages/sdk/src/__tests__/engine-commands/getDmmf.test.ts index 397ce5b4b768..7cf0fa6f9c8d 100644 --- a/packages/sdk/src/__tests__/engine-commands/getDmmf.test.ts +++ b/packages/sdk/src/__tests__/engine-commands/getDmmf.test.ts @@ -1,6 +1,7 @@ import fs from 'fs' import path from 'path' import stripAnsi from 'strip-ansi' + import { getDMMF } from '../..' import { fixturesPath } from '../__utils__/fixtures' diff --git a/packages/sdk/src/__tests__/engine-commands/getVersion.test.ts b/packages/sdk/src/__tests__/engine-commands/getVersion.test.ts index c395f1f46a11..d8518b1f262d 100644 --- a/packages/sdk/src/__tests__/engine-commands/getVersion.test.ts +++ b/packages/sdk/src/__tests__/engine-commands/getVersion.test.ts @@ -1,4 +1,5 @@ import { enginesVersion, getCliQueryEngineBinaryType } from '@prisma/engines' + import { BinaryType, getVersion } from '../..' const testIf = (condition: boolean) => (condition ? test : test.skip) diff --git a/packages/sdk/src/__tests__/getGenerators/getGenerators.test.ts b/packages/sdk/src/__tests__/getGenerators/getGenerators.test.ts index d61704179f35..1b9451819f0e 100644 --- a/packages/sdk/src/__tests__/getGenerators/getGenerators.test.ts +++ b/packages/sdk/src/__tests__/getGenerators/getGenerators.test.ts @@ -3,10 +3,14 @@ import { BinaryType } from '@prisma/fetch-engine' import { getPlatform } from '@prisma/get-platform' import path from 'path' import stripAnsi from 'strip-ansi' + import { getGenerators } from '../../get-generators/getGenerators' -import { omit } from '../../omit' -import { pick } from '../../pick' import { resolveBinary } from '../../resolveBinary' +import { jestConsoleContext, jestContext } from '../../utils/jestContext' +import { omit } from '../../utils/omit' +import { pick } from '../../utils/pick' + +const ctx = jestContext.new().add(jestConsoleContext()).assemble() jest.setTimeout(20000) @@ -184,6 +188,11 @@ describe('getGenerators', () => { } `) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + generators.forEach((g) => g.stop()) }) @@ -269,6 +278,11 @@ describe('getGenerators', () => { } `) + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + generators.forEach((g) => g.stop()) }) @@ -288,20 +302,20 @@ describe('getGenerators', () => { }) expect(generators.map((g) => g.manifest)).toMatchInlineSnapshot(` - Array [ - Object { - "defaultOutput": "default-output", - "denylist": Array [ - "SomeForbiddenType", - ], - "prettyName": "This is a pretty pretty name", - "requiresEngines": Array [ - "queryEngine", - "migrationEngine", - ], - }, - ] - `) + Array [ + Object { + "defaultOutput": "default-output", + "denylist": Array [ + "SomeForbiddenType", + ], + "prettyName": "This is a pretty pretty name", + "requiresEngines": Array [ + "queryEngine", + "migrationEngine", + ], + }, + ] + `) expect(pick(generators[0].options!, ['datamodel', 'datasources', 'otherGenerators'])).toMatchInlineSnapshot(` Object { @@ -343,16 +357,21 @@ describe('getGenerators', () => { expect(generator.binaryTargets[0].fromEnvVar).toEqual('BINARY_TARGETS_ENV_VAR_TEST') expect(omit(generator, ['binaryTargets'])).toMatchInlineSnapshot(` - Object { - "config": Object {}, - "name": "gen_env", - "previewFeatures": Array [], - "provider": Object { - "fromEnvVar": null, - "value": "predefined-generator", - }, - } - `) + Object { + "config": Object {}, + "name": "gen_env", + "previewFeatures": Array [], + "provider": Object { + "fromEnvVar": null, + "value": "predefined-generator", + }, + } + `) + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) generators.forEach((g) => g.stop()) }) @@ -373,20 +392,20 @@ describe('getGenerators', () => { }) expect(generators.map((g) => g.manifest)).toMatchInlineSnapshot(` - Array [ - Object { - "defaultOutput": "default-output", - "denylist": Array [ - "SomeForbiddenType", - ], - "prettyName": "This is a pretty pretty name", - "requiresEngines": Array [ - "queryEngine", - "migrationEngine", - ], - }, - ] - `) + Array [ + Object { + "defaultOutput": "default-output", + "denylist": Array [ + "SomeForbiddenType", + ], + "prettyName": "This is a pretty pretty name", + "requiresEngines": Array [ + "queryEngine", + "migrationEngine", + ], + }, + ] + `) expect(pick(generators[0].options!, ['datamodel', 'datasources', 'otherGenerators'])).toMatchInlineSnapshot(` Object { @@ -421,30 +440,126 @@ describe('getGenerators', () => { `) expect(omit(generators[0].options!.generator, ['output'])).toMatchInlineSnapshot(` - Object { - "binaryTargets": Array [ - Object { - "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", - "value": "darwin", - }, - Object { - "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", - "value": "windows", - }, - Object { - "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", - "value": "debian-openssl-1.1.x", - }, - ], - "config": Object {}, - "name": "gen_env", - "previewFeatures": Array [], - "provider": Object { - "fromEnvVar": null, - "value": "predefined-generator", - }, - } - `) + Object { + "binaryTargets": Array [ + Object { + "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", + "value": "darwin", + }, + Object { + "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", + "value": "windows", + }, + Object { + "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", + "value": "debian-openssl-1.1.x", + }, + ], + "config": Object {}, + "name": "gen_env", + "previewFeatures": Array [], + "provider": Object { + "fromEnvVar": null, + "value": "predefined-generator", + }, + } + `) + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + + generators.forEach((g) => g.stop()) + }) + + it('basic - binaryTargets as env var - linux-musl (missing current platform)', async () => { + process.env.BINARY_TARGETS_ENV_VAR_TEST = '["linux-musl"]' + + const aliases = { + 'predefined-generator': { + generatorPath: generatorPath, + outputPath: __dirname, + }, + } + + const generators = await getGenerators({ + schemaPath: path.join(__dirname, 'valid-minimal-schema-binaryTargets-env-var.prisma'), + providerAliases: aliases, + }) + + expect(generators.map((g) => g.manifest)).toMatchInlineSnapshot(` + Array [ + Object { + "defaultOutput": "default-output", + "denylist": Array [ + "SomeForbiddenType", + ], + "prettyName": "This is a pretty pretty name", + "requiresEngines": Array [ + "queryEngine", + "migrationEngine", + ], + }, + ] + `) + + expect(pick(generators[0].options!, ['datamodel', 'datasources', 'otherGenerators'])).toMatchInlineSnapshot(` + Object { + "datamodel": "datasource db { + provider = \\"sqlite\\" + url = \\"file:./dev.db\\" + } + + generator gen_env { + provider = \\"predefined-generator\\" + binaryTargets = env(\\"BINARY_TARGETS_ENV_VAR_TEST\\") + } + + model User { + id Int @id + name String + } + ", + "datasources": Array [ + Object { + "activeProvider": "sqlite", + "name": "db", + "provider": "sqlite", + "url": Object { + "fromEnvVar": null, + "value": "file:./dev.db", + }, + }, + ], + "otherGenerators": Array [], + } + `) + + expect(omit(generators[0].options!.generator, ['output'])).toMatchInlineSnapshot(` + Object { + "binaryTargets": Array [ + Object { + "fromEnvVar": "BINARY_TARGETS_ENV_VAR_TEST", + "value": "linux-musl", + }, + ], + "config": Object {}, + "name": "gen_env", + "previewFeatures": Array [], + "provider": Object { + "fromEnvVar": null, + "value": "predefined-generator", + }, + } + `) + + const consoleLog = stripAnsi(ctx.mocked['console.log'].mock.calls.join('\n')) + expect(consoleLog).toContain('Warning: Your current platform') + expect(consoleLog).toContain(`s not included in your generator's \`binaryTargets\` configuration`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) generators.forEach((g) => g.stop()) }) @@ -512,10 +627,15 @@ describe('getGenerators', () => { providerAliases: aliases, }), ).rejects.toThrow('Unknown') + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) }) test('fail if datasource is missing', async () => { - expect.assertions(1) + expect.assertions(5) const aliases = { 'predefined-generator': { generatorPath: generatorPath, @@ -544,10 +664,15 @@ describe('getGenerators', () => { " `) } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) }) test('fail if no model(s) found - sqlite', async () => { - expect.assertions(1) + expect.assertions(5) const aliases = { 'predefined-generator': { generatorPath: generatorPath, @@ -577,10 +702,15 @@ describe('getGenerators', () => { " `) } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) }) test('fail if no model(s) found - mongodb', async () => { - expect.assertions(1) + expect.assertions(5) const aliases = { 'predefined-generator': { generatorPath: generatorPath, @@ -600,7 +730,7 @@ describe('getGenerators', () => { You can define a model like this: model User { - id String @id @default(dbgenerated()) @map(\\"_id\\") @db.ObjectId + id String @id @default(auto()) @map(\\"_id\\") @db.ObjectId email String @unique name String? } @@ -610,10 +740,15 @@ describe('getGenerators', () => { " `) } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) }) test('fail if mongoDb not found in previewFeatures - prisma-client-js - mongodb', async () => { - expect.assertions(1) + expect.assertions(5) const aliases = { 'predefined-generator': { generatorPath: generatorPath, @@ -629,25 +764,30 @@ describe('getGenerators', () => { }) } catch (e) { expect(stripAnsi(e.message)).toMatchInlineSnapshot(` -" -In order to use the mongodb provider, -you need to set the mongodb feature flag. -You can define the feature flag like this: - -generator client { - provider = \\"prisma-client-js\\" - previewFeatures = [\\"mongoDb\\"] -} + " + In order to use the mongodb provider, + you need to set the mongodb feature flag. + You can define the feature flag like this: -More information in our documentation: -https://pris.ly/d/prisma-schema -" -`) + generator client { + provider = \\"prisma-client-js\\" + previewFeatures = [\\"mongoDb\\"] + } + + More information in our documentation: + https://pris.ly/d/prisma-schema + " + `) } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) }) test('fail if mongoDb not found in previewFeatures - prisma-client-go - mongodb', async () => { - expect.assertions(1) + expect.assertions(5) const aliases = { 'predefined-generator': { generatorPath: generatorPath, @@ -663,27 +803,70 @@ https://pris.ly/d/prisma-schema }) } catch (e) { expect(stripAnsi(e.message)).toMatchInlineSnapshot(` -" -In order to use the mongodb provider, -you need to set the mongodb feature flag. -You can define the feature flag like this: - -generator client { - provider = \\"prisma-client-js\\" - previewFeatures = [\\"mongoDb\\"] -} + " + In order to use the mongodb provider, + you need to set the mongodb feature flag. + You can define the feature flag like this: -More information in our documentation: -https://pris.ly/d/prisma-schema -" -`) + generator client { + provider = \\"prisma-client-js\\" + previewFeatures = [\\"mongoDb\\"] + } + + More information in our documentation: + https://pris.ly/d/prisma-schema + " + `) } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + }) + + test('fail if dataProxy and interactiveTransactions are used together - prisma-client-js - postgres', async () => { + expect.assertions(5) + const aliases = { + 'predefined-generator': { + generatorPath: generatorPath, + outputPath: __dirname, + }, + } + + try { + await getGenerators({ + schemaPath: path.join(__dirname, 'proxy-and-interactiveTransactions-client-js.prisma'), + providerAliases: aliases, + skipDownload: true, + }) + } catch (e) { + expect(stripAnsi(e.message)).toMatchInlineSnapshot(` + " + The dataProxy and interactiveTransactions Preview Features can not be enabled at the same time. + Remove interactiveTransactions from previewFeatures, for example: + + generator client { + provider = \\"prisma-client-js\\" + previewFeatures = [\\"dataProxy\\"] + } + + More information in our documentation: + https://pris.ly/d/data-proxy + " + `) + } + + expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(`""`) }) // skipped because breaks in CI: https://github.com/prisma/prisma/runs/3729932474#step:8:596 // thrown: "Exceeded timeout of 20000 ms for a test. test.skip('should not be blocked with mongoDb in previewFeatures - prisma-client-go - mongodb', async () => { - expect.assertions(1) + expect.assertions(5) const aliases = { 'predefined-generator': { generatorPath: generatorPath, diff --git a/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-go.prisma b/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-go.prisma index fd3e2c185b1d..06bb62e78ea2 100644 --- a/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-go.prisma +++ b/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-go.prisma @@ -1,6 +1,6 @@ generator client { - provider = "prisma-client-go" -// previewFeatures = ["mongoDb"] + provider = "prisma-client-go" + // previewFeatures = ["mongoDb"] } datasource db { @@ -9,9 +9,8 @@ datasource db { } model User { - id String @id @default(dbgenerated()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId createdAt DateTime @default(now()) email String @unique name String? } - diff --git a/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-js.prisma b/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-js.prisma index fc335279df6e..b7d43e9b1035 100644 --- a/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-js.prisma +++ b/packages/sdk/src/__tests__/getGenerators/missing-mongoDb-from-previewFeatures-client-js.prisma @@ -1,6 +1,6 @@ generator client { - provider = "prisma-client-js" -// previewFeatures = ["mongoDb"] + provider = "prisma-client-js" + // previewFeatures = ["mongoDb"] } datasource db { @@ -9,9 +9,8 @@ datasource db { } model User { - id String @id @default(dbgenerated()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId createdAt DateTime @default(now()) email String @unique name String? } - diff --git a/packages/sdk/src/__tests__/getGenerators/mongoDb-from-previewFeatures-client-go.prisma b/packages/sdk/src/__tests__/getGenerators/mongoDb-from-previewFeatures-client-go.prisma index 963f6401e794..a1c360e259e4 100644 --- a/packages/sdk/src/__tests__/getGenerators/mongoDb-from-previewFeatures-client-go.prisma +++ b/packages/sdk/src/__tests__/getGenerators/mongoDb-from-previewFeatures-client-go.prisma @@ -1,4 +1,3 @@ - generator go { provider = "go run github.com/prisma/prisma-client-go" previewFeatures = ["mongoDb"] @@ -10,9 +9,8 @@ datasource db { } model User { - id String @id @default(dbgenerated()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId createdAt DateTime @default(now()) email String @unique name String? } - diff --git a/packages/sdk/src/__tests__/getGenerators/proxy-and-interactiveTransactions-client-js.prisma b/packages/sdk/src/__tests__/getGenerators/proxy-and-interactiveTransactions-client-js.prisma new file mode 100644 index 000000000000..c9ebfc10f6c0 --- /dev/null +++ b/packages/sdk/src/__tests__/getGenerators/proxy-and-interactiveTransactions-client-js.prisma @@ -0,0 +1,16 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["dataProxy", "interactiveTransactions"] +} + +datasource db { + provider = "postgres" + url = env("DATABASE_URL") +} + +model User { + id String @id + createdAt DateTime @default(now()) + email String @unique + name String? +} diff --git a/packages/sdk/src/__tests__/getPackedPackage.test.ts b/packages/sdk/src/__tests__/getPackedPackage.test.ts index bfecc66306f8..ecb851d9df4e 100644 --- a/packages/sdk/src/__tests__/getPackedPackage.test.ts +++ b/packages/sdk/src/__tests__/getPackedPackage.test.ts @@ -1,11 +1,17 @@ -import { getPackedPackage } from './../getPackedPackage' -import path from 'path' import fs from 'fs' +import path from 'path' + +import { getPackedPackage } from './../getPackedPackage' + +const isMacOrWindowsCI = Boolean(process.env.CI) && ['darwin', 'win32'].includes(process.platform) +if (isMacOrWindowsCI) { + jest.setTimeout(60_000) +} else { + jest.setTimeout(20_000) +} describe('getPackedPackage', () => { it('test argument vulnerability', async () => { - jest.setTimeout(10000) - const outputDir = '/tmp/some-prisma-target-folder' const packageDir = 'foo`touch /tmp/getPackedPackage-exploit`' diff --git a/packages/sdk/src/__tests__/getSchema.test.ts b/packages/sdk/src/__tests__/getSchema.test.ts index cfc0840a6312..9bb039366a32 100644 --- a/packages/sdk/src/__tests__/getSchema.test.ts +++ b/packages/sdk/src/__tests__/getSchema.test.ts @@ -1,4 +1,5 @@ import path from 'path' + import { getSchemaPathInternal, getSchemaPathSyncInternal } from '../cli/getSchema' import { fixturesPath } from './__utils__/fixtures' diff --git a/packages/sdk/src/__tests__/migrateEngineCommands.test.ts b/packages/sdk/src/__tests__/migrateEngineCommands.test.ts index bcc87017527f..4f51a752c592 100644 --- a/packages/sdk/src/__tests__/migrateEngineCommands.test.ts +++ b/packages/sdk/src/__tests__/migrateEngineCommands.test.ts @@ -1,12 +1,13 @@ import tempy from 'tempy' + +import { credentialsToUri, uriToCredentials } from '../convertCredentials' import { - execaCommand, - doesSqliteDbExist, canConnectToDatabase, createDatabase, + doesSqliteDbExist, dropDatabase, + execaCommand, } from '../migrateEngineCommands' -import { uriToCredentials, credentialsToUri } from '../convertCredentials' if (process.env.CI) { // 5s is often not enough for the "postgresql - create database" test on macOS CI. @@ -165,7 +166,7 @@ describe('createDatabase', () => { test('invalid database type', async () => { await expect(createDatabase('invalid:somedburl')).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unknown database type invalid:"`, + `"Unknown protocol invalid:"`, ) }) diff --git a/packages/sdk/src/cli/getGeneratorSuccessMessage.ts b/packages/sdk/src/cli/getGeneratorSuccessMessage.ts index af4d4d5c15b7..b823c27991c5 100644 --- a/packages/sdk/src/cli/getGeneratorSuccessMessage.ts +++ b/packages/sdk/src/cli/getGeneratorSuccessMessage.ts @@ -1,5 +1,6 @@ import chalk from 'chalk' import path from 'path' + import { getClientEngineType } from '../client/getClientEngineType' import type { Generator } from '../Generator' import { formatms } from '../utils/formatms' diff --git a/packages/sdk/src/cli/getSchema.ts b/packages/sdk/src/cli/getSchema.ts index b1325b2385d9..b12e54b072e2 100644 --- a/packages/sdk/src/cli/getSchema.ts +++ b/packages/sdk/src/cli/getSchema.ts @@ -214,13 +214,14 @@ async function getAbsoluteSchemaPath(schemaPath: string): Promise } export async function getRelativeSchemaPath(cwd: string): Promise { - let schemaPath = path.join(cwd, 'schema.prisma') + let schemaPath: string | undefined + + schemaPath = path.join(cwd, 'schema.prisma') if (await exists(schemaPath)) { return schemaPath } schemaPath = path.join(cwd, `prisma/schema.prisma`) - if (await exists(schemaPath)) { return schemaPath } diff --git a/packages/sdk/src/cli/hashes.ts b/packages/sdk/src/cli/hashes.ts index d5a136bc5167..dc3cb2bed700 100644 --- a/packages/sdk/src/cli/hashes.ts +++ b/packages/sdk/src/cli/hashes.ts @@ -1,6 +1,7 @@ +import crypto from 'crypto' + import { getSchemaPath } from './getSchema' import { arg } from './utils' -import crypto from 'crypto' /** * Get a unique identifier for the project by hashing diff --git a/packages/sdk/src/cli/utils.ts b/packages/sdk/src/cli/utils.ts index 5757358b4cbb..e3240a0b1cd8 100644 --- a/packages/sdk/src/cli/utils.ts +++ b/packages/sdk/src/cli/utils.ts @@ -1,5 +1,5 @@ -import dedent from 'strip-indent' import Arg from 'arg' +import dedent from 'strip-indent' /** * format diff --git a/packages/sdk/src/convertCredentials.ts b/packages/sdk/src/convertCredentials.ts index e50a80095ea0..ddff625667e1 100644 --- a/packages/sdk/src/convertCredentials.ts +++ b/packages/sdk/src/convertCredentials.ts @@ -1,7 +1,8 @@ -import type { DatabaseCredentials } from './types' -import * as NodeURL from 'url' import type { ConnectorType } from '@prisma/generator-helper' import path from 'path' +import * as NodeURL from 'url' + +import type { DatabaseCredentials } from './types' // opposite of uriToCredentials // only used for internal tests @@ -161,9 +162,10 @@ export function uriToCredentials(connectionString: string): DatabaseCredentials } // do we need a function for that? -function databaseTypeToProtocol(databaseType: ConnectorType): string { +function databaseTypeToProtocol(databaseType: ConnectorType) { switch (databaseType) { case 'postgresql': + case 'cockroachdb': return 'postgresql:' case 'mysql': return 'mysql:' @@ -173,7 +175,11 @@ function databaseTypeToProtocol(databaseType: ConnectorType): string { return 'sqlite:' case 'sqlserver': return 'sqlserver:' + case 'jdbc:sqlserver': + return 'jdbc:sqlserver:' } + + throw new Error(`Unknown databaseType ${databaseType}`) } export function protocolToConnectorType(protocol: string): ConnectorType { @@ -194,5 +200,5 @@ export function protocolToConnectorType(protocol: string): ConnectorType { return 'sqlserver' } - throw new Error(`Unknown database type ${protocol}`) + throw new Error(`Unknown protocol ${protocol}`) } diff --git a/packages/sdk/src/engine-commands/formatSchema.ts b/packages/sdk/src/engine-commands/formatSchema.ts index 86849e9e600d..ec2a2fc63d5b 100644 --- a/packages/sdk/src/engine-commands/formatSchema.ts +++ b/packages/sdk/src/engine-commands/formatSchema.ts @@ -2,6 +2,7 @@ import Debug from '@prisma/debug' import { BinaryType } from '@prisma/fetch-engine' import execa from 'execa' import fs from 'fs' + import { resolveBinary } from '../resolveBinary' const debug = Debug('prisma:formatSchema') diff --git a/packages/sdk/src/engine-commands/getConfig.ts b/packages/sdk/src/engine-commands/getConfig.ts index 524558bfadfa..3150d6b731fa 100644 --- a/packages/sdk/src/engine-commands/getConfig.ts +++ b/packages/sdk/src/engine-commands/getConfig.ts @@ -9,6 +9,7 @@ import execa from 'execa' import fs from 'fs' import tmpWrite from 'temp-write' import { promisify } from 'util' + import { resolveBinary } from '../resolveBinary' import { load } from '../utils/load' @@ -19,9 +20,9 @@ const unlink = promisify(fs.unlink) const MAX_BUFFER = 1_000_000_000 export interface ConfigMetaFormat { - datasources: DataSource[] - generators: GeneratorConfig[] - warnings: string[] + datasources: DataSource[] | [] + generators: GeneratorConfig[] | [] + warnings: string[] | [] } export type GetConfigOptions = { @@ -62,11 +63,13 @@ export async function getConfig(options: GetConfigOptions): Promise { +async function getConfigNodeAPI(options: GetConfigOptions): Promise { let data: ConfigMetaFormat | undefined + const queryEnginePath = await resolveBinary(BinaryType.libqueryEngine, options.prismaPath) await isNodeAPISupported() debug(`Using CLI Query Engine (Node-API Library) at: ${queryEnginePath}`) + try { const NodeAPIQueryEngineLibrary = load(queryEnginePath) data = await NodeAPIQueryEngineLibrary.getConfig({ @@ -90,6 +93,7 @@ async function getConfigNodeAPI(options: GetConfigOptions): Promise { + const lowerCasePreviewFeatures = g.previewFeatures.map((pf) => pf.toLowerCase()) + return ['dataProxy', 'interactiveTransactions'].every((pf) => lowerCasePreviewFeatures.includes(pf.toLowerCase())) + }) + ) { + throw new Error(forbiddenTransactionsWithProxyFlagMessage) + } +} diff --git a/packages/sdk/src/get-generators/utils/check-feature-flags/forbiddenTransactionsWithProxyFlagMessage.ts b/packages/sdk/src/get-generators/utils/check-feature-flags/forbiddenTransactionsWithProxyFlagMessage.ts new file mode 100644 index 000000000000..73bfa4453d2c --- /dev/null +++ b/packages/sdk/src/get-generators/utils/check-feature-flags/forbiddenTransactionsWithProxyFlagMessage.ts @@ -0,0 +1,20 @@ +import chalk from 'chalk' + +import { highlightDatamodel } from '../../../highlight/highlight' +import { link } from '../../../utils/link' + +export const forbiddenTransactionsWithProxyFlagMessage = `\nThe ${chalk.green('dataProxy')} and ${chalk.green( + 'interactiveTransactions', +)} Preview Features can not be enabled at the same time. +Remove ${chalk.red('interactiveTransactions')} from previewFeatures, for example: + +${chalk.bold( + highlightDatamodel(`generator client { + provider = "prisma-client-js" + previewFeatures = ["dataProxy"] +}`), +)} + +More information in our documentation: +${link('https://pris.ly/d/data-proxy')} +` diff --git a/packages/sdk/src/get-generators/utils/check-feature-flags/mongoFeatureFlagMissingMessage.ts b/packages/sdk/src/get-generators/utils/check-feature-flags/mongoFeatureFlagMissingMessage.ts index 5cafa47f6137..414d4a0fb6bb 100644 --- a/packages/sdk/src/get-generators/utils/check-feature-flags/mongoFeatureFlagMissingMessage.ts +++ b/packages/sdk/src/get-generators/utils/check-feature-flags/mongoFeatureFlagMissingMessage.ts @@ -1,6 +1,7 @@ import chalk from 'chalk' + import { highlightDatamodel } from '../../../highlight/highlight' -import { link } from '../../../link' +import { link } from '../../../utils/link' export const mongoFeatureFlagMissingMessage = `\nIn order to use the ${chalk.bold('mongodb')} provider, you need to set the ${chalk.green('mongodb')} feature flag. diff --git a/packages/sdk/src/get-generators/utils/check-feature-flags/proxyFeatureFlagMissingMessage.ts b/packages/sdk/src/get-generators/utils/check-feature-flags/proxyFeatureFlagMissingMessage.ts index c96394a8c218..382835e1f307 100644 --- a/packages/sdk/src/get-generators/utils/check-feature-flags/proxyFeatureFlagMissingMessage.ts +++ b/packages/sdk/src/get-generators/utils/check-feature-flags/proxyFeatureFlagMissingMessage.ts @@ -1,6 +1,7 @@ import chalk from 'chalk' + import { highlightDatamodel } from '../../../highlight/highlight' -import { link } from '../../../link' +import { link } from '../../../utils/link' export const proxyFeatureFlagMissingMessage = `\nIn order to use the ${chalk.bold('dataproxy')} engine, you need to set the ${chalk.green('dataProxy')} feature flag. diff --git a/packages/sdk/src/get-generators/utils/getBinaryPathsByVersion.ts b/packages/sdk/src/get-generators/utils/getBinaryPathsByVersion.ts index cf34a65a5bee..c7828b0baad9 100644 --- a/packages/sdk/src/get-generators/utils/getBinaryPathsByVersion.ts +++ b/packages/sdk/src/get-generators/utils/getBinaryPathsByVersion.ts @@ -5,10 +5,11 @@ import type { BinaryPaths, BinaryTargetsEnvValue } from '@prisma/generator-helpe import type { Platform } from '@prisma/get-platform' import makeDir from 'make-dir' import path from 'path' + +import { mapKeys } from '../../utils/mapKeys' +import type { GetBinaryPathsByVersionInput } from '../getGenerators' import { binaryTypeToEngineType } from '../utils/binaryTypeToEngineType' import { engineTypeToBinaryType } from '../utils/engineTypeToBinaryType' -import type { GetBinaryPathsByVersionInput } from '../getGenerators' -import { mapKeys } from '../../utils/mapKeys' export async function getBinaryPathsByVersion({ neededVersions, diff --git a/packages/sdk/src/getPackedPackage.ts b/packages/sdk/src/getPackedPackage.ts index cb3a08ddc814..233ca9792c3a 100644 --- a/packages/sdk/src/getPackedPackage.ts +++ b/packages/sdk/src/getPackedPackage.ts @@ -4,13 +4,14 @@ import fs from 'fs' import makeDir from 'make-dir' import path from 'path' import readPkgUp from 'read-pkg-up' -import { resolvePkg } from './utils/resolve' import rimraf from 'rimraf' import { quote } from 'shell-quote' import tar from 'tar' import tempy from 'tempy' import { promisify } from 'util' + import { hasYarn } from './utils/hasYarn' +import { resolvePkg } from './utils/resolve' // why not directly use Sindre's 'del'? Because it's not ncc-able :/ const del = promisify(rimraf) diff --git a/packages/sdk/src/highlight/highlight.ts b/packages/sdk/src/highlight/highlight.ts index e35151bed560..0c5fdad40cc9 100644 --- a/packages/sdk/src/highlight/highlight.ts +++ b/packages/sdk/src/highlight/highlight.ts @@ -1,7 +1,7 @@ -import type { SyntaxDefinition } from './types' -import { Prism, Token } from './prism' import { dml } from './languages/dml' import { sql } from './languages/sql' +import { Prism, Token } from './prism' +import type { SyntaxDefinition } from './types' export function highlightDatamodel(str: string): any { return highlight(str, dml) diff --git a/packages/sdk/src/highlight/prism.ts b/packages/sdk/src/highlight/prism.ts index 6930a8542e33..d4f09a9b7639 100644 --- a/packages/sdk/src/highlight/prism.ts +++ b/packages/sdk/src/highlight/prism.ts @@ -1,4 +1,4 @@ -import { theme, identity } from './theme' +import { identity, theme } from './theme' /** eslint-disable */ /* ********************************************** @@ -18,17 +18,12 @@ let uniqueId = 0 export const Prism: any = { manual: _self.Prism && _self.Prism.manual, - disableWorkerMessageHandler: - _self.Prism && _self.Prism.disableWorkerMessageHandler, + disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, util: { encode: function (tokens: any) { if (tokens instanceof Token) { const anyTokens: any = tokens - return new Token( - anyTokens.type, - Prism.util.encode(anyTokens.content), - anyTokens.alias, - ) + return new Token(anyTokens.type, Prism.util.encode(anyTokens.content), anyTokens.alias) } else if (Array.isArray(tokens)) { return tokens.map(Prism.util.encode) } else { @@ -187,15 +182,7 @@ export const Prism: any = { return Token.stringify(Prism.util.encode(env.tokens), env.language) }, - matchGrammar: function ( - text, - strarr, - grammar, - index, - startPos, - oneshot, - target?: any, - ) { + matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target?: any) { for (const token in grammar) { if (!grammar.hasOwnProperty(token) || !grammar[token]) { continue @@ -225,11 +212,7 @@ export const Prism: any = { pattern = pattern.pattern || pattern // Don’t cache length as it changes during the loop - for ( - let i = index, pos = startPos; - i < strarr.length; - pos += strarr[i].length, ++i - ) { + for (let i = index, pos = startPos; i < strarr.length; pos += strarr[i].length, ++i) { let str = strarr[i] if (strarr.length > text.length) { @@ -253,11 +236,7 @@ export const Prism: any = { k = i, p = pos - for ( - let len = strarr.length; - k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); - ++k - ) { + for (let len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) { p += strarr[k].length // Move the index i to the element in strarr that is closest to from if (from >= p) { @@ -308,13 +287,7 @@ export const Prism: any = { args.push(before) } - const wrapped = new Token( - token, - inside ? Prism.tokenize(match, inside) : match, - alias, - match, - greedy, - ) + const wrapped = new Token(token, inside ? Prism.tokenize(match, inside) : match, alias, match, greedy) args.push(wrapped) @@ -324,8 +297,7 @@ export const Prism: any = { Array.prototype.splice.apply(strarr, args) - if (delNum != 1) - Prism.matchGrammar(text, strarr, grammar, i, pos, true, token) + if (delNum != 1) Prism.matchGrammar(text, strarr, grammar, i, pos, true, token) if (oneshot) break } @@ -394,15 +366,13 @@ Prism.languages.clike = { greedy: true, }, 'class-name': { - pattern: - /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i, + pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i, lookbehind: true, inside: { punctuation: /[.\\]/, }, }, - keyword: - /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, + keyword: /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, boolean: /\b(?:true|false)\b/, function: /\w+(?=\()/, number: /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, @@ -414,8 +384,7 @@ Prism.languages.javascript = Prism.languages.extend('clike', { 'class-name': [ Prism.languages.clike['class-name'], { - pattern: - /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, + pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, lookbehind: true, }, ], @@ -433,10 +402,8 @@ Prism.languages.javascript = Prism.languages.extend('clike', { number: /\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/, // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) - function: - /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, - operator: - /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/, + function: /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, + operator: /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/, }) Prism.languages.javascript['class-name'][0].pattern = @@ -457,8 +424,7 @@ Prism.languages.insertBefore('javascript', 'keyword', { }, parameter: [ { - pattern: - /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, + pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, lookbehind: true, inside: Prism.languages.javascript, }, @@ -511,20 +477,12 @@ Prism.languages.typescript = Prism.languages.extend('javascript', { // From JavaScript Prism keyword list and TypeScript language spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words keyword: /\b(?:abstract|as|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|var|void|while|with|yield)\b/, - builtin: - /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/, + builtin: /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/, }) Prism.languages.ts = Prism.languages.typescript -export function Token( - this: any, - type, - content, - alias, - matchedStr?: any, - greedy?: any, -) { +export function Token(this: any, type, content, alias, matchedStr?: any, greedy?: any) { this.type = type this.content = content this.alias = alias diff --git a/packages/sdk/src/highlight/theme.ts b/packages/sdk/src/highlight/theme.ts index a40838468464..02e150602191 100644 --- a/packages/sdk/src/highlight/theme.ts +++ b/packages/sdk/src/highlight/theme.ts @@ -1,6 +1,7 @@ -import type { Theme } from './types' import chalk from 'chalk' +import type { Theme } from './types' + // https://www.wnycstudios.org/story/211119-colors export const gamboge = chalk.rgb(228, 155, 15) diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 0349679ff8b5..45c36d87b669 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -1,5 +1,6 @@ export { getGeneratorSuccessMessage } from './cli/getGeneratorSuccessMessage' export { + getPrismaConfigFromPackageJson, getRelativeSchemaPath, getSchema, getSchemaDir, @@ -9,7 +10,6 @@ export { getSchemaPathFromPackageJsonSync, getSchemaPathSync, getSchemaSync, - getPrismaConfigFromPackageJson, } from './cli/getSchema' export { getCLIPathHash, getProjectHash } from './cli/hashes' export { unknownCommand } from './cli/Help' @@ -27,45 +27,47 @@ export type { } from './cli/types' export { arg, format, isError } from './cli/utils' export { ClientEngineType, DEFAULT_CLIENT_ENGINE_TYPE, getClientEngineType } from './client/getClientEngineType' -export { credentialsToUri, uriToCredentials } from './convertCredentials' -export { drawBox } from './drawBox' +export { credentialsToUri, protocolToConnectorType, uriToCredentials } from './convertCredentials' export * from './engine-commands' export { Generator } from './Generator' -export { getCommandWithExecutor } from './getCommandWithExecutor' -export { getGenerator, getGenerators } from './get-generators/getGenerators' export type { ProviderAliases } from './get-generators/getGenerators' +export { getGenerator, getGenerators } from './get-generators/getGenerators' export { getPackedPackage } from './getPackedPackage' export { highlightDatamodel, highlightSql, highlightTS } from './highlight/highlight' -export { IntrospectionEngine } from './IntrospectionEngine' export type { IntrospectionSchemaVersion, IntrospectionWarnings } from './IntrospectionEngine' -export { isCi } from './isCi' -export { isCurrentBinInstalledGlobally } from './isCurrentBinInstalledGlobally' -export { keyBy } from './keyBy' -export { link } from './link' +export { IntrospectionEngine } from './IntrospectionEngine' export * as logger from './logger' +export type { MigrateEngineLogLine } from './migrateEngineCommands' export { canConnectToDatabase, createDatabase, dropDatabase } from './migrateEngineCommands' export { MigrateEngineExitCode } from './migrateEngineCommands' -export type { MigrateEngineLogLine } from './migrateEngineCommands' export { ErrorArea, RustPanic } from './panic' -export { pick } from './pick' export type { GeneratorPaths } from './predefinedGeneratorResolvers' export { BinaryType } from './resolveBinary' export { engineEnvVarMap, resolveBinary } from './resolveBinary' export { sendPanic } from './sendPanic' export type { DatabaseCredentials } from './types' +export { drawBox } from './utils/drawBox' export { extractPreviewFeatures } from './utils/extractPreviewFeatures' export { formatms } from './utils/formatms' -export { getEnvPaths } from './utils/getEnvPaths' +export { getCommandWithExecutor } from './utils/getCommandWithExecutor' export type { EnvPaths } from './utils/getEnvPaths' +export { getEnvPaths } from './utils/getEnvPaths' +export { isCi } from './utils/isCi' +export { isCurrentBinInstalledGlobally } from './utils/isCurrentBinInstalledGlobally' +export { jestConsoleContext, jestContext } from './utils/jestContext' +export { keyBy } from './utils/keyBy' +export { link } from './utils/link' +export { load } from './utils/load' +export { loadEnvFile } from './utils/loadEnvFile' export { mapPreviewFeatures } from './utils/mapPreviewFeatures' export { maskSchema } from './utils/maskSchema' export { missingGeneratorMessage } from './utils/missingGeneratorMessage' export { parseBinaryTargetsEnvValue, parseEnvValue } from './utils/parseEnvValue' +export { pick } from './utils/pick' +export { platformRegex } from './utils/platformRegex' export { printConfigWarnings } from './utils/printConfigWarnings' -export { load } from './utils/load' -export { trimBlocksFromSchema, trimNewLine } from './utils/trimBlocksFromSchema' export type { Position } from './utils/trimBlocksFromSchema' +export { trimBlocksFromSchema, trimNewLine } from './utils/trimBlocksFromSchema' export { tryLoadEnvs } from './utils/tryLoadEnvs' -export { getPlatform, getNodeAPIName } from '@prisma/get-platform' export type { Platform } from '@prisma/get-platform' -export { platformRegex } from './utils/platformRegex' +export { getNodeAPIName, getPlatform } from '@prisma/get-platform' diff --git a/packages/sdk/src/migrateEngineCommands.ts b/packages/sdk/src/migrateEngineCommands.ts index b2a9e30636aa..b8afef31aec3 100644 --- a/packages/sdk/src/migrateEngineCommands.ts +++ b/packages/sdk/src/migrateEngineCommands.ts @@ -3,6 +3,7 @@ import execa from 'execa' import fs from 'fs' import path from 'path' import { promisify } from 'util' + import { getSchemaDir } from './cli/getSchema' import { protocolToConnectorType } from './convertCredentials' import { resolveBinary } from './resolveBinary' @@ -35,8 +36,6 @@ type LogLevel = 'INFO' | 'ERROR' | 'DEBUG' | 'WARN' interface LogFields { message: string git_hash?: string - /// Hint from the engine to the CLI to log this line. - migrate_action?: 'log' // Only for ERROR level messages is_panic?: boolean error_code?: string diff --git a/packages/sdk/src/predefinedGeneratorResolvers.ts b/packages/sdk/src/predefinedGeneratorResolvers.ts index a22db1258196..4b75ee2923e2 100644 --- a/packages/sdk/src/predefinedGeneratorResolvers.ts +++ b/packages/sdk/src/predefinedGeneratorResolvers.ts @@ -4,9 +4,11 @@ import execa from 'execa' import fs from 'fs' import hasYarn from 'has-yarn' import path from 'path' -import { resolvePkg } from './utils/resolve' + import { logger } from '.' -import { getCommandWithExecutor } from './getCommandWithExecutor' +import { getCommandWithExecutor } from './utils/getCommandWithExecutor' +import { resolvePkg } from './utils/resolve' + const debug = Debug('prisma:generator') const realPath = fs.promises.realpath diff --git a/packages/sdk/src/resolveBinary.ts b/packages/sdk/src/resolveBinary.ts index fc20fe5aab53..c75ac375f3d4 100644 --- a/packages/sdk/src/resolveBinary.ts +++ b/packages/sdk/src/resolveBinary.ts @@ -31,13 +31,13 @@ export const engineEnvVarMap = { } export { BinaryType } export async function resolveBinary(name: BinaryType, proposedPath?: string): Promise { + // if file exists at proposedPath (and does not start with `/snapshot/` (= pkg), use that one if (proposedPath && !proposedPath.startsWith('/snapshot/') && fs.existsSync(proposedPath)) { return proposedPath } - // tslint:disable-next-line + // If engine path was provided via env var, check and use that one const envVar = engineEnvVarMap[name] - if (process.env[envVar]) { if (!fs.existsSync(process.env[envVar]!)) { throw new Error(`Env var ${envVar} is provided, but provided path ${process.env[envVar]} can't be resolved.`) @@ -45,54 +45,61 @@ export async function resolveBinary(name: BinaryType, proposedPath?: string): Pr return process.env[envVar]! } - const dir = eval('__dirname') - + // If still here, try different paths const binaryName = await getBinaryName(name) - let prismaPath = path.join(getEnginesPath(), binaryName) + const prismaPath = path.join(getEnginesPath(), binaryName) if (fs.existsSync(prismaPath)) { return maybeCopyToTmp(prismaPath) } - // for pkg - prismaPath = path.join(__dirname, '..', binaryName) - if (fs.existsSync(prismaPath)) { - return maybeCopyToTmp(prismaPath) + + // for pkg (related: https://github.com/vercel/pkg#snapshot-filesystem) + const prismaPath2 = path.join(__dirname, '..', binaryName) + if (fs.existsSync(prismaPath2)) { + return maybeCopyToTmp(prismaPath2) } - prismaPath = path.join(__dirname, '../..', binaryName) - if (fs.existsSync(prismaPath)) { - return maybeCopyToTmp(prismaPath) + // TODO for ?? + const prismaPath3 = path.join(__dirname, '../..', binaryName) + if (fs.existsSync(prismaPath3)) { + return maybeCopyToTmp(prismaPath3) } - // needed to come from @prisma/client/generator-build to @prisma/client/runtime - prismaPath = path.join(__dirname, '../runtime', binaryName) - if (fs.existsSync(prismaPath)) { - return maybeCopyToTmp(prismaPath) + // TODO for ?? / needed to come from @prisma/client/generator-build to @prisma/client/runtime + const prismaPath4 = path.join(__dirname, '../runtime', binaryName) + if (fs.existsSync(prismaPath4)) { + return maybeCopyToTmp(prismaPath4) } + // Still here? Could not find the engine, so error out. throw new Error( - `Could not find ${name} binary. Searched in ${path.join(dir, '..', binaryName)} and ${path.join( - dir, - '../..', - binaryName, - )}`, + `Could not find ${name} binary. Searched in: +- ${prismaPath} +- ${prismaPath2} +- ${prismaPath3} +- ${prismaPath4}`, ) } export async function maybeCopyToTmp(file: string): Promise { - // in this case, we are in a "pkg" context with a virtual fs - // to make this work, we need to copy the binary to /tmp and execute it from there - const dir = eval('__dirname') + if (dir.startsWith('/snapshot/')) { + // in this case, we are in a "pkg" context with a virtual fs + // to make this work, we need to copy the binary to /tmp and execute it from there + // TODO Why is this needed? What happens if you do not do it? + // TODO Probably to be able to make the file executable? + // TODO Go and Python Client (which use pkg) actually provide the binaries _outside_ of the CLI via env vars - so never and up here const targetDir = path.join(tempDir, 'prisma-binaries') await makeDir(targetDir) const target = path.join(targetDir, path.basename(file)) + + // We have to read and write until https://github.com/zeit/pkg/issues/639 is resolved const data = await readFile(file) await writeFile(target, data) - // We have to read and write until https://github.com/zeit/pkg/issues/639 - // is resolved + // TODO Undo when https://github.com/vercel/pkg/pull/1484 is released // await copyFile(file, target) + plusX(target) return target } diff --git a/packages/sdk/src/resolveOutput.ts b/packages/sdk/src/resolveOutput.ts index d2e51588241f..995fb96b4157 100644 --- a/packages/sdk/src/resolveOutput.ts +++ b/packages/sdk/src/resolveOutput.ts @@ -1,6 +1,7 @@ import fs from 'fs' import path from 'path' import { promisify } from 'util' + const exists = promisify(fs.exists) async function resolveNodeModulesBase(cwd: string): Promise { diff --git a/packages/sdk/src/sendPanic.ts b/packages/sdk/src/sendPanic.ts index 82a2e1fabf7f..61e2f47e1f01 100644 --- a/packages/sdk/src/sendPanic.ts +++ b/packages/sdk/src/sendPanic.ts @@ -1,6 +1,8 @@ +import Debug from '@prisma/debug' +import { getProxyAgent } from '@prisma/fetch-engine' import { getPlatform } from '@prisma/get-platform' import archiver from 'archiver' -import Debug from '@prisma/debug' +import * as checkpoint from 'checkpoint-client' import fs from 'fs' import globby from 'globby' import fetch from 'node-fetch' @@ -8,12 +10,11 @@ import os from 'os' import path from 'path' import stripAnsi from 'strip-ansi' import tmp from 'tmp' -import * as checkpoint from 'checkpoint-client' -import { maskSchema, mapScalarValues } from './utils/maskSchema' + +import { IntrospectionEngine } from './IntrospectionEngine' import type { RustPanic } from './panic' import { ErrorArea } from './panic' -import { getProxyAgent } from '@prisma/fetch-engine' -import { IntrospectionEngine } from './IntrospectionEngine' +import { mapScalarValues, maskSchema } from './utils/maskSchema' const debug = Debug('prisma:sendPanic') // cleanup the temporary files even when an uncaught exception occurs diff --git a/packages/sdk/src/drawBox.ts b/packages/sdk/src/utils/drawBox.ts similarity index 100% rename from packages/sdk/src/drawBox.ts rename to packages/sdk/src/utils/drawBox.ts diff --git a/packages/sdk/src/getCommandWithExecutor.ts b/packages/sdk/src/utils/getCommandWithExecutor.ts similarity index 100% rename from packages/sdk/src/getCommandWithExecutor.ts rename to packages/sdk/src/utils/getCommandWithExecutor.ts diff --git a/packages/sdk/src/utils/getEnvPaths.ts b/packages/sdk/src/utils/getEnvPaths.ts index 6e896566a9e0..b010a321e386 100644 --- a/packages/sdk/src/utils/getEnvPaths.ts +++ b/packages/sdk/src/utils/getEnvPaths.ts @@ -1,7 +1,8 @@ import Debug from '@prisma/debug' import findUp from 'find-up' -import path from 'path' import fs from 'fs' +import path from 'path' + import { getSchemaPathFromPackageJsonSync } from '../cli/getSchema' import { exists } from './tryLoadEnvs' diff --git a/packages/sdk/src/isCi.ts b/packages/sdk/src/utils/isCi.ts similarity index 100% rename from packages/sdk/src/isCi.ts rename to packages/sdk/src/utils/isCi.ts diff --git a/packages/sdk/src/isCurrentBinInstalledGlobally.ts b/packages/sdk/src/utils/isCurrentBinInstalledGlobally.ts similarity index 100% rename from packages/sdk/src/isCurrentBinInstalledGlobally.ts rename to packages/sdk/src/utils/isCurrentBinInstalledGlobally.ts diff --git a/packages/migrate/src/__tests__/__helpers__/context.ts b/packages/sdk/src/utils/jestContext.ts similarity index 77% rename from packages/migrate/src/__tests__/__helpers__/context.ts rename to packages/sdk/src/utils/jestContext.ts index edd57927cc23..b1174c5e487e 100644 --- a/packages/migrate/src/__tests__/__helpers__/context.ts +++ b/packages/sdk/src/utils/jestContext.ts @@ -1,8 +1,8 @@ import type { ExecaChildProcess } from 'execa' import execa from 'execa' -import * as FSJet from 'fs-jetpack' +import fs from 'fs-jetpack' import type { FSJetpack } from 'fs-jetpack/types' -import * as Path from 'path' +import path from 'path' import tempy from 'tempy' /** @@ -23,7 +23,7 @@ type BaseContext = { * * @remarks * - * For this to work the source must be built! + * For this to work the source must be built */ cli: (...input: string[]) => ExecaChildProcess } @@ -36,24 +36,31 @@ type BaseContext = { * - Mocked process.cwd via Node process.chdir * - Fixture loader for boostrapping the temporary directory with content */ -export const Context = { +export const jestContext = { new: function (ctx: BaseContext = {} as any) { - const c = ctx as any + const c = ctx as BaseContext beforeEach(() => { + const originalCwd = process.cwd() + c.tmpDir = tempy.directory() - c.fs = FSJet.cwd(c.tmpDir) + c.fs = fs.cwd(c.tmpDir) c.fixture = (name: string) => { - c.fs.copy(Path.join(__dirname, '..', 'fixtures', name), '.', { + // copy the specific fixture directory in isolated tmp directory + c.fs.copy(path.join(originalCwd, 'src', '__tests__', 'fixtures', name), '.', { overwrite: true, }) + // symlink to local client version in tmp dir + c.fs.symlink(path.join(originalCwd, '..', 'client'), path.join(c.fs.cwd(), 'node_modules', '@prisma', 'client')) + } + c.mocked = c.mocked ?? { + cwd: process.cwd(), } - c.mocked = c.mocked ?? {} - c.mocked.cwd = process.cwd() c.cli = (...input) => { - return execa.node(Path.join(__dirname, '../../../build/index.js'), input, { + return execa.node(path.join(originalCwd, '../cli/build/index.js'), input, { cwd: c.fs.cwd(), stdio: 'pipe', + all: true, }) } process.chdir(c.tmpDir) @@ -86,6 +93,7 @@ function factory(ctx: Context) { return { add(contextContributor: ContextContributor) { contextContributor(ctx) + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument return factory(ctx as any) }, assemble(): Context { @@ -97,7 +105,7 @@ function factory(ctx: Context) { /** * Test context contributor. Mocks console.error with a Jest spy before each test. */ -export const consoleContext: ContextContributorFactory< +export const jestConsoleContext: ContextContributorFactory< {}, BaseContext, { diff --git a/packages/sdk/src/utils/jestSnapshotSerializer.js b/packages/sdk/src/utils/jestSnapshotSerializer.js new file mode 100644 index 000000000000..5e4191e863c1 --- /dev/null +++ b/packages/sdk/src/utils/jestSnapshotSerializer.js @@ -0,0 +1,144 @@ +const path = require('path') +const replaceAll = require('replace-string') // sindre's replaceAll polyfill +const stripAnsi = require('strip-ansi') +const { platformRegex } = require('./platformRegex') + +// Pipe utility +const pipe = + (...fns) => + (x) => + fns.reduce((v, f) => f(v), x) + +function normalizePrismaPaths(str) { + return str + .replace(/prisma\\([\w-]+)\.prisma/g, 'prisma/$1.prisma') + .replace(/prisma\\seed\.ts/g, 'prisma/seed.ts') + .replace(/custom-folder\\seed\.js/g, 'custom-folder/seed.js') +} + +function normalizeLogs(str) { + return str + .replace( + /Started query engine http server on http:\/\/127\.0\.0\.1:\d{1,5}/g, + 'Started query engine http server on http://127.0.0.1:00000', + ) + .replace(/Starting a postgresql pool with \d+ connections./g, 'Starting a postgresql pool with XX connections.') +} + +function normalizeTmpDir(str) { + return str.replace(/\/tmp\/([a-z0-9]+)\//g, '/tmp/dir/') +} + +function trimErrorPaths(str) { + const parentDir = path.dirname(path.dirname(path.dirname(__dirname))) + + return replaceAll(str, parentDir, '') +} + +function normalizeToUnixPaths(str) { + // TODO: Windows: this breaks some tests by replacing backslashes outside of file names. + return replaceAll(str, path.sep, '/') +} + +function normalizeGithubLinks(str) { + return str.replace(/https:\/\/github.com\/prisma\/prisma(-client-js)?\/issues\/new\S+/, 'TEST_GITHUB_LINK') +} + +function normalizeTsClientStackTrace(str) { + return str.replace(/([/\\]client[/\\]src[/\\]__tests__[/\\].*test.ts)(:\d*:\d*)/, '$1:0:0') +} + +function removePlatforms(str) { + return str.replace(platformRegex, 'TEST_PLATFORM') +} + +// When updating snapshots this is sensitive to OS +// macOS will update extension to .dylib.node, but CI uses .so.node for example +// Note that on Windows the file name doesn't start with "lib". +function normalizeNodeApiLibFilePath(str) { + return str.replace( + /((lib)?query_engine-TEST_PLATFORM.)(.*)(.node)/, + 'libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node', + ) +} + +function normalizeBinaryFilePath(str) { + return str.replace(/query-engine-TEST_PLATFORM\.exe/, 'query-engine-TEST_PLATFORM') +} + +function normalizeMigrateTimestamps(str) { + return str.replace(/\d{14}/g, '20201231000000') +} + +function normalizeDbUrl(str) { + return str.replace(/(localhost|postgres|mysql|mssql):(\d+)/g, 'localhost:$2') +} + +function normalizeRustError(str) { + return str.replace(/\/rustc\/(.+)\//g, '/rustc/hash/').replace(/(\[.*)(:\d*:\d*)(\])/g, '[/some/rust/path:0:0$3') +} + +function normalizeTime(str) { + // sometimes someting can take a few seconds when usually it's less than 1s or a few ms + return str.replace(/ \d+ms/g, ' XXXms').replace(/ \d+(\.\d+)?s/g, ' XXXms') +} + +/** + * Replace dynamic variable bits of Prisma schema with static strings. + * Only for integration-tests + */ +function prepareSchemaForSnapshot(str) { + if (!str.includes('tmp/prisma-tests/integration-test')) return str + + const urlRegex = /url\s*=\s*.+/ + const outputRegex = /output\s*=\s*.+/ + return str + .split('\n') + .map((line) => { + const urlMatch = urlRegex.exec(line) + if (urlMatch) { + return `${line.slice(0, urlMatch.index)}url = "***"` + } + const outputMatch = outputRegex.exec(line) + if (outputMatch) { + return `${line.slice(0, outputMatch.index)}output = "***"` + } + return line + }) + .join('\n') +} + +module.exports = { + // Expected by Jest + test(value) { + return typeof value === 'string' || value instanceof Error + }, + serialize(value) { + const message = typeof value === 'string' ? value : value instanceof Error ? value.message : '' + + // order is important + return pipe( + stripAnsi, + // integration-tests pkg + prepareSchemaForSnapshot, + // Generic + normalizeTmpDir, + normalizeTime, + // From Client package + normalizeGithubLinks, + removePlatforms, + normalizeNodeApiLibFilePath, + normalizeBinaryFilePath, + normalizeTsClientStackTrace, + trimErrorPaths, + normalizePrismaPaths, + normalizeLogs, + // remove windows \\ + normalizeToUnixPaths, + // From Migrate/CLI package + normalizeDbUrl, + normalizeRustError, + normalizeMigrateTimestamps, + )(message) + }, +} diff --git a/packages/sdk/src/keyBy.ts b/packages/sdk/src/utils/keyBy.ts similarity index 100% rename from packages/sdk/src/keyBy.ts rename to packages/sdk/src/utils/keyBy.ts diff --git a/packages/sdk/src/link.ts b/packages/sdk/src/utils/link.ts similarity index 100% rename from packages/sdk/src/link.ts rename to packages/sdk/src/utils/link.ts index 7961875563b5..5f38b14363fa 100644 --- a/packages/sdk/src/link.ts +++ b/packages/sdk/src/utils/link.ts @@ -1,5 +1,5 @@ -import terminalLink from 'terminal-link' import chalk from 'chalk' +import terminalLink from 'terminal-link' export function link(url): string { return terminalLink(url, url, { diff --git a/packages/sdk/src/utils/loadEnvFile.ts b/packages/sdk/src/utils/loadEnvFile.ts new file mode 100644 index 000000000000..1bb3e7ab9556 --- /dev/null +++ b/packages/sdk/src/utils/loadEnvFile.ts @@ -0,0 +1,15 @@ +import { getEnvPaths } from './getEnvPaths' +import { tryLoadEnvs } from './tryLoadEnvs' + +/** + * Read .env file only if next to schema.prisma + * .env found: print to console it's relative path + */ +export function loadEnvFile(schemaPath?: string, print = false) { + const envPaths = getEnvPaths(schemaPath) + const envData = tryLoadEnvs(envPaths, { conflictCheck: 'error' }) + + if (print && envData && envData.message) { + console.info(envData.message) + } +} diff --git a/packages/sdk/src/utils/missingDatasource.ts b/packages/sdk/src/utils/missingDatasource.ts index 38194d0b7719..13ccce7e869e 100644 --- a/packages/sdk/src/utils/missingDatasource.ts +++ b/packages/sdk/src/utils/missingDatasource.ts @@ -1,6 +1,7 @@ import chalk from 'chalk' + import { highlightDatamodel } from '../highlight/highlight' -import { link } from '../link' +import { link } from './link' export const missingDatasource = `\nYou don't have any ${chalk.bold('datasource')} defined in your ${chalk.bold( 'schema.prisma', diff --git a/packages/sdk/src/utils/missingGeneratorMessage.ts b/packages/sdk/src/utils/missingGeneratorMessage.ts index 73b28c863cc3..6c19617aa526 100644 --- a/packages/sdk/src/utils/missingGeneratorMessage.ts +++ b/packages/sdk/src/utils/missingGeneratorMessage.ts @@ -1,6 +1,7 @@ import chalk from 'chalk' + import { highlightDatamodel } from '../highlight/highlight' -import { link } from '../link' +import { link } from './link' export const missingGeneratorMessage = `\n${chalk.blue( 'info', @@ -37,7 +38,7 @@ You can define a model like this: ${chalk.bold( highlightDatamodel(`model User { - id String @id @default(dbgenerated()) @map("_id") @db.ObjectId + id String @id @default(auto()) @map("_id") @db.ObjectId email String @unique name String? }`), diff --git a/packages/sdk/src/omit.ts b/packages/sdk/src/utils/omit.ts similarity index 100% rename from packages/sdk/src/omit.ts rename to packages/sdk/src/utils/omit.ts diff --git a/packages/sdk/src/utils/parseEnvValue.ts b/packages/sdk/src/utils/parseEnvValue.ts index 526f9a4ee73f..0a197dc79c80 100644 --- a/packages/sdk/src/utils/parseEnvValue.ts +++ b/packages/sdk/src/utils/parseEnvValue.ts @@ -1,4 +1,4 @@ -import type { EnvValue, BinaryTargetsEnvValue } from '@prisma/generator-helper' +import type { BinaryTargetsEnvValue, EnvValue } from '@prisma/generator-helper' import chalk from 'chalk' /** diff --git a/packages/sdk/src/pick.ts b/packages/sdk/src/utils/pick.ts similarity index 100% rename from packages/sdk/src/pick.ts rename to packages/sdk/src/utils/pick.ts diff --git a/packages/sdk/src/utils/resolve.ts b/packages/sdk/src/utils/resolve.ts index 766802be7bdc..5914bddeb534 100644 --- a/packages/sdk/src/utils/resolve.ts +++ b/packages/sdk/src/utils/resolve.ts @@ -1,5 +1,5 @@ -import { default as _resolve } from 'resolve' import path from 'path' +import { default as _resolve } from 'resolve' async function resolve(id: string, options: _resolve.AsyncOpts) { const _options = { preserveSymlinks: false, ...options } diff --git a/packages/sdk/src/utils/tryLoadEnvs.ts b/packages/sdk/src/utils/tryLoadEnvs.ts index 6d34836ab874..0b030916d1d2 100644 --- a/packages/sdk/src/utils/tryLoadEnvs.ts +++ b/packages/sdk/src/utils/tryLoadEnvs.ts @@ -1,9 +1,11 @@ -import chalk from 'chalk' import Debug from '@prisma/debug' +import chalk from 'chalk' import dotenv from 'dotenv' import fs from 'fs' import path from 'path' + import { dotenvExpand } from '../dotenvExpand' + const debug = Debug('prisma:tryLoadEnv') type DotenvResult = dotenv.DotenvConfigOutput & { diff --git a/packages/sdk/src/unique.ts b/packages/sdk/src/utils/unique.ts similarity index 100% rename from packages/sdk/src/unique.ts rename to packages/sdk/src/utils/unique.ts diff --git a/packages/sdk/tsconfig.eslint.json b/packages/sdk/tsconfig.eslint.json deleted file mode 100644 index fc8520e73765..000000000000 --- a/packages/sdk/tsconfig.eslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./tsconfig.json" -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 550b2d7e2161..a164f55367f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ importers: '@types/benchmark': 2.1.1 '@types/glob': 7.2.0 '@types/graphviz': 0.0.34 - '@types/node': 14.18.3 + '@types/node': 14.18.12 '@types/redis': 2.8.32 '@types/resolve': 1.20.1 '@typescript-eslint/eslint-plugin': 5.9.0 @@ -24,16 +24,20 @@ importers: eslint: 8.6.0 eslint-config-prettier: 8.3.0 eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 + eslint-plugin-import: 2.25.4 + eslint-plugin-jest: 26.0.0 eslint-plugin-prettier: 4.0.0 + eslint-plugin-simple-import-sort: 7.0.0 eventemitter3: 4.0.7 execa: 5.1.1 glob: 7.2.0 globby: 11.0.4 - graphviz: 0.0.9 + graphviz-mit: 0.0.9 husky: 7.0.4 is-ci: 3.0.1 - node-fetch: 2.6.6 + jest-junit: 13.0.0 + lint-staged: 12.3.4 + node-fetch: 2.6.7 p-map: 4.0.0 p-reduce: 2.1.0 p-retry: 4.6.1 @@ -41,6 +45,7 @@ importers: prettier: 2.5.1 redis: 3.1.2 redis-lock: 0.1.4 + regenerator-runtime: 0.13.9 resolve: 1.21.0 safe-buffer: 5.2.1 semver: 7.3.5 @@ -58,7 +63,7 @@ importers: '@types/benchmark': 2.1.1 '@types/glob': 7.2.0 '@types/graphviz': 0.0.34 - '@types/node': 14.18.3 + '@types/node': 14.18.12 '@types/redis': 2.8.32 '@types/resolve': 1.20.1 '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 @@ -73,16 +78,20 @@ importers: eslint: 8.6.0 eslint-config-prettier: 8.3.0_eslint@8.6.0 eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_50718c277c711d46fdc0916b9b606e5d + eslint-plugin-import: 2.25.4_eslint@8.6.0 + eslint-plugin-jest: 26.0.0_50718c277c711d46fdc0916b9b606e5d eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 + eslint-plugin-simple-import-sort: 7.0.0_eslint@8.6.0 eventemitter3: 4.0.7 execa: 5.1.1 glob: 7.2.0 globby: 11.0.4 - graphviz: 0.0.9 + graphviz-mit: 0.0.9 husky: 7.0.4 is-ci: 3.0.1 - node-fetch: 2.6.6 + jest-junit: 13.0.0 + lint-staged: 12.3.4 + node-fetch: 2.6.7 p-map: 4.0.0 p-reduce: 2.1.0 p-retry: 4.6.1 @@ -90,13 +99,14 @@ importers: prettier: 2.5.1 redis: 3.1.2 redis-lock: 0.1.4 + regenerator-runtime: 0.13.9 resolve: 1.21.0 safe-buffer: 5.2.1 semver: 7.3.5 spdx-exceptions: 2.3.0 spdx-license-ids: 3.0.11 staged-git-files: 1.2.0 - ts-node: 10.4.0_60e8b8d4e7c9a6973679cdf61ab01fe0 + ts-node: 10.4.0_b575a4ed8d8a14db25cb9540c04f64f6 ts-toolbelt: 9.6.0 tty-browserify: 0.0.1 typescript: 4.5.4 @@ -106,31 +116,26 @@ importers: specifiers: '@prisma/client': workspace:* '@prisma/debug': workspace:* - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@prisma/fetch-engine': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@prisma/fetch-engine': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': workspace:* - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/migrate': workspace:* '@prisma/sdk': workspace:* - '@prisma/studio': 0.452.0 - '@prisma/studio-server': 0.452.0 + '@prisma/studio': 0.458.0 + '@prisma/studio-server': 0.458.0 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17 '@types/debug': 4.1.7 '@types/fs-extra': 9.0.13 - '@types/jest': 27.4.0 + '@types/jest': 27.4.1 '@types/rimraf': 3.0.2 - '@types/ws': 8.2.2 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 + '@types/ws': 8.5.3 chalk: 4.1.2 - checkpoint-client: 1.1.20 + checkpoint-client: 1.1.21 debug: 4.3.3 - dotenv: 10.0.0 + dotenv: 16.0.0 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 execa: 5.1.1 fast-deep-equal: 3.1.3 fs-extra: 10.0.0 @@ -138,51 +143,44 @@ importers: get-port: 5.1.1 global-dirs: 3.0.0 is-installed-globally: 0.4.0 - jest: 27.4.6 + jest: 27.5.1 + jest-junit: 13.0.0 line-replace: 2.0.1 - lint-staged: 12.1.5 log-update: 4.0.0 make-dir: 3.1.0 - node-fetch: 2.6.6 + node-fetch: 2.6.7 open: 7.4.2 pkg-up: 3.1.0 - prettier: 2.5.1 replace-string: 3.1.0 resolve-pkg: 2.0.0 rimraf: 3.0.2 strip-ansi: 6.0.1 tempy: 1.0.1 - ts-jest: 27.1.2 typescript: 4.5.4 dependencies: - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 devDependencies: '@prisma/client': link:../client '@prisma/debug': link:../debug - '@prisma/fetch-engine': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/fetch-engine': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': link:../generator-helper - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/migrate': link:../migrate '@prisma/sdk': link:../sdk - '@prisma/studio': 0.452.0 - '@prisma/studio-server': 0.452.0 + '@prisma/studio': 0.458.0 + '@prisma/studio-server': 0.458.0 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17_@swc+core@1.2.141 '@types/debug': 4.1.7 '@types/fs-extra': 9.0.13 - '@types/jest': 27.4.0 + '@types/jest': 27.4.1 '@types/rimraf': 3.0.2 - '@types/ws': 8.2.2 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 + '@types/ws': 8.5.3 chalk: 4.1.2 - checkpoint-client: 1.1.20 + checkpoint-client: 1.1.21 debug: 4.3.3 - dotenv: 10.0.0 + dotenv: 16.0.0 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 execa: 5.1.1 fast-deep-equal: 3.1.3 fs-extra: 10.0.0 @@ -190,54 +188,46 @@ importers: get-port: 5.1.1 global-dirs: 3.0.0 is-installed-globally: 0.4.0 - jest: 27.4.6_ts-node@10.4.0 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 line-replace: 2.0.1 - lint-staged: 12.1.5 log-update: 4.0.0 make-dir: 3.1.0 - node-fetch: 2.6.6 + node-fetch: 2.6.7 open: 7.4.2 pkg-up: 3.1.0 - prettier: 2.5.1 replace-string: 3.1.0 resolve-pkg: 2.0.0 rimraf: 3.0.2 strip-ansi: 6.0.1 tempy: 1.0.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 typescript: 4.5.4 packages/client: specifiers: '@microsoft/api-extractor': 7.19.3 + '@opentelemetry/api': 1.0.3 '@prisma/debug': workspace:* '@prisma/engine-core': workspace:* - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@prisma/engines-version': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@prisma/fetch-engine': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@prisma/engines-version': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@prisma/fetch-engine': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': workspace:* - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/migrate': workspace:* '@prisma/sdk': workspace:* '@timsuchanek/copy': 1.4.5 '@types/debug': 4.1.7 - '@types/jest': 27.4.0 + '@types/jest': 27.4.1 '@types/js-levenshtein': 1.1.1 - '@types/mssql': 6.0.8 - '@types/node': 12.20.39 - '@types/pg': 8.6.3 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 + '@types/mssql': 7.1.5 + '@types/node': 12.20.47 + '@types/pg': 8.6.5 arg: 5.0.1 benchmark: 2.1.4 chalk: 4.1.2 decimal.js: 10.3.1 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 execa: 5.1.1 flat-map-polyfill: 0.3.8 fs-monkey: 1.0.3 @@ -245,19 +235,19 @@ importers: indent-string: 4.0.0 is-obj: 2.0.0 is-regexp: 2.1.0 - jest: 27.4.6 + jest: 27.5.1 + jest-junit: 13.0.0 js-levenshtein: 1.1.6 klona: 2.0.5 - lint-staged: 12.1.5 lz-string: 1.4.4 make-dir: 3.1.0 - mariadb: 2.5.5 - mssql: 7.3.0 + mariadb: 3.0.0 + mssql: 8.0.1 pg: 8.7.1 pkg-up: 3.1.0 pluralize: 8.0.0 - prettier: 2.5.1 replace-string: 3.1.0 + resolve: 1.22.0 rimraf: 3.0.2 sort-keys: 4.2.0 source-map-support: 0.5.21 @@ -265,41 +255,35 @@ importers: stacktrace-parser: 0.1.10 strip-ansi: 6.0.1 strip-indent: 3.0.0 - ts-jest: 27.1.2 + ts-jest: 27.1.3 ts-node: 10.4.0 tsd: 0.19.1 typescript: 4.5.4 dependencies: - '@prisma/engines-version': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines-version': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 devDependencies: '@microsoft/api-extractor': 7.19.3 + '@opentelemetry/api': 1.0.3 '@prisma/debug': link:../debug '@prisma/engine-core': link:../engine-core - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@prisma/fetch-engine': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@prisma/fetch-engine': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': link:../generator-helper - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/migrate': link:../migrate '@prisma/sdk': link:../sdk '@timsuchanek/copy': 1.4.5 '@types/debug': 4.1.7 - '@types/jest': 27.4.0 + '@types/jest': 27.4.1 '@types/js-levenshtein': 1.1.1 - '@types/mssql': 6.0.8 - '@types/node': 12.20.39 - '@types/pg': 8.6.3 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 + '@types/mssql': 7.1.5 + '@types/node': 12.20.47 + '@types/pg': 8.6.5 arg: 5.0.1 benchmark: 2.1.4 chalk: 4.1.2 decimal.js: 10.3.1 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 execa: 5.1.1 flat-map-polyfill: 0.3.8 fs-monkey: 1.0.3 @@ -307,19 +291,19 @@ importers: indent-string: 4.0.0 is-obj: 2.0.0 is-regexp: 2.1.0 - jest: 27.4.6_ts-node@10.4.0 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 js-levenshtein: 1.1.6 klona: 2.0.5 - lint-staged: 12.1.5 lz-string: 1.4.4 make-dir: 3.1.0 - mariadb: 2.5.5 - mssql: 7.3.0 + mariadb: 3.0.0 + mssql: 8.0.1 pg: 8.7.1 pkg-up: 3.1.0 pluralize: 8.0.0 - prettier: 2.5.1 replace-string: 3.1.0 + resolve: 1.22.0 rimraf: 3.0.2 sort-keys: 4.2.0 source-map-support: 0.5.21 @@ -327,133 +311,96 @@ importers: stacktrace-parser: 0.1.10 strip-ansi: 6.0.1 strip-indent: 3.0.0 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 - ts-node: 10.4.0_9303900730675ceadab88ac326bf0384 + ts-jest: 27.1.3_78f71c585925c0b28fff5bb303a854b3 + ts-node: 10.4.0_7b0dfbb3f059e21b66ca1381a90df8cf tsd: 0.19.1 typescript: 4.5.4 packages/debug: specifiers: '@types/debug': 4.1.7 - '@types/jest': 27.4.0 - '@types/node': 12.20.39 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 - jest: 27.4.6 - lint-staged: 12.1.5 + jest: 27.5.1 + jest-junit: 13.0.0 ms: 2.1.3 - prettier: 2.5.1 strip-ansi: 6.0.1 - ts-jest: 27.1.2 + ts-jest: 27.1.3 typescript: 4.5.4 dependencies: '@types/debug': 4.1.7 ms: 2.1.3 + strip-ansi: 6.0.1 devDependencies: - '@types/jest': 27.4.0 - '@types/node': 12.20.39 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 - prettier: 2.5.1 - strip-ansi: 6.0.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 + ts-jest: 27.1.3_78f71c585925c0b28fff5bb303a854b3 typescript: 4.5.4 packages/engine-core: specifiers: '@prisma/debug': workspace:* - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': workspace:* - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@types/jest': 27.4.0 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17 + '@types/jest': 27.4.1 '@types/node': 16.6.2 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 chalk: 4.1.2 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 execa: 5.1.1 get-stream: 6.0.1 indent-string: 4.0.0 - jest: 27.4.6 - lint-staged: 12.1.5 + jest: 27.5.1 + jest-junit: 13.0.0 new-github-issue-url: 0.2.1 p-retry: 4.6.1 - prettier: 2.5.1 strip-ansi: 6.0.1 terminal-link: 2.1.1 - ts-jest: 27.1.2 typescript: 4.5.4 - undici: 4.12.1 + undici: 4.16.0 dependencies: '@prisma/debug': link:../debug - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': link:../generator-helper - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 chalk: 4.1.2 execa: 5.1.1 get-stream: 6.0.1 indent-string: 4.0.0 new-github-issue-url: 0.2.1 p-retry: 4.6.1 + strip-ansi: 6.0.1 terminal-link: 2.1.1 - undici: 4.12.1 + undici: 4.16.0 devDependencies: - '@types/jest': 27.4.0 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17_@swc+core@1.2.141 + '@types/jest': 27.4.1 '@types/node': 16.6.2 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 - prettier: 2.5.1 - strip-ansi: 6.0.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 typescript: 4.5.4 packages/generator-helper: specifiers: '@prisma/debug': workspace:* + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17 '@types/cross-spawn': 6.0.2 - '@types/jest': 27.4.0 - '@types/node': 12.20.39 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 chalk: 4.1.2 cross-spawn: 7.0.3 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 - jest: 27.4.6 - lint-staged: 12.1.5 - prettier: 2.5.1 - ts-jest: 27.1.2 + jest: 27.5.1 + jest-junit: 13.0.0 ts-node: 10.4.0 typescript: 4.5.4 dependencies: @@ -462,261 +409,210 @@ importers: chalk: 4.1.2 cross-spawn: 7.0.3 devDependencies: - '@types/jest': 27.4.0 - '@types/node': 12.20.39 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17_@swc+core@1.2.141 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 - prettier: 2.5.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 - ts-node: 10.4.0_9303900730675ceadab88ac326bf0384 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 + ts-node: 10.4.0_82274b92ec7bae91027ffd577a5efb53 typescript: 4.5.4 packages/integration-tests: specifiers: '@prisma/sdk': workspace:* '@sindresorhus/slugify': 1.1.2 - '@types/jest': 27.4.0 - '@types/mssql': 6.0.8 - '@types/node': 12.20.39 - '@types/pg': 8.6.3 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17 + '@types/jest': 27.4.1 + '@types/mssql': 7.1.5 + '@types/node': 12.20.47 + '@types/pg': 8.6.5 '@types/sqlite3': 3.1.8 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 decimal.js: 10.3.1 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 execa: 5.1.1 fs-jetpack: 4.3.0 - jest: 27.4.6 - lint-staged: 12.1.5 - mariadb: 2.5.5 - mssql: 7.3.0 + jest: 27.5.1 + jest-junit: 13.0.0 + mariadb: 3.0.0 + mssql: 8.0.1 pg: 8.7.1 - prettier: 2.5.1 replace-string: 3.1.0 sqlite-async: 1.1.2 string-hash: 1.1.3 strip-ansi: 6.0.1 tempy: 1.0.1 - ts-jest: 27.1.2 ts-node: 10.4.0 typescript: 4.5.4 verror: 1.10.1 devDependencies: '@prisma/sdk': link:../sdk '@sindresorhus/slugify': 1.1.2 - '@types/jest': 27.4.0 - '@types/mssql': 6.0.8 - '@types/node': 12.20.39 - '@types/pg': 8.6.3 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17_@swc+core@1.2.141 + '@types/jest': 27.4.1 + '@types/mssql': 7.1.5 + '@types/node': 12.20.47 + '@types/pg': 8.6.5 '@types/sqlite3': 3.1.8 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 decimal.js: 10.3.1 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 execa: 5.1.1 fs-jetpack: 4.3.0 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 - mariadb: 2.5.5 - mssql: 7.3.0 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 + mariadb: 3.0.0 + mssql: 8.0.1 pg: 8.7.1 - prettier: 2.5.1 replace-string: 3.1.0 sqlite-async: 1.1.2 string-hash: 1.1.3 strip-ansi: 6.0.1 tempy: 1.0.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 - ts-node: 10.4.0_9303900730675ceadab88ac326bf0384 + ts-node: 10.4.0_82274b92ec7bae91027ffd577a5efb53 typescript: 4.5.4 verror: 1.10.1 packages/migrate: specifiers: '@prisma/debug': workspace:* - '@prisma/engines-version': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines-version': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': workspace:* - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/sdk': workspace:* '@sindresorhus/slugify': 1.1.2 - '@types/jest': 27.4.0 - '@types/node': 12.20.39 - '@types/pg': 8.6.3 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 + '@types/pg': 8.6.5 '@types/prompts': 2.0.14 '@types/sqlite3': 3.1.8 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 chalk: 4.1.2 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 execa: 5.1.1 fs-jetpack: 4.3.0 + get-stdin: 8.0.0 has-yarn: 2.1.0 indent-string: 4.0.0 - jest: 27.4.6 - lint-staged: 12.1.5 + jest: 27.5.1 + jest-junit: 13.0.0 log-update: 4.0.0 make-dir: 3.1.0 - mariadb: 2.5.5 + mariadb: 3.0.0 mock-stdin: 1.0.0 + mssql: 8.0.2 new-github-issue-url: 0.2.1 open: 7.4.2 - pg: 8.7.1 + pg: 8.7.3 pkg-up: 3.1.0 - prettier: 2.5.1 prompts: 2.4.2 strip-ansi: 6.0.1 strip-indent: 3.0.0 tempy: 1.0.1 - ts-jest: 27.1.2 typescript: 4.5.4 dependencies: '@prisma/debug': link:../debug - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@sindresorhus/slugify': 1.1.2 + chalk: 4.1.2 execa: 5.1.1 + get-stdin: 8.0.0 has-yarn: 2.1.0 indent-string: 4.0.0 log-update: 4.0.0 + mariadb: 3.0.0 + mssql: 8.0.2 new-github-issue-url: 0.2.1 open: 7.4.2 + pg: 8.7.3 pkg-up: 3.1.0 prompts: 2.4.2 strip-ansi: 6.0.1 strip-indent: 3.0.0 devDependencies: - '@prisma/engines-version': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines-version': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': link:../generator-helper '@prisma/sdk': link:../sdk - '@types/jest': 27.4.0 - '@types/node': 12.20.39 - '@types/pg': 8.6.3 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17_@swc+core@1.2.141 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 + '@types/pg': 8.6.5 '@types/prompts': 2.0.14 '@types/sqlite3': 3.1.8 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 - chalk: 4.1.2 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 fs-jetpack: 4.3.0 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 make-dir: 3.1.0 - mariadb: 2.5.5 mock-stdin: 1.0.0 - pg: 8.7.1 - prettier: 2.5.1 tempy: 1.0.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 typescript: 4.5.4 packages/react-prisma: specifiers: '@prisma/client': workspace:* - '@types/jest': 27.4.0 - '@types/node': 16.11.19 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 - esbuild: 0.14.10 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 - jest: 27.4.6 - lint-staged: 12.1.5 - prettier: 2.5.1 + '@types/jest': 27.4.1 + '@types/node': 16.11.26 + esbuild: 0.14.27 + jest: 27.5.1 + jest-junit: 13.0.0 react: 17.0.2 - ts-jest: 27.1.2 - typescript: 4.5.4 + ts-jest: 27.1.3 + typescript: 4.6.2 devDependencies: '@prisma/client': link:../client - '@types/jest': 27.4.0 - '@types/node': 16.11.19 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 - esbuild: 0.14.10 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 - prettier: 2.5.1 + '@types/jest': 27.4.1 + '@types/node': 16.11.26 + esbuild: 0.14.27 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 react: 17.0.2 - ts-jest: 27.1.2_5cdf3cc77b92d7dbbe266bec95b76432 - typescript: 4.5.4 + ts-jest: 27.1.3_e3f3aae470b938602dcd13c1910abd3b + typescript: 4.6.2 packages/sdk: specifiers: '@prisma/debug': workspace:* '@prisma/engine-core': workspace:* - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@prisma/fetch-engine': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@prisma/fetch-engine': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': workspace:* - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17 '@timsuchanek/copy': 1.4.5 - '@types/jest': 27.4.0 - '@types/node': 12.20.39 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 '@types/resolve': 1.20.1 '@types/shell-quote': 1.7.1 '@types/tar': 6.1.1 - '@typescript-eslint/eslint-plugin': 5.9.0 - '@typescript-eslint/parser': 5.9.0 archiver: 5.3.0 arg: 5.0.1 chalk: 4.1.2 - checkpoint-client: 1.1.20 + checkpoint-client: 1.1.21 cli-truncate: 2.1.0 - dotenv: 10.0.0 + dotenv: 16.0.0 esbuild: 0.13.14 escape-string-regexp: 4.0.0 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0 - eslint-plugin-eslint-comments: 3.2.0 - eslint-plugin-jest: 25.3.4 - eslint-plugin-prettier: 4.0.0 execa: 5.1.1 find-up: 5.0.0 + fs-jetpack: 4.3.1 global-dirs: 3.0.0 - globby: 11.0.4 + globby: 11.1.0 has-yarn: 2.1.0 is-ci: 3.0.1 - jest: 27.4.6 - lint-staged: 12.1.5 + jest: 27.5.1 + jest-junit: 13.0.0 make-dir: 3.1.0 - node-fetch: 2.6.6 + node-fetch: 2.6.7 p-map: 4.0.0 - prettier: 2.5.1 read-pkg-up: 7.0.1 - resolve: 1.20.0 + replace-string: 3.1.0 + resolve: 1.22.0 rimraf: 3.0.2 shell-quote: 1.7.3 string-width: 4.2.3 @@ -728,35 +624,36 @@ importers: tempy: 1.0.1 terminal-link: 2.1.1 tmp: 0.2.1 - ts-jest: 27.1.2 ts-node: 10.4.0 typescript: 4.5.4 dependencies: '@prisma/debug': link:../debug '@prisma/engine-core': link:../engine-core - '@prisma/engines': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 - '@prisma/fetch-engine': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/engines': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 + '@prisma/fetch-engine': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@prisma/generator-helper': link:../generator-helper - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 '@timsuchanek/copy': 1.4.5 archiver: 5.3.0 arg: 5.0.1 chalk: 4.1.2 - checkpoint-client: 1.1.20 + checkpoint-client: 1.1.21 cli-truncate: 2.1.0 - dotenv: 10.0.0 + dotenv: 16.0.0 escape-string-regexp: 4.0.0 execa: 5.1.1 find-up: 5.0.0 + fs-jetpack: 4.3.1 global-dirs: 3.0.0 - globby: 11.0.4 + globby: 11.1.0 has-yarn: 2.1.0 is-ci: 3.0.1 make-dir: 3.1.0 - node-fetch: 2.6.6 + node-fetch: 2.6.7 p-map: 4.0.0 read-pkg-up: 7.0.1 - resolve: 1.20.0 + replace-string: 3.1.0 + resolve: 1.22.0 rimraf: 3.0.2 shell-quote: 1.7.3 string-width: 4.2.3 @@ -769,38 +666,33 @@ importers: terminal-link: 2.1.1 tmp: 0.2.1 devDependencies: - '@types/jest': 27.4.0 - '@types/node': 12.20.39 + '@swc/core': 1.2.141 + '@swc/jest': 0.2.17_@swc+core@1.2.141 + '@types/jest': 27.4.1 + '@types/node': 12.20.47 '@types/resolve': 1.20.1 '@types/shell-quote': 1.7.1 '@types/tar': 6.1.1 - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 esbuild: 0.13.14 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-eslint-comments: 3.2.0_eslint@8.6.0 - eslint-plugin-jest: 25.3.4_fc7ad14cecfc112c3a62fcc1531edd55 - eslint-plugin-prettier: 4.0.0_1c588f61426b1faf18812943f1678311 - jest: 27.4.6_ts-node@10.4.0 - lint-staged: 12.1.5 - prettier: 2.5.1 - ts-jest: 27.1.2_96b3dccf67dffb8a903f55c0ad4de774 - ts-node: 10.4.0_9303900730675ceadab88ac326bf0384 + jest: 27.5.1_ts-node@10.4.0 + jest-junit: 13.0.0 + ts-node: 10.4.0_82274b92ec7bae91027ffd577a5efb53 typescript: 4.5.4 packages: + /@alloc/quick-lru/5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + /@azure/abort-controller/1.0.4: resolution: {integrity: sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==} engines: {node: '>=8.0.0'} dependencies: tslib: 2.3.1 - dev: true /@azure/core-asynciterator-polyfill/1.0.0: resolution: {integrity: sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg==} - dev: true /@azure/core-auth/1.3.2: resolution: {integrity: sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA==} @@ -808,24 +700,23 @@ packages: dependencies: '@azure/abort-controller': 1.0.4 tslib: 2.3.1 - dev: true - /@azure/core-client/1.3.2: - resolution: {integrity: sha512-qfkRYKmeEmisluMdGTbBtXeyBLaImjFeVW0gcT5yRAwxJmlnTvSyD+a3PjukAtjIrl/tnb4WSJOBpONSJ91+5Q==} + /@azure/core-client/1.4.0: + resolution: {integrity: sha512-6v1pn4ubNSeI56PUgj2NLR/nfoMfkjYmrtNX0YdXrjxSajKcf/TZc/QJtTFj4wHIvYqU/Yn/g/Zb+MNhFZ5c+Q==} engines: {node: '>=12.0.0'} dependencies: '@azure/abort-controller': 1.0.4 '@azure/core-asynciterator-polyfill': 1.0.0 '@azure/core-auth': 1.3.2 - '@azure/core-rest-pipeline': 1.3.1 + '@azure/core-rest-pipeline': 1.4.0 '@azure/core-tracing': 1.0.0-preview.13 + '@azure/logger': 1.0.3 tslib: 2.3.1 transitivePeerDependencies: - supports-color - dev: true - /@azure/core-http/2.2.1: - resolution: {integrity: sha512-7ATnV3OGzCO2K9kMrh3NKUM8b4v+xasmlUhkNZz6uMbm+8XH/AexLkhRGsoo0GyKNlEGvyGEfytqTk0nUY2I4A==} + /@azure/core-http/2.2.3: + resolution: {integrity: sha512-xr8AeszxP418rI//W38NfJDDr0kbVAPZkURZnZ+Fle+lLWeURjDE5zNIuocA1wUPoKSP8iXc0ApW6nPtbLGswA==} engines: {node: '>=12.0.0'} dependencies: '@azure/abort-controller': 1.0.4 @@ -836,35 +727,34 @@ packages: '@types/node-fetch': 2.5.12 '@types/tunnel': 0.0.3 form-data: 4.0.0 - node-fetch: 2.6.6 + node-fetch: 2.6.7 process: 0.11.10 tough-cookie: 4.0.0 tslib: 2.3.1 tunnel: 0.0.6 uuid: 8.3.2 xml2js: 0.4.23 - dev: true + transitivePeerDependencies: + - encoding - /@azure/core-lro/2.2.1: - resolution: {integrity: sha512-HE6PBl+mlKa0eBsLwusHqAqjLc5n9ByxeDo3Hz4kF3B1hqHvRkBr4oMgoT6tX7Hc3q97KfDctDUon7EhvoeHPA==} + /@azure/core-lro/2.2.3: + resolution: {integrity: sha512-UMdlR9NsqDCLTba3EUbRjfMF4gDmWvld196JmUjbz9WWhJ2XT00OR5MXeWiR+vmGT+ETiO4hHFCi2/eGO5YVtg==} engines: {node: '>=12.0.0'} dependencies: '@azure/abort-controller': 1.0.4 '@azure/core-tracing': 1.0.0-preview.13 '@azure/logger': 1.0.3 tslib: 2.3.1 - dev: true - /@azure/core-paging/1.2.0: - resolution: {integrity: sha512-ZX1bCjm/MjKPCN6kQD/9GJErYSoKA8YWp6YWoo5EIzcTWlSBLXu3gNaBTUl8usGl+UShiKo7b4Gdy1NSTIlpZg==} + /@azure/core-paging/1.2.1: + resolution: {integrity: sha512-UtH5iMlYsvg+nQYIl4UHlvvSrsBjOlRF4fs0j7mxd3rWdAStrKYrh2durOpHs5C9yZbVhsVDaisoyaf/lL1EVA==} engines: {node: '>=12.0.0'} dependencies: '@azure/core-asynciterator-polyfill': 1.0.0 tslib: 2.3.1 - dev: true - /@azure/core-rest-pipeline/1.3.1: - resolution: {integrity: sha512-xTQiv47O5cWzJFkwiDrUTT4K4IYbUIts0gaou5TZxAAuhQi9kAKWHEmFTjHVMOeAmyDhlMM5cb21M2n4WDto1A==} + /@azure/core-rest-pipeline/1.4.0: + resolution: {integrity: sha512-M2uL9PbvhJIEMRoUad3EnXCHWLN/i0W7D7MQJ9rnIDW7iLVCteUiegdqNa2Cr1/7he/ysEXYiwaXiHmfack/6g==} engines: {node: '>=12.0.0'} dependencies: '@azure/abort-controller': 1.0.4 @@ -878,31 +768,28 @@ packages: uuid: 8.3.2 transitivePeerDependencies: - supports-color - dev: true /@azure/core-tracing/1.0.0-preview.12: resolution: {integrity: sha512-nvo2Wc4EKZGN6eFu9n3U7OXmASmL8VxoPIH7xaD6OlQqi44bouF0YIi9ID5rEsKLiAU59IYx6M297nqWVMWPDg==} engines: {node: '>=12.0.0'} dependencies: - '@opentelemetry/api': 1.0.3 + '@opentelemetry/api': 1.0.4 tslib: 2.3.1 - dev: true /@azure/core-tracing/1.0.0-preview.13: resolution: {integrity: sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==} engines: {node: '>=12.0.0'} dependencies: - '@opentelemetry/api': 1.0.3 + '@opentelemetry/api': 1.0.4 tslib: 2.3.1 - dev: true /@azure/identity/1.5.2_debug@4.3.3: resolution: {integrity: sha512-vqyeRbd2i0h9F4mqW5JbkP1xfabqKQ21l/81osKhpOQ2LtwaJW6nw4+0PsVYnxcbPHFCIZt6EWAk74a3OGYZJA==} engines: {node: '>=12.0.0'} dependencies: '@azure/core-auth': 1.3.2 - '@azure/core-client': 1.3.2 - '@azure/core-rest-pipeline': 1.3.1 + '@azure/core-client': 1.4.0 + '@azure/core-rest-pipeline': 1.4.0 '@azure/core-tracing': 1.0.0-preview.12 '@azure/logger': 1.0.3 '@azure/msal-node': 1.0.0-beta.6_debug@4.3.3 @@ -910,66 +797,37 @@ packages: axios: 0.21.4_debug@4.3.3 events: 3.3.0 jws: 4.0.0 - msal: 1.4.14 + msal: 1.4.15 open: 7.4.2 - qs: 6.10.1 + qs: 6.10.3 stoppable: 1.1.0 tslib: 2.3.1 uuid: 8.3.2 optionalDependencies: - keytar: 7.7.0 + keytar: 7.9.0 transitivePeerDependencies: - debug - supports-color - dev: true /@azure/keyvault-keys/4.3.0: resolution: {integrity: sha512-OEosl0/rE/mKD5Ji9KaQN7UH+yQnV5MS0MRhGqQIiJrG+qAvAla0MYudJzv3XvBlplpGk0+MVgyL9H3KX/UAwQ==} engines: {node: '>=8.0.0'} dependencies: '@azure/abort-controller': 1.0.4 - '@azure/core-http': 2.2.1 - '@azure/core-lro': 2.2.1 - '@azure/core-paging': 1.2.0 + '@azure/core-http': 2.2.3 + '@azure/core-lro': 2.2.3 + '@azure/core-paging': 1.2.1 '@azure/core-tracing': 1.0.0-preview.13 '@azure/logger': 1.0.3 tslib: 2.3.1 - dev: true + transitivePeerDependencies: + - encoding /@azure/logger/1.0.3: resolution: {integrity: sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==} engines: {node: '>=12.0.0'} dependencies: tslib: 2.3.1 - dev: true - - /@azure/ms-rest-azure-env/2.0.0: - resolution: {integrity: sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==} - dev: true - - /@azure/ms-rest-js/2.6.0: - resolution: {integrity: sha512-4C5FCtvEzWudblB+h92/TYYPiq7tuElX8icVYToxOdggnYqeec4Se14mjse5miInKtZahiFHdl8lZA/jziEc5g==} - dependencies: - '@azure/core-auth': 1.3.2 - abort-controller: 3.0.0 - form-data: 2.5.1 - node-fetch: 2.6.6 - tough-cookie: 3.0.1 - tslib: 1.14.1 - tunnel: 0.0.6 - uuid: 8.3.2 - xml2js: 0.4.23 - dev: true - - /@azure/ms-rest-nodeauth/3.1.0_debug@4.3.3: - resolution: {integrity: sha512-F4NKrbkZg0qD3+rUM8fvJHOFRkXFoEiptYTZtLBruN3VwBFIqbTFW0fmgRyBW9seZl+mX2OexQA5GzWenSA3Kw==} - dependencies: - '@azure/ms-rest-azure-env': 2.0.0 - '@azure/ms-rest-js': 2.6.0 - adal-node: 0.2.3_debug@4.3.3 - transitivePeerDependencies: - - debug - dev: true /@azure/msal-common/4.5.1: resolution: {integrity: sha512-/i5dXM+QAtO+6atYd5oHGBAx48EGSISkXNXViheliOQe+SIFMDo3gSq3lL54W0suOSAsVPws3XnTaIHlla0PIQ==} @@ -978,7 +836,6 @@ packages: debug: 4.3.3 transitivePeerDependencies: - supports-color - dev: true /@azure/msal-node/1.0.0-beta.6_debug@4.3.3: resolution: {integrity: sha512-ZQI11Uz1j0HJohb9JZLRD8z0moVcPks1AFW4Q/Gcl67+QvH4aKEJti7fjCcipEEZYb/qzLSO8U6IZgPYytsiJQ==} @@ -990,32 +847,31 @@ packages: transitivePeerDependencies: - debug - supports-color - dev: true - /@babel/code-frame/7.15.8: - resolution: {integrity: sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==} + /@babel/code-frame/7.16.7: + resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.14.5 + '@babel/highlight': 7.16.7 - /@babel/compat-data/7.15.0: - resolution: {integrity: sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==} + /@babel/compat-data/7.16.8: + resolution: {integrity: sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.15.8: - resolution: {integrity: sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==} + /@babel/core/7.16.7: + resolution: {integrity: sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.15.8 - '@babel/generator': 7.15.8 - '@babel/helper-compilation-targets': 7.15.4_@babel+core@7.15.8 - '@babel/helper-module-transforms': 7.15.8 - '@babel/helpers': 7.15.4 - '@babel/parser': 7.15.8 - '@babel/template': 7.15.4 - '@babel/traverse': 7.15.4 - '@babel/types': 7.15.6 + '@babel/code-frame': 7.16.7 + '@babel/generator': 7.16.8 + '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.16.7 + '@babel/helper-module-transforms': 7.16.7 + '@babel/helpers': 7.16.7 + '@babel/parser': 7.16.8 + '@babel/template': 7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 convert-source-map: 1.8.0 debug: 4.3.3 gensync: 1.0.0-beta.2 @@ -1026,400 +882,285 @@ packages: - supports-color dev: true - /@babel/generator/7.15.8: - resolution: {integrity: sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==} + /@babel/generator/7.16.8: + resolution: {integrity: sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 jsesc: 2.5.2 source-map: 0.5.7 dev: true - /@babel/helper-compilation-targets/7.15.4_@babel+core@7.15.8: - resolution: {integrity: sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==} + /@babel/helper-compilation-targets/7.16.7_@babel+core@7.16.7: + resolution: {integrity: sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.15.0 - '@babel/core': 7.15.8 - '@babel/helper-validator-option': 7.14.5 - browserslist: 4.17.5 + '@babel/compat-data': 7.16.8 + '@babel/core': 7.16.7 + '@babel/helper-validator-option': 7.16.7 + browserslist: 4.19.1 semver: 6.3.0 dev: true - /@babel/helper-function-name/7.15.4: - resolution: {integrity: sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==} + /@babel/helper-environment-visitor/7.16.7: + resolution: {integrity: sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-get-function-arity': 7.15.4 - '@babel/template': 7.15.4 - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true - /@babel/helper-get-function-arity/7.15.4: - resolution: {integrity: sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==} + /@babel/helper-function-name/7.16.7: + resolution: {integrity: sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.15.6 + '@babel/helper-get-function-arity': 7.16.7 + '@babel/template': 7.16.7 + '@babel/types': 7.16.8 dev: true - /@babel/helper-hoist-variables/7.15.4: - resolution: {integrity: sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==} + /@babel/helper-get-function-arity/7.16.7: + resolution: {integrity: sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true - /@babel/helper-member-expression-to-functions/7.15.4: - resolution: {integrity: sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==} + /@babel/helper-hoist-variables/7.16.7: + resolution: {integrity: sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true - /@babel/helper-module-imports/7.15.4: - resolution: {integrity: sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==} + /@babel/helper-module-imports/7.16.7: + resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true - /@babel/helper-module-transforms/7.15.8: - resolution: {integrity: sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==} + /@babel/helper-module-transforms/7.16.7: + resolution: {integrity: sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-module-imports': 7.15.4 - '@babel/helper-replace-supers': 7.15.4 - '@babel/helper-simple-access': 7.15.4 - '@babel/helper-split-export-declaration': 7.15.4 - '@babel/helper-validator-identifier': 7.15.7 - '@babel/template': 7.15.4 - '@babel/traverse': 7.15.4 - '@babel/types': 7.15.6 + '@babel/helper-environment-visitor': 7.16.7 + '@babel/helper-module-imports': 7.16.7 + '@babel/helper-simple-access': 7.16.7 + '@babel/helper-split-export-declaration': 7.16.7 + '@babel/helper-validator-identifier': 7.16.7 + '@babel/template': 7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-optimise-call-expression/7.15.4: - resolution: {integrity: sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.15.6 - dev: true - - /@babel/helper-plugin-utils/7.14.5: - resolution: {integrity: sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==} + /@babel/helper-plugin-utils/7.16.7: + resolution: {integrity: sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-replace-supers/7.15.4: - resolution: {integrity: sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==} + /@babel/helper-simple-access/7.16.7: + resolution: {integrity: sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-member-expression-to-functions': 7.15.4 - '@babel/helper-optimise-call-expression': 7.15.4 - '@babel/traverse': 7.15.4 - '@babel/types': 7.15.6 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.16.8 dev: true - /@babel/helper-simple-access/7.15.4: - resolution: {integrity: sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==} + /@babel/helper-split-export-declaration/7.16.7: + resolution: {integrity: sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true - /@babel/helper-split-export-declaration/7.15.4: - resolution: {integrity: sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==} + /@babel/helper-validator-identifier/7.16.7: + resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.15.6 - dev: true - /@babel/helper-validator-identifier/7.15.7: - resolution: {integrity: sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==} - engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option/7.14.5: - resolution: {integrity: sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==} + /@babel/helper-validator-option/7.16.7: + resolution: {integrity: sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==} engines: {node: '>=6.9.0'} dev: true - /@babel/helpers/7.15.4: - resolution: {integrity: sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==} + /@babel/helpers/7.16.7: + resolution: {integrity: sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.15.4 - '@babel/traverse': 7.15.4 - '@babel/types': 7.15.6 + '@babel/template': 7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 transitivePeerDependencies: - supports-color dev: true - /@babel/highlight/7.14.5: - resolution: {integrity: sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==} + /@babel/highlight/7.16.7: + resolution: {integrity: sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.15.7 + '@babel/helper-validator-identifier': 7.16.7 chalk: 2.4.2 js-tokens: 4.0.0 - /@babel/parser/7.15.8: - resolution: {integrity: sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==} + /@babel/parser/7.16.8: + resolution: {integrity: sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==} engines: {node: '>=6.0.0'} hasBin: true dev: true - /@babel/plugin-syntax-async-generators/7.8.4: - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.15.8: + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.16.7: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-bigint/7.8.3: - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.15.8: + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.16.7: resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-class-properties/7.12.13: - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.15.8: + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.16.7: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-import-meta/7.10.4: + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.16.7: resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.15.8: - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-json-strings/7.8.3: - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.15.8: + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.16.7: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4: + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.16.7: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.15.8: - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3: + /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.16.7: resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.15.8: - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-numeric-separator/7.10.4: + /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.16.7: resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.15.8: - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-object-rest-spread/7.8.3: + /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.16.7: resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.15.8: - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-optional-catch-binding/7.8.3: - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.15.8: + /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.16.7: resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3: + /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.16.7: resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.15.8: - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 - dev: true - - /@babel/plugin-syntax-top-level-await/7.14.5: - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.15.8: + /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.16.7: resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-typescript/7.14.5_@babel+core@7.15.8: - resolution: {integrity: sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==} + /@babel/plugin-syntax-typescript/7.16.7_@babel+core@7.16.7: + resolution: {integrity: sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.15.8 - '@babel/helper-plugin-utils': 7.14.5 + '@babel/core': 7.16.7 + '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/template/7.15.4: - resolution: {integrity: sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==} + /@babel/template/7.16.7: + resolution: {integrity: sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.15.8 - '@babel/parser': 7.15.8 - '@babel/types': 7.15.6 + '@babel/code-frame': 7.16.7 + '@babel/parser': 7.16.8 + '@babel/types': 7.16.8 dev: true - /@babel/traverse/7.15.4: - resolution: {integrity: sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==} + /@babel/traverse/7.16.8: + resolution: {integrity: sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.15.8 - '@babel/generator': 7.15.8 - '@babel/helper-function-name': 7.15.4 - '@babel/helper-hoist-variables': 7.15.4 - '@babel/helper-split-export-declaration': 7.15.4 - '@babel/parser': 7.15.8 - '@babel/types': 7.15.6 + '@babel/code-frame': 7.16.7 + '@babel/generator': 7.16.8 + '@babel/helper-environment-visitor': 7.16.7 + '@babel/helper-function-name': 7.16.7 + '@babel/helper-hoist-variables': 7.16.7 + '@babel/helper-split-export-declaration': 7.16.7 + '@babel/parser': 7.16.8 + '@babel/types': 7.16.8 debug: 4.3.3 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types/7.15.6: - resolution: {integrity: sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==} + /@babel/types/7.16.8: + resolution: {integrity: sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.15.7 + '@babel/helper-validator-identifier': 7.16.7 to-fast-properties: 2.0.0 dev: true @@ -1487,20 +1228,20 @@ packages: engines: {node: '>=8'} dev: true - /@jest/console/27.4.6: - resolution: {integrity: sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA==} + /@jest/console/27.5.1: + resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 chalk: 4.1.2 - jest-message-util: 27.4.6 - jest-util: 27.4.2 + jest-message-util: 27.5.1 + jest-util: 27.5.1 slash: 3.0.0 dev: true - /@jest/core/27.4.6_ts-node@10.4.0: - resolution: {integrity: sha512-2XvkAguDxaSAg6+Rznq7VZeIs3eV4owk3dud0zL4FH0d8mX7whkAUnO9rb0keMGStazfekR1ec9Yf9BFt4m02Q==} + /@jest/core/27.5.1_ts-node@10.4.0: + resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -1508,36 +1249,35 @@ packages: node-notifier: optional: true dependencies: - '@jest/console': 27.4.6 - '@jest/reporters': 27.4.6 - '@jest/test-result': 27.4.6 - '@jest/transform': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/console': 27.5.1 + '@jest/reporters': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.8.1 exit: 0.1.2 - graceful-fs: 4.2.8 - jest-changed-files: 27.4.2 - jest-config: 27.4.6_ts-node@10.4.0 - jest-haste-map: 27.4.6 - jest-message-util: 27.4.6 - jest-regex-util: 27.4.0 - jest-resolve: 27.4.6 - jest-resolve-dependencies: 27.4.6 - jest-runner: 27.4.6 - jest-runtime: 27.4.6 - jest-snapshot: 27.4.6 - jest-util: 27.4.2 - jest-validate: 27.4.6 - jest-watcher: 27.4.6 + graceful-fs: 4.2.9 + jest-changed-files: 27.5.1 + jest-config: 27.5.1_ts-node@10.4.0 + jest-haste-map: 27.5.1 + jest-message-util: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-resolve-dependencies: 27.5.1 + jest-runner: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + jest-watcher: 27.5.1 micromatch: 4.0.4 rimraf: 3.0.2 slash: 3.0.0 strip-ansi: 6.0.1 transitivePeerDependencies: - - '@babel/core' - bufferutil - canvas - supports-color @@ -1545,39 +1285,46 @@ packages: - utf-8-validate dev: true - /@jest/environment/27.4.6: - resolution: {integrity: sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==} + /@jest/create-cache-key-function/27.5.1: + resolution: {integrity: sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/fake-timers': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 - jest-mock: 27.4.6 + '@jest/types': 27.5.1 dev: true - /@jest/fake-timers/27.4.6: - resolution: {integrity: sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==} + /@jest/environment/27.5.1: + resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - '@sinonjs/fake-timers': 8.0.1 - '@types/node': 16.11.19 - jest-message-util: 27.4.6 - jest-mock: 27.4.6 - jest-util: 27.4.2 + '@jest/fake-timers': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 + jest-mock: 27.5.1 + dev: true + + /@jest/fake-timers/27.5.1: + resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.5.1 + '@sinonjs/fake-timers': 8.1.0 + '@types/node': 17.0.18 + jest-message-util: 27.5.1 + jest-mock: 27.5.1 + jest-util: 27.5.1 dev: true - /@jest/globals/27.4.6: - resolution: {integrity: sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw==} + /@jest/globals/27.5.1: + resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/environment': 27.4.6 - '@jest/types': 27.4.2 - expect: 27.4.6 + '@jest/environment': 27.5.1 + '@jest/types': 27.5.1 + expect: 27.5.1 dev: true - /@jest/reporters/27.4.6: - resolution: {integrity: sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ==} + /@jest/reporters/27.5.1: + resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -1586,79 +1333,79 @@ packages: optional: true dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 27.4.6 - '@jest/test-result': 27.4.6 - '@jest/transform': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/console': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 glob: 7.2.0 - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 istanbul-lib-coverage: 3.2.0 istanbul-lib-instrument: 5.1.0 istanbul-lib-report: 3.0.0 istanbul-lib-source-maps: 4.0.1 istanbul-reports: 3.1.3 - jest-haste-map: 27.4.6 - jest-resolve: 27.4.6 - jest-util: 27.4.2 - jest-worker: 27.4.6 + jest-haste-map: 27.5.1 + jest-resolve: 27.5.1 + jest-util: 27.5.1 + jest-worker: 27.5.1 slash: 3.0.0 source-map: 0.6.1 string-length: 4.0.2 terminal-link: 2.1.1 - v8-to-istanbul: 8.1.0 + v8-to-istanbul: 8.1.1 transitivePeerDependencies: - supports-color dev: true - /@jest/source-map/27.4.0: - resolution: {integrity: sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==} + /@jest/source-map/27.5.1: + resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: callsites: 3.1.0 - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 source-map: 0.6.1 dev: true - /@jest/test-result/27.4.6: - resolution: {integrity: sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ==} + /@jest/test-result/27.5.1: + resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/console': 27.4.6 - '@jest/types': 27.4.2 - '@types/istanbul-lib-coverage': 2.0.3 + '@jest/console': 27.5.1 + '@jest/types': 27.5.1 + '@types/istanbul-lib-coverage': 2.0.4 collect-v8-coverage: 1.0.1 dev: true - /@jest/test-sequencer/27.4.6: - resolution: {integrity: sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw==} + /@jest/test-sequencer/27.5.1: + resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/test-result': 27.4.6 - graceful-fs: 4.2.8 - jest-haste-map: 27.4.6 - jest-runtime: 27.4.6 + '@jest/test-result': 27.5.1 + graceful-fs: 4.2.9 + jest-haste-map: 27.5.1 + jest-runtime: 27.5.1 transitivePeerDependencies: - supports-color dev: true - /@jest/transform/27.4.6: - resolution: {integrity: sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw==} + /@jest/transform/27.5.1: + resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/core': 7.15.8 - '@jest/types': 27.4.2 + '@babel/core': 7.16.7 + '@jest/types': 27.5.1 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 1.8.0 fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.8 - jest-haste-map: 27.4.6 - jest-regex-util: 27.4.0 - jest-util: 27.4.2 + graceful-fs: 4.2.9 + jest-haste-map: 27.5.1 + jest-regex-util: 27.5.1 + jest-util: 27.5.1 micromatch: 4.0.4 pirates: 4.0.4 slash: 3.0.0 @@ -1668,20 +1415,19 @@ packages: - supports-color dev: true - /@jest/types/27.4.2: - resolution: {integrity: sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==} + /@jest/types/27.5.1: + resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@types/istanbul-lib-coverage': 2.0.3 + '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 16.11.19 + '@types/node': 17.0.18 '@types/yargs': 16.0.4 chalk: 4.1.2 dev: true - /@js-joda/core/3.2.0: - resolution: {integrity: sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==} - dev: true + /@js-joda/core/4.3.1: + resolution: {integrity: sha512-oeaetlodcqVsiZDxnEcqsbs+sXBkASxua0mXs5OXuPQXz3/wdPTMlxwfQ4z2HKcOik3S9voW3QJkp/KLWDhvRQ==} /@microsoft/api-extractor-model/7.15.2: resolution: {integrity: sha512-qgxKX/s6vo3nCVLhP0Ds7555QrErhcYHEok5/KyEZ7iR8J5M5oldD1eJJQmtEdVF5IzmnPPbxx1nRvfgA674LQ==} @@ -1745,24 +1491,29 @@ packages: engines: {node: '>=8.0.0'} dev: true - /@prisma/debug/3.7.0: - resolution: {integrity: sha512-3FdQRGUt2zSe1D+RnCh2wmbCiMmhX+BKNRnC6Ic8KHayXMbEuRR4Ofgt0AZHRCdEQBwVFvM2Yep9zN3hNnWssw==} + /@opentelemetry/api/1.0.4: + resolution: {integrity: sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==} + engines: {node: '>=8.0.0'} + + /@prisma/debug/3.11.0: + resolution: {integrity: sha512-hbOU50++HdE0Xdt0FenrVvCteTvRg8EHNGKkxa1jWIB8O2o0bkm5igOlhfYGkvHZ3H1GK35oZp7rllMVeMM4ig==} dependencies: '@types/debug': 4.1.7 ms: 2.1.3 + strip-ansi: 6.0.1 - /@prisma/engines-version/3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908: - resolution: {integrity: sha512-rYqz1lmLQHvfBSDzF/kqsgSLFNu3VJWG4sRwTJoDfHD10r/ecfuEPaOBRXt55hjNfVttDf6eUZ2tWvpBc9Ji6Q==} + /@prisma/engines-version/3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77: + resolution: {integrity: sha512-o2iAjhWH7rPkIxqlbC417VRJ3u0ng9+l4HJdQy6OqerP7iO7haFc5zqP+/0VJekbACQ/GuCpL9lhq80eGGFnkA==} - /@prisma/engines/3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908: - resolution: {integrity: sha512-WjF2BhQ9elZEWfp5lFhLQaUd0gKdwfElchqW82FYo14TnXv4qAAQEWBKBr7RttD9X39sjNiu3nlZhwGGB176qw==} + /@prisma/engines/3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77: + resolution: {integrity: sha512-fhacvGqsUWXFqxGqOKzTt9mXvl0loNvKcZoMHYOk18qrEXO1t3uj4x87RCa4hGhsqVyCibse9JxdOX5tnG6Kxg==} requiresBuild: true - /@prisma/fetch-engine/3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908: - resolution: {integrity: sha512-WgXlyKHONjastsefmCwrAGLaL49w9JzlZJCBoKNJJwxojUYFj8vmQYno0FGanI/GAQTkMoTLHFmAoA7S/83/AQ==} + /@prisma/fetch-engine/3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77: + resolution: {integrity: sha512-y/+QlPlQ7HMbzAu5KMhAYIRtMrbymUkEXDuFlX2nlTwQZtSjHwCz1xpXEtH3y+s0HHMM/fytu/GIiXJ+Su+I4w==} dependencies: - '@prisma/debug': 3.7.0 - '@prisma/get-platform': 3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908 + '@prisma/debug': 3.11.0 + '@prisma/get-platform': 3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77 chalk: 4.1.2 execa: 5.1.1 find-cache-dir: 3.3.2 @@ -1770,7 +1521,7 @@ packages: http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.0 make-dir: 3.1.0 - node-fetch: 2.6.6 + node-fetch: 2.6.7 p-filter: 2.1.0 p-map: 4.0.0 p-retry: 4.6.1 @@ -1779,22 +1530,23 @@ packages: temp-dir: 2.0.0 tempy: 1.0.1 transitivePeerDependencies: + - encoding - supports-color - /@prisma/get-platform/3.8.0-31.9ca223420d3b050064a6f4fd76240a96b14d3908: - resolution: {integrity: sha512-5nPph2U1lohU/ELrMIFsAAZibLURPF+9yv43lpBYEwMYV7QBvG3sB5k0FPoPMHe+ToCn14SBlyBmpxCTiuXW8w==} + /@prisma/get-platform/3.12.0-16.f2e63a76e8eed99d99f0eb65596c7677b70a1e77: + resolution: {integrity: sha512-KZLHySOJMmrSdj4cPyvYeQz+TyYlvrSPcXQ5NXA8lprwgW7YGXHc2c0URFN/rMLipqBMVqcQjvpm9yNGMAR3Mw==} dependencies: - '@prisma/debug': 3.7.0 + '@prisma/debug': 3.11.0 - /@prisma/studio-common/0.452.0: - resolution: {integrity: sha512-bYiRFyo0yFCKaQifJ+kcxY9EWxbENDJLTZzVBQwDUhEmUdpMH6lnyJngXbp4niWyUqPtDQfL3Ozpx7lfpUbiHg==} + /@prisma/studio-common/0.458.0: + resolution: {integrity: sha512-4j4dBsq3bw9hRb4XEYv4M/0Kq2asObUmQWsA2jaqvHYt43n1s5E9pra2Pt7PSKKk8/6pZSmi7Lsl1GIhCV/mUw==} engines: {node: '>= 12'} dependencies: buffer: 6.0.3 dev: true - /@prisma/studio-pcw/0.452.0: - resolution: {integrity: sha512-DXLv2pw5VaZsBIh3SiroRrMgcojWWrhhQIhLjHcHtM/HkZJurB1DO3Wpk5xb7DUYUnA3bkOG681ApuW56je0dA==} + /@prisma/studio-pcw/0.458.0: + resolution: {integrity: sha512-8rgvhgbaQpc4BUaxDIAorTm2yOzGPRwwuIGdM3WoD9YQyuFBpHE3xGR2FBABP8v89qcB9YLsGQ9wgyfrRURl+g==} engines: {node: '>= 12'} peerDependencies: '@prisma/client': '*' @@ -1806,15 +1558,15 @@ packages: - supports-color dev: true - /@prisma/studio-server/0.452.0: - resolution: {integrity: sha512-zYqWtAVhBgoGlg8C+IHVEMq8uY9Ixnt2zT3KLtiM7iEtG74w7YpIibhuvHFe8mLwqq4ronhARtvg5KLM6KgFng==} + /@prisma/studio-server/0.458.0: + resolution: {integrity: sha512-kTRXClg14wIYagy8zYQmB6vMfEu3mz4r8rJ+eia+GUWQ/W0aqXznOR6aA/v/FSR9GJAgZN5n5wnsexymETQ88w==} engines: {node: '>= 12'} peerDependencies: '@prisma/sdk': '*' dependencies: - '@prisma/studio': 0.452.0 - '@prisma/studio-common': 0.452.0 - '@prisma/studio-pcw': 0.452.0 + '@prisma/studio': 0.458.0 + '@prisma/studio-common': 0.458.0 + '@prisma/studio-pcw': 0.458.0 checkpoint-client: 1.1.20 cors: 2.8.5 debug: 4.3.3 @@ -1824,8 +1576,8 @@ packages: - supports-color dev: true - /@prisma/studio/0.452.0: - resolution: {integrity: sha512-GjjXLjxs5tkHImcrNBIBWKlnGgB9X1gwn3Z4AgVQjvB4rXQhwchpP2ii1VR16wNqK03JKYF0cjM4XNKf1C/VUg==} + /@prisma/studio/0.458.0: + resolution: {integrity: sha512-59t1c5HPWVsUiwQqKsVB6XCWmdcM4C1zIEbpDX3rYDBsTtHx6IPilwPTE6yoGA7EUMdzQD+1ypeYX7JJ6Y802g==} dev: true /@rushstack/node-core-library/3.44.3: @@ -1878,8 +1630,8 @@ packages: type-detect: 4.0.8 dev: true - /@sinonjs/fake-timers/8.0.1: - resolution: {integrity: sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==} + /@sinonjs/fake-timers/8.1.0: + resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} dependencies: '@sinonjs/commons': 1.8.3 dev: true @@ -1894,15 +1646,160 @@ packages: engines: {node: '>= 12.13.0', npm: '>= 6.12.0'} dependencies: '@slack/types': 1.10.0 - '@types/node': 16.11.15 + '@types/node': 17.0.8 axios: 0.21.4 transitivePeerDependencies: - debug dev: true + /@swc/core-android-arm-eabi/1.2.141: + resolution: {integrity: sha512-rkp8KPR93/H25KL+nGZqDZahTLrW6ub09GsjzfZWTijAeOn0NnLLWzSdY60UTbvBUz/GJP6ueNWmV8V8q8MkKw==} + engines: {node: '>=10'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@swc/core-android-arm64/1.2.141: + resolution: {integrity: sha512-S9wNosJZA463nu+MHHv9xBwwe4KehEiBpKyk9gytGgblCD0aXa6Seb6CtsoZbo3C/Q881sVi9JG8COXFRFby/g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@swc/core-darwin-arm64/1.2.141: + resolution: {integrity: sha512-jlWgQw+S208aETBH2mBZUWknObJQOMk1iuhxdqMsKzFSnmSnitEtCNIP55LkBHdvG8/k5elR6HQ0JPsEnQSiwA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@swc/core-darwin-x64/1.2.141: + resolution: {integrity: sha512-fr4BXQhZe7SrCepgYeBedEq5NLO5hpUNoC84NN9njygP0xe+HP0SJkCHZ0INKHdBoQV+0qdl/JWZnYTSoOD9Hg==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@swc/core-freebsd-x64/1.2.141: + resolution: {integrity: sha512-BbYv36t2vnZ9A1PID5/tLv64/dPxFlp6JAtGDPhpc53I6WXORHDyL9oI8FYL0zLYByx1nHEBnu9ApBjmMEGfPw==} + engines: {node: '>=10'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm-gnueabihf/1.2.141: + resolution: {integrity: sha512-GhXllm5F2aKs1uNn7Se2dPkszKPm0JJtPSMxalcn+axiNVaTreXs0AnTploj/9mwjNzYibVgeefbbQRJ/dPH4g==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-gnu/1.2.141: + resolution: {integrity: sha512-KkhDgTAT1zac4D3jAzLgDkjCjNg/YhVW4kqHNR6yZVO8E8SNd2mfyGKpzI8xpZzqH9VF8MUJ3tcfZEa+O3q57A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-musl/1.2.141: + resolution: {integrity: sha512-5q+OfJM+FGpvzTyET8vuLY4GNKdiEOTtS5Td4oWQHQvmy6swUE/+WFveaNrIpbv9W2fMvXINHILeYz0fsBjzcg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-x64-gnu/1.2.141: + resolution: {integrity: sha512-IR84Sp7Jftsot/ZSuLgkoIHNsAMMzsGtT28oBNWlEcIEGSjps9lAd4N1uRFo9nK35fYjQHxQ/0bujbHqeO7hhQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-x64-musl/1.2.141: + resolution: {integrity: sha512-sV7qc71++h19pp7FyU+1FWEVSHeghuGO67/VKNYdo6NpJhIuR4F0J76H6WP2hMlLgvWCd/lXudljKr0vDBFW5g==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-arm64-msvc/1.2.141: + resolution: {integrity: sha512-cqsuUOP+MmuKZ6KR5CaC3l6pUkULGpSDjmbFtoSTjuduu144GQ2HOpJslxOMPTkJbDm2fVYYSlPZTyIbBrCj1g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-ia32-msvc/1.2.141: + resolution: {integrity: sha512-jkHWFwgTjOl9HChJpl1gZPdPSUUhwOZ/3a/SBnlrbuePcfro3DIbJysIcizpJtCGtnX7U3XECAzZn8c03OiKfg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-x64-msvc/1.2.141: + resolution: {integrity: sha512-qCFMX/6HtBksLZeVB/jrbxZ1TxqEac03zvRGDe3N4ZVBtMZi7nfayJTsYRrvfw87XOegIz5mEWfShxEy44FtGw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core/1.2.141: + resolution: {integrity: sha512-etjy0pWW2i3BDpTtg72CzFW6m91g3WC8incE82w37tll9easR9fJE4+njs1h4fP164xAiyAXOfsBECxsfH+t6A==} + engines: {node: '>=10'} + optionalDependencies: + '@swc/core-android-arm-eabi': 1.2.141 + '@swc/core-android-arm64': 1.2.141 + '@swc/core-darwin-arm64': 1.2.141 + '@swc/core-darwin-x64': 1.2.141 + '@swc/core-freebsd-x64': 1.2.141 + '@swc/core-linux-arm-gnueabihf': 1.2.141 + '@swc/core-linux-arm64-gnu': 1.2.141 + '@swc/core-linux-arm64-musl': 1.2.141 + '@swc/core-linux-x64-gnu': 1.2.141 + '@swc/core-linux-x64-musl': 1.2.141 + '@swc/core-win32-arm64-msvc': 1.2.141 + '@swc/core-win32-ia32-msvc': 1.2.141 + '@swc/core-win32-x64-msvc': 1.2.141 + dev: true + + /@swc/jest/0.2.17_@swc+core@1.2.141: + resolution: {integrity: sha512-n/g989+O8xxMcTZnP0phDrrgezGZBQBf7cX4QuzEsn07QkWbqmMsfaCxdF0kzajXublXWJ8yk5vRe3VNk1tczA==} + engines: {npm: '>= 7.0.0'} + peerDependencies: + '@swc/core': '*' + dependencies: + '@jest/create-cache-key-function': 27.5.1 + '@swc/core': 1.2.141 + dev: true + /@tediousjs/connection-string/0.3.0: resolution: {integrity: sha512-d/keJiNKfpHo+GmSB8QcsAwBx8h+V1UbdozA5TD+eSLXprNY53JAYub47J9evsSKWDdNG5uVj0FiMozLKuzowQ==} - dev: true /@timsuchanek/copy/1.4.5: resolution: {integrity: sha512-N4+2/DvfwzQqHYL/scq07fv8yXbZc6RyUxKJoE8Clm14JpLOf9yNI4VB4D6RsV3h9zgzZ4loJUydHKM7pp3blw==} @@ -1919,7 +1816,6 @@ packages: /@tootallnate/once/1.1.2: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} - dev: true /@tootallnate/once/2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} @@ -1950,33 +1846,33 @@ packages: resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} dev: true - /@types/babel__core/7.1.16: - resolution: {integrity: sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==} + /@types/babel__core/7.1.18: + resolution: {integrity: sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==} dependencies: - '@babel/parser': 7.15.8 - '@babel/types': 7.15.6 - '@types/babel__generator': 7.6.3 + '@babel/parser': 7.16.8 + '@babel/types': 7.16.8 + '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.14.2 dev: true - /@types/babel__generator/7.6.3: - resolution: {integrity: sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==} + /@types/babel__generator/7.6.4: + resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true /@types/babel__template/7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.15.8 - '@babel/types': 7.15.6 + '@babel/parser': 7.16.8 + '@babel/types': 7.16.8 dev: true /@types/babel__traverse/7.14.2: resolution: {integrity: sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==} dependencies: - '@babel/types': 7.15.6 + '@babel/types': 7.16.8 dev: true /@types/benchmark/2.1.1: @@ -1986,7 +1882,7 @@ packages: /@types/cross-spawn/6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.18 dev: false /@types/debug/4.1.7: @@ -1994,8 +1890,8 @@ packages: dependencies: '@types/ms': 0.7.31 - /@types/eslint/7.28.2: - resolution: {integrity: sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==} + /@types/eslint/7.29.0: + resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==} dependencies: '@types/estree': 0.0.50 '@types/json-schema': 7.0.9 @@ -2008,40 +1904,39 @@ packages: /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 16.11.6 + '@types/node': 17.0.8 dev: true /@types/geojson/7946.0.8: resolution: {integrity: sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==} - dev: true /@types/glob/7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 3.0.5 - '@types/node': 16.11.15 + '@types/node': 17.0.8 dev: true /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 16.11.19 + '@types/node': 17.0.18 dev: true /@types/graphviz/0.0.34: resolution: {integrity: sha512-5pyobgT+/NhwKy/LMLw14xFInvYXBPx4ITc2a5FvZbm6hcudcP73DpTKTlaZbjr8fdNAkaK9KdP8GAEF0iBwlQ==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.8 dev: true - /@types/istanbul-lib-coverage/2.0.3: - resolution: {integrity: sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==} + /@types/istanbul-lib-coverage/2.0.4: + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} dev: true /@types/istanbul-lib-report/3.0.0: resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} dependencies: - '@types/istanbul-lib-coverage': 2.0.3 + '@types/istanbul-lib-coverage': 2.0.4 dev: true /@types/istanbul-reports/3.0.1: @@ -2050,11 +1945,11 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest/27.4.0: - resolution: {integrity: sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==} + /@types/jest/27.4.1: + resolution: {integrity: sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==} dependencies: - jest-diff: 27.4.6 - pretty-format: 27.4.6 + jest-matcher-utils: 27.5.1 + pretty-format: 27.5.1 dev: true /@types/js-levenshtein/1.1.1: @@ -2065,6 +1960,10 @@ packages: resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==} dev: true + /@types/json5/0.0.29: + resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=} + dev: true + /@types/minimatch/3.0.5: resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} dev: true @@ -2073,89 +1972,81 @@ packages: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} dev: true - /@types/minipass/3.1.0: - resolution: {integrity: sha512-b2yPKwCrB8x9SB65kcCistMoe3wrYnxxt5rJSZ1kprw0uOXvhuKi9kTQ746Y+Pbqoh+9C0N4zt0ztmTnG9yg7A==} + /@types/minipass/3.1.2: + resolution: {integrity: sha512-foLGjgrJkUjLG/o2t2ymlZGEoBNBa/TfoUZ7oCTkOjP1T43UGBJspovJou/l3ZuHvye2ewR5cZNtp2zyWgILMA==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.18 dev: true /@types/ms/0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} - /@types/mssql/6.0.8: - resolution: {integrity: sha512-N3dr3o1c6EXhHhhNRaKpLTdAoXT/s6qDEJET5FID2gFCj58vIV9q/7RtkvYdE6ntpkJF5F9hpURhxT/oC62yLw==} + /@types/mssql/7.1.5: + resolution: {integrity: sha512-+I/4wNTUlZVxWSDo8BBo3Hw7aAKvmH+0JiovF3aW7NqjOvZZNa1xeqyjp7BBiktZx1wiV/ZKAxi21viAR53vjQ==} dependencies: - '@types/node': 16.11.15 - '@types/tedious': 4.0.5 + '@types/node': 17.0.18 + '@types/tedious': 4.0.6 + tarn: 3.0.2 dev: true /@types/node-fetch/2.5.12: resolution: {integrity: sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==} dependencies: - '@types/node': 16.11.17 + '@types/node': 17.0.18 form-data: 3.0.1 - dev: true /@types/node/12.20.24: resolution: {integrity: sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==} dev: true - /@types/node/12.20.39: - resolution: {integrity: sha512-U7PMwkDmc3bnL0e4U8oA0POpi1vfsYDc+DEUS2+rPxm9NlLcW1dBa5JcRhO633PoPUcCSWMNXrMsqhmAVEo+IQ==} - dev: true - - /@types/node/14.18.3: - resolution: {integrity: sha512-GtTH2crF4MtOIrrAa+jgTV9JX/PfoUCYr6MiZw7O/dkZu5b6gm5dc1nAL0jwGo4ortSBBtGyeVaxdC8X6V+pLg==} + /@types/node/12.20.47: + resolution: {integrity: sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==} dev: true - /@types/node/16.11.11: - resolution: {integrity: sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==} + /@types/node/14.18.12: + resolution: {integrity: sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==} dev: true - /@types/node/16.11.15: - resolution: {integrity: sha512-LMGR7iUjwZRxoYnfc9+YELxwqkaLmkJlo4/HUvOMyGvw9DaHO0gtAbH2FUdoFE6PXBTYZIT7x610r7kdo8o1fQ==} - - /@types/node/16.11.17: - resolution: {integrity: sha512-C1vTZME8cFo8uxY2ui41xcynEotVkczIVI5AjLmy5pkpBv/FtG+jhtOlfcPysI8VRVwoOMv6NJm44LGnoMSWkw==} + /@types/node/16.11.26: + resolution: {integrity: sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==} dev: true - /@types/node/16.11.19: - resolution: {integrity: sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng==} + /@types/node/16.6.2: + resolution: {integrity: sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==} dev: true - /@types/node/16.11.6: - resolution: {integrity: sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==} - dev: true + /@types/node/17.0.18: + resolution: {integrity: sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==} - /@types/node/16.6.2: - resolution: {integrity: sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==} + /@types/node/17.0.8: + resolution: {integrity: sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==} dev: true /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} - /@types/pg/8.6.3: - resolution: {integrity: sha512-P0RrXJcw1hPS+KF0nBCC3FEEdZBfRsHbYtAzbY2QTc0gC4jFQvjQxIKXs0X/NgPhPI4DbAzdeW7WMCjaWjT7Pg==} + /@types/pg/8.6.5: + resolution: {integrity: sha512-tOkGtAqRVkHa/PVZicq67zuujI4Oorfglsr2IbKofDwBSysnaqSx7W1mDqFqdkGE6Fbgh+PZAl0r/BWON/mozw==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.18 pg-protocol: 1.5.0 pg-types: 2.2.0 dev: true - /@types/prettier/2.4.1: - resolution: {integrity: sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==} + /@types/prettier/2.4.3: + resolution: {integrity: sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==} dev: true /@types/prompts/2.0.14: resolution: {integrity: sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.18 dev: true /@types/redis/2.8.32: resolution: {integrity: sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.8 dev: true /@types/resolve/1.20.1: @@ -2169,7 +2060,7 @@ packages: resolution: {integrity: sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==} dependencies: '@types/glob': 7.2.0 - '@types/node': 16.11.6 + '@types/node': 17.0.8 dev: true /@types/shell-quote/1.7.1: @@ -2179,7 +2070,7 @@ packages: /@types/sqlite3/3.1.8: resolution: {integrity: sha512-sQMt/qnyUWnqiTcJXm5ZfNPIBeJ/DVvJDwxw+0tAxPJvadzfiP1QhryO1JOR6t1yfb8NpzQb/Rud06mob5laIA==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.18 dev: true /@types/stack-utils/2.0.1: @@ -2189,32 +2080,30 @@ packages: /@types/stoppable/1.1.1: resolution: {integrity: sha512-b8N+fCADRIYYrGZOcmOR8ZNBOqhktWTB/bMUl5LvGtT201QKJZOOH5UsFyI3qtteM6ZAJbJqZoBcLqqxKIwjhw==} dependencies: - '@types/node': 16.11.17 - dev: true + '@types/node': 17.0.18 /@types/tar/6.1.1: resolution: {integrity: sha512-8mto3YZfVpqB1CHMaYz1TUYIQfZFbh/QbEq5Hsn6D0ilCfqRVCdalmc89B7vi3jhl9UYIk+dWDABShNfOkv5HA==} dependencies: - '@types/minipass': 3.1.0 - '@types/node': 16.11.15 + '@types/minipass': 3.1.2 + '@types/node': 17.0.18 dev: true - /@types/tedious/4.0.5: - resolution: {integrity: sha512-zlnChTP63Bds6kMBuKOR+qJPB9wcYf1zVm78qiXTnT1gbcU6wdTmSp28cd2BPxePy4mrGM6TnQG1fmHxQW1pZw==} + /@types/tedious/4.0.6: + resolution: {integrity: sha512-IrcBDpVpaSGBDoUImdAwoJhMGEJZhur1IzfZRqnbjXvFnsWmny7X1CGDSj/B3yzRF9XVdbgLrQ4UA8cHyTCyjg==} dependencies: - '@types/node': 16.11.15 + '@types/node': 17.0.18 dev: true /@types/tunnel/0.0.3: resolution: {integrity: sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==} dependencies: - '@types/node': 16.11.17 - dev: true + '@types/node': 17.0.18 - /@types/ws/8.2.2: - resolution: {integrity: sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==} + /@types/ws/8.5.3: + resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} dependencies: - '@types/node': 16.11.11 + '@types/node': 17.0.18 dev: true /@types/yargs-parser/20.2.1: @@ -2245,7 +2134,7 @@ packages: debug: 4.3.3 eslint: 8.6.0 functional-red-black-tree: 1.0.1 - ignore: 5.1.8 + ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.5 tsutils: 3.21.0_typescript@4.5.4 @@ -2292,6 +2181,14 @@ packages: - supports-color dev: true + /@typescript-eslint/scope-manager/5.10.1: + resolution: {integrity: sha512-Lyvi559Gvpn94k7+ElXNMEnXu/iundV5uFmCUNnftbFrUbAJ1WBoaGgkbOBm07jVZa682oaBU37ao/NGGX4ZDg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.10.1 + '@typescript-eslint/visitor-keys': 5.10.1 + dev: true + /@typescript-eslint/scope-manager/5.9.0: resolution: {integrity: sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2300,30 +2197,56 @@ packages: '@typescript-eslint/visitor-keys': 5.9.0 dev: true - /@typescript-eslint/type-utils/5.9.0_eslint@8.6.0+typescript@4.5.4: - resolution: {integrity: sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==} + /@typescript-eslint/type-utils/5.9.0_eslint@8.6.0+typescript@4.5.4: + resolution: {integrity: sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/experimental-utils': 5.9.0_eslint@8.6.0+typescript@4.5.4 + debug: 4.3.3 + eslint: 8.6.0 + tsutils: 3.21.0_typescript@4.5.4 + typescript: 4.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types/5.10.1: + resolution: {integrity: sha512-ZvxQ2QMy49bIIBpTqFiOenucqUyjTQ0WNLhBM6X1fh1NNlYAC6Kxsx8bRTY3jdYsYg44a0Z/uEgQkohbR0H87Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/types/5.9.0: + resolution: {integrity: sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree/5.10.1_typescript@4.5.4: + resolution: {integrity: sha512-PwIGnH7jIueXv4opcwEbVGDATjGPO1dx9RkUl5LlHDSe+FXxPwFL5W/qYd5/NHr7f6lo/vvTrAzd0KlQtRusJQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - eslint: '*' typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.9.0_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/types': 5.10.1 + '@typescript-eslint/visitor-keys': 5.10.1 debug: 4.3.3 - eslint: 8.6.0 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.5 tsutils: 3.21.0_typescript@4.5.4 typescript: 4.5.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types/5.9.0: - resolution: {integrity: sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/typescript-estree/5.9.0_typescript@4.5.4: resolution: {integrity: sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2345,6 +2268,32 @@ packages: - supports-color dev: true + /@typescript-eslint/utils/5.10.1_eslint@8.6.0+typescript@4.5.4: + resolution: {integrity: sha512-RRmlITiUbLuTRtn/gcPRi4202niF+q7ylFLCKu4c+O/PcpRvZ/nAUwQ2G00bZgpWkhrNLNnvhZLbDn8Ml0qsQw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.9 + '@typescript-eslint/scope-manager': 5.10.1 + '@typescript-eslint/types': 5.10.1 + '@typescript-eslint/typescript-estree': 5.10.1_typescript@4.5.4 + eslint: 8.6.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys/5.10.1: + resolution: {integrity: sha512-NjQ0Xinhy9IL979tpoTRuLKxMc0zJC7QVSdeerXs2/QvOy2yRkzX5dRb10X5woNUdJgU8G3nYRDlI33sq1K4YQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.10.1 + eslint-visitor-keys: 3.2.0 + dev: true + /@typescript-eslint/visitor-keys/5.9.0: resolution: {integrity: sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2353,11 +2302,6 @@ packages: eslint-visitor-keys: 3.1.0 dev: true - /@xmldom/xmldom/0.7.5: - resolution: {integrity: sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==} - engines: {node: '>=10.0.0'} - dev: true - /abab/2.0.5: resolution: {integrity: sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==} dev: true @@ -2366,18 +2310,11 @@ packages: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: true - /abort-controller/3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - dependencies: - event-target-shim: 5.0.1 - dev: true - /accepts/1.3.7: resolution: {integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==} engines: {node: '>= 0.6'} dependencies: - mime-types: 2.1.33 + mime-types: 2.1.34 negotiator: 0.6.2 dev: true @@ -2412,34 +2349,12 @@ packages: hasBin: true dev: true - /acorn/8.5.0: - resolution: {integrity: sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - /acorn/8.7.0: resolution: {integrity: sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /adal-node/0.2.3_debug@4.3.3: - resolution: {integrity: sha512-gMKr8RuYEYvsj7jyfCv/4BfKToQThz20SP71N3AtFn3ia3yAR8Qt2T3aVQhuJzunWs2b38ZsQV0qsZPdwZr7VQ==} - engines: {node: '>= 0.6.15'} - dependencies: - '@xmldom/xmldom': 0.7.5 - async: 2.6.3 - axios: 0.21.4_debug@4.3.3 - date-utils: 1.2.21 - jws: 3.2.2 - underscore: 1.13.1 - uuid: 3.4.0 - xpath.js: 1.1.0 - transitivePeerDependencies: - - debug - dev: true - /agent-base/6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -2478,7 +2393,6 @@ packages: /ansi-regex/2.1.1: resolution: {integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=} engines: {node: '>=0.10.0'} - dev: true /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -2516,19 +2430,18 @@ packages: engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 - picomatch: 2.3.0 + picomatch: 2.3.1 dev: true /aproba/1.2.0: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} - dev: true /archiver-utils/2.1.0: resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} engines: {node: '>= 6'} dependencies: glob: 7.2.0 - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 lazystream: 1.0.1 lodash.defaults: 4.2.0 lodash.difference: 4.5.0 @@ -2544,7 +2457,7 @@ packages: engines: {node: '>= 10'} dependencies: archiver-utils: 2.1.0 - async: 3.2.1 + async: 3.2.3 buffer-crc32: 0.2.13 readable-stream: 3.6.0 readdir-glob: 1.1.1 @@ -2557,7 +2470,6 @@ packages: dependencies: delegates: 1.0.0 readable-stream: 2.3.7 - dev: true /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -2580,17 +2492,37 @@ packages: resolution: {integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=} dev: true + /array-includes/3.1.4: + resolution: {integrity: sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.3 + es-abstract: 1.19.1 + get-intrinsic: 1.1.1 + is-string: 1.0.7 + dev: true + /array-union/2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + /array.prototype.flat/1.2.5: + resolution: {integrity: sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.3 + es-abstract: 1.19.1 + dev: true + /arrify/1.0.1: resolution: {integrity: sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=} engines: {node: '>=0.10.0'} dev: true - /asn1/0.2.4: - resolution: {integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==} + /asn1/0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} dependencies: safer-buffer: 2.1.2 dev: true @@ -2605,19 +2537,12 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} - /async/2.6.3: - resolution: {integrity: sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==} - dependencies: - lodash: 4.17.21 - dev: true - - /async/3.2.1: - resolution: {integrity: sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==} + /async/3.2.3: + resolution: {integrity: sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==} dev: false /asynckit/0.4.0: resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} - dev: true /available-typed-arrays/1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} @@ -2637,7 +2562,7 @@ packages: /axios/0.21.4: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: - follow-redirects: 1.14.4 + follow-redirects: 1.14.7 transitivePeerDependencies: - debug dev: true @@ -2645,24 +2570,24 @@ packages: /axios/0.21.4_debug@4.3.3: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: - follow-redirects: 1.14.4_debug@4.3.3 + follow-redirects: 1.14.7_debug@4.3.3 transitivePeerDependencies: - debug - dev: true - /babel-jest/27.4.6: - resolution: {integrity: sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg==} + /babel-jest/27.5.1_@babel+core@7.16.7: + resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@jest/transform': 27.4.6 - '@jest/types': 27.4.2 - '@types/babel__core': 7.1.16 + '@babel/core': 7.16.7 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/babel__core': 7.1.18 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.4.0 + babel-preset-jest: 27.5.1_@babel+core@7.16.7 chalk: 4.1.2 - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 slash: 3.0.0 transitivePeerDependencies: - supports-color @@ -2672,7 +2597,7 @@ packages: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} dependencies: - '@babel/helper-plugin-utils': 7.14.5 + '@babel/helper-plugin-utils': 7.16.7 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.1.0 @@ -2681,63 +2606,45 @@ packages: - supports-color dev: true - /babel-plugin-jest-hoist/27.4.0: - resolution: {integrity: sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==} + /babel-plugin-jest-hoist/27.5.1: + resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/template': 7.15.4 - '@babel/types': 7.15.6 - '@types/babel__core': 7.1.16 + '@babel/template': 7.16.7 + '@babel/types': 7.16.8 + '@types/babel__core': 7.1.18 '@types/babel__traverse': 7.14.2 dev: true - /babel-preset-current-node-syntax/1.0.1: + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.16.7: resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/plugin-syntax-async-generators': 7.8.4 - '@babel/plugin-syntax-bigint': 7.8.3 - '@babel/plugin-syntax-class-properties': 7.12.13 - '@babel/plugin-syntax-import-meta': 7.10.4 - '@babel/plugin-syntax-json-strings': 7.8.3 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3 - '@babel/plugin-syntax-numeric-separator': 7.10.4 - '@babel/plugin-syntax-object-rest-spread': 7.8.3 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3 - '@babel/plugin-syntax-optional-chaining': 7.8.3 - '@babel/plugin-syntax-top-level-await': 7.14.5 - dev: true - - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.15.8: - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.15.8 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.15.8 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.15.8 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.15.8 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.15.8 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.15.8 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.15.8 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.15.8 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.15.8 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.15.8 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.15.8 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.15.8 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.15.8 - dev: true - - /babel-preset-jest/27.4.0: - resolution: {integrity: sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==} + '@babel/core': 7.16.7 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.16.7 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.16.7 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.16.7 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.16.7 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.16.7 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.16.7 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.16.7 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.16.7 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.16.7 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.16.7 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.16.7 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.16.7 + dev: true + + /babel-preset-jest/27.5.1_@babel+core@7.16.7: + resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - babel-plugin-jest-hoist: 27.4.0 - babel-preset-current-node-syntax: 1.0.1 + '@babel/core': 7.16.7 + babel-plugin-jest-hoist: 27.5.1 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.16.7 dev: true /balanced-match/1.0.2: @@ -2783,7 +2690,6 @@ packages: buffer: 6.0.3 inherits: 2.0.4 readable-stream: 3.6.0 - dev: true /block-stream/0.0.9: resolution: {integrity: sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=} @@ -2825,13 +2731,13 @@ packages: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} dev: true - /browserslist/4.17.5: - resolution: {integrity: sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==} + /browserslist/4.19.1: + resolution: {integrity: sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001271 - electron-to-chromium: 1.3.880 + caniuse-lite: 1.0.30001299 + electron-to-chromium: 1.4.45 escalade: 3.1.1 node-releases: 2.0.1 picocolors: 1.0.0 @@ -2856,7 +2762,6 @@ packages: /buffer-equal-constant-time/1.0.1: resolution: {integrity: sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=} - dev: true /buffer-from/1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2865,7 +2770,6 @@ packages: /buffer-writer/2.0.0: resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} engines: {node: '>=4'} - dev: true /buffer/5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -2878,7 +2782,6 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: true /bytes/3.1.1: resolution: {integrity: sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==} @@ -2890,7 +2793,6 @@ packages: dependencies: function-bind: 1.1.1 get-intrinsic: 1.1.1 - dev: true /callsites/3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -2911,13 +2813,13 @@ packages: engines: {node: '>=6'} dev: true - /camelcase/6.2.0: - resolution: {integrity: sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==} + /camelcase/6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001271: - resolution: {integrity: sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==} + /caniuse-lite/1.0.30001299: + resolution: {integrity: sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==} dev: true /caseless/0.12.0: @@ -2955,6 +2857,20 @@ packages: ms: 2.1.3 node-fetch: 2.6.1 uuid: 8.3.2 + dev: true + + /checkpoint-client/1.1.21: + resolution: {integrity: sha512-bcrcnJncn6uGhj06IIsWvUBPyJWK1ZezDbLCJ//IQEYXkUobhGvOOBlHe9K5x0ZMkAZGinPB4T+lTUmFz/acWQ==} + dependencies: + ci-info: 3.3.0 + env-paths: 2.2.1 + fast-write-atomic: 0.2.1 + make-dir: 3.1.0 + ms: 2.1.3 + node-fetch: 2.6.7 + uuid: 8.3.2 + transitivePeerDependencies: + - encoding /chokidar/3.5.2: resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==} @@ -2973,7 +2889,6 @@ packages: /chownr/1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - dev: true /chownr/2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} @@ -2982,9 +2897,10 @@ packages: /ci-info/3.1.1: resolution: {integrity: sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ==} + dev: true - /ci-info/3.2.0: - resolution: {integrity: sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==} + /ci-info/3.3.0: + resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} /cjs-module-lexer/1.2.2: resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} @@ -3012,7 +2928,7 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: slice-ansi: 5.0.0 - string-width: 5.0.1 + string-width: 5.1.0 dev: true /cliui/7.0.4: @@ -3031,7 +2947,6 @@ packages: /code-point-at/1.1.0: resolution: {integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=} engines: {node: '>=0.10.0'} - dev: true /collect-v8-coverage/1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} @@ -3068,7 +2983,6 @@ packages: engines: {node: '>= 0.8'} dependencies: delayed-stream: 1.0.0 - dev: true /commander/2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -3096,7 +3010,6 @@ packages: /console-control-strings/1.1.0: resolution: {integrity: sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=} - dev: true /content-disposition/0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} @@ -3205,11 +3118,6 @@ packages: whatwg-url: 8.7.0 dev: true - /date-utils/1.2.21: - resolution: {integrity: sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=} - engines: {node: '>0.4.0'} - dev: true - /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} dependencies: @@ -3263,12 +3171,11 @@ packages: resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==} dev: true - /decompress-response/4.2.1: - resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} - engines: {node: '>=8'} + /decompress-response/6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} dependencies: - mimic-response: 2.1.0 - dev: true + mimic-response: 3.1.0 optional: true /dedent/0.7.0: @@ -3278,7 +3185,6 @@ packages: /deep-extend/0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} - dev: true /deep-is/0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -3300,8 +3206,8 @@ packages: resolution: {integrity: sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==} engines: {node: '>=10'} dependencies: - globby: 11.0.4 - graceful-fs: 4.2.8 + globby: 11.1.0 + graceful-fs: 4.2.9 is-glob: 4.0.3 is-path-cwd: 2.2.0 is-path-inside: 3.0.3 @@ -3312,27 +3218,24 @@ packages: /delayed-stream/1.0.0: resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=} engines: {node: '>=0.4.0'} - dev: true /delegates/1.0.0: resolution: {integrity: sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=} - dev: true /denque/1.5.1: resolution: {integrity: sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==} engines: {node: '>=0.10'} dev: true + /denque/2.0.1: + resolution: {integrity: sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==} + engines: {node: '>=0.10'} + /depd/1.1.2: resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=} engines: {node: '>= 0.6'} dev: true - /depd/2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dev: true - /destroy/1.0.4: resolution: {integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=} dev: true @@ -3343,13 +3246,18 @@ packages: hasBin: true dev: true + /detect-libc/2.0.0: + resolution: {integrity: sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw==} + engines: {node: '>=8'} + optional: true + /detect-newline/3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} dev: true - /diff-sequences/27.4.0: - resolution: {integrity: sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==} + /diff-sequences/27.5.1: + resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true @@ -3364,6 +3272,13 @@ packages: dependencies: path-type: 4.0.0 + /doctrine/2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + /doctrine/3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -3378,9 +3293,13 @@ packages: webidl-conversions: 5.0.0 dev: true - /dotenv/10.0.0: - resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} - engines: {node: '>=10'} + /dotenv/16.0.0: + resolution: {integrity: sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==} + engines: {node: '>=12'} + + /eastasianwidth/0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true /ecc-jsbn/0.1.2: resolution: {integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=} @@ -3394,14 +3313,13 @@ packages: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} dependencies: safe-buffer: 5.2.1 - dev: true /ee-first/1.1.1: resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} dev: true - /electron-to-chromium/1.3.880: - resolution: {integrity: sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw==} + /electron-to-chromium/1.4.45: + resolution: {integrity: sha512-czF9eYVuOmlY/vxyMQz2rGlNSjZpxNQYBe1gmQv7al171qOIhgyO9k7D5AKlgeTCSPKk+LHhj5ZyIdmEub9oNg==} dev: true /emittery/0.8.1: @@ -3455,12 +3373,12 @@ packages: has-symbols: 1.0.2 internal-slot: 1.0.3 is-callable: 1.2.4 - is-negative-zero: 2.0.1 + is-negative-zero: 2.0.2 is-regex: 1.1.4 is-shared-array-buffer: 1.0.1 is-string: 1.0.7 - is-weakref: 1.0.1 - object-inspect: 1.11.0 + is-weakref: 1.0.2 + object-inspect: 1.12.0 object-keys: 1.1.1 object.assign: 4.1.2 string.prototype.trimend: 1.0.4 @@ -3477,6 +3395,15 @@ packages: is-symbol: 1.0.4 dev: true + /esbuild-android-64/0.14.27: + resolution: {integrity: sha512-LuEd4uPuj/16Y8j6kqy3Z2E9vNY9logfq8Tq+oTE2PZVuNs3M1kj5Qd4O95ee66yDGb3isaOCV7sOLDwtMfGaQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /esbuild-android-arm64/0.13.14: resolution: {integrity: sha512-Q+Xhfp827r+ma8/DJgpMRUbDZfefsk13oePFEXEIJ4gxFbNv5+vyiYXYuKm43/+++EJXpnaYmEnu4hAKbAWYbA==} cpu: [arm64] @@ -3485,8 +3412,9 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.14.10: - resolution: {integrity: sha512-vzkTafHKoiMX4uIN1kBnE/HXYLpNT95EgGanVk6DHGeYgDolU0NBxjO7yZpq4ZGFPOx8384eAdDrBYhO11TAlQ==} + /esbuild-android-arm64/0.14.27: + resolution: {integrity: sha512-E8Ktwwa6vX8q7QeJmg8yepBYXaee50OdQS3BFtEHKrzbV45H4foMOeEE7uqdjGQZFBap5VAqo7pvjlyA92wznQ==} + engines: {node: '>=12'} cpu: [arm64] os: [android] requiresBuild: true @@ -3501,8 +3429,9 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.14.10: - resolution: {integrity: sha512-DJwzFVB95ZV7C3PQbf052WqaUuuMFXJeZJ0LKdnP1w+QOU0rlbKfX0tzuhoS//rOXUj1TFIwRuRsd0FX6skR7A==} + /esbuild-darwin-64/0.14.27: + resolution: {integrity: sha512-czw/kXl/1ZdenPWfw9jDc5iuIYxqUxgQ/Q+hRd4/3udyGGVI31r29LCViN2bAJgGvQkqyLGVcG03PJPEXQ5i2g==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] requiresBuild: true @@ -3517,8 +3446,9 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.14.10: - resolution: {integrity: sha512-RNaaoZDg3nsqs5z56vYCjk/VJ76npf752W0rOaCl5lO5TsgV9zecfdYgt7dtUrIx8b7APhVaNYud+tGsDOVC9g==} + /esbuild-darwin-arm64/0.14.27: + resolution: {integrity: sha512-BEsv2U2U4o672oV8+xpXNxN9bgqRCtddQC6WBh4YhXKDcSZcdNh7+6nS+DM2vu7qWIWNA4JbRG24LUUYXysimQ==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] requiresBuild: true @@ -3533,8 +3463,9 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.14.10: - resolution: {integrity: sha512-10B3AzW894u6bGZZhWiJOHw1uEHb4AFbUuBdyml1Ht0vIqd+KqWW+iY/yMwQAzILr2WJZqEhbOXRkJtY8aRqOw==} + /esbuild-freebsd-64/0.14.27: + resolution: {integrity: sha512-7FeiFPGBo+ga+kOkDxtPmdPZdayrSzsV9pmfHxcyLKxu+3oTcajeZlOO1y9HW+t5aFZPiv7czOHM4KNd0tNwCA==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] requiresBuild: true @@ -3549,8 +3480,9 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.14.10: - resolution: {integrity: sha512-mSQrKB7UaWvuryBTCo9leOfY2uEUSimAvcKIaUWbk5Hth9Sg+Try+qNA/NibPgs/vHkX0KFo/Rce6RPea+P15g==} + /esbuild-freebsd-arm64/0.14.27: + resolution: {integrity: sha512-8CK3++foRZJluOWXpllG5zwAVlxtv36NpHfsbWS7TYlD8S+QruXltKlXToc/5ZNzBK++l6rvRKELu/puCLc7jA==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] requiresBuild: true @@ -3565,8 +3497,9 @@ packages: dev: true optional: true - /esbuild-linux-32/0.14.10: - resolution: {integrity: sha512-lktF09JgJLZ63ANYHIPdYe339PDuVn19Q/FcGKkXWf+jSPkn5xkYzAabboNGZNUgNqSJ/vY7VrOn6UrBbJjgYA==} + /esbuild-linux-32/0.14.27: + resolution: {integrity: sha512-qhNYIcT+EsYSBClZ5QhLzFzV5iVsP1YsITqblSaztr3+ZJUI+GoK8aXHyzKd7/CKKuK93cxEMJPpfi1dfsOfdw==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] requiresBuild: true @@ -3581,8 +3514,9 @@ packages: dev: true optional: true - /esbuild-linux-64/0.14.10: - resolution: {integrity: sha512-K+gCQz2oLIIBI8ZM77e9sYD5/DwEpeYCrOQ2SYXx+R4OU2CT9QjJDi4/OpE7ko4AcYMlMW7qrOCuLSgAlEj4Wg==} + /esbuild-linux-64/0.14.27: + resolution: {integrity: sha512-ESjck9+EsHoTaKWlFKJpPZRN26uiav5gkI16RuI8WBxUdLrrAlYuYSndxxKgEn1csd968BX/8yQZATYf/9+/qg==} + engines: {node: '>=12'} cpu: [x64] os: [linux] requiresBuild: true @@ -3597,8 +3531,9 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.14.10: - resolution: {integrity: sha512-BYa60dZ/KPmNKYxtHa3LSEdfKWHcm/RzP0MjB4AeBPhjS0D6/okhaBesZIY9kVIGDyeenKsJNOmnVt4+dhNnvQ==} + /esbuild-linux-arm/0.14.27: + resolution: {integrity: sha512-JnnmgUBdqLQO9hoNZQqNHFWlNpSX82vzB3rYuCJMhtkuaWQEmQz6Lec1UIxJdC38ifEghNTBsF9bbe8dFilnCw==} + engines: {node: '>=12'} cpu: [arm] os: [linux] requiresBuild: true @@ -3613,8 +3548,9 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.14.10: - resolution: {integrity: sha512-+qocQuQvcp5wo/V+OLXxqHPc+gxHttJEvbU/xrCGE03vIMqraL4wMua8JQx0SWEnJCWP+Nhf//v8OSwz1Xr5kA==} + /esbuild-linux-arm64/0.14.27: + resolution: {integrity: sha512-no6Mi17eV2tHlJnqBHRLekpZ2/VYx+NfGxKcBE/2xOMYwctsanCaXxw4zapvNrGE9X38vefVXLz6YCF8b1EHiQ==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] requiresBuild: true @@ -3629,8 +3565,9 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.14.10: - resolution: {integrity: sha512-nmUd2xoBXpGo4NJCEWoaBj+n4EtDoLEvEYc8Z3aSJrY0Oa6s04czD1flmhd0I/d6QEU8b7GQ9U0g/rtBfhtxBg==} + /esbuild-linux-mips64le/0.14.27: + resolution: {integrity: sha512-NolWP2uOvIJpbwpsDbwfeExZOY1bZNlWE/kVfkzLMsSgqeVcl5YMen/cedRe9mKnpfLli+i0uSp7N+fkKNU27A==} + engines: {node: '>=12'} cpu: [mips64el] os: [linux] requiresBuild: true @@ -3645,16 +3582,27 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.14.10: - resolution: {integrity: sha512-vsOWZjm0rZix7HSmqwPph9arRVCyPtUpcURdayQDuIhMG2/UxJxpbdRaa//w4zYqcJzAWwuyH2PAlyy0ZNuxqQ==} + /esbuild-linux-ppc64le/0.14.27: + resolution: {integrity: sha512-/7dTjDvXMdRKmsSxKXeWyonuGgblnYDn0MI1xDC7J1VQXny8k1qgNp6VmrlsawwnsymSUUiThhkJsI+rx0taNA==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-s390x/0.14.10: - resolution: {integrity: sha512-knArKKZm0ypIYWOWyOT7+accVwbVV1LZnl2FWWy05u9Tyv5oqJ2F5+X2Vqe/gqd61enJXQWqoufXopvG3zULOg==} + /esbuild-linux-riscv64/0.14.27: + resolution: {integrity: sha512-D+aFiUzOJG13RhrSmZgrcFaF4UUHpqj7XSKrIiCXIj1dkIkFqdrmqMSOtSs78dOtObWiOrFCDDzB24UyeEiNGg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-s390x/0.14.27: + resolution: {integrity: sha512-CD/D4tj0U4UQjELkdNlZhQ8nDHU5rBn6NGp47Hiz0Y7/akAY5i0oGadhEIg0WCY/HYVXFb3CsSPPwaKcTOW3bg==} + engines: {node: '>=12'} cpu: [s390x] os: [linux] requiresBuild: true @@ -3669,8 +3617,9 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.14.10: - resolution: {integrity: sha512-6Gg8neVcLeyq0yt9bZpReb8ntZ8LBEjthxrcYWVrBElcltnDjIy1hrzsujt0+sC2rL+TlSsE9dzgyuvlDdPp2w==} + /esbuild-netbsd-64/0.14.27: + resolution: {integrity: sha512-h3mAld69SrO1VoaMpYl3a5FNdGRE/Nqc+E8VtHOag4tyBwhCQXxtvDDOAKOUQexBGca0IuR6UayQ4ntSX5ij1Q==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] requiresBuild: true @@ -3685,8 +3634,9 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.14.10: - resolution: {integrity: sha512-9rkHZzp10zI90CfKbFrwmQjqZaeDmyQ6s9/hvCwRkbOCHuto6RvMYH9ghQpcr5cUxD5OQIA+sHXi0zokRNXjcg==} + /esbuild-openbsd-64/0.14.27: + resolution: {integrity: sha512-xwSje6qIZaDHXWoPpIgvL+7fC6WeubHHv18tusLYMwL+Z6bEa4Pbfs5IWDtQdHkArtfxEkIZz77944z8MgDxGw==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] requiresBuild: true @@ -3709,8 +3659,9 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.14.10: - resolution: {integrity: sha512-mEU+pqkhkhbwpJj5DiN3vL0GUFR/yrL3qj8ER1amIVyRibKbj02VM1QaIuk1sy5DRVIKiFXXgCaHvH3RNWCHIw==} + /esbuild-sunos-64/0.14.27: + resolution: {integrity: sha512-/nBVpWIDjYiyMhuqIqbXXsxBc58cBVH9uztAOIfWShStxq9BNBik92oPQPJ57nzWXRNKQUEFWr4Q98utDWz7jg==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] requiresBuild: true @@ -3725,8 +3676,9 @@ packages: dev: true optional: true - /esbuild-windows-32/0.14.10: - resolution: {integrity: sha512-Z5DieUL1N6s78dOSdL95KWf8Y89RtPGxIoMF+LEy8ChDsX+pZpz6uAVCn+YaWpqQXO+2TnrcbgBIoprq2Mco1g==} + /esbuild-windows-32/0.14.27: + resolution: {integrity: sha512-Q9/zEjhZJ4trtWhFWIZvS/7RUzzi8rvkoaS9oiizkHTTKd8UxFwn/Mm2OywsAfYymgUYm8+y2b+BKTNEFxUekw==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] requiresBuild: true @@ -3741,8 +3693,9 @@ packages: dev: true optional: true - /esbuild-windows-64/0.14.10: - resolution: {integrity: sha512-LE5Mm62y0Bilu7RDryBhHIX8rK3at5VwJ6IGM3BsASidCfOBTzqcs7Yy0/Vkq39VKeTmy9/66BAfVoZRNznoDw==} + /esbuild-windows-64/0.14.27: + resolution: {integrity: sha512-b3y3vTSl5aEhWHK66ngtiS/c6byLf6y/ZBvODH1YkBM+MGtVL6jN38FdHUsZasCz9gFwYs/lJMVY9u7GL6wfYg==} + engines: {node: '>=12'} cpu: [x64] os: [win32] requiresBuild: true @@ -3757,8 +3710,9 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.14.10: - resolution: {integrity: sha512-OJOyxDtabvcUYTc+O4dR0JMzLBz6G9+gXIHA7Oc5d5Fv1xiYa0nUeo8+W5s2e6ZkPRdIwOseYoL70rZz80S5BA==} + /esbuild-windows-arm64/0.14.27: + resolution: {integrity: sha512-I/reTxr6TFMcR5qbIkwRGvldMIaiBu2+MP0LlD7sOlNXrfqIl9uNjsuxFPGEG4IRomjfQ5q8WT+xlF/ySVkqKg==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] requiresBuild: true @@ -3789,29 +3743,32 @@ packages: esbuild-windows-arm64: 0.13.14 dev: true - /esbuild/0.14.10: - resolution: {integrity: sha512-ibZb+NwFqBwHHJlpnFMtg4aNmVK+LUtYMFC9CuKs6lDCBEvCHpqCFZFEirpqt1jOugwKGx8gALNGvX56lQyfew==} + /esbuild/0.14.27: + resolution: {integrity: sha512-MZQt5SywZS3hA9fXnMhR22dv0oPGh6QtjJRIYbgL1AeqAoQZE+Qn5ppGYQAoHv/vq827flj4tIJ79Mrdiwk46Q==} + engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-arm64: 0.14.10 - esbuild-darwin-64: 0.14.10 - esbuild-darwin-arm64: 0.14.10 - esbuild-freebsd-64: 0.14.10 - esbuild-freebsd-arm64: 0.14.10 - esbuild-linux-32: 0.14.10 - esbuild-linux-64: 0.14.10 - esbuild-linux-arm: 0.14.10 - esbuild-linux-arm64: 0.14.10 - esbuild-linux-mips64le: 0.14.10 - esbuild-linux-ppc64le: 0.14.10 - esbuild-linux-s390x: 0.14.10 - esbuild-netbsd-64: 0.14.10 - esbuild-openbsd-64: 0.14.10 - esbuild-sunos-64: 0.14.10 - esbuild-windows-32: 0.14.10 - esbuild-windows-64: 0.14.10 - esbuild-windows-arm64: 0.14.10 + esbuild-android-64: 0.14.27 + esbuild-android-arm64: 0.14.27 + esbuild-darwin-64: 0.14.27 + esbuild-darwin-arm64: 0.14.27 + esbuild-freebsd-64: 0.14.27 + esbuild-freebsd-arm64: 0.14.27 + esbuild-linux-32: 0.14.27 + esbuild-linux-64: 0.14.27 + esbuild-linux-arm: 0.14.27 + esbuild-linux-arm64: 0.14.27 + esbuild-linux-mips64le: 0.14.27 + esbuild-linux-ppc64le: 0.14.27 + esbuild-linux-riscv64: 0.14.27 + esbuild-linux-s390x: 0.14.27 + esbuild-netbsd-64: 0.14.27 + esbuild-openbsd-64: 0.14.27 + esbuild-sunos-64: 0.14.27 + esbuild-windows-32: 0.14.27 + esbuild-windows-64: 0.14.27 + esbuild-windows-arm64: 0.14.27 dev: true /escalade/3.1.1: @@ -3861,7 +3818,7 @@ packages: resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==} engines: {node: '>=10'} dependencies: - '@types/eslint': 7.28.2 + '@types/eslint': 7.29.0 ansi-escapes: 4.3.2 chalk: 4.1.2 eslint-rule-docs: 1.1.231 @@ -3871,6 +3828,21 @@ packages: supports-hyperlinks: 2.2.0 dev: true + /eslint-import-resolver-node/0.3.6: + resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + dependencies: + debug: 3.2.7 + resolve: 1.22.0 + dev: true + + /eslint-module-utils/2.7.3: + resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} + engines: {node: '>=4'} + dependencies: + debug: 3.2.7 + find-up: 2.1.0 + dev: true + /eslint-plugin-eslint-comments/3.2.0_eslint@8.6.0: resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} engines: {node: '>=6.5.0'} @@ -3879,35 +3851,36 @@ packages: dependencies: escape-string-regexp: 1.0.5 eslint: 8.6.0 - ignore: 5.1.8 + ignore: 5.2.0 dev: true - /eslint-plugin-jest/25.3.4_50718c277c711d46fdc0916b9b606e5d: - resolution: {integrity: sha512-CCnwG71wvabmwq/qkz0HWIqBHQxw6pXB1uqt24dxqJ9WB34pVg49bL1sjXphlJHgTMWGhBjN1PicdyxDxrfP5A==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /eslint-plugin-import/2.25.4_eslint@8.6.0: + resolution: {integrity: sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==} + engines: {node: '>=4'} peerDependencies: - '@typescript-eslint/eslint-plugin': ^4.0.0 || ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - jest: '*' - peerDependenciesMeta: - '@typescript-eslint/eslint-plugin': - optional: true - jest: - optional: true + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 dependencies: - '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/experimental-utils': 5.9.0_eslint@8.6.0+typescript@4.5.4 + array-includes: 3.1.4 + array.prototype.flat: 1.2.5 + debug: 2.6.9 + doctrine: 2.1.0 eslint: 8.6.0 - transitivePeerDependencies: - - supports-color - - typescript + eslint-import-resolver-node: 0.3.6 + eslint-module-utils: 2.7.3 + has: 1.0.3 + is-core-module: 2.8.1 + is-glob: 4.0.3 + minimatch: 3.0.4 + object.values: 1.1.5 + resolve: 1.22.0 + tsconfig-paths: 3.12.0 dev: true - /eslint-plugin-jest/25.3.4_fc7ad14cecfc112c3a62fcc1531edd55: - resolution: {integrity: sha512-CCnwG71wvabmwq/qkz0HWIqBHQxw6pXB1uqt24dxqJ9WB34pVg49bL1sjXphlJHgTMWGhBjN1PicdyxDxrfP5A==} + /eslint-plugin-jest/26.0.0_50718c277c711d46fdc0916b9b606e5d: + resolution: {integrity: sha512-Fvs0YgJ/nw9FTrnqTuMGVrkozkd07jkQzWm0ajqyHlfcsdkxGfAuv30fgfWHOnHiCr9+1YQ365CcDX7vrNhqQg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} peerDependencies: - '@typescript-eslint/eslint-plugin': ^4.0.0 || ^5.0.0 + '@typescript-eslint/eslint-plugin': ^5.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 jest: '*' peerDependenciesMeta: @@ -3917,9 +3890,8 @@ packages: optional: true dependencies: '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 - '@typescript-eslint/experimental-utils': 5.9.0_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/utils': 5.10.1_eslint@8.6.0+typescript@4.5.4 eslint: 8.6.0 - jest: 27.4.6_ts-node@10.4.0 transitivePeerDependencies: - supports-color - typescript @@ -3942,6 +3914,14 @@ packages: prettier-linter-helpers: 1.0.0 dev: true + /eslint-plugin-simple-import-sort/7.0.0_eslint@8.6.0: + resolution: {integrity: sha512-U3vEDB5zhYPNfxT5TYR7u01dboFZp+HNpnGhkDB2g/2E4wZ/g1Q9Ton8UwCLfRV9yAKyYqDh62oHOamvkFxsvw==} + peerDependencies: + eslint: '>=5.0.0' + dependencies: + eslint: 8.6.0 + dev: true + /eslint-rule-docs/1.1.231: resolution: {integrity: sha512-egHz9A1WG7b8CS0x1P6P/Rj5FqZOjray/VjpJa14tMZalfRKvpE2ONJ3plCM7+PcinmU4tcmbPLv0VtwzSdLVA==} dev: true @@ -3982,6 +3962,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /eslint-visitor-keys/3.2.0: + resolution: {integrity: sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /eslint/8.6.0: resolution: {integrity: sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4035,7 +4020,7 @@ packages: dependencies: acorn: 8.7.0 acorn-jsx: 5.3.2_acorn@8.7.0 - eslint-visitor-keys: 3.1.0 + eslint-visitor-keys: 3.2.0 dev: true /esprima/4.0.1: @@ -4078,11 +4063,6 @@ packages: engines: {node: '>= 0.6'} dev: true - /event-target-shim/5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - dev: true - /eventemitter3/4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} dev: true @@ -4090,7 +4070,6 @@ packages: /events/3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - dev: true /execa/5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} @@ -4103,7 +4082,7 @@ packages: merge-stream: 2.0.0 npm-run-path: 4.0.1 onetime: 5.1.2 - signal-exit: 3.0.5 + signal-exit: 3.0.6 strip-final-newline: 2.0.0 /exit-on-epipe/1.0.1: @@ -4119,17 +4098,16 @@ packages: /expand-template/2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - dev: true optional: true - /expect/27.4.6: - resolution: {integrity: sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag==} + /expect/27.5.1: + resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - jest-get-type: 27.4.0 - jest-matcher-utils: 27.4.6 - jest-message-util: 27.4.6 + '@jest/types': 27.5.1 + jest-get-type: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 dev: true /express/4.17.2: @@ -4179,8 +4157,8 @@ packages: dev: true optional: true - /extsprintf/1.4.0: - resolution: {integrity: sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=} + /extsprintf/1.4.1: + resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} engines: {'0': node >=0.6.0} dev: true @@ -4192,9 +4170,9 @@ packages: resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} dev: true - /fast-glob/3.2.7: - resolution: {integrity: sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==} - engines: {node: '>=8'} + /fast-glob/3.2.10: + resolution: {integrity: sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==} + engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 @@ -4258,6 +4236,13 @@ packages: make-dir: 3.1.0 pkg-dir: 4.2.0 + /find-up/2.1.0: + resolution: {integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=} + engines: {node: '>=4'} + dependencies: + locate-path: 2.0.0 + dev: true + /find-up/3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -4283,7 +4268,7 @@ packages: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.2 + flatted: 3.2.4 rimraf: 3.0.2 dev: true @@ -4291,12 +4276,12 @@ packages: resolution: {integrity: sha512-ZfmD5MnU7GglUEhiky9C7yEPaNq1/wh36RDohe+Xr3nJVdccwHbdTkFIYvetcdsoAckUKT51fuf44g7Ni5Doyg==} dev: true - /flatted/3.2.2: - resolution: {integrity: sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==} + /flatted/3.2.4: + resolution: {integrity: sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==} dev: true - /follow-redirects/1.14.4: - resolution: {integrity: sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==} + /follow-redirects/1.14.7: + resolution: {integrity: sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -4305,8 +4290,8 @@ packages: optional: true dev: true - /follow-redirects/1.14.4_debug@4.3.3: - resolution: {integrity: sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==} + /follow-redirects/1.14.7_debug@4.3.3: + resolution: {integrity: sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -4315,7 +4300,6 @@ packages: optional: true dependencies: debug: 4.3.3 - dev: true /foreach/2.0.5: resolution: {integrity: sha1-C+4AUBiusmDQo6865ljdATbsG5k=} @@ -4332,27 +4316,17 @@ packages: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 - mime-types: 2.1.33 + mime-types: 2.1.34 dev: true optional: true - /form-data/2.5.1: - resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} - engines: {node: '>= 0.12'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.33 - dev: true - /form-data/3.0.1: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 - mime-types: 2.1.33 - dev: true + mime-types: 2.1.34 /form-data/4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} @@ -4360,8 +4334,7 @@ packages: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 - mime-types: 2.1.33 - dev: true + mime-types: 2.1.34 /forwarded/0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} @@ -4380,7 +4353,7 @@ packages: resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==} engines: {node: '>=12'} dependencies: - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 jsonfile: 6.1.0 universalify: 2.0.0 dev: true @@ -4389,7 +4362,7 @@ packages: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} dependencies: - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 jsonfile: 4.0.0 universalify: 0.1.2 dev: true @@ -4401,6 +4374,13 @@ packages: rimraf: 2.7.1 dev: true + /fs-jetpack/4.3.1: + resolution: {integrity: sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==} + dependencies: + minimatch: 3.0.4 + rimraf: 2.7.1 + dev: false + /fs-minipass/1.2.7: resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} dependencies: @@ -4411,7 +4391,7 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} dependencies: - minipass: 3.1.5 + minipass: 3.1.6 dev: false /fs-monkey/1.0.3: @@ -4433,7 +4413,7 @@ packages: resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} engines: {node: '>=0.6'} dependencies: - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 inherits: 2.0.4 mkdirp: 0.5.5 rimraf: 2.7.1 @@ -4454,11 +4434,10 @@ packages: console-control-strings: 1.1.0 has-unicode: 2.0.1 object-assign: 4.1.1 - signal-exit: 3.0.5 + signal-exit: 3.0.6 string-width: 1.0.2 strip-ansi: 3.0.1 wide-align: 1.1.5 - dev: true /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -4476,7 +4455,6 @@ packages: function-bind: 1.1.1 has: 1.0.3 has-symbols: 1.0.2 - dev: true /get-own-enumerable-property-symbols/3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} @@ -4492,6 +4470,11 @@ packages: engines: {node: '>=8'} dev: true + /get-stdin/8.0.0: + resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==} + engines: {node: '>=10'} + dev: false + /get-stream/6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -4513,7 +4496,6 @@ packages: /github-from-package/0.0.0: resolution: {integrity: sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=} - dev: true optional: true /glob-parent/5.1.2: @@ -4563,19 +4545,32 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.7 - ignore: 5.1.8 + fast-glob: 3.2.10 + ignore: 5.2.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /globby/11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.10 + ignore: 5.2.0 merge2: 1.4.1 slash: 3.0.0 - /graceful-fs/4.2.8: - resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==} + /graceful-fs/4.2.9: + resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} - /graphviz/0.0.9: - resolution: {integrity: sha512-SmoY2pOtcikmMCqCSy2NO1YsRfu9OO0wpTlOYW++giGjfX1a6gax/m1Fo8IdUd0/3H15cTOfR1SMKwohj4LKsg==} + /graphviz-mit/0.0.9: + resolution: {integrity: sha512-om4IO5Rp5D/BnKluHsciWPi9tqB2MQN5yKbo9fXghFQL8QtWm3EpMnT/Llje0kE+DpG6qIQVLT6HqKpAnKyQGw==} engines: {node: '>=0.6.8'} dependencies: temp: 0.4.0 + which: 1.3.1 dev: true /har-schema/2.0.0: @@ -4614,7 +4609,6 @@ packages: /has-symbols/1.0.2: resolution: {integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==} engines: {node: '>= 0.4'} - dev: true /has-tostringtag/1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} @@ -4625,7 +4619,6 @@ packages: /has-unicode/2.0.1: resolution: {integrity: sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=} - dev: true /has-yarn/2.1.0: resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} @@ -4648,8 +4641,8 @@ packages: /hosted-git-info/2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - /hosted-git-info/4.0.2: - resolution: {integrity: sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==} + /hosted-git-info/4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} dependencies: lru-cache: 6.0.0 @@ -4686,7 +4679,6 @@ packages: debug: 4.3.3 transitivePeerDependencies: - supports-color - dev: true /http-proxy-agent/5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} @@ -4703,8 +4695,8 @@ packages: engines: {node: '>=0.8', npm: '>=1.3.7'} dependencies: assert-plus: 1.0.0 - jsprim: 1.4.1 - sshpk: 1.16.1 + jsprim: 1.4.2 + sshpk: 1.17.0 dev: true optional: true @@ -4739,7 +4731,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: true /ieee754/1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -4755,8 +4746,8 @@ packages: engines: {node: '>= 4'} dev: true - /ignore/5.1.8: - resolution: {integrity: sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==} + /ignore/5.2.0: + resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} engines: {node: '>= 4'} /import-fresh/3.3.0: @@ -4772,8 +4763,8 @@ packages: engines: {node: '>=8'} dev: true - /import-local/3.0.3: - resolution: {integrity: sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==} + /import-local/3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} hasBin: true dependencies: @@ -4801,7 +4792,6 @@ packages: /ini/1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /ini/2.0.0: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} @@ -4816,11 +4806,6 @@ packages: side-channel: 1.0.4 dev: true - /ip-regex/2.1.0: - resolution: {integrity: sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=} - engines: {node: '>=4'} - dev: true - /ipaddr.js/1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -4872,10 +4857,10 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - ci-info: 3.2.0 + ci-info: 3.3.0 - /is-core-module/2.8.0: - resolution: {integrity: sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==} + /is-core-module/2.8.1: + resolution: {integrity: sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==} dependencies: has: 1.0.3 @@ -4900,7 +4885,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: number-is-nan: 1.0.1 - dev: true /is-fullwidth-code-point/3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -4937,8 +4921,8 @@ packages: is-path-inside: 3.0.3 dev: true - /is-negative-zero/2.0.1: - resolution: {integrity: sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==} + /is-negative-zero/2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} dev: true @@ -5035,8 +5019,8 @@ packages: engines: {node: '>=10'} dev: true - /is-weakref/1.0.1: - resolution: {integrity: sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==} + /is-weakref/1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true @@ -5067,8 +5051,8 @@ packages: resolution: {integrity: sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.15.8 - '@babel/parser': 7.15.8 + '@babel/core': 7.16.7 + '@babel/parser': 7.16.8 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -5104,35 +5088,35 @@ packages: istanbul-lib-report: 3.0.0 dev: true - /jest-changed-files/27.4.2: - resolution: {integrity: sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==} + /jest-changed-files/27.5.1: + resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 + '@jest/types': 27.5.1 execa: 5.1.1 throat: 6.0.1 dev: true - /jest-circus/27.4.6: - resolution: {integrity: sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ==} + /jest-circus/27.5.1: + resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/environment': 27.4.6 - '@jest/test-result': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/environment': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 - expect: 27.4.6 + expect: 27.5.1 is-generator-fn: 2.1.0 - jest-each: 27.4.6 - jest-matcher-utils: 27.4.6 - jest-message-util: 27.4.6 - jest-runtime: 27.4.6 - jest-snapshot: 27.4.6 - jest-util: 27.4.2 - pretty-format: 27.4.6 + jest-each: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + pretty-format: 27.5.1 slash: 3.0.0 stack-utils: 2.0.5 throat: 6.0.1 @@ -5140,8 +5124,8 @@ packages: - supports-color dev: true - /jest-cli/27.4.6_ts-node@10.4.0: - resolution: {integrity: sha512-SFfUC7jMHPGwsNSYBnJMNtjoSDrb34T+SEH5psDeGNVuTVov5Zi1RQpfJYwzpK2ex3OmnsNsiqLe3/SCc8S01Q==} + /jest-cli/27.5.1_ts-node@10.4.0: + resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true peerDependencies: @@ -5150,20 +5134,19 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 27.4.6_ts-node@10.4.0 - '@jest/test-result': 27.4.6 - '@jest/types': 27.4.2 + '@jest/core': 27.5.1_ts-node@10.4.0 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 chalk: 4.1.2 exit: 0.1.2 - graceful-fs: 4.2.8 - import-local: 3.0.3 - jest-config: 27.4.6_ts-node@10.4.0 - jest-util: 27.4.2 - jest-validate: 27.4.6 + graceful-fs: 4.2.9 + import-local: 3.1.0 + jest-config: 27.5.1_ts-node@10.4.0 + jest-util: 27.5.1 + jest-validate: 27.5.1 prompts: 2.4.2 yargs: 16.2.0 transitivePeerDependencies: - - '@babel/core' - bufferutil - canvas - supports-color @@ -5171,8 +5154,8 @@ packages: - utf-8-validate dev: true - /jest-config/27.4.6_ts-node@10.4.0: - resolution: {integrity: sha512-3SGoFbaanQVg7MK5w/z8LnCMF6aZc2I7EQxS4s8fTfZpVYnWNDN34llcaViToIB62DFMhwHWTPX9X2O+4aDL1g==} + /jest-config/27.5.1_ts-node@10.4.0: + resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: ts-node: '>=9.0.0' @@ -5180,74 +5163,76 @@ packages: ts-node: optional: true dependencies: - '@jest/test-sequencer': 27.4.6 - '@jest/types': 27.4.2 - babel-jest: 27.4.6 + '@babel/core': 7.16.7 + '@jest/test-sequencer': 27.5.1 + '@jest/types': 27.5.1 + babel-jest: 27.5.1_@babel+core@7.16.7 chalk: 4.1.2 - ci-info: 3.2.0 + ci-info: 3.3.0 deepmerge: 4.2.2 glob: 7.2.0 - graceful-fs: 4.2.8 - jest-circus: 27.4.6 - jest-environment-jsdom: 27.4.6 - jest-environment-node: 27.4.6 - jest-get-type: 27.4.0 - jest-jasmine2: 27.4.6 - jest-regex-util: 27.4.0 - jest-resolve: 27.4.6 - jest-runner: 27.4.6 - jest-util: 27.4.2 - jest-validate: 27.4.6 + graceful-fs: 4.2.9 + jest-circus: 27.5.1 + jest-environment-jsdom: 27.5.1 + jest-environment-node: 27.5.1 + jest-get-type: 27.5.1 + jest-jasmine2: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-runner: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 micromatch: 4.0.4 - pretty-format: 27.4.6 + parse-json: 5.2.0 + pretty-format: 27.5.1 slash: 3.0.0 - ts-node: 10.4.0_60e8b8d4e7c9a6973679cdf61ab01fe0 + strip-json-comments: 3.1.1 + ts-node: 10.4.0_b575a4ed8d8a14db25cb9540c04f64f6 transitivePeerDependencies: - - '@babel/core' - bufferutil - canvas - supports-color - utf-8-validate dev: true - /jest-diff/27.4.6: - resolution: {integrity: sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==} + /jest-diff/27.5.1: + resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: chalk: 4.1.2 - diff-sequences: 27.4.0 - jest-get-type: 27.4.0 - pretty-format: 27.4.6 + diff-sequences: 27.5.1 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 dev: true - /jest-docblock/27.4.0: - resolution: {integrity: sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==} + /jest-docblock/27.5.1: + resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: detect-newline: 3.1.0 dev: true - /jest-each/27.4.6: - resolution: {integrity: sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA==} + /jest-each/27.5.1: + resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 + '@jest/types': 27.5.1 chalk: 4.1.2 - jest-get-type: 27.4.0 - jest-util: 27.4.2 - pretty-format: 27.4.6 + jest-get-type: 27.5.1 + jest-util: 27.5.1 + pretty-format: 27.5.1 dev: true - /jest-environment-jsdom/27.4.6: - resolution: {integrity: sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA==} + /jest-environment-jsdom/27.5.1: + resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/environment': 27.4.6 - '@jest/fake-timers': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 - jest-mock: 27.4.6 - jest-util: 27.4.2 + '@jest/environment': 27.5.1 + '@jest/fake-timers': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 + jest-mock: 27.5.1 + jest-util: 27.5.1 jsdom: 16.7.0 transitivePeerDependencies: - bufferutil @@ -5256,110 +5241,120 @@ packages: - utf-8-validate dev: true - /jest-environment-node/27.4.6: - resolution: {integrity: sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ==} + /jest-environment-node/27.5.1: + resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/environment': 27.4.6 - '@jest/fake-timers': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 - jest-mock: 27.4.6 - jest-util: 27.4.2 + '@jest/environment': 27.5.1 + '@jest/fake-timers': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 + jest-mock: 27.5.1 + jest-util: 27.5.1 dev: true - /jest-get-type/27.4.0: - resolution: {integrity: sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==} + /jest-get-type/27.5.1: + resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true - /jest-haste-map/27.4.6: - resolution: {integrity: sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ==} + /jest-haste-map/27.5.1: + resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 + '@jest/types': 27.5.1 '@types/graceful-fs': 4.1.5 - '@types/node': 16.11.19 + '@types/node': 17.0.18 anymatch: 3.1.2 fb-watchman: 2.0.1 - graceful-fs: 4.2.8 - jest-regex-util: 27.4.0 - jest-serializer: 27.4.0 - jest-util: 27.4.2 - jest-worker: 27.4.6 + graceful-fs: 4.2.9 + jest-regex-util: 27.5.1 + jest-serializer: 27.5.1 + jest-util: 27.5.1 + jest-worker: 27.5.1 micromatch: 4.0.4 walker: 1.0.8 optionalDependencies: fsevents: 2.3.2 dev: true - /jest-jasmine2/27.4.6: - resolution: {integrity: sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw==} + /jest-jasmine2/27.5.1: + resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/environment': 27.4.6 - '@jest/source-map': 27.4.0 - '@jest/test-result': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/environment': 27.5.1 + '@jest/source-map': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 chalk: 4.1.2 co: 4.6.0 - expect: 27.4.6 + expect: 27.5.1 is-generator-fn: 2.1.0 - jest-each: 27.4.6 - jest-matcher-utils: 27.4.6 - jest-message-util: 27.4.6 - jest-runtime: 27.4.6 - jest-snapshot: 27.4.6 - jest-util: 27.4.2 - pretty-format: 27.4.6 + jest-each: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + pretty-format: 27.5.1 throat: 6.0.1 transitivePeerDependencies: - supports-color dev: true - /jest-leak-detector/27.4.6: - resolution: {integrity: sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA==} + /jest-junit/13.0.0: + resolution: {integrity: sha512-JSHR+Dhb32FGJaiKkqsB7AR3OqWKtldLd6ZH2+FJ8D4tsweb8Id8zEVReU4+OlrRO1ZluqJLQEETm+Q6/KilBg==} + engines: {node: '>=10.12.0'} + dependencies: + mkdirp: 1.0.4 + strip-ansi: 6.0.1 + uuid: 8.3.2 + xml: 1.0.1 + dev: true + + /jest-leak-detector/27.5.1: + resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - jest-get-type: 27.4.0 - pretty-format: 27.4.6 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 dev: true - /jest-matcher-utils/27.4.6: - resolution: {integrity: sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA==} + /jest-matcher-utils/27.5.1: + resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: chalk: 4.1.2 - jest-diff: 27.4.6 - jest-get-type: 27.4.0 - pretty-format: 27.4.6 + jest-diff: 27.5.1 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 dev: true - /jest-message-util/27.4.6: - resolution: {integrity: sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==} + /jest-message-util/27.5.1: + resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/code-frame': 7.15.8 - '@jest/types': 27.4.2 + '@babel/code-frame': 7.16.7 + '@jest/types': 27.5.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 micromatch: 4.0.4 - pretty-format: 27.4.6 + pretty-format: 27.5.1 slash: 3.0.0 stack-utils: 2.0.5 dev: true - /jest-mock/27.4.6: - resolution: {integrity: sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==} + /jest-mock/27.5.1: + resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 dev: true - /jest-pnp-resolver/1.2.2_jest-resolve@27.4.6: + /jest-pnp-resolver/1.2.2_jest-resolve@27.5.1: resolution: {integrity: sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==} engines: {node: '>=6'} peerDependencies: @@ -5368,65 +5363,64 @@ packages: jest-resolve: optional: true dependencies: - jest-resolve: 27.4.6 + jest-resolve: 27.5.1 dev: true - /jest-regex-util/27.4.0: - resolution: {integrity: sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==} + /jest-regex-util/27.5.1: + resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true - /jest-resolve-dependencies/27.4.6: - resolution: {integrity: sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw==} + /jest-resolve-dependencies/27.5.1: + resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - jest-regex-util: 27.4.0 - jest-snapshot: 27.4.6 + '@jest/types': 27.5.1 + jest-regex-util: 27.5.1 + jest-snapshot: 27.5.1 transitivePeerDependencies: - supports-color dev: true - /jest-resolve/27.4.6: - resolution: {integrity: sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw==} + /jest-resolve/27.5.1: + resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 + '@jest/types': 27.5.1 chalk: 4.1.2 - graceful-fs: 4.2.8 - jest-haste-map: 27.4.6 - jest-pnp-resolver: 1.2.2_jest-resolve@27.4.6 - jest-util: 27.4.2 - jest-validate: 27.4.6 - resolve: 1.21.0 + graceful-fs: 4.2.9 + jest-haste-map: 27.5.1 + jest-pnp-resolver: 1.2.2_jest-resolve@27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + resolve: 1.22.0 resolve.exports: 1.1.0 slash: 3.0.0 dev: true - /jest-runner/27.4.6: - resolution: {integrity: sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg==} + /jest-runner/27.5.1: + resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/console': 27.4.6 - '@jest/environment': 27.4.6 - '@jest/test-result': 27.4.6 - '@jest/transform': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/console': 27.5.1 + '@jest/environment': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 chalk: 4.1.2 emittery: 0.8.1 - exit: 0.1.2 - graceful-fs: 4.2.8 - jest-docblock: 27.4.0 - jest-environment-jsdom: 27.4.6 - jest-environment-node: 27.4.6 - jest-haste-map: 27.4.6 - jest-leak-detector: 27.4.6 - jest-message-util: 27.4.6 - jest-resolve: 27.4.6 - jest-runtime: 27.4.6 - jest-util: 27.4.2 - jest-worker: 27.4.6 + graceful-fs: 4.2.9 + jest-docblock: 27.5.1 + jest-environment-jsdom: 27.5.1 + jest-environment-node: 27.5.1 + jest-haste-map: 27.5.1 + jest-leak-detector: 27.5.1 + jest-message-util: 27.5.1 + jest-resolve: 27.5.1 + jest-runtime: 27.5.1 + jest-util: 27.5.1 + jest-worker: 27.5.1 source-map-support: 0.5.21 throat: 6.0.1 transitivePeerDependencies: @@ -5436,69 +5430,69 @@ packages: - utf-8-validate dev: true - /jest-runtime/27.4.6: - resolution: {integrity: sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ==} + /jest-runtime/27.5.1: + resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/environment': 27.4.6 - '@jest/fake-timers': 27.4.6 - '@jest/globals': 27.4.6 - '@jest/source-map': 27.4.0 - '@jest/test-result': 27.4.6 - '@jest/transform': 27.4.6 - '@jest/types': 27.4.2 + '@jest/environment': 27.5.1 + '@jest/fake-timers': 27.5.1 + '@jest/globals': 27.5.1 + '@jest/source-map': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 execa: 5.1.1 glob: 7.2.0 - graceful-fs: 4.2.8 - jest-haste-map: 27.4.6 - jest-message-util: 27.4.6 - jest-mock: 27.4.6 - jest-regex-util: 27.4.0 - jest-resolve: 27.4.6 - jest-snapshot: 27.4.6 - jest-util: 27.4.2 + graceful-fs: 4.2.9 + jest-haste-map: 27.5.1 + jest-message-util: 27.5.1 + jest-mock: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /jest-serializer/27.4.0: - resolution: {integrity: sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==} + /jest-serializer/27.5.1: + resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@types/node': 16.11.19 - graceful-fs: 4.2.8 + '@types/node': 17.0.18 + graceful-fs: 4.2.9 dev: true - /jest-snapshot/27.4.6: - resolution: {integrity: sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ==} + /jest-snapshot/27.5.1: + resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/core': 7.15.8 - '@babel/generator': 7.15.8 - '@babel/plugin-syntax-typescript': 7.14.5_@babel+core@7.15.8 - '@babel/traverse': 7.15.4 - '@babel/types': 7.15.6 - '@jest/transform': 27.4.6 - '@jest/types': 27.4.2 + '@babel/core': 7.16.7 + '@babel/generator': 7.16.8 + '@babel/plugin-syntax-typescript': 7.16.7_@babel+core@7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 '@types/babel__traverse': 7.14.2 - '@types/prettier': 2.4.1 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.15.8 + '@types/prettier': 2.4.3 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.16.7 chalk: 4.1.2 - expect: 27.4.6 - graceful-fs: 4.2.8 - jest-diff: 27.4.6 - jest-get-type: 27.4.0 - jest-haste-map: 27.4.6 - jest-matcher-utils: 27.4.6 - jest-message-util: 27.4.6 - jest-util: 27.4.2 + expect: 27.5.1 + graceful-fs: 4.2.9 + jest-diff: 27.5.1 + jest-get-type: 27.5.1 + jest-haste-map: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + jest-util: 27.5.1 natural-compare: 1.4.0 - pretty-format: 27.4.6 + pretty-format: 27.5.1 semver: 7.3.5 transitivePeerDependencies: - supports-color @@ -5508,50 +5502,62 @@ packages: resolution: {integrity: sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 + chalk: 4.1.2 + ci-info: 3.3.0 + graceful-fs: 4.2.9 + picomatch: 2.3.1 + dev: true + + /jest-util/27.5.1: + resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.5.1 + '@types/node': 17.0.18 chalk: 4.1.2 - ci-info: 3.2.0 - graceful-fs: 4.2.8 - picomatch: 2.3.0 + ci-info: 3.3.0 + graceful-fs: 4.2.9 + picomatch: 2.3.1 dev: true - /jest-validate/27.4.6: - resolution: {integrity: sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==} + /jest-validate/27.5.1: + resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/types': 27.4.2 - camelcase: 6.2.0 + '@jest/types': 27.5.1 + camelcase: 6.3.0 chalk: 4.1.2 - jest-get-type: 27.4.0 + jest-get-type: 27.5.1 leven: 3.1.0 - pretty-format: 27.4.6 + pretty-format: 27.5.1 dev: true - /jest-watcher/27.4.6: - resolution: {integrity: sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw==} + /jest-watcher/27.5.1: + resolution: {integrity: sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@jest/test-result': 27.4.6 - '@jest/types': 27.4.2 - '@types/node': 16.11.19 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.18 ansi-escapes: 4.3.2 chalk: 4.1.2 - jest-util: 27.4.2 + jest-util: 27.5.1 string-length: 4.0.2 dev: true - /jest-worker/27.4.6: - resolution: {integrity: sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==} + /jest-worker/27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 16.11.19 + '@types/node': 17.0.18 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest/27.4.6_ts-node@10.4.0: - resolution: {integrity: sha512-BRbYo0MeujnnJIo206WRsfsr3gIMraR+LO9vZJsdG2/298aKYQJbS3wHG0KN3Z7SWIcf6JaSMM4E8X6cIdG9AA==} + /jest/27.5.1_ts-node@10.4.0: + resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true peerDependencies: @@ -5560,11 +5566,10 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 27.4.6_ts-node@10.4.0 - import-local: 3.0.3 - jest-cli: 27.4.6_ts-node@10.4.0 + '@jest/core': 27.5.1_ts-node@10.4.0 + import-local: 3.1.0 + jest-cli: 27.5.1_ts-node@10.4.0 transitivePeerDependencies: - - '@babel/core' - bufferutil - canvas - supports-color @@ -5601,7 +5606,6 @@ packages: /jsbi/3.2.5: resolution: {integrity: sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==} - dev: true /jsbn/0.1.1: resolution: {integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM=} @@ -5642,7 +5646,7 @@ packages: whatwg-encoding: 1.0.5 whatwg-mimetype: 2.3.0 whatwg-url: 8.7.0 - ws: 7.5.5 + ws: 7.5.6 xml-name-validator: 3.0.0 transitivePeerDependencies: - bufferutil @@ -5663,8 +5667,8 @@ packages: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true - /json-schema/0.2.3: - resolution: {integrity: sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=} + /json-schema/0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} dev: true optional: true @@ -5677,6 +5681,13 @@ packages: dev: true optional: true + /json5/1.0.1: + resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + /json5/2.2.0: resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} engines: {node: '>=6'} @@ -5688,7 +5699,7 @@ packages: /jsonfile/4.0.0: resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=} optionalDependencies: - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 dev: true /jsonfile/6.1.0: @@ -5696,7 +5707,7 @@ packages: dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 dev: true /jsonwebtoken/8.5.1: @@ -5713,15 +5724,14 @@ packages: lodash.once: 4.1.1 ms: 2.1.3 semver: 5.7.1 - dev: true - /jsprim/1.4.1: - resolution: {integrity: sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=} - engines: {'0': node >=0.6.0} + /jsprim/1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} dependencies: assert-plus: 1.0.0 extsprintf: 1.3.0 - json-schema: 0.2.3 + json-schema: 0.4.0 verror: 1.10.0 dev: true optional: true @@ -5732,7 +5742,6 @@ packages: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - dev: true /jwa/2.0.0: resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} @@ -5740,29 +5749,25 @@ packages: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - dev: true /jws/3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} dependencies: jwa: 1.4.1 safe-buffer: 5.2.1 - dev: true /jws/4.0.0: resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} dependencies: jwa: 2.0.0 safe-buffer: 5.2.1 - dev: true - /keytar/7.7.0: - resolution: {integrity: sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==} + /keytar/7.9.0: + resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} requiresBuild: true dependencies: - node-addon-api: 3.2.1 - prebuild-install: 6.1.4 - dev: true + node-addon-api: 4.3.0 + prebuild-install: 7.0.1 optional: true /kind-of/6.0.3: @@ -5817,11 +5822,11 @@ packages: hasBin: true dev: true - /lines-and-columns/1.1.6: - resolution: {integrity: sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=} + /lines-and-columns/1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - /lint-staged/12.1.5: - resolution: {integrity: sha512-WyKb+0sNKDTd1LwwAfTBPp0XmdaKkAOEbg4oHE4Kq2+oQVchg/VAcjVQtSqZih1izNsTURjc2EkhG/syRQUXdA==} + /lint-staged/12.3.4: + resolution: {integrity: sha512-yv/iK4WwZ7/v0GtVkNb3R82pdL9M+ScpIbJLJNyCXkJ1FGaXvRCOg/SeL59SZtPpqZhE7BD6kPKFLIDUhDx2/w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true dependencies: @@ -5831,7 +5836,7 @@ packages: debug: 4.3.3_supports-color@9.2.1 execa: 5.1.1 lilconfig: 2.0.4 - listr2: 3.13.5 + listr2: 4.0.1 micromatch: 4.0.4 normalize-path: 3.0.0 object-inspect: 1.12.0 @@ -5842,9 +5847,9 @@ packages: - enquirer dev: true - /listr2/3.13.5: - resolution: {integrity: sha512-3n8heFQDSk+NcwBn3CgxEibZGaRzx+pC64n3YjpMD1qguV4nWus3Al+Oo3KooqFKTQEJ1v7MmnbnyyNspgx3NA==} - engines: {node: '>=10.0.0'} + /listr2/4.0.1: + resolution: {integrity: sha512-D65Nl+zyYHL2jQBGmxtH/pU8koPZo5C8iCNE8EoB04RwPgQG1wuaKwVbeZv9LJpiH4Nxs0FCp+nNcG8OqpniiA==} + engines: {node: '>=12'} peerDependencies: enquirer: '>= 2.3.0 < 3' peerDependenciesMeta: @@ -5856,11 +5861,19 @@ packages: log-update: 4.0.0 p-map: 4.0.0 rfdc: 1.3.0 - rxjs: 7.4.0 + rxjs: 7.5.2 through: 2.3.8 wrap-ansi: 7.0.0 dev: true + /locate-path/2.0.0: + resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=} + engines: {node: '>=4'} + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + dev: true + /locate-path/3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -5902,11 +5915,9 @@ packages: /lodash.includes/4.3.0: resolution: {integrity: sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=} - dev: true /lodash.isboolean/3.0.3: resolution: {integrity: sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=} - dev: true /lodash.isequal/4.5.0: resolution: {integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=} @@ -5914,18 +5925,15 @@ packages: /lodash.isinteger/4.0.4: resolution: {integrity: sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=} - dev: true /lodash.isnumber/3.0.3: resolution: {integrity: sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=} - dev: true /lodash.isplainobject/4.0.6: resolution: {integrity: sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=} /lodash.isstring/4.0.1: resolution: {integrity: sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=} - dev: true /lodash.memoize/4.1.2: resolution: {integrity: sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=} @@ -5937,7 +5945,6 @@ packages: /lodash.once/4.1.1: resolution: {integrity: sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=} - dev: true /lodash.union/4.6.0: resolution: {integrity: sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=} @@ -5964,10 +5971,6 @@ packages: slice-ansi: 4.0.0 wrap-ansi: 6.2.0 - /long/4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - dev: true - /loose-envify/1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -5980,7 +5983,6 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 - dev: true /lz-string/1.4.4: resolution: {integrity: sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=} @@ -6013,18 +6015,17 @@ packages: engines: {node: '>=8'} dev: true - /mariadb/2.5.5: - resolution: {integrity: sha512-6dklvcKWuuaV1JjAwnE2ezR+jTt7JrZHftgeHHBmjB0wgfaUpdxol1DPWclwMcCrsO9yoM0FuCOiCcCgXc//9Q==} - engines: {node: '>= 10.13'} + /mariadb/3.0.0: + resolution: {integrity: sha512-1uIqD6AWLP5ojMY67XP4+4uRLe9L92HD1ZGU8fidi8cGdYIC+Ghx1JliAtf7lc/tGjOh6J400f/1M4BXVtZFvA==} + engines: {node: '>= 12'} dependencies: + '@alloc/quick-lru': 5.2.0 '@types/geojson': 7946.0.8 - '@types/node': 14.18.3 - denque: 1.5.1 + '@types/node': 17.0.18 + denque: 2.0.1 iconv-lite: 0.6.3 - long: 4.0.0 - moment-timezone: 0.5.33 + moment-timezone: 0.5.34 please-upgrade-node: 3.2.0 - dev: true /media-typer/0.3.0: resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} @@ -6070,19 +6071,17 @@ packages: engines: {node: '>=8.6'} dependencies: braces: 3.0.2 - picomatch: 2.3.0 + picomatch: 2.3.1 - /mime-db/1.50.0: - resolution: {integrity: sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==} + /mime-db/1.51.0: + resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==} engines: {node: '>= 0.6'} - dev: true - /mime-types/2.1.33: - resolution: {integrity: sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==} + /mime-types/2.1.34: + resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==} engines: {node: '>= 0.6'} dependencies: - mime-db: 1.50.0 - dev: true + mime-db: 1.51.0 /mime/1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} @@ -6094,10 +6093,9 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - /mimic-response/2.1.0: - resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==} - engines: {node: '>=8'} - dev: true + /mimic-response/3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} optional: true /min-indent/1.0.1: @@ -6120,7 +6118,6 @@ packages: /minimist/1.2.5: resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} - dev: true /minipass/2.9.0: resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} @@ -6129,8 +6126,8 @@ packages: yallist: 3.1.1 dev: true - /minipass/3.1.5: - resolution: {integrity: sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==} + /minipass/3.1.6: + resolution: {integrity: sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==} engines: {node: '>=8'} dependencies: yallist: 4.0.0 @@ -6146,13 +6143,12 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} dependencies: - minipass: 3.1.5 + minipass: 3.1.6 yallist: 4.0.0 dev: false /mkdirp-classic/0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - dev: true optional: true /mkdirp/0.5.5: @@ -6171,15 +6167,13 @@ packages: resolution: {integrity: sha512-tukRdb9Beu27t6dN+XztSRHq9J0B/CoAOySGzHfn8UTfmqipA5yNT/sDUEyYdAV3Hpka6Wx6kOMxuObdOex60Q==} dev: true - /moment-timezone/0.5.33: - resolution: {integrity: sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==} + /moment-timezone/0.5.34: + resolution: {integrity: sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==} dependencies: moment: 2.29.1 - dev: true /moment/2.29.1: resolution: {integrity: sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==} - dev: true /ms/2.0.0: resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} @@ -6191,35 +6185,48 @@ packages: /ms/2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /msal/1.4.14: - resolution: {integrity: sha512-k8M5+/jbfSQoCf7CyQzBP5HE5mY8TkBujykLGTEp2x0MvOK/FQsfUTNis28zlvvPVzhgrhb5GQiGM8rRpXyHdA==} + /msal/1.4.15: + resolution: {integrity: sha512-H/CxkeZJ4laEK6GZ/cDKQoYjBTvDNFK3hDC8mfU8IkuZvKFfFdo9KM89r8spXY7xnBK9SQBAjIuQgwUogeUw7g==} engines: {node: '>=0.8.0'} dependencies: tslib: 1.14.1 - dev: true - /mssql/7.3.0: - resolution: {integrity: sha512-3NGxDomH5Lci2g0EUrsejHIsvtFwlIE6A9SNFWQ2/JD4Dh0+5XVFHeyB4RXKb+nRMDosSUBAQDIVSuLXo5XFZA==} + /mssql/8.0.1: + resolution: {integrity: sha512-GZ1YnfMjfEdiXNRWZeYyTtqHWptUMA5jWrygbqfl72zsCxXsNuLPH9gPxz7m2F6+tWY48hR+ieZ92QY11ILNeg==} engines: {node: '>=10'} hasBin: true dependencies: '@tediousjs/connection-string': 0.3.0 debug: 4.3.3 rfdc: 1.3.0 - tarn: 3.0.1 - tedious: 11.8.0_debug@4.3.3 + tarn: 3.0.2 + tedious: 14.1.0_debug@4.3.3 transitivePeerDependencies: + - encoding - supports-color dev: true + /mssql/8.0.2: + resolution: {integrity: sha512-2FKoSFjJ5Ax3QlS/m6peMOlTZ7ks4SQ6D+K7/c7X0a7rJ70EqnQrriZHSvUE6Ale6EaQTtqrjgRMFPDNM9VfXg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@tediousjs/connection-string': 0.3.0 + debug: 4.3.3 + rfdc: 1.3.0 + tarn: 3.0.2 + tedious: 14.1.0_debug@4.3.3 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /napi-build-utils/1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - dev: true optional: true /native-duplexpair/1.0.0: resolution: {integrity: sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=} - dev: true /natural-compare/1.4.0: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} @@ -6245,28 +6252,37 @@ packages: engines: {node: '>=10'} dev: false - /node-abi/2.30.1: - resolution: {integrity: sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==} + /node-abi/3.7.0: + resolution: {integrity: sha512-3J+U4CvxVNEk9+lGdJkmYbN8cIN0HMTDT9R0ezX7pmp7aD6BaKsfAHwVn3IvVg6pYIRUuQ+gHW1eawrvywnSQQ==} + engines: {node: '>=10'} dependencies: - semver: 5.7.1 - dev: true + semver: 7.3.5 optional: true - /node-abort-controller/2.0.0: - resolution: {integrity: sha512-L8RfEgjBTHAISTuagw51PprVAqNZoG6KSB6LQ6H1bskMVkFs5E71IyjauLBv3XbuomJlguWF/VnRHdJ1gqiAqA==} - dev: true + /node-abort-controller/3.0.1: + resolution: {integrity: sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==} /node-addon-api/3.2.1: resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} dev: true + /node-addon-api/4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + optional: true + /node-fetch/2.6.1: resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==} engines: {node: 4.x || >=6.0.0} + dev: true - /node-fetch/2.6.6: - resolution: {integrity: sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==} + /node-fetch/2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true dependencies: whatwg-url: 5.0.0 @@ -6278,7 +6294,7 @@ packages: dependencies: fstream: 1.0.12 glob: 7.2.0 - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 mkdirp: 0.5.5 nopt: 3.0.6 npmlog: 4.1.2 @@ -6336,7 +6352,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.20.0 + resolve: 1.22.0 semver: 5.7.1 validate-npm-package-license: 3.0.4 @@ -6344,8 +6360,8 @@ packages: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} dependencies: - hosted-git-info: 4.0.2 - is-core-module: 2.8.0 + hosted-git-info: 4.1.0 + is-core-module: 2.8.1 semver: 7.3.5 validate-npm-package-license: 3.0.4 dev: true @@ -6385,12 +6401,10 @@ packages: console-control-strings: 1.1.0 gauge: 2.7.4 set-blocking: 2.0.0 - dev: true /number-is-nan/1.0.1: resolution: {integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=} engines: {node: '>=0.10.0'} - dev: true /nwsapi/2.2.0: resolution: {integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==} @@ -6404,15 +6418,9 @@ packages: /object-assign/4.1.1: resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=} engines: {node: '>=0.10.0'} - dev: true - - /object-inspect/1.11.0: - resolution: {integrity: sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==} - dev: true /object-inspect/1.12.0: resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==} - dev: true /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -6429,6 +6437,15 @@ packages: object-keys: 1.1.1 dev: true + /object.values/1.1.5: + resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.3 + es-abstract: 1.19.1 + dev: true + /on-finished/2.3.0: resolution: {integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=} engines: {node: '>= 0.8'} @@ -6501,6 +6518,13 @@ packages: dependencies: p-map: 2.1.0 + /p-limit/1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + dependencies: + p-try: 1.0.0 + dev: true + /p-limit/2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -6514,6 +6538,13 @@ packages: yocto-queue: 0.1.0 dev: false + /p-locate/2.0.0: + resolution: {integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=} + engines: {node: '>=4'} + dependencies: + p-limit: 1.3.0 + dev: true + /p-locate/3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} @@ -6555,13 +6586,17 @@ packages: '@types/retry': 0.12.1 retry: 0.13.1 + /p-try/1.0.0: + resolution: {integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=} + engines: {node: '>=4'} + dev: true + /p-try/2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} /packet-reader/1.0.0: resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} - dev: true /parent-module/1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -6574,10 +6609,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.15.8 + '@babel/code-frame': 7.16.7 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.1.6 + lines-and-columns: 1.2.4 /parse5/6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} @@ -6626,12 +6661,10 @@ packages: /pg-connection-string/2.5.0: resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} - dev: true /pg-int8/1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - dev: true /pg-pool/3.4.1_pg@8.7.1: resolution: {integrity: sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==} @@ -6641,9 +6674,16 @@ packages: pg: 8.7.1 dev: true + /pg-pool/3.5.1_pg@8.7.3: + resolution: {integrity: sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.7.3 + dev: false + /pg-protocol/1.5.0: resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==} - dev: true /pg-types/2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} @@ -6654,7 +6694,6 @@ packages: postgres-bytea: 1.0.0 postgres-date: 1.0.7 postgres-interval: 1.2.0 - dev: true /pg/8.7.1: resolution: {integrity: sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==} @@ -6671,21 +6710,38 @@ packages: pg-pool: 3.4.1_pg@8.7.1 pg-protocol: 1.5.0 pg-types: 2.2.0 - pgpass: 1.0.4 + pgpass: 1.0.5 dev: true - /pgpass/1.0.4: - resolution: {integrity: sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==} + /pg/8.7.3: + resolution: {integrity: sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=2.0.0' + peerDependenciesMeta: + pg-native: + optional: true dependencies: - split2: 3.2.2 - dev: true + buffer-writer: 2.0.0 + packet-reader: 1.0.0 + pg-connection-string: 2.5.0 + pg-pool: 3.5.1_pg@8.7.3 + pg-protocol: 1.5.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + dev: false + + /pgpass/1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.1.0 /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true - /picomatch/2.3.0: - resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==} + /picomatch/2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} /pirates/4.0.4: @@ -6713,7 +6769,6 @@ packages: resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} dependencies: semver-compare: 1.0.0 - dev: true /plur/4.0.0: resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} @@ -6730,44 +6785,39 @@ packages: /postgres-array/2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} - dev: true /postgres-bytea/1.0.0: resolution: {integrity: sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=} engines: {node: '>=0.10.0'} - dev: true /postgres-date/1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} - dev: true /postgres-interval/1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} dependencies: xtend: 4.0.2 - dev: true - /prebuild-install/6.1.4: - resolution: {integrity: sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==} - engines: {node: '>=6'} + /prebuild-install/7.0.1: + resolution: {integrity: sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==} + engines: {node: '>=10'} hasBin: true dependencies: - detect-libc: 1.0.3 + detect-libc: 2.0.0 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.5 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 2.30.1 + node-abi: 3.7.0 npmlog: 4.1.2 pump: 3.0.0 rc: 1.2.8 - simple-get: 3.1.0 + simple-get: 4.0.1 tar-fs: 2.1.1 tunnel-agent: 0.6.0 - dev: true optional: true /prelude-ls/1.1.2: @@ -6793,8 +6843,8 @@ packages: hasBin: true dev: true - /pretty-format/27.4.6: - resolution: {integrity: sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==} + /pretty-format/27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: ansi-regex: 5.0.1 @@ -6817,7 +6867,6 @@ packages: /process/0.11.10: resolution: {integrity: sha1-czIwDoQBYb2j5podHZGn1LwW8YI=} engines: {node: '>= 0.6.0'} - dev: true /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} @@ -6840,30 +6889,26 @@ packages: /psl/1.8.0: resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==} - dev: true /pump/3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} dependencies: end-of-stream: 1.4.4 once: 1.4.0 - dev: true optional: true /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} - dev: true - /qs/6.10.1: - resolution: {integrity: sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==} + /qs/6.10.3: + resolution: {integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==} engines: {node: '>=0.6'} dependencies: side-channel: 1.0.4 - dev: true - /qs/6.5.2: - resolution: {integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==} + /qs/6.5.3: + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} engines: {node: '>=0.6'} dev: true optional: true @@ -6904,7 +6949,6 @@ packages: ini: 1.3.8 minimist: 1.2.5 strip-json-comments: 2.0.1 - dev: true /react-is/17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -6964,7 +7008,7 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: - picomatch: 2.3.0 + picomatch: 2.3.1 dev: true /redent/3.0.0: @@ -7006,6 +7050,10 @@ packages: redis-parser: 3.0.0 dev: true + /regenerator-runtime/0.13.9: + resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} + dev: true + /regexpp/3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -7014,7 +7062,6 @@ packages: /replace-string/3.1.0: resolution: {integrity: sha512-yPpxc4ZR2makceA9hy/jHNqc7QVkd4Je/N0WRHm6bs3PtivPuPynxE5ejU/mp5EhnCv8+uZL7vhz8rkluSlx+Q==} engines: {node: '>=8'} - dev: true /request/2.88.2: resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} @@ -7033,10 +7080,10 @@ packages: is-typedarray: 1.0.0 isstream: 0.1.2 json-stringify-safe: 5.0.1 - mime-types: 2.1.33 + mime-types: 2.1.34 oauth-sign: 0.9.0 performance-now: 2.1.0 - qs: 6.5.2 + qs: 6.5.3 safe-buffer: 5.2.1 tough-cookie: 2.5.0 tunnel-agent: 0.6.0 @@ -7087,31 +7134,33 @@ packages: /resolve/1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: - is-core-module: 2.8.0 + is-core-module: 2.8.1 path-parse: 1.0.7 dev: true - /resolve/1.20.0: - resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==} - dependencies: - is-core-module: 2.8.0 - path-parse: 1.0.7 - /resolve/1.21.0: resolution: {integrity: sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==} hasBin: true dependencies: - is-core-module: 2.8.0 + is-core-module: 2.8.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true + /resolve/1.22.0: + resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==} + hasBin: true + dependencies: + is-core-module: 2.8.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + /restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} dependencies: onetime: 5.1.2 - signal-exit: 3.0.5 + signal-exit: 3.0.6 /retry/0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} @@ -7123,14 +7172,12 @@ packages: /rfdc/1.3.0: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} - dev: true /rimraf/2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true dependencies: glob: 7.2.0 - dev: true /rimraf/3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -7143,10 +7190,10 @@ packages: dependencies: queue-microtask: 1.2.3 - /rxjs/7.4.0: - resolution: {integrity: sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==} + /rxjs/7.5.2: + resolution: {integrity: sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==} dependencies: - tslib: 2.1.0 + tslib: 2.3.1 dev: true /safe-buffer/5.1.2: @@ -7157,11 +7204,9 @@ packages: /safer-buffer/2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true /sax/1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} - dev: true /saxes/5.0.1: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} @@ -7172,7 +7217,6 @@ packages: /semver-compare/1.0.0: resolution: {integrity: sha1-De4hahyUGrN+nvsXiPavxf9VN/w=} - dev: true /semver/5.3.0: resolution: {integrity: sha1-myzl094C0XxgEq0yaqa00M9U+U8=} @@ -7194,7 +7238,6 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 - dev: true /send/0.17.2: resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} @@ -7227,7 +7270,6 @@ packages: /set-blocking/2.0.0: resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=} - dev: true /setprototypeof/1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -7253,23 +7295,20 @@ packages: call-bind: 1.0.2 get-intrinsic: 1.1.1 object-inspect: 1.12.0 - dev: true - /signal-exit/3.0.5: - resolution: {integrity: sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==} + /signal-exit/3.0.6: + resolution: {integrity: sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==} /simple-concat/1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - dev: true optional: true - /simple-get/3.1.0: - resolution: {integrity: sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==} + /simple-get/4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} dependencies: - decompress-response: 4.2.1 + decompress-response: 6.0.0 once: 1.4.0 simple-concat: 1.0.1 - dev: true optional: true /sisteransi/1.0.5: @@ -7336,7 +7375,7 @@ packages: resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.10 + spdx-license-ids: 3.0.11 /spdx-exceptions/2.3.0: resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} @@ -7345,20 +7384,14 @@ packages: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.10 - - /spdx-license-ids/3.0.10: - resolution: {integrity: sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==} + spdx-license-ids: 3.0.11 /spdx-license-ids/3.0.11: resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==} - dev: true - /split2/3.2.2: - resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} - dependencies: - readable-stream: 3.6.0 - dev: true + /split2/4.1.0: + resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} + engines: {node: '>= 10.x'} /sprintf-js/1.0.3: resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} @@ -7366,7 +7399,6 @@ packages: /sprintf-js/1.1.2: resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} - dev: true /sql-template-tag/4.0.0: resolution: {integrity: sha512-S82ZPaT3a8rw7dDfOQyrVR82fQPA0qqihq/qkKIZrm4IfkP8RpyT6SyF+syp2Pmf8pzPh63H3yTIMuBRsL95kQ==} @@ -7392,12 +7424,12 @@ packages: node-gyp: 3.8.0 dev: true - /sshpk/1.16.1: - resolution: {integrity: sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==} + /sshpk/1.17.0: + resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} engines: {node: '>=0.10.0'} hasBin: true dependencies: - asn1: 0.2.4 + asn1: 0.2.6 assert-plus: 1.0.0 bcrypt-pbkdf: 1.0.2 dashdash: 1.14.1 @@ -7436,7 +7468,6 @@ packages: /stoppable/1.1.0: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} - dev: true /string-argv/0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} @@ -7462,7 +7493,6 @@ packages: code-point-at: 1.1.0 is-fullwidth-code-point: 1.0.0 strip-ansi: 3.0.1 - dev: true /string-width/4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -7472,12 +7502,12 @@ packages: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - /string-width/5.0.1: - resolution: {integrity: sha512-5ohWO/M4//8lErlUUtrFy3b11GtNOuMOU0ysKCDXFcfXuuvUXu95akgj/i8ofmaGdN0hCqyl6uu9i8dS/mQp5g==} + /string-width/5.1.0: + resolution: {integrity: sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==} engines: {node: '>=12'} dependencies: + eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - is-fullwidth-code-point: 4.0.0 strip-ansi: 7.0.1 dev: true @@ -7510,7 +7540,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: ansi-regex: 2.1.1 - dev: true /strip-ansi/6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} @@ -7525,6 +7554,11 @@ packages: ansi-regex: 6.0.1 dev: true + /strip-bom/3.0.0: + resolution: {integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=} + engines: {node: '>=4'} + dev: true + /strip-bom/4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -7543,7 +7577,6 @@ packages: /strip-json-comments/2.0.1: resolution: {integrity: sha1-PFMZQukIwml8DsNEhYwobHygpgo=} engines: {node: '>=0.10.0'} - dev: true /strip-json-comments/3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} @@ -7584,7 +7617,6 @@ packages: /supports-preserve-symlinks-flag/1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - dev: true /symbol-tree/3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -7597,7 +7629,6 @@ packages: mkdirp-classic: 0.5.3 pump: 3.0.0 tar-stream: 2.2.0 - dev: true optional: true /tar-stream/2.2.0: @@ -7639,38 +7670,34 @@ packages: dependencies: chownr: 2.0.0 fs-minipass: 2.1.0 - minipass: 3.1.5 + minipass: 3.1.6 minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 dev: false - /tarn/3.0.1: - resolution: {integrity: sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==} + /tarn/3.0.2: + resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==} engines: {node: '>=8.0.0'} - dev: true - /tedious/11.8.0_debug@4.3.3: - resolution: {integrity: sha512-GtFrO694x/7CRiUBt0AI4jrMtrkXV+ywifiOrDy4K0ufJLeKB4rgmPjy5Ws366fCaBaKlqQ9RnJ+sCJ1Jbd1lw==} - engines: {node: '>= 10'} + /tedious/14.1.0_debug@4.3.3: + resolution: {integrity: sha512-9DU4696o8ToSAviVn0y4D7rbBS49NYOkJ0eiNW50A81qXZT+5YWTQxnGp4HctW4qFkwklzBsp5lcdnOdWIRHSA==} + engines: {node: '>= 12'} dependencies: '@azure/identity': 1.5.2_debug@4.3.3 '@azure/keyvault-keys': 4.3.0 - '@azure/ms-rest-nodeauth': 3.1.0_debug@4.3.3 - '@js-joda/core': 3.2.0 - adal-node: 0.2.3_debug@4.3.3 + '@js-joda/core': 4.3.1 bl: 5.0.0 - depd: 2.0.0 iconv-lite: 0.6.3 jsbi: 3.2.5 native-duplexpair: 1.0.0 - node-abort-controller: 2.0.0 + node-abort-controller: 3.0.1 punycode: 2.1.1 sprintf-js: 1.1.2 transitivePeerDependencies: - debug + - encoding - supports-color - dev: true /temp-dir/1.0.0: resolution: {integrity: sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=} @@ -7685,7 +7712,7 @@ packages: resolution: {integrity: sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==} engines: {node: '>=8'} dependencies: - graceful-fs: 4.2.8 + graceful-fs: 4.2.9 is-stream: 2.0.1 make-dir: 3.1.0 temp-dir: 1.0.0 @@ -7775,15 +7802,6 @@ packages: dev: true optional: true - /tough-cookie/3.0.1: - resolution: {integrity: sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==} - engines: {node: '>=6'} - dependencies: - ip-regex: 2.1.0 - psl: 1.8.0 - punycode: 2.1.1 - dev: true - /tough-cookie/4.0.0: resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==} engines: {node: '>=6'} @@ -7791,7 +7809,6 @@ packages: psl: 1.8.0 punycode: 2.1.1 universalify: 0.1.2 - dev: true /tr46/0.0.3: resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=} @@ -7808,8 +7825,8 @@ packages: engines: {node: '>=8'} dev: true - /ts-jest/27.1.2_5cdf3cc77b92d7dbbe266bec95b76432: - resolution: {integrity: sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==} + /ts-jest/27.1.3_78f71c585925c0b28fff5bb303a854b3: + resolution: {integrity: sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true peerDependencies: @@ -7829,11 +7846,11 @@ packages: esbuild: optional: true dependencies: - '@types/jest': 27.4.0 + '@types/jest': 27.4.1 bs-logger: 0.2.6 - esbuild: 0.14.10 + esbuild: 0.13.14 fast-json-stable-stringify: 2.1.0 - jest: 27.4.6_ts-node@10.4.0 + jest: 27.5.1_ts-node@10.4.0 jest-util: 27.4.2 json5: 2.2.0 lodash.memoize: 4.1.2 @@ -7843,8 +7860,8 @@ packages: yargs-parser: 20.2.9 dev: true - /ts-jest/27.1.2_96b3dccf67dffb8a903f55c0ad4de774: - resolution: {integrity: sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==} + /ts-jest/27.1.3_e3f3aae470b938602dcd13c1910abd3b: + resolution: {integrity: sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} hasBin: true peerDependencies: @@ -7864,21 +7881,51 @@ packages: esbuild: optional: true dependencies: - '@types/jest': 27.4.0 + '@types/jest': 27.4.1 bs-logger: 0.2.6 - esbuild: 0.13.14 + esbuild: 0.14.27 fast-json-stable-stringify: 2.1.0 - jest: 27.4.6_ts-node@10.4.0 + jest: 27.5.1_ts-node@10.4.0 jest-util: 27.4.2 json5: 2.2.0 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.3.5 - typescript: 4.5.4 + typescript: 4.6.2 yargs-parser: 20.2.9 dev: true - /ts-node/10.4.0_60e8b8d4e7c9a6973679cdf61ab01fe0: + /ts-node/10.4.0_7b0dfbb3f059e21b66ca1381a90df8cf: + resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.7.0 + '@tsconfig/node10': 1.0.8 + '@tsconfig/node12': 1.0.9 + '@tsconfig/node14': 1.0.1 + '@tsconfig/node16': 1.0.2 + '@types/node': 12.20.47 + acorn: 8.7.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.5.4 + yn: 3.1.1 + dev: true + + /ts-node/10.4.0_82274b92ec7bae91027ffd577a5efb53: resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} hasBin: true peerDependencies: @@ -7893,12 +7940,13 @@ packages: optional: true dependencies: '@cspotcode/source-map-support': 0.7.0 + '@swc/core': 1.2.141 '@tsconfig/node10': 1.0.8 '@tsconfig/node12': 1.0.9 '@tsconfig/node14': 1.0.1 '@tsconfig/node16': 1.0.2 - '@types/node': 14.18.3 - acorn: 8.5.0 + '@types/node': 12.20.47 + acorn: 8.7.0 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 @@ -7908,7 +7956,7 @@ packages: yn: 3.1.1 dev: true - /ts-node/10.4.0_9303900730675ceadab88ac326bf0384: + /ts-node/10.4.0_b575a4ed8d8a14db25cb9540c04f64f6: resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} hasBin: true peerDependencies: @@ -7927,8 +7975,8 @@ packages: '@tsconfig/node12': 1.0.9 '@tsconfig/node14': 1.0.1 '@tsconfig/node16': 1.0.2 - '@types/node': 12.20.39 - acorn: 8.5.0 + '@types/node': 14.18.12 + acorn: 8.7.0 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 @@ -7942,6 +7990,15 @@ packages: resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} dev: true + /tsconfig-paths/3.12.0: + resolution: {integrity: sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.1 + minimist: 1.2.5 + strip-bom: 3.0.0 + dev: true + /tsd/0.19.1: resolution: {integrity: sha512-pSwchclr+ADdxlahRUQXUrdAIOjXx1T1PQV+fLfVLuo/S4z+T00YU84fH8iPlZxyA2pWgJjo42BG1p9SDb4NOw==} engines: {node: '>=12'} @@ -7949,7 +8006,7 @@ packages: dependencies: '@tsd/typescript': 4.5.4 eslint-formatter-pretty: 4.1.0 - globby: 11.0.4 + globby: 11.1.0 meow: 9.0.0 path-exists: 4.0.0 read-pkg-up: 7.0.1 @@ -7957,15 +8014,9 @@ packages: /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - - /tslib/2.1.0: - resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==} - dev: true /tslib/2.3.1: resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} - dev: true /tsutils/3.21.0_typescript@4.5.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -7985,13 +8036,11 @@ packages: resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=} dependencies: safe-buffer: 5.2.1 - dev: true optional: true /tunnel/0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - dev: true /tweetnacl/0.14.5: resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=} @@ -8053,7 +8102,7 @@ packages: engines: {node: '>= 0.6'} dependencies: media-typer: 0.3.0 - mime-types: 2.1.33 + mime-types: 2.1.34 dev: true /typedarray-to-buffer/3.1.5: @@ -8068,6 +8117,12 @@ packages: hasBin: true dev: true + /typescript/4.6.2: + resolution: {integrity: sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + /unbox-primitive/1.0.1: resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==} dependencies: @@ -8077,12 +8132,8 @@ packages: which-boxed-primitive: 1.0.2 dev: true - /underscore/1.13.1: - resolution: {integrity: sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==} - dev: true - - /undici/4.12.1: - resolution: {integrity: sha512-MSfap7YiQJqTPP12C11PFRs9raZuVicDbwsZHTjB0a8+SsCqt7KdUis54f373yf7ZFhJzAkGJLaKm0202OIxHg==} + /undici/4.16.0: + resolution: {integrity: sha512-tkZSECUYi+/T1i4u+4+lwZmQgLXd4BLGlrc7KZPcLIW7Jpq99+Xpc30ONv7nS6F5UNOxp/HBZSSL9MafUrvJbw==} engines: {node: '>=12.18'} dev: false @@ -8095,7 +8146,6 @@ packages: /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - dev: true /universalify/2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} @@ -8150,11 +8200,11 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true - /v8-to-istanbul/8.1.0: - resolution: {integrity: sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==} + /v8-to-istanbul/8.1.1: + resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} engines: {node: '>=10.12.0'} dependencies: - '@types/istanbul-lib-coverage': 2.0.3 + '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 1.8.0 source-map: 0.7.3 dev: true @@ -8181,7 +8231,7 @@ packages: dependencies: assert-plus: 1.0.0 core-util-is: 1.0.2 - extsprintf: 1.4.0 + extsprintf: 1.3.0 dev: true optional: true @@ -8191,7 +8241,7 @@ packages: dependencies: assert-plus: 1.0.0 core-util-is: 1.0.2 - extsprintf: 1.4.0 + extsprintf: 1.4.1 dev: true /w3c-hr-time/1.0.2: @@ -8279,7 +8329,6 @@ packages: dependencies: isexe: 2.0.0 dev: true - optional: true /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -8292,7 +8341,6 @@ packages: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: string-width: 1.0.2 - dev: true /word-wrap/1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} @@ -8324,12 +8372,12 @@ packages: dependencies: imurmurhash: 0.1.4 is-typedarray: 1.0.0 - signal-exit: 3.0.5 + signal-exit: 3.0.6 typedarray-to-buffer: 3.1.5 dev: true - /ws/7.5.5: - resolution: {integrity: sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==} + /ws/7.5.6: + resolution: {integrity: sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==} engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 @@ -8345,32 +8393,28 @@ packages: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} dev: true + /xml/1.0.1: + resolution: {integrity: sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=} + dev: true + /xml2js/0.4.23: resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} engines: {node: '>=4.0.0'} dependencies: sax: 1.2.4 xmlbuilder: 11.0.1 - dev: true /xmlbuilder/11.0.1: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} - dev: true /xmlchars/2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true - /xpath.js/1.1.0: - resolution: {integrity: sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==} - engines: {node: '>=0.4.0'} - dev: true - /xtend/4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - dev: true /y18n/5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} diff --git a/reproductions/basic-sqlite/index.ts b/reproductions/basic-sqlite/index.ts new file mode 100644 index 000000000000..7bf5e32ea64c --- /dev/null +++ b/reproductions/basic-sqlite/index.ts @@ -0,0 +1,21 @@ +import { PrismaClient } from '.prisma/client' + +async function main() { + const prisma = new PrismaClient() + + const email = `user.${Date.now()}@prisma.io` + await prisma.user.create({ + data: { + email: email, + }, + }) + + const users = await prisma.user.findMany() + + console.log(users) +} + +void main().catch((e) => { + console.log(e.message) + process.exit(1) +}) diff --git a/reproductions/basic-sqlite/package.json b/reproductions/basic-sqlite/package.json new file mode 100644 index 000000000000..df16302c59b6 --- /dev/null +++ b/reproductions/basic-sqlite/package.json @@ -0,0 +1,19 @@ +{ + "private": true, + "name": "basic-sqlite", + "description": "Prisma development playground", + "main": "index.ts", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@prisma/client": "../../packages/client" + }, + "devDependencies": { + "@types/node": "17.0.21", + "prisma": "../../packages/cli", + "ts-node": "10.4.0", + "typescript": "4.5.5" + } +} diff --git a/reproductions/basic-sqlite/prisma/schema.prisma b/reproductions/basic-sqlite/prisma/schema.prisma new file mode 100644 index 000000000000..3d33110c9d2f --- /dev/null +++ b/reproductions/basic-sqlite/prisma/schema.prisma @@ -0,0 +1,31 @@ +generator client { + provider = "prisma-client-js" + output = "../node_modules/.prisma/client" + previewFeatures = [] +} + +datasource db { + provider = "sqlite" + url = "file:./dev.db" +} + +model Link { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + url String + shortUrl String + user User? @relation(fields: [userId], references: [id]) + userId String? +} + +model User { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + name String? + email String @unique + links Link[] + date DateTime? + decimal Decimal? +} diff --git a/reproductions/pnpm-workspace.yaml b/reproductions/pnpm-workspace.yaml new file mode 100644 index 000000000000..a2dc0713a157 --- /dev/null +++ b/reproductions/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - '*' diff --git a/scripts/bench.ts b/scripts/bench.ts index 3c79cf09eec9..64fc2cafc68a 100644 --- a/scripts/bench.ts +++ b/scripts/bench.ts @@ -1,22 +1,22 @@ -import execa from "execa"; -import globby from "globby"; -import path from "path"; +import execa from 'execa' +import globby from 'globby' +import path from 'path' async function main() { - const benchmarks = await globby("./packages/**/*.bench.ts", { + const benchmarks = await globby('./packages/**/*.bench.ts', { gitignore: true, - }); - await run(benchmarks); + }) + await run(benchmarks) } async function run(benchmarks: string[]) { for (const location of benchmarks) { await execa.command(`yarn ts-node ${location}`, { cwd: path.join(__dirname, `..`), - stdio: "inherit", - }); + stdio: 'inherit', + }) } } main().catch((e) => { - console.error(e); - process.exit(1); -}); + console.error(e) + process.exit(1) +}) diff --git a/scripts/bump-engines.ts b/scripts/bump-engines.ts index 8b0515acb611..3e2399476d94 100644 --- a/scripts/bump-engines.ts +++ b/scripts/bump-engines.ts @@ -35,9 +35,8 @@ async function run(cwd: string, cmd: string): Promise { }) } catch (e) { throw new Error( - chalk.bold.red( - `Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`, - ) + (e.stderr || e.stack || e.message), + chalk.bold.red(`Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`) + + (e.stderr || e.stack || e.message), ) } } diff --git a/scripts/check-version-conflicts.ts b/scripts/check-version-conflicts.ts index 67ada98b2cbb..7e178a135d6b 100644 --- a/scripts/check-version-conflicts.ts +++ b/scripts/check-version-conflicts.ts @@ -1,10 +1,10 @@ -import globby from 'globby' -import { promises as fs } from 'fs' -import path from 'path' -import chalk from 'chalk' import arg from 'arg' -import pMap from 'p-map' +import chalk from 'chalk' import execa from 'execa' +import { promises as fs } from 'fs' +import globby from 'globby' +import pMap from 'p-map' +import path from 'path' type PackageUser = { path: string @@ -16,17 +16,13 @@ const tab = ' ' async function main() { const packagePaths = await globby( - [ - 'migrate/package.json', - 'prisma2/cli/**/package.json', - 'prisma-client-js/packages/**/package.json', - ], + ['migrate/package.json', 'prisma2/cli/**/package.json', 'prisma-client-js/packages/**/package.json'], { ignore: ['**/node_modules/**', '**/examples/**'], }, ) const packages = await Promise.all( - packagePaths.map(async p => ({ + packagePaths.map(async (p) => ({ path: p, package: JSON.parse(await fs.readFile(p, 'utf-8')), })), @@ -35,20 +31,22 @@ async function main() { const packageCache: { [key: string]: PackageUser[] } = {} for (const p of packages) { - const handler = dev => ([name, version]: any) => { - const v = version.replace('^', '') - if (packageCache[name]) { - if (packageCache[name].find(c => c.version !== v)) { - packageCache[name].push({ - path: p.path, - version: v, - dev, - }) + const handler = + (dev) => + ([name, version]: any) => { + const v = version.replace('^', '') + if (packageCache[name]) { + if (packageCache[name].find((c) => c.version !== v)) { + packageCache[name].push({ + path: p.path, + version: v, + dev, + }) + } + } else { + packageCache[name] = [{ path: p.path, version: v, dev }] } - } else { - packageCache[name] = [{ path: p.path, version: v, dev }] } - } if (p.package.dependencies) { Object.entries(p.package.dependencies).forEach(handler(false)) } @@ -60,22 +58,17 @@ async function main() { Object.entries(packageCache).forEach(([key, value]) => { let out = '\n' if (value.length > 1) { - out += - chalk.bold.red(`Version mismatch`) + ` for ${chalk.bold.blue(key)}\n` - value.forEach(v => { - out += `${tab}${chalk.underline(v.path).padEnd(60)}${v.version.padEnd( - 20, - )} ${v.dev ? chalk.dim('dependency') : chalk.dim('devDependency')}\n` + out += chalk.bold.red(`Version mismatch`) + ` for ${chalk.bold.blue(key)}\n` + value.forEach((v) => { + out += `${tab}${chalk.underline(v.path).padEnd(60)}${v.version.padEnd(20)} ${ + v.dev ? chalk.dim('dependency') : chalk.dim('devDependency') + }\n` }) console.error(out) } }) - console.log( - `Found mismatches for ${ - Object.values(packageCache).filter(v => v.length > 1).length - } packages`, - ) + console.log(`Found mismatches for ${Object.values(packageCache).filter((v) => v.length > 1).length} packages`) const argv = arg({ ['--auto-fix']: Boolean, @@ -94,20 +87,12 @@ async function main() { if (!packageName.startsWith('@types')) { return } - const latestVersion = await runResult( - '.', - `npm info ${packageName} version`, - ) - console.log( - `\nSetting ${chalk.blue(`${packageName}@${latestVersion}`)}`, - ) + const latestVersion = await runResult('.', `npm info ${packageName} version`) + console.log(`\nSetting ${chalk.blue(`${packageName}@${latestVersion}`)}`) await pMap( packageUsers, - async u => { - await run( - path.dirname(u.path), - `yarn add ${packageName}@${latestVersion}${u.dev ? ' -D' : ''}`, - ) + async (u) => { + await run(path.dirname(u.path), `yarn add ${packageName}@${latestVersion}${u.dev ? ' -D' : ''}`) }, { concurrency: 1 }, ) @@ -128,9 +113,8 @@ async function runResult(cwd: string, cmd: string): Promise { return result.stdout } catch (e) { throw new Error( - chalk.bold.red( - `Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`, - ) + (e.stderr || e.stack || e.message), + chalk.bold.red(`Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`) + + (e.stderr || e.stack || e.message), ) } } @@ -144,9 +128,8 @@ async function run(cwd: string, cmd: string): Promise { }) } catch (e) { throw new Error( - chalk.bold.red( - `Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`, - ) + (e.stderr || e.stack || e.message), + chalk.bold.red(`Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`) + + (e.stderr || e.stack || e.message), ) } } diff --git a/scripts/ci/all.ts b/scripts/ci/all.ts index 252650a5e76c..baedb4ad5155 100644 --- a/scripts/ci/all.ts +++ b/scripts/ci/all.ts @@ -19,9 +19,7 @@ async function run(cwd: string, cmd: string): Promise { }) } catch (e) { throw new Error( - chalk.red( - `Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`, - ) + (e.stderr || e.stack || e.message), + chalk.red(`Error running ${chalk.bold(cmd)} in ${chalk.underline(cwd)}:`) + (e.stderr || e.stack || e.message), ) } } @@ -29,32 +27,18 @@ async function run(cwd: string, cmd: string): Promise { async function all() { const argv = process.argv.slice(2) if (argv.length === 0) { - throw new Error( - `Please provide a command like so: ts-node scripts/ci/all.ts git status`, - ) + throw new Error(`Please provide a command like so: ts-node scripts/ci/all.ts git status`) } const command = argv.join(' ') - console.log( - chalk.cyanBright.bold(`prisma `.padEnd(10)) + chalk.bold(command) + '\n', - ) + console.log(chalk.cyanBright.bold(`prisma `.padEnd(10)) + chalk.bold(command) + '\n') await run(`prisma`, command) - console.log( - '\n' + - chalk.cyanBright.bold(`migrate `.padEnd(10)) + - chalk.bold(command) + - '\n', - ) + console.log('\n' + chalk.cyanBright.bold(`migrate `.padEnd(10)) + chalk.bold(command) + '\n') await run(`migrate`, command) - console.log( - '\n' + - chalk.cyanBright.bold(`prisma-client-js `.padEnd(10)) + - chalk.bold(command) + - '\n', - ) + console.log('\n' + chalk.cyanBright.bold(`prisma-client-js `.padEnd(10)) + chalk.bold(command) + '\n') await run(`prisma-client-js`, command) } diff --git a/scripts/ci/publish.ts b/scripts/ci/publish.ts index a38d5959a33a..37f885b0abe0 100644 --- a/scripts/ci/publish.ts +++ b/scripts/ci/publish.ts @@ -4,7 +4,7 @@ import arg from 'arg' import topo from 'batching-toposort' import chalk from 'chalk' import execa from 'execa' -import { promises as fs, existsSync } from 'fs' +import { existsSync, promises as fs } from 'fs' import globby from 'globby' import fetch from 'node-fetch' import pMap from 'p-map' @@ -14,6 +14,7 @@ import path from 'path' import redis from 'redis' import semver from 'semver' import { promisify } from 'util' + import { unique } from './unique' export type Commit = { diff --git a/scripts/graph-dependencies.ts b/scripts/graph-dependencies.ts index 650da92dd5c0..f53f6b4d1483 100644 --- a/scripts/graph-dependencies.ts +++ b/scripts/graph-dependencies.ts @@ -1,11 +1,9 @@ import { readdirSync, statSync } from 'fs' -import { digraph } from 'graphviz' +import { digraph } from 'graphviz-mit' import { join } from 'path' const getDirectories = (path: string) => { - const packages = readdirSync(path).filter((any) => - statSync(join(path, any)).isDirectory(), - ) + const packages = readdirSync(path).filter((any) => statSync(join(path, any)).isDirectory()) const result = packages.map((pkg) => ({ dirName: pkg, path: join('..', path, pkg), diff --git a/scripts/lint.ts b/scripts/lint.ts deleted file mode 100644 index d082b58a268c..000000000000 --- a/scripts/lint.ts +++ /dev/null @@ -1,148 +0,0 @@ -import execa from 'execa' -import path from 'path' -import chalk from 'chalk' -import os from 'os' -import arg from 'arg' -import globby from 'globby' -import staged from 'staged-git-files' -import pMap from 'p-map' - -async function main() { - const args = arg({ - '--staged': Boolean, - }) - - if (args._.length === 1) { - const result = await lintPackage(args._[0]) - if (!result) { - process.exit(1) - } - } - - let packages = [] as string[] - if (args['--staged']) { - packages = await getStagedPackages() - } else { - packages = await getAllPackages() - } - - if (packages.length === 0) { - console.log( - chalk.blueBright('Nothing to lint ') + chalk.bold.greenBright(`✔️`), - ) - } - - const results = await pMap( - packages, - (pkg) => lintPackage(pkg, args['--staged']), - { - concurrency: args['--staged'] ? 1 : os.cpus().length, - }, - ) - - if (results.some((r) => !r)) { - process.exit(1) - } -} - -/** - * Examples: - * Lint all packages: - * pnpm run lint - * - * Lint a specific package: - * pnpm run lint - * pnpm run lint engine-core - * pnpm run lint client - * - * Lint the staged files: - * pnpm run lint --staged - */ - -main().catch((e) => { - console.error(e) - process.exit(1) -}) - -async function getAllPackages(): Promise { - const packages = await globby('./packages/*/package.json') - return packages.map((p) => path.basename(path.dirname(p))) -} - -async function lintPackage(pkg: string, stagedOnly = false): Promise { - try { - const lint = process.env.CI ? 'lint-ci' : 'lint' - const command = `pnpm run ${stagedOnly ? 'precommit' : lint}` - console.log(`${pkg}: running ${command}`) - await execa.command(command, { - cwd: path.join(__dirname, `../packages/${pkg}`), - stdio: 'pipe', - env: { - ...process.env, - FORCE_COLOR: '1', - }, - }) - printPkg(chalk.bold.greenBright(`✔️`), pkg) - return true - } catch (e: any) { - console.log() - printPkg(e.stdout, pkg) - printPkg(e.stderr, pkg) - return false - } -} - -function prefixLine(color: string, pkg: string, line: string) { - return `${chalk.bold.underline[color](pkg)} ${line}` -} - -function printPkg(msg: string, pkg: string) { - const color = getColor() - console.log( - msg - .split('\n') - .map((l) => prefixLine(color, pkg, l)) - .join('\n'), - ) -} - -async function getStagedPackages(): Promise { - const files: Array<{ filename: string; status: string }> = await staged() - - return Object.keys( - files.reduce((acc, { filename, status }) => { - if (status !== 'Deleted' && /packages\/.*?\/src\//.exec(filename)) { - let packageName = filename.slice('packages/'.length) - packageName = packageName.slice(0, packageName.indexOf('/')) - if (!acc[packageName]) { - acc[packageName] = true - } - } - return acc - }, {}), - ) -} - -const colors = [ - 'blue', - 'yellow', - 'magenta', - 'blueBright', - 'magentaBright', - 'cyanBright', - 'cyan', - 'green', - 'black', - 'white', - 'blackBright', - 'redBright', - 'greenBright', - 'yellowBright', - 'whiteBright', -] - -let colorIndex = 0 - -function getColor() { - return colors[colorIndex++ % colors.length] -} diff --git a/scripts/only-allow-pnpm.js b/scripts/only-allow-pnpm.js index b39a183fc49a..ef3c5973b0b6 100644 --- a/scripts/only-allow-pnpm.js +++ b/scripts/only-allow-pnpm.js @@ -4,61 +4,57 @@ // https://github.com/zkochan/packages/blob/80a87115e134b2222124e1af91e01b074b4921b6/which-pm-runs/index.js const whichPMRuns = function () { if (!process.env.npm_config_user_agent) { - return undefined; + return undefined } - return pmFromUserAgent(process.env.npm_config_user_agent); -}; + return pmFromUserAgent(process.env.npm_config_user_agent) +} function pmFromUserAgent(userAgent) { - const pmSpec = userAgent.split(" ")[0]; - const separatorPos = pmSpec.lastIndexOf("/"); + const pmSpec = userAgent.split(' ')[0] + const separatorPos = pmSpec.lastIndexOf('/') return { name: pmSpec.substr(0, separatorPos), version: pmSpec.substr(separatorPos + 1), - }; + } } // Inlined because always running npx is slow // from https://github.com/pnpm/only-allow/blob/c9cd3039b365454c8f064a8304bac0ec7fc6d5fa/bin.js -const argv = process.argv.slice(2); +const argv = process.argv.slice(2) if (argv.length === 0) { - console.log( - "Please specify the wanted package manager: only-allow \n" - ); - process.exit(1); + console.log('Please specify the wanted package manager: only-allow \n') + process.exit(1) } -const wantedPM = argv[0]; -if (wantedPM !== "npm" && wantedPM !== "pnpm" && wantedPM !== "yarn") { - console.log( - `"${wantedPM}" is not a valid package manager. Available package managers are: npm, pnpm, or yarn.\n` - ); - process.exit(1); +const wantedPM = argv[0] +if (wantedPM !== 'npm' && wantedPM !== 'pnpm' && wantedPM !== 'yarn') { + console.log(`"${wantedPM}" is not a valid package manager. Available package managers are: npm, pnpm, or yarn.\n`) + process.exit(1) } -const usedPM = whichPMRuns(); +const usedPM = whichPMRuns() if (usedPM && usedPM.name !== wantedPM) { switch (wantedPM) { - case "npm": - console.log('Use "npm install" for installation in this project\n'); - break; - case "pnpm": + case 'npm': + console.log('Use "npm install" for installation in this project\n') + break + case 'pnpm': console.log( `Use "pnpm install" for installation in this project. If you don't have pnpm, install it via "npm i -g pnpm". -For more details, go to https://pnpm.js.org/\n` - ); - break; - case "yarn": +For more details, go to https://pnpm.io/\n`, + ) + break + case 'yarn': console.log( `Use "yarn" for installation in this project. If you don't have Yarn, install it via "npm i -g yarn". -For more details, go to https://yarnpkg.com/\n` - ); - break; +For more details, go to https://yarnpkg.com/\n`, + ) + break } - process.exit(1); + process.exit(1) } diff --git a/scripts/setup.ts b/scripts/setup.ts index 6d3f4c5939fd..6bb62f199d21 100644 --- a/scripts/setup.ts +++ b/scripts/setup.ts @@ -1,10 +1,7 @@ -import execa from 'execa' import chalk from 'chalk' -import path from 'path' -import pRetry from 'p-retry' -import pMap from 'p-map' -import { getPackages, getPublishOrder, getPackageDependencies } from './ci/publish' +import execa from 'execa' import fetch from 'node-fetch' +import path from 'path' async function main() { // this is for when you want to use it locally @@ -27,7 +24,7 @@ has to point to the dev version you want to promote, for example 2.1.0-dev.123`) if (process.env.RELEASE_PROMOTE_DEV) { // this is a way to get the commit hash of that specific version - const versions = await getPrismaCommitFromPackageJsonViaUnpkg(process.env.RELEASE_PROMOTE_DEV) + const versions = await getPrismaCommitFromPackageJsonViaNpmRegistry(process.env.RELEASE_PROMOTE_DEV) await run(`.`, `git stash`) // TODO: can we remove this? await run(`.`, `git checkout ${versions.prisma}`, true) // TODO: disable the dry run here @@ -50,11 +47,6 @@ has to point to the dev version you want to promote, for example 2.1.0-dev.123`) } // TODO: separate into utils shared between publish & setup - const rawPackages = await getPackages() - const packages = getPackageDependencies(rawPackages) - const publishOrder = getPublishOrder(packages) - - console.log('publish order', publishOrder) if (buildOnly === false) { console.debug(`Installing dependencies`) await run('.', `pnpm i`).catch((e) => { @@ -63,62 +55,12 @@ has to point to the dev version you want to promote, for example 2.1.0-dev.123`) } console.debug(`Building packages`) - - // TODO: replace with pnpm -r - for (const batch of publishOrder) { - await pMap( - batch, - async (pkgName) => { - const pkg = packages[pkgName] - const pkgDir = path.dirname(pkg.path) - const runPromise = run(pkgDir, 'pnpm run build') - - // we want to build all in build-only to see all errors at once - if (buildOnly) { - runPromise.catch(console.error) - - // for sqlite3 native bindings, they need a rebuild after an update - if (['@prisma/migrate', '@prisma/integration-tests'].includes(pkgName)) { - await run(pkgDir, 'pnpm rebuild') - } - } - - await runPromise - }, - { concurrency: 1 }, - ) - } + // Build CLI + await run('.', `pnpm -r build`) if (buildOnly) { return } - - // TODO: this can now be removed - // this should not be necessary, it's an pnpm bug - // it doesn't execute postinstall correctly - for (const batch of publishOrder) { - for (const pkgName of batch) { - const pkg = packages[pkgName] - if (pkg.packageJson.scripts.postinstall) { - const pkgDir = path.dirname(pkg.path) - await run(pkgDir, 'pnpm run postinstall') - } - } - } - - // TODO: same as the other retry? - // final install on top level - await pRetry( - async () => { - await run('.', 'pnpm i') - }, - { - retries: 6, - onFailedAttempt: (e) => { - console.error(e) - }, - }, - ) } // TODO: fix this @@ -205,8 +147,8 @@ async function branchExists(dir: string, branch: string): Promise { return exists } -async function getPrismaCommitFromPackageJsonViaUnpkg(npmVersion: string): Promise<{ prisma: string }> { - return fetch(`https://unpkg.com/prisma@${npmVersion}/package.json`, { +async function getPrismaCommitFromPackageJsonViaNpmRegistry(npmVersion: string): Promise<{ prisma: string }> { + return fetch(`https://registry.npmjs.org/prisma/${npmVersion}`, { headers: { accept: 'application/json', }, diff --git a/tsconfig.json b/tsconfig.json index 3b20f0ea9bef..bd5cf79590c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,10 +17,6 @@ "@prisma/engines-version": ["../engines-wrapper/packages/engines-version/src"] } }, - "include": ["**/*"], - "exclude": [ - "**/dist", - "**/build", - "**/node_modules" - ] + "include": ["**/*", ".eslintrc.js"], + "exclude": ["**/dist", "**/build", "**/node_modules", "**/packages"] }