diff --git a/.eslintignore b/.eslintignore index 94ac4254b..d88c5d722 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,3 +5,4 @@ examples **/*.js **/*.mjs **/*.cjs +**/playground diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 7af1bd426..bc71e00bc 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -16,6 +16,7 @@ rules: - error - disallowTypeAnnotations: false fixStyle: separate-type-imports + '@typescript-eslint/no-import-type-side-effects': 'error' import/no-cycle: error import/no-self-import: error import/no-empty-named-blocks: error @@ -66,3 +67,4 @@ rules: '@typescript-eslint/ban-ts-comment': 'off' '@typescript-eslint/no-empty-interface': 'off' '@typescript-eslint/no-unsafe-declaration-merging': 'off' + 'no-inner-declarations': 'off' diff --git a/.github/workflows/release-feature-branch.yaml b/.github/workflows/release-feature-branch.yaml index a588079f2..3126e994a 100644 --- a/.github/workflows/release-feature-branch.yaml +++ b/.github/workflows/release-feature-branch.yaml @@ -79,11 +79,35 @@ jobs: - name: Install dependencies run: pnpm install + - name: Check preconditions + id: checks + shell: bash + working-directory: ${{ matrix.package }} + run: | + old_version="$(jq -r .version package.json)" + version="$old_version-$(git rev-parse --short HEAD)" + npm version $version + tag="${{ github.ref_name }}" + is_version_published="$(npm view ${{ matrix.package }} versions --json | jq -r '.[] | select(. == "'$version'") | . == "'$version'"')" + + if [[ "$is_version_published" == "true" ]]; then + echo "\`${{ matrix.package }}@$version\` already published, adding tag \`$tag\`" >> $GITHUB_STEP_SUMMARY + npm dist-tag add ${{ matrix.package }}@$version $tag + else + { + echo "version=$version" + echo "tag=$tag" + echo "has_new_release=true" + } >> $GITHUB_OUTPUT + fi + - name: Build + if: steps.checks.outputs.has_new_release == 'true' run: | pnpm build - name: Run tests + if: steps.checks.outputs.has_new_release == 'true' env: PG_CONNECTION_STRING: postgres://postgres:postgres@localhost:5432/drizzle MYSQL_CONNECTION_STRING: mysql://root:root@localhost:3306/drizzle @@ -99,28 +123,37 @@ jobs: pnpm test --filter ${{ matrix.package }} fi + - name: Pack + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + npm run pack + + - name: Run @arethetypeswrong/cli + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + pnpm attw package.tgz + - name: Publish - if: github.event_name == 'push' + if: github.event_name == 'push' && steps.checks.outputs.has_new_release == 'true' run: | - tag="${{ github.ref_name }}" - old_version="$(jq -r .version package.json)" - version="$old_version-$(git rev-parse --short HEAD)" - is_version_published="$(npm view ${{ matrix.package }} versions --json | jq -r '.[] | select(. == "'$version'") | . == "'$version'"')" + tag="${{ steps.checks.outputs.tag }}" + version="${{ steps.checks.outputs.version }}" - if [[ "$is_version_published" == "true" ]]; then - echo "Version $version already published, adding tag $tag" - npm dist-tag add ${{ matrix.package }}@$version $tag - else - echo "Publishing ${{ matrix.package }}@$tag using version $version" - (cd dist && npm version $version) - npm run pack - npm run publish -- --tag $tag - fi + echo "Publishing ${{ matrix.package }}@$tag using version $version" + npm run publish -- --tag $tag echo "npm: \`${{ matrix.package }}@$tag | ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY # Post release message to Discord - curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}/v/$version\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Version\", \"value\": \"\`$version\`\"}, {\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_DEV_RELEASE_WEBHOOK_URL }} + # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}/v/$version\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Version\", \"value\": \"\`$version\`\"}, {\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_DEV_RELEASE_WEBHOOK_URL }} working-directory: ${{ matrix.package }} shell: bash env: diff --git a/.github/workflows/release-latest.yaml b/.github/workflows/release-latest.yaml index c49c56707..3153adb32 100644 --- a/.github/workflows/release-latest.yaml +++ b/.github/workflows/release-latest.yaml @@ -79,8 +79,12 @@ jobs: run: | latest="$(npm view --json ${{ matrix.package }} dist-tags.latest | jq -r)" version="$(jq -r .version package.json)" + is_version_published="$(npm view ${{ matrix.package }} versions --json | jq -r '.[] | select(. == "'$version'") | . == "'$version'"')" - if [[ "$latest" != "$version" ]]; then + if [[ "$is_version_published" == "true" ]]; then + echo "\`${{ matrix.package }}@$version\` already published, adding tag \`latest\`" >> $GITHUB_STEP_SUMMARY + npm dist-tag add ${{ matrix.package }}@$version latest + elif [[ "$latest" != "$version" ]]; then echo "Latest: $latest" echo "Current: $version" @@ -119,6 +123,24 @@ jobs: pnpm test --filter ${{ matrix.package }} fi + - name: Pack + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + npm run pack + + - name: Run @arethetypeswrong/cli + if: steps.checks.outputs.has_new_release == 'true' + working-directory: ${{ matrix.package }} + shell: bash + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: | + pnpm attw package.tgz + - name: Publish if: steps.checks.outputs.has_new_release == 'true' working-directory: ${{ matrix.package }} @@ -127,21 +149,14 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} run: | version="${{ steps.checks.outputs.version }}" - is_version_published="$(npm view ${{ matrix.package }} versions --json | jq -r '.[] | select(. == "'$version'") | . == "'$version'"')" - if [[ "$is_version_published" == "true" ]]; then - echo "Version $version already published, adding tag $tag" - npm dist-tag add ${{ matrix.package }}@$version latest - else - echo echo "Publishing ${{ matrix.package }}@$version" - npm run pack - npm run publish - fi + echo "Publishing ${{ matrix.package }}@$version" + npm run publish echo "npm: \`+ ${{ matrix.package }}@$version\`" >> $GITHUB_STEP_SUMMARY # Post release message to Discord - curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} + # curl -X POST -H "Content-Type: application/json" -d "{\"embeds\": [{\"title\": \"New \`${{ matrix.package }}\` release! 🎉\", \"url\": \"https://www.npmjs.com/package/${{ matrix.package }}\", \"color\": \"12907856\", \"fields\": [{\"name\": \"Tag\", \"value\": \"\`$tag\`\"}]}]}" ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }} - name: Create GitHub release for ORM package uses: actions/github-script@v6 diff --git a/changelogs/drizzle-orm/0.28.6.md b/changelogs/drizzle-orm/0.28.6.md new file mode 100644 index 000000000..7a894c698 --- /dev/null +++ b/changelogs/drizzle-orm/0.28.6.md @@ -0,0 +1,140 @@ +## Changes + +> **Note**: +> MySQL `datetime` with `mode: 'date'` will now store dates in UTC strings and retrieve data in UTC as well to align with MySQL behavior for `datetime`. If you need a different behavior and want to handle `datetime` mapping in a different way, please use `mode: 'string'` or [Custom Types](https://orm.drizzle.team/docs/custom-types) implementation + +Check [Fix Datetime mapping for MySQL](https://github.com/drizzle-team/drizzle-orm/pull/1082) for implementation details + +## New Features + +### 🎉 `LibSQL` batch api support + +Reference: https://docs.turso.tech/reference/client-access/javascript-typescript-sdk#execute-a-batch-of-statements + +Batch API usage example: + +```ts +const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ + id: usersTable.id, + }), + db.update(usersTable).set({ name: 'Dan' }).where(eq(usersTable.id, 1)), + db.query.usersTable.findMany({}), + db.select().from(usersTable).where(eq(usersTable.id, 1)), + db.select({ id: usersTable.id, invitedBy: usersTable.invitedBy }).from( + usersTable, + ), +]); +``` + +Type for `batchResponse` in this example would be: + +```ts +type BatchResponse = [ + { + id: number; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + invitedBy: number | null; + }[], +]; +``` + +All possible builders that can be used inside `db.batch`: + +```ts +`db.all()`, +`db.get()`, +`db.values()`, +`db.run()`, +`db.query..findMany()`, +`db.query.
.findFirst()`, +`db.select()...`, +`db.update()...`, +`db.delete()...`, +`db.insert()...`, +``` + +More usage examples here: [integration-tests/tests/libsql-batch.test.ts](https://github.com/drizzle-team/drizzle-orm/pull/1161/files#diff-17253895532e520545027dd48dcdbac2d69a5a49d594974e6d55d7502f89b838R248) and in [docs](https://orm.drizzle.team/docs/batch-api) + +### 🎉 Add json mode for text in SQLite + +Example + +```ts +const test = sqliteTable('test', { + dataTyped: text('data_typed', { mode: 'json' }).$type<{ a: 1 }>().notNull(), +}); +``` + +### 🎉 Add `.toSQL()` to Relational Query API calls + +Example + +```ts +const query = db.query.usersTable.findFirst().toSQL(); +``` + +### 🎉 Added new PostgreSQL operators for Arrays - thanks @L-Mario564 + +List of operators and usage examples +`arrayContains`, `arrayContained`, `arrayOverlaps` + +```ts +const contains = await db.select({ id: posts.id }).from(posts) + .where(arrayContains(posts.tags, ['Typescript', 'ORM'])); + +const contained = await db.select({ id: posts.id }).from(posts) + .where(arrayContained(posts.tags, ['Typescript', 'ORM'])); + +const overlaps = await db.select({ id: posts.id }).from(posts) + .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])); + +const withSubQuery = await db.select({ id: posts.id }).from(posts) + .where(arrayContains( + posts.tags, + db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)), + )); +``` + +### 🎉 Add more SQL operators for where filter function in Relational Queries - thanks @cayter! + +**Before** + +```ts +import { inArray } from "drizzle-orm/pg-core"; + +await db.users.findFirst({ + where: (table, _) => inArray(table.id, [ ... ]) +}) +``` + +**After** + +```ts +await db.users.findFirst({ + where: (table, { inArray }) => inArray(table.id, [ ... ]) +}) +``` + +## Bug Fixes + +- 🐛 [Correct where in on conflict in sqlite](https://github.com/drizzle-team/drizzle-orm/pull/1076) - Thanks @hanssonduck! +- 🐛 [Fix libsql/client type import](https://github.com/drizzle-team/drizzle-orm/pull/1122) - Thanks @luisfvieirasilva! +- 🐛 [Fix: raw sql query not being mapped properly on RDS](https://github.com/drizzle-team/drizzle-orm/pull/1071) - Thanks @boian-ivanov +- 🐛 [Fix Datetime mapping for MySQL](https://github.com/drizzle-team/drizzle-orm/pull/1082) - thanks @Angelelz +- 🐛 [Fix smallserial generating as serial](https://github.com/drizzle-team/drizzle-orm/pull/1127) - thanks @L-Mario564 diff --git a/changelogs/drizzle-orm/0.29.0.md b/changelogs/drizzle-orm/0.29.0.md new file mode 100644 index 000000000..18a24e502 --- /dev/null +++ b/changelogs/drizzle-orm/0.29.0.md @@ -0,0 +1,321 @@ +> Drizzle ORM version `0.29.0` will require a minimum Drizzle Kit version of `0.20.0`, and vice versa. Therefore, when upgrading to a newer version of Drizzle ORM, you will also need to upgrade Drizzle Kit. This may result in some breaking changes throughout the versions, especially if you need to upgrade Drizzle Kit and your Drizzle ORM version is older than `<0.28.0` + +## New Features + +### 🎉 MySQL `unsigned` option for bigint + +You can now specify `bigint unsigned` type + +```ts +const table = mysqlTable('table', { + id: bigint('id', { mode: 'number', unsigned: true }), +}); +``` + +Read more in [docs](https://orm.drizzle.team/docs/column-types/mysql#bigint) + +### 🎉 Improved query builder types + +Starting from `0.29.0` by default, as all the query builders in Drizzle try to conform to SQL as much as possible, you can only invoke most of the methods once. For example, in a SELECT statement there might only be one WHERE clause, so you can only invoke .where() once: + +```ts +const query = db + .select() + .from(users) + .where(eq(users.id, 1)) + .where(eq(users.name, 'John')); // ❌ Type error - where() can only be invoked once +``` + +This behavior is useful for conventional query building, i.e. when you create the whole query at once. However, it becomes a problem when you want to build a query dynamically, i.e. if you have a shared function that takes a query builder and enhances it. To solve this problem, Drizzle provides a special 'dynamic' mode for query builders, which removes the restriction of invoking methods only once. To enable it, you need to call .$dynamic() on a query builder. + +Let's see how it works by implementing a simple withPagination function that adds LIMIT and OFFSET clauses to a query based on the provided page number and an optional page size: + +```ts +function withPagination( + qb: T, + page: number, + pageSize: number = 10, +) { + return qb.limit(pageSize).offset(page * pageSize); +} + +const query = db.select().from(users).where(eq(users.id, 1)); +withPagination(query, 1); // ❌ Type error - the query builder is not in dynamic mode + +const dynamicQuery = query.$dynamic(); +withPagination(dynamicQuery, 1); // ✅ OK +``` + +Note that the withPagination function is generic, which allows you to modify the result type of the query builder inside it, for example by adding a join: + +```ts +function withFriends(qb: T) { + return qb.leftJoin(friends, eq(friends.userId, users.id)); +} + +let query = db.select().from(users).where(eq(users.id, 1)).$dynamic(); +query = withFriends(query); +``` + +Read more in [docs](https://orm.drizzle.team/docs/dynamic-query-building) + +### 🎉 Possibility to specify name for primary keys and foreign keys + +There is an issue when constraint names exceed the 64-character limit of the database. This causes the database engine to truncate the name, potentially leading to issues. Starting from `0.29.0`, you have the option to specify custom names for both `primaryKey()` and `foreignKey()`. We have also deprecated the old `primaryKey()` syntax, which can still be used but will be removed in future releases + +```ts +const table = pgTable('table', { + id: integer('id'), + name: text('name'), +}, (table) => ({ + cpk: primaryKey({ name: 'composite_key', columns: [table.id, table.name] }), + cfk: foreignKey({ + name: 'fkName', + columns: [table.id], + foreignColumns: [table.name], + }), +})); +``` + +Read more in [docs](https://orm.drizzle.team/docs/indexes-constraints#composite-primary-key) + +### 🎉 Read Replicas Support + +You can now use the Drizzle `withReplica` function to specify different database connections for read replicas and the main instance for write operations. By default, `withReplicas` will use a random read replica for read operations and the main instance for all other data modification operations. You can also specify custom logic for choosing which read replica connection to use. You have the freedom to make any weighted, custom decision for that. Here are some usage examples: + +```ts +const primaryDb = drizzle(client); +const read1 = drizzle(client); +const read2 = drizzle(client); + +const db = withReplicas(primaryDb, [read1, read2]); + +// read from primary +db.$primary.select().from(usersTable); + +// read from either read1 connection or read2 connection +db.select().from(usersTable) + +// use primary database for delete operation +db.delete(usersTable).where(eq(usersTable.id, 1)) +``` + +Implementation example of custom logic for selecting read replicas, where the first replica has a 70% chance of being chosen, and the second replica has a 30% chance of being chosen. Note that you can implement any type of random selection for read replicas + +```ts +const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + const weight = [0.7, 0.3]; + let cumulativeProbability = 0; + const rand = Math.random(); + + for (const [i, replica] of replicas.entries()) { + cumulativeProbability += weight[i]!; + if (rand < cumulativeProbability) return replica; + } + return replicas[0]! +}); +``` + +`withReplicas` function is available for all dialects in Drizzle ORM + +Read more in [docs](https://orm.drizzle.team/docs/read-replicas) + +### 🎉 Set operators support (UNION, UNION ALL, INTERSECT, INTERSECT ALL, EXCEPT, EXCEPT ALL) + +Huge thanks to @Angelelz for the significant contribution he made, from API discussions to proper type checks and runtime logic, along with an extensive set of tests. This greatly assisted us in delivering this feature in this release + +Usage examples: +All set operators can be used in a two ways: `import approach` or `builder approach` + +##### Import approach +```ts +import { union } from 'drizzle-orm/pg-core' + +const allUsersQuery = db.select().from(users); +const allCustomersQuery = db.select().from(customers); + +const result = await union(allUsersQuery, allCustomersQuery) +``` + +##### Builder approach +```ts +const result = await db.select().from(users).union(db.select().from(customers)); +``` + +Read more in [docs](https://orm.drizzle.team/docs/set-operations) + +### 🎉 New MySQL Proxy Driver + +A new driver has been released, allowing you to create your own implementation for an HTTP driver using a MySQL database. You can find usage examples in the `./examples/mysql-proxy` folder + +You need to implement two endpoints on your server that will be used for queries and migrations(Migrate endpoint is optional and only if you want to use drizzle migrations). Both the server and driver implementation are up to you, so you are not restricted in any way. You can add custom mappings, logging, and much more + +You can find both server and driver implementation examples in the `./examples/mysql-proxy` folder + +```ts +// Driver +import axios from 'axios'; +import { eq } from 'drizzle-orm/expressions'; +import { drizzle } from 'drizzle-orm/mysql-proxy'; +import { migrate } from 'drizzle-orm/mysql-proxy/migrator'; +import { cities, users } from './schema'; + +async function main() { + const db = drizzle(async (sql, params, method) => { + try { + const rows = await axios.post(`${process.env.REMOTE_DRIVER}/query`, { + sql, + params, + method, + }); + + return { rows: rows.data }; + } catch (e: any) { + console.error('Error from pg proxy server:', e.response.data); + return { rows: [] }; + } + }); + + await migrate(db, async (queries) => { + try { + await axios.post(`${process.env.REMOTE_DRIVER}/migrate`, { queries }); + } catch (e) { + console.log(e); + throw new Error('Proxy server cannot run migrations'); + } + }, { migrationsFolder: 'drizzle' }); + + await db.insert(cities).values({ id: 1, name: 'name' }); + + await db.insert(users).values({ + id: 1, + name: 'name', + email: 'email', + cityId: 1, + }); + + const usersToCityResponse = await db.select().from(users).leftJoin( + cities, + eq(users.cityId, cities.id), + ); +} +``` + +### 🎉 New PostgreSQL Proxy Driver + +Same as MySQL you can now implement your own http driver for PostgreSQL database. You can find usage examples in the `./examples/pg-proxy` folder + +You need to implement two endpoints on your server that will be used for queries and migrations (Migrate endpoint is optional and only if you want to use drizzle migrations). Both the server and driver implementation are up to you, so you are not restricted in any way. You can add custom mappings, logging, and much more + +You can find both server and driver implementation examples in the `./examples/pg-proxy` folder + +```ts +import axios from 'axios'; +import { eq } from 'drizzle-orm/expressions'; +import { drizzle } from 'drizzle-orm/pg-proxy'; +import { migrate } from 'drizzle-orm/pg-proxy/migrator'; +import { cities, users } from './schema'; + +async function main() { + const db = drizzle(async (sql, params, method) => { + try { + const rows = await axios.post(`${process.env.REMOTE_DRIVER}/query`, { sql, params, method }); + + return { rows: rows.data }; + } catch (e: any) { + console.error('Error from pg proxy server:', e.response.data); + return { rows: [] }; + } + }); + + await migrate(db, async (queries) => { + try { + await axios.post(`${process.env.REMOTE_DRIVER}/query`, { queries }); + } catch (e) { + console.log(e); + throw new Error('Proxy server cannot run migrations'); + } + }, { migrationsFolder: 'drizzle' }); + + const insertedCity = await db.insert(cities).values({ id: 1, name: 'name' }).returning(); + const insertedUser = await db.insert(users).values({ id: 1, name: 'name', email: 'email', cityId: 1 }); + const usersToCityResponse = await db.select().from(users).leftJoin(cities, eq(users.cityId, cities.id)); +} +``` + +### 🎉 `D1` Batch API support + +Reference: https://developers.cloudflare.com/d1/platform/client-api/#dbbatch + +Batch API usage example: + +```ts +const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ + id: usersTable.id, + }), + db.update(usersTable).set({ name: 'Dan' }).where(eq(usersTable.id, 1)), + db.query.usersTable.findMany({}), + db.select().from(usersTable).where(eq(usersTable.id, 1)), + db.select({ id: usersTable.id, invitedBy: usersTable.invitedBy }).from( + usersTable, + ), +]); +``` + +Type for `batchResponse` in this example would be: + +```ts +type BatchResponse = [ + { + id: number; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + invitedBy: number | null; + }[], +]; +``` + +All possible builders that can be used inside `db.batch`: + +```ts +`db.all()`, +`db.get()`, +`db.values()`, +`db.run()`, +`db.query.
.findMany()`, +`db.query.
.findFirst()`, +`db.select()...`, +`db.update()...`, +`db.delete()...`, +`db.insert()...`, +``` + +More usage examples here: [integration-tests/tests/d1-batch.test.ts](https://github.com/drizzle-team/drizzle-orm/blob/beta/integration-tests/tests/d1-batch.test.ts) and in [docs](https://orm.drizzle.team/docs/batch-api) + +--- +## Drizzle Kit 0.20.0 + +1. New way to define drizzle.config using `defineConfig` function +2. Possibility to access Cloudflare D1 with Drizzle Studio using wrangler.toml file +3. Drizzle Studio is migrating to https://local.drizzle.studio/ +4. `bigint unsigned` support +5. `primaryKeys` and `foreignKeys` now can have custom names +6. Environment variables are now automatically fetched +7. Some bug fixes and improvements + +You can read more about drizzle-kit updates [here](https://github.com/drizzle-team/drizzle-kit-mirror/releases/tag/v0.20.0) \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e9fed1334..6d2613d75 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.28.5", + "version": "0.29.0", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -12,7 +12,7 @@ "publish": "npm publish package.tgz" }, "main": "./index.cjs", - "module": "./index.mjs", + "module": "./index.js", "types": "./index.d.ts", "sideEffects": false, "publishConfig": { @@ -124,15 +124,12 @@ }, "devDependencies": { "@aws-sdk/client-rds-data": "^3.344.0", - "@cloudflare/workers-types": "^4.20230518.0", + "@cloudflare/workers-types": "^4.20230904.0", "@libsql/client": "^0.1.6", "@neondatabase/serverless": "^0.4.24", "@opentelemetry/api": "^1.4.1", "@originjs/vite-plugin-commonjs": "^1.0.3", "@planetscale/database": "^1.7.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-typescript": "^11.1.1", "@types/better-sqlite3": "^7.6.4", "@types/node": "^20.2.5", "@types/pg": "^8.10.1", @@ -141,16 +138,11 @@ "better-sqlite3": "^8.4.0", "bun-types": "^0.6.6", "cpy": "^10.1.0", - "cpy-cli": "^5.0.0", "knex": "^2.4.2", "kysely": "^0.25.0", "mysql2": "^3.3.3", "pg": "^8.11.0", "postgres": "^3.3.5", - "rimraf": "^5.0.0", - "rollup": "^3.27.2", - "rollup-plugin-dts": "^5.3.1", - "rollup-plugin-typescript2": "^0.35.0", "sql.js": "^1.8.0", "sqlite3": "^5.1.2", "tslib": "^2.5.2", diff --git a/drizzle-orm/rollup.cjs.config.ts b/drizzle-orm/rollup.cjs.config.ts deleted file mode 100644 index 52f7b959e..000000000 --- a/drizzle-orm/rollup.cjs.config.ts +++ /dev/null @@ -1,39 +0,0 @@ -import json from '@rollup/plugin-json'; -import replace from '@rollup/plugin-replace'; -import typescript from '@rollup/plugin-typescript'; -import { defineConfig } from 'rollup'; - -import { entries, external } from './rollup.common'; - -export default defineConfig([ - { - input: entries.reduce>((acc, entry) => { - const from = 'src/' + entry + '.ts'; - const to = entry; - acc[to] = from; - return acc; - }, {}), - output: { - format: 'cjs', - dir: 'dist.new', - entryFileNames: '[name].cjs', - chunkFileNames: '[name]-[hash].cjs', - sourcemap: true, - }, - external, - plugins: [ - replace({ - 'await import': 'require', - preventAssignment: true, - }), - json({ - preferConst: true, - }), - typescript({ - tsconfig: 'tsconfig.cjs.json', - outputToFilesystem: true, - incremental: false, - }), - ], - }, -]); diff --git a/drizzle-orm/rollup.common.ts b/drizzle-orm/rollup.common.ts deleted file mode 100644 index 741c1c38f..000000000 --- a/drizzle-orm/rollup.common.ts +++ /dev/null @@ -1,59 +0,0 @@ -export const entries = [ - 'index', - 'aws-data-api/pg/index', - 'aws-data-api/pg/migrator', - 'better-sqlite3/index', - 'better-sqlite3/migrator', - 'bun-sqlite/index', - 'bun-sqlite/migrator', - 'd1/index', - 'd1/migrator', - 'vercel-postgres/migrator', - 'vercel-postgres/index', - 'knex/index', - 'kysely/index', - 'libsql/index', - 'libsql/migrator', - 'mysql-core/index', - 'mysql2/index', - 'mysql2/migrator', - 'neon-serverless/index', - 'neon-serverless/migrator', - 'neon-http/index', - 'neon-http/migrator', - 'node-postgres/index', - 'node-postgres/migrator', - 'pg-core/index', - 'planetscale-serverless/index', - 'planetscale-serverless/migrator', - 'postgres-js/index', - 'postgres-js/migrator', - 'sql-js/index', - 'sql-js/migrator', - 'sqlite-core/index', - 'sqlite-proxy/index', - 'sqlite-proxy/migrator', - 'migrator', - 'version', -]; - -export const external = [ - /^node:/, - '@aws-sdk/client-rds-data', - '@cloudflare/workers-types', - '@libsql/client', - '@neondatabase/serverless', - '@planetscale/database', - 'better-sqlite3', - 'pg', - 'sql.js', - 'knex', - 'kysely', - 'mysql2', - 'mysql2/promise', - 'postgres', - 'sqlite3', - 'bun:sqlite', - '@opentelemetry/api', - '@vercel/postgres', -]; diff --git a/drizzle-orm/rollup.esm.config.ts b/drizzle-orm/rollup.esm.config.ts deleted file mode 100644 index 4b3a04910..000000000 --- a/drizzle-orm/rollup.esm.config.ts +++ /dev/null @@ -1,34 +0,0 @@ -import json from '@rollup/plugin-json'; -import typescript from '@rollup/plugin-typescript'; -import { defineConfig } from 'rollup'; - -import { entries, external } from './rollup.common'; - -export default defineConfig([ - { - input: entries.reduce>((acc, entry) => { - const from = 'src/' + entry + '.ts'; - const to = entry; - acc[to] = from; - return acc; - }, {}), - output: { - format: 'esm', - dir: 'dist.new', - entryFileNames: '[name].mjs', - chunkFileNames: '[name]-[hash].mjs', - sourcemap: true, - }, - external, - plugins: [ - json({ - preferConst: true, - }), - typescript({ - tsconfig: 'tsconfig.esm.json', - outputToFilesystem: true, - incremental: false, - }), - ], - }, -]); diff --git a/drizzle-orm/scripts/build.ts b/drizzle-orm/scripts/build.ts index e5cf56a94..058a719b9 100755 --- a/drizzle-orm/scripts/build.ts +++ b/drizzle-orm/scripts/build.ts @@ -2,10 +2,10 @@ import 'zx/globals'; import cpy from 'cpy'; -import { entries } from '../rollup.common'; +async function updateAndCopyPackageJson() { + const pkg = await fs.readJSON('package.json'); -function updateAndCopyPackageJson() { - const pkg = fs.readJSONSync('package.json'); + const entries = await glob('src/**/*.ts'); pkg.exports = entries.reduce< Record >( - (acc, entry) => { + (acc, rawEntry) => { + const entry = rawEntry.match(/src\/(.*)\.ts/)![1]!; const exportsEntry = entry === 'index' ? '.' : './' + entry.replace(/\/index$/, ''); - const importEntry = `./${entry}.mjs`; + const importEntry = `./${entry}.js`; const requireEntry = `./${entry}.cjs`; acc[exportsEntry] = { import: { - types: `./${entry}.d.mts`, + types: `./${entry}.d.ts`, default: importEntry, }, require: { @@ -42,21 +43,34 @@ function updateAndCopyPackageJson() { {}, ); - fs.writeJSONSync('dist.new/package.json', pkg, { spaces: 2 }); + await fs.writeJSON('dist.new/package.json', pkg, { spaces: 2 }); } -await $`rollup --config rollup.cjs.config.ts --configPlugin typescript`; -await $`rollup --config rollup.esm.config.ts --configPlugin typescript`; -await $`rimraf dist-dts && tsc -p tsconfig.dts.json && resolve-tspaths -p tsconfig.dts.json --out dist-dts`; -await cpy('dist-dts/**/*.d.ts', 'dist.new', { - rename: (basename) => basename.replace(/\.d\.ts$/, '.d.mts'), -}); -await cpy('dist-dts/**/*.d.ts', 'dist.new', { - rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), -}); -await cpy('dist-dts/**/*.d.ts', 'dist.new'); -fs.removeSync('dist-dts'); -fs.copySync('../README.md', 'dist.new/README.md'); -updateAndCopyPackageJson(); -fs.removeSync('dist'); -fs.renameSync('dist.new', 'dist'); +await fs.remove('dist.new'); + +await Promise.all([ + (async () => { + await $`tsup`; + })(), + (async () => { + await $`tsc -p tsconfig.dts.json`; + await cpy('dist-dts/**/*.d.ts', 'dist.new', { + rename: (basename) => basename.replace(/\.d\.ts$/, '.d.cts'), + }); + await cpy('dist-dts/**/*.d.ts', 'dist.new', { + rename: (basename) => basename.replace(/\.d\.ts$/, '.d.ts'), + }); + })(), +]); + +await Promise.all([ + $`tsup src/version.ts --no-config --dts --format esm --outDir dist.new`, + $`tsup src/version.ts --no-config --dts --format cjs --outDir dist.new`, +]); + +await $`scripts/fix-imports.ts`; + +await fs.copy('../README.md', 'dist.new/README.md'); +await updateAndCopyPackageJson(); +await fs.remove('dist'); +await fs.rename('dist.new', 'dist'); diff --git a/drizzle-orm/scripts/fix-imports.ts b/drizzle-orm/scripts/fix-imports.ts new file mode 100755 index 000000000..f2035eeda --- /dev/null +++ b/drizzle-orm/scripts/fix-imports.ts @@ -0,0 +1,89 @@ +#!/usr/bin/env -S pnpm tsx +import 'zx/globals'; + +import path from 'node:path'; +import { parse, print, visit } from 'recast'; +import parser from 'recast/parsers/typescript'; + +function resolvePathAlias(importPath: string, file: string) { + if (importPath.startsWith('~/')) { + const relativePath = path.relative(path.dirname(file), path.resolve('dist.new', importPath.slice(2))); + importPath = relativePath.startsWith('.') ? relativePath : './' + relativePath; + } + + return importPath; +} + +function fixImportPath(importPath: string, file: string, ext: string) { + importPath = resolvePathAlias(importPath, file); + + if (!/\..*\.(js|ts)$/.test(importPath)) { + return importPath; + } + + return importPath.replace(/\.(js|ts)$/, ext); +} + +const cjsFiles = await glob('dist.new/**/*.{cjs,d.cts}'); + +await Promise.all(cjsFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.cjs'); + } + this.traverse(path); + }, + visitCallExpression(path) { + if (path.value.callee.type === 'Identifier' && path.value.callee.name === 'require') { + path.value.arguments[0].value = fixImportPath(path.value.arguments[0].value, file, '.cjs'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = resolvePathAlias(path.value.argument.value, file); + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); + +const esmFiles = await glob('dist.new/**/*.{js,d.ts}'); + +await Promise.all(esmFiles.map(async (file) => { + const code = parse(await fs.readFile(file, 'utf8'), { parser }); + + visit(code, { + visitImportDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportAllDeclaration(path) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + this.traverse(path); + }, + visitExportNamedDeclaration(path) { + if (path.value.source) { + path.value.source.value = fixImportPath(path.value.source.value, file, '.js'); + } + this.traverse(path); + }, + visitTSImportType(path) { + path.value.argument.value = fixImportPath(path.value.argument.value, file, '.js'); + this.traverse(path); + }, + }); + + await fs.writeFile(file, print(code).code); +})); diff --git a/drizzle-orm/src/alias.ts b/drizzle-orm/src/alias.ts index e570921d2..ecbc2dc56 100644 --- a/drizzle-orm/src/alias.ts +++ b/drizzle-orm/src/alias.ts @@ -2,9 +2,10 @@ import type { AnyColumn } from './column.ts'; import { Column } from './column.ts'; import { entityKind, is } from './entity.ts'; import type { Relation } from './relations.ts'; -import { SQL, sql } from './sql/index.ts'; +import type { View} from './sql/sql.ts'; +import { SQL, sql } from './sql/sql.ts'; import { Table } from './table.ts'; -import { type View, ViewBaseConfig } from './view.ts'; +import { ViewBaseConfig } from './view-common.ts'; export class ColumnAliasProxyHandler implements ProxyHandler { static readonly [entityKind]: string = 'ColumnAliasProxyHandler'; diff --git a/drizzle-orm/src/aws-data-api/common/index.ts b/drizzle-orm/src/aws-data-api/common/index.ts index 805011941..9a657ba6c 100644 --- a/drizzle-orm/src/aws-data-api/common/index.ts +++ b/drizzle-orm/src/aws-data-api/common/index.ts @@ -1,6 +1,6 @@ import type { Field } from '@aws-sdk/client-rds-data'; import { TypeHint } from '@aws-sdk/client-rds-data'; -import type { QueryTypingsValue } from '~/sql/index.ts'; +import type { QueryTypingsValue } from '~/sql/sql.ts'; export function getValueFromDataApi(field: Field) { if (field.stringValue !== undefined) { diff --git a/drizzle-orm/src/aws-data-api/pg/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts index dac77b54d..e5acbe939 100644 --- a/drizzle-orm/src/aws-data-api/pg/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -9,7 +9,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import type { AwsDataApiClient, AwsDataApiPgQueryResultHKT } from './session.ts'; import { AwsDataApiSession } from './session.ts'; diff --git a/drizzle-orm/src/aws-data-api/pg/session.ts b/drizzle-orm/src/aws-data-api/pg/session.ts index 97d3dd3c0..53519e6b9 100644 --- a/drizzle-orm/src/aws-data-api/pg/session.ts +++ b/drizzle-orm/src/aws-data-api/pg/session.ts @@ -1,4 +1,4 @@ -import type { ExecuteStatementCommandOutput, Field, RDSDataClient } from '@aws-sdk/client-rds-data'; +import type { ColumnMetadata, ExecuteStatementCommandOutput, Field, RDSDataClient } from '@aws-sdk/client-rds-data'; import { BeginTransactionCommand, CommitTransactionCommand, @@ -17,8 +17,8 @@ import { type QueryResultHKT, } from '~/pg-core/index.ts'; import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, type QueryTypingsValue, type SQL, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type QueryTypingsValue, type QueryWithTypings, type SQL, sql } from '~/sql/sql.ts'; import { mapResultRow } from '~/utils.ts'; import { getValueFromDataApi, toValueParam } from '../common/index.ts'; @@ -48,6 +48,7 @@ export class AwsDataApiPreparedQuery extends Prep resourceArn: options.resourceArn, database: options.database, transactionId, + includeResultMetadata: !fields && !customResultMapper, }); } @@ -80,6 +81,9 @@ export class AwsDataApiPreparedQuery extends Prep const { fields, rawQuery, client, customResultMapper } = this; if (!fields && !customResultMapper) { const result = await client.send(rawQuery); + if (result.columnMetadata && result.columnMetadata.length > 0) { + return this.mapResultRows(result.records ?? [], result.columnMetadata); + } return result.records ?? []; } @@ -89,6 +93,18 @@ export class AwsDataApiPreparedQuery extends Prep return row.map((field: Field) => getValueFromDataApi(field)); }); } + + /** @internal */ + mapResultRows(records: Field[][], columnMetadata: ColumnMetadata[]) { + return records.map((record) => { + const row: Record = {}; + for (const [index, field] of record.entries()) { + const { name } = columnMetadata[index]!; + row[name ?? index] = getValueFromDataApi(field); // not what to default if name is undefined + } + return row; + }); + } } export interface AwsDataApiSessionOptions { @@ -131,7 +147,7 @@ export class AwsDataApiSession< } prepareQuery( - query: Query, + query: QueryWithTypings, fields: SelectedFieldsOrdered | undefined, transactionId?: string, customResultMapper?: (rows: unknown[][]) => T['execute'], diff --git a/drizzle-orm/src/batch.ts b/drizzle-orm/src/batch.ts new file mode 100644 index 000000000..0931440a5 --- /dev/null +++ b/drizzle-orm/src/batch.ts @@ -0,0 +1,8 @@ +import type { Dialect } from './column-builder.ts'; +import type { RunnableQuery } from './runnable-query.ts'; + +export type BatchItem = RunnableQuery; + +export type BatchResponse = { + [K in keyof T]: T[K]['_']['result']; +}; diff --git a/drizzle-orm/src/better-sqlite3/driver.ts b/drizzle-orm/src/better-sqlite3/driver.ts index ac2c7db0a..728586e57 100644 --- a/drizzle-orm/src/better-sqlite3/driver.ts +++ b/drizzle-orm/src/better-sqlite3/driver.ts @@ -8,7 +8,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { BetterSQLiteSession } from './session.ts'; export type BetterSQLite3Database< diff --git a/drizzle-orm/src/better-sqlite3/session.ts b/drizzle-orm/src/better-sqlite3/session.ts index 74be6830b..20d1612c2 100644 --- a/drizzle-orm/src/better-sqlite3/session.ts +++ b/drizzle-orm/src/better-sqlite3/session.ts @@ -2,15 +2,15 @@ import type { Database, RunResult, Statement } from 'better-sqlite3'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import type { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { SQLiteTransaction } from '~/sqlite-core/index.ts'; import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; import { - PreparedQuery as PreparedQueryBase, type PreparedQueryConfig as PreparedQueryConfigBase, type SQLiteExecuteMethod, + SQLitePreparedQuery as PreparedQueryBase, SQLiteSession, type SQLiteTransactionConfig, } from '~/sqlite-core/session.ts'; @@ -47,7 +47,7 @@ export class BetterSQLiteSession< customResultMapper?: (rows: unknown[][]) => unknown, ): PreparedQuery { const stmt = this.client.prepare(query.sql); - return new PreparedQuery(stmt, query.sql, query.params, this.logger, fields, executeMethod, customResultMapper); + return new PreparedQuery(stmt, query, this.logger, fields, executeMethod, customResultMapper); } override transaction( @@ -88,27 +88,26 @@ export class PreparedQuery constructor( private stmt: Statement, - private queryString: string, - private params: unknown[], + query: Query, private logger: Logger, private fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, private customResultMapper?: (rows: unknown[][]) => unknown, ) { - super('sync', executeMethod); + super('sync', executeMethod, query); } run(placeholderValues?: Record): RunResult { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); return this.stmt.run(...params); } all(placeholderValues?: Record): T['all'] { - const { fields, joinsNotNullableMap, queryString, logger, stmt, customResultMapper } = this; + const { fields, joinsNotNullableMap, query, logger, stmt, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); return stmt.all(...params); } @@ -120,8 +119,8 @@ export class PreparedQuery } get(placeholderValues?: Record): T['get'] { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); const { fields, stmt, joinsNotNullableMap, customResultMapper } = this; if (!fields && !customResultMapper) { @@ -142,8 +141,8 @@ export class PreparedQuery } values(placeholderValues?: Record): T['values'] { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); return this.stmt.raw().all(...params) as T['values']; } } diff --git a/drizzle-orm/src/bun-sqlite/driver.ts b/drizzle-orm/src/bun-sqlite/driver.ts index 36d500748..0d196ff03 100644 --- a/drizzle-orm/src/bun-sqlite/driver.ts +++ b/drizzle-orm/src/bun-sqlite/driver.ts @@ -10,7 +10,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { SQLiteBunSession } from './session.ts'; export type BunSQLiteDatabase< diff --git a/drizzle-orm/src/bun-sqlite/session.ts b/drizzle-orm/src/bun-sqlite/session.ts index 816b1ab06..612350a47 100644 --- a/drizzle-orm/src/bun-sqlite/session.ts +++ b/drizzle-orm/src/bun-sqlite/session.ts @@ -4,8 +4,8 @@ import type { Database, Statement as BunStatement } from 'bun:sqlite'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import type { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { SQLiteTransaction } from '~/sqlite-core/index.ts'; import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; @@ -14,7 +14,7 @@ import type { SQLiteExecuteMethod, SQLiteTransactionConfig, } from '~/sqlite-core/session.ts'; -import { PreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; import { mapResultRow } from '~/utils.ts'; export interface SQLiteBunSessionOptions { @@ -53,7 +53,7 @@ export class SQLiteBunSession< customResultMapper?: (rows: unknown[][]) => unknown, ): PreparedQuery { const stmt = this.client.prepare(query.sql); - return new PreparedQuery(stmt, query.sql, query.params, this.logger, fields, executeMethod, customResultMapper); + return new PreparedQuery(stmt, query, this.logger, fields, executeMethod, customResultMapper); } override transaction( @@ -98,27 +98,26 @@ export class PreparedQuery constructor( private stmt: Statement, - private queryString: string, - private params: unknown[], + query: Query, private logger: Logger, private fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, private customResultMapper?: (rows: unknown[][]) => unknown, ) { - super('sync', executeMethod); + super('sync', executeMethod, query); } run(placeholderValues?: Record): void { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); return this.stmt.run(...params); } all(placeholderValues?: Record): T['all'] { - const { fields, queryString, logger, joinsNotNullableMap, stmt, customResultMapper } = this; + const { fields, query, logger, joinsNotNullableMap, stmt, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); return stmt.all(...params); } @@ -132,8 +131,8 @@ export class PreparedQuery } get(placeholderValues?: Record): T['get'] { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); const row = this.stmt.get(...params); if (!row) { @@ -153,8 +152,8 @@ export class PreparedQuery } values(placeholderValues?: Record): T['values'] { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); return this.stmt.values(...params); } } diff --git a/drizzle-orm/src/column-builder.ts b/drizzle-orm/src/column-builder.ts index 5adce6e73..7ef9b6d14 100644 --- a/drizzle-orm/src/column-builder.ts +++ b/drizzle-orm/src/column-builder.ts @@ -2,7 +2,7 @@ import { entityKind } from '~/entity.ts'; import type { Column } from './column.ts'; import type { MySqlColumn } from './mysql-core/index.ts'; import type { PgColumn } from './pg-core/index.ts'; -import type { SQL } from './sql/index.ts'; +import type { SQL } from './sql/sql.ts'; import type { SQLiteColumn } from './sqlite-core/index.ts'; import type { Simplify } from './utils.ts'; diff --git a/drizzle-orm/src/column.ts b/drizzle-orm/src/column.ts index 836d32700..deacc073a 100644 --- a/drizzle-orm/src/column.ts +++ b/drizzle-orm/src/column.ts @@ -1,6 +1,6 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, ColumnDataType } from './column-builder.ts'; import { entityKind } from './entity.ts'; -import type { DriverValueMapper, SQL, SQLWrapper } from './sql/index.ts'; +import type { DriverValueMapper, SQL, SQLWrapper } from './sql/sql.ts'; import type { Table } from './table.ts'; import type { Update } from './utils.ts'; @@ -38,7 +38,9 @@ export interface Column< TRuntimeConfig extends object = object, // eslint-disable-next-line @typescript-eslint/no-unused-vars TTypeConfig extends object = object, -> extends DriverValueMapper, SQLWrapper {} +> extends DriverValueMapper, SQLWrapper { + // SQLWrapper runtime implementation is defined in 'sql/sql.ts' +} /* `Column` only accepts a full `ColumnConfig` as its generic. To infer parts of the config, use `AnyColumn` that accepts a partial config. diff --git a/drizzle-orm/src/d1/driver.ts b/drizzle-orm/src/d1/driver.ts index e4f32109e..0cbd0a0cc 100644 --- a/drizzle-orm/src/d1/driver.ts +++ b/drizzle-orm/src/d1/driver.ts @@ -1,20 +1,33 @@ /// - +import type { BatchItem, BatchResponse } from '~/batch.ts'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, + type ExtractTablesWithRelations, type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { SQLiteD1Session } from './session.ts'; -export type DrizzleD1Database< +export class DrizzleD1Database< TSchema extends Record = Record, -> = BaseSQLiteDatabase<'async', D1Result, TSchema>; +> extends BaseSQLiteDatabase<'async', D1Result, TSchema> { + static readonly [entityKind]: string = 'LibSQLDatabase'; + + /** @internal */ + declare readonly session: SQLiteD1Session>; + + async batch, T extends Readonly<[U, ...U[]]>>( + batch: T, + ): Promise> { + return this.session.batch(batch) as Promise>; + } +} export function drizzle = Record>( client: D1Database, @@ -42,5 +55,5 @@ export function drizzle = Record; + return new DrizzleD1Database('async', dialect, session, schema) as DrizzleD1Database; } diff --git a/drizzle-orm/src/d1/session.ts b/drizzle-orm/src/d1/session.ts index d45731764..da2040ec7 100644 --- a/drizzle-orm/src/d1/session.ts +++ b/drizzle-orm/src/d1/session.ts @@ -1,20 +1,21 @@ /// +import type { BatchItem } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { type Query, sql } from '~/sql/index.ts'; -import { fillPlaceholders } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { PreparedQuery } from '~/session.ts'; +import { type Query, sql, fillPlaceholders } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; import { SQLiteTransaction } from '~/sqlite-core/index.ts'; import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; -import { - type PreparedQueryConfig as PreparedQueryConfigBase, - type SQLiteExecuteMethod, - type SQLiteTransactionConfig, +import type { + PreparedQueryConfig as PreparedQueryConfigBase, + SQLiteExecuteMethod, + SQLiteTransactionConfig, } from '~/sqlite-core/session.ts'; -import { PreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { mapResultRow } from '~/utils.ts'; export interface SQLiteD1SessionOptions { @@ -46,9 +47,123 @@ export class SQLiteD1Session< fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, customResultMapper?: (rows: unknown[][]) => unknown, - ): PreparedQuery { + ): D1PreparedQuery { const stmt = this.client.prepare(query.sql); - return new PreparedQuery(stmt, query.sql, query.params, this.logger, fields, executeMethod, customResultMapper); + return new D1PreparedQuery(stmt, query, this.logger, fields, executeMethod, customResultMapper); + } + + /*override */ async batch>(queries: T) { + const preparedQueries: PreparedQuery[] = []; + const builtQueries: D1PreparedStatement[] = []; + + for (const query of queries) { + const preparedQuery = query.prepare(); + const builtQuery = preparedQuery.getQuery(); + preparedQueries.push(preparedQuery); + if (builtQuery.params.length > 0) { + builtQueries.push((preparedQuery as D1PreparedQuery).stmt.bind(...builtQuery.params)); + } else { + const builtQuery = preparedQuery.getQuery(); + builtQueries.push( + this.client.prepare(builtQuery.sql).bind(...builtQuery.params), + ); + } + } + + // const queryToType: ( + // | { mode: 'all' } + // | { + // mode: 'all_mapped'; + // config: { fields: SelectedFieldsOrdered; joinsNotNullableMap?: Record }; + // } + // | { mode: 'get' } + // | { mode: 'values' } + // | { mode: 'raw' } + // | { mode: 'rqb'; mapper: any } + // )[] = []; + + // const builtQueries: D1PreparedStatement[] = queries.map((query) => { + // if (is(query, SQLiteSelectBase)) { + // const prepared = query.prepare() as D1PreparedQuery; + // prepared.fields === undefined + // ? queryToType.push({ mode: 'all' }) + // : queryToType.push({ + // mode: 'all_mapped', + // config: { fields: prepared.fields, joinsNotNullableMap: prepared.joinsNotNullableMap }, + // }); + // return prepared.stmt.bind(...prepared.params); + // } else if ( + // is(query, SQLiteInsertBase) || is(query, SQLiteUpdateBase) + // || is(query, SQLiteDeleteBase) + // ) { + // const prepared = query.prepare() as D1PreparedQuery; + // queryToType.push( + // query.config.returning + // ? { + // mode: 'all_mapped', + // config: { fields: query.config.returning }, + // } + // : { mode: 'raw' }, + // ); + // return prepared.stmt.bind(...prepared.params); + // } else if (is(query, SQLiteRaw)) { + // const builtQuery = this.dialect.sqlToQuery(query.getSQL()); + // queryToType.push( + // query.config.action === 'run' ? { mode: 'raw' } : { mode: query.config.action }, + // ); + // return this.client.prepare(builtQuery.sql).bind(...builtQuery.params); + // } else if (is(query, SQLiteRelationalQuery)) { + // const preparedRqb = query.prepare() as D1PreparedQuery; + // queryToType.push({ mode: 'rqb', mapper: preparedRqb.customResultMapper }); + // return preparedRqb.stmt.bind(...preparedRqb.params); + // } + // throw new DrizzleError({ message: 'You can use only drizzle queries in D1 batch API' }); + // }); + + const batchResults = await this.client.batch(builtQueries); + return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); + + // const res = this.client.batch(builtQueries).then((stmt) => + // stmt.map(({ results }, index) => { + // const action = queryToType[index]!; + // if (action.mode === 'all') { + // return results; + // } + // if (action.mode === 'all_mapped') { + // const mappedRows = this.d1ToRawMapping(results); + // return mappedRows!.map((row) => { + // return mapResultRow( + // action.config.fields, + // row, + // action.config.joinsNotNullableMap, + // ); + // }); + // } + // if (action.mode === 'get') { + // return results![0] as unknown[]; + // } + // if (action.mode === 'values') { + // return this.d1ToRawMapping(results); + // } + // if (action.mode === 'raw') { + // return stmt[index]; + // } + // return action.mapper(this.d1ToRawMapping(results)); + // }) + // ); + // return res; + } + + override extractRawAllValueFromBatchResult(_result: unknown): unknown { + return (_result as D1Result).results; + } + + override extractRawGetValueFromBatchResult(result: unknown): unknown { + return (result as D1Result).results[0]; + } + + override extractRawValuesValueFromBatchResult(result: unknown): unknown { + return d1ToRawMapping((result as D1Result).results); } override async transaction( @@ -89,51 +204,89 @@ export class D1Transaction< } } -export class PreparedQuery extends PreparedQueryBase< +/** + * This function was taken from the D1 implementation: https://github.com/cloudflare/workerd/blob/4aae9f4c7ae30a59a88ca868c4aff88bda85c956/src/cloudflare/internal/d1-api.ts#L287 + * It may cause issues with duplicated column names in join queries, which should be fixed on the D1 side. + * @param results + * @returns + */ +function d1ToRawMapping(results: any) { + const rows: unknown[][] = []; + for (const row of results) { + const entry = Object.keys(row).map((k) => row[k]); + rows.push(entry); + } + return rows; +} + +export class D1PreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: D1Result; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { static readonly [entityKind]: string = 'D1PreparedQuery'; + /** @internal */ + customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown; + + /** @internal */ + fields?: SelectedFieldsOrdered; + + /** @internal */ + stmt: D1PreparedStatement; + constructor( - private stmt: D1PreparedStatement, - private queryString: string, - private params: unknown[], + stmt: D1PreparedStatement, + query: Query, private logger: Logger, - private fields: SelectedFieldsOrdered | undefined, + fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, - private customResultMapper?: (rows: unknown[][]) => unknown, + customResultMapper?: (rows: unknown[][]) => unknown, ) { - super('async', executeMethod); + super('async', executeMethod, query); + this.customResultMapper = customResultMapper; + this.fields = fields; + this.stmt = stmt; } run(placeholderValues?: Record): Promise { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); return this.stmt.bind(...params).run(); } async all(placeholderValues?: Record): Promise { - const { fields, joinsNotNullableMap, queryString, logger, stmt, customResultMapper } = this; + const { fields, query, logger, stmt, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); - return stmt.bind(...params).all().then(({ results }) => results!); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); + return stmt.bind(...params).all().then(({ results }) => this.mapAllResult(results!)); } const rows = await this.values(placeholderValues); - if (customResultMapper) { - return customResultMapper(rows) as T['all']; + return this.mapAllResult(rows); + } + + override mapAllResult(rows: unknown, isFromBatch?: boolean): unknown { + if (isFromBatch) { + rows = d1ToRawMapping((rows as D1Result).results); + } + + if (!this.fields && !this.customResultMapper) { + return rows; + } + + if (this.customResultMapper) { + return this.customResultMapper(rows as unknown[][]); } - return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + return (rows as unknown[][]).map((row) => mapResultRow(this.fields!, row, this.joinsNotNullableMap)); } async get(placeholderValues?: Record): Promise { - const { fields, joinsNotNullableMap, queryString, logger, stmt, customResultMapper } = this; + const { fields, joinsNotNullableMap, query, logger, stmt, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); return stmt.bind(...params).all().then(({ results }) => results![0]); } @@ -150,9 +303,25 @@ export class PreparedQuery return mapResultRow(fields!, rows[0], joinsNotNullableMap); } + override mapGetResult(result: unknown, isFromBatch?: boolean): unknown { + if (isFromBatch) { + result = d1ToRawMapping((result as D1Result).results)[0]; + } + + if (!this.fields && !this.customResultMapper) { + return result; + } + + if (this.customResultMapper) { + return this.customResultMapper([result as unknown[]]) as T['all']; + } + + return mapResultRow(this.fields!, result as unknown[], this.joinsNotNullableMap); + } + values(placeholderValues?: Record): Promise { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); return this.stmt.bind(...params).raw(); } } diff --git a/drizzle-orm/src/errors.ts b/drizzle-orm/src/errors.ts index 151264c68..ede6e0a59 100644 --- a/drizzle-orm/src/errors.ts +++ b/drizzle-orm/src/errors.ts @@ -3,15 +3,10 @@ import { entityKind } from '~/entity.ts'; export class DrizzleError extends Error { static readonly [entityKind]: string = 'DrizzleError'; - constructor(message: string) { + constructor({ message, cause }: { message?: string; cause?: unknown }) { super(message); this.name = 'DrizzleError'; - } - - static wrap(error: unknown, message?: string): DrizzleError { - return error instanceof Error // eslint-disable-line no-instanceof/no-instanceof - ? new DrizzleError(message ? `${message}: ${error.message}` : error.message) - : new DrizzleError(message ?? String(error)); + this.cause = cause; } } @@ -19,6 +14,6 @@ export class TransactionRollbackError extends DrizzleError { static readonly [entityKind]: string = 'TransactionRollbackError'; constructor() { - super('Rollback'); + super({ message: 'Rollback' }); } } diff --git a/drizzle-orm/src/index.ts b/drizzle-orm/src/index.ts index 2eb9a58ca..bc72260b9 100644 --- a/drizzle-orm/src/index.ts +++ b/drizzle-orm/src/index.ts @@ -12,4 +12,4 @@ export * from './sql/index.ts'; export * from './subquery.ts'; export * from './table.ts'; export * from './utils.ts'; -export * from './view.ts'; +export * from './view-common.ts'; diff --git a/drizzle-orm/src/libsql/driver.ts b/drizzle-orm/src/libsql/driver.ts index 2d47a52a8..3acff2893 100644 --- a/drizzle-orm/src/libsql/driver.ts +++ b/drizzle-orm/src/libsql/driver.ts @@ -1,19 +1,33 @@ import type { Client, ResultSet } from '@libsql/client'; +import type { BatchItem, BatchResponse } from '~/batch.ts'; +import { entityKind } from '~/entity.ts'; import { DefaultLogger } from '~/logger.ts'; import { createTableRelationsHelpers, extractTablesRelationalConfig, + type ExtractTablesWithRelations, type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { LibSQLSession } from './session.ts'; -export type LibSQLDatabase< +export class LibSQLDatabase< TSchema extends Record = Record, -> = BaseSQLiteDatabase<'async', ResultSet, TSchema>; +> extends BaseSQLiteDatabase<'async', ResultSet, TSchema> { + static readonly [entityKind]: string = 'LibSQLDatabase'; + + /** @internal */ + declare readonly session: LibSQLSession>; + + async batch, T extends Readonly<[U, ...U[]]>>( + batch: T, + ): Promise> { + return this.session.batch(batch) as Promise>; + } +} export function drizzle< TSchema extends Record = Record, @@ -40,5 +54,5 @@ export function drizzle< } const session = new LibSQLSession(client, dialect, schema, { logger }, undefined); - return new BaseSQLiteDatabase('async', dialect, session, schema) as LibSQLDatabase; + return new LibSQLDatabase('async', dialect, session, schema) as LibSQLDatabase; } diff --git a/drizzle-orm/src/libsql/session.ts b/drizzle-orm/src/libsql/session.ts index 210cd6429..76155f041 100644 --- a/drizzle-orm/src/libsql/session.ts +++ b/drizzle-orm/src/libsql/session.ts @@ -1,18 +1,20 @@ import type { Client, InArgs, InStatement, ResultSet, Transaction } from '@libsql/client'; +import type { BatchItem as BatchItem } from '~/batch.ts'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { PreparedQuery } from '~/session.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; import { SQLiteTransaction } from '~/sqlite-core/index.ts'; import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; -import { - type PreparedQueryConfig as PreparedQueryConfigBase, - type SQLiteExecuteMethod, - type SQLiteTransactionConfig, +import type { + PreparedQueryConfig as PreparedQueryConfigBase, + SQLiteExecuteMethod, + SQLiteTransactionConfig, } from '~/sqlite-core/session.ts'; -import { PreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { mapResultRow } from '~/utils.ts'; export interface LibSQLSessionOptions { @@ -45,11 +47,10 @@ export class LibSQLSession< fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, customResultMapper?: (rows: unknown[][]) => unknown, - ): PreparedQuery { - return new PreparedQuery( + ): LibSQLPreparedQuery { + return new LibSQLPreparedQuery( this.client, - query.sql, - query.params, + query, this.logger, fields, this.tx, @@ -58,12 +59,19 @@ export class LibSQLSession< ); } - /*override */ batch(queries: SQL[]): Promise { - const builtQueries: InStatement[] = queries.map((query) => { - const builtQuery = this.dialect.sqlToQuery(query); - return { sql: builtQuery.sql, args: builtQuery.params as InArgs }; - }); - return this.client.batch(builtQueries); + async batch[] | readonly BatchItem<'sqlite'>[]>(queries: T) { + const preparedQueries: PreparedQuery[] = []; + const builtQueries: InStatement[] = []; + + for (const query of queries) { + const preparedQuery = query.prepare(); + const builtQuery = preparedQuery.getQuery(); + preparedQueries.push(preparedQuery); + builtQueries.push({ sql: builtQuery.sql, args: builtQuery.params as InArgs }); + } + + const batchResults = await this.client.batch(builtQueries); + return batchResults.map((result, i) => preparedQueries[i]!.mapResult(result, true)); } override async transaction( @@ -83,6 +91,18 @@ export class LibSQLSession< throw err; } } + + override extractRawAllValueFromBatchResult(result: unknown): unknown { + return (result as ResultSet).rows; + } + + override extractRawGetValueFromBatchResult(result: unknown): unknown { + return (result as ResultSet).rows[0]; + } + + override extractRawValuesValueFromBatchResult(result: unknown): unknown { + return (result as ResultSet).rows; + } } export class LibSQLTransaction< @@ -106,85 +126,115 @@ export class LibSQLTransaction< } } -export class PreparedQuery extends PreparedQueryBase< +export class LibSQLPreparedQuery extends SQLitePreparedQuery< { type: 'async'; run: ResultSet; all: T['all']; get: T['get']; values: T['values']; execute: T['execute'] } > { static readonly [entityKind]: string = 'LibSQLPreparedQuery'; constructor( private client: Client, - private queryString: string, - private params: unknown[], + query: Query, private logger: Logger, - private fields: SelectedFieldsOrdered | undefined, + /** @internal */ public fields: SelectedFieldsOrdered | undefined, private tx: Transaction | undefined, executeMethod: SQLiteExecuteMethod, - private customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, + /** @internal */ public customResultMapper?: ( + rows: unknown[][], + mapColumnValue?: (value: unknown) => unknown, + ) => unknown, ) { - super('async', executeMethod); + super('async', executeMethod, query); + this.customResultMapper = customResultMapper; + this.fields = fields; } run(placeholderValues?: Record): Promise { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); - const stmt: InStatement = { sql: this.queryString, args: params as InArgs }; + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + const stmt: InStatement = { sql: this.query.sql, args: params as InArgs }; return this.tx ? this.tx.execute(stmt) : this.client.execute(stmt); } async all(placeholderValues?: Record): Promise { - const { fields, joinsNotNullableMap, logger, queryString, tx, client, customResultMapper } = this; + const { fields, logger, query, tx, client, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); - const stmt: InStatement = { sql: queryString, args: params as InArgs }; - return (tx ? tx.execute(stmt) : client.execute(stmt)).then(({ rows }) => rows.map((row) => normalizeRow(row))); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); + const stmt: InStatement = { sql: query.sql, args: params as InArgs }; + return (tx ? tx.execute(stmt) : client.execute(stmt)).then(({ rows }) => this.mapAllResult(rows)); } const rows = await this.values(placeholderValues) as unknown[][]; - if (customResultMapper) { - return customResultMapper(rows, normalizeFieldValue) as T['all']; + return this.mapAllResult(rows); + } + + override mapAllResult(rows: unknown, isFromBatch?: boolean): unknown { + if (isFromBatch) { + rows = (rows as ResultSet).rows; + } + + if (!this.fields && !this.customResultMapper) { + return (rows as unknown[]).map((row) => normalizeRow(row)); } - return rows.map((row) => { + if (this.customResultMapper) { + return this.customResultMapper(rows as unknown[][], normalizeFieldValue) as T['all']; + } + + return (rows as unknown[]).map((row) => { return mapResultRow( - fields!, + this.fields!, Array.prototype.slice.call(row).map((v) => normalizeFieldValue(v)), - joinsNotNullableMap, + this.joinsNotNullableMap, ); }); } async get(placeholderValues?: Record): Promise { - const { fields, joinsNotNullableMap, logger, queryString, tx, client, customResultMapper } = this; + const { fields, logger, query, tx, client, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); - const stmt: InStatement = { sql: queryString, args: params as InArgs }; - return (tx ? tx.execute(stmt) : client.execute(stmt)).then(({ rows }) => normalizeRow(rows[0])); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); + const stmt: InStatement = { sql: query.sql, args: params as InArgs }; + return (tx ? tx.execute(stmt) : client.execute(stmt)).then(({ rows }) => this.mapGetResult(rows)); } const rows = await this.values(placeholderValues) as unknown[][]; - if (!rows[0]) { + return this.mapGetResult(rows); + } + + override mapGetResult(rows: unknown, isFromBatch?: boolean): unknown { + if (isFromBatch) { + rows = (rows as ResultSet).rows; + } + + const row = (rows as unknown[])[0]; + + if (!this.fields && !this.customResultMapper) { + return normalizeRow(row); + } + + if (!row) { return undefined; } - if (customResultMapper) { - return customResultMapper(rows, normalizeFieldValue) as T['get']; + if (this.customResultMapper) { + return this.customResultMapper(rows as unknown[][], normalizeFieldValue) as T['get']; } return mapResultRow( - fields!, - Array.prototype.slice.call(rows[0]).map((v) => normalizeFieldValue(v)), - joinsNotNullableMap, + this.fields!, + Array.prototype.slice.call(row).map((v) => normalizeFieldValue(v)), + this.joinsNotNullableMap, ); } values(placeholderValues?: Record): Promise { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); - const stmt: InStatement = { sql: this.queryString, args: params as InArgs }; + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + const stmt: InStatement = { sql: this.query.sql, args: params as InArgs }; return (this.tx ? this.tx.execute(stmt) : this.client.execute(stmt)).then(({ rows }) => rows) as Promise< T['values'] >; @@ -205,7 +255,7 @@ function normalizeRow(obj: any) { } function normalizeFieldValue(value: unknown) { - if (value instanceof ArrayBuffer) { // eslint-disable-line no-instanceof/no-instanceof + if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { // eslint-disable-line no-instanceof/no-instanceof if (typeof Buffer !== 'undefined') { if (!(value instanceof Buffer)) { // eslint-disable-line no-instanceof/no-instanceof return Buffer.from(value); diff --git a/drizzle-orm/src/mysql-core/alias.ts b/drizzle-orm/src/mysql-core/alias.ts index 08d70f035..8320c5533 100644 --- a/drizzle-orm/src/mysql-core/alias.ts +++ b/drizzle-orm/src/mysql-core/alias.ts @@ -1,7 +1,7 @@ import { TableAliasProxyHandler } from '~/alias.ts'; import type { BuildAliasTable } from './query-builders/select.types.ts'; import type { MySqlTable } from './table.ts'; -import { type MySqlViewBase } from './view.ts'; +import type { MySqlViewBase } from './view-base.ts'; export function alias( table: TTable, diff --git a/drizzle-orm/src/mysql-core/checks.ts b/drizzle-orm/src/mysql-core/checks.ts index fa76b4537..af9a29f6a 100644 --- a/drizzle-orm/src/mysql-core/checks.ts +++ b/drizzle-orm/src/mysql-core/checks.ts @@ -1,5 +1,5 @@ import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/index.ts'; +import type { SQL } from '~/sql/sql.ts'; import type { MySqlTable } from './table.ts'; export class CheckBuilder { diff --git a/drizzle-orm/src/mysql-core/columns/bigint.ts b/drizzle-orm/src/mysql-core/columns/bigint.ts index d87195868..c80770d22 100644 --- a/drizzle-orm/src/mysql-core/columns/bigint.ts +++ b/drizzle-orm/src/mysql-core/columns/bigint.ts @@ -14,12 +14,13 @@ export type MySqlBigInt53BuilderInitial = MySqlBigInt53Bui }>; export class MySqlBigInt53Builder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static readonly [entityKind]: string = 'MySqlBigInt53Builder'; - constructor(name: T['name']) { + constructor(name: T['name'], unsigned: boolean = false) { super(name, 'number', 'MySqlBigInt53'); + this.config.unsigned = unsigned; } /** @internal */ @@ -34,12 +35,12 @@ export class MySqlBigInt53Builder> - extends MySqlColumnWithAutoIncrement + extends MySqlColumnWithAutoIncrement { static readonly [entityKind]: string = 'MySqlBigInt53'; getSQLType(): string { - return 'bigint'; + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; } override mapFromDriverValue(value: number | string): number { @@ -60,12 +61,13 @@ export type MySqlBigInt64BuilderInitial = MySqlBigInt64Bui }>; export class MySqlBigInt64Builder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static readonly [entityKind]: string = 'MySqlBigInt64Builder'; - constructor(name: T['name']) { + constructor(name: T['name'], unsigned: boolean = false) { super(name, 'bigint', 'MySqlBigInt64'); + this.config.unsigned = unsigned; } /** @internal */ @@ -80,12 +82,12 @@ export class MySqlBigInt64Builder> - extends MySqlColumnWithAutoIncrement + extends MySqlColumnWithAutoIncrement { static readonly [entityKind]: string = 'MySqlBigInt64'; getSQLType(): string { - return 'bigint'; + return `bigint${this.config.unsigned ? ' unsigned' : ''}`; } // eslint-disable-next-line unicorn/prefer-native-coercion-functions @@ -96,6 +98,7 @@ export class MySqlBigInt64 interface MySqlBigIntConfig { mode: T; + unsigned?: boolean; } export function bigint( @@ -104,7 +107,7 @@ export function bigint : MySqlBigInt64BuilderInitial; export function bigint(name: string, config: MySqlBigIntConfig) { if (config.mode === 'number') { - return new MySqlBigInt53Builder(name); + return new MySqlBigInt53Builder(name, config.unsigned); } - return new MySqlBigInt64Builder(name); + return new MySqlBigInt64Builder(name, config.unsigned); } diff --git a/drizzle-orm/src/mysql-core/columns/char.ts b/drizzle-orm/src/mysql-core/columns/char.ts index 78b845e71..5466ec046 100644 --- a/drizzle-orm/src/mysql-core/columns/char.ts +++ b/drizzle-orm/src/mysql-core/columns/char.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlCharBuilderInitial = MySqlCharBuilder<{ diff --git a/drizzle-orm/src/mysql-core/columns/common.ts b/drizzle-orm/src/mysql-core/columns/common.ts index 2f1ee2fce..fe518cebb 100644 --- a/drizzle-orm/src/mysql-core/columns/common.ts +++ b/drizzle-orm/src/mysql-core/columns/common.ts @@ -14,7 +14,7 @@ import { entityKind } from '~/entity.ts'; import type { ForeignKey, UpdateDeleteAction } from '~/mysql-core/foreign-keys.ts'; import { ForeignKeyBuilder } from '~/mysql-core/foreign-keys.ts'; import type { AnyMySqlTable, MySqlTable } from '~/mysql-core/table.ts'; -import { type Update } from '~/utils.ts'; +import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; export interface ReferenceConfig { diff --git a/drizzle-orm/src/mysql-core/columns/custom.ts b/drizzle-orm/src/mysql-core/columns/custom.ts index c67904e38..135bc8c09 100644 --- a/drizzle-orm/src/mysql-core/columns/custom.ts +++ b/drizzle-orm/src/mysql-core/columns/custom.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; -import { type Equal } from '~/utils.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { Equal } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = diff --git a/drizzle-orm/src/mysql-core/columns/date.common.ts b/drizzle-orm/src/mysql-core/columns/date.common.ts index 9800a3d90..3fd8aa612 100644 --- a/drizzle-orm/src/mysql-core/columns/date.common.ts +++ b/drizzle-orm/src/mysql-core/columns/date.common.ts @@ -6,7 +6,7 @@ import type { } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export interface MySqlDateColumnBaseConfig { diff --git a/drizzle-orm/src/mysql-core/columns/date.ts b/drizzle-orm/src/mysql-core/columns/date.ts index 396e23d60..c51971829 100644 --- a/drizzle-orm/src/mysql-core/columns/date.ts +++ b/drizzle-orm/src/mysql-core/columns/date.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Equal } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlDateBuilderInitial = MySqlDateBuilder<{ diff --git a/drizzle-orm/src/mysql-core/columns/datetime.ts b/drizzle-orm/src/mysql-core/columns/datetime.ts index 801801969..cfe9ce0b7 100644 --- a/drizzle-orm/src/mysql-core/columns/datetime.ts +++ b/drizzle-orm/src/mysql-core/columns/datetime.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Equal } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlDateTimeBuilderInitial = MySqlDateTimeBuilder<{ @@ -53,8 +53,12 @@ export class MySqlDateTime> return `datetime${precision}`; } + override mapToDriverValue(value: Date): unknown { + return value.toISOString().replace('T', ' ').replace('Z', ''); + } + override mapFromDriverValue(value: string): Date { - return new Date(value); + return new Date(value.replace(' ', 'T') + 'Z'); } } diff --git a/drizzle-orm/src/mysql-core/columns/enum.ts b/drizzle-orm/src/mysql-core/columns/enum.ts index 48221f868..a7d5399ed 100644 --- a/drizzle-orm/src/mysql-core/columns/enum.ts +++ b/drizzle-orm/src/mysql-core/columns/enum.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlEnumColumnBuilderInitial = diff --git a/drizzle-orm/src/mysql-core/columns/int.ts b/drizzle-orm/src/mysql-core/columns/int.ts index a3bdf5377..4fa1bb936 100644 --- a/drizzle-orm/src/mysql-core/columns/int.ts +++ b/drizzle-orm/src/mysql-core/columns/int.ts @@ -14,12 +14,13 @@ export type MySqlIntBuilderInitial = MySqlIntBuilder<{ }>; export class MySqlIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static readonly [entityKind]: string = 'MySqlIntBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlInt'); + this.config.unsigned = config ? config.unsigned : false; } /** @internal */ @@ -30,11 +31,13 @@ export class MySqlIntBuilder> extends MySqlColumnWithAutoIncrement { +export class MySqlInt> + extends MySqlColumnWithAutoIncrement +{ static readonly [entityKind]: string = 'MySqlInt'; getSQLType(): string { - return 'int'; + return `int${this.config.unsigned ? ' unsigned' : ''}`; } override mapFromDriverValue(value: number | string): number { @@ -45,6 +48,10 @@ export class MySqlInt> extends } } -export function int(name: TName): MySqlIntBuilderInitial { - return new MySqlIntBuilder(name); +export interface MySqlIntConfig { + unsigned?: boolean; +} + +export function int(name: TName, config?: MySqlIntConfig): MySqlIntBuilderInitial { + return new MySqlIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/mediumint.ts b/drizzle-orm/src/mysql-core/columns/mediumint.ts index e17e2f368..9a9277fe0 100644 --- a/drizzle-orm/src/mysql-core/columns/mediumint.ts +++ b/drizzle-orm/src/mysql-core/columns/mediumint.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { MySqlIntConfig } from './int.ts'; export type MySqlMediumIntBuilderInitial = MySqlMediumIntBuilder<{ name: TName; @@ -14,12 +15,13 @@ export type MySqlMediumIntBuilderInitial = MySqlMediumIntB }>; export class MySqlMediumIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static readonly [entityKind]: string = 'MySqlMediumIntBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlMediumInt'); + this.config.unsigned = config ? config.unsigned : false; } /** @internal */ @@ -34,12 +36,12 @@ export class MySqlMediumIntBuilder> - extends MySqlColumnWithAutoIncrement + extends MySqlColumnWithAutoIncrement { static readonly [entityKind]: string = 'MySqlMediumInt'; getSQLType(): string { - return 'mediumint'; + return `mediumint${this.config.unsigned ? ' unsigned' : ''}`; } override mapFromDriverValue(value: number | string): number { @@ -50,6 +52,9 @@ export class MySqlMediumInt(name: TName): MySqlMediumIntBuilderInitial { - return new MySqlMediumIntBuilder(name); +export function mediumint( + name: TName, + config?: MySqlIntConfig, +): MySqlMediumIntBuilderInitial { + return new MySqlMediumIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/smallint.ts b/drizzle-orm/src/mysql-core/columns/smallint.ts index e1723dbd0..e4653f5dd 100644 --- a/drizzle-orm/src/mysql-core/columns/smallint.ts +++ b/drizzle-orm/src/mysql-core/columns/smallint.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { MySqlIntConfig } from './int.ts'; export type MySqlSmallIntBuilderInitial = MySqlSmallIntBuilder<{ name: TName; @@ -14,12 +15,13 @@ export type MySqlSmallIntBuilderInitial = MySqlSmallIntBui }>; export class MySqlSmallIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static readonly [entityKind]: string = 'MySqlSmallIntBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlSmallInt'); + this.config.unsigned = config ? config.unsigned : false; } /** @internal */ @@ -34,12 +36,12 @@ export class MySqlSmallIntBuilder> - extends MySqlColumnWithAutoIncrement + extends MySqlColumnWithAutoIncrement { static readonly [entityKind]: string = 'MySqlSmallInt'; getSQLType(): string { - return 'smallint'; + return `smallint${this.config.unsigned ? ' unsigned' : ''}`; } override mapFromDriverValue(value: number | string): number { @@ -50,6 +52,9 @@ export class MySqlSmallInt } } -export function smallint(name: TName): MySqlSmallIntBuilderInitial { - return new MySqlSmallIntBuilder(name); +export function smallint( + name: TName, + config?: MySqlIntConfig, +): MySqlSmallIntBuilderInitial { + return new MySqlSmallIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/text.ts b/drizzle-orm/src/mysql-core/columns/text.ts index 9853532d4..8a4a30822 100644 --- a/drizzle-orm/src/mysql-core/columns/text.ts +++ b/drizzle-orm/src/mysql-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlTextColumnType = 'tinytext' | 'text' | 'mediumtext' | 'longtext'; diff --git a/drizzle-orm/src/mysql-core/columns/timestamp.ts b/drizzle-orm/src/mysql-core/columns/timestamp.ts index aed1ad04a..3b6df80d3 100644 --- a/drizzle-orm/src/mysql-core/columns/timestamp.ts +++ b/drizzle-orm/src/mysql-core/columns/timestamp.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Equal } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; import { MySqlDateBaseColumn, MySqlDateColumnBaseBuilder } from './date.common.ts'; export type MySqlTimestampBuilderInitial = MySqlTimestampBuilder<{ diff --git a/drizzle-orm/src/mysql-core/columns/tinyint.ts b/drizzle-orm/src/mysql-core/columns/tinyint.ts index 1fdef4e61..35a68cbd2 100644 --- a/drizzle-orm/src/mysql-core/columns/tinyint.ts +++ b/drizzle-orm/src/mysql-core/columns/tinyint.ts @@ -3,6 +3,7 @@ import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; +import type { MySqlIntConfig } from './int.ts'; export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuilder<{ name: TName; @@ -14,12 +15,13 @@ export type MySqlTinyIntBuilderInitial = MySqlTinyIntBuild }>; export class MySqlTinyIntBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static readonly [entityKind]: string = 'MySqlTinyIntBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config?: MySqlIntConfig) { super(name, 'number', 'MySqlTinyInt'); + this.config.unsigned = config ? config.unsigned : false; } /** @internal */ @@ -34,12 +36,12 @@ export class MySqlTinyIntBuilder> - extends MySqlColumnWithAutoIncrement + extends MySqlColumnWithAutoIncrement { static readonly [entityKind]: string = 'MySqlTinyInt'; getSQLType(): string { - return 'tinyint'; + return `tinyint${this.config.unsigned ? ' unsigned' : ''}`; } override mapFromDriverValue(value: number | string): number { @@ -50,6 +52,6 @@ export class MySqlTinyInt> } } -export function tinyint(name: TName): MySqlTinyIntBuilderInitial { - return new MySqlTinyIntBuilder(name); +export function tinyint(name: TName, config?: MySqlIntConfig): MySqlTinyIntBuilderInitial { + return new MySqlTinyIntBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/varchar.ts b/drizzle-orm/src/mysql-core/columns/varchar.ts index 99c52db77..7db55563f 100644 --- a/drizzle-orm/src/mysql-core/columns/varchar.ts +++ b/drizzle-orm/src/mysql-core/columns/varchar.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { MySqlColumn, MySqlColumnBuilder } from './common.ts'; export type MySqlVarCharBuilderInitial = MySqlVarCharBuilder< diff --git a/drizzle-orm/src/mysql-core/db.ts b/drizzle-orm/src/mysql-core/db.ts index 3c79f9d86..e3a07cee3 100644 --- a/drizzle-orm/src/mysql-core/db.ts +++ b/drizzle-orm/src/mysql-core/db.ts @@ -1,18 +1,12 @@ import type { ResultSetHeader } from 'mysql2/promise'; import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; -import { - type ExtractTablesWithRelations, - type RelationalSchemaConfig, - type TablesRelationalConfig, -} from '~/relations.ts'; -import type { SQLWrapper } from '~/sql/index.ts'; -import { SelectionProxyHandler, WithSubquery } from '~/subquery.ts'; -import { type DrizzleTypeError } from '~/utils.ts'; -import { type ColumnsSelection } from '~/view.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; import type { MySqlDialect } from './dialect.ts'; import { - MySqlDelete, + MySqlDeleteBase, MySqlInsertBuilder, MySqlSelectBuilder, MySqlUpdateBuilder, @@ -31,6 +25,8 @@ import type { } from './session.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { MySqlTable } from './table.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export class MySqlDatabase< TQueryResult extends QueryResultHKT, @@ -84,7 +80,7 @@ export class MySqlDatabase< return { as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), - ): WithSubqueryWithSelection { + ): WithSubqueryWithSelection { if (typeof qb === 'function') { qb = qb(new QueryBuilder()); } @@ -92,7 +88,7 @@ export class MySqlDatabase< return new Proxy( new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), - ) as WithSubqueryWithSelection; + ) as WithSubqueryWithSelection; }, }; } @@ -159,8 +155,8 @@ export class MySqlDatabase< return new MySqlInsertBuilder(table, this.session, this.dialect); } - delete(table: TTable): MySqlDelete { - return new MySqlDelete(table, this.session, this.dialect); + delete(table: TTable): MySqlDeleteBase { + return new MySqlDeleteBase(table, this.session, this.dialect); } execute( @@ -179,3 +175,55 @@ export class MySqlDatabase< return this.session.transaction(transaction, config); } } + +export type MySQLWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + HKT extends QueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase, + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, + Q extends MySqlDatabase< + HKT, + TPreparedQueryHKT, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): MySQLWithReplicas => { + const select: Q['select'] = (...args: any) => getReplica(replicas).select(args); + const selectDistinct: Q['selectDistinct'] = (...args: any) => getReplica(replicas).selectDistinct(args); + const $with: Q['with'] = (...args: any) => getReplica(replicas).with(args); + + const update: Q['update'] = (...args: any) => primary.update(args); + const insert: Q['insert'] = (...args: any) => primary.insert(args); + const $delete: Q['delete'] = (...args: any) => primary.delete(args); + const execute: Q['execute'] = (...args: any) => primary.execute(args); + const transaction: Q['transaction'] = (...args: any) => primary.transaction(args); + + return new Proxy( + { + ...primary, + update, + insert, + delete: $delete, + execute, + transaction, + $primary: primary, + select, + selectDistinct, + with: $with, + }, + { + get(target, prop, _receiver) { + if (prop === 'query') { + return getReplica(replicas).query; + } + return target[prop as keyof typeof target]; + }, + }, + ); +}; diff --git a/drizzle-orm/src/mysql-core/dialect.ts b/drizzle-orm/src/mysql-core/dialect.ts index 46dbd2d5e..34d5bf907 100644 --- a/drizzle-orm/src/mysql-core/dialect.ts +++ b/drizzle-orm/src/mysql-core/dialect.ts @@ -14,28 +14,19 @@ import { type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { and, eq, Param, type Query, SQL, sql, type SQLChunk } from '~/sql/index.ts'; +import { Param, type QueryWithTypings, SQL, sql, type SQLChunk, View } from '~/sql/sql.ts'; import { Subquery, SubqueryConfig } from '~/subquery.ts'; import { getTableName, Table } from '~/table.ts'; import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; -import { View, ViewBaseConfig } from '~/view.ts'; -import { DrizzleError } from '../index.ts'; +import { DrizzleError, type Name, ViewBaseConfig, and, eq } from '../index.ts'; import { MySqlColumn } from './columns/common.ts'; import type { MySqlDeleteConfig } from './query-builders/delete.ts'; import type { MySqlInsertConfig } from './query-builders/insert.ts'; -import type { Join, MySqlSelectConfig, SelectedFieldsOrdered } from './query-builders/select.types.ts'; +import type { MySqlSelectConfig, MySqlSelectJoinConfig, SelectedFieldsOrdered } from './query-builders/select.types.ts'; import type { MySqlUpdateConfig } from './query-builders/update.ts'; import type { MySqlSession } from './session.ts'; import { MySqlTable } from './table.ts'; -import { MySqlViewBase } from './view.ts'; - -// TODO find out how to use all/values. Seems like I need those functions -// Build project -// copy runtime tests to be sure it's working - -// Add mysql to drizzle-kit - -// Add Planetscale Driver and create example repo +import { MySqlViewBase } from './view-base.ts'; export class MySqlDialect { static readonly [entityKind]: string = 'MySqlDialect'; @@ -204,6 +195,7 @@ export class MySqlDialect { offset, lockingClause, distinct, + setOperators, }: MySqlSelectConfig, ): SQL { const fieldsList = fieldsFlat ?? orderSelectedFields(fields); @@ -331,7 +323,75 @@ export class MySqlDialect { } } - return sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: MySqlSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: MySqlSelectConfig['setOperators'][number] }): SQL { + const leftChunk = sql`(${leftSelect.getSQL()}) `; + const rightChunk = sql`(${rightSelect.getSQL()})`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid MySql syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const orderByUnit of orderBy) { + if (is(orderByUnit, MySqlColumn)) { + orderByValues.push(sql.identifier(orderByUnit.name)); + } else if (is(orderByUnit, SQL)) { + for (let i = 0; i < orderByUnit.queryChunks.length; i++) { + const chunk = orderByUnit.queryChunks[i]; + + if (is(chunk, MySqlColumn)) { + orderByUnit.queryChunks[i] = sql.identifier(chunk.name); + } + } + + orderByValues.push(sql`${orderByUnit}`); + } else { + orderByValues.push(sql`${orderByUnit}`); + } + } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `; + } + + const limitSql = limit ? sql` limit ${limit}` : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } buildInsertQuery({ table, values, ignore, onConflict }: MySqlInsertConfig): SQL { @@ -374,7 +434,7 @@ export class MySqlDialect { return sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`; } - sqlToQuery(sql: SQL): Query { + sqlToQuery(sql: SQL): QueryWithTypings { return sql.toQuery({ escapeName: this.escapeName, escapeParam: this.escapeParam, @@ -405,7 +465,7 @@ export class MySqlDialect { }): BuildRelationalQueryResult { let selection: BuildRelationalQueryResult['selection'] = []; let limit, offset, orderBy: MySqlSelectConfig['orderBy'], where; - const joins: Join[] = []; + const joins: MySqlSelectJoinConfig[] = []; if (config === true) { const selectionEntries = Object.entries(tableConfig.columns); @@ -578,7 +638,7 @@ export class MySqlDialect { } if (selection.length === 0) { - throw new DrizzleError(`No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")`); + throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` }); } let result; @@ -631,6 +691,7 @@ export class MySqlDialect { where, limit, offset, + setOperators: [], }); where = undefined; @@ -653,6 +714,7 @@ export class MySqlDialect { limit, offset, orderBy, + setOperators: [], }); } else { result = this.buildSelectQuery({ @@ -667,6 +729,7 @@ export class MySqlDialect { limit, offset, orderBy, + setOperators: [], }); } @@ -869,9 +932,10 @@ export class MySqlDialect { } if (selection.length === 0) { - throw new DrizzleError( - `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}"). You need to have at least one item in "columns", "with" or "extras". If you need to select all columns, omit the "columns" key or set it to undefined.`, - ); + throw new DrizzleError({ + message: + `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}"). You need to have at least one item in "columns", "with" or "extras". If you need to select all columns, omit the "columns" key or set it to undefined.`, + }); } let result; @@ -920,6 +984,7 @@ export class MySqlDialect { where, limit, offset, + setOperators: [], }); where = undefined; @@ -941,6 +1006,7 @@ export class MySqlDialect { limit, offset, orderBy, + setOperators: [], }); } else { result = this.buildSelectQuery({ @@ -954,6 +1020,7 @@ export class MySqlDialect { limit, offset, orderBy, + setOperators: [], }); } diff --git a/drizzle-orm/src/mysql-core/expressions.ts b/drizzle-orm/src/mysql-core/expressions.ts index 76db28551..a61f77786 100644 --- a/drizzle-orm/src/mysql-core/expressions.ts +++ b/drizzle-orm/src/mysql-core/expressions.ts @@ -1,6 +1,6 @@ import { bindIfParam } from '~/expressions.ts'; -import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/index.ts'; -import { sql } from '~/sql/index.ts'; +import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; import type { MySqlColumn } from './columns/index.ts'; export * from '~/expressions.ts'; diff --git a/drizzle-orm/src/mysql-core/foreign-keys.ts b/drizzle-orm/src/mysql-core/foreign-keys.ts index 8f9abdae8..957e1f15c 100644 --- a/drizzle-orm/src/mysql-core/foreign-keys.ts +++ b/drizzle-orm/src/mysql-core/foreign-keys.ts @@ -5,6 +5,7 @@ import { MySqlTable } from './table.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; export type Reference = () => { + readonly name?: string; readonly columns: MySqlColumn[]; readonly foreignTable: MySqlTable; readonly foreignColumns: MySqlColumn[]; @@ -24,6 +25,7 @@ export class ForeignKeyBuilder { constructor( config: () => { + name?: string; columns: MySqlColumn[]; foreignColumns: MySqlColumn[]; }, @@ -33,8 +35,8 @@ export class ForeignKeyBuilder { } | undefined, ) { this.reference = () => { - const { columns, foreignColumns } = config(); - return { columns, foreignTable: foreignColumns[0]!.table as MySqlTable, foreignColumns }; + const { name, columns, foreignColumns } = config(); + return { name, columns, foreignTable: foreignColumns[0]!.table as MySqlTable, foreignColumns }; }; if (actions) { this._onUpdate = actions.onUpdate; @@ -74,7 +76,7 @@ export class ForeignKey { } getName(): string { - const { columns, foreignColumns } = this.reference(); + const { name, columns, foreignColumns } = this.reference(); const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ @@ -83,7 +85,7 @@ export class ForeignKey { foreignColumns[0]!.table[MySqlTable.Symbol.Name], ...foreignColumnNames, ]; - return `${chunks.join('_')}_fk`; + return name ?? `${chunks.join('_')}_fk`; } } @@ -105,13 +107,15 @@ export function foreignKey< TColumns extends [AnyMySqlColumn<{ tableName: TTableName }>, ...AnyMySqlColumn<{ tableName: TTableName }>[]], >( config: { + name?: string; columns: TColumns; foreignColumns: ColumnsWithTable; }, ): ForeignKeyBuilder { function mappedConfig() { - const { columns, foreignColumns } = config; + const { name, columns, foreignColumns } = config; return { + name, columns, foreignColumns, }; diff --git a/drizzle-orm/src/mysql-core/index.ts b/drizzle-orm/src/mysql-core/index.ts index 7120e0c5c..204e0af3c 100644 --- a/drizzle-orm/src/mysql-core/index.ts +++ b/drizzle-orm/src/mysql-core/index.ts @@ -13,4 +13,5 @@ export * from './subquery.ts'; export * from './table.ts'; export * from './unique-constraint.ts'; export * from './utils.ts'; +export * from './view-common.ts'; export * from './view.ts'; diff --git a/drizzle-orm/src/mysql-core/indexes.ts b/drizzle-orm/src/mysql-core/indexes.ts index 8a6139e1e..5b73b1d30 100644 --- a/drizzle-orm/src/mysql-core/indexes.ts +++ b/drizzle-orm/src/mysql-core/indexes.ts @@ -1,5 +1,5 @@ import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/index.ts'; +import type { SQL } from '~/sql/sql.ts'; import type { AnyMySqlColumn, MySqlColumn } from './columns/index.ts'; import type { MySqlTable } from './table.ts'; diff --git a/drizzle-orm/src/mysql-core/primary-keys.ts b/drizzle-orm/src/mysql-core/primary-keys.ts index 26bd3edca..014cbd8c0 100644 --- a/drizzle-orm/src/mysql-core/primary-keys.ts +++ b/drizzle-orm/src/mysql-core/primary-keys.ts @@ -4,9 +4,22 @@ import { MySqlTable } from './table.ts'; export function primaryKey< TTableName extends string, + TColumn extends AnyMySqlColumn<{ tableName: TTableName }>, TColumns extends AnyMySqlColumn<{ tableName: TTableName }>[], ->(...columns: TColumns): PrimaryKeyBuilder { - return new PrimaryKeyBuilder(columns); +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnyMySqlColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); } export class PrimaryKeyBuilder { @@ -15,15 +28,20 @@ export class PrimaryKeyBuilder { /** @internal */ columns: MySqlColumn[]; + /** @internal */ + name?: string; + constructor( columns: MySqlColumn[], + name?: string, ) { this.columns = columns; + this.name = name; } /** @internal */ build(table: MySqlTable): PrimaryKey { - return new PrimaryKey(table, this.columns); + return new PrimaryKey(table, this.columns, this.name); } } @@ -31,12 +49,15 @@ export class PrimaryKey { static readonly [entityKind]: string = 'MySqlPrimaryKey'; readonly columns: MySqlColumn[]; + readonly name?: string; - constructor(readonly table: MySqlTable, columns: MySqlColumn[]) { + constructor(readonly table: MySqlTable, columns: MySqlColumn[], name?: string) { this.columns = columns; + this.name = name; } getName(): string { - return `${this.table[MySqlTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + return this.name + ?? `${this.table[MySqlTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; } } diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index 7ec773f82..33588fd16 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -1,6 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { + AnyQueryResultHKT, MySqlSession, PreparedQueryConfig, PreparedQueryHKTBase, @@ -10,28 +11,78 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/index.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; +export type MySqlDeleteWithout< + T extends AnyMySqlDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + MySqlDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type MySqlDelete< + TTable extends MySqlTable = MySqlTable, + TQueryResult extends QueryResultHKT = AnyQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = MySqlDeleteBase; + export interface MySqlDeleteConfig { where?: SQL | undefined; table: MySqlTable; returning?: SelectedFieldsOrdered; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface MySqlDelete< - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type MySqlDeletePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + PreparedQueryConfig & { + execute: QueryResultKind; + iterator: never; + }, + true +>; + +type MySqlDeleteDynamic = MySqlDelete< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +type AnyMySqlDeleteBase = MySqlDeleteBase; + +export interface MySqlDeleteBase< TTable extends MySqlTable, TQueryResult extends QueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, -> extends QueryPromise> {} + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise> { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} -export class MySqlDelete< +export class MySqlDeleteBase< TTable extends MySqlTable, TQueryResult extends QueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { static readonly [entityKind]: string = 'MySqlDelete'; @@ -46,11 +97,9 @@ export class MySqlDelete< this.config = { table }; } - where( - where: SQL | undefined, - ): Omit { + where(where: SQL | undefined): MySqlDeleteWithout { this.config.where = where; - return this; + return this as any; } /** @internal */ @@ -58,23 +107,16 @@ export class MySqlDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - prepare() { + prepare(): MySqlDeletePrepare { return this.session.prepareQuery( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, - ) as PreparedQueryKind< - TPreparedQueryHKT, - PreparedQueryConfig & { - execute: QueryResultKind; - iterator: never; - }, - true - >; + ) as MySqlDeletePrepare; } override execute: ReturnType['execute'] = (placeholderValues) => { @@ -89,4 +131,8 @@ export class MySqlDelete< }; iterator = this.createIterator(); + + $dynamic(): MySqlDeleteDynamic { + return this as any; + } } diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index f34b46011..56bf18af4 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -1,6 +1,7 @@ import { entityKind, is } from '~/entity.ts'; import type { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { + AnyQueryResultHKT, MySqlSession, PreparedQueryConfig, PreparedQueryHKTBase, @@ -10,8 +11,8 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Placeholder, Query, SQLWrapper } from '~/sql/index.ts'; -import { Param, SQL, sql } from '~/sql/index.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; import { Table } from '~/table.ts'; import { mapUpdateSet, type ValidateShape } from '~/utils.ts'; import type { MySqlUpdateSetSource } from './update.ts'; @@ -51,15 +52,15 @@ export class MySqlInsertBuilder< return this; } - values( + values>( value: ValidateShape>, - ): MySqlInsert; - values( + ): MySqlInsertBase; + values>( values: ValidateShape>[], - ): MySqlInsert; - values( + ): MySqlInsertBase; + values>( values: ValidateShape> | ValidateShape>[], - ): MySqlInsert { + ): MySqlInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -74,21 +75,75 @@ export class MySqlInsertBuilder< return result; }); - return new MySqlInsert(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); + return new MySqlInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect); } } -export interface MySqlInsert< - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type MySqlInsertWithout = + TDynamic extends true ? T + : Omit< + MySqlInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type MySqlInsertDynamic = MySqlInsert< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +export type MySqlInsertPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + PreparedQueryConfig & { + execute: QueryResultKind; + iterator: never; + }, + true +>; + +export type MySqlInsertOnDuplicateKeyUpdateConfig = { + set: MySqlUpdateSetSource; +}; + +export type MySqlInsert< + TTable extends MySqlTable = MySqlTable, + TQueryResult extends QueryResultHKT = AnyQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = MySqlInsertBase; + +export type AnyMySqlInsert = MySqlInsertBase; + +export interface MySqlInsertBase< TTable extends MySqlTable, TQueryResult extends QueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, -> extends QueryPromise>, SQLWrapper {} -export class MySqlInsert< + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class MySqlInsertBase< TTable extends MySqlTable, TQueryResult extends QueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { static readonly [entityKind]: string = 'MySqlInsert'; @@ -107,13 +162,12 @@ export class MySqlInsert< this.config = { table, values, ignore }; } - onDuplicateKeyUpdate(config: { - // target?: IndexColumn | IndexColumn[]; - set: MySqlUpdateSetSource; - }): this { + onDuplicateKeyUpdate( + config: MySqlInsertOnDuplicateKeyUpdateConfig, + ): MySqlInsertWithout { const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); this.config.onConflict = sql`update ${setSql}`; - return this; + return this as any; } /** @internal */ @@ -121,23 +175,16 @@ export class MySqlInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - prepare() { + prepare(): MySqlInsertPrepare { return this.session.prepareQuery( this.dialect.sqlToQuery(this.getSQL()), undefined, - ) as PreparedQueryKind< - TPreparedQueryHKT, - PreparedQueryConfig & { - execute: QueryResultKind; - iterator: never; - }, - true - >; + ) as MySqlInsertPrepare; } override execute: ReturnType['execute'] = (placeholderValues) => { @@ -152,4 +199,8 @@ export class MySqlInsert< }; iterator = this.createIterator(); + + $dynamic(): MySqlInsertDynamic { + return this as any; + } } diff --git a/drizzle-orm/src/mysql-core/query-builders/query-builder.ts b/drizzle-orm/src/mysql-core/query-builders/query-builder.ts index b91ce61f5..9cb5ca9e2 100644 --- a/drizzle-orm/src/mysql-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/mysql-core/query-builders/query-builder.ts @@ -2,10 +2,11 @@ import { entityKind } from '~/entity.ts'; import { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { WithSubqueryWithSelection } from '~/mysql-core/subquery.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; -import { SelectionProxyHandler, WithSubquery } from '~/subquery.ts'; -import { type ColumnsSelection } from '~/view.ts'; import { MySqlSelectBuilder } from './select.ts'; import type { SelectedFields } from './select.types.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; export class QueryBuilder { static readonly [entityKind]: string = 'MySqlQueryBuilder'; @@ -18,7 +19,7 @@ export class QueryBuilder { return { as( qb: TypedQueryBuilder | ((qb: QueryBuilder) => TypedQueryBuilder), - ): WithSubqueryWithSelection { + ): WithSubqueryWithSelection { if (typeof qb === 'function') { qb = qb(queryBuilder); } @@ -26,7 +27,7 @@ export class QueryBuilder { return new Proxy( new WithSubquery(qb.getSQL(), qb.getSelectedFields() as SelectedFields, alias, true), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), - ) as WithSubqueryWithSelection; + ) as WithSubqueryWithSelection; }, }; } @@ -35,7 +36,9 @@ export class QueryBuilder { const self = this; function select(): MySqlSelectBuilder; - function select(fields: TSelection): MySqlSelectBuilder; + function select( + fields: TSelection, + ): MySqlSelectBuilder; function select( fields?: TSelection, ): MySqlSelectBuilder { @@ -75,7 +78,9 @@ export class QueryBuilder { } selectDistinct(): MySqlSelectBuilder; - selectDistinct(fields: TSelection): MySqlSelectBuilder; + selectDistinct( + fields: TSelection, + ): MySqlSelectBuilder; selectDistinct( fields?: TSelection, ): MySqlSelectBuilder { diff --git a/drizzle-orm/src/mysql-core/query-builders/query.ts b/drizzle-orm/src/mysql-core/query-builders/query.ts index 45a040189..f14a5a74e 100644 --- a/drizzle-orm/src/mysql-core/query-builders/query.ts +++ b/drizzle-orm/src/mysql-core/query-builders/query.ts @@ -2,22 +2,17 @@ import { entityKind } from '~/entity.ts'; import { QueryPromise } from '~/query-promise.ts'; import { type BuildQueryResult, + type BuildRelationalQueryResult, type DBQueryConfig, mapRelationalRow, type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type SQL } from '~/sql/index.ts'; -import { type KnownKeysOnly } from '~/utils.ts'; -import { type MySqlDialect } from '../dialect.ts'; -import { - type Mode, - type MySqlSession, - type PreparedQueryConfig, - type PreparedQueryHKTBase, - type PreparedQueryKind, -} from '../session.ts'; -import { type MySqlTable } from '../table.ts'; +import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; +import type { MySqlDialect } from '../dialect.ts'; +import type { Mode, MySqlSession, PreparedQueryConfig, PreparedQueryHKTBase, PreparedQueryKind } from '../session.ts'; +import type { MySqlTable } from '../table.ts'; export class RelationalQueryBuilder< TPreparedQueryHKT extends PreparedQueryHKTBase, @@ -96,6 +91,21 @@ export class MySqlRelationalQuery< } prepare() { + const { query, builtQuery } = this._toSQL(); + return this.session.prepareQuery( + builtQuery, + undefined, + (rawRows) => { + const rows = rawRows.map((row) => mapRelationalRow(this.schema, this.tableConfig, row, query.selection)); + if (this.queryMode === 'first') { + return rows[0] as TResult; + } + return rows as TResult; + }, + ) as PreparedQueryKind; + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { const query = this.mode === 'planetscale' ? this.dialect.buildRelationalQueryWithoutLateralSubqueries({ fullSchema: this.fullSchema, @@ -117,17 +127,12 @@ export class MySqlRelationalQuery< }); const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); - return this.session.prepareQuery( - builtQuery, - undefined, - (rawRows) => { - const rows = rawRows.map((row) => mapRelationalRow(this.schema, this.tableConfig, row, query.selection)); - if (this.queryMode === 'first') { - return rows[0] as TResult; - } - return rows as TResult; - }, - ) as PreparedQueryKind; + + return { builtQuery, query }; + } + + toSQL(): Query { + return this._toSQL().builtQuery; } override execute(): Promise { diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index 08ab3854c..23f31342e 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -1,15 +1,9 @@ import { entityKind, is } from '~/entity.ts'; import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; import type { MySqlDialect } from '~/mysql-core/dialect.ts'; -import type { - MySqlSession, - PreparedQueryConfig, - PreparedQueryHKTBase, - PreparedQueryKind, -} from '~/mysql-core/session.ts'; +import type { MySqlSession, PreparedQueryConfig, PreparedQueryHKTBase } from '~/mysql-core/session.ts'; import type { SubqueryWithSelection } from '~/mysql-core/subquery.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; -import { MySqlViewBase } from '~/mysql-core/view.ts'; import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { BuildSubquerySelection, @@ -19,34 +13,38 @@ import type { JoinType, SelectMode, SelectResult, + SetOperator, } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import { type Query, SQL } from '~/sql/index.ts'; -import { SelectionProxyHandler, Subquery, SubqueryConfig } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import { SQL, View } from '~/sql/sql.ts'; +import { Subquery, SubqueryConfig } from '~/subquery.ts'; import { Table } from '~/table.ts'; -import { applyMixins, getTableColumns, getTableLikeName, type ValueOrArray } from '~/utils.ts'; +import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; import { orderSelectedFields } from '~/utils.ts'; -import { type ColumnsSelection, View, ViewBaseConfig } from '~/view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import { MySqlViewBase } from '../view-base.ts'; import type { - JoinFn, + AnyMySqlSelect, + CreateMySqlSelectFromBuilderMode, + GetMySqlSetOperators, LockConfig, LockStrength, + MySqlCreateSetOperatorFn, + MySqlJoinFn, MySqlSelectConfig, + MySqlSelectDynamic, MySqlSelectHKT, MySqlSelectHKTBase, - MySqlSelectQueryBuilderHKT, + MySqlSelectPrepare, + MySqlSelectWithout, + MySqlSetOperatorExcludedMethods, + MySqlSetOperatorWithResult, SelectedFields, + SetOperatorRightSelect, } from './select.types.ts'; -type CreateMySqlSelectFromBuilderMode< - TBuilderMode extends 'db' | 'qb', - TTableName extends string | undefined, - TSelection extends ColumnsSelection, - TSelectMode extends SelectMode, - TPreparedQueryHKT extends PreparedQueryHKTBase, -> = TBuilderMode extends 'db' ? MySqlSelect - : MySqlSelectQueryBuilder; - export class MySqlSelectBuilder< TSelection extends SelectedFields | undefined, TPreparedQueryHKT extends PreparedQueryHKTBase, @@ -107,7 +105,7 @@ export class MySqlSelectBuilder< fields = getTableColumns(source); } - return new MySqlSelect( + return new MySqlSelectBase( { table: source, fields, @@ -121,24 +119,32 @@ export class MySqlSelectBuilder< } } -export abstract class MySqlSelectQueryBuilder< +export abstract class MySqlSelectQueryBuilderBase< THKT extends MySqlSelectHKTBase, TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, TNullabilityMap extends Record = TTableName extends string ? Record : {}, -> extends TypedQueryBuilder< - BuildSubquerySelection, - SelectResult[] -> { + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { static readonly [entityKind]: string = 'MySqlSelectQueryBuilder'; override readonly _: { - selectMode: TSelectMode; - selection: TSelection; - result: SelectResult[]; - selectedFields: BuildSubquerySelection; + readonly hkt: THKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; }; protected config: MySqlSelectConfig; @@ -166,12 +172,13 @@ export abstract class MySqlSelectQueryBuilder< table, fields: { ...fields }, distinct, + setOperators: [], }; this.isPartialSelect = isPartialSelect; this.session = session; this.dialect = dialect; this._ = { - selectedFields: fields as BuildSubquerySelection, + selectedFields: fields as TSelectedFields, } as this['_']; this.tableName = getTableLikeName(table); this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; @@ -179,7 +186,7 @@ export abstract class MySqlSelectQueryBuilder< private createJoin( joinType: TJoinType, - ): JoinFn { + ): MySqlJoinFn { return ( table: MySqlTable | Subquery | MySqlViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, @@ -250,7 +257,7 @@ export abstract class MySqlSelectQueryBuilder< } } - return this; + return this as any; }; } @@ -262,7 +269,64 @@ export abstract class MySqlSelectQueryBuilder< fullJoin = this.createJoin('full'); - where(where: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) { + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetMySqlSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => MySqlSelectWithout< + this, + TDynamic, + MySqlSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getMySqlSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + union = this.createSetOperator('union', false); + + unionAll = this.createSetOperator('union', true); + + intersect = this.createSetOperator('intersect', false); + + intersectAll = this.createSetOperator('intersect', true); + + except = this.createSetOperator('except', false); + + exceptAll = this.createSetOperator('except', true); + + /** @internal */ + addSetOperators(setOperators: MySqlSelectConfig['setOperators']): MySqlSelectWithout< + this, + TDynamic, + MySqlSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + + where( + where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): MySqlSelectWithout { if (typeof where === 'function') { where = where( new Proxy( @@ -272,10 +336,12 @@ export abstract class MySqlSelectQueryBuilder< ); } this.config.where = where; - return this; + return this as any; } - having(having: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) { + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): MySqlSelectWithout { if (typeof having === 'function') { having = having( new Proxy( @@ -285,16 +351,18 @@ export abstract class MySqlSelectQueryBuilder< ); } this.config.having = having; - return this; + return this as any; } - groupBy(builder: (aliases: TSelection) => ValueOrArray): this; - groupBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): this; + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): MySqlSelectWithout; + groupBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlSelectWithout; groupBy( ...columns: - | [(aliases: TSelection) => ValueOrArray] + | [(aliases: this['_']['selection']) => ValueOrArray] | (MySqlColumn | SQL | SQL.Aliased)[] - ) { + ): MySqlSelectWithout { if (typeof columns[0] === 'function') { const groupBy = columns[0]( new Proxy( @@ -306,16 +374,18 @@ export abstract class MySqlSelectQueryBuilder< } else { this.config.groupBy = columns as (MySqlColumn | SQL | SQL.Aliased)[]; } - return this; + return this as any; } - orderBy(builder: (aliases: TSelection) => ValueOrArray): this; - orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): this; + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): MySqlSelectWithout; + orderBy(...columns: (MySqlColumn | SQL | SQL.Aliased)[]): MySqlSelectWithout; orderBy( ...columns: - | [(aliases: TSelection) => ValueOrArray] + | [(aliases: this['_']['selection']) => ValueOrArray] | (MySqlColumn | SQL | SQL.Aliased)[] - ) { + ): MySqlSelectWithout { if (typeof columns[0] === 'function') { const orderBy = columns[0]( new Proxy( @@ -323,26 +393,47 @@ export abstract class MySqlSelectQueryBuilder< new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), ) as TSelection, ); - this.config.orderBy = Array.isArray(orderBy) ? orderBy : [orderBy]; + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } } else { - this.config.orderBy = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + const orderByArray = columns as (MySqlColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } } - return this; + return this as any; } - limit(limit: number) { - this.config.limit = limit; - return this; + limit(limit: number): MySqlSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; } - offset(offset: number) { - this.config.offset = offset; - return this; + offset(offset: number): MySqlSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; } - for(strength: LockStrength, config: LockConfig = {}) { + for(strength: LockStrength, config: LockConfig = {}): MySqlSelectWithout { this.config.lockingClause = { strength, config }; - return this; + return this as any; } /** @internal */ @@ -350,57 +441,86 @@ export abstract class MySqlSelectQueryBuilder< return this.dialect.buildSelectQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } as( alias: TAlias, - ): SubqueryWithSelection, TAlias, 'mysql'> { + ): SubqueryWithSelection { return new Proxy( new Subquery(this.getSQL(), this.config.fields, alias), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), - ) as SubqueryWithSelection, TAlias, 'mysql'>; + ) as SubqueryWithSelection; + } + + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { + return new Proxy( + this.config.fields, + new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as this['_']['selectedFields']; + } + + $dynamic(): MySqlSelectDynamic { + return this as any; } } -export interface MySqlSelect< +export interface MySqlSelectBase< TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, - // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, TNullabilityMap extends Record = TTableName extends string ? Record : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends - MySqlSelectQueryBuilder< + MySqlSelectQueryBuilderBase< MySqlSelectHKT, TTableName, TSelection, TSelectMode, - TNullabilityMap + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields >, - QueryPromise[]> + QueryPromise {} -export class MySqlSelect< +export class MySqlSelectBase< TTableName extends string | undefined, TSelection, TSelectMode extends SelectMode, TPreparedQueryHKT extends PreparedQueryHKTBase, TNullabilityMap extends Record = TTableName extends string ? Record : {}, -> extends MySqlSelectQueryBuilder< + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> extends MySqlSelectQueryBuilderBase< MySqlSelectHKT, TTableName, TSelection, TSelectMode, - TNullabilityMap + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields > { static readonly [entityKind]: string = 'MySqlSelect'; - prepare() { + prepare(): MySqlSelectPrepare { if (!this.session) { throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); } @@ -410,14 +530,7 @@ export class MySqlSelect< TPreparedQueryHKT >(this.dialect.sqlToQuery(this.getSQL()), fieldsList); query.joinsNotNullableMap = this.joinsNotNullableMap; - return query as PreparedQueryKind< - TPreparedQueryHKT, - PreparedQueryConfig & { - execute: SelectResult[]; - iterator: SelectResult; - }, - true - >; + return query as MySqlSelectPrepare; } execute = ((placeholderValues) => { @@ -434,4 +547,45 @@ export class MySqlSelect< iterator = this.createIterator(); } -applyMixins(MySqlSelect, [QueryPromise]); +applyMixins(MySqlSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): MySqlCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnyMySqlSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnyMySqlSelect).addSetOperators(setOperators) as any; + }; +} + +const getMySqlSetOperators = () => ({ + union, + unionAll, + intersect, + intersectAll, + except, + exceptAll, +}); + +export const union = createSetOperator('union', false); + +export const unionAll = createSetOperator('union', true); + +export const intersect = createSetOperator('intersect', false); + +export const intersectAll = createSetOperator('intersect', true); + +export const except = createSetOperator('except', false); + +export const exceptAll = createSetOperator('except', true); diff --git a/drizzle-orm/src/mysql-core/query-builders/select.types.ts b/drizzle-orm/src/mysql-core/query-builders/select.types.ts index b75023cdf..711df48f9 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.types.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.types.ts @@ -1,29 +1,33 @@ import type { MySqlColumn } from '~/mysql-core/columns/index.ts'; import type { MySqlTable, MySqlTableWithColumns } from '~/mysql-core/table.ts'; -import type { MySqlViewBase, MySqlViewWithSelection } from '~/mysql-core/view.ts'; import type { SelectedFields as SelectedFieldsBase, SelectedFieldsFlat as SelectedFieldsFlatBase, SelectedFieldsOrdered as SelectedFieldsOrderedBase, } from '~/operations.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AppendToNullabilityMap, AppendToResult, + BuildSubquerySelection, GetSelectTableName, JoinNullability, JoinType, MapColumnsToTableAlias, SelectMode, + SelectResult, + SetOperator, } from '~/query-builders/select.types.ts'; -import type { Placeholder, SQL } from '~/sql/index.ts'; +import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; -import type { Assume } from '~/utils.ts'; -import { type ColumnsSelection, type View } from '~/view.ts'; -import { type PreparedQueryHKTBase } from '../session.ts'; -import type { MySqlSelect, MySqlSelectQueryBuilder } from './select.ts'; +import type { Assume, ValidateShape } from '~/utils.ts'; +import type { PreparedQueryConfig, PreparedQueryHKTBase, PreparedQueryKind } from '../session.ts'; +import type { MySqlSelectBase, MySqlSelectQueryBuilderBase } from './select.ts'; +import type { MySqlViewBase } from '../view-base.ts'; +import type { MySqlViewWithSelection } from '../view.ts'; -export interface Join { +export interface MySqlSelectJoinConfig { on: SQL | undefined; table: MySqlTable | Subquery | MySqlViewBase | SQL; alias: string | undefined; @@ -31,8 +35,6 @@ export interface Join { lateral?: boolean; } -export type AnyMySqlSelect = MySqlSelect; - export type BuildAliasTable = TTable extends Table ? MySqlTableWithColumns< UpdateTableConfig; + type: SetOperator; + isAll: boolean; + orderBy?: (MySqlColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; } -export type JoinFn< - THKT extends MySqlSelectHKTBase, - TTableName extends string | undefined, - TSelectMode extends SelectMode, +export type MySqlJoin< + T extends AnyMySqlSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? MySqlSelectWithout< + MySqlSelectKind< + T['_']['hkt'], + T['_']['tableName'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends MySqlTable ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + T['_']['preparedQueryHKT'], + AppendToNullabilityMap, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type MySqlJoinFn< + T extends AnyMySqlSelectQueryBuilder, + TDynamic extends boolean, TJoinType extends JoinType, - TSelection, - TNullabilityMap extends Record, > = < TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL, TJoinedName extends GetSelectTableName = GetSelectTableName, ->(table: TJoinedTable, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) => MySqlSelectKind< - THKT, - TTableName, - AppendToResult< - TTableName, - TSelection, - TJoinedName, - TJoinedTable extends MySqlTable ? TJoinedTable['_']['columns'] - : TJoinedTable extends Subquery ? Assume - : never, - TSelectMode - >, - TSelectMode extends 'partial' ? TSelectMode : 'multiple', - AppendToNullabilityMap ->; +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => MySqlJoin; export type SelectedFieldsFlat = SelectedFieldsFlatBase; @@ -117,38 +143,290 @@ export interface MySqlSelectHKTBase { selectMode: SelectMode; preparedQueryHKT: unknown; nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; _type: unknown; } export type MySqlSelectKind< T extends MySqlSelectHKTBase, TTableName extends string | undefined, - TSelection, + TSelection extends ColumnsSelection, TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, > = (T & { tableName: TTableName; selection: TSelection; selectMode: TSelectMode; + preparedQueryHKT: TPreparedQueryHKT; nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; })['_type']; export interface MySqlSelectQueryBuilderHKT extends MySqlSelectHKTBase { - _type: MySqlSelectQueryBuilder< - this, + _type: MySqlSelectQueryBuilderBase< + MySqlSelectQueryBuilderHKT, this['tableName'], Assume, this['selectMode'], - Assume> + Assume, + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume >; } export interface MySqlSelectHKT extends MySqlSelectHKTBase { - _type: MySqlSelect< + _type: MySqlSelectBase< this['tableName'], Assume, this['selectMode'], Assume, - Assume> + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume >; } + +export type MySqlSetOperatorExcludedMethods = + | 'where' + | 'having' + | 'groupBy' + | 'session' + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'for'; + +export type MySqlSelectWithout< + T extends AnyMySqlSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + MySqlSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type MySqlSelectPrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + PreparedQueryConfig & { + execute: T['_']['result']; + iterator: T['_']['result'][number]; + }, + true +>; + +export type MySqlSelectDynamic = MySqlSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['preparedQueryHKT'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type CreateMySqlSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase, +> = TBuilderMode extends 'db' ? MySqlSelectBase + : MySqlSelectQueryBuilderBase; + +export type MySqlSelectQueryBuilder< + THKT extends MySqlSelectHKTBase = MySqlSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = MySqlSelectQueryBuilderBase< + THKT, + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnyMySqlSelectQueryBuilder = MySqlSelectQueryBuilderBase; + +export type AnyMySqlSetOperatorInterface = MySqlSetOperatorInterface; + +export interface MySqlSetOperatorInterface< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: MySqlSelectHKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type MySqlSetOperatorWithResult = MySqlSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type MySqlSelect< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = MySqlSelectBase; + +export type AnyMySqlSelect = MySqlSelectBase; + +export type MySqlSetOperator< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = Record, +> = MySqlSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + true, + MySqlSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends MySqlSetOperatorWithResult, + TResult extends any[], +> = TValue extends MySqlSetOperatorInterface + ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly MySqlSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends MySqlSetOperatorInterface + ? Rest extends AnyMySqlSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type MySqlCreateSetOperatorFn = < + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TValue extends MySqlSetOperatorWithResult, + TRest extends MySqlSetOperatorWithResult[], + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: MySqlSetOperatorInterface< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => MySqlSelectWithout< + MySqlSelectBase< + TTableName, + TSelection, + TSelectMode, + TPreparedQueryHKT, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + MySqlSetOperatorExcludedMethods, + true +>; + +export type GetMySqlSetOperators = { + union: MySqlCreateSetOperatorFn; + intersect: MySqlCreateSetOperatorFn; + except: MySqlCreateSetOperatorFn; + unionAll: MySqlCreateSetOperatorFn; + intersectAll: MySqlCreateSetOperatorFn; + exceptAll: MySqlCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 2412660c8..94b884058 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -2,6 +2,7 @@ import type { GetColumnData } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { MySqlDialect } from '~/mysql-core/dialect.ts'; import type { + AnyQueryResultHKT, MySqlSession, PreparedQueryConfig, PreparedQueryHKTBase, @@ -11,7 +12,7 @@ import type { } from '~/mysql-core/session.ts'; import type { MySqlTable } from '~/mysql-core/table.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/index.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import { mapUpdateSet, type UpdateSet } from '~/utils.ts'; import type { SelectedFieldsOrdered } from './select.types.ts'; @@ -37,7 +38,9 @@ export class MySqlUpdateBuilder< > { static readonly [entityKind]: string = 'MySqlUpdateBuilder'; - declare protected $table: TTable; + declare readonly _: { + readonly table: TTable; + }; constructor( private table: TTable, @@ -45,27 +48,77 @@ export class MySqlUpdateBuilder< private dialect: MySqlDialect, ) {} - set(values: MySqlUpdateSetSource): MySqlUpdate { - return new MySqlUpdate(this.table, mapUpdateSet(this.table, values), this.session, this.dialect); + set(values: MySqlUpdateSetSource): MySqlUpdateBase { + return new MySqlUpdateBase(this.table, mapUpdateSet(this.table, values), this.session, this.dialect); } } -export interface MySqlUpdate< - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type MySqlUpdateWithout< + T extends AnyMySqlUpdateBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + MySqlUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type MySqlUpdatePrepare = PreparedQueryKind< + T['_']['preparedQueryHKT'], + PreparedQueryConfig & { + execute: QueryResultKind; + iterator: never; + }, + true +>; + +export type MySqlUpdateDynamic = MySqlUpdate< + T['_']['table'], + T['_']['queryResult'], + T['_']['preparedQueryHKT'] +>; + +export type MySqlUpdate< + TTable extends MySqlTable = MySqlTable, + TQueryResult extends QueryResultHKT = AnyQueryResultHKT, + TPreparedQueryHKT extends PreparedQueryHKTBase = PreparedQueryHKTBase, +> = MySqlUpdateBase; + +export type AnyMySqlUpdateBase = MySqlUpdateBase; + +export interface MySqlUpdateBase< TTable extends MySqlTable, TQueryResult extends QueryResultHKT, - // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, -> extends QueryPromise>, SQLWrapper {} -export class MySqlUpdate< + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly preparedQueryHKT: TPreparedQueryHKT; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} + +export class MySqlUpdateBase< TTable extends MySqlTable, TQueryResult extends QueryResultHKT, + // eslint-disable-next-line @typescript-eslint/no-unused-vars TPreparedQueryHKT extends PreparedQueryHKTBase, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, > extends QueryPromise> implements SQLWrapper { static readonly [entityKind]: string = 'MySqlUpdate'; - declare protected $table: TTable; - private config: MySqlUpdateConfig; constructor( @@ -78,9 +131,9 @@ export class MySqlUpdate< this.config = { set, table }; } - where(where: SQL | undefined): this { + where(where: SQL | undefined): MySqlUpdateWithout { this.config.where = where; - return this; + return this as any; } /** @internal */ @@ -88,23 +141,16 @@ export class MySqlUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - prepare() { + prepare(): MySqlUpdatePrepare { return this.session.prepareQuery( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, - ) as PreparedQueryKind< - TPreparedQueryHKT, - PreparedQueryConfig & { - execute: QueryResultKind; - iterator: never; - }, - true - >; + ) as MySqlUpdatePrepare; } override execute: ReturnType['execute'] = (placeholderValues) => { @@ -119,4 +165,8 @@ export class MySqlUpdate< }; iterator = this.createIterator(); + + $dynamic(): MySqlUpdateDynamic { + return this as any; + } } diff --git a/drizzle-orm/src/mysql-core/session.ts b/drizzle-orm/src/mysql-core/session.ts index 224b7068c..528782d7b 100644 --- a/drizzle-orm/src/mysql-core/session.ts +++ b/drizzle-orm/src/mysql-core/session.ts @@ -1,8 +1,8 @@ import { entityKind } from '~/entity.ts'; import { TransactionRollbackError } from '~/errors.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { type Query, type SQL, sql } from '~/sql/index.ts'; -import { type Assume, type Equal } from '~/utils.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { type Query, type SQL, sql } from '~/sql/sql.ts'; +import type { Assume, Equal } from '~/utils.ts'; import { MySqlDatabase } from './db.ts'; import type { MySqlDialect } from './dialect.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; @@ -15,6 +15,10 @@ export interface QueryResultHKT { readonly type: unknown; } +export interface AnyQueryResultHKT extends QueryResultHKT { + readonly type: any; +} + export type QueryResultKind = (TKind & { readonly row: TRow; })['type']; diff --git a/drizzle-orm/src/mysql-core/subquery.ts b/drizzle-orm/src/mysql-core/subquery.ts index 603a86b5a..9d2c1828c 100644 --- a/drizzle-orm/src/mysql-core/subquery.ts +++ b/drizzle-orm/src/mysql-core/subquery.ts @@ -1,20 +1,17 @@ -import { type Dialect } from '~/column-builder.ts'; import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; import type { Subquery, WithSubquery } from '~/subquery.ts'; -import { type ColumnsSelection } from '~/view.ts'; export type SubqueryWithSelection< TSelection extends ColumnsSelection, TAlias extends string, - TDialect extends Dialect, > = - & Subquery> - & AddAliasToSelection; + & Subquery> + & AddAliasToSelection; export type WithSubqueryWithSelection< TSelection extends ColumnsSelection, TAlias extends string, - TDialect extends Dialect, > = - & WithSubquery> - & AddAliasToSelection; + & WithSubquery> + & AddAliasToSelection; diff --git a/drizzle-orm/src/mysql-core/utils.ts b/drizzle-orm/src/mysql-core/utils.ts index 1d53694f7..f09f65f3e 100644 --- a/drizzle-orm/src/mysql-core/utils.ts +++ b/drizzle-orm/src/mysql-core/utils.ts @@ -1,6 +1,6 @@ import { is } from '~/entity.ts'; import { Table } from '~/table.ts'; -import { ViewBaseConfig } from '~/view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { Check } from './checks.ts'; import { CheckBuilder } from './checks.ts'; import type { ForeignKey } from './foreign-keys.ts'; @@ -11,8 +11,8 @@ import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; import { MySqlTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; +import { MySqlViewConfig } from './view-common.ts'; import type { MySqlView } from './view.ts'; -import { MySqlViewConfig } from './view.ts'; export function getTableConfig(table: MySqlTable) { const columns = Object.values(table[MySqlTable.Symbol.Columns]); diff --git a/drizzle-orm/src/mysql-core/view-base.ts b/drizzle-orm/src/mysql-core/view-base.ts new file mode 100644 index 000000000..53c9e38c2 --- /dev/null +++ b/drizzle-orm/src/mysql-core/view-base.ts @@ -0,0 +1,15 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnsSelection} from '~/sql/sql.ts'; +import { View } from '~/sql/sql.ts'; + +export abstract class MySqlViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends View { + static readonly [entityKind]: string = 'MySqlViewBase'; + + declare readonly _: View['_'] & { + readonly viewBrand: 'MySqlViewBase'; + }; +} diff --git a/drizzle-orm/src/mysql-core/view-common.ts b/drizzle-orm/src/mysql-core/view-common.ts new file mode 100644 index 000000000..9bbc130c3 --- /dev/null +++ b/drizzle-orm/src/mysql-core/view-common.ts @@ -0,0 +1 @@ +export const MySqlViewConfig = Symbol.for('drizzle:MySqlViewConfig'); diff --git a/drizzle-orm/src/mysql-core/view.ts b/drizzle-orm/src/mysql-core/view.ts index 5c81dff21..dd7d2f82d 100644 --- a/drizzle-orm/src/mysql-core/view.ts +++ b/drizzle-orm/src/mysql-core/view.ts @@ -2,14 +2,15 @@ import type { BuildColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; -import type { SQL } from '~/sql/index.ts'; -import { SelectionProxyHandler } from '~/subquery.ts'; +import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; -import { type ColumnsSelection, View } from '~/view.ts'; -import { type MySqlColumn, type MySqlColumnBuilderBase } from './columns/index.ts'; -import { QueryBuilder } from './query-builders/index.ts'; +import type { MySqlColumn, MySqlColumnBuilderBase } from './columns/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import { mysqlTable } from './table.ts'; +import { MySqlViewConfig } from './view-common.ts'; +import { MySqlViewBase } from './view-base.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; @@ -151,20 +152,6 @@ export class ManualViewBuilder< } } -export abstract class MySqlViewBase< - TName extends string = string, - TExisting extends boolean = boolean, - TSelectedFields extends ColumnsSelection = ColumnsSelection, -> extends View { - static readonly [entityKind]: string = 'MySqlViewBase'; - - declare readonly _: View['_'] & { - readonly viewBrand: 'MySqlViewBase'; - }; -} - -export const MySqlViewConfig = Symbol.for('drizzle:MySqlViewConfig'); - export class MySqlView< TName extends string = string, TExisting extends boolean = boolean, diff --git a/drizzle-orm/src/mysql-proxy/driver.ts b/drizzle-orm/src/mysql-proxy/driver.ts new file mode 100644 index 000000000..e9008f816 --- /dev/null +++ b/drizzle-orm/src/mysql-proxy/driver.ts @@ -0,0 +1,50 @@ +import { DefaultLogger } from '~/logger.ts'; +import { MySqlDatabase } from '~/mysql-core/db.ts'; +import { MySqlDialect } from '~/mysql-core/dialect.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { type MySqlRemotePreparedQueryHKT, type MySqlRemoteQueryResultHKT, MySqlRemoteSession } from './session.ts'; + +export type MySqlRemoteDatabase< + TSchema extends Record = Record, +> = MySqlDatabase; + +export type RemoteCallback = ( + sql: string, + params: any[], + method: 'all' | 'execute', +) => Promise<{ rows: any[] }>; + +export function drizzle = Record>( + callback: RemoteCallback, + config: DrizzleConfig = {}, +): MySqlRemoteDatabase { + const dialect = new MySqlDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new MySqlRemoteSession(callback, dialect, schema, { logger }); + return new MySqlDatabase(dialect, session, schema, 'default') as MySqlRemoteDatabase; +} diff --git a/drizzle-orm/src/mysql-proxy/index.ts b/drizzle-orm/src/mysql-proxy/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/mysql-proxy/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/mysql-proxy/migrator.ts b/drizzle-orm/src/mysql-proxy/migrator.ts new file mode 100644 index 000000000..b75184934 --- /dev/null +++ b/drizzle-orm/src/mysql-proxy/migrator.ts @@ -0,0 +1,52 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import { sql } from '~/sql/sql.ts'; +import type { MySqlRemoteDatabase } from './driver.ts'; + +export type ProxyMigrator = (migrationQueries: string[]) => Promise; + +export async function migrate>( + db: MySqlRemoteDatabase, + callback: ProxyMigrator, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config); + + const migrationsTable = config.migrationsTable ?? '__drizzle_migrations'; + const migrationTableCreate = sql` + create table if not exists ${sql.identifier(migrationsTable)} ( + id serial primary key, + hash text not null, + created_at bigint + ) + `; + await db.execute(migrationTableCreate); + + const dbMigrations = await db.select({ + id: sql.raw('id'), + hash: sql.raw('hash'), + created_at: sql.raw('created_at'), + }).from(sql.raw(migrationsTable)).orderBy( + sql.raw('created_at desc'), + ).limit(1); + + const lastDbMigration = dbMigrations[0]; + + const queriesToRun: string[] = []; + + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration.created_at) < migration.folderMillis + ) { + queriesToRun.push( + ...migration.sql, + `insert into ${ + sql.identifier(migrationsTable) + } (\`hash\`, \`created_at\`) values(${migration.hash}, ${migration.folderMillis})`, + ); + } + } + + await callback(queriesToRun); +} diff --git a/drizzle-orm/src/mysql-proxy/session.ts b/drizzle-orm/src/mysql-proxy/session.ts new file mode 100644 index 000000000..973cb2393 --- /dev/null +++ b/drizzle-orm/src/mysql-proxy/session.ts @@ -0,0 +1,137 @@ +import type { FieldPacket, ResultSetHeader } from 'mysql2/promise'; +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { MySqlDialect } from '~/mysql-core/dialect.ts'; +import { MySqlTransaction } from '~/mysql-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/mysql-core/query-builders/select.types.ts'; +import type { + MySqlTransactionConfig, + PreparedQueryConfig, + PreparedQueryHKT, + PreparedQueryKind, + QueryResultHKT, +} from '~/mysql-core/session.ts'; +import { MySqlSession, PreparedQuery as PreparedQueryBase } from '~/mysql-core/session.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders } from '~/sql/sql.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; +import type { RemoteCallback } from './driver.ts'; + +export type MySqlRawQueryResult = [ResultSetHeader, FieldPacket[]]; + +export interface MySqlRemoteSessionOptions { + logger?: Logger; +} + +export class MySqlRemoteSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends MySqlSession { + static readonly [entityKind]: string = 'MySqlRemoteSession'; + + private logger: Logger; + + constructor( + private client: RemoteCallback, + dialect: MySqlDialect, + private schema: RelationalSchemaConfig | undefined, + options: MySqlRemoteSessionOptions, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + ): PreparedQueryKind { + return new PreparedQuery( + this.client, + query.sql, + query.params, + this.logger, + fields, + customResultMapper, + ) as PreparedQueryKind; + } + + override all(query: SQL): Promise { + const querySql = this.dialect.sqlToQuery(query); + this.logger.logQuery(querySql.sql, querySql.params); + return this.client(querySql.sql, querySql.params, 'all').then(({ rows }) => rows) as Promise; + } + + override async transaction( + _transaction: (tx: MySqlProxyTransaction) => Promise, + _config?: MySqlTransactionConfig, + ): Promise { + throw new Error('Transactions are not supported by the MySql Proxy driver'); + } +} + +export class MySqlProxyTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends MySqlTransaction { + static readonly [entityKind]: string = 'MySqlProxyTransaction'; + + override async transaction( + _transaction: (tx: MySqlProxyTransaction) => Promise, + ): Promise { + throw new Error('Transactions are not supported by the MySql Proxy driver'); + } +} + +export class PreparedQuery extends PreparedQueryBase { + static readonly [entityKind]: string = 'MySqlProxyPreparedQuery'; + + constructor( + private client: RemoteCallback, + private queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + ) { + super(); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + const { fields, client, queryString, logger, joinsNotNullableMap, customResultMapper } = this; + + logger.logQuery(queryString, params); + + if (!fields && !customResultMapper) { + const { rows } = await client(queryString, params, 'execute'); + + return rows; + } + + const { rows } = await client(queryString, params, 'all'); + + if (customResultMapper) { + return customResultMapper(rows); + } + + return rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + } + + override iterator( + _placeholderValues: Record = {}, + ): AsyncGenerator { + throw new Error('Streaming is not supported by the MySql Proxy driver'); + } +} + +export interface MySqlRemoteQueryResultHKT extends QueryResultHKT { + type: MySqlRawQueryResult; +} + +export interface MySqlRemotePreparedQueryHKT extends PreparedQueryHKT { + type: PreparedQuery>; +} diff --git a/drizzle-orm/src/mysql2/driver.ts b/drizzle-orm/src/mysql2/driver.ts index 87c21df26..3b21bf11d 100644 --- a/drizzle-orm/src/mysql2/driver.ts +++ b/drizzle-orm/src/mysql2/driver.ts @@ -1,4 +1,4 @@ -import { type Connection as CallbackConnection, type Pool as CallbackPool } from 'mysql2'; +import type { Connection as CallbackConnection, Pool as CallbackPool } from 'mysql2'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { DefaultLogger } from '~/logger.ts'; @@ -11,7 +11,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { DrizzleError } from '../index.ts'; import type { MySql2Client, MySql2PreparedQueryHKT, MySql2QueryResultHKT } from './session.ts'; import { MySql2Session } from './session.ts'; @@ -66,9 +66,10 @@ export function drizzle = Record | undefined; if (config.schema) { if (config.mode === undefined) { - throw new DrizzleError( - 'You need to specify "mode": "planetscale" or "default" when providing a schema. Read more: https://orm.drizzle.team/docs/rqb#modes', - ); + throw new DrizzleError({ + message: + 'You need to specify "mode": "planetscale" or "default" when providing a schema. Read more: https://orm.drizzle.team/docs/rqb#modes', + }); } const tablesConfig = extractTablesRelationalConfig( diff --git a/drizzle-orm/src/mysql2/session.ts b/drizzle-orm/src/mysql2/session.ts index 31b86a56d..3d3e535d6 100644 --- a/drizzle-orm/src/mysql2/session.ts +++ b/drizzle-orm/src/mysql2/session.ts @@ -1,13 +1,13 @@ -import { type Connection as CallbackConnection } from 'mysql2'; -import { - type Connection, - type FieldPacket, - type OkPacket, - type Pool, - type PoolConnection, - type QueryOptions, - type ResultSetHeader, - type RowDataPacket, +import type { Connection as CallbackConnection } from 'mysql2'; +import type { + Connection, + FieldPacket, + OkPacket, + Pool, + PoolConnection, + QueryOptions, + ResultSetHeader, + RowDataPacket, } from 'mysql2/promise'; import { once } from 'node:events'; import { entityKind } from '~/entity.ts'; @@ -26,8 +26,8 @@ import { type PreparedQueryKind, type QueryResultHKT, } from '~/mysql-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type MySql2Client = Pool | Connection; diff --git a/drizzle-orm/src/neon-http/driver.ts b/drizzle-orm/src/neon-http/driver.ts index 9681299ce..7172dfd01 100644 --- a/drizzle-orm/src/neon-http/driver.ts +++ b/drizzle-orm/src/neon-http/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { type NeonHttpClient, type NeonHttpQueryResultHKT, NeonHttpSession } from './session.ts'; export interface NeonDriverOptions { diff --git a/drizzle-orm/src/neon-http/migrator.ts b/drizzle-orm/src/neon-http/migrator.ts index b56d5f7d6..ffda77760 100644 --- a/drizzle-orm/src/neon-http/migrator.ts +++ b/drizzle-orm/src/neon-http/migrator.ts @@ -1,7 +1,7 @@ import type { MigrationConfig } from '~/migrator.ts'; import { readMigrationFiles } from '~/migrator.ts'; -import { type SQL, sql } from '~/sql/index.ts'; -import { type NeonHttpDatabase } from './driver.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; +import type { NeonHttpDatabase } from './driver.ts'; /** * This function reads migrationFolder and execute each unapplied migration and mark it as executed in database diff --git a/drizzle-orm/src/neon-http/session.ts b/drizzle-orm/src/neon-http/session.ts index e12cb014c..9b73ab98c 100644 --- a/drizzle-orm/src/neon-http/session.ts +++ b/drizzle-orm/src/neon-http/session.ts @@ -1,4 +1,4 @@ -import { type FullQueryResults, type QueryRows } from '@neondatabase/serverless'; +import type { FullQueryResults, QueryRows } from '@neondatabase/serverless'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; @@ -7,8 +7,8 @@ import { PgTransaction } from '~/pg-core/index.ts'; import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; import type { PgTransactionConfig, PreparedQueryConfig, QueryResultHKT } from '~/pg-core/session.ts'; import { PgSession, PreparedQuery } from '~/pg-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type NeonHttpClient = { diff --git a/drizzle-orm/src/neon-serverless/driver.ts b/drizzle-orm/src/neon-serverless/driver.ts index a90213d56..9f58b0e65 100644 --- a/drizzle-orm/src/neon-serverless/driver.ts +++ b/drizzle-orm/src/neon-serverless/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import type { NeonClient, NeonQueryResultHKT } from './session.ts'; import { NeonSession } from './session.ts'; diff --git a/drizzle-orm/src/neon-serverless/session.ts b/drizzle-orm/src/neon-serverless/session.ts index 7e47bc093..891835259 100644 --- a/drizzle-orm/src/neon-serverless/session.ts +++ b/drizzle-orm/src/neon-serverless/session.ts @@ -15,8 +15,8 @@ import { PgTransaction } from '~/pg-core/index.ts'; import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; import type { PgTransactionConfig, PreparedQueryConfig, QueryResultHKT } from '~/pg-core/session.ts'; import { PgSession, PreparedQuery } from '~/pg-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type NeonClient = Pool | PoolClient | Client; diff --git a/drizzle-orm/src/node-postgres/driver.ts b/drizzle-orm/src/node-postgres/driver.ts index 5ad20ce23..4c233f891 100644 --- a/drizzle-orm/src/node-postgres/driver.ts +++ b/drizzle-orm/src/node-postgres/driver.ts @@ -10,7 +10,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import type { NodePgClient, NodePgQueryResultHKT } from './session.ts'; import { NodePgSession } from './session.ts'; diff --git a/drizzle-orm/src/node-postgres/session.ts b/drizzle-orm/src/node-postgres/session.ts index eac168c7e..01ad7cac8 100644 --- a/drizzle-orm/src/node-postgres/session.ts +++ b/drizzle-orm/src/node-postgres/session.ts @@ -7,8 +7,8 @@ import { PgTransaction } from '~/pg-core/index.ts'; import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; import type { PgTransactionConfig, PreparedQueryConfig, QueryResultHKT } from '~/pg-core/session.ts'; import { PgSession, PreparedQuery } from '~/pg-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; diff --git a/drizzle-orm/src/operations.ts b/drizzle-orm/src/operations.ts index 19927cd94..09cf41b8a 100644 --- a/drizzle-orm/src/operations.ts +++ b/drizzle-orm/src/operations.ts @@ -1,5 +1,5 @@ import type { AnyColumn, Column } from './column.ts'; -import type { SQL } from './sql/index.ts'; +import type { SQL } from './sql/sql.ts'; import type { Table } from './table.ts'; export type RequiredKeyOnly = T extends AnyColumn<{ diff --git a/drizzle-orm/src/pg-core/alias.ts b/drizzle-orm/src/pg-core/alias.ts index 2d9800e7e..53bbf5d43 100644 --- a/drizzle-orm/src/pg-core/alias.ts +++ b/drizzle-orm/src/pg-core/alias.ts @@ -2,7 +2,7 @@ import { TableAliasProxyHandler } from '~/alias.ts'; import type { BuildAliasTable } from './query-builders/select.types.ts'; import type { PgTable } from './table.ts'; -import { type PgViewBase } from './view.ts'; +import type { PgViewBase } from './view-base.ts'; export function alias( table: TTable, diff --git a/drizzle-orm/src/pg-core/columns/array.ts b/drizzle-orm/src/pg-core/columns/array.ts deleted file mode 100644 index 4106f18d5..000000000 --- a/drizzle-orm/src/pg-core/columns/array.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { - ColumnBuilderBaseConfig, - ColumnBuilderRuntimeConfig, - ColumnDataType, - MakeColumnConfig, -} from '~/column-builder.ts'; -import type { ColumnBaseConfig } from '~/column.ts'; -import { entityKind, is } from '~/entity.ts'; -import type { AnyPgTable } from '~/pg-core/table.ts'; -import { makePgArray, parsePgArray } from '../utils.ts'; -import { PgColumn, PgColumnBuilder } from './common.ts'; - -export class PgArrayBuilder< - T extends ColumnBuilderBaseConfig<'array', 'PgArray'>, - TBase extends ColumnBuilderBaseConfig, -> extends PgColumnBuilder< - T, - { - baseBuilder: PgColumnBuilder; - size: number | undefined; - }, - { - baseBuilder: PgColumnBuilder; - } -> { - static override readonly [entityKind] = 'PgArrayBuilder'; - - constructor( - name: string, - baseBuilder: PgArrayBuilder['config']['baseBuilder'], - size: number | undefined, - ) { - super(name, 'array', 'PgArray'); - this.config.baseBuilder = baseBuilder; - this.config.size = size; - } - - /** @internal */ - override build( - table: AnyPgTable<{ name: TTableName }>, - ): PgArray, TBase> { - const baseColumn = this.config.baseBuilder.build(table); - return new PgArray, TBase>( - table as AnyPgTable<{ name: MakeColumnConfig['tableName'] }>, - this.config as ColumnBuilderRuntimeConfig, - baseColumn, - ); - } -} - -export class PgArray< - T extends ColumnBaseConfig<'array', 'PgArray'>, - TBase extends ColumnBuilderBaseConfig, -> extends PgColumn { - readonly size: number | undefined; - - static readonly [entityKind]: string = 'PgArray'; - - constructor( - table: AnyPgTable<{ name: T['tableName'] }>, - config: PgArrayBuilder['config'], - readonly baseColumn: PgColumn, - readonly range?: [number | undefined, number | undefined], - ) { - super(table, config); - this.size = config.size; - } - - getSQLType(): string { - return `${this.baseColumn.getSQLType()}[${typeof this.size === 'number' ? this.size : ''}]`; - } - - override mapFromDriverValue(value: unknown[] | string): T['data'] { - if (typeof value === 'string') { - // Thank you node-postgres for not parsing enum arrays - value = parsePgArray(value); - } - return value.map((v) => this.baseColumn.mapFromDriverValue(v)); - } - - override mapToDriverValue(value: unknown[], isNestedArray = false): unknown[] | string { - const a = value.map((v) => - v === null - ? null - : is(this.baseColumn, PgArray) - ? this.baseColumn.mapToDriverValue(v as unknown[], true) - : this.baseColumn.mapToDriverValue(v) - ); - if (isNestedArray) return a; - return makePgArray(a); - } -} diff --git a/drizzle-orm/src/pg-core/columns/char.ts b/drizzle-orm/src/pg-core/columns/char.ts index 1c5d88416..85eb65954 100644 --- a/drizzle-orm/src/pg-core/columns/char.ts +++ b/drizzle-orm/src/pg-core/columns/char.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgCharBuilderInitial = PgCharBuilder<{ diff --git a/drizzle-orm/src/pg-core/columns/common.ts b/drizzle-orm/src/pg-core/columns/common.ts index 6e71fec17..17ba6b929 100644 --- a/drizzle-orm/src/pg-core/columns/common.ts +++ b/drizzle-orm/src/pg-core/columns/common.ts @@ -9,14 +9,15 @@ import type { import { ColumnBuilder } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { Column } from '~/column.ts'; -import { entityKind } from '~/entity.ts'; -import { iife, type Update } from '~/utils.ts'; +import { entityKind, is } from '~/entity.ts'; +import type { Update } from '~/utils.ts'; import type { ForeignKey, UpdateDeleteAction } from '~/pg-core/foreign-keys.ts'; import { ForeignKeyBuilder } from '~/pg-core/foreign-keys.ts'; import type { AnyPgTable, PgTable } from '~/pg-core/table.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; -import { PgArrayBuilder } from './array.ts'; +import { makePgArray, parsePgArray } from '../utils/array.ts'; +import { iife } from '~/tracing-utils.ts'; export interface ReferenceConfig { ref: () => PgColumn; @@ -128,3 +129,84 @@ export abstract class PgColumn< export type AnyPgColumn> = {}> = PgColumn< Required, TPartial>> >; + +export class PgArrayBuilder< + T extends ColumnBuilderBaseConfig<'array', 'PgArray'>, + TBase extends ColumnBuilderBaseConfig, +> extends PgColumnBuilder< + T, + { + baseBuilder: PgColumnBuilder; + size: number | undefined; + }, + { + baseBuilder: PgColumnBuilder; + } +> { + static override readonly [entityKind] = 'PgArrayBuilder'; + + constructor( + name: string, + baseBuilder: PgArrayBuilder['config']['baseBuilder'], + size: number | undefined, + ) { + super(name, 'array', 'PgArray'); + this.config.baseBuilder = baseBuilder; + this.config.size = size; + } + + /** @internal */ + override build( + table: AnyPgTable<{ name: TTableName }>, + ): PgArray, TBase> { + const baseColumn = this.config.baseBuilder.build(table); + return new PgArray, TBase>( + table as AnyPgTable<{ name: MakeColumnConfig['tableName'] }>, + this.config as ColumnBuilderRuntimeConfig, + baseColumn, + ); + } +} + +export class PgArray< + T extends ColumnBaseConfig<'array', 'PgArray'>, + TBase extends ColumnBuilderBaseConfig, +> extends PgColumn { + readonly size: number | undefined; + + static readonly [entityKind]: string = 'PgArray'; + + constructor( + table: AnyPgTable<{ name: T['tableName'] }>, + config: PgArrayBuilder['config'], + readonly baseColumn: PgColumn, + readonly range?: [number | undefined, number | undefined], + ) { + super(table, config); + this.size = config.size; + } + + getSQLType(): string { + return `${this.baseColumn.getSQLType()}[${typeof this.size === 'number' ? this.size : ''}]`; + } + + override mapFromDriverValue(value: unknown[] | string): T['data'] { + if (typeof value === 'string') { + // Thank you node-postgres for not parsing enum arrays + value = parsePgArray(value); + } + return value.map((v) => this.baseColumn.mapFromDriverValue(v)); + } + + override mapToDriverValue(value: unknown[], isNestedArray = false): unknown[] | string { + const a = value.map((v) => + v === null + ? null + : is(this.baseColumn, PgArray) + ? this.baseColumn.mapToDriverValue(v as unknown[], true) + : this.baseColumn.mapToDriverValue(v) + ); + if (isNestedArray) return a; + return makePgArray(a); + } +} diff --git a/drizzle-orm/src/pg-core/columns/custom.ts b/drizzle-orm/src/pg-core/columns/custom.ts index ff768d0ae..7af6c73d1 100644 --- a/drizzle-orm/src/pg-core/columns/custom.ts +++ b/drizzle-orm/src/pg-core/columns/custom.ts @@ -2,8 +2,8 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import type { SQL } from '~/sql/index.ts'; -import { type Equal } from '~/utils.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { Equal } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = diff --git a/drizzle-orm/src/pg-core/columns/date.common.ts b/drizzle-orm/src/pg-core/columns/date.common.ts index afae5bb67..c2a46d1ce 100644 --- a/drizzle-orm/src/pg-core/columns/date.common.ts +++ b/drizzle-orm/src/pg-core/columns/date.common.ts @@ -1,6 +1,6 @@ import type { ColumnBuilderBaseConfig, ColumnDataType } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { PgColumnBuilder } from './common.ts'; export abstract class PgDateColumnBaseBuilder< diff --git a/drizzle-orm/src/pg-core/columns/enum.ts b/drizzle-orm/src/pg-core/columns/enum.ts index dcae97545..7f3840271 100644 --- a/drizzle-orm/src/pg-core/columns/enum.ts +++ b/drizzle-orm/src/pg-core/columns/enum.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgEnumColumnBuilderInitial = diff --git a/drizzle-orm/src/pg-core/columns/index.ts b/drizzle-orm/src/pg-core/columns/index.ts index a87315a1f..7e2a52c2e 100644 --- a/drizzle-orm/src/pg-core/columns/index.ts +++ b/drizzle-orm/src/pg-core/columns/index.ts @@ -1,4 +1,3 @@ -export * from './array.ts'; export * from './bigint.ts'; export * from './bigserial.ts'; export * from './boolean.ts'; diff --git a/drizzle-orm/src/pg-core/columns/smallserial.ts b/drizzle-orm/src/pg-core/columns/smallserial.ts index b12cad4b0..7d02c306e 100644 --- a/drizzle-orm/src/pg-core/columns/smallserial.ts +++ b/drizzle-orm/src/pg-core/columns/smallserial.ts @@ -39,7 +39,7 @@ export class PgSmallSerial static readonly [entityKind]: string = 'PgSmallSerial'; getSQLType(): string { - return 'serial'; + return 'smallserial'; } } diff --git a/drizzle-orm/src/pg-core/columns/text.ts b/drizzle-orm/src/pg-core/columns/text.ts index 946d5f3cb..844e9182c 100644 --- a/drizzle-orm/src/pg-core/columns/text.ts +++ b/drizzle-orm/src/pg-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; type PgTextBuilderInitial = PgTextBuilder<{ diff --git a/drizzle-orm/src/pg-core/columns/timestamp.ts b/drizzle-orm/src/pg-core/columns/timestamp.ts index 92a2f4be1..3060bfb3f 100644 --- a/drizzle-orm/src/pg-core/columns/timestamp.ts +++ b/drizzle-orm/src/pg-core/columns/timestamp.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { type Equal } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; import { PgColumn } from './common.ts'; import { PgDateColumnBaseBuilder } from './date.common.ts'; diff --git a/drizzle-orm/src/pg-core/columns/uuid.ts b/drizzle-orm/src/pg-core/columns/uuid.ts index f9fe9e808..4c9ba04ed 100644 --- a/drizzle-orm/src/pg-core/columns/uuid.ts +++ b/drizzle-orm/src/pg-core/columns/uuid.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgUUIDBuilderInitial = PgUUIDBuilder<{ diff --git a/drizzle-orm/src/pg-core/columns/varchar.ts b/drizzle-orm/src/pg-core/columns/varchar.ts index 488a605b8..31d66aade 100644 --- a/drizzle-orm/src/pg-core/columns/varchar.ts +++ b/drizzle-orm/src/pg-core/columns/varchar.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyPgTable } from '~/pg-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Writable } from '~/utils.ts'; import { PgColumn, PgColumnBuilder } from './common.ts'; export type PgVarcharBuilderInitial = PgVarcharBuilder<{ diff --git a/drizzle-orm/src/pg-core/db.ts b/drizzle-orm/src/pg-core/db.ts index 4ac6575ed..8a1be58de 100644 --- a/drizzle-orm/src/pg-core/db.ts +++ b/drizzle-orm/src/pg-core/db.ts @@ -1,7 +1,7 @@ import { entityKind } from '~/entity.ts'; import type { PgDialect } from '~/pg-core/dialect.ts'; import { - PgDelete, + PgDeleteBase, PgInsertBuilder, PgSelectBuilder, PgUpdateBuilder, @@ -14,23 +14,19 @@ import type { QueryResultHKT, QueryResultKind, } from '~/pg-core/session.ts'; -import { type PgTable } from '~/pg-core/table.ts'; +import type { PgTable } from '~/pg-core/table.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; -import { - type ExtractTablesWithRelations, - type RelationalSchemaConfig, - type TablesRelationalConfig, -} from '~/relations.ts'; -import { type SQLWrapper } from '~/sql/index.ts'; -import { SelectionProxyHandler, WithSubquery } from '~/subquery.ts'; -import { type DrizzleTypeError } from '~/utils.ts'; -import { type ColumnsSelection } from '~/view.ts'; -import { type PgColumn } from './columns/index.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; +import type { PgColumn } from './columns/index.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; import { PgRefreshMaterializedView } from './query-builders/refresh-materialized-view.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; import type { PgMaterializedView } from './view.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export class PgDatabase< TQueryResult extends QueryResultHKT, @@ -156,8 +152,8 @@ export class PgDatabase< return new PgInsertBuilder(table, this.session, this.dialect); } - delete(table: TTable): PgDelete { - return new PgDelete(table, this.session, this.dialect); + delete(table: TTable): PgDeleteBase { + return new PgDeleteBase(table, this.session, this.dialect); } refreshMaterializedView(view: TView): PgRefreshMaterializedView { @@ -177,3 +173,53 @@ export class PgDatabase< return this.session.transaction(transaction, config); } } + +export type PgWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + HKT extends QueryResultHKT, + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, + Q extends PgDatabase, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): PgWithReplicas => { + const select: Q['select'] = (...args: any) => getReplica(replicas).select(args); + const selectDistinct: Q['selectDistinct'] = (...args: any) => getReplica(replicas).selectDistinct(args); + const selectDistinctOn: Q['selectDistinctOn'] = (...args: any) => getReplica(replicas).selectDistinctOn(args); + const $with: Q['with'] = (...args: any) => getReplica(replicas).with(args); + + const update: Q['update'] = (...args: any) => primary.update(args); + const insert: Q['insert'] = (...args: any) => primary.insert(args); + const $delete: Q['delete'] = (...args: any) => primary.delete(args); + const execute: Q['execute'] = (...args: any) => primary.execute(args); + const transaction: Q['transaction'] = (...args: any) => primary.transaction(args); + const refreshMaterializedView: Q['refreshMaterializedView'] = (...args: any) => primary.refreshMaterializedView(args); + + return new Proxy( + { + ...primary, + update, + insert, + delete: $delete, + execute, + transaction, + refreshMaterializedView, + $primary: primary, + select, + selectDistinct, + selectDistinctOn, + with: $with, + }, + { + get(target, prop, _receiver) { + if (prop === 'query') { + return getReplica(replicas).query; + } + return target[prop as keyof typeof target]; + }, + }, + ); +}; diff --git a/drizzle-orm/src/pg-core/dialect.ts b/drizzle-orm/src/pg-core/dialect.ts index 0dcdf53e2..366436e29 100644 --- a/drizzle-orm/src/pg-core/dialect.ts +++ b/drizzle-orm/src/pg-core/dialect.ts @@ -4,8 +4,13 @@ import { entityKind, is } from '~/entity.ts'; import { DrizzleError } from '~/errors.ts'; import type { MigrationMeta } from '~/migrator.ts'; import { PgColumn, PgDate, PgJson, PgJsonb, PgNumeric, PgTime, PgTimestamp, PgUUID } from '~/pg-core/columns/index.ts'; -import type { PgDeleteConfig, PgInsertConfig, PgUpdateConfig } from '~/pg-core/query-builders/index.ts'; -import type { Join, PgSelectConfig, SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; +import type { + PgDeleteConfig, + PgInsertConfig, + PgSelectJoinConfig, + PgUpdateConfig, +} from '~/pg-core/query-builders/index.ts'; +import type { PgSelectConfig, SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; import { PgTable } from '~/pg-core/table.ts'; import { type BuildRelationalQueryResult, @@ -20,22 +25,23 @@ import { type TablesRelationalConfig, } from '~/relations.ts'; import { - and, type DriverValueEncoder, - eq, + type Name, Param, - type Query, type QueryTypingsValue, + type QueryWithTypings, SQL, sql, type SQLChunk, -} from '~/sql/index.ts'; +} from '~/sql/sql.ts'; import { Subquery, SubqueryConfig } from '~/subquery.ts'; import { getTableName, Table } from '~/table.ts'; import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; -import { View, ViewBaseConfig } from '~/view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { PgSession } from './session.ts'; -import { type PgMaterializedView, PgViewBase } from './view.ts'; +import type { PgMaterializedView } from './view.ts'; +import { View, and, eq } from '~/sql/index.ts'; +import { PgViewBase } from './view-base.ts'; export class PgDialect { static readonly [entityKind]: string = 'PgDialect'; @@ -199,8 +205,9 @@ export class PgDialect { groupBy, limit, offset, - lockingClauses, + lockingClause, distinct, + setOperators, }: PgSelectConfig, ): SQL { const fieldsList = fieldsFlat ?? orderSelectedFields(fields); @@ -324,23 +331,95 @@ export class PgDialect { const offsetSql = offset ? sql` offset ${offset}` : undefined; - const lockingClausesSql = sql.empty(); - if (lockingClauses) { - for (const { strength, config } of lockingClauses) { - const clauseSql = sql` for ${sql.raw(strength)}`; - if (config.of) { - clauseSql.append(sql` of ${config.of}`); - } - if (config.noWait) { - clauseSql.append(sql` no wait`); - } else if (config.skipLocked) { - clauseSql.append(sql` skip locked`); + const lockingClauseSql = sql.empty(); + if (lockingClause) { + const clauseSql = sql` for ${sql.raw(lockingClause.strength)}`; + if (lockingClause.config.of) { + clauseSql.append( + sql` of ${ + sql.join( + Array.isArray(lockingClause.config.of) ? lockingClause.config.of : [lockingClause.config.of], + sql`, `, + ) + }`, + ); + } + if (lockingClause.config.noWait) { + clauseSql.append(sql` no wait`); + } else if (lockingClause.config.skipLocked) { + clauseSql.append(sql` skip locked`); + } + lockingClauseSql.append(clauseSql); + } + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClauseSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: PgSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: PgSelectConfig['setOperators'][number] }): SQL { + const leftChunk = sql`(${leftSelect.getSQL()}) `; + const rightChunk = sql`(${rightSelect.getSQL()})`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid Sql syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const singleOrderBy of orderBy) { + if (is(singleOrderBy, PgColumn)) { + orderByValues.push(sql.identifier(singleOrderBy.name)); + } else if (is(singleOrderBy, SQL)) { + for (let i = 0; i < singleOrderBy.queryChunks.length; i++) { + const chunk = singleOrderBy.queryChunks[i]; + + if (is(chunk, PgColumn)) { + singleOrderBy.queryChunks[i] = sql.identifier(chunk.name); + } + } + + orderByValues.push(sql`${singleOrderBy}`); + } else { + orderByValues.push(sql`${singleOrderBy}`); } - lockingClausesSql.append(clauseSql); } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `; } - return sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`; + const limitSql = limit ? sql` limit ${limit}` : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } buildInsertQuery({ table, values, onConflict, returning }: PgInsertConfig): SQL { @@ -415,7 +494,7 @@ export class PgDialect { } } - sqlToQuery(sql: SQL): Query { + sqlToQuery(sql: SQL): QueryWithTypings { return sql.toQuery({ escapeName: this.escapeName, escapeParam: this.escapeParam, @@ -977,7 +1056,7 @@ export class PgDialect { }): BuildRelationalQueryResult { let selection: BuildRelationalQueryResult['selection'] = []; let limit, offset, orderBy: NonNullable = [], where; - const joins: Join[] = []; + const joins: PgSelectJoinConfig[] = []; if (config === true) { const selectionEntries = Object.entries(tableConfig.columns); @@ -1150,7 +1229,7 @@ export class PgDialect { } if (selection.length === 0) { - throw new DrizzleError(`No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")`); + throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` }); } let result; @@ -1199,6 +1278,7 @@ export class PgDialect { limit, offset, orderBy, + setOperators: [], }); where = undefined; @@ -1221,6 +1301,7 @@ export class PgDialect { limit, offset, orderBy, + setOperators: [], }); } else { result = this.buildSelectQuery({ @@ -1235,6 +1316,7 @@ export class PgDialect { limit, offset, orderBy, + setOperators: [], }); } diff --git a/drizzle-orm/src/pg-core/expressions.ts b/drizzle-orm/src/pg-core/expressions.ts index e410587b4..88f494633 100644 --- a/drizzle-orm/src/pg-core/expressions.ts +++ b/drizzle-orm/src/pg-core/expressions.ts @@ -1,7 +1,7 @@ import { bindIfParam } from '~/expressions.ts'; import type { PgColumn } from '~/pg-core/columns/index.ts'; -import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/index.ts'; -import { sql } from '~/sql/index.ts'; +import type { Placeholder, SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; export * from '~/expressions.ts'; diff --git a/drizzle-orm/src/pg-core/foreign-keys.ts b/drizzle-orm/src/pg-core/foreign-keys.ts index 31fc00d41..841ac4aa8 100644 --- a/drizzle-orm/src/pg-core/foreign-keys.ts +++ b/drizzle-orm/src/pg-core/foreign-keys.ts @@ -5,6 +5,7 @@ import { PgTable } from './table.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; export type Reference = () => { + readonly name?: string; readonly columns: PgColumn[]; readonly foreignTable: PgTable; readonly foreignColumns: PgColumn[]; @@ -24,6 +25,7 @@ export class ForeignKeyBuilder { constructor( config: () => { + name?: string; columns: PgColumn[]; foreignColumns: PgColumn[]; }, @@ -33,8 +35,8 @@ export class ForeignKeyBuilder { } | undefined, ) { this.reference = () => { - const { columns, foreignColumns } = config(); - return { columns, foreignTable: foreignColumns[0]!.table as PgTable, foreignColumns }; + const { name, columns, foreignColumns } = config(); + return { name, columns, foreignTable: foreignColumns[0]!.table as PgTable, foreignColumns }; }; if (actions) { this._onUpdate = actions.onUpdate; @@ -74,7 +76,7 @@ export class ForeignKey { } getName(): string { - const { columns, foreignColumns } = this.reference(); + const { name, columns, foreignColumns } = this.reference(); const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ @@ -83,7 +85,7 @@ export class ForeignKey { foreignColumns[0]!.table[PgTable.Symbol.Name], ...foreignColumnNames, ]; - return `${chunks.join('_')}_fk`; + return name ?? `${chunks.join('_')}_fk`; } } @@ -98,13 +100,15 @@ export function foreignKey< TColumns extends [AnyPgColumn<{ tableName: TTableName }>, ...AnyPgColumn<{ tableName: TTableName }>[]], >( config: { + name?: string; columns: TColumns; foreignColumns: ColumnsWithTable; }, ): ForeignKeyBuilder { function mappedConfig() { - const { columns, foreignColumns } = config; + const { name, columns, foreignColumns } = config; return { + name, columns, foreignColumns, }; diff --git a/drizzle-orm/src/pg-core/index.ts b/drizzle-orm/src/pg-core/index.ts index 7120e0c5c..1a80ff7ad 100644 --- a/drizzle-orm/src/pg-core/index.ts +++ b/drizzle-orm/src/pg-core/index.ts @@ -13,4 +13,6 @@ export * from './subquery.ts'; export * from './table.ts'; export * from './unique-constraint.ts'; export * from './utils.ts'; +export * from './utils/index.ts'; +export * from './view-common.ts'; export * from './view.ts'; diff --git a/drizzle-orm/src/pg-core/indexes.ts b/drizzle-orm/src/pg-core/indexes.ts index d4ecaf535..a719d44fe 100644 --- a/drizzle-orm/src/pg-core/indexes.ts +++ b/drizzle-orm/src/pg-core/indexes.ts @@ -1,4 +1,4 @@ -import type { SQL } from '~/sql/index.ts'; +import type { SQL } from '~/sql/sql.ts'; import { entityKind } from '~/entity.ts'; import type { PgColumn } from './columns/index.ts'; diff --git a/drizzle-orm/src/pg-core/primary-keys.ts b/drizzle-orm/src/pg-core/primary-keys.ts index 113471192..98d7d3e79 100644 --- a/drizzle-orm/src/pg-core/primary-keys.ts +++ b/drizzle-orm/src/pg-core/primary-keys.ts @@ -4,9 +4,22 @@ import { PgTable } from './table.ts'; export function primaryKey< TTableName extends string, + TColumn extends AnyPgColumn<{ tableName: TTableName }>, TColumns extends AnyPgColumn<{ tableName: TTableName }>[], ->(...columns: TColumns): PrimaryKeyBuilder { - return new PrimaryKeyBuilder(columns); +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnyPgColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); } export class PrimaryKeyBuilder { @@ -15,15 +28,20 @@ export class PrimaryKeyBuilder { /** @internal */ columns: PgColumn[]; + /** @internal */ + name?: string; + constructor( columns: PgColumn[], + name?: string, ) { this.columns = columns; + this.name = name; } /** @internal */ build(table: PgTable): PrimaryKey { - return new PrimaryKey(table, this.columns); + return new PrimaryKey(table, this.columns, this.name); } } @@ -31,12 +49,14 @@ export class PrimaryKey { static readonly [entityKind]: string = 'PgPrimaryKey'; readonly columns: AnyPgColumn<{}>[]; + readonly name?: string; - constructor(readonly table: PgTable, columns: AnyPgColumn<{}>[]) { + constructor(readonly table: PgTable, columns: AnyPgColumn<{}>[], name?: string) { this.columns = columns; + this.name = name; } getName(): string { - return `${this.table[PgTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + return this.name ?? `${this.table[PgTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; } } diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index b9716c692..5f446e03f 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -10,30 +10,109 @@ import type { import type { PgTable } from '~/pg-core/table.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/index.ts'; -import { type InferModel, Table } from '~/table.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; import { orderSelectedFields } from '~/utils.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; +export type PgDeleteWithout< + T extends AnyPgDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + PgDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type PgDelete< + TTable extends PgTable = PgTable, + TQueryResult extends QueryResultHKT = QueryResultHKT, + TReturning extends Record | undefined = Record | undefined, +> = PgDeleteBase; + export interface PgDeleteConfig { where?: SQL | undefined; table: PgTable; returning?: SelectedFieldsOrdered; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface PgDelete< - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type PgDeleteReturningAll< + T extends AnyPgDeleteBase, + TDynamic extends boolean, +> = PgDeleteWithout< + PgDeleteBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['table']['$inferSelect'], + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type PgDeleteReturning< + T extends AnyPgDeleteBase, + TDynamic extends boolean, + TSelectedFields extends SelectedFieldsFlat, +> = PgDeleteWithout< + PgDeleteBase< + T['_']['table'], + T['_']['queryResult'], + SelectResultFields, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type PgDeletePrepare = PreparedQuery< + PreparedQueryConfig & { + execute: T['_']['returning'] extends undefined ? QueryResultKind + : T['_']['returning'][]; + } +>; + +export type PgDeleteDynamic = PgDelete< + T['_']['table'], + T['_']['queryResult'], + T['_']['returning'] +>; + +export type AnyPgDeleteBase = PgDeleteBase; + +export interface PgDeleteBase< TTable extends PgTable, TQueryResult extends QueryResultHKT, TReturning extends Record | undefined = undefined, -> extends QueryPromise : TReturning[]> {} + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]> { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly returning: TReturning; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} -export class PgDelete< +export class PgDeleteBase< TTable extends PgTable, TQueryResult extends QueryResultHKT, TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, > extends QueryPromise : TReturning[]> implements SQLWrapper { @@ -50,18 +129,20 @@ export class PgDelete< this.config = { table }; } - where(where: SQL | undefined): Omit { + where(where: SQL | undefined): PgDeleteWithout { this.config.where = where; - return this; + return this as any; } - returning(): PgDelete>; + returning(): PgDeleteReturningAll; returning( fields: TSelectedFields, - ): PgDelete>; - returning(fields: SelectedFieldsFlat = this.config.table[Table.Symbol.Columns]): PgDelete { + ): PgDeleteReturning; + returning( + fields: SelectedFieldsFlat = this.config.table[Table.Symbol.Columns], + ): PgDeleteReturning { this.config.returning = orderSelectedFields(fields); - return this as PgDelete; + return this as any; } /** @internal */ @@ -69,16 +150,12 @@ export class PgDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - private _prepare(name?: string): PreparedQuery< - PreparedQueryConfig & { - execute: TReturning extends undefined ? QueryResultKind : TReturning[]; - } - > { + private _prepare(name?: string): PgDeletePrepare { return tracer.startActiveSpan('drizzle.prepareQuery', () => { return this.session.prepareQuery< PreparedQueryConfig & { @@ -88,11 +165,7 @@ export class PgDelete< }); } - prepare(name: string): PreparedQuery< - PreparedQueryConfig & { - execute: TReturning extends undefined ? QueryResultKind : TReturning[]; - } - > { + prepare(name: string): PgDeletePrepare { return this._prepare(name); } @@ -101,4 +174,8 @@ export class PgDelete< return this._prepare().execute(placeholderValues); }); }; + + $dynamic(): PgDeleteDynamic { + return this as any; + } } diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index d6cd6c7f9..b886426be 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -11,9 +11,9 @@ import type { import type { PgTable } from '~/pg-core/table.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Placeholder, Query, SQLWrapper } from '~/sql/index.ts'; -import { Param, SQL, sql } from '~/sql/index.ts'; -import { type InferModel, Table } from '~/table.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; import { mapUpdateSet, orderSelectedFields } from '~/utils.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; @@ -28,7 +28,7 @@ export interface PgInsertConfig { export type PgInsertValue = & { - [Key in keyof InferModel]: InferModel[Key] | SQL | Placeholder; + [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; } & {}; @@ -41,9 +41,9 @@ export class PgInsertBuilder): PgInsert; - values(values: PgInsertValue[]): PgInsert; - values(values: PgInsertValue | PgInsertValue[]): PgInsert { + values(value: PgInsertValue): PgInsertBase; + values(values: PgInsertValue[]): PgInsertBase; + values(values: PgInsertValue | PgInsertValue[]): PgInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -58,34 +58,99 @@ export class PgInsertBuilder = + TDynamic extends true ? T + : Omit< + PgInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type PgInsertReturning< + T extends AnyPgInsert, + TDynamic extends boolean, + TSelectedFields extends SelectedFieldsFlat, +> = PgInsertBase< + T['_']['table'], + T['_']['queryResult'], + SelectResultFields, + TDynamic, + T['_']['excludedMethods'] +>; + +export type PgInsertReturningAll = PgInsertBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['table']['$inferSelect'], + TDynamic, + T['_']['excludedMethods'] +>; + +export interface PgInsertOnConflictDoUpdateConfig { + target: IndexColumn | IndexColumn[]; + where?: SQL; + set: PgUpdateSetSource; +} + +export type PgInsertPrepare = PreparedQuery< + PreparedQueryConfig & { + execute: T['_']['returning'] extends undefined ? QueryResultKind + : T['_']['returning'][]; + } +>; + +export type PgInsertDynamic = PgInsert< + T['_']['table'], + T['_']['queryResult'], + T['_']['returning'] +>; + +export type AnyPgInsert = PgInsertBase; + +export interface PgInsertBase< TTable extends PgTable, TQueryResult extends QueryResultHKT, TReturning extends Record | undefined = undefined, -> extends - QueryPromise : TReturning[]>, - SQLWrapper -{} + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly returning: TReturning; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} -export class PgInsert< +export type PgInsert< + TTable extends PgTable = PgTable, + TQueryResult extends QueryResultHKT = QueryResultHKT, + TReturning extends Record | undefined = Record | undefined, +> = PgInsertBase; + +export class PgInsertBase< TTable extends PgTable, TQueryResult extends QueryResultHKT, TReturning extends Record | undefined = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, > extends QueryPromise : TReturning[]> implements SQLWrapper { static readonly [entityKind]: string = 'PgInsert'; - declare _: { - table: TTable; - return: TReturning; - }; - private config: PgInsertConfig; constructor( @@ -98,18 +163,20 @@ export class PgInsert< this.config = { table, values }; } - returning(): PgInsert>; + returning(): PgInsertWithout, TDynamic, 'returning'>; returning( fields: TSelectedFields, - ): PgInsert>; + ): PgInsertWithout, TDynamic, 'returning'>; returning( fields: SelectedFieldsFlat = this.config.table[Table.Symbol.Columns], - ): PgInsert { + ): PgInsertWithout { this.config.returning = orderSelectedFields(fields); - return this; + return this as any; } - onConflictDoNothing(config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {}): this { + onConflictDoNothing( + config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {}, + ): PgInsertWithout { if (config.target === undefined) { this.config.onConflict = sql`do nothing`; } else { @@ -121,14 +188,12 @@ export class PgInsert< const whereSql = config.where ? sql` where ${config.where}` : undefined; this.config.onConflict = sql`(${sql.raw(targetColumn)}) do nothing${whereSql}`; } - return this; + return this as any; } - onConflictDoUpdate(config: { - target: IndexColumn | IndexColumn[]; - where?: SQL; - set: PgUpdateSetSource; - }): this { + onConflictDoUpdate( + config: PgInsertOnConflictDoUpdateConfig, + ): PgInsertWithout { const whereSql = config.where ? sql` where ${config.where}` : undefined; const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); let targetColumn = ''; @@ -136,7 +201,7 @@ export class PgInsert< ? config.target.map((it) => this.dialect.escapeName(it.name)).join(',') : this.dialect.escapeName(config.target.name); this.config.onConflict = sql`(${sql.raw(targetColumn)}) do update set ${setSql}${whereSql}`; - return this; + return this as any; } /** @internal */ @@ -144,16 +209,12 @@ export class PgInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - private _prepare(name?: string): PreparedQuery< - PreparedQueryConfig & { - execute: TReturning extends undefined ? QueryResultKind : TReturning[]; - } - > { + private _prepare(name?: string): PgInsertPrepare { return tracer.startActiveSpan('drizzle.prepareQuery', () => { return this.session.prepareQuery< PreparedQueryConfig & { @@ -163,11 +224,7 @@ export class PgInsert< }); } - prepare(name: string): PreparedQuery< - PreparedQueryConfig & { - execute: TReturning extends undefined ? QueryResultKind : TReturning[]; - } - > { + prepare(name: string): PgInsertPrepare { return this._prepare(name); } @@ -176,4 +233,8 @@ export class PgInsert< return this._prepare().execute(placeholderValues); }); }; + + $dynamic(): PgInsertDynamic { + return this as any; + } } diff --git a/drizzle-orm/src/pg-core/query-builders/query-builder.ts b/drizzle-orm/src/pg-core/query-builders/query-builder.ts index d0b6590c1..755f54251 100644 --- a/drizzle-orm/src/pg-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/pg-core/query-builders/query-builder.ts @@ -1,13 +1,13 @@ import { entityKind } from '~/entity.ts'; import { PgDialect } from '~/pg-core/dialect.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; -import { type SQLWrapper } from '~/sql/index.ts'; -import { SelectionProxyHandler, WithSubquery } from '~/subquery.ts'; -import { type ColumnsSelection } from '~/view.ts'; -import { type PgColumn } from '../columns/index.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; +import type { PgColumn } from '../columns/index.ts'; import type { WithSubqueryWithSelection } from '../subquery.ts'; import { PgSelectBuilder } from './select.ts'; import type { SelectedFields } from './select.types.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export class QueryBuilder { static readonly [entityKind]: string = 'PgQueryBuilder'; diff --git a/drizzle-orm/src/pg-core/query-builders/query.ts b/drizzle-orm/src/pg-core/query-builders/query.ts index 9313f3d31..ab0a99839 100644 --- a/drizzle-orm/src/pg-core/query-builders/query.ts +++ b/drizzle-orm/src/pg-core/query-builders/query.ts @@ -2,17 +2,18 @@ import { entityKind } from '~/entity.ts'; import { QueryPromise } from '~/query-promise.ts'; import { type BuildQueryResult, + type BuildRelationalQueryResult, type DBQueryConfig, mapRelationalRow, type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import type { SQL } from '~/sql/index.ts'; +import type { Query, QueryWithTypings, SQL } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; -import { type KnownKeysOnly } from '~/utils.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; import type { PgDialect } from '../dialect.ts'; import type { PgSession, PreparedQuery, PreparedQueryConfig } from '../session.ts'; -import { type PgTable } from '../table.ts'; +import type { PgTable } from '../table.ts'; export class RelationalQueryBuilder { static readonly [entityKind]: string = 'PgRelationalQueryBuilder'; @@ -81,38 +82,8 @@ export class PgRelationalQuery extends QueryPromise { private _prepare(name?: string): PreparedQuery { return tracer.startActiveSpan('drizzle.prepareQuery', () => { - // const query = this.tableConfig.primaryKey.length > 0 - // ? this.dialect.buildRelationalQueryWithPK({ - // fullSchema: this.fullSchema, - // schema: this.schema, - // tableNamesMap: this.tableNamesMap, - // table: this.table, - // tableConfig: this.tableConfig, - // queryConfig: this.config, - // tableAlias: this.tableConfig.tsName, - // isRoot: true, - // }) - // : this.dialect.buildRelationalQueryWithoutPK({ - // fullSchema: this.fullSchema, - // schema: this.schema, - // tableNamesMap: this.tableNamesMap, - // table: this.table, - // tableConfig: this.tableConfig, - // queryConfig: this.config, - // tableAlias: this.tableConfig.tsName, - // }); + const { query, builtQuery } = this._toSQL(); - const query = this.dialect.buildRelationalQueryWithoutPK({ - fullSchema: this.fullSchema, - schema: this.schema, - tableNamesMap: this.tableNamesMap, - table: this.table, - tableConfig: this.tableConfig, - queryConfig: this.config, - tableAlias: this.tableConfig.tsName, - }); - - const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); return this.session.prepareQuery( builtQuery, undefined, @@ -134,6 +105,26 @@ export class PgRelationalQuery extends QueryPromise { return this._prepare(name); } + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { + const query = this.dialect.buildRelationalQueryWithoutPK({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }); + + const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); + + return { query, builtQuery }; + } + + toSQL(): Query { + return this._toSQL().builtQuery; + } + override execute(): Promise { return tracer.startActiveSpan('drizzle.operation', () => { return this._prepare().execute(); diff --git a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts index ee843641e..3ce015793 100644 --- a/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts +++ b/drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts @@ -9,7 +9,7 @@ import type { } from '~/pg-core/session.ts'; import type { PgMaterializedView } from '~/pg-core/view.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL } from '~/sql/index.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -58,7 +58,7 @@ export class PgRefreshMaterializedView return this.dialect.buildRefreshMaterializedViewQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 5b25a08c8..b76c9c778 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -1,10 +1,10 @@ import { entityKind, is } from '~/entity.ts'; import type { PgColumn } from '~/pg-core/columns/index.ts'; import type { PgDialect } from '~/pg-core/dialect.ts'; -import type { PgSession, PreparedQuery, PreparedQueryConfig } from '~/pg-core/session.ts'; +import type { PgSession, PreparedQueryConfig } from '~/pg-core/session.ts'; import type { SubqueryWithSelection } from '~/pg-core/subquery.ts'; import type { PgTable } from '~/pg-core/table.ts'; -import { PgViewBase } from '~/pg-core/view.ts'; +import { PgViewBase } from '~/pg-core/view-base.ts'; import { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { BuildSubquerySelection, @@ -14,34 +14,38 @@ import type { JoinType, SelectMode, SelectResult, + SetOperator, } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import { type Placeholder, type Query, SQL, type SQLWrapper } from '~/sql/index.ts'; -import { SelectionProxyHandler, Subquery, SubqueryConfig } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; +import { SQL, View } from '~/sql/sql.ts'; +import type { ColumnsSelection, Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Subquery, SubqueryConfig } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { tracer } from '~/tracing.ts'; -import { applyMixins, getTableColumns, getTableLikeName, type ValueOrArray } from '~/utils.ts'; +import { applyMixins, getTableColumns, getTableLikeName, haveSameKeys, type ValueOrArray } from '~/utils.ts'; import { orderSelectedFields } from '~/utils.ts'; -import { type ColumnsSelection, View, ViewBaseConfig } from '~/view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { - JoinFn, + AnyPgSelect, + CreatePgSelectFromBuilderMode, + GetPgSetOperators, LockConfig, LockStrength, + PgCreateSetOperatorFn, + PgJoinFn, PgSelectConfig, + PgSelectDynamic, PgSelectHKT, PgSelectHKTBase, - PgSelectQueryBuilderHKT, + PgSelectPrepare, + PgSelectWithout, + PgSetOperatorExcludedMethods, + PgSetOperatorWithResult, SelectedFields, + SetOperatorRightSelect, } from './select.types.ts'; -type CreatePgSelectFromBuilderMode< - TBuilderMode extends 'db' | 'qb', - TTableName extends string | undefined, - TSelection extends ColumnsSelection, - TSelectMode extends SelectMode, -> = TBuilderMode extends 'db' ? PgSelect - : PgSelectQueryBuilder; - export class PgSelectBuilder< TSelection extends SelectedFields | undefined, TBuilderMode extends 'db' | 'qb' = 'db', @@ -80,7 +84,7 @@ export class PgSelectBuilder< * Specify the table, subquery, or other target that you're * building a select query against. * - * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM|Postgres from documentation} + * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM | Postgres from documentation} */ from( source: TFrom, @@ -110,7 +114,7 @@ export class PgSelectBuilder< fields = getTableColumns(source); } - return new PgSelect({ + return new PgSelectBase({ table: source, fields, isPartialSelect, @@ -122,24 +126,30 @@ export class PgSelectBuilder< } } -export abstract class PgSelectQueryBuilder< +export abstract class PgSelectQueryBuilderBase< THKT extends PgSelectHKTBase, TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record = TTableName extends string ? Record : {}, -> extends TypedQueryBuilder< - BuildSubquerySelection, - SelectResult[] -> { + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { static readonly [entityKind]: string = 'PgSelectQueryBuilder'; override readonly _: { - readonly selectMode: TSelectMode; + readonly hkt: THKT; + readonly tableName: TTableName; readonly selection: TSelection; - readonly result: SelectResult[]; - readonly selectedFields: BuildSubquerySelection; + readonly selectMode: TSelectMode; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; }; protected config: PgSelectConfig; @@ -168,12 +178,13 @@ export abstract class PgSelectQueryBuilder< table, fields: { ...fields }, distinct, + setOperators: [], }; this.isPartialSelect = isPartialSelect; this.session = session; this.dialect = dialect; this._ = { - selectedFields: fields as BuildSubquerySelection, + selectedFields: fields as TSelectedFields, } as this['_']; this.tableName = getTableLikeName(table); this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; @@ -181,7 +192,7 @@ export abstract class PgSelectQueryBuilder< private createJoin( joinType: TJoinType, - ): JoinFn { + ): PgJoinFn { return ( table: PgTable | Subquery | PgViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, @@ -252,7 +263,7 @@ export abstract class PgSelectQueryBuilder< } } - return this; + return this as any; }; } @@ -289,6 +300,61 @@ export abstract class PgSelectQueryBuilder< */ fullJoin = this.createJoin('full'); + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetPgSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => PgSelectWithout< + this, + TDynamic, + PgSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getPgSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + union = this.createSetOperator('union', false); + + unionAll = this.createSetOperator('union', true); + + intersect = this.createSetOperator('intersect', false); + + intersectAll = this.createSetOperator('intersect', true); + + except = this.createSetOperator('except', false); + + exceptAll = this.createSetOperator('except', true); + + /** @internal */ + addSetOperators(setOperators: PgSelectConfig['setOperators']): PgSelectWithout< + this, + TDynamic, + PgSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + /** * Specify a condition to narrow the result set. Multiple * conditions can be combined with the `and` and `or` @@ -301,7 +367,9 @@ export abstract class PgSelectQueryBuilder< * db.select().from(cars).where(eq(cars.year, 2000)); * ``` */ - where(where: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) { + where( + where: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): PgSelectWithout { if (typeof where === 'function') { where = where( new Proxy( @@ -311,7 +379,7 @@ export abstract class PgSelectQueryBuilder< ); } this.config.where = where; - return this; + return this as any; } /** @@ -319,9 +387,11 @@ export abstract class PgSelectQueryBuilder< * used with GROUP BY and filters rows after they've been * grouped together and combined. * - * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-HAVING|Postgres having clause documentation} + * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-HAVING | Postgres having clause documentation} */ - having(having: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) { + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): PgSelectWithout { if (typeof having === 'function') { having = having( new Proxy( @@ -331,7 +401,7 @@ export abstract class PgSelectQueryBuilder< ); } this.config.having = having; - return this; + return this as any; } /** @@ -350,15 +420,17 @@ export abstract class PgSelectQueryBuilder< * }).from(people).groupBy(people.lastName); * ``` * - * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-GROUPBY|Postgres GROUP BY documentation} + * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-GROUPBY | Postgres GROUP BY documentation} */ - groupBy(builder: (aliases: TSelection) => ValueOrArray): this; - groupBy(...columns: (PgColumn | SQL | SQL.Aliased)[]): this; + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): PgSelectWithout; + groupBy(...columns: (PgColumn | SQL | SQL.Aliased)[]): PgSelectWithout; groupBy( ...columns: - | [(aliases: TSelection) => ValueOrArray] + | [(aliases: this['_']['selection']) => ValueOrArray] | (PgColumn | SQL | SQL.Aliased)[] - ) { + ): PgSelectWithout { if (typeof columns[0] === 'function') { const groupBy = columns[0]( new Proxy( @@ -370,7 +442,7 @@ export abstract class PgSelectQueryBuilder< } else { this.config.groupBy = columns as (PgColumn | SQL | SQL.Aliased)[]; } - return this; + return this as any; } /** @@ -386,15 +458,17 @@ export abstract class PgSelectQueryBuilder< * db.select().from(cars).orderBy(cars.year); * ``` * - * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-ORDERBY|Postgres ORDER BY documentation} + * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-ORDERBY | Postgres ORDER BY documentation} */ - orderBy(builder: (aliases: TSelection) => ValueOrArray): this; - orderBy(...columns: (PgColumn | SQL | SQL.Aliased)[]): this; + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): PgSelectWithout; + orderBy(...columns: (PgColumn | SQL | SQL.Aliased)[]): PgSelectWithout; orderBy( ...columns: - | [(aliases: TSelection) => ValueOrArray] + | [(aliases: this['_']['selection']) => ValueOrArray] | (PgColumn | SQL | SQL.Aliased)[] - ) { + ): PgSelectWithout { if (typeof columns[0] === 'function') { const orderBy = columns[0]( new Proxy( @@ -402,11 +476,24 @@ export abstract class PgSelectQueryBuilder< new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), ) as TSelection, ); - this.config.orderBy = Array.isArray(orderBy) ? orderBy : [orderBy]; + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } } else { - this.config.orderBy = columns as (PgColumn | SQL | SQL.Aliased)[]; + const orderByArray = columns as (PgColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } } - return this; + return this as any; } /** @@ -420,11 +507,15 @@ export abstract class PgSelectQueryBuilder< * db.select().from(people).limit(10); * ``` * - * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-LIMIT|Postgres LIMIT documentation} + * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-LIMIT | Postgres LIMIT documentation} */ - limit(limit: number | Placeholder) { - this.config.limit = limit; - return this; + limit(limit: number | Placeholder): PgSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; } /** @@ -438,9 +529,13 @@ export abstract class PgSelectQueryBuilder< * db.select().from(people).offset(10).limit(10); * ``` */ - offset(offset: number | Placeholder) { - this.config.offset = offset; - return this; + offset(offset: number | Placeholder): PgSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; } /** @@ -448,14 +543,11 @@ export abstract class PgSelectQueryBuilder< * that controls how strictly it acquires exclusive access to * the rows being queried. * - * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE|Postgres locking clause documentation} + * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE | PostgreSQL locking clause documentation} */ - for(strength: LockStrength, config: LockConfig = {}) { - if (!this.config.lockingClauses) { - this.config.lockingClauses = []; - } - this.config.lockingClauses.push({ strength, config }); - return this; + for(strength: LockStrength, config: LockConfig = {}): PgSelectWithout { + this.config.lockingClause = { strength, config }; + return this as any; } /** @internal */ @@ -463,46 +555,82 @@ export abstract class PgSelectQueryBuilder< return this.dialect.buildSelectQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } as( alias: TAlias, - ): SubqueryWithSelection, TAlias> { + ): SubqueryWithSelection { return new Proxy( new Subquery(this.getSQL(), this.config.fields, alias), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), - ) as SubqueryWithSelection, TAlias>; + ) as SubqueryWithSelection; + } + + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { + return new Proxy( + this.config.fields, + new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), + ) as this['_']['selectedFields']; + } + + $dynamic(): PgSelectDynamic { + return this; } } -export interface PgSelect< +export interface PgSelectBase< TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record = TTableName extends string ? Record : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends - PgSelectQueryBuilder, - QueryPromise[]> + PgSelectQueryBuilderBase< + PgSelectHKT, + TTableName, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + QueryPromise {} -export class PgSelect< +export class PgSelectBase< TTableName extends string | undefined, - TSelection, + TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record = TTableName extends string ? Record : {}, -> extends PgSelectQueryBuilder { + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, +> extends PgSelectQueryBuilderBase< + PgSelectHKT, + TTableName, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields +> { static readonly [entityKind]: string = 'PgSelect'; - private _prepare(name?: string): PreparedQuery< - PreparedQueryConfig & { - execute: SelectResult[]; - } - > { + private _prepare(name?: string): PgSelectPrepare { const { session, config, dialect, joinsNotNullableMap } = this; if (!session) { throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); @@ -510,7 +638,7 @@ export class PgSelect< return tracer.startActiveSpan('drizzle.prepareQuery', () => { const fieldsList = orderSelectedFields(config.fields); const query = session.prepareQuery< - PreparedQueryConfig & { execute: SelectResult[] } + PreparedQueryConfig & { execute: TResult } >(dialect.sqlToQuery(this.getSQL()), fieldsList, name); query.joinsNotNullableMap = joinsNotNullableMap; return query; @@ -522,13 +650,9 @@ export class PgSelect< * the database to remember this query for the given session * and call it by name, rather than specifying the full query. * - * {@link https://www.postgresql.org/docs/current/sql-prepare.html|Postgres prepare documentation} + * {@link https://www.postgresql.org/docs/current/sql-prepare.html | Postgres prepare documentation} */ - prepare(name: string): PreparedQuery< - PreparedQueryConfig & { - execute: SelectResult[]; - } - > { + prepare(name: string): PgSelectPrepare { return this._prepare(name); } @@ -539,4 +663,45 @@ export class PgSelect< }; } -applyMixins(PgSelect, [QueryPromise]); +applyMixins(PgSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): PgCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnyPgSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnyPgSelect).addSetOperators(setOperators) as any; + }; +} + +const getPgSetOperators = () => ({ + union, + unionAll, + intersect, + intersectAll, + except, + exceptAll, +}); + +export const union = createSetOperator('union', false); + +export const unionAll = createSetOperator('union', true); + +export const intersect = createSetOperator('intersect', false); + +export const intersectAll = createSetOperator('intersect', true); + +export const except = createSetOperator('except', false); + +export const exceptAll = createSetOperator('except', true); diff --git a/drizzle-orm/src/pg-core/query-builders/select.types.ts b/drizzle-orm/src/pg-core/query-builders/select.types.ts index 2ab6d4e62..226a68ac2 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.types.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.types.ts @@ -5,24 +5,29 @@ import type { } from '~/operations.ts'; import type { PgColumn } from '~/pg-core/columns/index.ts'; import type { PgTable, PgTableWithColumns } from '~/pg-core/table.ts'; -import type { PgViewBase, PgViewWithSelection } from '~/pg-core/view.ts'; +import type { PgViewBase } from '~/pg-core/view-base.ts'; +import type { PgViewWithSelection } from '~/pg-core/view.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AppendToNullabilityMap, AppendToResult, + BuildSubquerySelection, GetSelectTableName, JoinNullability, JoinType, MapColumnsToTableAlias, SelectMode, + SelectResult, + SetOperator, } from '~/query-builders/select.types.ts'; -import type { Placeholder, SQL, SQLWrapper } from '~/sql/index.ts'; +import type { ColumnsSelection, Placeholder, SQL, SQLWrapper, View } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; -import type { Assume } from '~/utils.ts'; -import { type ColumnsSelection, type View } from '~/view.ts'; -import type { PgSelect, PgSelectQueryBuilder } from './select.ts'; +import type { Assume, ValidateShape, ValueOrArray } from '~/utils.ts'; +import type { PreparedQuery, PreparedQueryConfig } from '../session.ts'; +import type { PgSelectBase, PgSelectQueryBuilderBase } from './select.ts'; -export interface Join { +export interface PgSelectJoinConfig { on: SQL | undefined; table: PgTable | Subquery | PgViewBase | SQL; alias: string | undefined; @@ -30,8 +35,6 @@ export interface Join { lateral?: boolean; } -export type AnyPgSelect = PgSelect; - export type BuildAliasTable = TTable extends Table ? PgTableWithColumns< UpdateTableConfig; + type: SetOperator; + isAll: boolean; + orderBy?: (PgColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; } -export type JoinFn< - THKT extends PgSelectHKTBase, - TTableName extends string | undefined, - TSelectMode extends SelectMode, +export type PgJoin< + T extends AnyPgSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends PgTable | Subquery | PgViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? PgSelectWithout< + PgSelectKind< + T['_']['hkt'], + T['_']['tableName'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends Table ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + AppendToNullabilityMap, + T['_']['dynamic'], + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type PgJoinFn< + T extends AnyPgSelectQueryBuilder, + TDynamic extends boolean, TJoinType extends JoinType, - TSelection, - TNullabilityMap extends Record, > = < TJoinedTable extends PgTable | Subquery | PgViewBase | SQL, TJoinedName extends GetSelectTableName = GetSelectTableName, ->(table: TJoinedTable, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) => PgSelectKind< - THKT, - TTableName, - AppendToResult< - TTableName, - TSelection, - TJoinedName, - TJoinedTable extends Table ? TJoinedTable['_']['columns'] - : TJoinedTable extends Subquery ? Assume - : never, - TSelectMode - >, - TSelectMode extends 'partial' ? TSelectMode : 'multiple', - AppendToNullabilityMap ->; +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => PgJoin; export type SelectedFieldsFlat = SelectedFieldsFlatBase; @@ -104,7 +130,7 @@ export type LockStrength = 'update' | 'no key update' | 'share' | 'key share'; export type LockConfig = & { - of?: PgTable; + of?: ValueOrArray; } & ({ noWait: true; @@ -122,37 +148,268 @@ export interface PgSelectHKTBase { selection: unknown; selectMode: SelectMode; nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; _type: unknown; } export type PgSelectKind< T extends PgSelectHKTBase, TTableName extends string | undefined, - TSelection, + TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, > = (T & { tableName: TTableName; selection: TSelection; selectMode: TSelectMode; nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; })['_type']; export interface PgSelectQueryBuilderHKT extends PgSelectHKTBase { - _type: PgSelectQueryBuilder< - this, + _type: PgSelectQueryBuilderBase< + PgSelectQueryBuilderHKT, this['tableName'], Assume, this['selectMode'], - Assume> + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume >; } export interface PgSelectHKT extends PgSelectHKTBase { - _type: PgSelect< + _type: PgSelectBase< this['tableName'], Assume, this['selectMode'], - Assume> + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume >; } + +export type CreatePgSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, +> = TBuilderMode extends 'db' ? PgSelectBase + : PgSelectQueryBuilderBase; + +export type PgSetOperatorExcludedMethods = + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'where' + | 'having' + | 'groupBy' + | 'for'; + +export type PgSelectWithout< + T extends AnyPgSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + PgSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type PgSelectPrepare = PreparedQuery< + PreparedQueryConfig & { + execute: T['_']['result']; + } +>; + +export type PgSelectDynamic = PgSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type PgSelectQueryBuilder< + THKT extends PgSelectHKTBase = PgSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = PgSelectQueryBuilderBase< + THKT, + TTableName, + TSelection, + TSelectMode, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnyPgSelectQueryBuilder = PgSelectQueryBuilderBase; + +export type AnyPgSetOperatorInterface = PgSetOperatorInterface; + +export interface PgSetOperatorInterface< + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: PgSelectHKT; + readonly tableName: TTableName; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type PgSetOperatorWithResult = PgSetOperatorInterface< + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type PgSelect< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = PgSelectBase; + +export type AnyPgSelect = PgSelectBase; + +export type PgSetOperator< + TTableName extends string | undefined = string | undefined, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = PgSelectBase< + TTableName, + TSelection, + TSelectMode, + TNullabilityMap, + true, + PgSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends PgSetOperatorWithResult, + TResult extends any[], +> = TValue extends PgSetOperatorInterface ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly PgSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends PgSetOperatorInterface + ? Rest extends AnyPgSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type PgCreateSetOperatorFn = < + TTableName extends string | undefined, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, + TValue extends PgSetOperatorWithResult, + TRest extends PgSetOperatorWithResult[], + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: PgSetOperatorInterface< + TTableName, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => PgSelectWithout< + PgSelectBase< + TTableName, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + PgSetOperatorExcludedMethods, + true +>; + +export type GetPgSetOperators = { + union: PgCreateSetOperatorFn; + intersect: PgCreateSetOperatorFn; + except: PgCreateSetOperatorFn; + unionAll: PgCreateSetOperatorFn; + intersectAll: PgCreateSetOperatorFn; + exceptAll: PgCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index 4139e484b..449f99149 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -11,8 +11,8 @@ import type { import type { PgTable } from '~/pg-core/table.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/index.ts'; -import { type InferModel, Table } from '~/table.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; +import { Table } from '~/table.ts'; import { mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; @@ -44,35 +44,109 @@ export class PgUpdateBuilder): PgUpdate { - return new PgUpdate(this.table, mapUpdateSet(this.table, values), this.session, this.dialect); + set(values: PgUpdateSetSource): PgUpdateBase { + return new PgUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + ); } } -export interface PgUpdate< - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type PgUpdateWithout< + T extends AnyPgUpdate, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + PgUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type PgUpdateReturningAll = PgUpdateWithout< + PgUpdateBase< + T['_']['table'], + T['_']['queryResult'], + T['_']['table']['$inferSelect'], + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type PgUpdateReturning< + T extends AnyPgUpdate, + TDynamic extends boolean, + TSelectedFields extends SelectedFields, +> = PgUpdateWithout< + PgUpdateBase< + T['_']['table'], + T['_']['queryResult'], + SelectResultFields, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type PgUpdatePrepare = PreparedQuery< + PreparedQueryConfig & { + execute: T['_']['returning'] extends undefined ? QueryResultKind + : T['_']['returning'][]; + } +>; + +export type PgUpdateDynamic = PgUpdate< + T['_']['table'], + T['_']['queryResult'], + T['_']['returning'] +>; + +export type PgUpdate< + TTable extends PgTable = PgTable, + TQueryResult extends QueryResultHKT = QueryResultHKT, + TReturning extends Record | undefined = Record | undefined, +> = PgUpdateBase; + +type AnyPgUpdate = PgUpdateBase; + +export interface PgUpdateBase< TTable extends PgTable, TQueryResult extends QueryResultHKT, TReturning extends Record | undefined = undefined, -> extends - QueryPromise : TReturning[]>, - SQLWrapper -{} + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends QueryPromise : TReturning[]>, SQLWrapper { + readonly _: { + readonly table: TTable; + readonly queryResult: TQueryResult; + readonly returning: TReturning; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + }; +} -export class PgUpdate< +export class PgUpdateBase< TTable extends PgTable, TQueryResult extends QueryResultHKT, TReturning extends Record | undefined = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, > extends QueryPromise : TReturning[]> implements SQLWrapper { static readonly [entityKind]: string = 'PgUpdate'; - declare readonly _: { - readonly table: TTable; - readonly return: TReturning; - }; - private config: PgUpdateConfig; constructor( @@ -85,20 +159,20 @@ export class PgUpdate< this.config = { set, table }; } - where(where: SQL | undefined): this { + where(where: SQL | undefined): PgUpdateWithout { this.config.where = where; - return this; + return this as any; } - returning(): PgUpdate>; + returning(): PgUpdateReturningAll; returning( fields: TSelectedFields, - ): PgUpdate>; + ): PgUpdateReturning; returning( fields: SelectedFields = this.config.table[Table.Symbol.Columns], - ): PgUpdate { + ): PgUpdateWithout { this.config.returning = orderSelectedFields(fields); - return this as PgUpdate; + return this as any; } /** @internal */ @@ -106,28 +180,24 @@ export class PgUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Omit { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - private _prepare(name?: string): PreparedQuery< - PreparedQueryConfig & { - execute: TReturning extends undefined ? QueryResultKind : TReturning[]; - } - > { + private _prepare(name?: string): PgUpdatePrepare { return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } - prepare(name: string): PreparedQuery< - PreparedQueryConfig & { - execute: TReturning extends undefined ? QueryResultKind : TReturning[]; - } - > { + prepare(name: string): PgUpdatePrepare { return this._prepare(name); } override execute: ReturnType['execute'] = (placeholderValues) => { return this._prepare().execute(placeholderValues); }; + + $dynamic(): PgUpdateDynamic { + return this as any; + } } diff --git a/drizzle-orm/src/pg-core/session.ts b/drizzle-orm/src/pg-core/session.ts index 87dbdc76d..2b65567c6 100644 --- a/drizzle-orm/src/pg-core/session.ts +++ b/drizzle-orm/src/pg-core/session.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; import { TransactionRollbackError } from '~/errors.ts'; -import { type TablesRelationalConfig } from '~/relations.ts'; +import type { TablesRelationalConfig } from '~/relations.ts'; import { type Query, type SQL, sql } from '~/sql/index.ts'; import { tracer } from '~/tracing.ts'; import { PgDatabase } from './db.ts'; diff --git a/drizzle-orm/src/pg-core/subquery.ts b/drizzle-orm/src/pg-core/subquery.ts index f2952628c..02d78dee1 100644 --- a/drizzle-orm/src/pg-core/subquery.ts +++ b/drizzle-orm/src/pg-core/subquery.ts @@ -1,6 +1,6 @@ import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; import type { Subquery, WithSubquery } from '~/subquery.ts'; -import { type ColumnsSelection } from '~/view.ts'; export type SubqueryWithSelection = & Subquery> diff --git a/drizzle-orm/src/pg-core/utils.ts b/drizzle-orm/src/pg-core/utils.ts index 87a72bb0e..325b7191a 100644 --- a/drizzle-orm/src/pg-core/utils.ts +++ b/drizzle-orm/src/pg-core/utils.ts @@ -1,14 +1,15 @@ import { is } from '~/entity.ts'; import { PgTable } from '~/pg-core/table.ts'; import { Table } from '~/table.ts'; -import { ViewBaseConfig } from '~/view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import { type Check, CheckBuilder } from './checks.ts'; import type { AnyPgColumn } from './columns/index.ts'; import { type ForeignKey, ForeignKeyBuilder } from './foreign-keys.ts'; import { type Index, IndexBuilder } from './indexes.ts'; import { type PrimaryKey, PrimaryKeyBuilder } from './primary-keys.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; -import { type PgMaterializedView, PgMaterializedViewConfig, type PgView, PgViewConfig } from './view.ts'; +import { PgViewConfig } from './view-common.ts'; +import { type PgMaterializedView, PgMaterializedViewConfig, type PgView } from './view.ts'; export function getTableConfig(table: TTable) { const columns = Object.values(table[Table.Symbol.Columns]); @@ -71,102 +72,6 @@ export function getMaterializedViewConfig< }; } -function parsePgArrayValue(arrayString: string, startFrom: number, inQuotes: boolean): [string, number] { - for (let i = startFrom; i < arrayString.length; i++) { - const char = arrayString[i]; - - if (char === '\\') { - i++; - continue; - } - - if (char === '"') { - return [arrayString.slice(startFrom, i).replace(/\\/g, ''), i + 1]; - } - - if (inQuotes) { - continue; - } - - if (char === ',' || char === '}') { - return [arrayString.slice(startFrom, i).replace(/\\/g, ''), i]; - } - } - - return [arrayString.slice(startFrom).replace(/\\/g, ''), arrayString.length]; -} - -export function parsePgNestedArray(arrayString: string, startFrom = 0): [any[], number] { - const result: any[] = []; - let i = startFrom; - let lastCharIsComma = false; - - while (i < arrayString.length) { - const char = arrayString[i]; - - if (char === ',') { - if (lastCharIsComma || i === startFrom) { - result.push(''); - } - lastCharIsComma = true; - i++; - continue; - } - - lastCharIsComma = false; - - if (char === '\\') { - i += 2; - continue; - } - - if (char === '"') { - const [value, startFrom] = parsePgArrayValue(arrayString, i + 1, true); - result.push(value); - i = startFrom; - continue; - } - - if (char === '}') { - return [result, i + 1]; - } - - if (char === '{') { - const [value, startFrom] = parsePgNestedArray(arrayString, i + 1); - result.push(value); - i = startFrom; - continue; - } - - const [value, newStartFrom] = parsePgArrayValue(arrayString, i, false); - result.push(value); - i = newStartFrom; - } - - return [result, i]; -} - -export function parsePgArray(arrayString: string): any[] { - const [result] = parsePgNestedArray(arrayString, 1); - return result; -} - -export function makePgArray(array: any[]): string { - return `{${ - array.map((item) => { - if (Array.isArray(item)) { - return makePgArray(item); - } - - if (typeof item === 'string' && item.includes(',')) { - return `"${item.replace(/"/g, '\\"')}"`; - } - - return `${item}`; - }).join(',') - }}`; -} - export type ColumnsWithTable< TTableName extends string, TForeignTableName extends string, diff --git a/drizzle-orm/src/pg-core/utils/array.ts b/drizzle-orm/src/pg-core/utils/array.ts new file mode 100644 index 000000000..fef4d3fb2 --- /dev/null +++ b/drizzle-orm/src/pg-core/utils/array.ts @@ -0,0 +1,95 @@ +function parsePgArrayValue(arrayString: string, startFrom: number, inQuotes: boolean): [string, number] { + for (let i = startFrom; i < arrayString.length; i++) { + const char = arrayString[i]; + + if (char === '\\') { + i++; + continue; + } + + if (char === '"') { + return [arrayString.slice(startFrom, i).replace(/\\/g, ''), i + 1]; + } + + if (inQuotes) { + continue; + } + + if (char === ',' || char === '}') { + return [arrayString.slice(startFrom, i).replace(/\\/g, ''), i]; + } + } + + return [arrayString.slice(startFrom).replace(/\\/g, ''), arrayString.length]; +} + +export function parsePgNestedArray(arrayString: string, startFrom = 0): [any[], number] { + const result: any[] = []; + let i = startFrom; + let lastCharIsComma = false; + + while (i < arrayString.length) { + const char = arrayString[i]; + + if (char === ',') { + if (lastCharIsComma || i === startFrom) { + result.push(''); + } + lastCharIsComma = true; + i++; + continue; + } + + lastCharIsComma = false; + + if (char === '\\') { + i += 2; + continue; + } + + if (char === '"') { + const [value, startFrom] = parsePgArrayValue(arrayString, i + 1, true); + result.push(value); + i = startFrom; + continue; + } + + if (char === '}') { + return [result, i + 1]; + } + + if (char === '{') { + const [value, startFrom] = parsePgNestedArray(arrayString, i + 1); + result.push(value); + i = startFrom; + continue; + } + + const [value, newStartFrom] = parsePgArrayValue(arrayString, i, false); + result.push(value); + i = newStartFrom; + } + + return [result, i]; +} + +export function parsePgArray(arrayString: string): any[] { + const [result] = parsePgNestedArray(arrayString, 1); + return result; +} + +export function makePgArray(array: any[]): string { + return `{${ + array.map((item) => { + if (Array.isArray(item)) { + return makePgArray(item); + } + + if (typeof item === 'string' && item.includes(',')) { + return `"${item.replace(/"/g, '\\"')}"`; + } + + return `${item}`; + }).join(',') + }}`; +} diff --git a/drizzle-orm/src/pg-core/utils/index.ts b/drizzle-orm/src/pg-core/utils/index.ts new file mode 100644 index 000000000..76eb91d0b --- /dev/null +++ b/drizzle-orm/src/pg-core/utils/index.ts @@ -0,0 +1 @@ +export * from './array.ts'; diff --git a/drizzle-orm/src/pg-core/view-base.ts b/drizzle-orm/src/pg-core/view-base.ts new file mode 100644 index 000000000..87f76ac24 --- /dev/null +++ b/drizzle-orm/src/pg-core/view-base.ts @@ -0,0 +1,14 @@ +import { entityKind } from '~/entity.ts'; +import { type ColumnsSelection, View } from '~/sql/sql.ts'; + +export abstract class PgViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> extends View { + static readonly [entityKind]: string = 'PgViewBase'; + + declare readonly _: View['_'] & { + readonly viewBrand: 'PgViewBase'; + }; +} diff --git a/drizzle-orm/src/pg-core/view-common.ts b/drizzle-orm/src/pg-core/view-common.ts new file mode 100644 index 000000000..01194c7f2 --- /dev/null +++ b/drizzle-orm/src/pg-core/view-common.ts @@ -0,0 +1 @@ +export const PgViewConfig = Symbol.for('drizzle:PgViewConfig'); diff --git a/drizzle-orm/src/pg-core/view.ts b/drizzle-orm/src/pg-core/view.ts index 0ddfcf772..99a06036d 100644 --- a/drizzle-orm/src/pg-core/view.ts +++ b/drizzle-orm/src/pg-core/view.ts @@ -2,14 +2,15 @@ import type { BuildColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; -import type { SQL } from '~/sql/index.ts'; -import { SelectionProxyHandler } from '~/subquery.ts'; +import type { SQL, ColumnsSelection } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; -import { type ColumnsSelection, View } from '~/view.ts'; import type { PgColumn, PgColumnBuilderBase } from './columns/common.ts'; -import { QueryBuilder } from './query-builders/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import { pgTable } from './table.ts'; +import { PgViewConfig } from './view-common.ts'; +import { PgViewBase } from './view-base.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export interface ViewWithConfig { checkOption: 'local' | 'cascaded'; @@ -270,20 +271,6 @@ export class ManualMaterializedViewBuilder< } } -export abstract class PgViewBase< - TName extends string = string, - TExisting extends boolean = boolean, - TSelectedFields extends ColumnsSelection = ColumnsSelection, -> extends View { - static readonly [entityKind]: string = 'PgViewBase'; - - declare readonly _: View['_'] & { - readonly viewBrand: 'PgViewBase'; - }; -} - -export const PgViewConfig = Symbol.for('drizzle:PgViewConfig'); - export class PgView< TName extends string = string, TExisting extends boolean = boolean, diff --git a/drizzle-orm/src/pg-proxy/driver.ts b/drizzle-orm/src/pg-proxy/driver.ts new file mode 100644 index 000000000..2c03dfb61 --- /dev/null +++ b/drizzle-orm/src/pg-proxy/driver.ts @@ -0,0 +1,50 @@ +import { DefaultLogger } from '~/logger.ts'; +import { PgDatabase } from '~/pg-core/db.ts'; +import { PgDialect } from '~/pg-core/dialect.ts'; +import { + createTableRelationsHelpers, + extractTablesRelationalConfig, + type RelationalSchemaConfig, + type TablesRelationalConfig, +} from '~/relations.ts'; +import type { DrizzleConfig } from '~/utils.ts'; +import { type PgRemoteQueryResultHKT, PgRemoteSession } from './session.ts'; + +export type PgRemoteDatabase< + TSchema extends Record = Record, +> = PgDatabase; + +export type RemoteCallback = ( + sql: string, + params: any[], + method: 'all' | 'execute', +) => Promise<{ rows: any[] }>; + +export function drizzle = Record>( + callback: RemoteCallback, + config: DrizzleConfig = {}, +): PgRemoteDatabase { + const dialect = new PgDialect(); + let logger; + if (config.logger === true) { + logger = new DefaultLogger(); + } else if (config.logger !== false) { + logger = config.logger; + } + + let schema: RelationalSchemaConfig | undefined; + if (config.schema) { + const tablesConfig = extractTablesRelationalConfig( + config.schema, + createTableRelationsHelpers, + ); + schema = { + fullSchema: config.schema, + schema: tablesConfig.tables, + tableNamesMap: tablesConfig.tableNamesMap, + }; + } + + const session = new PgRemoteSession(callback, dialect, schema, { logger }); + return new PgDatabase(dialect, session, schema) as PgRemoteDatabase; +} diff --git a/drizzle-orm/src/pg-proxy/index.ts b/drizzle-orm/src/pg-proxy/index.ts new file mode 100644 index 000000000..b1b6a52e7 --- /dev/null +++ b/drizzle-orm/src/pg-proxy/index.ts @@ -0,0 +1,2 @@ +export * from './driver.ts'; +export * from './session.ts'; diff --git a/drizzle-orm/src/pg-proxy/migrator.ts b/drizzle-orm/src/pg-proxy/migrator.ts new file mode 100644 index 000000000..f1b3fb107 --- /dev/null +++ b/drizzle-orm/src/pg-proxy/migrator.ts @@ -0,0 +1,47 @@ +import type { MigrationConfig } from '~/migrator.ts'; +import { readMigrationFiles } from '~/migrator.ts'; +import { sql } from '~/sql/sql.ts'; +import type { PgRemoteDatabase } from './driver.ts'; + +export type ProxyMigrator = (migrationQueries: string[]) => Promise; + +export async function migrate>( + db: PgRemoteDatabase, + callback: ProxyMigrator, + config: string | MigrationConfig, +) { + const migrations = readMigrationFiles(config); + + const migrationTableCreate = sql` + CREATE TABLE IF NOT EXISTS "drizzle"."__drizzle_migrations" ( + id SERIAL PRIMARY KEY, + hash text NOT NULL, + created_at numeric + ) + `; + + await db.execute(sql`CREATE SCHEMA IF NOT EXISTS "drizzle"`); + await db.execute(migrationTableCreate); + + const dbMigrations = await db.execute( + sql`SELECT id, hash, created_at FROM "drizzle"."__drizzle_migrations" ORDER BY created_at DESC LIMIT 1`, + ) as unknown as [number, string, string][]; + + const lastDbMigration = dbMigrations[0] ?? undefined; + + const queriesToRun: string[] = []; + + for (const migration of migrations) { + if ( + !lastDbMigration + || Number(lastDbMigration[2])! < migration.folderMillis + ) { + queriesToRun.push( + ...migration.sql, + `INSERT INTO "drizzle"."__drizzle_migrations" ("hash", "created_at") VALUES('${migration.hash}', '${migration.folderMillis}')`, + ); + } + } + + await callback(queriesToRun); +} diff --git a/drizzle-orm/src/pg-proxy/session.ts b/drizzle-orm/src/pg-proxy/session.ts new file mode 100644 index 000000000..cdff2beca --- /dev/null +++ b/drizzle-orm/src/pg-proxy/session.ts @@ -0,0 +1,127 @@ +import { entityKind } from '~/entity.ts'; +import type { Logger } from '~/logger.ts'; +import { NoopLogger } from '~/logger.ts'; +import type { PgDialect } from '~/pg-core/dialect.ts'; +import { PgTransaction } from '~/pg-core/index.ts'; +import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; +import type { PgTransactionConfig, PreparedQueryConfig, QueryResultHKT } from '~/pg-core/session.ts'; +import { PgSession, PreparedQuery as PreparedQueryBase } from '~/pg-core/session.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query } from '~/sql/sql.ts'; +import { tracer } from '~/tracing.ts'; +import { type Assume, mapResultRow } from '~/utils.ts'; +import type { RemoteCallback } from './driver.ts'; + +export interface PgRemoteSessionOptions { + logger?: Logger; +} + +export class PgRemoteSession< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends PgSession { + static readonly [entityKind]: string = 'PgRemoteSession'; + + private logger: Logger; + + constructor( + private client: RemoteCallback, + dialect: PgDialect, + private schema: RelationalSchemaConfig | undefined, + options: PgRemoteSessionOptions = {}, + ) { + super(dialect); + this.logger = options.logger ?? new NoopLogger(); + } + + prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + name: string | undefined, + customResultMapper?: (rows: unknown[][]) => T['execute'], + ): PreparedQuery { + return new PreparedQuery(this.client, query.sql, query.params, this.logger, fields, customResultMapper); + } + + override async transaction( + _transaction: (tx: PgProxyTransaction) => Promise, + _config?: PgTransactionConfig, + ): Promise { + throw new Error('Transactions are not supported by the Postgres Proxy driver'); + } +} + +export class PgProxyTransaction< + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, +> extends PgTransaction { + static readonly [entityKind]: string = 'PgProxyTransaction'; + + override async transaction( + _transaction: (tx: PgProxyTransaction) => Promise, + ): Promise { + throw new Error('Transactions are not supported by the Postgres Proxy driver'); + } +} + +export class PreparedQuery extends PreparedQueryBase { + static readonly [entityKind]: string = 'PgProxyPreparedQuery'; + + constructor( + private client: RemoteCallback, + private queryString: string, + private params: unknown[], + private logger: Logger, + private fields: SelectedFieldsOrdered | undefined, + private customResultMapper?: (rows: unknown[][]) => T['execute'], + ) { + super(); + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + return tracer.startActiveSpan('drizzle.execute', async (span) => { + const params = fillPlaceholders(this.params, placeholderValues); + const { fields, client, queryString, joinsNotNullableMap, customResultMapper, logger } = this; + + span?.setAttributes({ + 'drizzle.query.text': queryString, + 'drizzle.query.params': JSON.stringify(params), + }); + + logger.logQuery(queryString, params); + + if (!fields && !customResultMapper) { + return tracer.startActiveSpan('drizzle.driver.execute', async () => { + const { rows } = await client(queryString, params as any[], 'execute'); + + return rows; + }); + } + + const rows = await tracer.startActiveSpan('drizzle.driver.execute', async () => { + span?.setAttributes({ + 'drizzle.query.text': queryString, + 'drizzle.query.params': JSON.stringify(params), + }); + + const { rows } = await client(queryString, params as any[], 'all'); + + return rows; + }); + + return tracer.startActiveSpan('drizzle.mapResponse', () => { + return customResultMapper + ? customResultMapper(rows) + : rows.map((row) => mapResultRow(fields!, row, joinsNotNullableMap)); + }); + }); + } + + async all() {} +} + +export interface PgRemoteQueryResultHKT extends QueryResultHKT { + type: Assume[]; +} diff --git a/drizzle-orm/src/planetscale-serverless/driver.ts b/drizzle-orm/src/planetscale-serverless/driver.ts index 9f55a2fac..2cc72053f 100644 --- a/drizzle-orm/src/planetscale-serverless/driver.ts +++ b/drizzle-orm/src/planetscale-serverless/driver.ts @@ -9,7 +9,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from './session.ts'; import { PlanetscaleSession } from './session.ts'; diff --git a/drizzle-orm/src/planetscale-serverless/session.ts b/drizzle-orm/src/planetscale-serverless/session.ts index 8652120ff..913008c95 100644 --- a/drizzle-orm/src/planetscale-serverless/session.ts +++ b/drizzle-orm/src/planetscale-serverless/session.ts @@ -12,8 +12,8 @@ import { type PreparedQueryHKT, type QueryResultHKT, } from '~/mysql-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, type SQL, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type PlanetScaleConnection = Connection; diff --git a/drizzle-orm/src/postgres-js/README.md b/drizzle-orm/src/postgres-js/README.md index 12b421f18..8ddf9586e 100644 --- a/drizzle-orm/src/postgres-js/README.md +++ b/drizzle-orm/src/postgres-js/README.md @@ -19,11 +19,11 @@ pnpm add -D drizzle-kit ## Connection ```typescript -import { drizzle, PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import { drizzle } from 'drizzle-orm/postgres-js'; import postgres from 'postgres'; const client = postgres(connectionString); -const db: PostgresJsDatabase = drizzle(client); +const db = drizzle(client); ``` See [main docs](/drizzle-orm/src/pg-core/README.md#sql-schema-declaration) for further usage. diff --git a/drizzle-orm/src/postgres-js/driver.ts b/drizzle-orm/src/postgres-js/driver.ts index bdc2a958d..9726bef8f 100644 --- a/drizzle-orm/src/postgres-js/driver.ts +++ b/drizzle-orm/src/postgres-js/driver.ts @@ -8,7 +8,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import type { PostgresJsQueryResultHKT } from './session.ts'; import { PostgresJsSession } from './session.ts'; diff --git a/drizzle-orm/src/postgres-js/session.ts b/drizzle-orm/src/postgres-js/session.ts index 8431ca2e0..f861b260f 100644 --- a/drizzle-orm/src/postgres-js/session.ts +++ b/drizzle-orm/src/postgres-js/session.ts @@ -7,8 +7,8 @@ import { PgTransaction } from '~/pg-core/index.ts'; import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; import type { PgTransactionConfig, PreparedQueryConfig, QueryResultHKT } from '~/pg-core/session.ts'; import { PgSession, PreparedQuery } from '~/pg-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query } from '~/sql/sql.ts'; import { tracer } from '~/tracing.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; diff --git a/drizzle-orm/src/primary-key.ts b/drizzle-orm/src/primary-key.ts index 78ec818fc..b4660fe2f 100644 --- a/drizzle-orm/src/primary-key.ts +++ b/drizzle-orm/src/primary-key.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; -import { type AnyColumn } from './column.ts'; -import { type Table } from './table.ts'; +import type { AnyColumn } from './column.ts'; +import type { Table } from './table.ts'; export abstract class PrimaryKey { static readonly [entityKind]: string = 'PrimaryKey'; diff --git a/drizzle-orm/src/query-builders/select.types.ts b/drizzle-orm/src/query-builders/select.types.ts index 8659b0cad..0078330e4 100644 --- a/drizzle-orm/src/query-builders/select.types.ts +++ b/drizzle-orm/src/query-builders/select.types.ts @@ -1,11 +1,10 @@ import type { ChangeColumnTableName, Dialect } from '~/column-builder.ts'; import type { AnyColumn, Column, GetColumnData, UpdateColConfig } from '~/column.ts'; import type { SelectedFields } from '~/operations.ts'; -import type { SQL } from '~/sql/index.ts'; +import type { ColumnsSelection, SQL, View } from '~/sql/sql.ts'; import type { Subquery } from '~/subquery.ts'; -import type { AnyTable, Table } from '~/table.ts'; +import type { Table } from '~/table.ts'; import type { Assume, DrizzleTypeError, Equal, IsAny, Simplify } from '~/utils.ts'; -import type { ColumnsSelection, View } from '~/view.ts'; export type JoinType = 'inner' | 'left' | 'right' | 'full'; @@ -49,7 +48,7 @@ type Not = T extends true ? false : true; type SelectPartialResult> = TNullability extends TNullability ? { [Key in keyof TFields]: TFields[Key] extends infer TField - ? TField extends AnyTable ? TField['_']['name'] extends keyof TNullability ? ApplyNullability< + ? TField extends Table ? TField['_']['name'] extends keyof TNullability ? ApplyNullability< SelectResultFields, TNullability[TField['_']['name']] > @@ -160,8 +159,10 @@ export type SelectResultField = T extends Drizz : T extends Record ? SelectResultFields : never; -export type SelectResultFields = - & { +export type SelectResultFields = Simplify< + { [Key in keyof TSelectedFields & string]: SelectResultField; } - & {}; +>; + +export type SetOperator = 'union' | 'intersect' | 'except'; diff --git a/drizzle-orm/src/relations.ts b/drizzle-orm/src/relations.ts index e56a55e81..cc87cf787 100644 --- a/drizzle-orm/src/relations.ts +++ b/drizzle-orm/src/relations.ts @@ -1,9 +1,34 @@ import { type AnyTable, type InferModelFromColumns, isTable, Table } from '~/table.ts'; import { type AnyColumn, Column } from './column.ts'; import { entityKind, is } from './entity.ts'; -import { PrimaryKeyBuilder } from './pg-core/index.ts'; -import { and, asc, desc, eq, or, type Placeholder, SQL, sql } from './sql/index.ts'; -import { type Assume, type ColumnsWithTable, type Equal, type Simplify, type ValueOrArray } from './utils.ts'; +import { PrimaryKeyBuilder } from './pg-core/primary-keys.ts'; +import { + and, + asc, + between, + desc, + eq, + exists, + gt, + gte, + ilike, + inArray, + isNotNull, + isNull, + like, + lt, + lte, + ne, + not, + notBetween, + notExists, + notIlike, + notInArray, + notLike, + or, +} from './sql/expressions/index.ts'; +import { type Placeholder, SQL, sql } from './sql/sql.ts'; +import type { Assume, ColumnsWithTable, Equal, Simplify, ValueOrArray } from './utils.ts'; export abstract class Relation { static readonly [entityKind]: string = 'Relation'; @@ -37,9 +62,10 @@ export class Relations< ) {} } -export class One - extends Relation -{ +export class One< + TTableName extends string = string, + TIsNullable extends boolean = boolean, +> extends Relation { static readonly [entityKind]: string = 'One'; declare protected $relationBrand: 'One'; @@ -60,7 +86,12 @@ export class One { - const relation = new One(this.sourceTable, this.referencedTable, this.config, this.isNullable); + const relation = new One( + this.sourceTable, + this.referencedTable, + this.config, + this.isNullable, + ); relation.fieldName = fieldName; return relation; } @@ -80,7 +111,11 @@ export class Many extends Relation { } withFieldName(fieldName: string): Many { - const relation = new Many(this.sourceTable, this.referencedTable, this.config); + const relation = new Many( + this.sourceTable, + this.referencedTable, + this.config, + ); relation.fieldName = fieldName; return relation; } @@ -92,29 +127,59 @@ export type TableRelationsKeysOnly< K extends keyof TSchema, > = TSchema[K] extends Relations ? K : never; -export type ExtractTableRelationsFromSchema, TTableName extends string> = - ExtractObjectValues< - { - [K in keyof TSchema as TableRelationsKeysOnly]: TSchema[K] extends - Relations ? TConfig : never; - } - >; +export type ExtractTableRelationsFromSchema< + TSchema extends Record, + TTableName extends string, +> = ExtractObjectValues< + { + [ + K in keyof TSchema as TableRelationsKeysOnly< + TSchema, + TTableName, + K + > + ]: TSchema[K] extends Relations ? TConfig : never; + } +>; export type ExtractObjectValues = T[keyof T]; -export type ExtractRelationsFromTableExtraConfigSchema = ExtractObjectValues< +export type ExtractRelationsFromTableExtraConfigSchema< + TConfig extends unknown[], +> = ExtractObjectValues< { - [K in keyof TConfig as TConfig[K] extends Relations ? K : never]: TConfig[K] extends - Relations ? TRelationConfig : never; + [ + K in keyof TConfig as TConfig[K] extends Relations ? K + : never + ]: TConfig[K] extends Relations ? TRelationConfig + : never; } >; export function getOperators() { return { - sql, - eq, and, + between, + eq, + exists, + gt, + gte, + ilike, + inArray, + isNull, + isNotNull, + like, + lt, + lte, + ne, + not, + notBetween, + notExists, + notLike, + notIlike, + notInArray, or, + sql, }; } @@ -130,9 +195,15 @@ export function getOrderByOperators() { export type OrderByOperators = ReturnType; -export type FindTableByDBName = ExtractObjectValues< +export type FindTableByDBName< + TSchema extends TablesRelationalConfig, + TTableName extends string, +> = ExtractObjectValues< { - [K in keyof TSchema as TSchema[K]['dbName'] extends TTableName ? K : never]: TSchema[K]; + [ + K in keyof TSchema as TSchema[K]['dbName'] extends TTableName ? K + : never + ]: TSchema[K]; } >; @@ -153,13 +224,19 @@ export type DBQueryConfig< TTableConfig['relations'][K] extends One ? 'one' : 'many', false, TSchema, - FindTableByDBName + FindTableByDBName< + TSchema, + TTableConfig['relations'][K]['referencedTableName'] + > >; }; extras?: | Record | (( - fields: Simplify<[TTableConfig['columns']] extends [never] ? {} : TTableConfig['columns']>, + fields: Simplify< + [TTableConfig['columns']] extends [never] ? {} + : TTableConfig['columns'] + >, operators: { sql: Operators['sql'] }, ) => Record); } @@ -169,13 +246,19 @@ export type DBQueryConfig< | SQL | undefined | (( - fields: Simplify<[TTableConfig['columns']] extends [never] ? {} : TTableConfig['columns']>, + fields: Simplify< + [TTableConfig['columns']] extends [never] ? {} + : TTableConfig['columns'] + >, operators: Operators, ) => SQL | undefined); orderBy?: | ValueOrArray | (( - fields: Simplify<[TTableConfig['columns']] extends [never] ? {} : TTableConfig['columns']>, + fields: Simplify< + [TTableConfig['columns']] extends [never] ? {} + : TTableConfig['columns'] + >, operators: OrderByOperators, ) => ValueOrArray); limit?: number | Placeholder; @@ -192,41 +275,57 @@ export interface TableRelationalConfig { columns: Record; relations: Record; primaryKey: AnyColumn[]; + schema?: string; } export type TablesRelationalConfig = Record; -export interface RelationalSchemaConfig { +export interface RelationalSchemaConfig< + TSchema extends TablesRelationalConfig, +> { fullSchema: Record; schema: TSchema; tableNamesMap: Record; } -export type ExtractTablesWithRelations> = { - [K in keyof TSchema as TSchema[K] extends Table ? K : never]: TSchema[K] extends Table ? { +export type ExtractTablesWithRelations< + TSchema extends Record, +> = { + [ + K in keyof TSchema as TSchema[K] extends Table ? K + : never + ]: TSchema[K] extends Table ? { tsName: K & string; dbName: TSchema[K]['_']['name']; columns: TSchema[K]['_']['columns']; - relations: ExtractTableRelationsFromSchema; + relations: ExtractTableRelationsFromSchema< + TSchema, + TSchema[K]['_']['name'] + >; primaryKey: AnyColumn[]; } : never; }; -export type ReturnTypeOrValue = T extends (...args: any[]) => infer R ? R : T; +export type ReturnTypeOrValue = T extends (...args: any[]) => infer R ? R + : T; export type BuildRelationResult< TSchema extends TablesRelationalConfig, TInclude, TRelations extends Record, > = { - [K in NonUndefinedKeysOnly & keyof TRelations]: TRelations[K] extends infer TRel extends Relation - ? BuildQueryResult< + [ + K in + & NonUndefinedKeysOnly + & keyof TRelations + ]: TRelations[K] extends infer TRel extends Relation ? BuildQueryResult< TSchema, FindTableByDBName, Assume> - > extends infer TResult - ? TRel extends One ? (TResult | (Equal extends true ? null : never)) + > extends infer TResult ? TRel extends One ? + | TResult + | (Equal extends true ? null : never) : TResult[] : never : never; @@ -245,29 +344,44 @@ export type BuildQueryResult< TTableConfig extends TableRelationalConfig, TFullSelection extends true | Record, > = Equal extends true ? InferModelFromColumns - : TFullSelection extends Record ? (Simplify< + : TFullSelection extends Record ? Simplify< & (TFullSelection['columns'] extends Record ? InferModelFromColumns< { [ - K in (Equal< + K in Equal< Exclude< - TFullSelection['columns'][keyof TFullSelection['columns'] & keyof TTableConfig['columns']], + TFullSelection['columns'][ + & keyof TFullSelection['columns'] + & keyof TTableConfig['columns'] + ], undefined >, false - > extends true ? Exclude> + > extends true ? Exclude< + keyof TTableConfig['columns'], + NonUndefinedKeysOnly + > : & { - [K in keyof TFullSelection['columns']]: Equal extends true ? K + [K in keyof TFullSelection['columns']]: Equal< + TFullSelection['columns'][K], + true + > extends true ? K : never; }[keyof TFullSelection['columns']] - & keyof TTableConfig['columns']) + & keyof TTableConfig['columns'] ]: TTableConfig['columns'][K]; } > : InferModelFromColumns) - & (TFullSelection['extras'] extends Record | ((...args: any[]) => Record) ? { - [K in NonUndefinedKeysOnly>]: Assume< + & (TFullSelection['extras'] extends + | Record + | ((...args: any[]) => Record) ? { + [ + K in NonUndefinedKeysOnly< + ReturnTypeOrValue + > + ]: Assume< ReturnTypeOrValue[K], SQL.Aliased >['_']['type']; @@ -279,7 +393,7 @@ export type BuildQueryResult< TTableConfig['relations'] > : {}) - >) + > : never; export interface RelationConfig< @@ -292,18 +406,27 @@ export interface RelationConfig< references: ColumnsWithTable; } -export function extractTablesRelationalConfig( +export function extractTablesRelationalConfig< + TTables extends TablesRelationalConfig, +>( schema: Record, configHelpers: (table: Table) => any, ): { tables: TTables; tableNamesMap: Record } { - if (Object.keys(schema).length === 1 && 'default' in schema && !is(schema['default'], Table)) { + if ( + Object.keys(schema).length === 1 + && 'default' in schema + && !is(schema['default'], Table) + ) { schema = schema['default'] as Record; } // table DB name -> schema table key const tableNamesMap: Record = {}; // Table relations found before their tables - need to buffer them until we know the schema table key - const relationsBuffer: Record; primaryKey?: AnyColumn[] }> = {}; + const relationsBuffer: Record< + string, + { relations: Record; primaryKey?: AnyColumn[] } + > = {}; const tablesConfig: TablesRelationalConfig = {}; for (const [key, value] of Object.entries(schema)) { if (isTable(value)) { @@ -313,13 +436,18 @@ export function extractTablesRelationalConfig = value.config(configHelpers(value.table)); + const relations: Record = value.config( + configHelpers(value.table), + ); let primaryKey: AnyColumn[] | undefined; for (const [relationName, relation] of Object.entries(relations)) { @@ -362,7 +492,10 @@ export function extractTablesRelationalConfig>>( +export function relations< + TTableName extends string, + TRelations extends Record>, +>( table: AnyTable<{ name: TTableName }>, relations: (helpers: TableRelationsHelpers) => TRelations, ): Relations { @@ -370,8 +503,10 @@ export function relations) => Object.fromEntries( - Object.entries(relations(helpers)) - .map(([key, value]) => [key, value.withFieldName(key)]), + Object.entries(relations(helpers)).map(([key, value]) => [ + key, + value.withFieldName(key), + ]), ) as TRelations, ); } @@ -386,15 +521,16 @@ export function createOne(sourceTable: Table) { >( table: TForeignTable, config?: RelationConfig, - ): One> { + ): One< + TForeignTable['_']['name'], + Equal + > { return new One( sourceTable, table, config, - (config?.fields.reduce((res, f) => res && f.notNull, true) ?? false) as Equal< - TColumns[number]['_']['notNull'], - true - >, + (config?.fields.reduce((res, f) => res && f.notNull, true) + ?? false) as Equal, ); }; } @@ -427,7 +563,9 @@ export function normalizeRelation( const referencedTableTsName = tableNamesMap[relation.referencedTable[Table.Symbol.Name]]; if (!referencedTableTsName) { - throw new Error(`Table "${relation.referencedTable[Table.Symbol.Name]}" not found in schema`); + throw new Error( + `Table "${relation.referencedTable[Table.Symbol.Name]}" not found in schema`, + ); } const referencedTableConfig = schema[referencedTableTsName]; @@ -438,15 +576,23 @@ export function normalizeRelation( const sourceTable = relation.sourceTable; const sourceTableTsName = tableNamesMap[sourceTable[Table.Symbol.Name]]; if (!sourceTableTsName) { - throw new Error(`Table "${sourceTable[Table.Symbol.Name]}" not found in schema`); + throw new Error( + `Table "${sourceTable[Table.Symbol.Name]}" not found in schema`, + ); } const reverseRelations: Relation[] = []; - for (const referencedTableRelation of Object.values(referencedTableConfig.relations)) { + for ( + const referencedTableRelation of Object.values( + referencedTableConfig.relations, + ) + ) { if ( - (relation.relationName && relation !== referencedTableRelation + (relation.relationName + && relation !== referencedTableRelation && referencedTableRelation.relationName === relation.relationName) - || (!relation.relationName && referencedTableRelation.referencedTable === relation.sourceTable) + || (!relation.relationName + && referencedTableRelation.referencedTable === relation.sourceTable) ) { reverseRelations.push(referencedTableRelation); } @@ -464,7 +610,11 @@ export function normalizeRelation( ); } - if (reverseRelations[0] && is(reverseRelations[0], One) && reverseRelations[0].config) { + if ( + reverseRelations[0] + && is(reverseRelations[0], One) + && reverseRelations[0].config + ) { return { fields: reverseRelations[0].config.references, references: reverseRelations[0].config.fields, @@ -489,7 +639,10 @@ export type TableRelationsHelpers = ReturnType< typeof createTableRelationsHelpers >; -export interface BuildRelationalQueryResult { +export interface BuildRelationalQueryResult< + TTable extends Table = Table, + TColumn extends Column = Column, +> { tableTsKey: string; selection: { dbKey: string; @@ -512,11 +665,22 @@ export function mapRelationalRow( ): Record { const result: Record = {}; - for (const [selectionItemIndex, selectionItem] of buildQueryResultSelection.entries()) { + for ( + const [ + selectionItemIndex, + selectionItem, + ] of buildQueryResultSelection.entries() + ) { if (selectionItem.isJson) { const relation = tableConfig.relations[selectionItem.tsKey]!; - const rawSubRows = row[selectionItemIndex] as unknown[] | null | [null] | string; - const subRows = typeof rawSubRows === 'string' ? JSON.parse(rawSubRows) as unknown[] : rawSubRows; + const rawSubRows = row[selectionItemIndex] as + | unknown[] + | null + | [null] + | string; + const subRows = typeof rawSubRows === 'string' + ? (JSON.parse(rawSubRows) as unknown[]) + : rawSubRows; result[selectionItem.tsKey] = is(relation, One) ? subRows && mapRelationalRow( diff --git a/drizzle-orm/src/runnable-query.ts b/drizzle-orm/src/runnable-query.ts new file mode 100644 index 000000000..c554daae6 --- /dev/null +++ b/drizzle-orm/src/runnable-query.ts @@ -0,0 +1,11 @@ +import type { Dialect } from './column-builder.ts'; +import type { PreparedQuery } from './session.ts'; + +export interface RunnableQuery { + readonly _: { + readonly dialect: TDialect; + readonly result: T; + }; + + prepare(): PreparedQuery; +} diff --git a/drizzle-orm/src/selection-proxy.ts b/drizzle-orm/src/selection-proxy.ts new file mode 100644 index 000000000..9127793ac --- /dev/null +++ b/drizzle-orm/src/selection-proxy.ts @@ -0,0 +1,121 @@ +import { ColumnAliasProxyHandler, TableAliasProxyHandler } from './alias.ts'; +import { Column } from './column.ts'; +import { entityKind, is } from './entity.ts'; +import { SQL, View } from './sql/sql.ts'; +import { Subquery, SubqueryConfig } from './subquery.ts'; +import { ViewBaseConfig } from './view-common.ts'; + +export class SelectionProxyHandler | View> + implements ProxyHandler | View> +{ + static readonly [entityKind]: string = 'SelectionProxyHandler'; + + private config: { + /** + * Table alias for the columns + */ + alias?: string; + /** + * What to do when a field is an instance of `SQL.Aliased` and it's not a selection field (from a subquery) + * + * `sql` - return the underlying SQL expression + * + * `alias` - return the field alias + */ + sqlAliasedBehavior: 'sql' | 'alias'; + /** + * What to do when a field is an instance of `SQL` and it doesn't have an alias declared + * + * `sql` - return the underlying SQL expression + * + * `error` - return a DrizzleTypeError on type level and throw an error on runtime + */ + sqlBehavior: 'sql' | 'error'; + + /** + * Whether to replace the original name of the column with the alias + * Should be set to `true` for views creation + * @default false + */ + replaceOriginalName?: boolean; + }; + + constructor(config: SelectionProxyHandler['config']) { + this.config = { ...config }; + } + + get(subquery: T, prop: string | symbol): any { + if (prop === SubqueryConfig) { + return { + ...subquery[SubqueryConfig as keyof typeof subquery], + selection: new Proxy( + (subquery as Subquery)[SubqueryConfig].selection, + this as ProxyHandler>, + ), + }; + } + + if (prop === ViewBaseConfig) { + return { + ...subquery[ViewBaseConfig as keyof typeof subquery], + selectedFields: new Proxy( + (subquery as View)[ViewBaseConfig].selectedFields, + this as ProxyHandler>, + ), + }; + } + + if (typeof prop === 'symbol') { + return subquery[prop as keyof typeof subquery]; + } + + const columns = is(subquery, Subquery) + ? subquery[SubqueryConfig].selection + : is(subquery, View) + ? subquery[ViewBaseConfig].selectedFields + : subquery; + const value: unknown = columns[prop as keyof typeof columns]; + + if (is(value, SQL.Aliased)) { + // Never return the underlying SQL expression for a field previously selected in a subquery + if (this.config.sqlAliasedBehavior === 'sql' && !value.isSelectionField) { + return value.sql; + } + + const newValue = value.clone(); + newValue.isSelectionField = true; + return newValue; + } + + if (is(value, SQL)) { + if (this.config.sqlBehavior === 'sql') { + return value; + } + + throw new Error( + `You tried to reference "${prop}" field from a subquery, which is a raw SQL field, but it doesn't have an alias declared. Please add an alias to the field using ".as('alias')" method.`, + ); + } + + if (is(value, Column)) { + if (this.config.alias) { + return new Proxy( + value, + new ColumnAliasProxyHandler( + new Proxy( + value.table, + new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false), + ), + ), + ); + } + return value; + } + + if (typeof value !== 'object' || value === null) { + return value; + } + + return new Proxy(value, new SelectionProxyHandler(this.config)); + } +} diff --git a/drizzle-orm/src/session.ts b/drizzle-orm/src/session.ts new file mode 100644 index 000000000..128475891 --- /dev/null +++ b/drizzle-orm/src/session.ts @@ -0,0 +1,6 @@ +import type { Query } from './index.ts'; + +export interface PreparedQuery { + getQuery(): Query; + mapResult(response: unknown, isFromBatch?: boolean): unknown; +} diff --git a/drizzle-orm/src/sql-js/driver.ts b/drizzle-orm/src/sql-js/driver.ts index b35912c87..2e7080721 100644 --- a/drizzle-orm/src/sql-js/driver.ts +++ b/drizzle-orm/src/sql-js/driver.ts @@ -8,7 +8,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { SQLJsSession } from './session.ts'; export type SQLJsDatabase< diff --git a/drizzle-orm/src/sql-js/session.ts b/drizzle-orm/src/sql-js/session.ts index f9617e40c..978de6e3e 100644 --- a/drizzle-orm/src/sql-js/session.ts +++ b/drizzle-orm/src/sql-js/session.ts @@ -2,8 +2,8 @@ import type { BindParams, Database, Statement } from 'sql.js'; import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import type { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { SQLiteTransaction } from '~/sqlite-core/index.ts'; import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; @@ -12,7 +12,7 @@ import type { SQLiteExecuteMethod, SQLiteTransactionConfig, } from '~/sqlite-core/session.ts'; -import { PreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; import { mapResultRow } from '~/utils.ts'; export interface SQLJsSessionOptions { @@ -45,7 +45,7 @@ export class SQLJsSession< executeMethod: SQLiteExecuteMethod, ): PreparedQuery { const stmt = this.client.prepare(query.sql); - return new PreparedQuery(stmt, query.sql, query.params, this.logger, fields, executeMethod); + return new PreparedQuery(stmt, query, this.logger, fields, executeMethod); } override prepareOneTimeQuery>( @@ -57,8 +57,7 @@ export class SQLJsSession< const stmt = this.client.prepare(query.sql); return new PreparedQuery( stmt, - query.sql, - query.params, + query, this.logger, fields, executeMethod, @@ -112,20 +111,19 @@ export class PreparedQuery constructor( private stmt: Statement, - private queryString: string, - private params: unknown[], + query: Query, private logger: Logger, private fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, private customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, private isOneTimeQuery = false, ) { - super('sync', executeMethod); + super('sync', executeMethod, query); } run(placeholderValues?: Record): void { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); const result = this.stmt.run(params as BindParams); if (this.isOneTimeQuery) { @@ -136,10 +134,10 @@ export class PreparedQuery } all(placeholderValues?: Record): T['all'] { - const { fields, joinsNotNullableMap, logger, queryString, stmt, isOneTimeQuery, customResultMapper } = this; + const { fields, joinsNotNullableMap, logger, query, stmt, isOneTimeQuery, customResultMapper } = this; if (!fields && !customResultMapper) { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); stmt.bind(params as BindParams); const rows: unknown[] = []; while (stmt.step()) { @@ -163,8 +161,8 @@ export class PreparedQuery } get(placeholderValues?: Record): T['get'] { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); const { fields, stmt, isOneTimeQuery, joinsNotNullableMap, customResultMapper } = this; if (!fields && !customResultMapper) { @@ -195,8 +193,8 @@ export class PreparedQuery } values(placeholderValues?: Record): T['values'] { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); this.stmt.bind(params as BindParams); const rows: unknown[] = []; while (this.stmt.step()) { diff --git a/drizzle-orm/src/sql/expressions/conditions.ts b/drizzle-orm/src/sql/expressions/conditions.ts index fe0e66efd..d1fa377ce 100644 --- a/drizzle-orm/src/sql/expressions/conditions.ts +++ b/drizzle-orm/src/sql/expressions/conditions.ts @@ -1,7 +1,6 @@ import { type AnyColumn, Column, type GetColumnData } from '~/column.ts'; import { is } from '~/entity.ts'; import { Table } from '~/table.ts'; -import { View } from '~/view.ts'; import { isDriverValueEncoder, isSQLWrapper, @@ -12,12 +11,18 @@ import { type SQLChunk, type SQLWrapper, StringChunk, -} from '../index.ts'; + View, +} from '../sql.ts'; export function bindIfParam(value: unknown, column: SQLWrapper): SQLChunk { if ( - isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder) - && !is(value, Column) && !is(value, Table) && !is(value, View) + isDriverValueEncoder(column) + && !isSQLWrapper(value) + && !is(value, Param) + && !is(value, Placeholder) + && !is(value, Column) + && !is(value, Table) + && !is(value, View) ) { return new Param(value, column); } @@ -29,10 +34,7 @@ export interface BinaryOperator { left: TColumn, right: GetColumnData | SQLWrapper, ): SQL; - ( - left: SQL.Aliased, - right: T | SQLWrapper, - ): SQL; + (left: SQL.Aliased, right: T | SQLWrapper): SQL; ( left: Exclude, right: unknown, @@ -100,8 +102,12 @@ export const ne: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => { * ``` */ export function and(...conditions: (SQLWrapper | undefined)[]): SQL | undefined; -export function and(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | undefined { - const conditions = unfilteredConditions.filter((c): c is Exclude => c !== undefined); +export function and( + ...unfilteredConditions: (SQLWrapper | undefined)[] +): SQL | undefined { + const conditions = unfilteredConditions.filter( + (c): c is Exclude => c !== undefined, + ); if (conditions.length === 0) { return undefined; @@ -111,7 +117,11 @@ export function and(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | return new SQL(conditions); } - return new SQL([new StringChunk('('), sql.join(conditions, new StringChunk(' and ')), new StringChunk(')')]); + return new SQL([ + new StringChunk('('), + sql.join(conditions, new StringChunk(' and ')), + new StringChunk(')'), + ]); } /** @@ -131,8 +141,12 @@ export function and(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | * ``` */ export function or(...conditions: (SQLWrapper | undefined)[]): SQL | undefined; -export function or(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | undefined { - const conditions = unfilteredConditions.filter((c): c is Exclude => c !== undefined); +export function or( + ...unfilteredConditions: (SQLWrapper | undefined)[] +): SQL | undefined { + const conditions = unfilteredConditions.filter( + (c): c is Exclude => c !== undefined, + ); if (conditions.length === 0) { return undefined; @@ -142,7 +156,11 @@ export function or(...unfilteredConditions: (SQLWrapper | undefined)[]): SQL | u return new SQL(conditions); } - return new SQL([new StringChunk('('), sql.join(conditions, new StringChunk(' or ')), new StringChunk(')')]); + return new SQL([ + new StringChunk('('), + sql.join(conditions, new StringChunk(' or ')), + new StringChunk(')'), + ]); } /** @@ -240,7 +258,7 @@ export const lte: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => { * * ## Throws * - * The argument passed in the second array can’t be empty: + * The argument passed in the second array can't be empty: * if an empty is provided, this method will throw. * * ## Examples @@ -286,7 +304,7 @@ export function inArray( * * ## Throws * - * The argument passed in the second array can’t be empty: + * The argument passed in the second array can't be empty: * if an empty is provided, this method will throw. * * ## Examples @@ -315,13 +333,9 @@ export function notInArray( column: SQLWrapper, values: (unknown | Placeholder)[] | SQLWrapper, ): SQL { - if (isSQLWrapper(values)) { - return sql`${column} not in ${values}`; - } - if (Array.isArray(values)) { if (values.length === 0) { - throw new Error('inArray requires at least one value'); + throw new Error('notInArray requires at least one value'); } return sql`${column} not in ${values.map((v) => bindIfParam(v, column))}`; } @@ -452,12 +466,13 @@ export function between( min: unknown, max: unknown, ): SQL; -export function between( - column: SQLWrapper, - min: unknown, - max: unknown, -): SQL { - return sql`${column} between ${bindIfParam(min, column)} and ${bindIfParam(max, column)}`; +export function between(column: SQLWrapper, min: unknown, max: unknown): SQL { + return sql`${column} between ${bindIfParam(min, column)} and ${ + bindIfParam( + max, + column, + ) + }`; } /** @@ -497,7 +512,12 @@ export function notBetween( min: unknown, max: unknown, ): SQL { - return sql`${column} not between ${bindIfParam(min, column)} and ${bindIfParam(max, column)}`; + return sql`${column} not between ${ + bindIfParam( + min, + column, + ) + } and ${bindIfParam(max, column)}`; } /** @@ -586,3 +606,145 @@ export function ilike(column: Column, value: string | SQLWrapper): SQL { export function notIlike(column: Column, value: string | SQLWrapper): SQL { return sql`${column} not ilike ${value}`; } + +/** + * Test that a column or expression contains all elements of + * the list passed as the second argument. + * + * ## Throws + * + * The argument passed in the second array can't be empty: + * if an empty is provided, this method will throw. + * + * ## Examples + * + * ```ts + * // Select posts where its tags contain "Typescript" and "ORM". + * db.select().from(posts) + * .where(arrayContains(posts.tags, ['Typescript', 'ORM'])) + * ``` + * + * @see arrayContained to find if an array contains all elements of a column or expression + * @see arrayOverlaps to find if a column or expression contains any elements of an array + */ +export function arrayContains( + column: SQL.Aliased, + values: (T | Placeholder) | SQLWrapper, +): SQL; +export function arrayContains( + column: TColumn, + values: (GetColumnData | Placeholder) | SQLWrapper, +): SQL; +export function arrayContains( + column: Exclude, + values: (unknown | Placeholder)[] | SQLWrapper, +): SQL; +export function arrayContains( + column: SQLWrapper, + values: (unknown | Placeholder)[] | SQLWrapper, +): SQL { + if (Array.isArray(values)) { + if (values.length === 0) { + throw new Error('arrayContains requires at least one value'); + } + const array = sql`${bindIfParam(values, column)}`; + return sql`${column} @> ${array}`; + } + + return sql`${column} @> ${bindIfParam(values, column)}`; +} + +/** + * Test that the list passed as the second argument contains + * all elements of a column or expression. + * + * ## Throws + * + * The argument passed in the second array can't be empty: + * if an empty is provided, this method will throw. + * + * ## Examples + * + * ```ts + * // Select posts where its tags contain "Typescript", "ORM" or both, + * // but filtering posts that have additional tags. + * db.select().from(posts) + * .where(arrayContained(posts.tags, ['Typescript', 'ORM'])) + * ``` + * + * @see arrayContains to find if a column or expression contains all elements of an array + * @see arrayOverlaps to find if a column or expression contains any elements of an array + */ +export function arrayContained( + column: SQL.Aliased, + values: (T | Placeholder) | SQLWrapper, +): SQL; +export function arrayContained( + column: TColumn, + values: (GetColumnData | Placeholder) | SQLWrapper, +): SQL; +export function arrayContained( + column: Exclude, + values: (unknown | Placeholder)[] | SQLWrapper, +): SQL; +export function arrayContained( + column: SQLWrapper, + values: (unknown | Placeholder)[] | SQLWrapper, +): SQL { + if (Array.isArray(values)) { + if (values.length === 0) { + throw new Error('arrayContained requires at least one value'); + } + const array = sql`${bindIfParam(values, column)}`; + return sql`${column} <@ ${array}`; + } + + return sql`${column} <@ ${bindIfParam(values, column)}`; +} + +/** + * Test that a column or expression contains any elements of + * the list passed as the second argument. + * + * ## Throws + * + * The argument passed in the second array can't be empty: + * if an empty is provided, this method will throw. + * + * ## Examples + * + * ```ts + * // Select posts where its tags contain "Typescript", "ORM" or both. + * db.select().from(posts) + * .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])) + * ``` + * + * @see arrayContains to find if a column or expression contains all elements of an array + * @see arrayContained to find if an array contains all elements of a column or expression + */ +export function arrayOverlaps( + column: SQL.Aliased, + values: (T | Placeholder) | SQLWrapper, +): SQL; +export function arrayOverlaps( + column: TColumn, + values: (GetColumnData | Placeholder) | SQLWrapper, +): SQL; +export function arrayOverlaps( + column: Exclude, + values: (unknown | Placeholder)[] | SQLWrapper, +): SQL; +export function arrayOverlaps( + column: SQLWrapper, + values: (unknown | Placeholder)[] | SQLWrapper, +): SQL { + if (Array.isArray(values)) { + if (values.length === 0) { + throw new Error('arrayOverlaps requires at least one value'); + } + const array = sql`${bindIfParam(values, column)}`; + return sql`${column} && ${array}`; + } + + return sql`${column} && ${bindIfParam(values, column)}`; +} diff --git a/drizzle-orm/src/sql/expressions/select.ts b/drizzle-orm/src/sql/expressions/select.ts index 4308454cd..2ff8de346 100644 --- a/drizzle-orm/src/sql/expressions/select.ts +++ b/drizzle-orm/src/sql/expressions/select.ts @@ -1,6 +1,6 @@ import type { AnyColumn } from '../../column.ts'; -import type { SQL, SQLWrapper } from '../index.ts'; -import { sql } from '../index.ts'; +import type { SQL, SQLWrapper } from '../sql.ts'; +import { sql } from '../sql.ts'; /** * Used in sorting, this specifies that the given diff --git a/drizzle-orm/src/sql/index.ts b/drizzle-orm/src/sql/index.ts index 2563ce466..ec7f9ed76 100644 --- a/drizzle-orm/src/sql/index.ts +++ b/drizzle-orm/src/sql/index.ts @@ -1,580 +1,2 @@ -import { entityKind, is } from '~/entity.ts'; -import { Relation } from '~/relations.ts'; -import { Subquery, SubqueryConfig } from '~/subquery.ts'; -import { tracer } from '~/tracing.ts'; -import { View, ViewBaseConfig } from '~/view.ts'; -import type { AnyColumn } from '../column.ts'; -import { Column } from '../column.ts'; -import { Table } from '../table.ts'; - export * from './expressions/index.ts'; - -/** - * This class is used to indicate a primitive param value that is used in `sql` tag. - * It is only used on type level and is never instantiated at runtime. - * If you see a value of this type in the code, its runtime value is actually the primitive param value. - */ -export class FakePrimitiveParam { - static readonly [entityKind]: string = 'FakePrimitiveParam'; -} - -export type Chunk = - | string - | Table - | View - | AnyColumn - | Name - | Param - | Placeholder - | SQL; - -export interface BuildQueryConfig { - escapeName(name: string): string; - escapeParam(num: number, value: unknown): string; - escapeString(str: string): string; - prepareTyping?: (encoder: DriverValueEncoder) => QueryTypingsValue; - paramStartIndex?: { value: number }; - inlineParams?: boolean; -} - -export type QueryTypingsValue = 'json' | 'decimal' | 'time' | 'timestamp' | 'uuid' | 'date' | 'none'; - -export interface Query { - sql: string; - params: unknown[]; - typings?: QueryTypingsValue[]; -} - -/** - * Any value that implements the `getSQL` method. The implementations include: - * - `Table` - * - `Column` - * - `View` - * - `Subquery` - * - `SQL` - * - `SQL.Aliased` - * - `Placeholder` - * - `Param` - */ -export interface SQLWrapper { - getSQL(): SQL; -} - -export function isSQLWrapper(value: unknown): value is SQLWrapper { - return typeof value === 'object' && value !== null && 'getSQL' in value - && typeof (value as any).getSQL === 'function'; -} - -function mergeQueries(queries: Query[]): Query { - const result: Query = { sql: '', params: [] }; - for (const query of queries) { - result.sql += query.sql; - result.params.push(...query.params); - if (query.typings?.length) { - result.typings = result.typings || []; - result.typings.push(...query.typings); - } - } - return result; -} - -export class StringChunk implements SQLWrapper { - static readonly [entityKind]: string = 'StringChunk'; - - readonly value: string[]; - - constructor(value: string | string[]) { - this.value = Array.isArray(value) ? value : [value]; - } - - getSQL(): SQL { - return new SQL([this]); - } -} - -export class SQL implements SQLWrapper { - static readonly [entityKind]: string = 'SQL'; - - declare _: { - brand: 'SQL'; - type: T; - }; - - /** @internal */ - decoder: DriverValueDecoder = noopDecoder; - private shouldInlineParams = false; - - constructor(readonly queryChunks: SQLChunk[]) {} - - append(query: SQL): this { - this.queryChunks.push(...query.queryChunks); - return this; - } - - toQuery(config: BuildQueryConfig): Query { - return tracer.startActiveSpan('drizzle.buildSQL', (span) => { - const query = this.buildQueryFromSourceParams(this.queryChunks, config); - span?.setAttributes({ - 'drizzle.query.text': query.sql, - 'drizzle.query.params': JSON.stringify(query.params), - }); - return query; - }); - } - - buildQueryFromSourceParams(chunks: SQLChunk[], _config: BuildQueryConfig): Query { - const config = Object.assign({}, _config, { - inlineParams: _config.inlineParams || this.shouldInlineParams, - paramStartIndex: _config.paramStartIndex || { value: 0 }, - }); - - const { - escapeName, - escapeParam, - prepareTyping, - inlineParams, - paramStartIndex, - } = config; - - return mergeQueries(chunks.map((chunk): Query => { - if (is(chunk, StringChunk)) { - return { sql: chunk.value.join(''), params: [] }; - } - - if (is(chunk, Name)) { - return { sql: escapeName(chunk.value), params: [] }; - } - - if (chunk === undefined) { - return { sql: '', params: [] }; - } - - if (Array.isArray(chunk)) { - const result: SQLChunk[] = [new StringChunk('(')]; - for (const [i, p] of chunk.entries()) { - result.push(p); - if (i < chunk.length - 1) { - result.push(new StringChunk(', ')); - } - } - result.push(new StringChunk(')')); - return this.buildQueryFromSourceParams(result, config); - } - - if (is(chunk, SQL)) { - return this.buildQueryFromSourceParams(chunk.queryChunks, { - ...config, - inlineParams: inlineParams || chunk.shouldInlineParams, - }); - } - - if (is(chunk, Table)) { - const schemaName = chunk[Table.Symbol.Schema]; - const tableName = chunk[Table.Symbol.Name]; - return { - sql: schemaName === undefined - ? escapeName(tableName) - : escapeName(schemaName) + '.' + escapeName(tableName), - params: [], - }; - } - - if (is(chunk, Column)) { - return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(chunk.name), params: [] }; - } - - if (is(chunk, View)) { - const schemaName = chunk[ViewBaseConfig].schema; - const viewName = chunk[ViewBaseConfig].name; - return { - sql: schemaName === undefined - ? escapeName(viewName) - : escapeName(schemaName) + '.' + escapeName(viewName), - params: [], - }; - } - - if (is(chunk, Param)) { - const mappedValue = (chunk.value === null) ? null : chunk.encoder.mapToDriverValue(chunk.value); - - if (is(mappedValue, SQL)) { - return this.buildQueryFromSourceParams([mappedValue], config); - } - - if (inlineParams) { - return { sql: this.mapInlineParam(mappedValue, config), params: [] }; - } - - let typings: QueryTypingsValue[] | undefined; - if (prepareTyping !== undefined) { - typings = [prepareTyping(chunk.encoder)]; - } - - return { sql: escapeParam(paramStartIndex.value++, mappedValue), params: [mappedValue], typings }; - } - - if (is(chunk, Placeholder)) { - return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk] }; - } - - if (is(chunk, SQL.Aliased) && chunk.fieldAlias !== undefined) { - return { sql: escapeName(chunk.fieldAlias), params: [] }; - } - - if (is(chunk, Subquery)) { - if (chunk[SubqueryConfig].isWith) { - return { sql: escapeName(chunk[SubqueryConfig].alias), params: [] }; - } - return this.buildQueryFromSourceParams([ - new StringChunk('('), - chunk[SubqueryConfig].sql, - new StringChunk(') '), - new Name(chunk[SubqueryConfig].alias), - ], config); - } - - // if (is(chunk, Placeholder)) { - // return {sql: escapeParam} - - if (isSQLWrapper(chunk)) { - return this.buildQueryFromSourceParams([ - new StringChunk('('), - chunk.getSQL(), - new StringChunk(')'), - ], config); - } - - if (is(chunk, Relation)) { - return this.buildQueryFromSourceParams([ - chunk.sourceTable, - new StringChunk('.'), - sql.identifier(chunk.fieldName), - ], config); - } - - if (inlineParams) { - return { sql: this.mapInlineParam(chunk, config), params: [] }; - } - - return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk] }; - })); - } - - private mapInlineParam( - chunk: unknown, - { escapeString }: BuildQueryConfig, - ): string { - if (chunk === null) { - return 'null'; - } - if (typeof chunk === 'number' || typeof chunk === 'boolean') { - return chunk.toString(); - } - if (typeof chunk === 'string') { - return escapeString(chunk); - } - if (typeof chunk === 'object') { - const mappedValueAsString = chunk.toString(); - if (mappedValueAsString === '[object Object]') { - return escapeString(JSON.stringify(chunk)); - } - return escapeString(mappedValueAsString); - } - throw new Error('Unexpected param value: ' + chunk); - } - - getSQL(): SQL { - return this; - } - - as(alias: string): SQL.Aliased; - /** - * @deprecated - * Use ``sql`query`.as(alias)`` instead. - */ - as(): SQL; - /** - * @deprecated - * Use ``sql`query`.as(alias)`` instead. - */ - as(alias: string): SQL.Aliased; - as(alias?: string): SQL | SQL.Aliased { - // TODO: remove with deprecated overloads - if (alias === undefined) { - return this; - } - - return new SQL.Aliased(this, alias); - } - - mapWith< - TDecoder extends - | DriverValueDecoder - | DriverValueDecoder['mapFromDriverValue'], - >(decoder: TDecoder): SQL> { - this.decoder = typeof decoder === 'function' ? { mapFromDriverValue: decoder } : decoder; - return this as SQL>; - } - - inlineParams(): this { - this.shouldInlineParams = true; - return this; - } -} - -export type GetDecoderResult = T extends Column ? T['_']['data'] : T extends - | DriverValueDecoder - | DriverValueDecoder['mapFromDriverValue'] ? TData -: never; - -/** - * Any DB name (table, column, index etc.) - */ -export class Name implements SQLWrapper { - static readonly [entityKind]: string = 'Name'; - - protected brand!: 'Name'; - - constructor(readonly value: string) {} - - getSQL(): SQL { - return new SQL([this]); - } -} - -/** - * Any DB name (table, column, index etc.) - * @deprecated Use `sql.identifier` instead. - */ -export function name(value: string): Name { - return new Name(value); -} - -export interface DriverValueDecoder { - mapFromDriverValue(value: TDriverParam): TData; -} - -export interface DriverValueEncoder { - mapToDriverValue(value: TData): TDriverParam | SQL; -} - -export function isDriverValueEncoder(value: unknown): value is DriverValueEncoder { - return typeof value === 'object' && value !== null && 'mapToDriverValue' in value - && typeof (value as any).mapToDriverValue === 'function'; -} - -export const noopDecoder: DriverValueDecoder = { - mapFromDriverValue: (value) => value, -}; - -export const noopEncoder: DriverValueEncoder = { - mapToDriverValue: (value) => value, -}; - -export interface DriverValueMapper - extends DriverValueDecoder, DriverValueEncoder -{} - -export const noopMapper: DriverValueMapper = { - ...noopDecoder, - ...noopEncoder, -}; - -/** Parameter value that is optionally bound to an encoder (for example, a column). */ -export class Param implements SQLWrapper { - static readonly [entityKind]: string = 'Param'; - - protected brand!: 'BoundParamValue'; - - /** - * @param value - Parameter value - * @param encoder - Encoder to convert the value to a driver parameter - */ - constructor( - readonly value: TDataType, - readonly encoder: DriverValueEncoder = noopEncoder, - ) {} - - getSQL(): SQL { - return new SQL([this]); - } -} - -/** @deprecated Use `sql.param` instead. */ -export function param( - value: TData, - encoder?: DriverValueEncoder, -): Param { - return new Param(value, encoder); -} - -/** - * Anything that can be passed to the `` sql`...` `` tagged function. - */ -export type SQLChunk = - | StringChunk - | SQLChunk[] - | SQLWrapper - | SQL - | Table - | View - | Subquery - | AnyColumn - | Param - | Name - | undefined - | FakePrimitiveParam - | Placeholder; - -export function sql(strings: TemplateStringsArray, ...params: any[]): SQL; -/* - The type of `params` is specified as `SQLSourceParam[]`, but that's slightly incorrect - - in runtime, users won't pass `FakePrimitiveParam` instances as `params` - they will pass primitive values - which will be wrapped in `Param` using `buildChunksFromParam(...)`. That's why the overload - specify `params` as `any[]` and not as `SQLSourceParam[]`. This type is used to make our lives easier and - the type checker happy. -*/ -export function sql(strings: TemplateStringsArray, ...params: SQLChunk[]): SQL { - const queryChunks: SQLChunk[] = []; - if (params.length > 0 || (strings.length > 0 && strings[0] !== '')) { - queryChunks.push(new StringChunk(strings[0]!)); - } - for (const [paramIndex, param] of params.entries()) { - queryChunks.push(param, new StringChunk(strings[paramIndex + 1]!)); - } - - return new SQL(queryChunks); -} - -export namespace sql { - export function empty(): SQL { - return new SQL([]); - } - - /** @deprecated - use `sql.join()` */ - export function fromList(list: SQLChunk[]): SQL { - return new SQL(list); - } - - /** - * Convenience function to create an SQL query from a raw string. - * @param str The raw SQL query string. - */ - export function raw(str: string): SQL { - return new SQL([new StringChunk(str)]); - } - - /** - * Join a list of SQL chunks with a separator. - * @example - * ```ts - * const query = sql.join([sql`a`, sql`b`, sql`c`]); - * // sql`abc` - * ``` - * @example - * ```ts - * const query = sql.join([sql`a`, sql`b`, sql`c`], sql`, `); - * // sql`a, b, c` - * ``` - */ - export function join(chunks: SQLChunk[], separator?: SQLChunk): SQL { - const result: SQLChunk[] = []; - for (const [i, chunk] of chunks.entries()) { - if (i > 0 && separator !== undefined) { - result.push(separator); - } - result.push(chunk); - } - return new SQL(result); - } - - /** - * Create a SQL chunk that represents a DB identifier (table, column, index etc.). - * When used in a query, the identifier will be escaped based on the DB engine. - * For example, in PostgreSQL, identifiers are escaped with double quotes. - * - * **WARNING: This function does not offer any protection against SQL injections, so you must validate any user input beforehand.** - * - * @example ```ts - * const query = sql`SELECT * FROM ${sql.identifier('my-table')}`; - * // 'SELECT * FROM "my-table"' - * ``` - */ - export function identifier(value: string): Name { - return new Name(value); - } - - export function placeholder(name: TName): Placeholder { - return new Placeholder(name); - } - - export function param( - value: TData, - encoder?: DriverValueEncoder, - ): Param { - return new Param(value, encoder); - } -} - -export namespace SQL { - export class Aliased implements SQLWrapper { - static readonly [entityKind]: string = 'SQL.Aliased'; - - declare _: { - brand: 'SQL.Aliased'; - type: T; - }; - - /** @internal */ - isSelectionField = false; - - constructor( - readonly sql: SQL, - readonly fieldAlias: string, - ) {} - - getSQL(): SQL { - return this.sql; - } - - /** @internal */ - clone() { - return new Aliased(this.sql, this.fieldAlias); - } - } -} - -export class Placeholder implements SQLWrapper { - static readonly [entityKind]: string = 'Placeholder'; - - declare protected: TValue; - - constructor(readonly name: TName) {} - - getSQL(): SQL { - return new SQL([this]); - } -} - -/** @deprecated Use `sql.placeholder` instead. */ -export function placeholder(name: TName): Placeholder { - return new Placeholder(name); -} - -export function fillPlaceholders(params: unknown[], values: Record): unknown[] { - return params.map((p) => { - if (is(p, Placeholder)) { - if (!(p.name in values)) { - throw new Error(`No value for placeholder "${p.name}" was provided`); - } - return values[p.name]; - } - - return p; - }); -} - -// Defined separately from the Column class to resolve circular dependency -Column.prototype.getSQL = function() { - return new SQL([this]); -}; +export * from './sql.ts'; diff --git a/drizzle-orm/src/sql/sql.ts b/drizzle-orm/src/sql/sql.ts new file mode 100644 index 000000000..a40eb079d --- /dev/null +++ b/drizzle-orm/src/sql/sql.ts @@ -0,0 +1,646 @@ +import { entityKind, is } from '~/entity.ts'; +import { Relation } from '~/relations.ts'; +import { Subquery, SubqueryConfig } from '~/subquery.ts'; +import { tracer } from '~/tracing.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import type { AnyColumn } from '../column.ts'; +import { Column } from '../column.ts'; +import { Table } from '../table.ts'; +import type { SelectedFields } from '~/operations.ts'; + +/** + * This class is used to indicate a primitive param value that is used in `sql` tag. + * It is only used on type level and is never instantiated at runtime. + * If you see a value of this type in the code, its runtime value is actually the primitive param value. + */ +export class FakePrimitiveParam { + static readonly [entityKind]: string = 'FakePrimitiveParam'; +} + +export type Chunk = + | string + | Table + | View + | AnyColumn + | Name + | Param + | Placeholder + | SQL; + +export interface BuildQueryConfig { + escapeName(name: string): string; + escapeParam(num: number, value: unknown): string; + escapeString(str: string): string; + prepareTyping?: (encoder: DriverValueEncoder) => QueryTypingsValue; + paramStartIndex?: { value: number }; + inlineParams?: boolean; +} + +export type QueryTypingsValue = 'json' | 'decimal' | 'time' | 'timestamp' | 'uuid' | 'date' | 'none'; + +export interface Query { + sql: string; + params: unknown[]; +} + +export interface QueryWithTypings extends Query { + typings?: QueryTypingsValue[]; +} + +/** + * Any value that implements the `getSQL` method. The implementations include: + * - `Table` + * - `Column` + * - `View` + * - `Subquery` + * - `SQL` + * - `SQL.Aliased` + * - `Placeholder` + * - `Param` + */ +export interface SQLWrapper { + getSQL(): SQL; +} + +export function isSQLWrapper(value: unknown): value is SQLWrapper { + return typeof value === 'object' && value !== null && 'getSQL' in value + && typeof (value as any).getSQL === 'function'; +} + +function mergeQueries(queries: QueryWithTypings[]): QueryWithTypings { + const result: QueryWithTypings = { sql: '', params: [] }; + for (const query of queries) { + result.sql += query.sql; + result.params.push(...query.params); + if (query.typings?.length) { + if (!result.typings) { + result.typings = []; + } + result.typings.push(...query.typings); + } + } + return result; +} + +export class StringChunk implements SQLWrapper { + static readonly [entityKind]: string = 'StringChunk'; + + readonly value: string[]; + + constructor(value: string | string[]) { + this.value = Array.isArray(value) ? value : [value]; + } + + getSQL(): SQL { + return new SQL([this]); + } +} + +export class SQL implements SQLWrapper { + static readonly [entityKind]: string = 'SQL'; + + declare _: { + brand: 'SQL'; + type: T; + }; + + /** @internal */ + decoder: DriverValueDecoder = noopDecoder; + private shouldInlineParams = false; + + constructor(readonly queryChunks: SQLChunk[]) {} + + append(query: SQL): this { + this.queryChunks.push(...query.queryChunks); + return this; + } + + toQuery(config: BuildQueryConfig): QueryWithTypings { + return tracer.startActiveSpan('drizzle.buildSQL', (span) => { + const query = this.buildQueryFromSourceParams(this.queryChunks, config); + span?.setAttributes({ + 'drizzle.query.text': query.sql, + 'drizzle.query.params': JSON.stringify(query.params), + }); + return query; + }); + } + + buildQueryFromSourceParams(chunks: SQLChunk[], _config: BuildQueryConfig): Query { + const config = Object.assign({}, _config, { + inlineParams: _config.inlineParams || this.shouldInlineParams, + paramStartIndex: _config.paramStartIndex || { value: 0 }, + }); + + const { + escapeName, + escapeParam, + prepareTyping, + inlineParams, + paramStartIndex, + } = config; + + return mergeQueries(chunks.map((chunk): QueryWithTypings => { + if (is(chunk, StringChunk)) { + return { sql: chunk.value.join(''), params: [] }; + } + + if (is(chunk, Name)) { + return { sql: escapeName(chunk.value), params: [] }; + } + + if (chunk === undefined) { + return { sql: '', params: [] }; + } + + if (Array.isArray(chunk)) { + const result: SQLChunk[] = [new StringChunk('(')]; + for (const [i, p] of chunk.entries()) { + result.push(p); + if (i < chunk.length - 1) { + result.push(new StringChunk(', ')); + } + } + result.push(new StringChunk(')')); + return this.buildQueryFromSourceParams(result, config); + } + + if (is(chunk, SQL)) { + return this.buildQueryFromSourceParams(chunk.queryChunks, { + ...config, + inlineParams: inlineParams || chunk.shouldInlineParams, + }); + } + + if (is(chunk, Table)) { + const schemaName = chunk[Table.Symbol.Schema]; + const tableName = chunk[Table.Symbol.Name]; + return { + sql: schemaName === undefined + ? escapeName(tableName) + : escapeName(schemaName) + '.' + escapeName(tableName), + params: [], + }; + } + + if (is(chunk, Column)) { + return { sql: escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(chunk.name), params: [] }; + } + + if (is(chunk, View)) { + const schemaName = chunk[ViewBaseConfig].schema; + const viewName = chunk[ViewBaseConfig].name; + return { + sql: schemaName === undefined + ? escapeName(viewName) + : escapeName(schemaName) + '.' + escapeName(viewName), + params: [], + }; + } + + if (is(chunk, Param)) { + const mappedValue = (chunk.value === null) ? null : chunk.encoder.mapToDriverValue(chunk.value); + + if (is(mappedValue, SQL)) { + return this.buildQueryFromSourceParams([mappedValue], config); + } + + if (inlineParams) { + return { sql: this.mapInlineParam(mappedValue, config), params: [] }; + } + + let typings: QueryTypingsValue[] | undefined; + if (prepareTyping !== undefined) { + typings = [prepareTyping(chunk.encoder)]; + } + + return { sql: escapeParam(paramStartIndex.value++, mappedValue), params: [mappedValue], typings }; + } + + if (is(chunk, Placeholder)) { + return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk] }; + } + + if (is(chunk, SQL.Aliased) && chunk.fieldAlias !== undefined) { + return { sql: escapeName(chunk.fieldAlias), params: [] }; + } + + if (is(chunk, Subquery)) { + if (chunk[SubqueryConfig].isWith) { + return { sql: escapeName(chunk[SubqueryConfig].alias), params: [] }; + } + return this.buildQueryFromSourceParams([ + new StringChunk('('), + chunk[SubqueryConfig].sql, + new StringChunk(') '), + new Name(chunk[SubqueryConfig].alias), + ], config); + } + + // if (is(chunk, Placeholder)) { + // return {sql: escapeParam} + + if (isSQLWrapper(chunk)) { + return this.buildQueryFromSourceParams([ + new StringChunk('('), + chunk.getSQL(), + new StringChunk(')'), + ], config); + } + + if (is(chunk, Relation)) { + return this.buildQueryFromSourceParams([ + chunk.sourceTable, + new StringChunk('.'), + sql.identifier(chunk.fieldName), + ], config); + } + + if (inlineParams) { + return { sql: this.mapInlineParam(chunk, config), params: [] }; + } + + return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk] }; + })); + } + + private mapInlineParam( + chunk: unknown, + { escapeString }: BuildQueryConfig, + ): string { + if (chunk === null) { + return 'null'; + } + if (typeof chunk === 'number' || typeof chunk === 'boolean') { + return chunk.toString(); + } + if (typeof chunk === 'string') { + return escapeString(chunk); + } + if (typeof chunk === 'object') { + const mappedValueAsString = chunk.toString(); + if (mappedValueAsString === '[object Object]') { + return escapeString(JSON.stringify(chunk)); + } + return escapeString(mappedValueAsString); + } + throw new Error('Unexpected param value: ' + chunk); + } + + getSQL(): SQL { + return this; + } + + as(alias: string): SQL.Aliased; + /** + * @deprecated + * Use ``sql`query`.as(alias)`` instead. + */ + as(): SQL; + /** + * @deprecated + * Use ``sql`query`.as(alias)`` instead. + */ + as(alias: string): SQL.Aliased; + as(alias?: string): SQL | SQL.Aliased { + // TODO: remove with deprecated overloads + if (alias === undefined) { + return this; + } + + return new SQL.Aliased(this, alias); + } + + mapWith< + TDecoder extends + | DriverValueDecoder + | DriverValueDecoder['mapFromDriverValue'], + >(decoder: TDecoder): SQL> { + this.decoder = typeof decoder === 'function' ? { mapFromDriverValue: decoder } : decoder; + return this as SQL>; + } + + inlineParams(): this { + this.shouldInlineParams = true; + return this; + } +} + +export type GetDecoderResult = T extends Column ? T['_']['data'] : T extends + | DriverValueDecoder + | DriverValueDecoder['mapFromDriverValue'] ? TData +: never; + +/** + * Any DB name (table, column, index etc.) + */ +export class Name implements SQLWrapper { + static readonly [entityKind]: string = 'Name'; + + protected brand!: 'Name'; + + constructor(readonly value: string) {} + + getSQL(): SQL { + return new SQL([this]); + } +} + +/** + * Any DB name (table, column, index etc.) + * @deprecated Use `sql.identifier` instead. + */ +export function name(value: string): Name { + return new Name(value); +} + +export interface DriverValueDecoder { + mapFromDriverValue(value: TDriverParam): TData; +} + +export interface DriverValueEncoder { + mapToDriverValue(value: TData): TDriverParam | SQL; +} + +export function isDriverValueEncoder(value: unknown): value is DriverValueEncoder { + return typeof value === 'object' && value !== null && 'mapToDriverValue' in value + && typeof (value as any).mapToDriverValue === 'function'; +} + +export const noopDecoder: DriverValueDecoder = { + mapFromDriverValue: (value) => value, +}; + +export const noopEncoder: DriverValueEncoder = { + mapToDriverValue: (value) => value, +}; + +export interface DriverValueMapper + extends DriverValueDecoder, DriverValueEncoder +{} + +export const noopMapper: DriverValueMapper = { + ...noopDecoder, + ...noopEncoder, +}; + +/** Parameter value that is optionally bound to an encoder (for example, a column). */ +export class Param implements SQLWrapper { + static readonly [entityKind]: string = 'Param'; + + protected brand!: 'BoundParamValue'; + + /** + * @param value - Parameter value + * @param encoder - Encoder to convert the value to a driver parameter + */ + constructor( + readonly value: TDataType, + readonly encoder: DriverValueEncoder = noopEncoder, + ) {} + + getSQL(): SQL { + return new SQL([this]); + } +} + +/** @deprecated Use `sql.param` instead. */ +export function param( + value: TData, + encoder?: DriverValueEncoder, +): Param { + return new Param(value, encoder); +} + +/** + * Anything that can be passed to the `` sql`...` `` tagged function. + */ +export type SQLChunk = + | StringChunk + | SQLChunk[] + | SQLWrapper + | SQL + | Table + | View + | Subquery + | AnyColumn + | Param + | Name + | undefined + | FakePrimitiveParam + | Placeholder; + +export function sql(strings: TemplateStringsArray, ...params: any[]): SQL; +/* + The type of `params` is specified as `SQLSourceParam[]`, but that's slightly incorrect - + in runtime, users won't pass `FakePrimitiveParam` instances as `params` - they will pass primitive values + which will be wrapped in `Param` using `buildChunksFromParam(...)`. That's why the overload + specify `params` as `any[]` and not as `SQLSourceParam[]`. This type is used to make our lives easier and + the type checker happy. +*/ +export function sql(strings: TemplateStringsArray, ...params: SQLChunk[]): SQL { + const queryChunks: SQLChunk[] = []; + if (params.length > 0 || (strings.length > 0 && strings[0] !== '')) { + queryChunks.push(new StringChunk(strings[0]!)); + } + for (const [paramIndex, param] of params.entries()) { + queryChunks.push(param, new StringChunk(strings[paramIndex + 1]!)); + } + + return new SQL(queryChunks); +} + +export namespace sql { + export function empty(): SQL { + return new SQL([]); + } + + /** @deprecated - use `sql.join()` */ + export function fromList(list: SQLChunk[]): SQL { + return new SQL(list); + } + + /** + * Convenience function to create an SQL query from a raw string. + * @param str The raw SQL query string. + */ + export function raw(str: string): SQL { + return new SQL([new StringChunk(str)]); + } + + /** + * Join a list of SQL chunks with a separator. + * @example + * ```ts + * const query = sql.join([sql`a`, sql`b`, sql`c`]); + * // sql`abc` + * ``` + * @example + * ```ts + * const query = sql.join([sql`a`, sql`b`, sql`c`], sql`, `); + * // sql`a, b, c` + * ``` + */ + export function join(chunks: SQLChunk[], separator?: SQLChunk): SQL { + const result: SQLChunk[] = []; + for (const [i, chunk] of chunks.entries()) { + if (i > 0 && separator !== undefined) { + result.push(separator); + } + result.push(chunk); + } + return new SQL(result); + } + + /** + * Create a SQL chunk that represents a DB identifier (table, column, index etc.). + * When used in a query, the identifier will be escaped based on the DB engine. + * For example, in PostgreSQL, identifiers are escaped with double quotes. + * + * **WARNING: This function does not offer any protection against SQL injections, so you must validate any user input beforehand.** + * + * @example ```ts + * const query = sql`SELECT * FROM ${sql.identifier('my-table')}`; + * // 'SELECT * FROM "my-table"' + * ``` + */ + export function identifier(value: string): Name { + return new Name(value); + } + + export function placeholder(name: TName): Placeholder { + return new Placeholder(name); + } + + export function param( + value: TData, + encoder?: DriverValueEncoder, + ): Param { + return new Param(value, encoder); + } +} + +export namespace SQL { + export class Aliased implements SQLWrapper { + static readonly [entityKind]: string = 'SQL.Aliased'; + + declare _: { + brand: 'SQL.Aliased'; + type: T; + }; + + /** @internal */ + isSelectionField = false; + + constructor( + readonly sql: SQL, + readonly fieldAlias: string, + ) {} + + getSQL(): SQL { + return this.sql; + } + + /** @internal */ + clone() { + return new Aliased(this.sql, this.fieldAlias); + } + } +} + +export class Placeholder implements SQLWrapper { + static readonly [entityKind]: string = 'Placeholder'; + + declare protected: TValue; + + constructor(readonly name: TName) {} + + getSQL(): SQL { + return new SQL([this]); + } +} + +/** @deprecated Use `sql.placeholder` instead. */ +export function placeholder(name: TName): Placeholder { + return new Placeholder(name); +} + +export function fillPlaceholders(params: unknown[], values: Record): unknown[] { + return params.map((p) => { + if (is(p, Placeholder)) { + if (!(p.name in values)) { + throw new Error(`No value for placeholder "${p.name}" was provided`); + } + return values[p.name]; + } + + return p; + }); +} + +export type ColumnsSelection = Record; + +export abstract class View< + TName extends string = string, + TExisting extends boolean = boolean, + TSelection extends ColumnsSelection = ColumnsSelection, +> implements SQLWrapper { + static readonly [entityKind]: string = 'View'; + + declare _: { + brand: 'View'; + viewBrand: string; + name: TName; + existing: TExisting; + selectedFields: TSelection; + }; + + /** @internal */ + [ViewBaseConfig]: { + name: TName; + originalName: TName; + schema: string | undefined; + selectedFields: SelectedFields; + isExisting: TExisting; + query: TExisting extends true ? undefined : SQL; + isAlias: boolean; + }; + + constructor( + { name, schema, selectedFields, query }: { + name: TName; + schema: string | undefined; + selectedFields: SelectedFields; + query: SQL | undefined; + }, + ) { + this[ViewBaseConfig] = { + name, + originalName: name, + schema, + selectedFields, + query: query as (TExisting extends true ? undefined : SQL), + isExisting: !query as TExisting, + isAlias: false, + }; + } + + getSQL(): SQL { + return new SQL([this]); + } +} + +// Defined separately from the Column class to resolve circular dependency +Column.prototype.getSQL = function() { + return new SQL([this]); +}; + +// Defined separately from the Table class to resolve circular dependency +Table.prototype.getSQL = function() { + return new SQL([this]); +}; + +// Defined separately from the Column class to resolve circular dependency +Subquery.prototype.getSQL = function() { + return new SQL([this]); +}; \ No newline at end of file diff --git a/drizzle-orm/src/sqlite-core/alias.ts b/drizzle-orm/src/sqlite-core/alias.ts index 4fd9414ce..caf7ac9bb 100644 --- a/drizzle-orm/src/sqlite-core/alias.ts +++ b/drizzle-orm/src/sqlite-core/alias.ts @@ -1,8 +1,8 @@ import { TableAliasProxyHandler } from '~/alias.ts'; -import { type BuildAliasTable } from './query-builders/select.types.ts'; +import type { BuildAliasTable } from './query-builders/select.types.ts'; -import { type SQLiteTable } from './table.ts'; -import { type SQLiteViewBase } from './view.ts'; +import type { SQLiteTable } from './table.ts'; +import type { SQLiteViewBase } from './view-base.ts'; export function alias( table: TTable, diff --git a/drizzle-orm/src/sqlite-core/checks.ts b/drizzle-orm/src/sqlite-core/checks.ts index df992f7c5..8204a54f0 100644 --- a/drizzle-orm/src/sqlite-core/checks.ts +++ b/drizzle-orm/src/sqlite-core/checks.ts @@ -1,5 +1,5 @@ import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/index.ts'; +import type { SQL } from '~/sql/sql.ts'; import type { SQLiteTable } from './table.ts'; export class CheckBuilder { diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index e16ef9021..50a94c068 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import { type Equal } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; type BlobMode = 'buffer' | 'json' | 'bigint'; @@ -132,6 +132,12 @@ export interface BlobConfig { mode: TMode; } +/** + * It's recommended to use `text('...', { mode: 'json' })` instead of `blob` in JSON mode, because it supports JSON functions: + * >All JSON functions currently throw an error if any of their arguments are BLOBs because BLOBs are reserved for a future enhancement in which BLOBs will store the binary encoding for JSON. + * + * https://www.sqlite.org/json1.html + */ export function blob( name: TName, config?: BlobConfig, diff --git a/drizzle-orm/src/sqlite-core/columns/common.ts b/drizzle-orm/src/sqlite-core/columns/common.ts index 532f272a9..83a5e175d 100644 --- a/drizzle-orm/src/sqlite-core/columns/common.ts +++ b/drizzle-orm/src/sqlite-core/columns/common.ts @@ -13,7 +13,7 @@ import { entityKind } from '~/entity.ts'; import type { ForeignKey, UpdateDeleteAction } from '~/sqlite-core/foreign-keys.ts'; import { ForeignKeyBuilder } from '~/sqlite-core/foreign-keys.ts'; import type { AnySQLiteTable, SQLiteTable } from '~/sqlite-core/table.ts'; -import { type Update } from '~/utils.ts'; +import type { Update } from '~/utils.ts'; import { uniqueKeyName } from '../unique-constraint.ts'; export interface ReferenceConfig { diff --git a/drizzle-orm/src/sqlite-core/columns/custom.ts b/drizzle-orm/src/sqlite-core/columns/custom.ts index 7fc1ae47c..e8b765ffc 100644 --- a/drizzle-orm/src/sqlite-core/columns/custom.ts +++ b/drizzle-orm/src/sqlite-core/columns/custom.ts @@ -1,9 +1,9 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnConfig } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/index.ts'; +import type { SQL } from '~/sql/sql.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import { type Equal } from '~/utils.ts'; +import type { Equal } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; export type ConvertCustomConfig> = diff --git a/drizzle-orm/src/sqlite-core/columns/integer.ts b/drizzle-orm/src/sqlite-core/columns/integer.ts index 957f6fbdb..77f64069c 100644 --- a/drizzle-orm/src/sqlite-core/columns/integer.ts +++ b/drizzle-orm/src/sqlite-core/columns/integer.ts @@ -8,9 +8,9 @@ import type { } from '~/column-builder.ts'; import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { OnConflict } from '~/sqlite-core/utils.ts'; -import { type Equal, type Or } from '~/utils.ts'; +import type { Equal, Or } from '~/utils.ts'; import type { AnySQLiteTable } from '../table.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; diff --git a/drizzle-orm/src/sqlite-core/columns/text.ts b/drizzle-orm/src/sqlite-core/columns/text.ts index 2af26708e..4b1285259 100644 --- a/drizzle-orm/src/sqlite-core/columns/text.ts +++ b/drizzle-orm/src/sqlite-core/columns/text.ts @@ -2,7 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnySQLiteTable } from '~/sqlite-core/table.ts'; -import { type Writable } from '~/utils.ts'; +import type { Equal, Writable } from '~/utils.ts'; import { SQLiteColumn, SQLiteColumnBuilder } from './common.ts'; export type SQLiteTextBuilderInitial = SQLiteTextBuilder<{ @@ -20,7 +20,7 @@ export class SQLiteTextBuilder { static readonly [entityKind]: string = 'SQLiteTextBuilder'; - constructor(name: T['name'], config: SQLiteTextConfig) { + constructor(name: T['name'], config: SQLiteTextConfig<'text', T['enumValues']>) { super(name, 'string', 'SQLiteText'); this.config.enumValues = config.enum; this.config.length = config.length; @@ -55,14 +55,79 @@ export class SQLiteText> } } -export interface SQLiteTextConfig { - length?: number; - enum?: TEnum; +export type SQLiteTextJsonBuilderInitial = SQLiteTextJsonBuilder<{ + name: TName; + dataType: 'json'; + columnType: 'SQLiteTextJson'; + data: unknown; + driverParam: string; + enumValues: undefined; +}>; + +export class SQLiteTextJsonBuilder> + extends SQLiteColumnBuilder +{ + static readonly [entityKind]: string = 'SQLiteTextJsonBuilder'; + + constructor(name: T['name']) { + super(name, 'json', 'SQLiteTextJson'); + } + + /** @internal */ + override build( + table: AnySQLiteTable<{ name: TTableName }>, + ): SQLiteTextJson> { + return new SQLiteTextJson>( + table, + this.config as ColumnBuilderRuntimeConfig, + ); + } +} + +export class SQLiteTextJson> + extends SQLiteColumn +{ + static readonly [entityKind]: string = 'SQLiteTextJson'; + + getSQLType(): string { + return 'text'; + } + + override mapFromDriverValue(value: string): T['data'] { + return JSON.parse(value); + } + + override mapToDriverValue(value: T['data']): string { + return JSON.stringify(value); + } } -export function text>( +export type SQLiteTextConfig< + TMode extends 'text' | 'json', + TEnum extends readonly string[] | string[] | undefined, +> = TMode extends 'text' ? { + mode?: TMode; + length?: number; + enum?: TEnum; + } + : { + mode?: TMode; + }; + +export function text< + TName extends string, + U extends string, + T extends Readonly<[U, ...U[]]>, + TMode extends 'text' | 'json' = 'text' | 'json', +>( name: TName, - config: SQLiteTextConfig> = {}, -): SQLiteTextBuilderInitial> { - return new SQLiteTextBuilder(name, config); + config: SQLiteTextConfig> = {} as SQLiteTextConfig>, +): Equal extends true ? SQLiteTextJsonBuilderInitial + : SQLiteTextBuilderInitial> +{ + return (config.mode === 'json' + ? new SQLiteTextJsonBuilder(name) + : new SQLiteTextBuilder(name, config as SQLiteTextConfig<'text', Writable>)) as Equal extends true + ? SQLiteTextJsonBuilderInitial + : SQLiteTextBuilderInitial>; } diff --git a/drizzle-orm/src/sqlite-core/db.ts b/drizzle-orm/src/sqlite-core/db.ts index 57bbfc6eb..18594a3ba 100644 --- a/drizzle-orm/src/sqlite-core/db.ts +++ b/drizzle-orm/src/sqlite-core/db.ts @@ -1,27 +1,30 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; -import { - type ExtractTablesWithRelations, - type RelationalSchemaConfig, - type TablesRelationalConfig, -} from '~/relations.ts'; -import type { SQLWrapper } from '~/sql/index.ts'; +import type { ExtractTablesWithRelations, RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import type { ColumnsSelection, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { QueryBuilder, - SQLiteDelete, + SQLiteDeleteBase, SQLiteInsertBuilder, SQLiteSelectBuilder, SQLiteUpdateBuilder, } from '~/sqlite-core/query-builders/index.ts'; -import type { Result, SQLiteSession, SQLiteTransaction, SQLiteTransactionConfig } from '~/sqlite-core/session.ts'; +import type { + DBResult, + Result, + SQLiteSession, + SQLiteTransaction, + SQLiteTransactionConfig, +} from '~/sqlite-core/session.ts'; import type { SQLiteTable } from '~/sqlite-core/table.ts'; -import { SelectionProxyHandler, WithSubquery } from '~/subquery.ts'; -import { type DrizzleTypeError } from '~/utils.ts'; -import { type ColumnsSelection } from '~/view.ts'; +import { WithSubquery } from '~/subquery.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; import { RelationalQueryBuilder } from './query-builders/query.ts'; +import { SQLiteRaw } from './query-builders/raw.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import type { WithSubqueryWithSelection } from './subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export class BaseSQLiteDatabase< TResultKind extends 'sync' | 'async', @@ -43,7 +46,7 @@ export class BaseSQLiteDatabase< }; constructor( - resultKind: TResultKind, + private resultKind: TResultKind, /** @internal */ readonly dialect: { sync: SQLiteSyncDialect; async: SQLiteAsyncDialect }[TResultKind], /** @internal */ @@ -94,7 +97,9 @@ export class BaseSQLiteDatabase< function select( fields: TSelection, ): SQLiteSelectBuilder; - function select(fields?: SelectedFields): SQLiteSelectBuilder { + function select( + fields?: SelectedFields, + ): SQLiteSelectBuilder { return new SQLiteSelectBuilder({ fields: fields ?? undefined, session: self.session, @@ -134,7 +139,9 @@ export class BaseSQLiteDatabase< selectDistinct( fields: TSelection, ): SQLiteSelectBuilder; - selectDistinct(fields?: SelectedFields): SQLiteSelectBuilder { + selectDistinct( + fields?: SelectedFields, + ): SQLiteSelectBuilder { return new SQLiteSelectBuilder({ fields: fields ?? undefined, session: this.session, @@ -151,24 +158,64 @@ export class BaseSQLiteDatabase< return new SQLiteInsertBuilder(into, this.session, this.dialect); } - delete(from: TTable): SQLiteDelete { - return new SQLiteDelete(from, this.session, this.dialect); + delete(from: TTable): SQLiteDeleteBase { + return new SQLiteDeleteBase(from, this.session, this.dialect); } - run(query: SQLWrapper): Result { - return this.session.run(query.getSQL()); + run(query: SQLWrapper): DBResult { + const sql = query.getSQL(); + if (this.resultKind === 'async') { + return new SQLiteRaw( + async () => this.session.run(sql), + () => sql, + 'run', + this.dialect as SQLiteAsyncDialect, + this.session.extractRawRunValueFromBatchResult.bind(this.session), + ) as DBResult; + } + return this.session.run(sql) as DBResult; } - all(query: SQLWrapper): Result { - return this.session.all(query.getSQL()); + all(query: SQLWrapper): DBResult { + const sql = query.getSQL(); + if (this.resultKind === 'async') { + return new SQLiteRaw( + async () => this.session.all(sql), + () => sql, + 'all', + this.dialect as SQLiteAsyncDialect, + this.session.extractRawAllValueFromBatchResult.bind(this.session), + ) as any; + } + return this.session.all(sql) as DBResult; } - get(query: SQLWrapper): Result { - return this.session.get(query.getSQL()); + get(query: SQLWrapper): DBResult { + const sql = query.getSQL(); + if (this.resultKind === 'async') { + return new SQLiteRaw( + async () => this.session.get(sql), + () => sql, + 'get', + this.dialect as SQLiteAsyncDialect, + this.session.extractRawGetValueFromBatchResult.bind(this.session), + ) as DBResult; + } + return this.session.get(sql) as DBResult; } - values(query: SQLWrapper): Result { - return this.session.values(query.getSQL()); + values(query: SQLWrapper): DBResult { + const sql = query.getSQL(); + if (this.resultKind === 'async') { + return new SQLiteRaw( + async () => this.session.values(sql), + () => sql, + 'values', + this.dialect as SQLiteAsyncDialect, + this.session.extractRawValuesValueFromBatchResult.bind(this.session), + ) as any; + } + return this.session.values(sql) as DBResult; } transaction( @@ -178,3 +225,61 @@ export class BaseSQLiteDatabase< return this.session.transaction(transaction, config); } } + +export type SQLiteWithReplicas = Q & { $primary: Q }; + +export const withReplicas = < + TResultKind extends 'sync' | 'async', + TRunResult, + TFullSchema extends Record, + TSchema extends TablesRelationalConfig, + Q extends BaseSQLiteDatabase< + TResultKind, + TRunResult, + TFullSchema, + TSchema extends Record ? ExtractTablesWithRelations : TSchema + >, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): SQLiteWithReplicas => { + const select: Q['select'] = (...args: any) => getReplica(replicas).select(args); + const selectDistinct: Q['selectDistinct'] = (...args: any) => getReplica(replicas).selectDistinct(args); + const $with: Q['with'] = (...args: any) => getReplica(replicas).with(args); + + const update: Q['update'] = (...args: any) => primary.update(args); + const insert: Q['insert'] = (...args: any) => primary.insert(args); + const $delete: Q['delete'] = (...args: any) => primary.delete(args); + const run: Q['run'] = (...args: any) => primary.run(args); + const all: Q['all'] = (...args: any) => primary.all(args); + const get: Q['get'] = (...args: any) => primary.get(args); + const values: Q['values'] = (...args: any) => primary.values(args); + const transaction: Q['transaction'] = (...args: any) => primary.transaction(args); + + return new Proxy( + { + ...primary, + update, + insert, + delete: $delete, + run, + all, + get, + values, + transaction, + $primary: primary, + select, + selectDistinct, + with: $with, + }, + { + get(target, prop, _receiver) { + if (prop === 'query') { + return getReplica(replicas).query; + } + return target[prop as keyof typeof target]; + }, + }, + ); +}; diff --git a/drizzle-orm/src/sqlite-core/dialect.ts b/drizzle-orm/src/sqlite-core/dialect.ts index 4a46f573f..d58ef419e 100644 --- a/drizzle-orm/src/sqlite-core/dialect.ts +++ b/drizzle-orm/src/sqlite-core/dialect.ts @@ -16,17 +16,23 @@ import { type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { and, eq, Param, type Query, SQL, sql, type SQLChunk } from '~/sql/index.ts'; +import { Param, type QueryWithTypings, SQL, sql, type SQLChunk } from '~/sql/sql.ts'; +import type { Name} from '~/sql/index.ts'; +import { and, eq } from '~/sql/index.ts' import { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; import type { SQLiteDeleteConfig, SQLiteInsertConfig, SQLiteUpdateConfig } from '~/sqlite-core/query-builders/index.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; import { Subquery, SubqueryConfig } from '~/subquery.ts'; import { getTableName, Table } from '~/table.ts'; import { orderSelectedFields, type UpdateSet } from '~/utils.ts'; -import { ViewBaseConfig } from '~/view.ts'; -import type { Join, SelectedFieldsOrdered, SQLiteSelectConfig } from './query-builders/select.types.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; +import type { + SelectedFieldsOrdered, + SQLiteSelectConfig, + SQLiteSelectJoinConfig, +} from './query-builders/select.types.ts'; import type { SQLiteSession } from './session.ts'; -import { SQLiteViewBase } from './view.ts'; +import { SQLiteViewBase } from './view-base.ts'; export abstract class SQLiteDialect { static readonly [entityKind]: string = 'SQLiteDialect'; @@ -147,8 +153,21 @@ export abstract class SQLiteDialect { } buildSelectQuery( - { withList, fields, fieldsFlat, where, having, table, joins, orderBy, groupBy, limit, offset, distinct }: - SQLiteSelectConfig, + { + withList, + fields, + fieldsFlat, + where, + having, + table, + joins, + orderBy, + groupBy, + limit, + offset, + distinct, + setOperators, + }: SQLiteSelectConfig, ): SQL { const fieldsList = fieldsFlat ?? orderSelectedFields(fields); for (const f of fieldsList) { @@ -269,7 +288,76 @@ export abstract class SQLiteDialect { const offsetSql = offset ? sql` offset ${offset}` : undefined; - return sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}`; + const finalQuery = + sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}`; + + if (setOperators.length > 0) { + return this.buildSetOperations(finalQuery, setOperators); + } + + return finalQuery; + } + + buildSetOperations(leftSelect: SQL, setOperators: SQLiteSelectConfig['setOperators']): SQL { + const [setOperator, ...rest] = setOperators; + + if (!setOperator) { + throw new Error('Cannot pass undefined values to any set operator'); + } + + if (rest.length === 0) { + return this.buildSetOperationQuery({ leftSelect, setOperator }); + } + + // Some recursive magic here + return this.buildSetOperations( + this.buildSetOperationQuery({ leftSelect, setOperator }), + rest, + ); + } + + buildSetOperationQuery({ + leftSelect, + setOperator: { type, isAll, rightSelect, limit, orderBy, offset }, + }: { leftSelect: SQL; setOperator: SQLiteSelectConfig['setOperators'][number] }): SQL { + // SQLite doesn't support parenthesis in set operations + const leftChunk = sql`${leftSelect.getSQL()} `; + const rightChunk = sql`${rightSelect.getSQL()}`; + + let orderBySql; + if (orderBy && orderBy.length > 0) { + const orderByValues: (SQL | Name)[] = []; + + // The next bit is necessary because the sql operator replaces ${table.column} with `table`.`column` + // which is invalid Sql syntax, Table from one of the SELECTs cannot be used in global ORDER clause + for (const singleOrderBy of orderBy) { + if (is(singleOrderBy, SQLiteColumn)) { + orderByValues.push(sql.identifier(singleOrderBy.name)); + } else if (is(singleOrderBy, SQL)) { + for (let i = 0; i < singleOrderBy.queryChunks.length; i++) { + const chunk = singleOrderBy.queryChunks[i]; + + if (is(chunk, SQLiteColumn)) { + singleOrderBy.queryChunks[i] = sql.identifier(chunk.name); + } + } + + orderByValues.push(sql`${singleOrderBy}`); + } else { + orderByValues.push(sql`${singleOrderBy}`); + } + } + + orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)}`; + } + + const limitSql = limit ? sql` limit ${limit}` : undefined; + + const operatorChunk = sql.raw(`${type} ${isAll ? 'all ' : ''}`); + + const offsetSql = offset ? sql` offset ${offset}` : undefined; + + return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`; } buildInsertQuery({ table, values, onConflict, returning }: SQLiteInsertConfig): SQL { @@ -321,7 +409,7 @@ export abstract class SQLiteDialect { return sql`insert into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}${returningSql}`; } - sqlToQuery(sql: SQL): Query { + sqlToQuery(sql: SQL): QueryWithTypings { return sql.toQuery({ escapeName: this.escapeName, escapeParam: this.escapeParam, @@ -352,7 +440,7 @@ export abstract class SQLiteDialect { }): BuildRelationalQueryResult { let selection: BuildRelationalQueryResult['selection'] = []; let limit, offset, orderBy: SQLiteSelectConfig['orderBy'] = [], where; - const joins: Join[] = []; + const joins: SQLiteSelectJoinConfig[] = []; if (config === true) { const selectionEntries = Object.entries(tableConfig.columns); @@ -519,9 +607,10 @@ export abstract class SQLiteDialect { } if (selection.length === 0) { - throw new DrizzleError( - `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}"). You need to have at least one item in "columns", "with" or "extras". If you need to select all columns, omit the "columns" key or set it to undefined.`, - ); + throw new DrizzleError({ + message: + `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}"). You need to have at least one item in "columns", "with" or "extras". If you need to select all columns, omit the "columns" key or set it to undefined.`, + }); } let result; @@ -565,6 +654,7 @@ export abstract class SQLiteDialect { limit, offset, orderBy, + setOperators: [], }); where = undefined; @@ -587,6 +677,7 @@ export abstract class SQLiteDialect { limit, offset, orderBy, + setOperators: [], }); } else { result = this.buildSelectQuery({ @@ -601,6 +692,7 @@ export abstract class SQLiteDialect { limit, offset, orderBy, + setOperators: [], }); } diff --git a/drizzle-orm/src/sqlite-core/expressions.ts b/drizzle-orm/src/sqlite-core/expressions.ts index 5153c2bfa..c04db49d1 100644 --- a/drizzle-orm/src/sqlite-core/expressions.ts +++ b/drizzle-orm/src/sqlite-core/expressions.ts @@ -1,6 +1,6 @@ import { bindIfParam } from '~/expressions.ts'; -import type { SQL, SQLChunk, SQLWrapper } from '~/sql/index.ts'; -import { sql } from '~/sql/index.ts'; +import type { SQL, SQLChunk, SQLWrapper } from '~/sql/sql.ts'; +import { sql } from '~/sql/sql.ts'; import type { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; export * from '~/expressions.ts'; diff --git a/drizzle-orm/src/sqlite-core/foreign-keys.ts b/drizzle-orm/src/sqlite-core/foreign-keys.ts index 1aab5c765..9cc14072f 100644 --- a/drizzle-orm/src/sqlite-core/foreign-keys.ts +++ b/drizzle-orm/src/sqlite-core/foreign-keys.ts @@ -5,6 +5,7 @@ import { SQLiteTable } from './table.ts'; export type UpdateDeleteAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default'; export type Reference = () => { + readonly name?: string; readonly columns: SQLiteColumn[]; readonly foreignTable: SQLiteTable; readonly foreignColumns: SQLiteColumn[]; @@ -29,6 +30,7 @@ export class ForeignKeyBuilder { constructor( config: () => { + name?: string; columns: SQLiteColumn[]; foreignColumns: SQLiteColumn[]; }, @@ -38,8 +40,8 @@ export class ForeignKeyBuilder { } | undefined, ) { this.reference = () => { - const { columns, foreignColumns } = config(); - return { columns, foreignTable: foreignColumns[0]!.table as SQLiteTable, foreignColumns }; + const { name, columns, foreignColumns } = config(); + return { name, columns, foreignTable: foreignColumns[0]!.table as SQLiteTable, foreignColumns }; }; if (actions) { this._onUpdate = actions.onUpdate; @@ -77,7 +79,7 @@ export class ForeignKey { } getName(): string { - const { columns, foreignColumns } = this.reference(); + const { name, columns, foreignColumns } = this.reference(); const columnNames = columns.map((column) => column.name); const foreignColumnNames = foreignColumns.map((column) => column.name); const chunks = [ @@ -86,7 +88,7 @@ export class ForeignKey { foreignColumns[0]!.table[SQLiteTable.Symbol.Name], ...foreignColumnNames, ]; - return `${chunks.join('_')}_fk`; + return name ?? `${chunks.join('_')}_fk`; } } @@ -95,22 +97,46 @@ type ColumnsWithTable< TColumns extends SQLiteColumn[], > = { [Key in keyof TColumns]: AnySQLiteColumn<{ tableName: TTableName }> }; +/** + * @deprecated please use `foreignKey({ columns: [], foreignColumns: [] })` syntax without callback + * @param config + * @returns + */ export function foreignKey< TTableName extends string, TForeignTableName extends string, TColumns extends [AnySQLiteColumn<{ tableName: TTableName }>, ...AnySQLiteColumn<{ tableName: TTableName }>[]], >( config: () => { + name?: string; columns: TColumns; foreignColumns: ColumnsWithTable; }, +): ForeignKeyBuilder; +export function foreignKey< + TTableName extends string, + TForeignTableName extends string, + TColumns extends [AnySQLiteColumn<{ tableName: TTableName }>, ...AnySQLiteColumn<{ tableName: TTableName }>[]], +>( + config: { + name?: string; + columns: TColumns; + foreignColumns: ColumnsWithTable; + }, +): ForeignKeyBuilder; +export function foreignKey( + config: any, ): ForeignKeyBuilder { function mappedConfig() { - const { columns, foreignColumns } = config(); - return { - columns, - foreignColumns, - }; + if (typeof config === 'function') { + const { name, columns, foreignColumns } = config(); + return { + name, + columns, + foreignColumns, + }; + } + return config; } return new ForeignKeyBuilder(mappedConfig); diff --git a/drizzle-orm/src/sqlite-core/indexes.ts b/drizzle-orm/src/sqlite-core/indexes.ts index d3efb8cde..70ca62a8c 100644 --- a/drizzle-orm/src/sqlite-core/indexes.ts +++ b/drizzle-orm/src/sqlite-core/indexes.ts @@ -1,6 +1,6 @@ import { entityKind } from '~/entity.ts'; -import type { SQL } from '~/sql/index.ts'; -import { type SQLiteColumn } from './columns/index.ts'; +import type { SQL } from '~/sql/sql.ts'; +import type { SQLiteColumn } from './columns/index.ts'; import type { SQLiteTable } from './table.ts'; export interface IndexConfig { diff --git a/drizzle-orm/src/sqlite-core/primary-keys.ts b/drizzle-orm/src/sqlite-core/primary-keys.ts index 5285eacbd..ea2111c63 100644 --- a/drizzle-orm/src/sqlite-core/primary-keys.ts +++ b/drizzle-orm/src/sqlite-core/primary-keys.ts @@ -4,13 +4,23 @@ import { SQLiteTable } from './table.ts'; export function primaryKey< TTableName extends string, + TColumn extends AnySQLiteColumn<{ tableName: TTableName }>, TColumns extends AnySQLiteColumn<{ tableName: TTableName }>[], ->( - ...columns: TColumns -): PrimaryKeyBuilder { - return new PrimaryKeyBuilder(columns); +>(config: { name?: string; columns: [TColumn, ...TColumns] }): PrimaryKeyBuilder; +/** + * @deprecated: Please use primaryKey({ columns: [] }) instead of this function + * @param columns + */ +export function primaryKey< + TTableName extends string, + TColumns extends AnySQLiteColumn<{ tableName: TTableName }>[], +>(...columns: TColumns): PrimaryKeyBuilder; +export function primaryKey(...config: any) { + if (config[0].columns) { + return new PrimaryKeyBuilder(config[0].columns, config[0].name); + } + return new PrimaryKeyBuilder(config); } - export class PrimaryKeyBuilder { static readonly [entityKind]: string = 'SQLitePrimaryKeyBuilder'; @@ -21,15 +31,20 @@ export class PrimaryKeyBuilder { /** @internal */ columns: SQLiteColumn[]; + /** @internal */ + name?: string; + constructor( columns: SQLiteColumn[], + name?: string, ) { this.columns = columns; + this.name = name; } /** @internal */ build(table: SQLiteTable): PrimaryKey { - return new PrimaryKey(table, this.columns); + return new PrimaryKey(table, this.columns, this.name); } } @@ -37,12 +52,15 @@ export class PrimaryKey { static readonly [entityKind]: string = 'SQLitePrimaryKey'; readonly columns: SQLiteColumn[]; + readonly name?: string; - constructor(readonly table: SQLiteTable, columns: SQLiteColumn[]) { + constructor(readonly table: SQLiteTable, columns: SQLiteColumn[], name?: string) { this.columns = columns; + this.name = name; } getName(): string { - return `${this.table[SQLiteTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; + return this.name + ?? `${this.table[SQLiteTable.Symbol.Name]}_${this.columns.map((column) => column.name).join('_')}_pk`; } } diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index f95833d1d..2296310f5 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -1,41 +1,138 @@ import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/index.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; -import type { PreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; +import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; -import type { InferModel } from '~/table.ts'; import { type DrizzleTypeError, orderSelectedFields } from '~/utils.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; +export type SQLiteDeleteWithout< + T extends AnySQLiteDeleteBase, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T + : Omit< + SQLiteDeleteBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SQLiteDelete< + TTable extends SQLiteTable = SQLiteTable, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, + TReturning extends Record | undefined = undefined, +> = SQLiteDeleteBase; + export interface SQLiteDeleteConfig { where?: SQL | undefined; table: SQLiteTable; returning?: SelectedFieldsOrdered; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SQLiteDelete< - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type SQLiteDeleteReturningAll< + T extends AnySQLiteDeleteBase, + TDynamic extends boolean, +> = SQLiteDeleteWithout< + SQLiteDeleteBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['table']['$inferSelect'], + T['_']['dynamic'], + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type SQLiteDeleteReturning< + T extends AnySQLiteDeleteBase, + TDynamic extends boolean, + TSelectedFields extends SelectedFieldsFlat, +> = SQLiteDeleteWithout< + SQLiteDeleteBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + SelectResultFields, + T['_']['dynamic'], + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type SQLiteDeleteExecute = T['_']['returning'] extends undefined + ? T['_']['runResult'] + : T['_']['returning'][]; + +export type SQLiteDeletePrepare = SQLitePreparedQuery<{ + type: T['_']['resultType']; + run: T['_']['runResult']; + all: T['_']['returning'] extends undefined ? DrizzleTypeError<'.all() cannot be used without .returning()'> + : T['_']['returning'][]; + get: T['_']['returning'] extends undefined ? DrizzleTypeError<'.get() cannot be used without .returning()'> + : T['_']['returning'] | undefined; + values: T['_']['returning'] extends undefined ? DrizzleTypeError<'.values() cannot be used without .returning()'> + : any[][]; + execute: SQLiteDeleteExecute; +}>; + +export type SQLiteDeleteDynamic = SQLiteDelete< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['returning'] +>; + +export type AnySQLiteDeleteBase = SQLiteDeleteBase; + +export interface SQLiteDeleteBase< TTable extends SQLiteTable, - // eslint-disable-next-line @typescript-eslint/no-unused-vars TResultType extends 'sync' | 'async', - // eslint-disable-next-line @typescript-eslint/no-unused-vars TRunResult, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TReturning = undefined, -> extends SQLWrapper {} + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends SQLWrapper { + readonly _: { + dialect: 'sqlite'; + readonly table: TTable; + readonly resultType: TResultType; + readonly runResult: TRunResult; + readonly returning: TReturning; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TReturning extends undefined ? TRunResult : TReturning[]; + }; +} -export class SQLiteDelete< +export class SQLiteDeleteBase< TTable extends SQLiteTable, + // eslint-disable-next-line @typescript-eslint/no-unused-vars TResultType extends 'sync' | 'async', TRunResult, - TReturning = undefined, -> extends QueryPromise implements SQLWrapper { + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise + implements RunnableQuery, SQLWrapper +{ static readonly [entityKind]: string = 'SQLiteDelete'; - private config: SQLiteDeleteConfig; + /** @internal */ + config: SQLiteDeleteConfig; constructor( private table: TTable, @@ -46,20 +143,20 @@ export class SQLiteDelete< this.config = { table }; } - where(where: SQL | undefined): Omit { + where(where: SQL | undefined): SQLiteDeleteWithout { this.config.where = where; - return this; + return this as any; } - returning(): SQLiteDelete>; + returning(): SQLiteDeleteReturningAll; returning( fields: TSelectedFields, - ): SQLiteDelete>; + ): SQLiteDeleteReturning; returning( fields: SelectedFieldsFlat = this.table[SQLiteTable.Symbol.Columns], - ): SQLiteDelete { + ): SQLiteDeleteReturning { this.config.returning = orderSelectedFields(fields); - return this; + return this as any; } /** @internal */ @@ -67,25 +164,17 @@ export class SQLiteDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Omit { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - prepare(isOneTimeQuery?: boolean): PreparedQuery<{ - type: TResultType; - run: TRunResult; - all: TReturning extends undefined ? DrizzleTypeError<'.all() cannot be used without .returning()'> : TReturning[]; - get: TReturning extends undefined ? DrizzleTypeError<'.get() cannot be used without .returning()'> - : TReturning | undefined; - values: TReturning extends undefined ? DrizzleTypeError<'.values() cannot be used without .returning()'> : any[][]; - execute: TReturning extends undefined ? TRunResult : TReturning[]; - }> { + prepare(isOneTimeQuery?: boolean): SQLiteDeletePrepare { return this.session[isOneTimeQuery ? 'prepareOneTimeQuery' : 'prepareQuery']( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, this.config.returning ? 'all' : 'run', - ) as ReturnType; + ) as SQLiteDeletePrepare; } run: ReturnType['run'] = (placeholderValues) => { @@ -104,10 +193,11 @@ export class SQLiteDelete< return this.prepare(true).values(placeholderValues); }; - override async execute( - placeholderValues?: Record, - ): Promise { - return this.prepare(true).execute(placeholderValues) as TReturning extends undefined ? TRunResult - : TReturning[]; + override async execute(placeholderValues?: Record): Promise> { + return this.prepare(true).execute(placeholderValues) as SQLiteDeleteExecute; + } + + $dynamic(): SQLiteDeleteDynamic { + return this as any; } } diff --git a/drizzle-orm/src/sqlite-core/query-builders/insert.ts b/drizzle-orm/src/sqlite-core/query-builders/insert.ts index 832662c09..1190fe79e 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/insert.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/insert.ts @@ -1,13 +1,14 @@ import { entityKind, is } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Placeholder, Query, SQLWrapper } from '~/sql/index.ts'; -import { Param, SQL, sql } from '~/sql/index.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { Placeholder, Query, SQLWrapper } from '~/sql/sql.ts'; +import { Param, SQL, sql } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; import type { IndexColumn } from '~/sqlite-core/indexes.ts'; -import type { PreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; +import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; -import { type InferModel, Table } from '~/table.ts'; +import { Table } from '~/table.ts'; import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type Simplify } from '~/utils.ts'; import type { SelectedFieldsFlat, SelectedFieldsOrdered } from './select.types.ts'; import type { SQLiteUpdateSetSource } from './update.ts'; @@ -21,7 +22,7 @@ export interface SQLiteInsertConfig { export type SQLiteInsertValue = Simplify< { - [Key in keyof InferModel]: InferModel[Key] | SQL | Placeholder; + [Key in keyof TTable['$inferInsert']]: TTable['$inferInsert'][Key] | SQL | Placeholder; } >; @@ -38,11 +39,11 @@ export class SQLiteInsertBuilder< protected dialect: SQLiteDialect, ) {} - values(value: SQLiteInsertValue): SQLiteInsert; - values(values: SQLiteInsertValue[]): SQLiteInsert; + values(value: SQLiteInsertValue): SQLiteInsertBase; + values(values: SQLiteInsertValue[]): SQLiteInsertBase; values( values: SQLiteInsertValue | SQLiteInsertValue[], - ): SQLiteInsert { + ): SQLiteInsertBase { values = Array.isArray(values) ? values : [values]; if (values.length === 0) { throw new Error('values() must be called with at least one value'); @@ -63,38 +64,137 @@ export class SQLiteInsertBuilder< // ); // } - return new SQLiteInsert(this.table, mappedValues, this.session, this.dialect); + return new SQLiteInsertBase(this.table, mappedValues, this.session, this.dialect); } } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SQLiteInsert< - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TTable extends SQLiteTable, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TResultType extends 'sync' | 'async', - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TRunResult, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TReturning = undefined, -> extends SQLWrapper, QueryPromise {} +export type SQLiteInsertWithout = + TDynamic extends true ? T + : Omit< + SQLiteInsertBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K + >; + +export type SQLiteInsertReturning< + T extends AnySQLiteInsert, + TDynamic extends boolean, + TSelectedFields extends SelectedFieldsFlat, +> = SQLiteInsertWithout< + SQLiteInsertBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + SelectResultFields, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type SQLiteInsertReturningAll< + T extends AnySQLiteInsert, + TDynamic extends boolean, +> = SQLiteInsertWithout< + SQLiteInsertBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['table']['$inferSelect'], + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type SQLiteInsertOnConflictDoUpdateConfig = { + target: IndexColumn | IndexColumn[]; + where?: SQL; + set: SQLiteUpdateSetSource; +}; + +export type SQLiteInsertDynamic = SQLiteInsert< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['returning'] +>; + +export type SQLiteInsertExecute = T['_']['returning'] extends undefined ? T['_']['runResult'] + : T['_']['returning'][]; + +export type SQLiteInsertPrepare = SQLitePreparedQuery< + { + type: T['_']['resultType']; + run: T['_']['runResult']; + all: T['_']['returning'] extends undefined ? DrizzleTypeError<'.all() cannot be used without .returning()'> + : T['_']['returning'][]; + get: T['_']['returning'] extends undefined ? DrizzleTypeError<'.get() cannot be used without .returning()'> + : T['_']['returning']; + values: T['_']['returning'] extends undefined ? DrizzleTypeError<'.values() cannot be used without .returning()'> + : any[][]; + execute: SQLiteInsertExecute; + } +>; -export class SQLiteInsert< +export type AnySQLiteInsert = SQLiteInsertBase; + +export type SQLiteInsert< + TTable extends SQLiteTable = SQLiteTable, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, + TReturning = any, +> = SQLiteInsertBase; + +export interface SQLiteInsertBase< TTable extends SQLiteTable, TResultType extends 'sync' | 'async', TRunResult, TReturning = undefined, -> extends QueryPromise implements SQLWrapper { - static readonly [entityKind]: string = 'SQLiteInsert'; - - declare readonly _: { + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends + SQLWrapper, + QueryPromise, + RunnableQuery +{ + readonly _: { + readonly dialect: 'sqlite'; readonly table: TTable; readonly resultType: TResultType; readonly runResult: TRunResult; readonly returning: TReturning; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TReturning extends undefined ? TRunResult : TReturning[]; }; +} - private config: SQLiteInsertConfig; +export class SQLiteInsertBase< + TTable extends SQLiteTable, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TResultType extends 'sync' | 'async', + TRunResult, + TReturning = undefined, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise + implements RunnableQuery, SQLWrapper +{ + static readonly [entityKind]: string = 'SQLiteInsert'; + + /** @internal */ + config: SQLiteInsertConfig; constructor( table: TTable, @@ -106,15 +206,15 @@ export class SQLiteInsert< this.config = { table, values }; } - returning(): SQLiteInsert>; + returning(): SQLiteInsertReturningAll; returning( fields: TSelectedFields, - ): SQLiteInsert>; + ): SQLiteInsertReturning; returning( fields: SelectedFieldsFlat = this.config.table[SQLiteTable.Symbol.Columns], - ): SQLiteInsert { + ): SQLiteInsertWithout { this.config.returning = orderSelectedFields(fields); - return this; + return this as any; } onConflictDoNothing(config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {}): this { @@ -128,11 +228,7 @@ export class SQLiteInsert< return this; } - onConflictDoUpdate(config: { - target: IndexColumn | IndexColumn[]; - where?: SQL; - set: SQLiteUpdateSetSource; - }): this { + onConflictDoUpdate(config: SQLiteInsertOnConflictDoUpdateConfig): this { const targetSql = Array.isArray(config.target) ? sql`${config.target}` : sql`${[config.target]}`; const whereSql = config.where ? sql` where ${config.where}` : sql``; const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set)); @@ -145,27 +241,17 @@ export class SQLiteInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): Simplify<{ sql: Query['sql']; params: Query['params'] }> { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - prepare(isOneTimeQuery?: boolean): PreparedQuery< - { - type: TResultType; - run: TRunResult; - all: TReturning extends undefined ? DrizzleTypeError<'.all() cannot be used without .returning()'> : TReturning[]; - get: TReturning extends undefined ? DrizzleTypeError<'.get() cannot be used without .returning()'> : TReturning; - values: TReturning extends undefined ? DrizzleTypeError<'.values() cannot be used without .returning()'> - : any[][]; - execute: TReturning extends undefined ? TRunResult : TReturning[]; - } - > { + prepare(isOneTimeQuery?: boolean): SQLiteInsertPrepare { return this.session[isOneTimeQuery ? 'prepareOneTimeQuery' : 'prepareQuery']( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, this.config.returning ? 'all' : 'run', - ) as ReturnType; + ) as SQLiteInsertPrepare; } run: ReturnType['run'] = (placeholderValues) => { @@ -184,8 +270,11 @@ export class SQLiteInsert< return this.prepare(true).values(placeholderValues); }; - override async execute(): Promise { - return (this.config.returning ? this.all() : this.run()) as TReturning extends undefined ? TRunResult - : TReturning[]; + override async execute(): Promise> { + return (this.config.returning ? this.all() : this.run()) as SQLiteInsertExecute; + } + + $dynamic(): SQLiteInsertDynamic { + return this as any; } } diff --git a/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts b/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts index 069588361..54b615b4d 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/query-builder.ts @@ -2,10 +2,11 @@ import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import { SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import type { WithSubqueryWithSelection } from '~/sqlite-core/subquery.ts'; -import { SelectionProxyHandler, WithSubquery } from '~/subquery.ts'; -import type { ColumnsSelection } from '~/view.ts'; import { SQLiteSelectBuilder } from './select.ts'; import type { SelectedFields } from './select.types.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; +import { WithSubquery } from '~/subquery.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export class QueryBuilder { static readonly [entityKind]: string = 'SQLiteQueryBuilder'; @@ -69,7 +70,9 @@ export class QueryBuilder { } select(): SQLiteSelectBuilder; - select(fields: TSelection): SQLiteSelectBuilder; + select( + fields: TSelection, + ): SQLiteSelectBuilder; select( fields?: TSelection, ): SQLiteSelectBuilder { diff --git a/drizzle-orm/src/sqlite-core/query-builders/query.ts b/drizzle-orm/src/sqlite-core/query-builders/query.ts index 0c52cfb1f..a8f04b764 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/query.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/query.ts @@ -2,16 +2,18 @@ import { entityKind } from '~/entity.ts'; import { QueryPromise } from '~/query-promise.ts'; import { type BuildQueryResult, + type BuildRelationalQueryResult, type DBQueryConfig, mapRelationalRow, type TableRelationalConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type SQL } from '~/sql/index.ts'; -import { type KnownKeysOnly } from '~/utils.ts'; -import { type SQLiteDialect } from '../dialect.ts'; -import type { PreparedQuery, PreparedQueryConfig, SQLiteSession } from '../session.ts'; -import { type SQLiteTable } from '../table.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { Query, QueryWithTypings, SQL, SQLWrapper } from '~/sql/sql.ts'; +import type { KnownKeysOnly } from '~/utils.ts'; +import type { SQLiteDialect } from '../dialect.ts'; +import type { PreparedQueryConfig, SQLitePreparedQuery, SQLiteSession } from '../session.ts'; +import type { SQLiteTable } from '../table.ts'; export type SQLiteRelationalQueryKind = TMode extends 'async' ? SQLiteRelationalQuery @@ -93,10 +95,19 @@ export class RelationalQueryBuilder< } } -export class SQLiteRelationalQuery extends QueryPromise { +export class SQLiteRelationalQuery extends QueryPromise + implements RunnableQuery, SQLWrapper +{ static readonly [entityKind]: string = 'SQLiteAsyncRelationalQuery'; - declare protected $brand: 'SQLiteRelationalQuery'; + declare readonly _: { + readonly dialect: 'sqlite'; + readonly type: TType; + readonly result: TResult; + }; + + /** @internal */ + mode: 'many' | 'first'; constructor( private fullSchema: Record, @@ -107,13 +118,15 @@ export class SQLiteRelationalQuery exte private dialect: SQLiteDialect, private session: SQLiteSession<'sync' | 'async', unknown, Record, TablesRelationalConfig>, private config: DBQueryConfig<'many', true> | true, - private mode: 'many' | 'first', + mode: 'many' | 'first', ) { super(); + this.mode = mode; } - prepare(): PreparedQuery { - const query = this.dialect.buildRelationalQuery({ + /** @internal */ + getSQL(): SQL { + return this.dialect.buildRelationalQuery({ fullSchema: this.fullSchema, schema: this.schema, tableNamesMap: this.tableNamesMap, @@ -121,9 +134,12 @@ export class SQLiteRelationalQuery exte tableConfig: this.tableConfig, queryConfig: this.config, tableAlias: this.tableConfig.tsName, - }); + }).sql as SQL; + } + + prepare(): SQLitePreparedQuery { + const { query, builtQuery } = this._toSQL(); - const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); return this.session.prepareQuery( builtQuery, undefined, @@ -137,7 +153,27 @@ export class SQLiteRelationalQuery exte } return rows as TResult; }, - ) as PreparedQuery; + ) as SQLitePreparedQuery; + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: QueryWithTypings } { + const query = this.dialect.buildRelationalQuery({ + fullSchema: this.fullSchema, + schema: this.schema, + tableNamesMap: this.tableNamesMap, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + tableAlias: this.tableConfig.tsName, + }); + + const builtQuery = this.dialect.sqlToQuery(query.sql as SQL); + + return { query, builtQuery }; + } + + toSQL(): Query { + return this._toSQL().builtQuery; } /** @internal */ diff --git a/drizzle-orm/src/sqlite-core/query-builders/raw.ts b/drizzle-orm/src/sqlite-core/query-builders/raw.ts new file mode 100644 index 000000000..b5a1223e2 --- /dev/null +++ b/drizzle-orm/src/sqlite-core/query-builders/raw.ts @@ -0,0 +1,54 @@ +import { entityKind } from '~/entity.ts'; +import type { SQL, SQLWrapper } from '~/index.ts'; +import { QueryPromise } from '~/query-promise.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { PreparedQuery } from '~/session.ts'; +import type { SQLiteAsyncDialect } from '../dialect.ts'; + +type SQLiteRawAction = 'all' | 'get' | 'values' | 'run'; +export interface SQLiteRawConfig { + action: SQLiteRawAction; +} + +export class SQLiteRaw extends QueryPromise implements RunnableQuery, SQLWrapper { + static readonly [entityKind]: string = 'SQLiteRaw'; + + declare readonly _: { + readonly dialect: 'sqlite'; + readonly result: TResult; + }; + + /** @internal */ + config: SQLiteRawConfig; + + constructor( + private cb: () => Promise, + private getSQLCb: () => SQL, + action: SQLiteRawAction, + private dialect: SQLiteAsyncDialect, + private mapBatchResult: (result: unknown) => unknown, + ) { + super(); + this.config = { action }; + } + + /** @internal */ + getSQL(): SQL { + return this.getSQLCb(); + } + + override async execute(): Promise { + return this.cb(); + } + + prepare(): PreparedQuery { + return { + getQuery: () => { + return this.dialect.sqlToQuery(this.getSQL()); + }, + mapResult: (result: unknown, isFromBatch?: boolean) => { + return isFromBatch ? this.mapBatchResult(result) : result; + }, + }; + } +} diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.ts b/drizzle-orm/src/sqlite-core/query-builders/select.ts index 31ebcf579..67cae227f 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.ts @@ -8,44 +8,48 @@ import type { JoinType, SelectMode, SelectResult, + SetOperator, } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import { type Placeholder, type Query, SQL } from '~/sql/index.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import { SQL, View } from '~/sql/sql.ts'; +import type { ColumnsSelection, Placeholder, Query } from '~/sql/sql.ts'; import type { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; -import type { PreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; +import type { SQLiteSession } from '~/sqlite-core/session.ts'; import type { SubqueryWithSelection } from '~/sqlite-core/subquery.ts'; import type { SQLiteTable } from '~/sqlite-core/table.ts'; -import { SelectionProxyHandler, Subquery, SubqueryConfig } from '~/subquery.ts'; import { Table } from '~/table.ts'; import { applyMixins, getTableColumns, getTableLikeName, + haveSameKeys, orderSelectedFields, - type PromiseOf, type ValueOrArray, } from '~/utils.ts'; -import { type ColumnsSelection, View, ViewBaseConfig } from '~/view.ts'; -import { SQLiteViewBase } from '../view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { - JoinFn, + AnySQLiteSelect, + CreateSQLiteSelectFromBuilderMode, + GetSQLiteSetOperators, SelectedFields, + SetOperatorRightSelect, + SQLiteCreateSetOperatorFn, + SQLiteJoinFn, SQLiteSelectConfig, + SQLiteSelectDynamic, + SQLiteSelectExecute, SQLiteSelectHKT, SQLiteSelectHKTBase, - SQLiteSelectQueryBuilderHKT, + SQLiteSelectPrepare, + SQLiteSelectWithout, + SQLiteSetOperatorExcludedMethods, + SQLiteSetOperatorWithResult, } from './select.types.ts'; - -type CreateSQLiteSelectFromBuilderMode< - TBuilderMode extends 'db' | 'qb', - TTableName extends string | undefined, - TResultType extends 'sync' | 'async', - TRunResult, - TSelection extends ColumnsSelection, - TSelectMode extends SelectMode, -> = TBuilderMode extends 'db' ? SQLiteSelect - : SQLiteSelectQueryBuilder; +import { Subquery, SubqueryConfig } from '~/subquery.ts'; +import { SQLiteViewBase } from '../view-base.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export class SQLiteSelectBuilder< TSelection extends SelectedFields | undefined, @@ -107,7 +111,7 @@ export class SQLiteSelectBuilder< fields = getTableColumns(source); } - return new SQLiteSelect({ + return new SQLiteSelectBase({ table: source, fields, isPartialSelect, @@ -119,7 +123,7 @@ export class SQLiteSelectBuilder< } } -export abstract class SQLiteSelectQueryBuilder< +export abstract class SQLiteSelectQueryBuilderBase< THKT extends SQLiteSelectHKTBase, TTableName extends string | undefined, TResultType extends 'sync' | 'async', @@ -128,20 +132,30 @@ export abstract class SQLiteSelectQueryBuilder< TSelectMode extends SelectMode, TNullabilityMap extends Record = TTableName extends string ? Record : {}, -> extends TypedQueryBuilder< - BuildSubquerySelection, - SelectResult[] -> { + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends TypedQueryBuilder { static readonly [entityKind]: string = 'SQLiteSelectQueryBuilder'; override readonly _: { - readonly selectMode: TSelectMode; + dialect: 'sqlite'; + readonly hkt: THKT; + readonly tableName: TTableName; + readonly resultType: TResultType; + readonly runResult: TRunResult; readonly selection: TSelection; - readonly result: SelectResult[]; - readonly selectedFields: BuildSubquerySelection; + readonly selectMode: TSelectMode; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; }; - protected config: SQLiteSelectConfig; + /** @internal */ + config: SQLiteSelectConfig; protected joinsNotNullableMap: Record; private tableName: string | undefined; private isPartialSelect: boolean; @@ -165,12 +179,13 @@ export abstract class SQLiteSelectQueryBuilder< table, fields: { ...fields }, distinct, + setOperators: [], }; this.isPartialSelect = isPartialSelect; this.session = session; this.dialect = dialect; this._ = { - selectedFields: fields as BuildSubquerySelection, + selectedFields: fields as TSelectedFields, } as this['_']; this.tableName = getTableLikeName(table); this.joinsNotNullableMap = typeof this.tableName === 'string' ? { [this.tableName]: true } : {}; @@ -178,7 +193,7 @@ export abstract class SQLiteSelectQueryBuilder< private createJoin( joinType: TJoinType, - ): JoinFn { + ): SQLiteJoinFn { return ( table: SQLiteTable | Subquery | SQLiteViewBase | SQL, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, @@ -248,7 +263,7 @@ export abstract class SQLiteSelectQueryBuilder< } } - return this; + return this as any; }; } @@ -260,7 +275,60 @@ export abstract class SQLiteSelectQueryBuilder< fullJoin = this.createJoin('full'); - where(where: ((aliases: TSelection) => SQL | undefined) | SQL | undefined): this { + private createSetOperator( + type: SetOperator, + isAll: boolean, + ): >( + rightSelection: + | ((setOperators: GetSQLiteSetOperators) => SetOperatorRightSelect) + | SetOperatorRightSelect, + ) => SQLiteSelectWithout< + this, + TDynamic, + SQLiteSetOperatorExcludedMethods, + true + > { + return (rightSelection) => { + const rightSelect = (typeof rightSelection === 'function' + ? rightSelection(getSQLiteSetOperators()) + : rightSelection) as TypedQueryBuilder< + any, + TResult + >; + + if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + + this.config.setOperators.push({ type, isAll, rightSelect }); + return this as any; + }; + } + + union = this.createSetOperator('union', false); + + unionAll = this.createSetOperator('union', true); + + intersect = this.createSetOperator('intersect', false); + + except = this.createSetOperator('except', false); + + /** @internal */ + addSetOperators(setOperators: SQLiteSelectConfig['setOperators']): SQLiteSelectWithout< + this, + TDynamic, + SQLiteSetOperatorExcludedMethods, + true + > { + this.config.setOperators.push(...setOperators); + return this as any; + } + + where( + where: ((aliases: TSelection) => SQL | undefined) | SQL | undefined, + ): SQLiteSelectWithout { if (typeof where === 'function') { where = where( new Proxy( @@ -270,10 +338,12 @@ export abstract class SQLiteSelectQueryBuilder< ); } this.config.where = where; - return this; + return this as any; } - having(having: ((aliases: TSelection) => SQL | undefined) | SQL | undefined): this { + having( + having: ((aliases: this['_']['selection']) => SQL | undefined) | SQL | undefined, + ): SQLiteSelectWithout { if (typeof having === 'function') { having = having( new Proxy( @@ -283,16 +353,18 @@ export abstract class SQLiteSelectQueryBuilder< ); } this.config.having = having; - return this; + return this as any; } - groupBy(builder: (aliases: TSelection) => ValueOrArray): this; - groupBy(...columns: (SQLiteColumn | SQL)[]): this; + groupBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SQLiteSelectWithout; + groupBy(...columns: (SQLiteColumn | SQL)[]): SQLiteSelectWithout; groupBy( ...columns: - | [(aliases: TSelection) => ValueOrArray] + | [(aliases: this['_']['selection']) => ValueOrArray] | (SQLiteColumn | SQL | SQL.Aliased)[] - ): this { + ): SQLiteSelectWithout { if (typeof columns[0] === 'function') { const groupBy = columns[0]( new Proxy( @@ -304,16 +376,18 @@ export abstract class SQLiteSelectQueryBuilder< } else { this.config.groupBy = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; } - return this; + return this as any; } - orderBy(builder: (aliases: TSelection) => ValueOrArray): this; - orderBy(...columns: (SQLiteColumn | SQL)[]): this; + orderBy( + builder: (aliases: this['_']['selection']) => ValueOrArray, + ): SQLiteSelectWithout; + orderBy(...columns: (SQLiteColumn | SQL)[]): SQLiteSelectWithout; orderBy( ...columns: - | [(aliases: TSelection) => ValueOrArray] + | [(aliases: this['_']['selection']) => ValueOrArray] | (SQLiteColumn | SQL | SQL.Aliased)[] - ): this { + ): SQLiteSelectWithout { if (typeof columns[0] === 'function') { const orderBy = columns[0]( new Proxy( @@ -321,21 +395,42 @@ export abstract class SQLiteSelectQueryBuilder< new SelectionProxyHandler({ sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' }), ) as TSelection, ); - this.config.orderBy = Array.isArray(orderBy) ? orderBy : [orderBy]; + + const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } } else { - this.config.orderBy = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; + const orderByArray = columns as (SQLiteColumn | SQL | SQL.Aliased)[]; + + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.orderBy = orderByArray; + } else { + this.config.orderBy = orderByArray; + } } - return this; + return this as any; } - limit(limit: number | Placeholder): this { - this.config.limit = limit; - return this; + limit(limit: number | Placeholder): SQLiteSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.limit = limit; + } else { + this.config.limit = limit; + } + return this as any; } - offset(offset: number | Placeholder): this { - this.config.offset = offset; - return this; + offset(offset: number | Placeholder): SQLiteSelectWithout { + if (this.config.setOperators.length > 0) { + this.config.setOperators.at(-1)!.offset = offset; + } else { + this.config.offset = offset; + } + return this as any; } /** @internal */ @@ -343,30 +438,35 @@ export abstract class SQLiteSelectQueryBuilder< return this.dialect.buildSelectQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } as( alias: TAlias, - ): SubqueryWithSelection, TAlias> { + ): SubqueryWithSelection { return new Proxy( new Subquery(this.getSQL(), this.config.fields, alias), new SelectionProxyHandler({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), - ) as SubqueryWithSelection, TAlias>; + ) as SubqueryWithSelection; } - override getSelectedFields(): BuildSubquerySelection { + /** @internal */ + override getSelectedFields(): this['_']['selectedFields'] { return new Proxy( this.config.fields, new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: 'alias', sqlBehavior: 'error' }), - ) as BuildSubquerySelection; + ) as this['_']['selectedFields']; + } + + $dynamic(): SQLiteSelectDynamic { + return this; } } // eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SQLiteSelect< +export interface SQLiteSelectBase< TTableName extends string | undefined, TResultType extends 'sync' | 'async', TRunResult, @@ -374,20 +474,28 @@ export interface SQLiteSelect< TSelectMode extends SelectMode = 'single', TNullabilityMap extends Record = TTableName extends string ? Record : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, > extends - SQLiteSelectQueryBuilder< + SQLiteSelectQueryBuilderBase< SQLiteSelectHKT, - TTableName | undefined, + TTableName, TResultType, TRunResult, TSelection, TSelectMode, - TNullabilityMap + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields >, - QueryPromise[]> + QueryPromise {} -export class SQLiteSelect< +export class SQLiteSelectBase< TTableName extends string | undefined, TResultType extends 'sync' | 'async', TRunResult, @@ -395,27 +503,26 @@ export class SQLiteSelect< TSelectMode extends SelectMode = 'single', TNullabilityMap extends Record = TTableName extends string ? Record : {}, -> extends SQLiteSelectQueryBuilder< + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> extends SQLiteSelectQueryBuilderBase< SQLiteSelectHKT, TTableName, TResultType, TRunResult, TSelection, TSelectMode, - TNullabilityMap -> { + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields +> implements RunnableQuery { static readonly [entityKind]: string = 'SQLiteSelect'; - prepare(isOneTimeQuery?: boolean): PreparedQuery< - { - type: TResultType; - run: TRunResult; - all: SelectResult[]; - get: SelectResult | undefined; - values: any[][]; - execute: SelectResult[]; - } - > { + prepare(isOneTimeQuery?: boolean): SQLiteSelectPrepare { if (!this.session) { throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.'); } @@ -445,9 +552,44 @@ export class SQLiteSelect< return this.prepare(true).values(placeholderValues); }; - async execute(): Promise[]> { - return this.all() as PromiseOf>; + async execute(): Promise> { + return this.all() as SQLiteSelectExecute; } } -applyMixins(SQLiteSelect, [QueryPromise]); +applyMixins(SQLiteSelectBase, [QueryPromise]); + +function createSetOperator(type: SetOperator, isAll: boolean): SQLiteCreateSetOperatorFn { + return (leftSelect, rightSelect, ...restSelects) => { + const setOperators = [rightSelect, ...restSelects].map((select) => ({ + type, + isAll, + rightSelect: select as AnySQLiteSelect, + })); + + for (const setOperator of setOperators) { + if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) { + throw new Error( + 'Set operator error (union / intersect / except): selected fields are not the same or are in a different order', + ); + } + } + + return (leftSelect as AnySQLiteSelect).addSetOperators(setOperators) as any; + }; +} + +const getSQLiteSetOperators = () => ({ + union, + unionAll, + intersect, + except, +}); + +export const union = createSetOperator('union', false); + +export const unionAll = createSetOperator('union', true); + +export const intersect = createSetOperator('intersect', false); + +export const except = createSetOperator('except', false); diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.types.ts b/drizzle-orm/src/sqlite-core/query-builders/select.types.ts index 9ad5ff436..a66c8ca38 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.types.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.types.ts @@ -1,5 +1,5 @@ -import type { Placeholder, SQL } from '~/sql/index.ts'; -import type { Assume } from '~/utils.ts'; +import type { ColumnsSelection, Placeholder, SQL, View } from '~/sql/sql.ts'; +import type { Assume, ValidateShape } from '~/utils.ts'; import type { SQLiteColumn } from '~/sqlite-core/columns/index.ts'; import type { SQLiteTable, SQLiteTableWithColumns } from '~/sqlite-core/table.ts'; @@ -9,30 +9,33 @@ import type { SelectedFieldsFlat as SelectFieldsFlatBase, SelectedFieldsOrdered as SelectFieldsOrderedBase, } from '~/operations.ts'; +import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AppendToNullabilityMap, AppendToResult, + BuildSubquerySelection, GetSelectTableName, JoinNullability, JoinType, MapColumnsToTableAlias, SelectMode, + SelectResult, + SetOperator, } from '~/query-builders/select.types.ts'; import type { Subquery } from '~/subquery.ts'; import type { Table, UpdateTableConfig } from '~/table.ts'; -import { type ColumnsSelection, type View } from '~/view.ts'; -import type { SQLiteViewBase, SQLiteViewWithSelection } from '../view.ts'; -import type { SQLiteSelect, SQLiteSelectQueryBuilder } from './select.ts'; +import type { SQLitePreparedQuery } from '../session.ts'; +import type { SQLiteSelectBase, SQLiteSelectQueryBuilderBase } from './select.ts'; +import type { SQLiteViewBase } from '../view-base.ts'; +import type { SQLiteViewWithSelection } from '../view.ts'; -export interface Join { +export interface SQLiteSelectJoinConfig { on: SQL | undefined; table: SQLiteTable | Subquery | SQLiteViewBase | SQL; alias: string | undefined; joinType: JoinType; } -export type AnySQLiteSelect = SQLiteSelect; - export type BuildAliasTable = TTable extends Table ? SQLiteTableWithColumns< UpdateTableConfig; + type: SetOperator; + isAll: boolean; + orderBy?: (SQLiteColumn | SQL | SQL.Aliased)[]; + limit?: number | Placeholder; + offset?: number | Placeholder; + }[]; } -export type JoinFn< - THKT extends SQLiteSelectHKTBase, - TTableName extends string | undefined, - TResultType extends 'sync' | 'async', - TRunResult, - TSelectMode extends SelectMode, +export type SQLiteJoin< + T extends AnySQLiteSelectQueryBuilder, + TDynamic extends boolean, + TJoinType extends JoinType, + TJoinedTable extends SQLiteTable | Subquery | SQLiteViewBase | SQL, + TJoinedName extends GetSelectTableName = GetSelectTableName, +> = T extends any ? SQLiteSelectWithout< + SQLiteSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['resultType'], + T['_']['runResult'], + AppendToResult< + T['_']['tableName'], + T['_']['selection'], + TJoinedName, + TJoinedTable extends SQLiteTable ? TJoinedTable['_']['columns'] + : TJoinedTable extends Subquery | View ? Assume + : never, + T['_']['selectMode'] + >, + T['_']['selectMode'] extends 'partial' ? T['_']['selectMode'] : 'multiple', + AppendToNullabilityMap, + T['_']['dynamic'], + T['_']['excludedMethods'] + >, + TDynamic, + T['_']['excludedMethods'] + > + : never; + +export type SQLiteJoinFn< + T extends AnySQLiteSelectQueryBuilder, + TDynamic extends boolean, TJoinType extends JoinType, - TSelection, - TNullabilityMap extends Record, > = < TJoinedTable extends SQLiteTable | Subquery | SQLiteViewBase | SQL, TJoinedName extends GetSelectTableName = GetSelectTableName, ->(table: TJoinedTable, on: ((aliases: TSelection) => SQL | undefined) | SQL | undefined) => SQLiteSelectKind< - THKT, - TTableName, - TResultType, - TRunResult, - AppendToResult< - TTableName, - TSelection, - TJoinedName, - TJoinedTable extends SQLiteTable ? TJoinedTable['_']['columns'] - : TJoinedTable extends Subquery | View ? Assume - : never, - TSelectMode - >, - TSelectMode extends 'partial' ? TSelectMode : 'multiple', - AppendToNullabilityMap ->; +>( + table: TJoinedTable, + on: ((aliases: T['_']['selection']) => SQL | undefined) | SQL | undefined, +) => SQLiteJoin; export type SelectedFieldsFlat = SelectFieldsFlatBase; @@ -105,6 +129,10 @@ export interface SQLiteSelectHKTBase { selection: unknown; selectMode: SelectMode; nullabilityMap: unknown; + dynamic: boolean; + excludedMethods: string; + result: unknown; + selectedFields: unknown; _type: unknown; } @@ -113,9 +141,13 @@ export type SQLiteSelectKind< TTableName extends string | undefined, TResultType extends 'sync' | 'async', TRunResult, - TSelection, + TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record, + TDynamic extends boolean, + TExcludedMethods extends string, + TResult = SelectResult[], + TSelectedFields = BuildSubquerySelection, > = (T & { tableName: TTableName; resultType: TResultType; @@ -123,27 +155,309 @@ export type SQLiteSelectKind< selection: TSelection; selectMode: TSelectMode; nullabilityMap: TNullabilityMap; + dynamic: TDynamic; + excludedMethods: TExcludedMethods; + result: TResult; + selectedFields: TSelectedFields; })['_type']; export interface SQLiteSelectQueryBuilderHKT extends SQLiteSelectHKTBase { - _type: SQLiteSelectQueryBuilder< - this, + _type: SQLiteSelectQueryBuilderBase< + SQLiteSelectQueryBuilderHKT, this['tableName'], this['resultType'], this['runResult'], Assume, this['selectMode'], - Assume> + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume >; } export interface SQLiteSelectHKT extends SQLiteSelectHKTBase { - _type: SQLiteSelect< + _type: SQLiteSelectBase< this['tableName'], this['resultType'], this['runResult'], Assume, this['selectMode'], - Assume> + Assume>, + this['dynamic'], + this['excludedMethods'], + Assume, + Assume >; } + +export type SQLiteSetOperatorExcludedMethods = + | 'config' + | 'leftJoin' + | 'rightJoin' + | 'innerJoin' + | 'fullJoin' + | 'where' + | 'having' + | 'groupBy'; + +export type CreateSQLiteSelectFromBuilderMode< + TBuilderMode extends 'db' | 'qb', + TTableName extends string | undefined, + TResultType extends 'sync' | 'async', + TRunResult, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode, +> = TBuilderMode extends 'db' ? SQLiteSelectBase< + TTableName, + TResultType, + TRunResult, + TSelection, + TSelectMode + > + : SQLiteSelectQueryBuilderBase< + SQLiteSelectQueryBuilderHKT, + TTableName, + TResultType, + TRunResult, + TSelection, + TSelectMode + >; + +export type SQLiteSelectWithout< + T extends AnySQLiteSelectQueryBuilder, + TDynamic extends boolean, + K extends keyof T & string, + TResetExcluded extends boolean = false, +> = TDynamic extends true ? T : Omit< + SQLiteSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['nullabilityMap'], + TDynamic, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K, + T['_']['result'], + T['_']['selectedFields'] + >, + TResetExcluded extends true ? K : T['_']['excludedMethods'] | K +>; + +export type SQLiteSelectExecute = T['_']['result']; + +export type SQLiteSelectPrepare = SQLitePreparedQuery< + { + type: T['_']['resultType']; + run: T['_']['runResult']; + all: T['_']['result']; + get: T['_']['result'][number] | undefined; + values: any[][]; + execute: SQLiteSelectExecute; + } +>; + +export type SQLiteSelectDynamic = SQLiteSelectKind< + T['_']['hkt'], + T['_']['tableName'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['selection'], + T['_']['selectMode'], + T['_']['nullabilityMap'], + true, + never, + T['_']['result'], + T['_']['selectedFields'] +>; + +export type SQLiteSelectQueryBuilder< + THKT extends SQLiteSelectHKTBase = SQLiteSelectQueryBuilderHKT, + TTableName extends string | undefined = string | undefined, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, + TSelection extends ColumnsSelection = ColumnsSelection, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, + TResult extends any[] = unknown[], + TSelectedFields extends ColumnsSelection = ColumnsSelection, +> = SQLiteSelectQueryBuilderBase< + THKT, + TTableName, + TResultType, + TRunResult, + TSelection, + TSelectMode, + TNullabilityMap, + true, + never, + TResult, + TSelectedFields +>; + +export type AnySQLiteSelectQueryBuilder = SQLiteSelectQueryBuilderBase< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any +>; + +export type AnySQLiteSetOperatorInterface = SQLiteSetOperatorInterface; + +export interface SQLiteSetOperatorInterface< + TTableName extends string | undefined, + TResultType extends 'sync' | 'async', + TRunResult, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode = 'single', + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +> { + _: { + readonly hkt: SQLiteSelectHKTBase; + readonly tableName: TTableName; + readonly resultType: TResultType; + readonly runResult: TRunResult; + readonly selection: TSelection; + readonly selectMode: TSelectMode; + readonly nullabilityMap: TNullabilityMap; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TResult; + readonly selectedFields: TSelectedFields; + }; +} + +export type SQLiteSetOperatorWithResult = SQLiteSetOperatorInterface< + any, + any, + any, + any, + any, + any, + any, + any, + TResult, + any +>; + +export type SQLiteSelect< + TTableName extends string | undefined = string | undefined, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = SQLiteSelectBase; + +export type AnySQLiteSelect = SQLiteSelectBase; + +export type SQLiteSetOperator< + TTableName extends string | undefined = string | undefined, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, + TSelection extends ColumnsSelection = Record, + TSelectMode extends SelectMode = SelectMode, + TNullabilityMap extends Record = Record, +> = SQLiteSelectBase< + TTableName, + TResultType, + TRunResult, + TSelection, + TSelectMode, + TNullabilityMap, + true, + SQLiteSetOperatorExcludedMethods +>; + +export type SetOperatorRightSelect< + TValue extends SQLiteSetOperatorWithResult, + TResult extends any[], +> = TValue extends SQLiteSetOperatorInterface + ? ValidateShape< + TValueResult[number], + TResult[number], + TypedQueryBuilder + > + : TValue; + +export type SetOperatorRestSelect< + TValue extends readonly SQLiteSetOperatorWithResult[], + TResult extends any[], +> = TValue extends [infer First, ...infer Rest] + ? First extends SQLiteSetOperatorInterface + ? Rest extends AnySQLiteSetOperatorInterface[] ? [ + ValidateShape>, + ...SetOperatorRestSelect, + ] + : ValidateShape[]> + : never + : TValue; + +export type SQLiteCreateSetOperatorFn = < + TTableName extends string | undefined, + TResultType extends 'sync' | 'async', + TRunResult, + TSelection extends ColumnsSelection, + TValue extends SQLiteSetOperatorWithResult, + TRest extends SQLiteSetOperatorWithResult[], + TSelectMode extends SelectMode = 'single', + TNullabilityMap extends Record = TTableName extends string ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, +>( + leftSelect: SQLiteSetOperatorInterface< + TTableName, + TResultType, + TRunResult, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + rightSelect: SetOperatorRightSelect, + ...restSelects: SetOperatorRestSelect +) => SQLiteSelectWithout< + SQLiteSelectBase< + TTableName, + TResultType, + TRunResult, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + false, + SQLiteSetOperatorExcludedMethods, + true +>; + +export type GetSQLiteSetOperators = { + union: SQLiteCreateSetOperatorFn; + intersect: SQLiteCreateSetOperatorFn; + except: SQLiteCreateSetOperatorFn; + unionAll: SQLiteCreateSetOperatorFn; +}; diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 5d130f4f8..857a944d8 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -2,11 +2,11 @@ import type { GetColumnData } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { SelectResultFields } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; -import type { Query, SQL, SQLWrapper } from '~/sql/index.ts'; +import type { RunnableQuery } from '~/runnable-query.ts'; +import type { Query, SQL, SQLWrapper } from '~/sql/sql.ts'; import type { SQLiteDialect } from '~/sqlite-core/dialect.ts'; -import type { PreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; +import type { SQLitePreparedQuery, SQLiteSession } from '~/sqlite-core/session.ts'; import { SQLiteTable } from '~/sqlite-core/table.ts'; -import type { InferModel } from '~/table.ts'; import { type DrizzleTypeError, mapUpdateSet, orderSelectedFields, type UpdateSet } from '~/utils.ts'; import type { SelectedFields, SelectedFieldsOrdered } from './select.types.ts'; @@ -42,36 +42,127 @@ export class SQLiteUpdateBuilder< protected dialect: SQLiteDialect, ) {} - set(values: SQLiteUpdateSetSource): SQLiteUpdate { - return new SQLiteUpdate(this.table, mapUpdateSet(this.table, values), this.session, this.dialect); + set(values: SQLiteUpdateSetSource): SQLiteUpdateBase { + return new SQLiteUpdateBase(this.table, mapUpdateSet(this.table, values), this.session, this.dialect); } } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SQLiteUpdate< - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TTable extends SQLiteTable, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TResultType extends 'sync' | 'async', - // eslint-disable-next-line @typescript-eslint/no-unused-vars - TRunResult, - // eslint-disable-next-line @typescript-eslint/no-unused-vars +export type SQLiteUpdateWithout< + T extends AnySQLiteUpdate, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true ? T : Omit< + SQLiteUpdateBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['returning'], + TDynamic, + T['_']['excludedMethods'] | K + >, + T['_']['excludedMethods'] | K +>; + +export type SQLiteUpdateReturningAll = SQLiteUpdateWithout< + SQLiteUpdateBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['table']['$inferSelect'], + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type SQLiteUpdateReturning< + T extends AnySQLiteUpdate, + TDynamic extends boolean, + TSelectedFields extends SelectedFields, +> = SQLiteUpdateWithout< + SQLiteUpdateBase< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + SelectResultFields, + TDynamic, + T['_']['excludedMethods'] + >, + TDynamic, + 'returning' +>; + +export type SQLiteUpdateExecute = T['_']['returning'] extends undefined ? T['_']['runResult'] + : T['_']['returning'][]; + +export type SQLiteUpdatePrepare = SQLitePreparedQuery< + { + type: T['_']['resultType']; + run: T['_']['runResult']; + all: T['_']['returning'] extends undefined ? DrizzleTypeError<'.all() cannot be used without .returning()'> + : T['_']['returning'][]; + get: T['_']['returning'] extends undefined ? DrizzleTypeError<'.get() cannot be used without .returning()'> + : T['_']['returning']; + values: T['_']['returning'] extends undefined ? DrizzleTypeError<'.values() cannot be used without .returning()'> + : any[][]; + execute: SQLiteUpdateExecute; + } +>; + +export type SQLiteUpdateDynamic = SQLiteUpdate< + T['_']['table'], + T['_']['resultType'], + T['_']['runResult'], + T['_']['returning'] +>; + +export type SQLiteUpdate< + TTable extends SQLiteTable = SQLiteTable, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = any, + TReturning extends Record | undefined = Record | undefined, +> = SQLiteUpdateBase; + +type AnySQLiteUpdate = SQLiteUpdateBase; + +export interface SQLiteUpdateBase< + TTable extends SQLiteTable = SQLiteTable, + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, TReturning = undefined, -> extends SQLWrapper, QueryPromise {} + TDynamic extends boolean = false, + TExcludedMethods extends string = never, +> extends SQLWrapper, QueryPromise { + readonly _: { + readonly dialect: 'sqlite'; + readonly table: TTable; + readonly resultType: TResultType; + readonly runResult: TRunResult; + readonly returning: TReturning; + readonly dynamic: TDynamic; + readonly excludedMethods: TExcludedMethods; + readonly result: TReturning extends undefined ? TRunResult : TReturning[]; + }; +} -export class SQLiteUpdate< - TTable extends SQLiteTable, - TResultType extends 'sync' | 'async', - TRunResult, +export class SQLiteUpdateBase< + TTable extends SQLiteTable = SQLiteTable, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TResultType extends 'sync' | 'async' = 'sync' | 'async', + TRunResult = unknown, TReturning = undefined, -> extends QueryPromise implements SQLWrapper { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TDynamic extends boolean = false, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TExcludedMethods extends string = never, +> extends QueryPromise + implements RunnableQuery, SQLWrapper +{ static readonly [entityKind]: string = 'SQLiteUpdate'; - declare readonly _: { - readonly table: TTable; - }; - - private config: SQLiteUpdateConfig; + /** @internal */ + config: SQLiteUpdateConfig; constructor( table: TTable, @@ -83,20 +174,20 @@ export class SQLiteUpdate< this.config = { set, table }; } - where(where: SQL | undefined): Omit { + where(where: SQL | undefined): SQLiteUpdateWithout { this.config.where = where; - return this; + return this as any; } - returning(): SQLiteUpdate>; + returning(): SQLiteUpdateReturningAll; returning( fields: TSelectedFields, - ): SQLiteUpdate>; + ): SQLiteUpdateReturning; returning( fields: SelectedFields = this.config.table[SQLiteTable.Symbol.Columns], - ): SQLiteUpdate> { + ): SQLiteUpdateWithout { this.config.returning = orderSelectedFields(fields); - return this as SQLiteUpdate>; + return this as any; } /** @internal */ @@ -104,27 +195,17 @@ export class SQLiteUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): { sql: Query['sql']; params: Query['params'] } { + toSQL(): Query { const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL()); return rest; } - prepare(isOneTimeQuery?: boolean): PreparedQuery< - { - type: TResultType; - run: TRunResult; - all: TReturning extends undefined ? DrizzleTypeError<'.all() cannot be used without .returning()'> : TReturning[]; - get: TReturning extends undefined ? DrizzleTypeError<'.get() cannot be used without .returning()'> : TReturning; - values: TReturning extends undefined ? DrizzleTypeError<'.values() cannot be used without .returning()'> - : any[][]; - execute: TReturning extends undefined ? TRunResult : TReturning[]; - } - > { + prepare(isOneTimeQuery?: boolean): SQLiteUpdatePrepare { return this.session[isOneTimeQuery ? 'prepareOneTimeQuery' : 'prepareQuery']( this.dialect.sqlToQuery(this.getSQL()), this.config.returning, this.config.returning ? 'all' : 'run', - ) as ReturnType; + ) as SQLiteUpdatePrepare; } run: ReturnType['run'] = (placeholderValues) => { @@ -143,8 +224,11 @@ export class SQLiteUpdate< return this.prepare(true).values(placeholderValues); }; - override async execute(): Promise { - return (this.config.returning ? this.all() : this.run()) as TReturning extends undefined ? TRunResult - : TReturning[]; + override async execute(): Promise> { + return (this.config.returning ? this.all() : this.run()) as SQLiteUpdateExecute; + } + + $dynamic(): SQLiteUpdateDynamic { + return this as any; } } diff --git a/drizzle-orm/src/sqlite-core/session.ts b/drizzle-orm/src/sqlite-core/session.ts index 5f162ec50..0dcfebe38 100644 --- a/drizzle-orm/src/sqlite-core/session.ts +++ b/drizzle-orm/src/sqlite-core/session.ts @@ -1,10 +1,12 @@ import { entityKind } from '~/entity.ts'; import { DrizzleError, TransactionRollbackError } from '~/errors.ts'; -import { type TablesRelationalConfig } from '~/relations.ts'; -import type { Query, SQL } from '~/sql/index.ts'; +import type { TablesRelationalConfig } from '~/relations.ts'; +import type { PreparedQuery } from '~/session.ts'; +import type { Query, SQL } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect, SQLiteSyncDialect } from '~/sqlite-core/dialect.ts'; import { QueryPromise } from '../index.ts'; import { BaseSQLiteDatabase } from './db.ts'; +import type { SQLiteRaw } from './query-builders/raw.ts'; import type { SelectedFieldsOrdered } from './query-builders/select.types.ts'; export interface PreparedQueryConfig { @@ -35,7 +37,7 @@ export class ExecuteResultSync extends QueryPromise { export type ExecuteResult = TType extends 'async' ? Promise : ExecuteResultSync; -export abstract class PreparedQuery { +export abstract class SQLitePreparedQuery implements PreparedQuery { static readonly [entityKind]: string = 'PreparedQuery'; /** @internal */ @@ -44,14 +46,31 @@ export abstract class PreparedQuery { constructor( private mode: 'sync' | 'async', private executeMethod: SQLiteExecuteMethod, + protected query: Query, ) {} + getQuery(): Query { + return this.query; + } + abstract run(placeholderValues?: Record): Result; + mapRunResult(result: unknown, _isFromBatch?: boolean): unknown { + return result; + } + abstract all(placeholderValues?: Record): Result; + mapAllResult(_result: unknown, _isFromBatch?: boolean): unknown { + throw new Error('Not implemented'); + } + abstract get(placeholderValues?: Record): Result; + mapGetResult(_result: unknown, _isFromBatch?: boolean): unknown { + throw new Error('Not implemented'); + } + abstract values(placeholderValues?: Record): Result; execute(placeholderValues?: Record): ExecuteResult { @@ -60,6 +79,20 @@ export abstract class PreparedQuery { } return new ExecuteResultSync(() => this[this.executeMethod](placeholderValues)); } + + mapResult(response: unknown, isFromBatch?: boolean) { + switch (this.executeMethod) { + case 'run': { + return this.mapRunResult(response, isFromBatch); + } + case 'all': { + return this.mapAllResult(response, isFromBatch); + } + case 'get': { + return this.mapGetResult(response, isFromBatch); + } + } + } } export interface SQLiteTransactionConfig { @@ -86,13 +119,13 @@ export abstract class SQLiteSession< fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, - ): PreparedQuery; + ): SQLitePreparedQuery; prepareOneTimeQuery( query: Query, fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, - ): PreparedQuery { + ): SQLitePreparedQuery { return this.prepareQuery(query, fields, executeMethod); } @@ -104,45 +137,53 @@ export abstract class SQLiteSession< run(query: SQL): Result { const staticQuery = this.dialect.sqlToQuery(query); try { - return this.prepareOneTimeQuery(staticQuery, undefined, 'run').run(); + return this.prepareOneTimeQuery(staticQuery, undefined, 'run').run() as Result; } catch (err) { - throw DrizzleError.wrap(err, `Failed to run the query '${staticQuery.sql}'`); + throw new DrizzleError({ cause: err, message: `Failed to run the query '${staticQuery.sql}'` }); } } + /** @internal */ + extractRawRunValueFromBatchResult(result: unknown) { + return result; + } + all(query: SQL): Result { - return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), undefined, 'run').all(); + return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), undefined, 'run').all() as Result; + } + + /** @internal */ + extractRawAllValueFromBatchResult(_result: unknown): unknown { + throw new Error('Not implemented'); } get(query: SQL): Result { - return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), undefined, 'run').get(); + return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), undefined, 'run').get() as Result; + } + + /** @internal */ + extractRawGetValueFromBatchResult(_result: unknown): unknown { + throw new Error('Not implemented'); } values( query: SQL, ): Result { - return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), undefined, 'run').values(); + return this.prepareOneTimeQuery(this.dialect.sqlToQuery(query), undefined, 'run').values() as Result< + TResultKind, + T[] + >; } -} - -interface ResultHKT { - readonly $brand: 'SQLiteResultHKT'; - readonly config: unknown; - readonly type: unknown; -} -interface SyncResultHKT extends ResultHKT { - readonly type: this['config']; + /** @internal */ + extractRawValuesValueFromBatchResult(_result: unknown): unknown { + throw new Error('Not implemented'); + } } -interface AsyncResultHKT extends ResultHKT { - readonly type: Promise; -} +export type Result = { sync: TResult; async: Promise }[TKind]; -export type Result = - (('sync' extends TKind ? SyncResultHKT : AsyncResultHKT) & { - readonly config: TResult; - })['type']; +export type DBResult = { sync: TResult; async: SQLiteRaw }[TKind]; export abstract class SQLiteTransaction< TResultType extends 'sync' | 'async', diff --git a/drizzle-orm/src/sqlite-core/subquery.ts b/drizzle-orm/src/sqlite-core/subquery.ts index 626241594..587f53e7d 100644 --- a/drizzle-orm/src/sqlite-core/subquery.ts +++ b/drizzle-orm/src/sqlite-core/subquery.ts @@ -1,6 +1,6 @@ import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; import type { Subquery, WithSubquery } from '~/subquery.ts'; -import { type ColumnsSelection } from '~/view.ts'; +import type { ColumnsSelection } from '~/sql/sql.ts'; export type SubqueryWithSelection = & Subquery> diff --git a/drizzle-orm/src/sqlite-core/unique-constraint.ts b/drizzle-orm/src/sqlite-core/unique-constraint.ts index 136280d79..83dfcebdd 100644 --- a/drizzle-orm/src/sqlite-core/unique-constraint.ts +++ b/drizzle-orm/src/sqlite-core/unique-constraint.ts @@ -1,5 +1,5 @@ import { entityKind } from '~/entity.ts'; -import { type SQLiteColumn } from './columns/index.ts'; +import type { SQLiteColumn } from './columns/common.ts'; import { SQLiteTable } from './table.ts'; export function uniqueKeyName(table: SQLiteTable, columns: string[]) { diff --git a/drizzle-orm/src/sqlite-core/utils.ts b/drizzle-orm/src/sqlite-core/utils.ts index 0d06dc8ef..2312466c4 100644 --- a/drizzle-orm/src/sqlite-core/utils.ts +++ b/drizzle-orm/src/sqlite-core/utils.ts @@ -1,6 +1,6 @@ import { is } from '~/entity.ts'; import { Table } from '~/table.ts'; -import { ViewBaseConfig } from '~/view.ts'; +import { ViewBaseConfig } from '~/view-common.ts'; import type { Check } from './checks.ts'; import { CheckBuilder } from './checks.ts'; import type { ForeignKey } from './foreign-keys.ts'; @@ -11,7 +11,8 @@ import type { PrimaryKey } from './primary-keys.ts'; import { PrimaryKeyBuilder } from './primary-keys.ts'; import { SQLiteTable } from './table.ts'; import { type UniqueConstraint, UniqueConstraintBuilder } from './unique-constraint.ts'; -import { type SQLiteView, SQLiteViewConfig } from './view.ts'; +import { SQLiteViewConfig } from './view-common.ts'; +import type { SQLiteView } from './view.ts'; export function getTableConfig(table: TTable) { const columns = Object.values(table[SQLiteTable.Symbol.Columns]); diff --git a/drizzle-orm/src/sqlite-core/view-base.ts b/drizzle-orm/src/sqlite-core/view-base.ts new file mode 100644 index 000000000..64f6529d4 --- /dev/null +++ b/drizzle-orm/src/sqlite-core/view-base.ts @@ -0,0 +1,15 @@ +import { entityKind } from '~/entity.ts'; +import type { ColumnsSelection} from '~/sql/sql.ts'; +import { View } from '~/sql/sql.ts'; + +export abstract class SQLiteViewBase< + TName extends string = string, + TExisting extends boolean = boolean, + TSelection extends ColumnsSelection = ColumnsSelection, +> extends View { + static readonly [entityKind]: string = 'SQLiteViewBase'; + + declare _: View['_'] & { + viewBrand: 'SQLiteView'; + }; +} diff --git a/drizzle-orm/src/sqlite-core/view-common.ts b/drizzle-orm/src/sqlite-core/view-common.ts new file mode 100644 index 000000000..ed1c08c96 --- /dev/null +++ b/drizzle-orm/src/sqlite-core/view-common.ts @@ -0,0 +1 @@ +export const SQLiteViewConfig = Symbol.for('drizzle:SQLiteViewConfig'); diff --git a/drizzle-orm/src/sqlite-core/view.ts b/drizzle-orm/src/sqlite-core/view.ts index 8b040ba9e..d07a36ba7 100644 --- a/drizzle-orm/src/sqlite-core/view.ts +++ b/drizzle-orm/src/sqlite-core/view.ts @@ -2,14 +2,15 @@ import type { BuildColumns } from '~/column-builder.ts'; import { entityKind } from '~/entity.ts'; import type { TypedQueryBuilder } from '~/query-builders/query-builder.ts'; import type { AddAliasToSelection } from '~/query-builders/select.types.ts'; -import type { SQL } from '~/sql/index.ts'; -import { SelectionProxyHandler } from '~/subquery.ts'; +import type { ColumnsSelection, SQL } from '~/sql/sql.ts'; import { getTableColumns } from '~/utils.ts'; -import { type ColumnsSelection, View } from '~/view.ts'; import type { SQLiteColumn, SQLiteColumnBuilderBase } from './columns/common.ts'; -import { QueryBuilder } from './query-builders/index.ts'; +import { QueryBuilder } from './query-builders/query-builder.ts'; import type { SelectedFields } from './query-builders/select.types.ts'; import { sqliteTable } from './table.ts'; +import { SQLiteViewConfig } from './view-common.ts'; +import { SQLiteViewBase } from './view-base.ts'; +import { SelectionProxyHandler } from '~/selection-proxy.ts'; export interface ViewBuilderConfig { algorithm?: 'undefined' | 'merge' | 'temptable'; @@ -126,20 +127,6 @@ export class ManualViewBuilder< } } -export abstract class SQLiteViewBase< - TName extends string = string, - TExisting extends boolean = boolean, - TSelection extends ColumnsSelection = ColumnsSelection, -> extends View { - static readonly [entityKind]: string = 'SQLiteViewBase'; - - declare _: View['_'] & { - viewBrand: 'SQLiteView'; - }; -} - -export const SQLiteViewConfig = Symbol.for('drizzle:SQLiteViewConfig'); - export class SQLiteView< TName extends string = string, TExisting extends boolean = boolean, diff --git a/drizzle-orm/src/sqlite-proxy/driver.ts b/drizzle-orm/src/sqlite-proxy/driver.ts index 1d2a33cd9..de560f2f1 100644 --- a/drizzle-orm/src/sqlite-proxy/driver.ts +++ b/drizzle-orm/src/sqlite-proxy/driver.ts @@ -7,7 +7,7 @@ import { } from '~/relations.ts'; import { BaseSQLiteDatabase } from '~/sqlite-core/db.ts'; import { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { SQLiteRemoteSession } from './session.ts'; export interface SqliteRemoteResult { diff --git a/drizzle-orm/src/sqlite-proxy/migrator.ts b/drizzle-orm/src/sqlite-proxy/migrator.ts index c5822a8c8..29448e01a 100644 --- a/drizzle-orm/src/sqlite-proxy/migrator.ts +++ b/drizzle-orm/src/sqlite-proxy/migrator.ts @@ -1,6 +1,6 @@ import type { MigrationConfig } from '~/migrator.ts'; import { readMigrationFiles } from '~/migrator.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { SqliteRemoteDatabase } from './driver.ts'; export type ProxyMigrator = (migrationQueries: string[]) => Promise; diff --git a/drizzle-orm/src/sqlite-proxy/session.ts b/drizzle-orm/src/sqlite-proxy/session.ts index e9b09990b..c8f35050c 100644 --- a/drizzle-orm/src/sqlite-proxy/session.ts +++ b/drizzle-orm/src/sqlite-proxy/session.ts @@ -1,8 +1,8 @@ import { entityKind } from '~/entity.ts'; import type { Logger } from '~/logger.ts'; import { NoopLogger } from '~/logger.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import type { SQLiteAsyncDialect } from '~/sqlite-core/dialect.ts'; import { SQLiteTransaction } from '~/sqlite-core/index.ts'; import type { SelectedFieldsOrdered } from '~/sqlite-core/query-builders/select.types.ts'; @@ -11,9 +11,9 @@ import type { SQLiteExecuteMethod, SQLiteTransactionConfig, } from '~/sqlite-core/session.ts'; -import { PreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; +import { SQLitePreparedQuery as PreparedQueryBase, SQLiteSession } from '~/sqlite-core/session.ts'; import { mapResultRow } from '~/utils.ts'; -import { type RemoteCallback, type SqliteRemoteResult } from './driver.ts'; +import type { RemoteCallback, SqliteRemoteResult } from './driver.ts'; export interface SQLiteRemoteSessionOptions { logger?: Logger; @@ -44,7 +44,7 @@ export class SQLiteRemoteSession< fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, ): PreparedQuery { - return new PreparedQuery(this.client, query.sql, query.params, this.logger, fields, executeMethod); + return new PreparedQuery(this.client, query, this.logger, fields, executeMethod); } override async transaction( @@ -94,28 +94,27 @@ export class PreparedQuery constructor( private client: RemoteCallback, - private queryString: string, - private params: unknown[], + query: Query, private logger: Logger, private fields: SelectedFieldsOrdered | undefined, executeMethod: SQLiteExecuteMethod, ) { - super('async', executeMethod); + super('async', executeMethod, query); } run(placeholderValues?: Record): Promise { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); - return this.client(this.queryString, params, 'run'); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + return this.client(this.query.sql, params, 'run'); } async all(placeholderValues?: Record): Promise { - const { fields, queryString, logger, joinsNotNullableMap } = this; + const { fields, query, logger, joinsNotNullableMap } = this; - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); - const { rows } = await this.client(queryString, params, 'all'); + const { rows } = await this.client(query.sql, params, 'all'); if (fields) { return rows.map((row) => mapResultRow(fields, row, joinsNotNullableMap)); @@ -125,12 +124,12 @@ export class PreparedQuery } async get(placeholderValues?: Record): Promise { - const { fields, queryString, logger, joinsNotNullableMap } = this; + const { fields, query, logger, joinsNotNullableMap } = this; - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - logger.logQuery(queryString, params); + const params = fillPlaceholders(query.params, placeholderValues ?? {}); + logger.logQuery(query.sql, params); - const clientResult = await this.client(queryString, params, 'get'); + const clientResult = await this.client(query.sql, params, 'get'); if (fields) { if (clientResult.rows === undefined) { @@ -143,9 +142,9 @@ export class PreparedQuery } async values(placeholderValues?: Record): Promise { - const params = fillPlaceholders(this.params, placeholderValues ?? {}); - this.logger.logQuery(this.queryString, params); - const clientResult = await this.client(this.queryString, params, 'values'); + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}); + this.logger.logQuery(this.query.sql, params); + const clientResult = await this.client(this.query.sql, params, 'values'); return clientResult.rows as T[]; } } diff --git a/drizzle-orm/src/subquery.ts b/drizzle-orm/src/subquery.ts index 094a075be..2f292cf06 100644 --- a/drizzle-orm/src/subquery.ts +++ b/drizzle-orm/src/subquery.ts @@ -1,11 +1,12 @@ -import { ColumnAliasProxyHandler, TableAliasProxyHandler } from './alias.ts'; -import { Column } from './column.ts'; -import { entityKind, is } from './entity.ts'; -import { SQL, type SQLWrapper } from './sql/index.ts'; -import { type ColumnsSelection, View, ViewBaseConfig } from './view.ts'; +import { entityKind } from './entity.ts'; +import type { SQL, SQLWrapper, ColumnsSelection } from './sql/sql.ts'; export const SubqueryConfig = Symbol.for('drizzle:SubqueryConfig'); +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export interface Subquery extends SQLWrapper { + // SQLWrapper runtime implementation is defined in 'sql/sql.ts' +} export class Subquery implements SQLWrapper { static readonly [entityKind]: string = 'Subquery'; @@ -32,126 +33,11 @@ export class Subquery }; } - getSQL(): SQL { - return new SQL([this]); - } + // getSQL(): SQL { + // return new SQL([this]); + // } } export class WithSubquery extends Subquery { static readonly [entityKind]: string = 'WithSubquery'; -} - -export class SelectionProxyHandler | View> - implements ProxyHandler | View> -{ - static readonly [entityKind]: string = 'SelectionProxyHandler'; - - private config: { - /** - * Table alias for the columns - */ - alias?: string; - /** - * What to do when a field is an instance of `SQL.Aliased` and it's not a selection field (from a subquery) - * - * `sql` - return the underlying SQL expression - * - * `alias` - return the field alias - */ - sqlAliasedBehavior: 'sql' | 'alias'; - /** - * What to do when a field is an instance of `SQL` and it doesn't have an alias declared - * - * `sql` - return the underlying SQL expression - * - * `error` - return a DrizzleTypeError on type level and throw an error on runtime - */ - sqlBehavior: 'sql' | 'error'; - - /** - * Whether to replace the original name of the column with the alias - * Should be set to `true` for views creation - * @default false - */ - replaceOriginalName?: boolean; - }; - - constructor(config: SelectionProxyHandler['config']) { - this.config = { ...config }; - } - - get(subquery: T, prop: string | symbol): any { - if (prop === SubqueryConfig) { - return { - ...subquery[SubqueryConfig as keyof typeof subquery], - selection: new Proxy( - (subquery as Subquery)[SubqueryConfig].selection, - this as ProxyHandler>, - ), - }; - } - - if (prop === ViewBaseConfig) { - return { - ...subquery[ViewBaseConfig as keyof typeof subquery], - selectedFields: new Proxy( - (subquery as View)[ViewBaseConfig].selectedFields, - this as ProxyHandler>, - ), - }; - } - - if (typeof prop === 'symbol') { - return subquery[prop as keyof typeof subquery]; - } - - const columns = is(subquery, Subquery) - ? subquery[SubqueryConfig].selection - : is(subquery, View) - ? subquery[ViewBaseConfig].selectedFields - : subquery; - const value: unknown = columns[prop as keyof typeof columns]; - - if (is(value, SQL.Aliased)) { - // Never return the underlying SQL expression for a field previously selected in a subquery - if (this.config.sqlAliasedBehavior === 'sql' && !value.isSelectionField) { - return value.sql; - } - - const newValue = value.clone(); - newValue.isSelectionField = true; - return newValue; - } - - if (is(value, SQL)) { - if (this.config.sqlBehavior === 'sql') { - return value; - } - - throw new Error( - `You tried to reference "${prop}" field from a subquery, which is a raw SQL field, but it doesn't have an alias declared. Please add an alias to the field using ".as('alias')" method.`, - ); - } - - if (is(value, Column)) { - if (this.config.alias) { - return new Proxy( - value, - new ColumnAliasProxyHandler( - new Proxy( - value.table, - new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false), - ), - ), - ); - } - return value; - } - - if (typeof value !== 'object' || value === null) { - return value; - } - - return new Proxy(value, new SelectionProxyHandler(this.config)); - } -} +} \ No newline at end of file diff --git a/drizzle-orm/src/table.ts b/drizzle-orm/src/table.ts index a6e6f0fc7..1ce1019a9 100644 --- a/drizzle-orm/src/table.ts +++ b/drizzle-orm/src/table.ts @@ -1,8 +1,8 @@ import type { Column, GetColumnData } from './column.ts'; import { entityKind } from './entity.ts'; import type { OptionalKeyOnly, RequiredKeyOnly } from './operations.ts'; -import { SQL, type SQLWrapper } from './sql/index.ts'; -import { type Simplify, type Update } from './utils.ts'; +import type { SQLWrapper } from './sql/sql.ts'; +import type { Simplify, Update } from './utils.ts'; export interface TableConfig> { name: string; @@ -38,6 +38,13 @@ export const ExtraConfigBuilder = Symbol.for('drizzle:ExtraConfigBuilder'); const IsDrizzleTable = Symbol.for('drizzle:IsDrizzleTable'); +export interface Table< + // eslint-disable-next-line @typescript-eslint/no-unused-vars + T extends TableConfig = TableConfig, +> extends SQLWrapper { + // SQLWrapper runtime implementation is defined in 'sql/sql.ts' +} + export class Table implements SQLWrapper { static readonly [entityKind]: string = 'Table'; @@ -102,17 +109,30 @@ export class Table implements SQLWrapper { this[Schema] = schema; this[BaseName] = baseName; } - - getSQL(): SQL { - return new SQL([this]); - } } export function isTable(table: unknown): table is Table { return typeof table === 'object' && table !== null && IsDrizzleTable in table; } -export type AnyTable = {}> = Table>; +/** + * Any table with a specified boundary. + * + * @example + ```ts + // Any table with a specific name + type AnyUsersTable = AnyTable<{ name: 'users' }>; + ``` + * + * To describe any table with any config, simply use `Table` without any type arguments, like this: + * + ```ts + function needsTable(table: Table) { + ... + } + ``` + */ +export type AnyTable> = Table>; export function getTableName(table: T): T['_']['name'] { return table[TableName]; @@ -155,7 +175,7 @@ export type InferModelFromColumns< } >; -/** @deprecated Use one of the alternatives: {@link InferSelectModel} / {@link InferInsertModel}, or `table._.inferSelect` / `table._.inferInsert` +/** @deprecated Use one of the alternatives: {@link InferSelectModel} / {@link InferInsertModel}, or `table.$inferSelect` / `table.$inferInsert` */ export type InferModel< TTable extends Table, diff --git a/drizzle-orm/src/tracing-utils.ts b/drizzle-orm/src/tracing-utils.ts new file mode 100644 index 000000000..b4809af25 --- /dev/null +++ b/drizzle-orm/src/tracing-utils.ts @@ -0,0 +1,3 @@ +export function iife(fn: (...args: T) => U, ...args: T): U { + return fn(...args); +} \ No newline at end of file diff --git a/drizzle-orm/src/tracing.ts b/drizzle-orm/src/tracing.ts index d18c2832e..7d5fd165b 100644 --- a/drizzle-orm/src/tracing.ts +++ b/drizzle-orm/src/tracing.ts @@ -1,5 +1,5 @@ import type { Span, Tracer } from '@opentelemetry/api'; -import { iife } from '~/utils.ts'; +import { iife } from '~/tracing-utils.ts'; import { npmVersion } from '~/version.ts'; let otel: typeof import('@opentelemetry/api') | undefined; diff --git a/drizzle-orm/src/utils.ts b/drizzle-orm/src/utils.ts index 94bf55fa5..da759f2f7 100644 --- a/drizzle-orm/src/utils.ts +++ b/drizzle-orm/src/utils.ts @@ -1,14 +1,14 @@ import type { AnyColumn } from './column.ts'; import { Column } from './column.ts'; import { is } from './entity.ts'; -import { type Logger } from './logger.ts'; +import type { Logger } from './logger.ts'; import type { SelectedFieldsOrdered } from './operations.ts'; -import { type TableLike } from './query-builders/select.types.ts'; -import { Param, SQL } from './sql/index.ts'; -import type { DriverValueDecoder } from './sql/index.ts'; +import type { TableLike } from './query-builders/select.types.ts'; +import { Param, SQL, View } from './sql/sql.ts'; +import type { DriverValueDecoder } from './sql/sql.ts'; import { Subquery, SubqueryConfig } from './subquery.ts'; import { getTableName, Table } from './table.ts'; -import { View, ViewBaseConfig } from './view.ts'; +import { ViewBaseConfig } from './view-common.ts'; /** @internal */ export function mapResultRow( @@ -91,6 +91,23 @@ export function orderSelectedFields( }, []) as SelectedFieldsOrdered; } +export function haveSameKeys(left: Record, right: Record) { + const leftKeys = Object.keys(left); + const rightKeys = Object.keys(right); + + if (leftKeys.length !== rightKeys.length) { + return false; + } + + for (const [index, key] of leftKeys.entries()) { + if (key !== rightKeys[index]) { + return false; + } + } + + return true; +} + /** @internal */ export function mapUpdateSet(table: Table, values: Record): UpdateSet { const entries: [string, UpdateSet[string]][] = Object.entries(values) @@ -193,6 +210,12 @@ export interface DrizzleConfig = Record< logger?: boolean | Logger; schema?: TSchema; } +export type ValidateShape = T extends ValidShape + ? Exclude extends never ? TResult + : DrizzleTypeError< + `Invalid key(s): ${Exclude<(keyof T) & (string | number | bigint | boolean | null | undefined), keyof ValidShape>}` + > + : never; export type ValidateShape = T extends ValidShape ? Exclude extends never ? T : Exclude extends string ? `Invalid key(s): ${Exclude}` @@ -203,8 +226,4 @@ export type KnownKeysOnly = { [K in keyof T]: K extends keyof U ? T[K] : never; }; -export function iife(fn: (...args: T) => U, ...args: T): U { - return fn(...args); -} - export type IsAny = 0 extends (1 & T) ? true : false; diff --git a/drizzle-orm/src/vercel-postgres/driver.ts b/drizzle-orm/src/vercel-postgres/driver.ts index 91fd5c3a2..bdbc49def 100644 --- a/drizzle-orm/src/vercel-postgres/driver.ts +++ b/drizzle-orm/src/vercel-postgres/driver.ts @@ -9,7 +9,7 @@ import { type RelationalSchemaConfig, type TablesRelationalConfig, } from '~/relations.ts'; -import { type DrizzleConfig } from '~/utils.ts'; +import type { DrizzleConfig } from '~/utils.ts'; import { type VercelPgClient, type VercelPgQueryResultHKT, VercelPgSession } from './session.ts'; export interface VercelPgDriverOptions { diff --git a/drizzle-orm/src/vercel-postgres/session.ts b/drizzle-orm/src/vercel-postgres/session.ts index cbb714935..f85748b46 100644 --- a/drizzle-orm/src/vercel-postgres/session.ts +++ b/drizzle-orm/src/vercel-postgres/session.ts @@ -13,8 +13,8 @@ import { type PgDialect, PgTransaction } from '~/pg-core/index.ts'; import type { SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types.ts'; import type { PgTransactionConfig, PreparedQueryConfig, QueryResultHKT } from '~/pg-core/session.ts'; import { PgSession, PreparedQuery } from '~/pg-core/session.ts'; -import { type RelationalSchemaConfig, type TablesRelationalConfig } from '~/relations.ts'; -import { fillPlaceholders, type Query, sql } from '~/sql/index.ts'; +import type { RelationalSchemaConfig, TablesRelationalConfig } from '~/relations.ts'; +import { fillPlaceholders, type Query, sql } from '~/sql/sql.ts'; import { type Assume, mapResultRow } from '~/utils.ts'; export type VercelPgClient = VercelPool | VercelClient | VercelPoolClient; diff --git a/drizzle-orm/src/version.ts b/drizzle-orm/src/version.ts index 355672c5f..d70a05d15 100644 --- a/drizzle-orm/src/version.ts +++ b/drizzle-orm/src/version.ts @@ -1,3 +1,3 @@ -// @ts-expect-error - imported using Rollup json plugin +// @ts-ignore - imported using Rollup json plugin export { version as npmVersion } from '../package.json'; -export const compatibilityVersion = 5; +export const compatibilityVersion = 6; diff --git a/drizzle-orm/src/view-common.ts b/drizzle-orm/src/view-common.ts new file mode 100644 index 000000000..f1537fb1b --- /dev/null +++ b/drizzle-orm/src/view-common.ts @@ -0,0 +1 @@ +export const ViewBaseConfig = Symbol.for('drizzle:ViewBaseConfig'); diff --git a/drizzle-orm/src/view.ts b/drizzle-orm/src/view.ts deleted file mode 100644 index 28b912432..000000000 --- a/drizzle-orm/src/view.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { AnyColumn } from './column.ts'; -import { entityKind } from './entity.ts'; -import type { SelectedFields } from './operations.ts'; -import { SQL, type SQLWrapper } from './sql/index.ts'; -import type { Table } from './table.ts'; - -export const ViewBaseConfig = Symbol.for('drizzle:ViewBaseConfig'); - -export type ColumnsSelection = Record; - -export abstract class View< - TName extends string = string, - TExisting extends boolean = boolean, - TSelection extends ColumnsSelection = ColumnsSelection, -> implements SQLWrapper { - static readonly [entityKind]: string = 'View'; - - declare _: { - brand: 'View'; - viewBrand: string; - name: TName; - existing: TExisting; - selectedFields: TSelection; - }; - - /** @internal */ - [ViewBaseConfig]: { - name: TName; - originalName: TName; - schema: string | undefined; - selectedFields: SelectedFields; - isExisting: TExisting; - query: TExisting extends true ? undefined : SQL; - isAlias: boolean; - }; - - constructor( - { name, schema, selectedFields, query }: { - name: TName; - schema: string | undefined; - selectedFields: SelectedFields; - query: SQL | undefined; - }, - ) { - this[ViewBaseConfig] = { - name, - originalName: name, - schema, - selectedFields, - query: query as (TExisting extends true ? undefined : SQL), - isExisting: !query as TExisting, - isAlias: false, - }; - } - - getSQL(): SQL { - return new SQL([this]); - } -} diff --git a/drizzle-orm/tests/tsconfig.json b/drizzle-orm/tests/tsconfig.json index d3e519834..851b0a8fd 100644 --- a/drizzle-orm/tests/tsconfig.json +++ b/drizzle-orm/tests/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "../tsconfig.build.json", "compilerOptions": { - "module": "esnext", - "target": "esnext", - "noEmit": true, - "rootDir": "..", - "outDir": "./.cache" + "rootDir": ".." }, "include": [".", "../src"] } diff --git a/drizzle-orm/tsconfig.build.json b/drizzle-orm/tsconfig.build.json index f8c8deaeb..b57ab6b00 100644 --- a/drizzle-orm/tsconfig.build.json +++ b/drizzle-orm/tsconfig.build.json @@ -1,17 +1,4 @@ { - "extends": "../tsconfig.json", - "compilerOptions": { - "composite": true, - "baseUrl": ".", - "verbatimModuleSyntax": true, - "moduleResolution": "NodeNext", - "allowImportingTsExtensions": true, - "noEmit": true, - "incremental": true, - "paths": { - "~/*": ["src/*"] - }, - "outDir": "dist.new" - }, + "extends": "./tsconfig.json", "include": ["src"] } diff --git a/drizzle-orm/tsconfig.cjs.json b/drizzle-orm/tsconfig.cjs.json deleted file mode 100644 index fa57f71e1..000000000 --- a/drizzle-orm/tsconfig.cjs.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.build.json", - "compilerOptions": { - "target": "es2020", - "module": "es2020", - "rootDir": "src" - } -} diff --git a/drizzle-orm/tsconfig.config.json b/drizzle-orm/tsconfig.config.json deleted file mode 100644 index 2fe7f262b..000000000 --- a/drizzle-orm/tsconfig.config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "composite": true - }, - "include": ["./*.ts", "scripts"] -} diff --git a/drizzle-orm/tsconfig.esm.json b/drizzle-orm/tsconfig.esm.json deleted file mode 100644 index 4a7f09d1d..000000000 --- a/drizzle-orm/tsconfig.esm.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.build.json", - "compilerOptions": { - "rootDir": "src" - }, - "include": ["src"] -} diff --git a/drizzle-orm/tsconfig.json b/drizzle-orm/tsconfig.json index c63720fd3..6be05cc9e 100644 --- a/drizzle-orm/tsconfig.json +++ b/drizzle-orm/tsconfig.json @@ -1,12 +1,13 @@ { - "files": [], - "references": [ - { - "path": "./tsconfig.build.json" + "extends": "../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "~/*": ["src/*"] }, - { - "path": "./tsconfig.config.json" - } - ], - "include": ["rollup.*.ts"] + "declaration": true, + "outDir": "dist", + "noEmit": true + }, + "include": ["src", "scripts"] } diff --git a/drizzle-orm/tsup.config.ts b/drizzle-orm/tsup.config.ts new file mode 100644 index 000000000..482596485 --- /dev/null +++ b/drizzle-orm/tsup.config.ts @@ -0,0 +1,19 @@ +import { globSync } from 'glob'; +import { defineConfig } from 'tsup'; + +const entries = globSync('src/**/*.ts'); + +export default defineConfig({ + entry: entries, + outDir: 'dist.new', + format: ['cjs', 'esm'], + bundle: false, + splitting: false, + sourcemap: true, + outExtension({ format }) { + return { + js: format === 'cjs' ? '.cjs' : '.js', + }; + }, + tsconfig: 'tsconfig.build.json', +}); diff --git a/drizzle-orm/type-tests/mysql/db-rel.ts b/drizzle-orm/type-tests/mysql/db-rel.ts index 0d528b186..957e6c9ce 100644 --- a/drizzle-orm/type-tests/mysql/db-rel.ts +++ b/drizzle-orm/type-tests/mysql/db-rel.ts @@ -1,7 +1,7 @@ import pg from 'pg'; import { type Equal, Expect } from 'type-tests/utils.ts'; import { drizzle } from '~/node-postgres/index.ts'; -import { placeholder, sql } from '~/sql/index.ts'; +import { placeholder, sql } from '~/sql/sql.ts'; import * as schema from './tables-rel.ts'; const { Pool } = pg; diff --git a/drizzle-orm/type-tests/mysql/delete.ts b/drizzle-orm/type-tests/mysql/delete.ts index 0842ae963..c3e5afbb2 100644 --- a/drizzle-orm/type-tests/mysql/delete.ts +++ b/drizzle-orm/type-tests/mysql/delete.ts @@ -1,7 +1,9 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { eq } from '~/expressions.ts'; +import type { MySqlDelete } from '~/mysql-core/index.ts'; import type { MySqlRawQueryResult } from '~/mysql2/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { users } from './tables.ts'; @@ -32,3 +34,28 @@ Expect>; const deleteReturningPartialStmt = db.delete(users).prepare(); const deleteReturningPartialPrepared = await deleteReturningPartialStmt.execute(); Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .$dynamic() + .where(sql``) + .where(sql``); +} diff --git a/drizzle-orm/type-tests/mysql/insert.ts b/drizzle-orm/type-tests/mysql/insert.ts index e739e49b1..7faa7726a 100644 --- a/drizzle-orm/type-tests/mysql/insert.ts +++ b/drizzle-orm/type-tests/mysql/insert.ts @@ -1,8 +1,8 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { int, mysqlTable, text } from '~/mysql-core/index.ts'; +import { int, type MySqlInsert, mysqlTable, text } from '~/mysql-core/index.ts'; import type { MySqlRawQueryResult } from '~/mysql2/index.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { users } from './tables.ts'; @@ -129,3 +129,23 @@ db.insert(users).values(usersWithExtraKeys); await db.insert(users).values({ name: 'John Wick', age: 58, occupation: 'housekeeper' }); } + +{ + function dynamic(qb: T) { + return qb.onDuplicateKeyUpdate({ set: {} }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0 }) + .onDuplicateKeyUpdate({ set: {} }) + // @ts-expect-error method was already called + .onDuplicateKeyUpdate({ set: {} }); +} diff --git a/drizzle-orm/type-tests/mysql/select.ts b/drizzle-orm/type-tests/mysql/select.ts index 17c9d12b3..0a6af743b 100644 --- a/drizzle-orm/type-tests/mysql/select.ts +++ b/drizzle-orm/type-tests/mysql/select.ts @@ -22,10 +22,11 @@ import { or, } from '~/expressions.ts'; import { alias } from '~/mysql-core/alias.ts'; -import { param, sql } from '~/sql/index.ts'; +import { param, sql } from '~/sql/sql.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; +import { type MySqlSelect, type MySqlSelectQueryBuilder, QueryBuilder } from '~/mysql-core/index.ts'; import { db } from './db.ts'; import { cities, classes, newYorkers, users } from './tables.ts'; @@ -433,3 +434,173 @@ await db Expect>(); } } + +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +{ + // TODO: add to docs + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const query = new QueryBuilder().select().from(users).$dynamic(); + dynamic(query); +} + +{ + // TODO: add to docs + function paginated(qb: T, page: number) { + return qb.limit(10).offset((page - 1) * 10); + } + + const qb = db.select().from(users).$dynamic(); + const result = await paginated(qb, 1); + + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); + + db + .select() + .from(users) + .for('update') + .limit(10) + // @ts-expect-error method was already called + .for('update'); +} diff --git a/drizzle-orm/type-tests/mysql/set-operators.ts b/drizzle-orm/type-tests/mysql/set-operators.ts new file mode 100644 index 000000000..9afac2346 --- /dev/null +++ b/drizzle-orm/type-tests/mysql/set-operators.ts @@ -0,0 +1,286 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { + except, + exceptAll, + intersect, + intersectAll, + type MySqlSetOperator, + union, + unionAll, +} from '~/mysql-core/index.ts'; +import { desc, sql } from '~/sql/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, age: users.age1 }) + .from(users) + .unionAll( + db.select({ id: users.id, age: users.age1 }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const intersectAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .intersect( + db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const exceptAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql<'A' | 'C'>`${users.class}` }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +const intersectAll2Test = await intersectAll( + union( + db.select({ + id: cities.id, + }).from(cities), + db.select({ + id: cities.id, + }) + .from(cities).where(sql``), + ), + db.select({ + id: cities.id, + }) + .from(cities), +).orderBy(desc(cities.id)).limit(23); + +Expect>; + +const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; + +const exceptAll2Test = await exceptAll( + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }) + .from(newYorkers).where(sql``), + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }).from(newYorkers).leftJoin(newYorkers, sql``), +); + +Expect>; + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + text: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: newYorkers.userId }).from(newYorkers), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/mysql/subquery.ts b/drizzle-orm/type-tests/mysql/subquery.ts index 920520e45..e559b80db 100644 --- a/drizzle-orm/type-tests/mysql/subquery.ts +++ b/drizzle-orm/type-tests/mysql/subquery.ts @@ -1,7 +1,7 @@ import { Expect } from 'type-tests/utils.ts'; import { and, eq } from '~/expressions.ts'; import { alias, int, mysqlTable, serial, text } from '~/mysql-core/index.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { DrizzleTypeError, Equal } from '~/utils.ts'; import { db } from './db.ts'; @@ -83,3 +83,15 @@ Expect< const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); Expect ? true : false>; } + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index ea1aaf42d..6eac879da 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -1,6 +1,6 @@ import { type Equal, Expect } from 'type-tests/utils.ts'; import { eq, gt } from '~/expressions.ts'; -import { type BuildColumn, type InferSelectModel, type Simplify } from '~/index.ts'; +import type { BuildColumn, InferSelectModel, Simplify } from '~/index.ts'; import { bigint, char, @@ -27,7 +27,7 @@ import { } from '~/mysql-core/index.ts'; import { mysqlSchema } from '~/mysql-core/schema.ts'; import { mysqlView, type MySqlViewWithSelection } from '~/mysql-core/view.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; export const users = mysqlTable( diff --git a/drizzle-orm/type-tests/mysql/update.ts b/drizzle-orm/type-tests/mysql/update.ts new file mode 100644 index 000000000..dc6967f44 --- /dev/null +++ b/drizzle-orm/type-tests/mysql/update.ts @@ -0,0 +1,26 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import type { MySqlUpdate } from '~/mysql-core/index.ts'; +import type { MySqlRawQueryResult } from '~/mysql2/session.ts'; +import { sql } from '~/sql/sql.ts'; +import { db } from './db.ts'; +import { users } from './tables.ts'; + +{ + function dynamic(qb: T) { + return qb.where(sql``); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} diff --git a/drizzle-orm/type-tests/mysql/with.ts b/drizzle-orm/type-tests/mysql/with.ts index eb36e520f..338f9c43b 100644 --- a/drizzle-orm/type-tests/mysql/with.ts +++ b/drizzle-orm/type-tests/mysql/with.ts @@ -2,7 +2,7 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { gt, inArray } from '~/expressions.ts'; import { int, mysqlTable, serial, text } from '~/mysql-core/index.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; const orders = mysqlTable('orders', { diff --git a/drizzle-orm/type-tests/pg/array.ts b/drizzle-orm/type-tests/pg/array.ts index 104849901..03ea190b4 100644 --- a/drizzle-orm/type-tests/pg/array.ts +++ b/drizzle-orm/type-tests/pg/array.ts @@ -1,5 +1,5 @@ import { type Equal, Expect } from 'type-tests/utils.ts'; -import { type Column } from '~/column.ts'; +import type { Column } from '~/column.ts'; import { integer, pgTable } from '~/pg-core/index.ts'; { diff --git a/drizzle-orm/type-tests/pg/db-rel.ts b/drizzle-orm/type-tests/pg/db-rel.ts index 3e90fbb8e..c8cc63c7f 100644 --- a/drizzle-orm/type-tests/pg/db-rel.ts +++ b/drizzle-orm/type-tests/pg/db-rel.ts @@ -1,7 +1,7 @@ import pg from 'pg'; import { type Equal, Expect } from 'type-tests/utils.ts'; import { drizzle } from '~/node-postgres/index.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import * as schema from './tables-rel.ts'; const { Pool } = pg; diff --git a/drizzle-orm/type-tests/pg/delete.ts b/drizzle-orm/type-tests/pg/delete.ts index 66eddc0c3..6421db090 100644 --- a/drizzle-orm/type-tests/pg/delete.ts +++ b/drizzle-orm/type-tests/pg/delete.ts @@ -2,6 +2,8 @@ import type { QueryResult } from 'pg'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { eq } from '~/expressions.ts'; +import type { PgDelete } from '~/pg-core/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { users } from './tables.ts'; @@ -38,3 +40,39 @@ const deleteReturningPartialStmt = db.delete(users).returning({ }).prepare('deleteReturningPartialStmt'); const deleteReturningPartialPrepared = await deleteReturningPartialStmt.execute(); Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``).returning(); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + function withReturning(qb: T) { + return qb.returning(); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = withReturning(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .returning() + // @ts-expect-error method was already called + .returning(); +} diff --git a/drizzle-orm/type-tests/pg/insert.ts b/drizzle-orm/type-tests/pg/insert.ts index 19aca71c3..6a5179804 100644 --- a/drizzle-orm/type-tests/pg/insert.ts +++ b/drizzle-orm/type-tests/pg/insert.ts @@ -1,7 +1,8 @@ import type { QueryResult } from 'pg'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { sql } from '~/sql/index.ts'; +import type { PgInsert } from '~/pg-core/query-builders/insert.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { users } from './tables.ts'; @@ -12,6 +13,7 @@ const insert = await db class: 'A', age1: 1, enumCol: 'a', + arrayCol: [''], }); Expect, typeof insert>>; @@ -22,6 +24,7 @@ const insertStmt = db class: 'A', age1: 1, enumCol: 'a', + arrayCol: [''], }) .prepare('insertStmt'); const insertPrepared = await insertStmt.execute(); @@ -32,6 +35,7 @@ const insertSql = await db.insert(users).values({ class: 'A', age1: 1, enumCol: sql`foobar`, + arrayCol: [''], }); Expect, typeof insertSql>>; @@ -42,6 +46,7 @@ const insertSqlStmt = db class: 'A', age1: 1, enumCol: sql`foobar`, + arrayCol: [''], }) .prepare('insertSqlStmt'); const insertSqlPrepared = await insertSqlStmt.execute(); @@ -54,6 +59,7 @@ const insertReturning = await db class: 'A', age1: 1, enumCol: 'a', + arrayCol: [''], }) .returning(); Expect>; @@ -65,6 +71,7 @@ const insertReturningStmt = db class: 'A', age1: 1, enumCol: 'a', + arrayCol: [''], }) .returning() .prepare('insertReturningStmt'); @@ -78,6 +85,7 @@ const insertReturningPartial = await db class: 'A', age1: 1, enumCol: 'a', + arrayCol: [''], }) .returning({ id: users.id, @@ -99,6 +107,7 @@ const insertReturningPartialStmt = db class: 'A', age1: 1, enumCol: 'a', + arrayCol: [''], }) .returning({ id: users.id, @@ -122,6 +131,7 @@ const insertReturningSql = await db class: 'A', age1: sql`2 + 2`, enumCol: 'a', + arrayCol: [''], }) .returning({ id: users.id, @@ -145,6 +155,7 @@ const insertReturningSqlStmt = db class: 'A', age1: sql`2 + 2`, enumCol: 'a', + arrayCol: [''], }) .returning({ id: users.id, @@ -162,3 +173,34 @@ Expect< classLower: string; }[], typeof insertReturningSqlPrepared> >; + +{ + function dynamic(qb: T) { + return qb.returning().onConflictDoNothing().onConflictDoUpdate({ set: {}, target: users.id, where: sql`` }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0, arrayCol: [] }).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + function withReturning(qb: T) { + return qb.returning(); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0, arrayCol: [] }).$dynamic(); + const qb = withReturning(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0, arrayCol: [] }) + .returning() + // @ts-expect-error method was already called + .returning(); +} diff --git a/drizzle-orm/type-tests/pg/other.ts b/drizzle-orm/type-tests/pg/other.ts index e1e781402..38d41f113 100644 --- a/drizzle-orm/type-tests/pg/other.ts +++ b/drizzle-orm/type-tests/pg/other.ts @@ -1,6 +1,6 @@ import type { QueryResult } from 'pg'; import { eq, inArray } from '~/expressions.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; diff --git a/drizzle-orm/type-tests/pg/select.ts b/drizzle-orm/type-tests/pg/select.ts index 383aaf345..0fde90a71 100644 --- a/drizzle-orm/type-tests/pg/select.ts +++ b/drizzle-orm/type-tests/pg/select.ts @@ -3,6 +3,9 @@ import { Expect } from 'type-tests/utils.ts'; import { and, + arrayContained, + arrayContains, + arrayOverlaps, between, eq, exists, @@ -25,9 +28,16 @@ import { or, } from '~/expressions.ts'; import { alias } from '~/pg-core/alias.ts'; -import { boolean, integer, pgTable, text } from '~/pg-core/index.ts'; -import type { AnyPgSelect } from '~/pg-core/query-builders/select.types.ts'; -import { type SQL, sql } from '~/sql/index.ts'; +import { + boolean, + integer, + type PgSelect, + type PgSelectQueryBuilder, + pgTable, + QueryBuilder, + text, +} from '~/pg-core/index.ts'; +import { type SQL, sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { cities, classes, newYorkers, newYorkers2, users } from './tables.ts'; @@ -278,6 +288,7 @@ Expect< age1: number; createdAt: Date; enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; } | null; cities: { id: number; @@ -421,6 +432,15 @@ const allOperators = await db notLike(users.id, '%1%'), ilike(users.id, '%1%'), notIlike(users.id, '%1%'), + arrayContains(users.arrayCol, ['abc']), + arrayContains(users.arrayCol, db.select({ arrayCol: users.arrayCol }).from(users)), + arrayContains(users.arrayCol, sql`select array_col from ${users}`), + arrayContained(users.arrayCol, ['abc']), + arrayContained(users.arrayCol, db.select({ arrayCol: users.arrayCol }).from(users)), + arrayContained(users.arrayCol, sql`select array_col from ${users}`), + arrayOverlaps(users.arrayCol, ['abc']), + arrayOverlaps(users.arrayCol, db.select({ arrayCol: users.arrayCol }).from(users)), + arrayOverlaps(users.arrayCol, sql`select array_col from ${users}`), ), ); @@ -545,6 +565,7 @@ Expect< age1: number; createdAt: Date; enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; }; currentCity: { id: number; @@ -564,6 +585,7 @@ Expect< age1: number; createdAt: Date; enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; }; closestCity: { id: number; @@ -662,6 +684,7 @@ Expect< age1: number; createdAt: Date; enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; } | null; currentCity: { id: number; @@ -681,6 +704,7 @@ Expect< age1: number; createdAt: Date; enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; } | null; closestCity: { id: number; @@ -811,6 +835,7 @@ Expect< age1: number; createdAt: Date; enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; }; }[], typeof join4> >; @@ -839,10 +864,26 @@ Expect< await db .select() .from(users) - .for('update') - .for('no key update', { of: users }) - .for('no key update', { of: users, skipLocked: true }) - .for('share', { of: users, noWait: true }) + .for('update'); + +await db + .select() + .from(users) + .for('no key update', { of: users }); + +await db + .select() + .from(users) + .for('no key update', { of: users, skipLocked: true }); + +await db + .select() + .from(users) + .for('share', { of: users, noWait: true }); + +await db + .select() + .from(users) // @ts-expect-error - can't use both skipLocked and noWait .for('share', { of: users, noWait: true, skipLocked: true }); @@ -908,14 +949,174 @@ await db >; } +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + { // TODO: add to docs - const withPagination = (qb: T) => { - return qb.offset(10).limit(10); - }; + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1).for('update'); + } + + const query = new QueryBuilder().select().from(users).$dynamic(); + dynamic(query); +} + +{ + // TODO: add to docs + function paginated(qb: T, page: number) { + return qb.limit(10).offset((page - 1) * 10); + } + + const qb = db.select().from(users).$dynamic(); + const result = await paginated(qb, 1); - const qb = db.select().from(users); - await withPagination(qb); + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); + + db + .select() + .from(users) + .for('update') + .limit(10) + // @ts-expect-error method was already called + .for('update'); } { diff --git a/drizzle-orm/type-tests/pg/set-operators.ts b/drizzle-orm/type-tests/pg/set-operators.ts new file mode 100644 index 000000000..3d53c4043 --- /dev/null +++ b/drizzle-orm/type-tests/pg/set-operators.ts @@ -0,0 +1,280 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { except, exceptAll, intersect, intersectAll, type PgSetOperator, union, unionAll } from '~/pg-core/index.ts'; +import { desc, sql } from '~/sql/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, age: users.age1 }) + .from(users) + .unionAll( + db.select({ id: users.id, age: users.age1 }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const intersectAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .intersect( + db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const exceptAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql<'A' | 'C'>`${users.class}` }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +const intersectAll2Test = await intersectAll( + union( + db.select({ + id: cities.id, + }).from(cities), + db.select({ + id: cities.id, + }) + .from(cities).where(sql``), + ), + db.select({ + id: cities.id, + }) + .from(cities), +).orderBy(desc(cities.id)).limit(23); + +Expect>; + +const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; + +const exceptAll2Test = await exceptAll( + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }) + .from(newYorkers).where(sql``), + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }).from(newYorkers).leftJoin(newYorkers, sql``), +); + +Expect>; + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + uuid: string; + homeCity: number; + currentCity: number | null; + serialNullable: number; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + text: string | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + arrayCol: string[]; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: newYorkers.userId }).from(newYorkers), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/pg/subquery.ts b/drizzle-orm/type-tests/pg/subquery.ts index 0af17ccf8..18fdcf4b2 100644 --- a/drizzle-orm/type-tests/pg/subquery.ts +++ b/drizzle-orm/type-tests/pg/subquery.ts @@ -1,7 +1,7 @@ import { Expect } from 'type-tests/utils.ts'; import { and, eq } from '~/expressions.ts'; import { alias, integer, pgTable, serial, text } from '~/pg-core/index.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { DrizzleTypeError, Equal } from '~/utils.ts'; import { db } from './db.ts'; @@ -83,3 +83,15 @@ Expect< const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); Expect ? true : false>; } + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/pg/tables.ts b/drizzle-orm/type-tests/pg/tables.ts index 6dcdc3867..4a940ebcb 100644 --- a/drizzle-orm/type-tests/pg/tables.ts +++ b/drizzle-orm/type-tests/pg/tables.ts @@ -45,7 +45,7 @@ import { pgView, type PgViewWithSelection, } from '~/pg-core/view.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { InferInsertModel, InferSelectModel } from '~/table.ts'; import { db } from './db.ts'; @@ -68,6 +68,7 @@ export const users = pgTable( age1: integer('age1').notNull(), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), enumCol: myEnum('enum_col').notNull(), + arrayCol: text('array_col').array().notNull(), }, (users) => ({ usersAge1Idx: uniqueIndex('usersAge1Idx').on(users.class), diff --git a/drizzle-orm/type-tests/pg/update.ts b/drizzle-orm/type-tests/pg/update.ts index 4123b26fe..a667825e0 100644 --- a/drizzle-orm/type-tests/pg/update.ts +++ b/drizzle-orm/type-tests/pg/update.ts @@ -2,6 +2,8 @@ import type { QueryResult } from 'pg'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { eq } from '~/expressions.ts'; +import type { PgUpdate } from '~/pg-core/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; import { users } from './tables.ts'; @@ -46,3 +48,41 @@ const updateReturningStmt = db.update(users) .prepare('updateReturningStmt'); const updateReturningPrepared = await updateReturningStmt.execute(); Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``).returning(); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + function withReturning(qb: T) { + return qb.returning(); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = withReturning(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .returning() + // @ts-expect-error method was already called + .returning(); + + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} diff --git a/drizzle-orm/type-tests/pg/with.ts b/drizzle-orm/type-tests/pg/with.ts index 49fc10f3b..1e4dfda99 100644 --- a/drizzle-orm/type-tests/pg/with.ts +++ b/drizzle-orm/type-tests/pg/with.ts @@ -2,7 +2,7 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { gt, inArray } from '~/expressions.ts'; import { integer, pgTable, serial, text } from '~/pg-core/index.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { db } from './db.ts'; const orders = pgTable('orders', { diff --git a/drizzle-orm/type-tests/sqlite/delete.ts b/drizzle-orm/type-tests/sqlite/delete.ts index 10827099f..fcc754740 100644 --- a/drizzle-orm/type-tests/sqlite/delete.ts +++ b/drizzle-orm/type-tests/sqlite/delete.ts @@ -3,7 +3,9 @@ import { eq } from '~/expressions.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; -import { type DrizzleTypeError } from '~/utils.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SQLiteDelete } from '~/sqlite-core/index.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; import { bunDb, db } from './db.ts'; import { users } from './tables.ts'; @@ -114,3 +116,39 @@ const deleteValuesBunReturningPartial = bunDb.delete(users).returning({ myHomeCity: users.homeCity, }).values(); Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``).returning(); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + function withReturning(qb: T) { + return qb.returning(); + } + + const qbBase = db.delete(users).$dynamic(); + const qb = withReturning(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .delete(users) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); + + db + .delete(users) + .returning() + // @ts-expect-error method was already called + .returning(); +} diff --git a/drizzle-orm/type-tests/sqlite/insert.ts b/drizzle-orm/type-tests/sqlite/insert.ts index cc877686c..c4566ae8f 100644 --- a/drizzle-orm/type-tests/sqlite/insert.ts +++ b/drizzle-orm/type-tests/sqlite/insert.ts @@ -2,8 +2,9 @@ import type { RunResult } from 'better-sqlite3'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { and, eq } from '~/expressions.ts'; -import { sql } from '~/sql/index.ts'; -import { type DrizzleTypeError } from '~/utils.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SQLiteInsert } from '~/sqlite-core/query-builders/insert.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; import { bunDb, db } from './db.ts'; import type { NewUser } from './tables.ts'; import { users } from './tables.ts'; @@ -171,3 +172,36 @@ const stmt = db.select().from(users) .limit(sql.placeholder('limit')) .prepare(); stmt.run({ id: 1, limit: 10, offset: 20 }); + +{ + function dynamic(qb: T) { + return qb.returning().onConflictDoNothing().onConflictDoUpdate({ set: {}, target: users.id, where: sql`` }); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0, serialNotNull: 0 }) + .$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + function withReturning(qb: T) { + return qb.returning(); + } + + const qbBase = db.insert(users).values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0, serialNotNull: 0 }) + .$dynamic(); + const qb = withReturning(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .insert(users) + .values({ age1: 0, class: 'A', enumCol: 'a', homeCity: 0, serialNotNull: 0 }) + .returning() + // @ts-expect-error method was already called + .returning(); +} diff --git a/drizzle-orm/type-tests/sqlite/other.ts b/drizzle-orm/type-tests/sqlite/other.ts index aa4960371..6dfe8a4c9 100644 --- a/drizzle-orm/type-tests/sqlite/other.ts +++ b/drizzle-orm/type-tests/sqlite/other.ts @@ -1,6 +1,6 @@ import type { RunResult } from 'better-sqlite3'; import { eq, inArray } from '~/expressions.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; @@ -11,17 +11,17 @@ const query = sql`select ${users.id}, ${users.class} from ${users} where ${inArr eq(users.class, 'A') }`; -const all = db.all(query); +const all = await db.all(query); Expect>; -const allValuesTyped = db.values<[number, 'A' | 'B' | 'C']>(query); +const allValuesTyped = await db.values<[number, 'A' | 'B' | 'C']>(query); Expect>; -const allObjects = db.all(query); +const allObjects = await db.all(query); Expect>; -const allObjectsTyped = db.all<{ id: number; class: 'A' | 'B' | 'C' }>(query); +const allObjectsTyped = await db.all<{ id: number; class: 'A' | 'B' | 'C' }>(query); Expect>; -const run = db.run(query); +const run = await db.run(query); Expect>; diff --git a/drizzle-orm/type-tests/sqlite/select.ts b/drizzle-orm/type-tests/sqlite/select.ts index ad9ef2cf2..196dbc4de 100644 --- a/drizzle-orm/type-tests/sqlite/select.ts +++ b/drizzle-orm/type-tests/sqlite/select.ts @@ -21,11 +21,12 @@ import { notLike, or, } from '~/expressions.ts'; -import { param, sql } from '~/sql/index.ts'; +import { param, sql } from '~/sql/sql.ts'; import { alias } from '~/sqlite-core/alias.ts'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; +import type { SQLiteSelect, SQLiteSelectQueryBuilder } from '~/sqlite-core/query-builders/select.types.ts'; import { db } from './db.ts'; import { cities, classes, newYorkers, users } from './tables.ts'; @@ -438,3 +439,143 @@ Expect< > >; } + +{ + db + .select() + .from(users) + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); + + db + .select() + .from(users) + .where(eq(users.id, 1)) + .limit(10) + // @ts-expect-error - can't use where twice + .where(eq(users.id, 1)); +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function withFriends(qb: T) { + const friends = alias(users, 'friends'); + const friends2 = alias(users, 'friends2'); + const friends3 = alias(users, 'friends3'); + const friends4 = alias(users, 'friends4'); + const friends5 = alias(users, 'friends5'); + return qb + .leftJoin(friends, sql`true`) + .leftJoin(friends2, sql`true`) + .leftJoin(friends3, sql`true`) + .leftJoin(friends4, sql`true`) + .leftJoin(friends5, sql`true`); + } + + const qb = db.select().from(users).$dynamic(); + const result = await withFriends(qb); + Expect< + Equal + >; +} + +{ + function dynamic(qb: T) { + return qb.where(sql``).having(sql``).groupBy(sql``).orderBy(sql``).limit(1).offset(1); + } + + const qb = db.select().from(users).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +{ + db + .select() + .from(users) + .where(sql``) + .limit(10) + // @ts-expect-error method was already called + .where(sql``); + + db + .select() + .from(users) + .having(sql``) + .limit(10) + // @ts-expect-error method was already called + .having(sql``); + + db + .select() + .from(users) + .groupBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .groupBy(sql``); + + db + .select() + .from(users) + .orderBy(sql``) + .limit(10) + // @ts-expect-error method was already called + .orderBy(sql``); + + db + .select() + .from(users) + .limit(10) + .where(sql``) + // @ts-expect-error method was already called + .limit(10); + + db + .select() + .from(users) + .offset(10) + .limit(10) + // @ts-expect-error method was already called + .offset(10); +} diff --git a/drizzle-orm/type-tests/sqlite/set-operators.ts b/drizzle-orm/type-tests/sqlite/set-operators.ts new file mode 100644 index 000000000..e0239ba24 --- /dev/null +++ b/drizzle-orm/type-tests/sqlite/set-operators.ts @@ -0,0 +1,278 @@ +import { type Equal, Expect } from 'type-tests/utils.ts'; +import { eq } from '~/expressions.ts'; +import { desc, sql } from '~/sql/index.ts'; +import { except, intersect, type SQLiteSetOperator, union, unionAll } from '~/sqlite-core/index.ts'; +import { db } from './db.ts'; +import { cities, classes, newYorkers, users } from './tables.ts'; + +const unionTest = await db + .select({ id: users.id }) + .from(users) + .union( + db + .select({ id: users.id }) + .from(users), + ); + +Expect>; + +const unionAllTest = await db + .select({ id: users.id, text: users.name }) + .from(users) + .unionAll( + db.select({ id: users.id, text: users.name }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const intersectTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .intersect(({ intersect }) => + intersect( + db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users), + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ) + ); + +Expect>; + +const intersectAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .intersect( + db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .leftJoin(cities, eq(users.id, cities.id)), + ); + +Expect>; + +const exceptTest = await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql`${users.homeCity}`.mapWith(Number) }) + .from(users), + ); + +Expect>; + +const exceptAllTest = await db + .select({ id: users.id, homeCity: users.class }) + .from(users) + .except( + db + .select({ id: users.id, homeCity: sql<'A' | 'C'>`${users.class}` }) + .from(users), + ); + +Expect>; + +const union2Test = await union(db.select().from(cities), db.select().from(cities), db.select().from(cities)); + +Expect>; + +const unionAll2Test = await unionAll( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select().from(cities), +); + +Expect>; + +const intersect2Test = await intersect( + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), + db.select({ + id: cities.id, + name: cities.name, + population: cities.population, + }).from(cities), +); + +Expect>; + +const intersectAll2Test = await intersect( + union( + db.select({ + id: cities.id, + }).from(cities), + db.select({ + id: cities.id, + }) + .from(cities).where(sql``), + ), + db.select({ + id: cities.id, + }) + .from(cities), +).orderBy(desc(cities.id)).limit(23); + +Expect>; + +const except2Test = await except( + db.select({ + userId: newYorkers.userId, + }) + .from(newYorkers), + db.select({ + userId: newYorkers.userId, + }).from(newYorkers), +); + +Expect>; + +const exceptAll2Test = await except( + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }) + .from(newYorkers).where(eq(newYorkers.cityId, 2)), + db.select({ + userId: newYorkers.userId, + cityId: newYorkers.cityId, + }).from(newYorkers).leftJoin(newYorkers, sql``), +); + +Expect>; + +const unionfull = await union(db.select().from(users), db.select().from(users)).orderBy(sql``).limit(1).offset(2); + +Expect< + Equal<{ + id: number; + name: string | null; + homeCity: number; + currentCity: number | null; + serialNullable: number | null; + serialNotNull: number; + class: 'A' | 'C'; + subClass: 'B' | 'D' | null; + age1: number; + createdAt: Date; + enumCol: 'a' | 'b' | 'c'; + }[], typeof unionfull> +>; + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +union(db.select().from(users), db.select().from(users)) + .offset(1) + // @ts-expect-error - method was already called + .offset(2); + +union(db.select().from(users), db.select().from(users)) + .orderBy(sql``) + // @ts-expect-error - method was already called + .orderBy(sql``); + +{ + function dynamic(qb: T) { + return qb.orderBy(sql``).limit(1).offset(2); + } + + const qb = union(db.select().from(users), db.select().from(users)).$dynamic(); + const result = await dynamic(qb); + Expect>; +} + +await db + .select({ id: users.id, homeCity: users.homeCity }) + .from(users) + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + .intersect(({ intersect }) => intersect(db.select().from(users), db.select().from(users))); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select().from(classes).union(db.select({ id: classes.id }).from(classes)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes).where(sql``)); + +// All queries in combining statements should return the same number of columns +// and the corresponding columns should have compatible data type +// @ts-expect-error +db.select({ id: classes.id }).from(classes).union(db.select().from(classes)); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + db.select({ id: cities.id, name: cities.name }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select().from(cities), +); + +union( + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities), + db.select({ id: cities.id, name: cities.name }).from(cities).where(sql``).limit(3).$dynamic(), + db.select({ id: cities.id, name: cities.name }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: newYorkers.userId }).from(newYorkers), + db.select({ id: cities.id }).from(cities), +); + +union( + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities), + db.select({ id: cities.id }).from(cities).where(sql``), + db.select({ id: sql`${cities.id}` }).from(cities), + db.select({ id: cities.id }).from(cities), + // All queries in combining statements should return the same number of columns + // and the corresponding columns should have compatible data type + // @ts-expect-error + db.select({ id: cities.id, name: cities.name, population: cities.population }).from(cities).where(sql``), +); diff --git a/drizzle-orm/type-tests/sqlite/subquery.ts b/drizzle-orm/type-tests/sqlite/subquery.ts index 87926864e..181cd6628 100644 --- a/drizzle-orm/type-tests/sqlite/subquery.ts +++ b/drizzle-orm/type-tests/sqlite/subquery.ts @@ -1,6 +1,6 @@ import { Expect } from 'type-tests/utils.ts'; import { and, eq } from '~/expressions.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { alias, integer, sqliteTable, text } from '~/sqlite-core/index.ts'; import type { DrizzleTypeError, Equal } from '~/utils.ts'; import { db } from './db.ts'; @@ -84,3 +84,15 @@ Expect< const sq = db.select({ count: sql`count(1)::int` }).from(names).as('sq'); Expect ? true : false>; } + +const sqUnion = db.select().from(names).union(db.select().from(names2)).as('sqUnion'); + +const resUnion = await db.select().from(sqUnion); + +Expect< + Equal<{ + id: number; + name: string | null; + authorId: number | null; + }[], typeof resUnion> +>; diff --git a/drizzle-orm/type-tests/sqlite/tables.ts b/drizzle-orm/type-tests/sqlite/tables.ts index eef6ec377..d56b5fe09 100644 --- a/drizzle-orm/type-tests/sqlite/tables.ts +++ b/drizzle-orm/type-tests/sqlite/tables.ts @@ -1,7 +1,7 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { eq, gt } from '~/expressions.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { alias, check, @@ -396,3 +396,17 @@ Expect< id4: integer('id').$defaultFn(() => '1'), }); } + +{ + const table = sqliteTable('test', { + data: text('data', { mode: 'json' }).notNull(), + dataTyped: text('dataTyped', { mode: 'json' }).$type<{ a: number }>().notNull(), + }); + + Expect< + Equal<{ + data: unknown; + dataTyped: { a: number }; + }, typeof table.$inferSelect> + >; +} diff --git a/drizzle-orm/type-tests/sqlite/update.ts b/drizzle-orm/type-tests/sqlite/update.ts index bde8bfbcb..aa1f8051f 100644 --- a/drizzle-orm/type-tests/sqlite/update.ts +++ b/drizzle-orm/type-tests/sqlite/update.ts @@ -2,7 +2,9 @@ import type { RunResult } from 'better-sqlite3'; import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { eq } from '~/expressions.ts'; -import { type DrizzleTypeError } from '~/utils.ts'; +import { sql } from '~/sql/sql.ts'; +import type { SQLiteUpdate } from '~/sqlite-core/query-builders/update.ts'; +import type { DrizzleTypeError } from '~/utils.ts'; import { bunDb, db } from './db.ts'; import { users } from './tables.ts'; @@ -93,3 +95,41 @@ const updateGetReturningAllBun = bunDb.update(users) .returning() .get(); Expect>; + +{ + function dynamic(qb: T) { + return qb.where(sql``).returning(); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = dynamic(qbBase); + const result = await qb; + Expect>; +} + +{ + function withReturning(qb: T) { + return qb.returning(); + } + + const qbBase = db.update(users).set({}).$dynamic(); + const qb = withReturning(qbBase); + const result = await qb; + Expect>; +} + +{ + db + .update(users) + .set({}) + .returning() + // @ts-expect-error method was already called + .returning(); + + db + .update(users) + .set({}) + .where(sql``) + // @ts-expect-error method was already called + .where(sql``); +} diff --git a/drizzle-orm/type-tests/sqlite/with.ts b/drizzle-orm/type-tests/sqlite/with.ts index db8b33d75..94a969dac 100644 --- a/drizzle-orm/type-tests/sqlite/with.ts +++ b/drizzle-orm/type-tests/sqlite/with.ts @@ -1,7 +1,7 @@ import type { Equal } from 'type-tests/utils.ts'; import { Expect } from 'type-tests/utils.ts'; import { gt, inArray } from '~/expressions.ts'; -import { sql } from '~/sql/index.ts'; +import { sql } from '~/sql/sql.ts'; import { integer, sqliteTable, text } from '~/sqlite-core/index.ts'; import { db } from './db.ts'; diff --git a/drizzle-orm/type-tests/tsconfig.json b/drizzle-orm/type-tests/tsconfig.json index 449ace992..b4e6c8007 100644 --- a/drizzle-orm/type-tests/tsconfig.json +++ b/drizzle-orm/type-tests/tsconfig.json @@ -2,11 +2,10 @@ "extends": "../tsconfig.build.json", "compilerOptions": { "composite": false, - "module": "esnext", - "target": "esnext", "noEmit": true, "rootDir": "..", "outDir": "./.cache" }, - "include": [".", "../src"] + "include": [".", "../src"], + "exclude": ["**/playground"] } diff --git a/drizzle-typebox/tests/utils.ts b/drizzle-typebox/tests/utils.ts index a98bfd961..0454dd48d 100644 --- a/drizzle-typebox/tests/utils.ts +++ b/drizzle-typebox/tests/utils.ts @@ -1,5 +1,5 @@ import type { TSchema } from '@sinclair/typebox'; -import { type ExecutionContext } from 'ava'; +import type { ExecutionContext } from 'ava'; export function expectSchemaShape(t: ExecutionContext, expected: T) { return { @@ -15,4 +15,3 @@ export function expectSchemaShape(t: ExecutionContext, expect }, }; } - diff --git a/drizzle-valibot/tests/utils.ts b/drizzle-valibot/tests/utils.ts index 1464847cb..19a129d4d 100644 --- a/drizzle-valibot/tests/utils.ts +++ b/drizzle-valibot/tests/utils.ts @@ -1,5 +1,5 @@ -import { type ExecutionContext } from 'ava'; -import { type BaseSchema } from 'valibot'; +import type { ExecutionContext } from 'ava'; +import type { BaseSchema } from 'valibot'; export function expectSchemaShape>(t: ExecutionContext, expected: T) { return { @@ -8,4 +8,3 @@ export function expectSchemaShape>(t: ExecutionCo }, }; } - diff --git a/drizzle-zod/tests/utils.ts b/drizzle-zod/tests/utils.ts index c30c9b243..b8daf972e 100644 --- a/drizzle-zod/tests/utils.ts +++ b/drizzle-zod/tests/utils.ts @@ -1,4 +1,4 @@ -import { type ExecutionContext } from 'ava'; +import type { ExecutionContext } from 'ava'; import type { z } from 'zod'; export function expectSchemaShape(t: ExecutionContext, expected: z.ZodObject) { diff --git a/examples/aws-lambda/.env.sample b/examples/aws-lambda/.env.sample new file mode 100644 index 000000000..92e0ef91c --- /dev/null +++ b/examples/aws-lambda/.env.sample @@ -0,0 +1 @@ +DATABASE_URL="postgresql://postgres:postgres@localhost:5432/dbname?schema=public" diff --git a/examples/aws-lambda/.gitignore b/examples/aws-lambda/.gitignore new file mode 100644 index 000000000..c3eabc8ba --- /dev/null +++ b/examples/aws-lambda/.gitignore @@ -0,0 +1,4 @@ +.env +.serverless +.node_modules + diff --git a/examples/aws-lambda/README.md b/examples/aws-lambda/README.md new file mode 100644 index 000000000..7d4519c1b --- /dev/null +++ b/examples/aws-lambda/README.md @@ -0,0 +1,68 @@ +## Drizzle ORM AWS Lambda Example + +## Initial project setup +- Create a `.env` file and add the database connection url +- Run `npm install` +- Configure AWS account credentials + +### Migrations +- Set the correct DB connection url in `migrate.ts` +- To create a migration file run `npm run generate-migration` +- To apply the migration run `npm run migrate` + +### Deployment +- Run `serverless deploy` + +### Usage with AWS Aurora DB +- To be able to connect to an Aurora RDS Instance, the Lambda function has to be in the same VPC as the RDS Instance. +- As an example, this can be achieved the following way using serverless framework: +``` +custom: + vpc_config: &vpc_config + vpc: + securityGroupIds: + - sg-samplegroupId + subnetIds: + - subnet-sample1 + - subnet-sample2 + - subnet-sample3 + +functions: + getUsers: + handler: ./src/api/user.getAll + <<: *vpc_config +``` + +#### To expose the Lambda function with the API Gateway add the following code snippet in `serverless.yml` +``` +functions: + getUsers: + handler: ./src/api/user.getAll + events: + - http: + path: "users" + method: GET + +resources: + Resources: + GatewayResponse: + Type: "AWS::ApiGateway::GatewayResponse" + Properties: + ResponseParameters: + gatewayresponse.header.Access-Control-Allow-Origin: "'*'" + gatewayresponse.header.Access-Control-Allow-Headers: "'*'" + gatewayresponse.header.Access-Control-Allow-Methods: "'*'" + ResponseType: DEFAULT_4XX + RestApiId: + Ref: "ApiGatewayRestApi" + GatewayResponse5xx: + Type: "AWS::ApiGateway::GatewayResponse" + Properties: + ResponseParameters: + gatewayresponse.header.Access-Control-Allow-Origin: "'*'" + gatewayresponse.header.Access-Control-Allow-Headers: "'*'" + gatewayresponse.header.Access-Control-Allow-Methods: "'*'" + ResponseType: DEFAULT_5XX + RestApiId: + Ref: "ApiGatewayRestApi" +``` diff --git a/examples/aws-lambda/package-lock.json b/examples/aws-lambda/package-lock.json new file mode 100644 index 000000000..09c5f5f07 --- /dev/null +++ b/examples/aws-lambda/package-lock.json @@ -0,0 +1,12589 @@ +{ + "name": "drizzle-aws-lambda", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "drizzle-aws-lambda", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "aws-lambda": "^1.0.7", + "drizzle-orm": "^0.27.0", + "pg": "^8.11.1", + "postgres": "^3.3.5" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "@types/node": "^20.4.0", + "@types/pg": "^8.10.2", + "drizzle-kit": "^0.19.3", + "serverless-dotenv-plugin": "^6.0.0", + "serverless-esbuild": "^1.45.1" + } + }, + "node_modules/@drizzle-team/studio": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.1.tgz", + "integrity": "sha512-cHgGezy2ojBFMaU6PZyBkksgFsg2CQ8IRN4mS7WdbA/Zv6xUK6fCNmpEWS/FftbxoA4B8Z0XGnuKsaTJEZsGgA==", + "dev": true + }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz", + "integrity": "sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==", + "dev": true, + "dependencies": { + "esbuild": "~0.17.6", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", + "integrity": "sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==", + "dev": true, + "dependencies": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true, + "peer": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@serverless/dashboard-plugin": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-6.2.3.tgz", + "integrity": "sha512-iTZhpZbiVl6G2AyfgoqxemqqpG4pUceWys3GsyZtjimnfnGd2UFBOMVUMTavLhYia7lQc4kQVuXQ+afLlkg+pQ==", + "dev": true, + "peer": true, + "dependencies": { + "@serverless/event-mocks": "^1.1.1", + "@serverless/platform-client": "^4.3.2", + "@serverless/utils": "^6.8.2", + "child-process-ext": "^2.1.1", + "chokidar": "^3.5.3", + "flat": "^5.0.2", + "fs-extra": "^9.1.0", + "js-yaml": "^4.1.0", + "jszip": "^3.10.1", + "lodash": "^4.17.21", + "memoizee": "^0.4.15", + "ncjsm": "^4.3.2", + "node-dir": "^0.1.17", + "node-fetch": "^2.6.8", + "open": "^7.4.2", + "semver": "^7.3.8", + "simple-git": "^3.16.0", + "type": "^2.7.2", + "uuid": "^8.3.2", + "yamljs": "^0.3.0" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/@serverless/dashboard-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@serverless/dashboard-plugin/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "peer": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@serverless/dashboard-plugin/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/@serverless/dashboard-plugin/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@serverless/event-mocks": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", + "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", + "dev": true, + "peer": true, + "dependencies": { + "@types/lodash": "^4.14.123", + "lodash": "^4.17.11" + } + }, + "node_modules/@serverless/platform-client": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-4.3.2.tgz", + "integrity": "sha512-DAa5Z0JAZc6UfrTZLYwqoZxgAponZpFwaqd7WzzMA+loMCkYWyJNwxrAmV6cr2UUJpkko4toPZuJ3vM9Ie+NDA==", + "dev": true, + "peer": true, + "dependencies": { + "adm-zip": "^0.5.5", + "archiver": "^5.3.0", + "axios": "^0.21.1", + "fast-glob": "^3.2.7", + "https-proxy-agent": "^5.0.0", + "ignore": "^5.1.8", + "isomorphic-ws": "^4.0.1", + "js-yaml": "^3.14.1", + "jwt-decode": "^2.2.0", + "minimatch": "^3.0.4", + "querystring": "^0.2.1", + "run-parallel-limit": "^1.1.0", + "throat": "^5.0.0", + "traverse": "^0.6.6", + "ws": "^7.5.3" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/@serverless/platform-client/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@serverless/platform-client/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@serverless/platform-client/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@serverless/platform-client/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@serverless/utils": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-6.11.2.tgz", + "integrity": "sha512-Uww5DM78K+bHmukNgVX3Yieu7CVnOKvpUhxxRe+5WiYBV7mNrLiZr9bNAtUSNOYFS4tU5Ig5YlMCCForCCYxEw==", + "dev": true, + "peer": true, + "dependencies": { + "archive-type": "^4.0.0", + "chalk": "^4.1.2", + "ci-info": "^3.8.0", + "cli-progress-footer": "^2.3.2", + "content-disposition": "^0.5.4", + "d": "^1.0.1", + "decompress": "^4.2.1", + "event-emitter": "^0.3.5", + "ext": "^1.7.0", + "ext-name": "^5.0.0", + "file-type": "^16.5.4", + "filenamify": "^4.3.0", + "get-stream": "^6.0.1", + "got": "^11.8.6", + "inquirer": "^8.2.5", + "js-yaml": "^4.1.0", + "jwt-decode": "^3.1.2", + "lodash": "^4.17.21", + "log": "^6.3.1", + "log-node": "^8.0.3", + "make-dir": "^3.1.0", + "memoizee": "^0.4.15", + "ms": "^2.1.3", + "ncjsm": "^4.3.2", + "node-fetch": "^2.6.11", + "open": "^8.4.2", + "p-event": "^4.2.0", + "supports-color": "^8.1.1", + "timers-ext": "^0.1.7", + "type": "^2.7.2", + "uni-global": "^1.0.0", + "uuid": "^8.3.2", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/@serverless/utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@serverless/utils/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@serverless/utils/node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "dev": true, + "peer": true + }, + "node_modules/@serverless/utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "peer": true + }, + "node_modules/@serverless/utils/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/@serverless/utils/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "peer": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true, + "peer": true + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.119", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.119.tgz", + "integrity": "sha512-Vqm22aZrCvCd6I5g1SvpW151jfqwTzEZ7XJ3yZ6xaZG31nUEOEyzzVImjRcsN8Wi/QyPxId/x8GTtgIbsy8kEw==", + "dev": true + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz", + "integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==", + "devOptional": true + }, + "node_modules/@types/pg": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.2.tgz", + "integrity": "sha512-MKFs9P6nJ+LAeHLU3V0cODEOgyThJ3OAnmOlsZsxux6sfQs3HRXR5bBn7xG5DjckEFhTAxsXi7k7cd0pCMxpJw==", + "devOptional": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/pg/node_modules/pg-types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", + "integrity": "sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==", + "devOptional": true, + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.0.1", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/pg/node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "devOptional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "devOptional": true, + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/pg/node_modules/postgres-date": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", + "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==", + "devOptional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "devOptional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/2-thenable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", + "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", + "dev": true, + "peer": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.47" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==", + "dev": true, + "peer": true, + "dependencies": { + "file-type": "^4.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/archive-type/node_modules/file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "peer": true + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-lambda": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/aws-lambda/-/aws-lambda-1.0.7.tgz", + "integrity": "sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==", + "dependencies": { + "aws-sdk": "^2.814.0", + "commander": "^3.0.2", + "js-yaml": "^3.14.1", + "watchpack": "^2.0.0-beta.10" + }, + "bin": { + "lambda": "bin/lambda" + } + }, + "node_modules/aws-lambda/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aws-lambda/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, + "node_modules/aws-lambda/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/aws-sdk": { + "version": "2.1413.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1413.0.tgz", + "integrity": "sha512-vKpjC7iRwOhgv7P0xw90mVGO//2rqVPJKyYIs7uxLzSV0JzriVD+yqktOu/Hz6/phOmAd1cMIeFgpEC9ynrppg==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "peer": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bestzip": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bestzip/-/bestzip-2.2.1.tgz", + "integrity": "sha512-XdAb87RXqOqF7C6UgQG9IqpEHJvS6IOUo0bXWEAebjSSdhDjsbcqFKdHpn5Q7QHz2pGr3Zmw4wgG3LlzdyDz7w==", + "dev": true, + "dependencies": { + "archiver": "^5.3.0", + "async": "^3.2.0", + "glob": "^7.1.6", + "which": "^2.0.2", + "yargs": "^16.2.0" + }, + "bin": { + "bestzip": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/bestzip/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/bestzip/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/bestzip/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/bestzip/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "peer": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "peer": true, + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true, + "peer": true + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "dev": true, + "peer": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", + "dev": true, + "peer": true + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "peer": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "peer": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "peer": true + }, + "node_modules/child-process-ext": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", + "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", + "dev": true, + "peer": true, + "dependencies": { + "cross-spawn": "^6.0.5", + "es5-ext": "^0.10.53", + "log": "^6.0.0", + "split2": "^3.1.1", + "stream-promise": "^3.2.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "peer": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-progress-footer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/cli-progress-footer/-/cli-progress-footer-2.3.2.tgz", + "integrity": "sha512-uzHGgkKdeA9Kr57eyH1W5HGiNShP8fV1ETq04HDNM1Un6ShXbHhwi/H8LNV9L1fQXKjEw0q5FUkEVNuZ+yZdSw==", + "dev": true, + "peer": true, + "dependencies": { + "cli-color": "^2.0.2", + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "mute-stream": "0.0.8", + "process-utils": "^4.0.0", + "timers-ext": "^0.1.7", + "type": "^2.6.0" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/cli-progress-footer/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-sprintf-format": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", + "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", + "dev": true, + "peer": true, + "dependencies": { + "cli-color": "^2.0.1", + "es5-ext": "^0.10.53", + "sprintf-kit": "^2.0.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cli-sprintf-format/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-sprintf-format/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "peer": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true, + "peer": true + }, + "node_modules/compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "peer": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "peer": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==", + "dev": true, + "peer": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "dev": true, + "peer": true, + "dependencies": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "peer": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "peer": true, + "dependencies": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tar/node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dev": true, + "peer": true, + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/decompress-tar/node_modules/file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tar/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/decompress-tar/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "peer": true + }, + "node_modules/decompress-tar/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/decompress-tar/node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "peer": true, + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "peer": true, + "dependencies": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-tarbz2/node_modules/file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "peer": true, + "dependencies": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-targz/node_modules/file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", + "dev": true, + "peer": true, + "dependencies": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress-unzip/node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-unzip/node_modules/get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", + "dev": true, + "peer": true, + "dependencies": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress/node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "peer": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/decompress/node_modules/make-dir/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "peer": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/deferred": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/deferred/-/deferred-0.7.11.tgz", + "integrity": "sha512-8eluCl/Blx4YOGwMapBvXRKxHXhA8ejDXYzEaK8+/gtcm8hRMhSLmXSqDmNUKNc/C8HNSmuyyp/hflhqDAvK2A==", + "dev": true, + "peer": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.50", + "event-emitter": "^0.3.5", + "next-tick": "^1.0.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "peer": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/dreamopt": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz", + "integrity": "sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==", + "dev": true, + "dependencies": { + "wordwrap": ">=0.0.2" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/drizzle-kit": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.19.3.tgz", + "integrity": "sha512-G3Es+gPbQcTka0eKdDyzhgyDAWP5nfZpRXtKEND8Cl1Ww0Tn71yV/CYNbYk+gxg5x5+jeBIN7kM/bZ/agGBxYw==", + "dev": true, + "dependencies": { + "@drizzle-team/studio": "^0.0.1", + "@esbuild-kit/esm-loader": "^2.5.5", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "commander": "^9.4.1", + "esbuild": "^0.18.6", + "esbuild-register": "^3.4.2", + "glob": "^8.1.0", + "hanji": "^0.0.5", + "json-diff": "0.9.0", + "minimatch": "^7.4.3", + "zod": "^3.20.2" + }, + "bin": { + "drizzle-kit": "index.cjs" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/android-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", + "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/android-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", + "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/android-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", + "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", + "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/darwin-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", + "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", + "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", + "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", + "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", + "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", + "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-loong64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", + "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", + "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", + "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", + "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-s390x": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", + "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/linux-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", + "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", + "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", + "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/sunos-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", + "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/win32-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", + "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/win32-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", + "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/@esbuild/win32-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", + "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/drizzle-kit/node_modules/esbuild": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", + "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.11", + "@esbuild/android-arm64": "0.18.11", + "@esbuild/android-x64": "0.18.11", + "@esbuild/darwin-arm64": "0.18.11", + "@esbuild/darwin-x64": "0.18.11", + "@esbuild/freebsd-arm64": "0.18.11", + "@esbuild/freebsd-x64": "0.18.11", + "@esbuild/linux-arm": "0.18.11", + "@esbuild/linux-arm64": "0.18.11", + "@esbuild/linux-ia32": "0.18.11", + "@esbuild/linux-loong64": "0.18.11", + "@esbuild/linux-mips64el": "0.18.11", + "@esbuild/linux-ppc64": "0.18.11", + "@esbuild/linux-riscv64": "0.18.11", + "@esbuild/linux-s390x": "0.18.11", + "@esbuild/linux-x64": "0.18.11", + "@esbuild/netbsd-x64": "0.18.11", + "@esbuild/openbsd-x64": "0.18.11", + "@esbuild/sunos-x64": "0.18.11", + "@esbuild/win32-arm64": "0.18.11", + "@esbuild/win32-ia32": "0.18.11", + "@esbuild/win32-x64": "0.18.11" + } + }, + "node_modules/drizzle-orm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.27.0.tgz", + "integrity": "sha512-LGiJ0icB+wQwgbSCOvAjONY8Ec6G/EDzQQP5PmUaQYeI9OqgpVKHC2T1fFIbvk5dabWsbokJ5NOciVAxriStig==", + "peerDependencies": { + "@aws-sdk/client-rds-data": ">=3", + "@cloudflare/workers-types": ">=3", + "@libsql/client": "*", + "@neondatabase/serverless": ">=0.1", + "@opentelemetry/api": "^1.4.1", + "@planetscale/database": ">=1", + "@types/better-sqlite3": "*", + "@types/pg": "*", + "@types/sql.js": "*", + "@vercel/postgres": "*", + "better-sqlite3": ">=7", + "bun-types": "*", + "knex": "*", + "kysely": "*", + "mysql2": ">=2", + "pg": ">=8", + "postgres": ">=3", + "sql.js": ">=1", + "sqlite3": ">=5" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-rds-data": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "@neondatabase/serverless": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@types/better-sqlite3": { + "optional": true + }, + "@types/pg": { + "optional": true + }, + "@types/sql.js": { + "optional": true + }, + "@vercel/postgres": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "bun-types": { + "optional": true + }, + "knex": { + "optional": true + }, + "kysely": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "postgres": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/duration": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", + "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "dev": true, + "peer": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.46" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, + "peer": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-set/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/esbuild-register": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.4.2.tgz", + "integrity": "sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esniff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-1.1.0.tgz", + "integrity": "sha512-vmHXOeOt7FJLsqofvFk4WB3ejvcHizCd8toXXwADmYfd02p2QwHRgkUbhYDX54y08nqk818CUTWipgZGlyN07g==", + "dev": true, + "peer": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.12" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/essentials": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/essentials/-/essentials-1.2.0.tgz", + "integrity": "sha512-kP/j7Iw7KeNE8b/o7+tr9uX2s1wegElGOoGZ2Xm35qBr4BbbEcH3/bxR2nfH9l9JANCq9AUrvKw+gRuHtZp0HQ==", + "dev": true, + "peer": true, + "dependencies": { + "uni-global": "^1.0.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/execa/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "peer": true, + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "peer": true, + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "peer": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "peer": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "peer": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "dev": true, + "peer": true, + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "peer": true, + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filesize": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.7.tgz", + "integrity": "sha512-iMRG7Qo9nayLoU3PNCiLizYtsy4W1ClrapeCwEgtiQelOAOuRJiw4QaLI+sSr8xr901dgHv+EYP2bCusGZgoiA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-requires": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-requires/-/find-requires-1.0.0.tgz", + "integrity": "sha512-UME7hNwBfzeISSFQcBEDemEEskpOjI/shPrpJM5PI4DSdn6hX0dmz+2dL70blZER2z8tSnTRL+2rfzlYgtbBoQ==", + "dev": true, + "peer": true, + "dependencies": { + "es5-ext": "^0.10.49", + "esniff": "^1.1.0" + }, + "bin": { + "find-requires": "bin/find-requires.js" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "peer": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "peer": true, + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "peer": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/fp-ts": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz", + "integrity": "sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==", + "dev": true + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fs2": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/fs2/-/fs2-0.3.9.tgz", + "integrity": "sha512-WsOqncODWRlkjwll+73bAxVW3JPChDgaPX3DT4iTTm73UmG4VgALa7LaFblP232/DN60itkOrPZ8kaP1feksGQ==", + "dev": true, + "peer": true, + "dependencies": { + "d": "^1.0.1", + "deferred": "^0.7.11", + "es5-ext": "^0.10.53", + "event-emitter": "^0.3.5", + "ignore": "^5.1.8", + "memoizee": "^0.4.14", + "type": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/fs2/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.2.tgz", + "integrity": "sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "peer": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/hanji": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/hanji/-/hanji-0.0.5.tgz", + "integrity": "sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==", + "dev": true, + "dependencies": { + "lodash.throttle": "^4.1.1", + "sisteransi": "^1.0.5" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true, + "peer": true + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "peer": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "peer": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "peer": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", + "dev": true, + "peer": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "peer": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "dev": true, + "peer": true, + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "node_modules/json-colorizer": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-colorizer/-/json-colorizer-2.2.2.tgz", + "integrity": "sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^2.4.1", + "lodash.get": "^4.4.2" + } + }, + "node_modules/json-colorizer/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/json-colorizer/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/json-colorizer/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-cycle": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", + "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/json-diff": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.9.0.tgz", + "integrity": "sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==", + "dev": true, + "dependencies": { + "cli-color": "^2.0.0", + "difflib": "~0.2.1", + "dreamopt": "~0.8.0" + }, + "bin": { + "json-diff": "bin/json-diff.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/json-refs": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz", + "integrity": "sha512-0vOQd9eLNBL18EGl5yYaO44GhixmImes2wiYn9Z3sag3QnehWrYWlB9AFtMxCL2Bj3fyxgDYkxGFEU/chlYssw==", + "dev": true, + "peer": true, + "dependencies": { + "commander": "~4.1.1", + "graphlib": "^2.1.8", + "js-yaml": "^3.13.1", + "lodash": "^4.17.15", + "native-promise-only": "^0.8.1", + "path-loader": "^1.0.10", + "slash": "^3.0.0", + "uri-js": "^4.2.2" + }, + "bin": { + "json-refs": "bin/json-refs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/json-refs/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/json-refs/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/json-refs/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "peer": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "peer": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/jwt-decode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", + "dev": true, + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "peer": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "peer": true + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true, + "peer": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "dev": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "node_modules/log": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/log/-/log-6.3.1.tgz", + "integrity": "sha512-McG47rJEWOkXTDioZzQNydAVvZNeEkSyLJ1VWkFwfW+o1knW+QSi8D1KjPn/TnctV+q99lkvJNe1f0E1IjfY2A==", + "dev": true, + "peer": true, + "dependencies": { + "d": "^1.0.1", + "duration": "^0.2.2", + "es5-ext": "^0.10.53", + "event-emitter": "^0.3.5", + "sprintf-kit": "^2.0.1", + "type": "^2.5.0", + "uni-global": "^1.0.0" + } + }, + "node_modules/log-node": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", + "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "cli-color": "^2.0.1", + "cli-sprintf-format": "^1.1.1", + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "sprintf-kit": "^2.0.1", + "supports-color": "^8.1.1", + "type": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "log": "^6.0.0" + } + }, + "node_modules/log-node/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "peer": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "peer": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "peer": true + }, + "node_modules/native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", + "dev": true, + "peer": true + }, + "node_modules/ncjsm": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ncjsm/-/ncjsm-4.3.2.tgz", + "integrity": "sha512-6d1VWA7FY31CpI4Ki97Fpm36jfURkVbpktizp8aoVViTZRQgr/0ddmlKerALSSlzfwQRBeSq1qwwVcBJK4Sk7Q==", + "dev": true, + "peer": true, + "dependencies": { + "builtin-modules": "^3.3.0", + "deferred": "^0.7.11", + "es5-ext": "^0.10.62", + "es6-set": "^0.1.6", + "ext": "^1.7.0", + "find-requires": "^1.0.0", + "fs2": "^0.3.9", + "type": "^2.7.2" + } + }, + "node_modules/ncjsm/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "peer": true + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "peer": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-dir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-dir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dev": true, + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-registry-utilities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-utilities/-/npm-registry-utilities-1.0.0.tgz", + "integrity": "sha512-9xYfSJy2IFQw1i6462EJzjChL9e65EfSo2Cw6kl0EFeDp05VvU+anrQk3Fc0d1MbVCq7rWIxeer89O9SUQ/uOg==", + "dev": true, + "peer": true, + "dependencies": { + "ext": "^1.6.0", + "fs2": "^0.3.9", + "memoizee": "^0.4.15", + "node-fetch": "^2.6.7", + "semver": "^7.3.5", + "type": "^2.6.0", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/npm-registry-utilities/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "devOptional": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "peer": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "peer": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "peer": true, + "dependencies": { + "p-timeout": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "peer": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "peer": true + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-loader": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.12.tgz", + "integrity": "sha512-n7oDG8B+k/p818uweWrOixY9/Dsr89o2TkCm6tOTex3fpdo2+BFDgR+KpB37mGKBRsBAlR8CIJMFN0OEy/7hIQ==", + "dev": true, + "peer": true, + "dependencies": { + "native-promise-only": "^0.8.1", + "superagent": "^7.1.6" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path2": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path2/-/path2-0.1.0.tgz", + "integrity": "sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA==", + "dev": true, + "peer": true + }, + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "peer": true + }, + "node_modules/pg": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.1.tgz", + "integrity": "sha512-utdq2obft07MxaDg0zBJI+l/M3mBRfIpEN3iSemsz0G5F2/VXx+XzqF4oxrbIZXQxt2AZzIUzyVg/YM6xOP/WQ==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.1", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz", + "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "devOptional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/pgpass/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "peer": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.3.5.tgz", + "integrity": "sha512-+JD93VELV9gHkqpV5gdL5/70HdGtEw4/XE1S4BC8f1mcPmdib3K5XsKVbnR1XcAyC41zOnifJ+9YRKxdIsXiUw==", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-range": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", + "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==", + "devOptional": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/process-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/process-utils/-/process-utils-4.0.0.tgz", + "integrity": "sha512-fMyMQbKCxX51YxR7YGCzPjLsU3yDzXFkP4oi1/Mt5Ixnk7GO/7uUTj8mrCHUwuvozWzI+V7QSJR9cZYnwNOZPg==", + "dev": true, + "peer": true, + "dependencies": { + "ext": "^1.4.0", + "fs2": "^0.3.9", + "memoizee": "^0.4.14", + "type": "^2.1.0" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/process-utils/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "peer": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "peer": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", + "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ramda": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", + "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dev": true, + "peer": true, + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "peer": true + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "peer": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "peer": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "peer": true + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "node_modules/seek-bzip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", + "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", + "dev": true, + "peer": true, + "dependencies": { + "commander": "^2.8.1" + }, + "bin": { + "seek-bunzip": "bin/seek-bunzip", + "seek-table": "bin/seek-bzip-table" + } + }, + "node_modules/seek-bzip/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "peer": true + }, + "node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serverless": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.33.0.tgz", + "integrity": "sha512-qmG0RMelsWmnS5Smxoy0CbjpecgnJlM89wzSIgJqfkGlmOo2nJdd8y0/E6KlaTsaozlPKkjUBDzis2nF8VNO2g==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "dependencies": { + "@serverless/dashboard-plugin": "^6.2.3", + "@serverless/platform-client": "^4.3.2", + "@serverless/utils": "^6.11.1", + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "archiver": "^5.3.1", + "aws-sdk": "^2.1404.0", + "bluebird": "^3.7.2", + "cachedir": "^2.3.0", + "chalk": "^4.1.2", + "child-process-ext": "^2.1.1", + "ci-info": "^3.8.0", + "cli-progress-footer": "^2.3.2", + "d": "^1.0.1", + "dayjs": "^1.11.8", + "decompress": "^4.2.1", + "dotenv": "^16.3.1", + "dotenv-expand": "^10.0.0", + "essentials": "^1.2.0", + "ext": "^1.7.0", + "fastest-levenshtein": "^1.0.16", + "filesize": "^10.0.7", + "fs-extra": "^10.1.0", + "get-stdin": "^8.0.0", + "globby": "^11.1.0", + "got": "^11.8.6", + "graceful-fs": "^4.2.11", + "https-proxy-agent": "^5.0.1", + "is-docker": "^2.2.1", + "js-yaml": "^4.1.0", + "json-colorizer": "^2.2.2", + "json-cycle": "^1.5.0", + "json-refs": "^3.0.15", + "lodash": "^4.17.21", + "memoizee": "^0.4.15", + "micromatch": "^4.0.5", + "node-fetch": "^2.6.11", + "npm-registry-utilities": "^1.0.0", + "object-hash": "^3.0.0", + "open": "^8.4.2", + "path2": "^0.1.0", + "process-utils": "^4.0.0", + "promise-queue": "^2.2.5", + "require-from-string": "^2.0.2", + "semver": "^7.5.3", + "signal-exit": "^3.0.7", + "stream-buffers": "^3.0.2", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "tar": "^6.1.15", + "timers-ext": "^0.1.7", + "type": "^2.7.2", + "untildify": "^4.0.0", + "uuid": "^9.0.0", + "ws": "^7.5.9", + "yaml-ast-parser": "0.0.43" + }, + "bin": { + "serverless": "bin/serverless.js", + "sls": "bin/serverless.js" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/serverless-dotenv-plugin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serverless-dotenv-plugin/-/serverless-dotenv-plugin-6.0.0.tgz", + "integrity": "sha512-8tLVNwHfDO0sBz6+m+DLTZquRk0AZq9rzqk3kphm1iIWKfan9R7RKt4hdq3eQ0kmDoqzudjPYBEXAJ5bUNKeGQ==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "dotenv": "^16.0.3", + "dotenv-expand": "^10.0.0" + }, + "peerDependencies": { + "serverless": "1 || 2 || pre-3 || 3" + } + }, + "node_modules/serverless-dotenv-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/serverless-dotenv-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/serverless-esbuild": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/serverless-esbuild/-/serverless-esbuild-1.45.1.tgz", + "integrity": "sha512-vPb9R7MoecOv8kdI41BLvYuB5vxBDNKQfGacIuJbmMO25uQHEgyLk27ryb+8XAxmMpb5FuI6/eUZmCK2kRQZZA==", + "dev": true, + "dependencies": { + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "anymatch": "^3.1.3", + "archiver": "^5.3.1", + "bestzip": "^2.2.1", + "chokidar": "^3.5.3", + "execa": "^5.1.1", + "fp-ts": "^2.13.1", + "fs-extra": "^11.1.0", + "globby": "^11.0.4", + "p-map": "^4.0.0", + "ramda": "^0.28.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=14.18.0" + }, + "peerDependencies": { + "esbuild": ">=0.8 <0.18", + "esbuild-node-externals": "^1.0.0" + }, + "peerDependenciesMeta": { + "esbuild-node-externals": { + "optional": true + } + } + }, + "node_modules/serverless-esbuild/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/serverless/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/serverless/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/serverless/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "peer": true + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "peer": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-git": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz", + "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==", + "dev": true, + "peer": true, + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "peer": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "peer": true, + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "peer": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/sprintf-kit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.1.tgz", + "integrity": "sha512-2PNlcs3j5JflQKcg4wpdqpZ+AjhQJ2OZEo34NXDtlB0tIPG84xaaXhpA8XFacFiwjKA4m49UOYG83y3hbMn/gQ==", + "dev": true, + "peer": true, + "dependencies": { + "es5-ext": "^0.10.53" + } + }, + "node_modules/stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/stream-promise": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", + "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", + "dev": true, + "peer": true, + "dependencies": { + "2-thenable": "^1.0.0", + "es5-ext": "^0.10.49", + "is-stream": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "peer": true, + "dependencies": { + "is-natural-number": "^4.0.1" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "dev": true, + "peer": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/superagent": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-7.1.6.tgz", + "integrity": "sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==", + "deprecated": "Please downgrade to v7.1.5 if you need IE/ActiveXObject support OR upgrade to v8.0.0 as we no longer support IE and published an incorrect patch version (see https://github.com/visionmedia/superagent/issues/1731)", + "dev": true, + "peer": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.0.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.10.3", + "readable-stream": "^3.6.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dev": true, + "peer": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true, + "peer": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "peer": true + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "peer": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true, + "peer": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "dev": true, + "peer": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "peer": true + }, + "node_modules/traverse": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "dev": true, + "peer": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "peer": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/unbzip2-stream/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/uni-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", + "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", + "dev": true, + "peer": true, + "dependencies": { + "type": "^2.5.0" + } + }, + "node_modules/uni-global/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/url/node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "dev": true, + "peer": true, + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "peer": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "peer": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "peer": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "peer": true + }, + "node_modules/yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + }, + "node_modules/yamljs/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/yamljs/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/yamljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/yamljs/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "peer": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + }, + "dependencies": { + "@drizzle-team/studio": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.1.tgz", + "integrity": "sha512-cHgGezy2ojBFMaU6PZyBkksgFsg2CQ8IRN4mS7WdbA/Zv6xUK6fCNmpEWS/FftbxoA4B8Z0XGnuKsaTJEZsGgA==", + "dev": true + }, + "@esbuild-kit/core-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz", + "integrity": "sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==", + "dev": true, + "requires": { + "esbuild": "~0.17.6", + "source-map-support": "^0.5.21" + } + }, + "@esbuild-kit/esm-loader": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", + "integrity": "sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==", + "dev": true, + "requires": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "dev": true, + "optional": true + }, + "@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "peer": true, + "requires": { + "debug": "^4.1.1" + } + }, + "@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true, + "peer": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@serverless/dashboard-plugin": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-6.2.3.tgz", + "integrity": "sha512-iTZhpZbiVl6G2AyfgoqxemqqpG4pUceWys3GsyZtjimnfnGd2UFBOMVUMTavLhYia7lQc4kQVuXQ+afLlkg+pQ==", + "dev": true, + "peer": true, + "requires": { + "@serverless/event-mocks": "^1.1.1", + "@serverless/platform-client": "^4.3.2", + "@serverless/utils": "^6.8.2", + "child-process-ext": "^2.1.1", + "chokidar": "^3.5.3", + "flat": "^5.0.2", + "fs-extra": "^9.1.0", + "js-yaml": "^4.1.0", + "jszip": "^3.10.1", + "lodash": "^4.17.21", + "memoizee": "^0.4.15", + "ncjsm": "^4.3.2", + "node-dir": "^0.1.17", + "node-fetch": "^2.6.8", + "open": "^7.4.2", + "semver": "^7.3.8", + "simple-git": "^3.16.0", + "type": "^2.7.2", + "uuid": "^8.3.2", + "yamljs": "^0.3.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "peer": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "peer": true + } + } + }, + "@serverless/event-mocks": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", + "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", + "dev": true, + "peer": true, + "requires": { + "@types/lodash": "^4.14.123", + "lodash": "^4.17.11" + } + }, + "@serverless/platform-client": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-4.3.2.tgz", + "integrity": "sha512-DAa5Z0JAZc6UfrTZLYwqoZxgAponZpFwaqd7WzzMA+loMCkYWyJNwxrAmV6cr2UUJpkko4toPZuJ3vM9Ie+NDA==", + "dev": true, + "peer": true, + "requires": { + "adm-zip": "^0.5.5", + "archiver": "^5.3.0", + "axios": "^0.21.1", + "fast-glob": "^3.2.7", + "https-proxy-agent": "^5.0.0", + "ignore": "^5.1.8", + "isomorphic-ws": "^4.0.1", + "js-yaml": "^3.14.1", + "jwt-decode": "^2.2.0", + "minimatch": "^3.0.4", + "querystring": "^0.2.1", + "run-parallel-limit": "^1.1.0", + "throat": "^5.0.0", + "traverse": "^0.6.6", + "ws": "^7.5.3" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@serverless/utils": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-6.11.2.tgz", + "integrity": "sha512-Uww5DM78K+bHmukNgVX3Yieu7CVnOKvpUhxxRe+5WiYBV7mNrLiZr9bNAtUSNOYFS4tU5Ig5YlMCCForCCYxEw==", + "dev": true, + "peer": true, + "requires": { + "archive-type": "^4.0.0", + "chalk": "^4.1.2", + "ci-info": "^3.8.0", + "cli-progress-footer": "^2.3.2", + "content-disposition": "^0.5.4", + "d": "^1.0.1", + "decompress": "^4.2.1", + "event-emitter": "^0.3.5", + "ext": "^1.7.0", + "ext-name": "^5.0.0", + "file-type": "^16.5.4", + "filenamify": "^4.3.0", + "get-stream": "^6.0.1", + "got": "^11.8.6", + "inquirer": "^8.2.5", + "js-yaml": "^4.1.0", + "jwt-decode": "^3.1.2", + "lodash": "^4.17.21", + "log": "^6.3.1", + "log-node": "^8.0.3", + "make-dir": "^3.1.0", + "memoizee": "^0.4.15", + "ms": "^2.1.3", + "ncjsm": "^4.3.2", + "node-fetch": "^2.6.11", + "open": "^8.4.2", + "p-event": "^4.2.0", + "supports-color": "^8.1.1", + "timers-ext": "^0.1.7", + "type": "^2.7.2", + "uni-global": "^1.0.0", + "uuid": "^8.3.2", + "write-file-atomic": "^4.0.2" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "dev": true, + "peer": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "peer": true + }, + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "peer": true + } + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "peer": true + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "peer": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true, + "peer": true + }, + "@types/aws-lambda": { + "version": "8.10.119", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.119.tgz", + "integrity": "sha512-Vqm22aZrCvCd6I5g1SvpW151jfqwTzEZ7XJ3yZ6xaZG31nUEOEyzzVImjRcsN8Wi/QyPxId/x8GTtgIbsy8kEw==", + "dev": true + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "peer": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true, + "peer": true + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true, + "peer": true + }, + "@types/node": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz", + "integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==", + "devOptional": true + }, + "@types/pg": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.2.tgz", + "integrity": "sha512-MKFs9P6nJ+LAeHLU3V0cODEOgyThJ3OAnmOlsZsxux6sfQs3HRXR5bBn7xG5DjckEFhTAxsXi7k7cd0pCMxpJw==", + "devOptional": true, + "requires": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + }, + "dependencies": { + "pg-types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", + "integrity": "sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==", + "devOptional": true, + "requires": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.0.1", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + } + }, + "postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "devOptional": true + }, + "postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "devOptional": true, + "requires": { + "obuf": "~1.1.2" + } + }, + "postgres-date": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", + "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==", + "devOptional": true + }, + "postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "devOptional": true + } + } + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "2-thenable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", + "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", + "dev": true, + "peer": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.47" + } + }, + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "dev": true, + "peer": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "peer": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "peer": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "peer": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==", + "dev": true, + "peer": true, + "requires": { + "file-type": "^4.2.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==", + "dev": true, + "peer": true + } + } + }, + "archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "peer": true + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "aws-lambda": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/aws-lambda/-/aws-lambda-1.0.7.tgz", + "integrity": "sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==", + "requires": { + "aws-sdk": "^2.814.0", + "commander": "^3.0.2", + "js-yaml": "^3.14.1", + "watchpack": "^2.0.0-beta.10" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "aws-sdk": { + "version": "2.1413.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1413.0.tgz", + "integrity": "sha512-vKpjC7iRwOhgv7P0xw90mVGO//2rqVPJKyYIs7uxLzSV0JzriVD+yqktOu/Hz6/phOmAd1cMIeFgpEC9ynrppg==", + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "dependencies": { + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + }, + "uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" + } + } + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "peer": true, + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bestzip": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bestzip/-/bestzip-2.2.1.tgz", + "integrity": "sha512-XdAb87RXqOqF7C6UgQG9IqpEHJvS6IOUo0bXWEAebjSSdhDjsbcqFKdHpn5Q7QHz2pGr3Zmw4wgG3LlzdyDz7w==", + "dev": true, + "requires": { + "archiver": "^5.3.0", + "async": "^3.2.0", + "glob": "^7.1.6", + "which": "^2.0.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "peer": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "peer": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true, + "peer": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "dev": true, + "peer": true + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "peer": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", + "dev": true, + "peer": true + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "peer": true + }, + "cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "peer": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "peer": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "peer": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true + }, + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "peer": true + }, + "child-process-ext": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", + "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", + "dev": true, + "peer": true, + "requires": { + "cross-spawn": "^6.0.5", + "es5-ext": "^0.10.53", + "log": "^6.0.0", + "split2": "^3.1.1", + "stream-promise": "^3.2.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "peer": true + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "peer": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "peer": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-progress-footer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/cli-progress-footer/-/cli-progress-footer-2.3.2.tgz", + "integrity": "sha512-uzHGgkKdeA9Kr57eyH1W5HGiNShP8fV1ETq04HDNM1Un6ShXbHhwi/H8LNV9L1fQXKjEw0q5FUkEVNuZ+yZdSw==", + "dev": true, + "peer": true, + "requires": { + "cli-color": "^2.0.2", + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "mute-stream": "0.0.8", + "process-utils": "^4.0.0", + "timers-ext": "^0.1.7", + "type": "^2.6.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "dev": true, + "peer": true + }, + "cli-sprintf-format": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", + "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", + "dev": true, + "peer": true, + "requires": { + "cli-color": "^2.0.1", + "es5-ext": "^0.10.53", + "sprintf-kit": "^2.0.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "peer": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "peer": true + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "peer": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true, + "peer": true + }, + "compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "peer": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "peer": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "peer": true + } + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==", + "dev": true, + "peer": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "dev": true, + "peer": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "peer": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "peer": true + } + } + } + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "peer": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "peer": true + } + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "peer": true, + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "dependencies": { + "bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dev": true, + "peer": true, + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "dev": true, + "peer": true + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "peer": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "peer": true, + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + } + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "peer": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true, + "peer": true + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "peer": true, + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==", + "dev": true, + "peer": true + } + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==", + "dev": true, + "peer": true, + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "dev": true, + "peer": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==", + "dev": true, + "peer": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + } + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "peer": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "peer": true + }, + "deferred": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/deferred/-/deferred-0.7.11.tgz", + "integrity": "sha512-8eluCl/Blx4YOGwMapBvXRKxHXhA8ejDXYzEaK8+/gtcm8hRMhSLmXSqDmNUKNc/C8HNSmuyyp/hflhqDAvK2A==", + "dev": true, + "peer": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.50", + "event-emitter": "^0.3.5", + "next-tick": "^1.0.0", + "timers-ext": "^0.1.7" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "peer": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true + }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "peer": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "requires": { + "heap": ">= 0.2.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true + }, + "dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true + }, + "dreamopt": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz", + "integrity": "sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==", + "dev": true, + "requires": { + "wordwrap": ">=0.0.2" + } + }, + "drizzle-kit": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.19.3.tgz", + "integrity": "sha512-G3Es+gPbQcTka0eKdDyzhgyDAWP5nfZpRXtKEND8Cl1Ww0Tn71yV/CYNbYk+gxg5x5+jeBIN7kM/bZ/agGBxYw==", + "dev": true, + "requires": { + "@drizzle-team/studio": "^0.0.1", + "@esbuild-kit/esm-loader": "^2.5.5", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "commander": "^9.4.1", + "esbuild": "^0.18.6", + "esbuild-register": "^3.4.2", + "glob": "^8.1.0", + "hanji": "^0.0.5", + "json-diff": "0.9.0", + "minimatch": "^7.4.3", + "zod": "^3.20.2" + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", + "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", + "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", + "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", + "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", + "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", + "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", + "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", + "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", + "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", + "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", + "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", + "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", + "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", + "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", + "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", + "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", + "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", + "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", + "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", + "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", + "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", + "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.18.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", + "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.11", + "@esbuild/android-arm64": "0.18.11", + "@esbuild/android-x64": "0.18.11", + "@esbuild/darwin-arm64": "0.18.11", + "@esbuild/darwin-x64": "0.18.11", + "@esbuild/freebsd-arm64": "0.18.11", + "@esbuild/freebsd-x64": "0.18.11", + "@esbuild/linux-arm": "0.18.11", + "@esbuild/linux-arm64": "0.18.11", + "@esbuild/linux-ia32": "0.18.11", + "@esbuild/linux-loong64": "0.18.11", + "@esbuild/linux-mips64el": "0.18.11", + "@esbuild/linux-ppc64": "0.18.11", + "@esbuild/linux-riscv64": "0.18.11", + "@esbuild/linux-s390x": "0.18.11", + "@esbuild/linux-x64": "0.18.11", + "@esbuild/netbsd-x64": "0.18.11", + "@esbuild/openbsd-x64": "0.18.11", + "@esbuild/sunos-x64": "0.18.11", + "@esbuild/win32-arm64": "0.18.11", + "@esbuild/win32-ia32": "0.18.11", + "@esbuild/win32-x64": "0.18.11" + } + } + } + }, + "drizzle-orm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.27.0.tgz", + "integrity": "sha512-LGiJ0icB+wQwgbSCOvAjONY8Ec6G/EDzQQP5PmUaQYeI9OqgpVKHC2T1fFIbvk5dabWsbokJ5NOciVAxriStig==", + "requires": {} + }, + "duration": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", + "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "dev": true, + "peer": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.46" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, + "peer": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "esbuild-register": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.4.2.tgz", + "integrity": "sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true + }, + "esniff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-1.1.0.tgz", + "integrity": "sha512-vmHXOeOt7FJLsqofvFk4WB3ejvcHizCd8toXXwADmYfd02p2QwHRgkUbhYDX54y08nqk818CUTWipgZGlyN07g==", + "dev": true, + "peer": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.12" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "essentials": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/essentials/-/essentials-1.2.0.tgz", + "integrity": "sha512-kP/j7Iw7KeNE8b/o7+tr9uX2s1wegElGOoGZ2Xm35qBr4BbbEcH3/bxR2nfH9l9JANCq9AUrvKw+gRuHtZp0HQ==", + "dev": true, + "peer": true, + "requires": { + "uni-global": "^1.0.0" + } + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "peer": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "peer": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "peer": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "peer": true + }, + "fast-glob": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "peer": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "peer": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "peer": true, + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "dev": true, + "peer": true, + "requires": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + } + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "peer": true + }, + "filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "peer": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + } + }, + "filesize": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.7.tgz", + "integrity": "sha512-iMRG7Qo9nayLoU3PNCiLizYtsy4W1ClrapeCwEgtiQelOAOuRJiw4QaLI+sSr8xr901dgHv+EYP2bCusGZgoiA==", + "dev": true, + "peer": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-requires": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-requires/-/find-requires-1.0.0.tgz", + "integrity": "sha512-UME7hNwBfzeISSFQcBEDemEEskpOjI/shPrpJM5PI4DSdn6hX0dmz+2dL70blZER2z8tSnTRL+2rfzlYgtbBoQ==", + "dev": true, + "peer": true, + "requires": { + "es5-ext": "^0.10.49", + "esniff": "^1.1.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "peer": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "peer": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "peer": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "peer": true, + "requires": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + } + }, + "fp-ts": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.0.tgz", + "integrity": "sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fs2": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/fs2/-/fs2-0.3.9.tgz", + "integrity": "sha512-WsOqncODWRlkjwll+73bAxVW3JPChDgaPX3DT4iTTm73UmG4VgALa7LaFblP232/DN60itkOrPZ8kaP1feksGQ==", + "dev": true, + "peer": true, + "requires": { + "d": "^1.0.1", + "deferred": "^0.7.11", + "es5-ext": "^0.10.53", + "event-emitter": "^0.3.5", + "ignore": "^5.1.8", + "memoizee": "^0.4.14", + "type": "^2.1.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "peer": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-tsconfig": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.2.tgz", + "integrity": "sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "peer": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "hanji": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/hanji/-/hanji-0.0.5.tgz", + "integrity": "sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==", + "dev": true, + "requires": { + "lodash.throttle": "^4.1.1", + "sisteransi": "^1.0.5" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "peer": true + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true, + "peer": true + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "peer": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "peer": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "peer": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "peer": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "peer": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "peer": true + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==", + "dev": true, + "peer": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "peer": true + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "peer": true + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "peer": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "peer": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "dev": true, + "peer": true, + "requires": {} + }, + "jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "json-colorizer": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-colorizer/-/json-colorizer-2.2.2.tgz", + "integrity": "sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^2.4.1", + "lodash.get": "^4.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "json-cycle": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", + "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", + "dev": true, + "peer": true + }, + "json-diff": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.9.0.tgz", + "integrity": "sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==", + "dev": true, + "requires": { + "cli-color": "^2.0.0", + "difflib": "~0.2.1", + "dreamopt": "~0.8.0" + } + }, + "json-refs": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz", + "integrity": "sha512-0vOQd9eLNBL18EGl5yYaO44GhixmImes2wiYn9Z3sag3QnehWrYWlB9AFtMxCL2Bj3fyxgDYkxGFEU/chlYssw==", + "dev": true, + "peer": true, + "requires": { + "commander": "~4.1.1", + "graphlib": "^2.1.8", + "js-yaml": "^3.13.1", + "lodash": "^4.17.15", + "native-promise-only": "^0.8.1", + "path-loader": "^1.0.10", + "slash": "^3.0.0", + "uri-js": "^4.2.2" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "peer": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "peer": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "peer": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "jwt-decode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", + "dev": true, + "peer": true + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "peer": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "peer": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "peer": true + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true, + "peer": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "log": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/log/-/log-6.3.1.tgz", + "integrity": "sha512-McG47rJEWOkXTDioZzQNydAVvZNeEkSyLJ1VWkFwfW+o1knW+QSi8D1KjPn/TnctV+q99lkvJNe1f0E1IjfY2A==", + "dev": true, + "peer": true, + "requires": { + "d": "^1.0.1", + "duration": "^0.2.2", + "es5-ext": "^0.10.53", + "event-emitter": "^0.3.5", + "sprintf-kit": "^2.0.1", + "type": "^2.5.0", + "uni-global": "^1.0.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "log-node": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", + "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^5.0.1", + "cli-color": "^2.0.1", + "cli-sprintf-format": "^1.1.1", + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "sprintf-kit": "^2.0.1", + "supports-color": "^8.1.1", + "type": "^2.5.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "peer": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "peer": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "peer": true + } + } + }, + "memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "peer": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "peer": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "peer": true + }, + "minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "peer": true + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "peer": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "peer": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "peer": true + }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", + "dev": true, + "peer": true + }, + "ncjsm": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ncjsm/-/ncjsm-4.3.2.tgz", + "integrity": "sha512-6d1VWA7FY31CpI4Ki97Fpm36jfURkVbpktizp8aoVViTZRQgr/0ddmlKerALSSlzfwQRBeSq1qwwVcBJK4Sk7Q==", + "dev": true, + "peer": true, + "requires": { + "builtin-modules": "^3.3.0", + "deferred": "^0.7.11", + "es5-ext": "^0.10.62", + "es6-set": "^0.1.6", + "ext": "^1.7.0", + "find-requires": "^1.0.0", + "fs2": "^0.3.9", + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "peer": true + }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "peer": true, + "requires": { + "minimatch": "^3.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dev": true, + "peer": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "peer": true + }, + "npm-registry-utilities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-utilities/-/npm-registry-utilities-1.0.0.tgz", + "integrity": "sha512-9xYfSJy2IFQw1i6462EJzjChL9e65EfSo2Cw6kl0EFeDp05VvU+anrQk3Fc0d1MbVCq7rWIxeer89O9SUQ/uOg==", + "dev": true, + "peer": true, + "requires": { + "ext": "^1.6.0", + "fs2": "^0.3.9", + "memoizee": "^0.4.15", + "node-fetch": "^2.6.7", + "semver": "^7.3.5", + "type": "^2.6.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + }, + "dependencies": { + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "peer": true + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "peer": true + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "peer": true + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "devOptional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "peer": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "peer": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "peer": true + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "peer": true + }, + "p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "peer": true, + "requires": { + "p-timeout": "^3.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "peer": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "peer": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "peer": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "peer": true + }, + "path-loader": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.12.tgz", + "integrity": "sha512-n7oDG8B+k/p818uweWrOixY9/Dsr89o2TkCm6tOTex3fpdo2+BFDgR+KpB37mGKBRsBAlR8CIJMFN0OEy/7hIQ==", + "dev": true, + "peer": true, + "requires": { + "native-promise-only": "^0.8.1", + "superagent": "^7.1.6" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "path2": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path2/-/path2-0.1.0.tgz", + "integrity": "sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA==", + "dev": true, + "peer": true + }, + "peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "dev": true, + "peer": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "peer": true + }, + "pg": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.1.tgz", + "integrity": "sha512-utdq2obft07MxaDg0zBJI+l/M3mBRfIpEN3iSemsz0G5F2/VXx+XzqF4oxrbIZXQxt2AZzIUzyVg/YM6xOP/WQ==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-cloudflare": "^1.1.1", + "pg-connection-string": "^2.6.1", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "pg-connection-string": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz", + "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "devOptional": true + }, + "pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + }, + "dependencies": { + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + } + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "peer": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "peer": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "peer": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "postgres": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.3.5.tgz", + "integrity": "sha512-+JD93VELV9gHkqpV5gdL5/70HdGtEw4/XE1S4BC8f1mcPmdib3K5XsKVbnR1XcAyC41zOnifJ+9YRKxdIsXiUw==" + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, + "postgres-range": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", + "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==", + "devOptional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "process-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/process-utils/-/process-utils-4.0.0.tgz", + "integrity": "sha512-fMyMQbKCxX51YxR7YGCzPjLsU3yDzXFkP4oi1/Mt5Ixnk7GO/7uUTj8mrCHUwuvozWzI+V7QSJR9cZYnwNOZPg==", + "dev": true, + "peer": true, + "requires": { + "ext": "^1.4.0", + "fs2": "^0.3.9", + "memoizee": "^0.4.14", + "type": "^2.1.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", + "dev": true, + "peer": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "peer": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "peer": true + }, + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "peer": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", + "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", + "dev": true, + "peer": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "peer": true + }, + "ramda": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", + "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "dev": true + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dev": true, + "peer": true, + "requires": { + "readable-stream": "^3.6.0" + } + }, + "readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "requires": { + "minimatch": "^5.1.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "peer": true + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "peer": true + }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "peer": true, + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "peer": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "peer": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "peer": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "peer": true + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "seek-bzip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", + "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", + "dev": true, + "peer": true, + "requires": { + "commander": "^2.8.1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "peer": true + } + } + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serverless": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.33.0.tgz", + "integrity": "sha512-qmG0RMelsWmnS5Smxoy0CbjpecgnJlM89wzSIgJqfkGlmOo2nJdd8y0/E6KlaTsaozlPKkjUBDzis2nF8VNO2g==", + "dev": true, + "peer": true, + "requires": { + "@serverless/dashboard-plugin": "^6.2.3", + "@serverless/platform-client": "^4.3.2", + "@serverless/utils": "^6.11.1", + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "archiver": "^5.3.1", + "aws-sdk": "^2.1404.0", + "bluebird": "^3.7.2", + "cachedir": "^2.3.0", + "chalk": "^4.1.2", + "child-process-ext": "^2.1.1", + "ci-info": "^3.8.0", + "cli-progress-footer": "^2.3.2", + "d": "^1.0.1", + "dayjs": "^1.11.8", + "decompress": "^4.2.1", + "dotenv": "^16.3.1", + "dotenv-expand": "^10.0.0", + "essentials": "^1.2.0", + "ext": "^1.7.0", + "fastest-levenshtein": "^1.0.16", + "filesize": "^10.0.7", + "fs-extra": "^10.1.0", + "get-stdin": "^8.0.0", + "globby": "^11.1.0", + "got": "^11.8.6", + "graceful-fs": "^4.2.11", + "https-proxy-agent": "^5.0.1", + "is-docker": "^2.2.1", + "js-yaml": "^4.1.0", + "json-colorizer": "^2.2.2", + "json-cycle": "^1.5.0", + "json-refs": "^3.0.15", + "lodash": "^4.17.21", + "memoizee": "^0.4.15", + "micromatch": "^4.0.5", + "node-fetch": "^2.6.11", + "npm-registry-utilities": "^1.0.0", + "object-hash": "^3.0.0", + "open": "^8.4.2", + "path2": "^0.1.0", + "process-utils": "^4.0.0", + "promise-queue": "^2.2.5", + "require-from-string": "^2.0.2", + "semver": "^7.5.3", + "signal-exit": "^3.0.7", + "stream-buffers": "^3.0.2", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "tar": "^6.1.15", + "timers-ext": "^0.1.7", + "type": "^2.7.2", + "untildify": "^4.0.0", + "uuid": "^9.0.0", + "ws": "^7.5.9", + "yaml-ast-parser": "0.0.43" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "serverless-dotenv-plugin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serverless-dotenv-plugin/-/serverless-dotenv-plugin-6.0.0.tgz", + "integrity": "sha512-8tLVNwHfDO0sBz6+m+DLTZquRk0AZq9rzqk3kphm1iIWKfan9R7RKt4hdq3eQ0kmDoqzudjPYBEXAJ5bUNKeGQ==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "dotenv": "^16.0.3", + "dotenv-expand": "^10.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "serverless-esbuild": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/serverless-esbuild/-/serverless-esbuild-1.45.1.tgz", + "integrity": "sha512-vPb9R7MoecOv8kdI41BLvYuB5vxBDNKQfGacIuJbmMO25uQHEgyLk27ryb+8XAxmMpb5FuI6/eUZmCK2kRQZZA==", + "dev": true, + "requires": { + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "anymatch": "^3.1.3", + "archiver": "^5.3.1", + "bestzip": "^2.2.1", + "chokidar": "^3.5.3", + "execa": "^5.1.1", + "fp-ts": "^2.13.1", + "fs-extra": "^11.1.0", + "globby": "^11.0.4", + "p-map": "^4.0.0", + "ramda": "^0.28.0", + "semver": "^7.3.8" + }, + "dependencies": { + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "peer": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "peer": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "peer": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "peer": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "simple-git": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz", + "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==", + "dev": true, + "peer": true, + "requires": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "peer": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "peer": true, + "requires": { + "sort-keys": "^1.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "peer": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "sprintf-kit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.1.tgz", + "integrity": "sha512-2PNlcs3j5JflQKcg4wpdqpZ+AjhQJ2OZEo34NXDtlB0tIPG84xaaXhpA8XFacFiwjKA4m49UOYG83y3hbMn/gQ==", + "dev": true, + "peer": true, + "requires": { + "es5-ext": "^0.10.53" + } + }, + "stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true, + "peer": true + }, + "stream-promise": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", + "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", + "dev": true, + "peer": true, + "requires": { + "2-thenable": "^1.0.0", + "es5-ext": "^0.10.49", + "is-stream": "^1.1.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "peer": true, + "requires": { + "is-natural-number": "^4.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "dev": true, + "peer": true, + "requires": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + } + }, + "superagent": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-7.1.6.tgz", + "integrity": "sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g==", + "dev": true, + "peer": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.0.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.10.3", + "readable-stream": "^3.6.0", + "semver": "^7.3.7" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dev": true, + "peer": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true, + "peer": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "peer": true + }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "peer": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true, + "peer": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "dev": true, + "peer": true, + "requires": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "dependencies": { + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "peer": true + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "peer": true + }, + "traverse": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "dev": true, + "peer": true + }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "tslib": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "dev": true, + "peer": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "peer": true + }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "peer": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "peer": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, + "uni-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", + "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", + "dev": true, + "peer": true, + "requires": { + "type": "^2.5.0" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true, + "peer": true + } + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "peer": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + } + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "peer": true + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "dev": true, + "peer": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "peer": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "peer": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "peer": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "peer": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "peer": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "peer": true, + "requires": {} + }, + "xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "peer": true + }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "peer": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "peer": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" + } + }, + "zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "dev": true + } + } +} diff --git a/examples/aws-lambda/package.json b/examples/aws-lambda/package.json new file mode 100644 index 000000000..575be948e --- /dev/null +++ b/examples/aws-lambda/package.json @@ -0,0 +1,28 @@ +{ + "name": "drizzle-aws-lambda", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "migrate": "npx tsx src/db/migrate.ts", + "generate-migration": "npx drizzle-kit generate:pg --schema=./src/db/schema.ts --out=./src/db/migrations", + "get-users": "sls invoke local -f getUsers" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "aws-lambda": "^1.0.7", + "drizzle-orm": "^0.27.0", + "pg": "^8.11.1", + "postgres": "^3.3.5" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "@types/node": "^20.4.0", + "@types/pg": "^8.10.2", + "drizzle-kit": "^0.19.3", + "serverless-dotenv-plugin": "^6.0.0", + "serverless-esbuild": "^1.45.1" + } +} diff --git a/examples/aws-lambda/serverless.yml b/examples/aws-lambda/serverless.yml new file mode 100644 index 000000000..24b988d74 --- /dev/null +++ b/examples/aws-lambda/serverless.yml @@ -0,0 +1,30 @@ +service: drizzle-sample + +plugins: + - serverless-esbuild + - serverless-dotenv-plugin + +package: + individually: true + +custom: + esbuild: + bundle: true + minify: true + stage: ${opt:stage, 'dev'} + +useDotenv: true + +provider: + name: aws + region: eu-west-1 + runtime: nodejs18.x + memorySize: 512 + stage: ${self:custom.stage} + environment: + ENV: ${self:provider.stage} + DATABASE_URL: ${env:DATABASE_URL} + +functions: + getUsers: + handler: ./src/api/user.getAll diff --git a/examples/aws-lambda/src/api/user.ts b/examples/aws-lambda/src/api/user.ts new file mode 100644 index 000000000..b3cbbf780 --- /dev/null +++ b/examples/aws-lambda/src/api/user.ts @@ -0,0 +1,19 @@ +import { APIGatewayEvent, Context } from "aws-lambda"; +import { db } from "db"; + +export const getAll = async (event: APIGatewayEvent, context: Context) => { + try { + const users = await db.query.users.findMany(); + return { + statusCode: 200, + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(users), + }; + } catch (error) { + return { + statusCode: 500, + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(error), + }; + } +}; diff --git a/examples/aws-lambda/src/db/index.ts b/examples/aws-lambda/src/db/index.ts new file mode 100644 index 000000000..3b89d268a --- /dev/null +++ b/examples/aws-lambda/src/db/index.ts @@ -0,0 +1,11 @@ +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; +import * as schema from "./schema"; + +const connectionString = process.env.DATABASE_URL!; + +const pool = new Pool({ + connectionString, +}); + +export const db = drizzle(pool, { schema }); diff --git a/examples/aws-lambda/src/db/migrate.ts b/examples/aws-lambda/src/db/migrate.ts new file mode 100644 index 000000000..48370029f --- /dev/null +++ b/examples/aws-lambda/src/db/migrate.ts @@ -0,0 +1,16 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import { migrate } from "drizzle-orm/postgres-js/migrator"; +import postgres from "postgres"; + +export const migrationClient = postgres("postgresql://postgres:postgres@localhost:5432/drizzle", { max: 1 }); + +// this will automatically run needed migrations on the database +migrate(drizzle(migrationClient), { migrationsFolder: "./src/db/migrations" }) + .then(() => { + console.log("Migrations complete!"); + process.exit(0); + }) + .catch((err) => { + console.error("Migrations failed!", err); + process.exit(1); + }); diff --git a/examples/aws-lambda/src/db/migrations/0000_simple_satana.sql b/examples/aws-lambda/src/db/migrations/0000_simple_satana.sql new file mode 100644 index 000000000..85691404b --- /dev/null +++ b/examples/aws-lambda/src/db/migrations/0000_simple_satana.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS "users" ( + "uuid1" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "name" text +); diff --git a/examples/aws-lambda/src/db/migrations/meta/0000_snapshot.json b/examples/aws-lambda/src/db/migrations/meta/0000_snapshot.json new file mode 100644 index 000000000..7f5d542a2 --- /dev/null +++ b/examples/aws-lambda/src/db/migrations/meta/0000_snapshot.json @@ -0,0 +1,37 @@ +{ + "version": "5", + "dialect": "pg", + "id": "62258ed7-dbf9-4db9-9a50-da9332d2d66a", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "users": { + "name": "users", + "schema": "", + "columns": { + "uuid1": { + "name": "uuid1", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/examples/aws-lambda/src/db/migrations/meta/_journal.json b/examples/aws-lambda/src/db/migrations/meta/_journal.json new file mode 100644 index 000000000..d6a5ae6ba --- /dev/null +++ b/examples/aws-lambda/src/db/migrations/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "5", + "dialect": "pg", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1688758142381, + "tag": "0000_simple_satana", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/examples/aws-lambda/src/db/schema.ts b/examples/aws-lambda/src/db/schema.ts new file mode 100644 index 000000000..be2a2219c --- /dev/null +++ b/examples/aws-lambda/src/db/schema.ts @@ -0,0 +1,6 @@ +import { pgTable, text, uuid } from "drizzle-orm/pg-core"; + +export const users = pgTable("users", { + id: uuid("uuid1").defaultRandom().primaryKey(), + name: text("name"), +}); diff --git a/examples/aws-lambda/tsconfig.json b/examples/aws-lambda/tsconfig.json new file mode 100644 index 000000000..0c9303ec6 --- /dev/null +++ b/examples/aws-lambda/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "lib": ["es6"], + "allowJs": true, + "outDir": "build", + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true, + "isolatedModules": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, + "baseUrl": "./src" + }, + "include": ["./src", "*.d.ts"], + "exclude": ["./.esbuild"] +} diff --git a/examples/better-sqlite3/.gitignore b/examples/better-sqlite3/.gitignore new file mode 100644 index 000000000..7ce04197e --- /dev/null +++ b/examples/better-sqlite3/.gitignore @@ -0,0 +1 @@ +sqlite.db \ No newline at end of file diff --git a/examples/better-sqlite3/drizzle.config.ts b/examples/better-sqlite3/drizzle.config.ts new file mode 100644 index 000000000..d67c60616 --- /dev/null +++ b/examples/better-sqlite3/drizzle.config.ts @@ -0,0 +1,10 @@ +import type { Config } from "drizzle-kit"; + +export default { + schema: "./src/schema.ts", + out: "./drizzle", + driver: "better-sqlite", + dbCredentials: { + url: "./sqlite.db", + }, +} satisfies Config; diff --git a/examples/better-sqlite3/drizzle/0000_omniscient_salo.sql b/examples/better-sqlite3/drizzle/0000_omniscient_salo.sql new file mode 100644 index 000000000..29a64f7bd --- /dev/null +++ b/examples/better-sqlite3/drizzle/0000_omniscient_salo.sql @@ -0,0 +1,11 @@ +CREATE TABLE `projects` ( + `id` integer PRIMARY KEY NOT NULL, + `name` text, + `owner_id` integer NOT NULL, + FOREIGN KEY (`owner_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action +); +--> statement-breakpoint +CREATE TABLE `users` ( + `id` integer PRIMARY KEY NOT NULL, + `full_name` text +); diff --git a/examples/better-sqlite3/drizzle/meta/0000_snapshot.json b/examples/better-sqlite3/drizzle/meta/0000_snapshot.json new file mode 100644 index 000000000..a78e1a749 --- /dev/null +++ b/examples/better-sqlite3/drizzle/meta/0000_snapshot.json @@ -0,0 +1,81 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "a354d184-80c0-46bf-91f2-52878776e3ca", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "projects_owner_id_users_id_fk": { + "name": "projects_owner_id_users_id_fk", + "tableFrom": "projects", + "tableTo": "users", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "full_name": { + "name": "full_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/examples/better-sqlite3/drizzle/meta/_journal.json b/examples/better-sqlite3/drizzle/meta/_journal.json new file mode 100644 index 000000000..1a972049f --- /dev/null +++ b/examples/better-sqlite3/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "5", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1689538038545, + "tag": "0000_omniscient_salo", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/examples/better-sqlite3/migrate.ts b/examples/better-sqlite3/migrate.ts new file mode 100644 index 000000000..409492909 --- /dev/null +++ b/examples/better-sqlite3/migrate.ts @@ -0,0 +1,9 @@ +import { drizzle } from "drizzle-orm/better-sqlite3"; +import { migrate } from "drizzle-orm/better-sqlite3/migrator"; +import Database from "better-sqlite3"; + +const sqlite = new Database("sqlite.db"); +const db = drizzle(sqlite); + +// this will automatically run needed migrations on the database +migrate(db, { migrationsFolder: "./drizzle" }); diff --git a/examples/better-sqlite3/package-lock.json b/examples/better-sqlite3/package-lock.json new file mode 100644 index 000000000..01a37f6c4 --- /dev/null +++ b/examples/better-sqlite3/package-lock.json @@ -0,0 +1,1845 @@ +{ + "name": "better-sqlite3", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "better-sqlite3", + "version": "0.0.0", + "dependencies": { + "better-sqlite3": "^8.4.0", + "drizzle-orm": "^0.27.2" + }, + "devDependencies": { + "@types/better-sqlite3": "^7.6.4", + "drizzle-kit": "^0.19.6", + "tsx": "^3.12.7" + } + }, + "node_modules/@drizzle-team/studio": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.1.tgz", + "integrity": "sha512-cHgGezy2ojBFMaU6PZyBkksgFsg2CQ8IRN4mS7WdbA/Zv6xUK6fCNmpEWS/FftbxoA4B8Z0XGnuKsaTJEZsGgA==", + "dev": true + }, + "node_modules/@esbuild-kit/cjs-loader": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/cjs-loader/-/cjs-loader-2.4.2.tgz", + "integrity": "sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==", + "dev": true, + "dependencies": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.1.0.tgz", + "integrity": "sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==", + "dev": true, + "dependencies": { + "esbuild": "~0.17.6", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", + "integrity": "sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==", + "dev": true, + "dependencies": { + "@esbuild-kit/core-utils": "^3.0.0", + "get-tsconfig": "^4.4.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.13.tgz", + "integrity": "sha512-KwqFhxRFMKZINHzCqf8eKxE0XqWlAVPRxwy6rc7CbVFxzUWB2sA/s3hbMZeemPdhN3fKBkqOaFhTbS8xJXYIWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.13.tgz", + "integrity": "sha512-j7NhycJUoUAG5kAzGf4fPWfd17N6SM3o1X6MlXVqfHvs2buFraCJzos9vbeWjLxOyBKHyPOnuCuipbhvbYtTAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.13.tgz", + "integrity": "sha512-M2eZkRxR6WnWfVELHmv6MUoHbOqnzoTVSIxgtsyhm/NsgmL+uTmag/VVzdXvmahak1I6sOb1K/2movco5ikDJg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.13.tgz", + "integrity": "sha512-f5goG30YgR1GU+fxtaBRdSW3SBG9pZW834Mmhxa6terzcboz7P2R0k4lDxlkP7NYRIIdBbWp+VgwQbmMH4yV7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.13.tgz", + "integrity": "sha512-RIrxoKH5Eo+yE5BtaAIMZaiKutPhZjw+j0OCh8WdvKEKJQteacq0myZvBDLU+hOzQOZWJeDnuQ2xgSScKf1Ovw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.13.tgz", + "integrity": "sha512-AfRPhHWmj9jGyLgW/2FkYERKmYR+IjYxf2rtSLmhOrPGFh0KCETFzSjx/JX/HJnvIqHt/DRQD/KAaVsUKoI3Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.13.tgz", + "integrity": "sha512-pGzWWZJBInhIgdEwzn8VHUBang8UvFKsvjDkeJ2oyY5gZtAM6BaxK0QLCuZY+qoj/nx/lIaItH425rm/hloETA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.13.tgz", + "integrity": "sha512-4iMxLRMCxGyk7lEvkkvrxw4aJeC93YIIrfbBlUJ062kilUUnAiMb81eEkVvCVoh3ON283ans7+OQkuy1uHW+Hw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.13.tgz", + "integrity": "sha512-hCzZbVJEHV7QM77fHPv2qgBcWxgglGFGCxk6KfQx6PsVIdi1u09X7IvgE9QKqm38OpkzaAkPnnPqwRsltvLkIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.13.tgz", + "integrity": "sha512-I3OKGbynl3AAIO6onXNrup/ttToE6Rv2XYfFgLK/wnr2J+1g+7k4asLrE+n7VMhaqX+BUnyWkCu27rl+62Adug==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.13.tgz", + "integrity": "sha512-8pcKDApAsKc6WW51ZEVidSGwGbebYw2qKnO1VyD8xd6JN0RN6EUXfhXmDk9Vc4/U3Y4AoFTexQewQDJGsBXBpg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.13.tgz", + "integrity": "sha512-6GU+J1PLiVqWx8yoCK4Z0GnfKyCGIH5L2KQipxOtbNPBs+qNDcMJr9euxnyJ6FkRPyMwaSkjejzPSISD9hb+gg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.13.tgz", + "integrity": "sha512-pfn/OGZ8tyR8YCV7MlLl5hAit2cmS+j/ZZg9DdH0uxdCoJpV7+5DbuXrR+es4ayRVKIcfS9TTMCs60vqQDmh+w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.13.tgz", + "integrity": "sha512-aIbhU3LPg0lOSCfVeGHbmGYIqOtW6+yzO+Nfv57YblEK01oj0mFMtvDJlOaeAZ6z0FZ9D13oahi5aIl9JFphGg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.13.tgz", + "integrity": "sha512-Pct1QwF2sp+5LVi4Iu5Y+6JsGaV2Z2vm4O9Dd7XZ5tKYxEHjFtb140fiMcl5HM1iuv6xXO8O1Vrb1iJxHlv8UA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.13.tgz", + "integrity": "sha512-zTrIP0KzYP7O0+3ZnmzvUKgGtUvf4+piY8PIO3V8/GfmVd3ZyHJGz7Ht0np3P1wz+I8qJ4rjwJKqqEAbIEPngA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.13.tgz", + "integrity": "sha512-I6zs10TZeaHDYoGxENuksxE1sxqZpCp+agYeW039yqFwh3MgVvdmXL5NMveImOC6AtpLvE4xG5ujVic4NWFIDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.13.tgz", + "integrity": "sha512-W5C5nczhrt1y1xPG5bV+0M12p2vetOGlvs43LH8SopQ3z2AseIROu09VgRqydx5qFN7y9qCbpgHLx0kb0TcW7g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.13.tgz", + "integrity": "sha512-X/xzuw4Hzpo/yq3YsfBbIsipNgmsm8mE/QeWbdGdTTeZ77fjxI2K0KP3AlhZ6gU3zKTw1bKoZTuKLnqcJ537qw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.13.tgz", + "integrity": "sha512-4CGYdRQT/ILd+yLLE5i4VApMPfGE0RPc/wFQhlluDQCK09+b4JDbxzzjpgQqTPrdnP7r5KUtGVGZYclYiPuHrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.13.tgz", + "integrity": "sha512-D+wKZaRhQI+MUGMH+DbEr4owC2D7XnF+uyGiZk38QbgzLcofFqIOwFs7ELmIeU45CQgfHNy9Q+LKW3cE8g37Kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.13.tgz", + "integrity": "sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/better-sqlite3": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.4.tgz", + "integrity": "sha512-dzrRZCYPXIXfSR1/surNbJ/grU3scTaygS0OMzjlGf71i9sc2fGyHPXXiXmEvNIoE0cGwsanEFMVJxPXmco9Eg==", + "devOptional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", + "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", + "devOptional": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/better-sqlite3": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-8.4.0.tgz", + "integrity": "sha512-NmsNW1CQvqMszu/CFAJ3pLct6NEFlNfuGM6vw72KHkjOD1UDnL96XNN1BMQc1hiHo8vE2GbOWQYIpZ+YM5wrZw==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dreamopt": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz", + "integrity": "sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==", + "dev": true, + "dependencies": { + "wordwrap": ">=0.0.2" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/drizzle-kit": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.19.6.tgz", + "integrity": "sha512-Feb/9yKPn6rZI95NvaUwTwpfRJkwGx9MR7ObhUropm+rEwcT9BfHdiJXGzLf4oNcoSFCqmY7zIj8j92lusjyRA==", + "dev": true, + "dependencies": { + "@drizzle-team/studio": "^0.0.1", + "@esbuild-kit/esm-loader": "^2.5.5", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "commander": "^9.4.1", + "esbuild": "^0.18.6", + "esbuild-register": "^3.4.2", + "glob": "^8.1.0", + "hanji": "^0.0.5", + "json-diff": "0.9.0", + "minimatch": "^7.4.3", + "zod": "^3.20.2" + }, + "bin": { + "drizzle-kit": "index.cjs" + } + }, + "node_modules/drizzle-orm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.27.2.tgz", + "integrity": "sha512-ZvBvceff+JlgP7FxHKe0zOU9CkZ4RcOtibumIrqfYzDGuOeF0YUY0F9iMqYpRM7pxnLRfC+oO7rWOUH3T5oFQA==", + "peerDependencies": { + "@aws-sdk/client-rds-data": ">=3", + "@cloudflare/workers-types": ">=3", + "@libsql/client": "*", + "@neondatabase/serverless": ">=0.1", + "@opentelemetry/api": "^1.4.1", + "@planetscale/database": ">=1", + "@types/better-sqlite3": "*", + "@types/pg": "*", + "@types/sql.js": "*", + "@vercel/postgres": "*", + "better-sqlite3": ">=7", + "bun-types": "*", + "knex": "*", + "kysely": "*", + "mysql2": ">=2", + "pg": ">=8", + "postgres": ">=3", + "sql.js": ">=1", + "sqlite3": ">=5" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-rds-data": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "@neondatabase/serverless": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@types/better-sqlite3": { + "optional": true + }, + "@types/pg": { + "optional": true + }, + "@types/sql.js": { + "optional": true + }, + "@vercel/postgres": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "bun-types": { + "optional": true + }, + "knex": { + "optional": true + }, + "kysely": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "postgres": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.18.13", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.13.tgz", + "integrity": "sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.13", + "@esbuild/android-arm64": "0.18.13", + "@esbuild/android-x64": "0.18.13", + "@esbuild/darwin-arm64": "0.18.13", + "@esbuild/darwin-x64": "0.18.13", + "@esbuild/freebsd-arm64": "0.18.13", + "@esbuild/freebsd-x64": "0.18.13", + "@esbuild/linux-arm": "0.18.13", + "@esbuild/linux-arm64": "0.18.13", + "@esbuild/linux-ia32": "0.18.13", + "@esbuild/linux-loong64": "0.18.13", + "@esbuild/linux-mips64el": "0.18.13", + "@esbuild/linux-ppc64": "0.18.13", + "@esbuild/linux-riscv64": "0.18.13", + "@esbuild/linux-s390x": "0.18.13", + "@esbuild/linux-x64": "0.18.13", + "@esbuild/netbsd-x64": "0.18.13", + "@esbuild/openbsd-x64": "0.18.13", + "@esbuild/sunos-x64": "0.18.13", + "@esbuild/win32-arm64": "0.18.13", + "@esbuild/win32-ia32": "0.18.13", + "@esbuild/win32-x64": "0.18.13" + } + }, + "node_modules/esbuild-register": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.4.2.tgz", + "integrity": "sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.2.tgz", + "integrity": "sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hanji": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/hanji/-/hanji-0.0.5.tgz", + "integrity": "sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==", + "dev": true, + "dependencies": { + "lodash.throttle": "^4.1.1", + "sisteransi": "^1.0.5" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/json-diff": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.9.0.tgz", + "integrity": "sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==", + "dev": true, + "dependencies": { + "cli-color": "^2.0.0", + "difflib": "~0.2.1", + "dreamopt": "~0.8.0" + }, + "bin": { + "json-diff": "bin/json-diff.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", + "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/tsx": { + "version": "3.12.7", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.7.tgz", + "integrity": "sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==", + "dev": true, + "dependencies": { + "@esbuild-kit/cjs-loader": "^2.4.2", + "@esbuild-kit/core-utils": "^3.0.0", + "@esbuild-kit/esm-loader": "^2.5.5" + }, + "bin": { + "tsx": "dist/cli.js" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/examples/better-sqlite3/package.json b/examples/better-sqlite3/package.json new file mode 100644 index 000000000..fd5d7da29 --- /dev/null +++ b/examples/better-sqlite3/package.json @@ -0,0 +1,19 @@ +{ + "name": "better-sqlite3", + "version": "0.0.0", + "scripts": { + "dev": "tsx src/index.ts", + "generate": "drizzle-kit generate:sqlite", + "migrate": "tsx migrate.ts", + "studio": "drizzle-kit studio" + }, + "dependencies": { + "better-sqlite3": "^8.4.0", + "drizzle-orm": "^0.27.2" + }, + "devDependencies": { + "@types/better-sqlite3": "^7.6.4", + "drizzle-kit": "^0.19.6", + "tsx": "^3.12.7" + } +} diff --git a/examples/better-sqlite3/readme.md b/examples/better-sqlite3/readme.md new file mode 100644 index 000000000..02b663f18 --- /dev/null +++ b/examples/better-sqlite3/readme.md @@ -0,0 +1,18 @@ +# Drizzle better-sqlite3 example + +## Usage + + +``` +npm run generate +npm run migrate +npm run dev +``` + +## Studio +to run web UI use +``` +npm run studio +``` + +reference documentation: [drizzle better-sqlite3 driver](https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/sqlite-core/README.md) \ No newline at end of file diff --git a/examples/better-sqlite3/src/index.ts b/examples/better-sqlite3/src/index.ts new file mode 100644 index 000000000..3d86b221c --- /dev/null +++ b/examples/better-sqlite3/src/index.ts @@ -0,0 +1,35 @@ +import Database from "better-sqlite3"; +import { eq } from "drizzle-orm"; +import { drizzle } from "drizzle-orm/better-sqlite3"; +import { projects, users } from "./schema"; + +const sqlite = new Database("./sqlite.db"); +const db = drizzle(sqlite); + +const res = db + .insert(users) + .values([ + { + fullName: "User_" + Date.now().toString(), + }, + ]) + .run(); + +const userId = res.lastInsertRowid; + +db.insert(projects) + .values([ + { + name: "Project_" + Date.now().toString(), + ownerId: userId as number, + }, + ]) + .run(); + +const allUsersAndProjects = db + .select() + .from(users) + .leftJoin(projects, eq(users.id, projects.ownerId)) + .all(); + +console.log(allUsersAndProjects); diff --git a/examples/better-sqlite3/src/schema.ts b/examples/better-sqlite3/src/schema.ts new file mode 100644 index 000000000..16f7e342a --- /dev/null +++ b/examples/better-sqlite3/src/schema.ts @@ -0,0 +1,14 @@ +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; + +export const users = sqliteTable("users", { + id: integer("id").primaryKey(), // 'id' is the column name + fullName: text("full_name"), +}); + +export const projects = sqliteTable("projects", { + id: integer("id").primaryKey(), // 'id' is the column name + name: text("name"), + ownerId: integer("owner_id") + .notNull() + .references(() => users.id), +}); diff --git a/examples/mysql-proxy/.gitignore b/examples/mysql-proxy/.gitignore new file mode 100644 index 000000000..55371e5c8 --- /dev/null +++ b/examples/mysql-proxy/.gitignore @@ -0,0 +1,2 @@ +node_modules +.vscode \ No newline at end of file diff --git a/examples/mysql-proxy/README.md b/examples/mysql-proxy/README.md new file mode 100644 index 000000000..8bbdf3f7b --- /dev/null +++ b/examples/mysql-proxy/README.md @@ -0,0 +1,178 @@ +Example project for [Drizzle ORM MySQL Proxy package](https://github.com/drizzle-team/drizzle-orm/tree/main/drizzle-orm/src/mysql-proxy) + +Subscribe to our updates on [Twitter](https://twitter.com/DrizzleOrm) and [Discord](https://discord.gg/MdXYZk5QtH) + +--- + +**MySQL Proxy Driver** was designed to easily define custom drivers, https clients, rpc and much more. No need to wait until Drizzle ORM will create support for specific drivers you need. Just create it yourself! 🚀 + +MySQL Proxy driver will do all the work except of 2 things, that you will be responsible for: + +1. Calls to database, http servers or any other way to communicate with database +2. Mapping data from database to `{rows: any[], ...additional db response params}` format. Only `rows` field is required. Rows should be a row array from database for `all` method and a objects for `execute` + +
+This project has simple example of defining http proxy server, that will proxy all calls from drizzle orm to database and back. This example could perfectly fit for serverless applications + +--- + +## Project structure + +1. `schema.ts` - drizzle orm schema file +2. `index.ts` - basic script, that uses drizzle orm pg proxy driver to define logic for server to server communication over http +3. `server.ts` - server implementation example + +### Database calls + +--- + +#### All you need to do - is to setup drizzle database instance with http call implementation + +
+ +> **Warning**: +> You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][] | object[]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back +> +> For `all` method you should return `{rows: string[][]}` +> For `execute` method you should return `{rows: object[]}` + +
+ +```typescript +import axios from 'axios'; +import { drizzle } from 'drizzle-orm/mysql-proxy'; + +const db = drizzle(async (sql, params, method) => { + try { + const rows = await axios.post('http://localhost:3000/query', { + sql, + params, + method, + }); + + return { rows: rows.data }; + } catch (e: any) { + console.error('Error from mysql proxy server: ', e.response.data); + return { rows: [] }; + } +}); +``` + +We have 3 params, that will be sent to server. It's your decision which of them and in which way should be used + +1. `sql` - SQL query (`SELECT * FROM users WHERE id = ?`) +2. `params` - params, that should be sent on database call (For query above it could be: `[1]`) +3. `method` - Method, that was executed (`all` | `execute`). Hint for proxy server on which pg method to invoke + +### Migrations using MySQL Proxy + +--- + +In current MySQL Proxy version - drizzle don't handle transactions for migrations. As for now we are sending an array of queries, that should be executed by user and user should do `commit` or `rollback` logic + +
+ +> **Warning**: +> You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback + +
+ +```typescript +import axios from 'axios'; +import { migrate } from 'drizzle-orm/mysql-proxy/migrator'; + +await migrate(db, async (queries) => { + try { + await axios.post('http://localhost:3000/migrate', { queries }); + } catch (e) { + console.log(e); + throw Error('Proxy server cannot run migrations'); + } +}, { migrationsFolder: 'drizzle' }); +``` + +1. `queries` - array of sql statements, that should be run on migration + +### Proxy Server implementation example + +--- + +> **Note**: +> It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls + +```typescript +import * as mysql from 'mysql2/promise'; +import express from 'express'; + +const app = express(); +app.use(express.json()); +const port = 3000; + +const main = async () => { +const connection = await mysql.createConnection('mysql://root:mysql@127.0.0.1:5432/drizzle'); + +app.post('/query', async (req, res) => { + const { sql: sqlBody, params, method } = req.body; + + if (method === 'all') { + try { + const result = await connection.query({ + sql: sqlBody, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + res.send(result[0]); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else if (method === 'execute') { + try { + const result = await connection.query({ + sql: sqlBody, + values: params, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + res.send(result); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else { + res.status(500).json({ error: 'Unknown method value' }); + } +}); + +app.post('/migrate', async (req, res) => { + const { queries } = req.body; + + await connection.query('BEGIN'); + try { + for (const query of queries) { + await connection.query(query); + } + await connection.query('COMMIT'); + } catch { + await connection.query('ROLLBACK'); + } + + res.send({}); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +} + +main(); +``` diff --git a/examples/mysql-proxy/drizzle/0000_ambiguous_marvel_boy.sql b/examples/mysql-proxy/drizzle/0000_ambiguous_marvel_boy.sql new file mode 100644 index 000000000..284afd483 --- /dev/null +++ b/examples/mysql-proxy/drizzle/0000_ambiguous_marvel_boy.sql @@ -0,0 +1,15 @@ +CREATE TABLE `cities` ( + `id` serial AUTO_INCREMENT NOT NULL, + `name` text NOT NULL, + CONSTRAINT `cities_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `users` ( + `id` serial AUTO_INCREMENT NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL, + `city_id` serial AUTO_INCREMENT, + CONSTRAINT `users_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +ALTER TABLE `users` ADD CONSTRAINT `users_city_id_cities_id_fk` FOREIGN KEY (`city_id`) REFERENCES `cities`(`id`) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/examples/mysql-proxy/drizzle/meta/0000_snapshot.json b/examples/mysql-proxy/drizzle/meta/0000_snapshot.json new file mode 100644 index 000000000..a8aea1038 --- /dev/null +++ b/examples/mysql-proxy/drizzle/meta/0000_snapshot.json @@ -0,0 +1,102 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "0859c898-548b-4943-a451-24aee7831a25", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "cities": { + "name": "cities", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "cities_id": { + "name": "cities_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "city_id": { + "name": "city_id", + "type": "serial", + "primaryKey": false, + "notNull": false, + "autoincrement": true + } + }, + "indexes": {}, + "foreignKeys": { + "users_city_id_cities_id_fk": { + "name": "users_city_id_cities_id_fk", + "tableFrom": "users", + "tableTo": "cities", + "columnsFrom": [ + "city_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/examples/mysql-proxy/drizzle/meta/_journal.json b/examples/mysql-proxy/drizzle/meta/_journal.json new file mode 100644 index 000000000..dd519472e --- /dev/null +++ b/examples/mysql-proxy/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "5", + "dialect": "mysql", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1696232477893, + "tag": "0000_ambiguous_marvel_boy", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/examples/mysql-proxy/package-lock.json b/examples/mysql-proxy/package-lock.json new file mode 100644 index 000000000..0efb375d2 --- /dev/null +++ b/examples/mysql-proxy/package-lock.json @@ -0,0 +1,1808 @@ +{ + "name": "mysql-proxy", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mysql-proxy", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "axios": "^1.5.1", + "express": "^4.18.2", + "express-rate-limit": "^7.0.2", + "mysql2": "^3.6.1" + }, + "devDependencies": { + "@types/express": "^4.17.18", + "drizzle-kit": "^0.19.13", + "tsx": "^3.13.0", + "typescript": "^5.2.2" + } + }, + "node_modules/@drizzle-team/studio": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.5.tgz", + "integrity": "sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==", + "dev": true + }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.18.20", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "dev": true, + "dependencies": { + "@esbuild-kit/core-utils": "^3.3.2", + "get-tsconfig": "^4.7.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", + "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", + "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.0.tgz", + "integrity": "sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", + "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", + "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dreamopt": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz", + "integrity": "sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==", + "dev": true, + "dependencies": { + "wordwrap": ">=0.0.2" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/drizzle-kit": { + "version": "0.19.13", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.19.13.tgz", + "integrity": "sha512-Rba5VW1O2JfJlwVBeZ8Zwt2E2us5oZ08PQBDiVSGlug53TOc8hzXjblZFuF+dnll9/RQEHrkzBmJFgqTvn5Rxg==", + "dev": true, + "dependencies": { + "@drizzle-team/studio": "^0.0.5", + "@esbuild-kit/esm-loader": "^2.5.5", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "commander": "^9.4.1", + "esbuild": "^0.18.6", + "esbuild-register": "^3.4.2", + "glob": "^8.1.0", + "hanji": "^0.0.5", + "json-diff": "0.9.0", + "minimatch": "^7.4.3", + "zod": "^3.20.2" + }, + "bin": { + "drizzle-kit": "index.cjs" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-rate-limit": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.0.2.tgz", + "integrity": "sha512-EZoojG9civtJ6GRR7vE0JErow5q/ltbIl0RGbYhrNJKwBC9/kp2HckpdAvQkkE0sRAAtFDBvILvwZSR2kQroDw==", + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "express": "^4 || ^5" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hanji": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/hanji/-/hanji-0.0.5.tgz", + "integrity": "sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==", + "dev": true, + "dependencies": { + "lodash.throttle": "^4.1.1", + "sisteransi": "^1.0.5" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "node_modules/json-diff": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.9.0.tgz", + "integrity": "sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==", + "dev": true, + "dependencies": { + "cli-color": "^2.0.0", + "difflib": "~0.2.1", + "dreamopt": "~0.8.0" + }, + "bin": { + "json-diff": "bin/json-diff.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "dev": true + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/lru-cache": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", + "engines": { + "node": ">=16.14" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/mysql2": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.6.1.tgz", + "integrity": "sha512-O7FXjLtNkjcMBpLURwkXIhyVbX9i4lq4nNRCykPNOXfceq94kJ0miagmTEGCZieuO8JtwtXaZ41U6KT4eF9y3g==", + "dependencies": { + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsx": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.13.0.tgz", + "integrity": "sha512-rjmRpTu3as/5fjNq/kOkOtihgLxuIz6pbKdj9xwP4J5jOLkBxw/rjN5ANw+KyrrOXV5uB7HC8+SrrSJxT65y+A==", + "dev": true, + "dependencies": { + "esbuild": "~0.18.20", + "get-tsconfig": "^4.7.2", + "source-map-support": "^0.5.21" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/zod": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", + "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/examples/mysql-proxy/package.json b/examples/mysql-proxy/package.json new file mode 100644 index 000000000..5f1104180 --- /dev/null +++ b/examples/mysql-proxy/package.json @@ -0,0 +1,26 @@ +{ + "name": "mysql-proxy", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test:types": "tsc --noEmit", + "start:script": "tsx src/index.ts", + "start:proxy-server": "tsx src/server.ts", + "generate": "drizzle-kit generate:mysql --schema src/schema.ts" + }, + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^1.5.1", + "express": "^4.18.2", + "express-rate-limit": "^7.0.2", + "mysql2": "^3.6.1" + }, + "devDependencies": { + "@types/express": "^4.17.18", + "drizzle-kit": "^0.19.13", + "tsx": "^3.13.0", + "typescript": "^5.2.2" + } +} diff --git a/examples/mysql-proxy/src/index.ts b/examples/mysql-proxy/src/index.ts new file mode 100644 index 000000000..8de2fe337 --- /dev/null +++ b/examples/mysql-proxy/src/index.ts @@ -0,0 +1,36 @@ +import axios from 'axios'; +import { eq } from 'drizzle-orm/expressions'; +import { drizzle } from 'drizzle-orm/mysql-proxy'; +import { migrate } from 'drizzle-orm/mysql-proxy/migrator'; +import { cities, users } from './schema'; + +async function main() { + const db = drizzle(async (sql, params, method) => { + try { + const rows = await axios.post('http://localhost:3000/query', { sql, params, method }); + + return { rows: rows.data }; + } catch (e: any) { + console.error('Error from pg proxy server:', e.response.data); + return { rows: [] }; + } + }); + + await migrate(db, async (queries) => { + try { + await axios.post('http://localhost:3000/migrate', { queries }); + } catch (e) { + console.log(e); + throw new Error('Proxy server cannot run migrations'); + } + }, { migrationsFolder: 'drizzle' }); + + await db.insert(cities).values({ id: 1, name: 'name' }); + + await db.insert(users).values({ id: 1, name: 'name', email: 'email', cityId: 1 }); + + const usersToCityResponse = await db.select().from(users).leftJoin(cities, eq(users.cityId, cities.id)); + console.log('usersToCityResponse:', usersToCityResponse); +} + +main(); diff --git a/examples/mysql-proxy/src/schema.ts b/examples/mysql-proxy/src/schema.ts new file mode 100644 index 000000000..4c8f58ee3 --- /dev/null +++ b/examples/mysql-proxy/src/schema.ts @@ -0,0 +1,13 @@ +import { mysqlTable, serial, text } from "drizzle-orm/mysql-core"; + +export const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), + cityId: serial('city_id').references(() => cities.id), +}); + +export const cities = mysqlTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); diff --git a/examples/mysql-proxy/src/server.ts b/examples/mysql-proxy/src/server.ts new file mode 100644 index 000000000..98842f4c0 --- /dev/null +++ b/examples/mysql-proxy/src/server.ts @@ -0,0 +1,85 @@ +import * as mysql from 'mysql2/promise'; +import express from 'express'; +import RateLimit from 'express-rate-limit'; + +const app = express(); + +const limiter = RateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // max 100 requests per windowMs +}); + +app.use(express.json()); +app.use(limiter); +const port = 3000; + +const main = async () => { +const connection = await mysql.createConnection('mysql://root:mysql@127.0.0.1:5432/drizzle'); + +app.post('/query', async (req, res) => { + const { sql, params, method } = req.body; + + // prevent multiple queries + const sqlBody = sql.replace(/;/g, ''); + + if (method === 'all') { + try { + const result = await connection.query({ + sql: sqlBody, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + res.send(result[0]); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else if (method === 'execute') { + try { + const result = await connection.query({ + sql: sqlBody, + values: params, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + res.send(result); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else { + res.status(500).json({ error: 'Unknown method value' }); + } +}); + +app.post('/migrate', async (req, res) => { + const { queries } = req.body; + + await connection.query('BEGIN'); + try { + for (const query of queries) { + await connection.query(query); + } + await connection.query('COMMIT'); + } catch { + await connection.query('ROLLBACK'); + } + + res.send({}); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +} + +main(); diff --git a/examples/mysql-proxy/tsconfig.json b/examples/mysql-proxy/tsconfig.json new file mode 100644 index 000000000..453f11f98 --- /dev/null +++ b/examples/mysql-proxy/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "module": "commonjs" /* Specify what module code is generated. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, + "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, + "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, + "strictBindCallApply": true /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */, + "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */, + "noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */, + "useUnknownInCatchVariables": true /* Default catch clause variables as 'unknown' instead of 'any'. */, + "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + "exactOptionalPropertyTypes": true /* Interpret optional property types as written, rather than adding 'undefined'. */, + "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, + "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, + "noUncheckedIndexedAccess": true /* Add 'undefined' to a type when accessed using an index. */, + "noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */, + "noPropertyAccessFromIndexSignature": true /* Enforces using indexed accessors for keys declared using an indexed type. */, + "skipLibCheck": true /* Skip type checking all .d.ts files. */, + } +} diff --git a/examples/pg-proxy/.gitignore b/examples/pg-proxy/.gitignore new file mode 100644 index 000000000..55371e5c8 --- /dev/null +++ b/examples/pg-proxy/.gitignore @@ -0,0 +1,2 @@ +node_modules +.vscode \ No newline at end of file diff --git a/examples/pg-proxy/README.md b/examples/pg-proxy/README.md new file mode 100644 index 000000000..d9ff24fb1 --- /dev/null +++ b/examples/pg-proxy/README.md @@ -0,0 +1,162 @@ +Example project for [Drizzle ORM Postgres Proxy package](https://github.com/drizzle-team/drizzle-orm/tree/main/drizzle-orm/src/pg-proxy) + +Subscribe to our updates on [Twitter](https://twitter.com/DrizzleOrm) and [Discord](https://discord.gg/MdXYZk5QtH) + +--- + +**Postgres Proxy Driver** was designed to easily define custom drivers, https clients, rpc and much more. No need to wait until Drizzle ORM will create support for specific drivers you need. Just create it yourself! 🚀 + +Postgres Proxy driver will do all the work except of 2 things, that you will be responsible for: + +1. Calls to database, http servers or any other way to communicate with database +2. Mapping data from database to `{rows: any[], ...additional db response params}` format. Only `rows` field is required. Rows should be a row array from database for `all` method and a objects for `execute` + +
+This project has simple example of defining http proxy server, that will proxy all calls from drizzle orm to database and back. This example could perfectly fit for serverless applications + +--- + +## Project structure + +1. `schema.ts` - drizzle orm schema file +2. `index.ts` - basic script, that uses drizzle orm pg proxy driver to define logic for server to server communication over http +3. `server.ts` - server implementation example + +### Database calls + +--- + +#### All you need to do - is to setup drizzle database instance with http call implementation + +
+ +> **Warning**: +> You will be responsible for proper error handling in this part. Drizzle always waits for `{rows: string[][] | object[]}` so if any error was on http call(or any other call) - be sure, that you return at least empty array back +> +> For `all` method you should return `{rows: string[][]}` +> For `execute` method you should return `{rows: object[]}` + +
+ +```typescript +import axios from 'axios'; +import { drizzle } from 'drizzle-orm/pg-proxy'; + +const db = drizzle(async (sql, params, method) => { + try { + const rows = await axios.post('http://localhost:3000/query', { + sql, + params, + method, + }); + + return { rows: rows.data }; + } catch (e: any) { + console.error('Error from pg proxy server: ', e.response.data); + return { rows: [] }; + } +}); +``` + +We have 3 params, that will be sent to server. It's your decision which of them and in which way should be used + +1. `sql` - SQL query (`SELECT * FROM users WHERE id = ?`) +2. `params` - params, that should be sent on database call (For query above it could be: `[1]`) +3. `method` - Method, that was executed (`all` | `execute`). Hint for proxy server on which pg method to invoke + +### Migrations using Postgres Proxy + +--- + +In current Postgres Proxy version - drizzle don't handle transactions for migrations. As for now we are sending an array of queries, that should be executed by user and user should do `commit` or `rollback` logic + +
+ +> **Warning**: +> You will be responsible for proper error handling in this part. Drizzle just finds migrations, that need to be executed on this iteration and if finds some -> provide `queries` array to callback + +
+ +```typescript +import axios from 'axios'; +import { migrate } from 'drizzle-orm/pg-proxy/migrator'; + +await migrate(db, async (queries) => { + try { + await axios.post('http://localhost:3000/migrate', { queries }); + } catch (e) { + console.log(e); + throw Error('Proxy server cannot run migrations'); + } +}, { migrationsFolder: 'drizzle' }); +``` + +1. `queries` - array of sql statements, that should be run on migration + +### Proxy Server implementation example + +--- + +> **Note**: +> It's just a suggestion on how proxy server could be set up and a simple example of params handling on `query` and `migration` calls + +```typescript +import { Client } from 'pg'; +import express from 'express'; + +const app = express(); +app.use(express.json()); +const port = 3000; + +const client = new Client('postgres://postgres:postgres@localhost:5432/postgres'); + +app.post('/query', async (req, res) => { + const { sql: sqlBody, params, method } = req.body; + + if (method === 'all') { + try { + const result = await client.query({ + text: sqlBody, + values: params, + rowMode: 'array', + }); + res.send(result.rows); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else if (method === 'execute') { + try { + const result = await client.query({ + text: sqlBody, + values: params, + }); + + res.send(result.rows); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else { + res.status(500).json({ error: 'Unknown method value' }); + } +}); + +app.post('/migrate', async (req, res) => { + const { queries } = req.body; + + await client.query('BEGIN'); + try { + for (const query of queries) { + await client.query(query); + } + await client.query('COMMIT'); + } catch { + await client.query('ROLLBACK'); + } + + res.send({}); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); +``` diff --git a/examples/pg-proxy/drizzle/0000_loving_gravity.sql b/examples/pg-proxy/drizzle/0000_loving_gravity.sql new file mode 100644 index 000000000..00c1f54ca --- /dev/null +++ b/examples/pg-proxy/drizzle/0000_loving_gravity.sql @@ -0,0 +1,17 @@ +CREATE TABLE IF NOT EXISTS "cities" ( + "id" serial PRIMARY KEY NOT NULL, + "name" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "users" ( + "id" serial PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "city_id" serial NOT NULL +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "users" ADD CONSTRAINT "users_city_id_cities_id_fk" FOREIGN KEY ("city_id") REFERENCES "cities"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/examples/pg-proxy/drizzle/meta/0000_snapshot.json b/examples/pg-proxy/drizzle/meta/0000_snapshot.json new file mode 100644 index 000000000..5b95cc690 --- /dev/null +++ b/examples/pg-proxy/drizzle/meta/0000_snapshot.json @@ -0,0 +1,85 @@ +{ + "version": "5", + "dialect": "pg", + "id": "2d1f89a5-9e67-4d3a-8769-89f5c509df82", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "cities": { + "name": "cities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "city_id": { + "name": "city_id", + "type": "serial", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "users_city_id_cities_id_fk": { + "name": "users_city_id_cities_id_fk", + "tableFrom": "users", + "tableTo": "cities", + "columnsFrom": [ + "city_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/examples/pg-proxy/drizzle/meta/_journal.json b/examples/pg-proxy/drizzle/meta/_journal.json new file mode 100644 index 000000000..f24425954 --- /dev/null +++ b/examples/pg-proxy/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "5", + "dialect": "pg", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1696231532854, + "tag": "0000_loving_gravity", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/examples/pg-proxy/package-lock.json b/examples/pg-proxy/package-lock.json new file mode 100644 index 000000000..794f959b9 --- /dev/null +++ b/examples/pg-proxy/package-lock.json @@ -0,0 +1,1950 @@ +{ + "name": "pg-proxy", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pg-proxy", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "axios": "^1.5.1", + "express": "^4.18.2", + "express-rate-limit": "^7.0.2", + "pg": "^8.11.3" + }, + "devDependencies": { + "@types/express": "^4.17.18", + "@types/pg": "^8.10.3", + "drizzle-kit": "^0.19.13", + "tsx": "^3.13.0", + "typescript": "^5.2.2" + } + }, + "node_modules/@drizzle-team/studio": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.5.tgz", + "integrity": "sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==", + "dev": true + }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.18.20", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "dev": true, + "dependencies": { + "@esbuild-kit/core-utils": "^3.3.2", + "get-tsconfig": "^4.7.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", + "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", + "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.0.tgz", + "integrity": "sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==", + "dev": true + }, + "node_modules/@types/pg": { + "version": "8.10.3", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.3.tgz", + "integrity": "sha512-BACzsw64lCZesclRpZGu55tnqgFAYcrCBP92xLh1KLypZLCOsvJTSTgaoFVTy3lCys/aZTQzfeDxtjwrvdzL2g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/pg/node_modules/pg-types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", + "integrity": "sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==", + "dev": true, + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.0.1", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/pg/node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "dev": true, + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/pg/node_modules/postgres-date": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", + "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/qs": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", + "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", + "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-color": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.3.tgz", + "integrity": "sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.61", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dreamopt": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz", + "integrity": "sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==", + "dev": true, + "dependencies": { + "wordwrap": ">=0.0.2" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/drizzle-kit": { + "version": "0.19.13", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.19.13.tgz", + "integrity": "sha512-Rba5VW1O2JfJlwVBeZ8Zwt2E2us5oZ08PQBDiVSGlug53TOc8hzXjblZFuF+dnll9/RQEHrkzBmJFgqTvn5Rxg==", + "dev": true, + "dependencies": { + "@drizzle-team/studio": "^0.0.5", + "@esbuild-kit/esm-loader": "^2.5.5", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "commander": "^9.4.1", + "esbuild": "^0.18.6", + "esbuild-register": "^3.4.2", + "glob": "^8.1.0", + "hanji": "^0.0.5", + "json-diff": "0.9.0", + "minimatch": "^7.4.3", + "zod": "^3.20.2" + }, + "bin": { + "drizzle-kit": "index.cjs" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-rate-limit": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.0.2.tgz", + "integrity": "sha512-EZoojG9civtJ6GRR7vE0JErow5q/ltbIl0RGbYhrNJKwBC9/kp2HckpdAvQkkE0sRAAtFDBvILvwZSR2kQroDw==", + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "express": "^4 || ^5" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hanji": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/hanji/-/hanji-0.0.5.tgz", + "integrity": "sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==", + "dev": true, + "dependencies": { + "lodash.throttle": "^4.1.1", + "sisteransi": "^1.0.5" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/json-diff": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.9.0.tgz", + "integrity": "sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==", + "dev": true, + "dependencies": { + "cli-color": "^2.0.0", + "difflib": "~0.2.1", + "dreamopt": "~0.8.0" + }, + "bin": { + "json-diff": "bin/json-diff.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "dev": true + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-range": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", + "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsx": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.13.0.tgz", + "integrity": "sha512-rjmRpTu3as/5fjNq/kOkOtihgLxuIz6pbKdj9xwP4J5jOLkBxw/rjN5ANw+KyrrOXV5uB7HC8+SrrSJxT65y+A==", + "dev": true, + "dependencies": { + "esbuild": "~0.18.20", + "get-tsconfig": "^4.7.2", + "source-map-support": "^0.5.21" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/zod": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", + "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/examples/pg-proxy/package.json b/examples/pg-proxy/package.json new file mode 100644 index 000000000..20a049c9b --- /dev/null +++ b/examples/pg-proxy/package.json @@ -0,0 +1,27 @@ +{ + "name": "pg-proxy", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test:types": "tsc --noEmit", + "start:script": "tsx src/index.ts", + "start:proxy-server": "tsx src/server.ts", + "generate": "drizzle-kit generate:pg --schema src/schema.ts" + }, + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^1.5.1", + "express": "^4.18.2", + "express-rate-limit": "^7.0.2", + "pg": "^8.11.3" + }, + "devDependencies": { + "@types/express": "^4.17.18", + "@types/pg": "^8.10.3", + "drizzle-kit": "^0.19.13", + "tsx": "^3.13.0", + "typescript": "^5.2.2" + } +} diff --git a/examples/pg-proxy/src/index.ts b/examples/pg-proxy/src/index.ts new file mode 100644 index 000000000..0cb2bfc9e --- /dev/null +++ b/examples/pg-proxy/src/index.ts @@ -0,0 +1,38 @@ +import axios from 'axios'; +import { eq } from 'drizzle-orm/expressions'; +import { drizzle } from 'drizzle-orm/pg-proxy'; +import { migrate } from 'drizzle-orm/pg-proxy/migrator'; +import { cities, users } from './schema'; + +async function main() { + const db = drizzle(async (sql, params, method) => { + try { + const rows = await axios.post('http://localhost:3000/query', { sql, params, method }); + + return { rows: rows.data }; + } catch (e: any) { + console.error('Error from pg proxy server:', e.response.data); + return { rows: [] }; + } + }); + + await migrate(db, async (queries) => { + try { + await axios.post('http://localhost:3000/migrate', { queries }); + } catch (e) { + console.log(e); + throw new Error('Proxy server cannot run migrations'); + } + }, { migrationsFolder: 'drizzle' }); + + const insertedCity = await db.insert(cities).values({ id: 1, name: 'name' }).returning(); + console.log('insertedCity:', insertedCity); + + const insertedUser = await db.insert(users).values({ id: 1, name: 'name', email: 'email', cityId: 1 }); + console.log('insertedUser:', insertedUser); + + const usersToCityResponse = await db.select().from(users).leftJoin(cities, eq(users.cityId, cities.id)); + console.log('usersToCityResponse:', usersToCityResponse); +} + +main(); diff --git a/examples/pg-proxy/src/schema.ts b/examples/pg-proxy/src/schema.ts new file mode 100644 index 000000000..115af9da0 --- /dev/null +++ b/examples/pg-proxy/src/schema.ts @@ -0,0 +1,13 @@ +import { pgTable, serial, text } from "drizzle-orm/pg-core"; + +export const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), + cityId: serial('city_id').references(() => cities.id), +}); + +export const cities = pgTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); diff --git a/examples/pg-proxy/src/server.ts b/examples/pg-proxy/src/server.ts new file mode 100644 index 000000000..698b6c6ef --- /dev/null +++ b/examples/pg-proxy/src/server.ts @@ -0,0 +1,69 @@ +import { Client } from 'pg'; +import express from 'express'; +import RateLimit from 'express-rate-limit'; + +const app = express(); + +const limiter = RateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // max 100 requests per windowMs +}); + +app.use(express.json()); +app.use(limiter); +const port = 3000; + +const client = new Client('postgres://postgres:postgres@localhost:5432/postgres'); + +app.post('/query', async (req, res) => { + const { sql, params, method } = req.body; + + // prevent multiple queries + const sqlBody = sql.replace(/;/g, ''); + + if (method === 'all') { + try { + const result = await client.query({ + text: sqlBody, + values: params, + rowMode: 'array', + }); + res.send(result.rows); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else if (method === 'execute') { + try { + const result = await client.query({ + text: sqlBody, + values: params, + }); + + res.send(result.rows); + } catch (e: any) { + res.status(500).json({ error: e }); + } + } else { + res.status(500).json({ error: 'Unknown method value' }); + } +}); + +app.post('/migrate', async (req, res) => { + const { queries } = req.body; + + await client.query('BEGIN'); + try { + for (const query of queries) { + await client.query(query); + } + await client.query('COMMIT'); + } catch { + await client.query('ROLLBACK'); + } + + res.send({}); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); diff --git a/examples/pg-proxy/tsconfig.json b/examples/pg-proxy/tsconfig.json new file mode 100644 index 000000000..453f11f98 --- /dev/null +++ b/examples/pg-proxy/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "module": "commonjs" /* Specify what module code is generated. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, + "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, + "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, + "strictBindCallApply": true /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */, + "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */, + "noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */, + "useUnknownInCatchVariables": true /* Default catch clause variables as 'unknown' instead of 'any'. */, + "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + "exactOptionalPropertyTypes": true /* Interpret optional property types as written, rather than adding 'undefined'. */, + "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, + "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, + "noUncheckedIndexedAccess": true /* Add 'undefined' to a type when accessed using an index. */, + "noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */, + "noPropertyAccessFromIndexSignature": true /* Enforces using indexed accessors for keys declared using an indexed type. */, + "skipLibCheck": true /* Skip type checking all .d.ts files. */, + } +} diff --git a/integration-tests/.gitignore b/integration-tests/.gitignore index 045655f19..eeff14916 100644 --- a/integration-tests/.gitignore +++ b/integration-tests/.gitignore @@ -1,3 +1,5 @@ .env *.db trace +tests/imports/imports.cjs +tests/imports/imports.mjs diff --git a/integration-tests/package.json b/integration-tests/package.json index d210f127f..745d1cbe0 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -20,7 +20,11 @@ "!tests/planetscale-serverless/**/*.ts", "!tests/bun/**/*", "!tests/vercel-pg.test.ts", - "!tests/relational/**/*" + "!tests/relational/**/*", + "!tests/libsql-batch.test.ts", + "!tests/d1-batch.test.ts", + "!tests/replicas/**/*", + "!tests/imports/**/*" ], "extensions": { "ts": "module" @@ -49,25 +53,26 @@ "axios": "^1.4.0", "tsx": "^3.12.7", "vite": "^4.3.9", - "vite-tsconfig-paths": "^4.2.0" + "vite-tsconfig-paths": "^4.2.0", + "zx": "^7.2.2" }, "dependencies": { "@aws-sdk/client-rds-data": "^3.345.0", "@aws-sdk/credential-providers": "^3.345.0", "@libsql/client": "^0.1.6", + "@miniflare/d1": "^2.14.0", + "@miniflare/shared": "^2.14.0", "@planetscale/database": "^1.7.0", "@typescript/analyze-trace": "^0.10.0", "@vercel/postgres": "^0.3.0", "better-sqlite3": "^8.4.0", "dockerode": "^3.3.4", "dotenv": "^16.1.4", - "drizzle-zod": "workspace:../drizzle-zod/dist", "drizzle-typebox": "workspace:../drizzle-typebox/dist", "drizzle-valibot": "workspace:../drizzle-valibot/dist", + "drizzle-zod": "workspace:../drizzle-zod/dist", "express": "^4.18.2", "get-port": "^7.0.0", - "@miniflare/shared": "^2.14.0", - "@miniflare/d1": "^2.14.0", "mysql2": "^3.3.3", "pg": "^8.11.0", "postgres": "^3.3.5", diff --git a/integration-tests/tests/awsdatapi.test.ts b/integration-tests/tests/awsdatapi.test.ts index 8ed1921d3..1f390eb70 100644 --- a/integration-tests/tests/awsdatapi.test.ts +++ b/integration-tests/tests/awsdatapi.test.ts @@ -766,7 +766,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -825,7 +825,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); @@ -835,6 +835,29 @@ test.serial('nested transaction rollback', async (t) => { await db.execute(sql`drop table ${users}`); }); +test.serial('select from raw sql', async (t) => { + const { db } = t.context; + + const result = await db.execute(sql`select 1 as id, 'John' as name`); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + ]); +}); + +test.serial('select from raw sql with mapped values', async (t) => { + const { db } = t.context; + + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + ]); +}); + test.after.always(async (t) => { const ctx = t.context; await ctx.db.execute(sql`drop table "users"`); diff --git a/integration-tests/tests/better-sqlite.test.ts b/integration-tests/tests/better-sqlite.test.ts index 9c12cca6b..44e04858b 100644 --- a/integration-tests/tests/better-sqlite.test.ts +++ b/integration-tests/tests/better-sqlite.test.ts @@ -1541,7 +1541,7 @@ test.serial('transaction rollback', (t) => { db.transaction((tx) => { tx.insert(users).values({ balance: 100 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = db.select().from(users).all(); @@ -1600,7 +1600,7 @@ test.serial('nested transaction rollback', (t) => { tx.transaction((tx) => { tx.update(users).set({ balance: 200 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = db.select().from(users).all(); @@ -1846,16 +1846,16 @@ test.serial('insert with onConflict do update where', (t) => { db .insert(usersTable) - .values([{ id: 1, name: "John", verified: false }]) + .values([{ id: 1, name: 'John', verified: false }]) .run(); db .insert(usersTable) - .values({ id: 1, name: "John1", verified: true }) + .values({ id: 1, name: 'John1', verified: true }) .onConflictDoUpdate({ target: usersTable.id, - set: { name: "John1", verified: true }, - where: eq(usersTable.verified, false) + set: { name: 'John1', verified: true }, + where: eq(usersTable.verified, false), }) .run(); @@ -1865,8 +1865,8 @@ test.serial('insert with onConflict do update where', (t) => { .where(eq(usersTable.id, 1)) .all(); - t.deepEqual(res, [{ id: 1, name: "John1", verified: true }]); -}) + t.deepEqual(res, [{ id: 1, name: 'John1', verified: true }]); +}); test.serial('insert undefined', (t) => { const { db } = t.context; @@ -2040,3 +2040,23 @@ test.serial('select + .get() for empty result', (t) => { db.run(sql`drop table ${users}`); }); + +test.serial.only('text w/ json mode', (t) => { + const { db } = t.context; + + const test = sqliteTable('test', { + data: text('data', { mode: 'json' }).notNull(), + dataTyped: text('data_typed', { mode: 'json' }).$type<{ a: 1 }>().notNull(), + }); + + db.run(sql`drop table if exists ${test}`); + db.run(sql`create table ${test} (data text not null, data_typed text not null)`); + + db.insert(test).values({ data: { foo: 'bar' }, dataTyped: { a: 1 } }).run(); + + const res = db.select().from(test).get(); + + t.deepEqual(res, { data: { foo: 'bar' }, dataTyped: { a: 1 } }); + + db.run(sql`drop table ${test}`); +}); diff --git a/integration-tests/tests/bun/sqlite.test.ts b/integration-tests/tests/bun/sqlite.test.ts index 7f21c07d8..faa3f8eb1 100644 --- a/integration-tests/tests/bun/sqlite.test.ts +++ b/integration-tests/tests/bun/sqlite.test.ts @@ -52,7 +52,8 @@ test.before.each((ctx) => { test.skip('select large integer', async (ctx) => { const a = 1667476703000; - const result = ctx.db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`)[0]!; + const res = await ctx.db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); + const result = res[0]!; assert.equal(result.a, a); }); diff --git a/integration-tests/tests/d1-batch.test.ts b/integration-tests/tests/d1-batch.test.ts new file mode 100644 index 000000000..7abebbb51 --- /dev/null +++ b/integration-tests/tests/d1-batch.test.ts @@ -0,0 +1,550 @@ +import 'dotenv/config'; +import { D1Database, D1DatabaseAPI } from '@miniflare/d1'; +import { createSQLiteDB } from '@miniflare/shared'; +import { eq, relations, sql } from 'drizzle-orm'; +import type { DrizzleD1Database } from 'drizzle-orm/d1'; +import { drizzle } from 'drizzle-orm/d1'; +import { type AnySQLiteColumn, integer, primaryKey, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; + +const ENABLE_LOGGING = false; + +export const usersTable = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + verified: integer('verified').notNull().default(0), + invitedBy: integer('invited_by').references((): AnySQLiteColumn => usersTable.id), +}); +export const usersConfig = relations(usersTable, ({ one, many }) => ({ + invitee: one(usersTable, { + fields: [usersTable.invitedBy], + references: [usersTable.id], + }), + usersToGroups: many(usersToGroupsTable), + posts: many(postsTable), +})); + +export const groupsTable = sqliteTable('groups', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + description: text('description'), +}); +export const groupsConfig = relations(groupsTable, ({ many }) => ({ + usersToGroups: many(usersToGroupsTable), +})); + +export const usersToGroupsTable = sqliteTable( + 'users_to_groups', + { + id: integer('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id', { mode: 'number' }).notNull().references( + () => usersTable.id, + ), + groupId: integer('group_id', { mode: 'number' }).notNull().references( + () => groupsTable.id, + ), + }, + (t) => ({ + pk: primaryKey(t.userId, t.groupId), + }), +); +export const usersToGroupsConfig = relations(usersToGroupsTable, ({ one }) => ({ + group: one(groupsTable, { + fields: [usersToGroupsTable.groupId], + references: [groupsTable.id], + }), + user: one(usersTable, { + fields: [usersToGroupsTable.userId], + references: [usersTable.id], + }), +})); + +export const postsTable = sqliteTable('posts', { + id: integer('id').primaryKey({ autoIncrement: true }), + content: text('content').notNull(), + ownerId: integer('owner_id', { mode: 'number' }).references( + () => usersTable.id, + ), + createdAt: integer('created_at', { mode: 'timestamp_ms' }) + .notNull().default(sql`current_timestamp`), +}); +export const postsConfig = relations(postsTable, ({ one, many }) => ({ + author: one(usersTable, { + fields: [postsTable.ownerId], + references: [usersTable.id], + }), + comments: many(commentsTable), +})); + +export const commentsTable = sqliteTable('comments', { + id: integer('id').primaryKey({ autoIncrement: true }), + content: text('content').notNull(), + creator: integer('creator', { mode: 'number' }).references( + () => usersTable.id, + ), + postId: integer('post_id', { mode: 'number' }).references(() => postsTable.id), + createdAt: integer('created_at', { mode: 'timestamp_ms' }) + .notNull().default(sql`current_timestamp`), +}); +export const commentsConfig = relations(commentsTable, ({ one, many }) => ({ + post: one(postsTable, { + fields: [commentsTable.postId], + references: [postsTable.id], + }), + author: one(usersTable, { + fields: [commentsTable.creator], + references: [usersTable.id], + }), + likes: many(commentLikesTable), +})); + +export const commentLikesTable = sqliteTable('comment_likes', { + id: integer('id').primaryKey({ autoIncrement: true }), + creator: integer('creator', { mode: 'number' }).references( + () => usersTable.id, + ), + commentId: integer('comment_id', { mode: 'number' }).references( + () => commentsTable.id, + ), + createdAt: integer('created_at', { mode: 'timestamp_ms' }) + .notNull().default(sql`current_timestamp`), +}); +export const commentLikesConfig = relations(commentLikesTable, ({ one }) => ({ + comment: one(commentsTable, { + fields: [commentLikesTable.commentId], + references: [commentsTable.id], + }), + author: one(usersTable, { + fields: [commentLikesTable.creator], + references: [usersTable.id], + }), +})); + +const schema = { + usersTable, + postsTable, + commentsTable, + usersToGroupsTable, + groupsTable, + commentLikesConfig, + commentsConfig, + postsConfig, + usersToGroupsConfig, + groupsConfig, + usersConfig, +}; + +let db: DrizzleD1Database; + +beforeAll(async () => { + const sqliteDb = await createSQLiteDB(':memory:'); + db = drizzle(new D1Database(new D1DatabaseAPI(sqliteDb)) as any, { schema, logger: ENABLE_LOGGING }); +}); + +beforeEach(async () => { + await db.run(sql`drop table if exists \`groups\``); + await db.run(sql`drop table if exists \`users\``); + await db.run(sql`drop table if exists \`users_to_groups\``); + await db.run(sql`drop table if exists \`posts\``); + await db.run(sql`drop table if exists \`comments\``); + await db.run(sql`drop table if exists \`comment_likes\``); + + await db.run( + sql` + CREATE TABLE \`users\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`verified\` integer DEFAULT 0 NOT NULL, + \`invited_by\` integer + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`groups\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`description\` text + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`users_to_groups\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`user_id\` integer NOT NULL, + \`group_id\` integer NOT NULL + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`posts\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`content\` text NOT NULL, + \`owner_id\` integer, + \`created_at\` integer DEFAULT current_timestamp NOT NULL + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`comments\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`content\` text NOT NULL, + \`creator\` integer, + \`post_id\` integer, + \`created_at\` integer DEFAULT current_timestamp NOT NULL + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`comment_likes\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`creator\` integer, + \`comment_id\` integer, + \`created_at\` integer DEFAULT current_timestamp NOT NULL + ); + `, + ); +}); + +afterAll(async () => { + await db.run(sql`drop table if exists \`groups\``); + await db.run(sql`drop table if exists \`users\``); + await db.run(sql`drop table if exists \`users_to_groups\``); + await db.run(sql`drop table if exists \`posts\``); + await db.run(sql`drop table if exists \`comments\``); + await db.run(sql`drop table if exists \`comment_likes\``); +}); + +test('batch api example', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ + id: usersTable.id, + invitedBy: usersTable.invitedBy, + }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.select().from(usersTable), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + invitedBy: number | null; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(3); + + expect(batchResponse[0]).toEqual([{ + id: 1, + invitedBy: null, + }]); + + // expect(batchResponse[1]).toEqual({ + // results: [], + // success: true, + // meta: { + // duration: 0.027083873748779297, + // last_row_id: 2, + // changes: 1, + // served_by: 'miniflare.db', + // internal_stats: null, + // }, + // }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); +}); + +// batch api only relational many +test('insert + findMany', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.query.usersTable.findMany({}), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(3); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + // expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); +}); + +// batch api relational many + one +test('insert + findMany + findFirst', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.query.usersTable.findMany({}), + db.query.usersTable.findFirst({}), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + } | undefined, + ]>(); + + expect(batchResponse.length).eq(4); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + // expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual( + { id: 1, name: 'John', verified: 0, invitedBy: null }, + ); +}); + +test('insert + db.all + db.get + db.values + db.run', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.run(sql`insert into users (id, name) values (2, 'Dan')`), + db.all(sql`select * from users`), + db.values(sql`select * from users`), + db.get(sql`select * from users`), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + unknown[][], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }, + ]>(); + + expect(batchResponse.length).eq(5); + + expect(batchResponse[0], 'insert').toEqual([{ + id: 1, + }]); + + // expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2], 'all').toEqual([ + { id: 1, name: 'John', verified: 0, invited_by: null }, + { id: 2, name: 'Dan', verified: 0, invited_by: null }, + ]); + + expect(batchResponse[3], 'values').toEqual([[1, 'John', 0, null], [2, 'Dan', 0, null]]); + + expect(batchResponse[4], 'get').toEqual( + { id: 1, name: 'John', verified: 0, invited_by: null }, + ); +}); + +// batch api combined rqb + raw call +test('insert + findManyWith + db.all', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.query.usersTable.findMany({}), + db.all(sql`select * from users`), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(4); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + // expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual([ + { id: 1, name: 'John', verified: 0, invited_by: null }, + { id: 2, name: 'Dan', verified: 0, invited_by: null }, + ]); +}); + +// batch api for insert + update + select +test('insert + update + select + select partial', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.update(usersTable).set({ name: 'Dan' }).where(eq(usersTable.id, 1)), + db.query.usersTable.findMany({}), + db.select().from(usersTable).where(eq(usersTable.id, 1)), + db.select({ id: usersTable.id, invitedBy: usersTable.invitedBy }).from(usersTable), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + D1Result, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(5); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + // expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 1n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual([ + { id: 1, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[4]).toEqual([ + { id: 1, invitedBy: null }, + ]); +}); + +// batch api for insert + delete + select +test('insert + delete + select + select partial', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.delete(usersTable).where(eq(usersTable.id, 1)).returning({ id: usersTable.id, invitedBy: usersTable.invitedBy }), + db.query.usersTable.findFirst({ + columns: { + id: true, + invitedBy: true, + }, + }), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + D1Result, + { + id: number; + invitedBy: number | null; + }[], + { + id: number; + invitedBy: number | null; + } | undefined, + ]>(); + + expect(batchResponse.length).eq(4); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + // expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual( + { id: 2, invitedBy: null }, + ); +}); + +// * additionally +// batch for all libsql cases, just replace simple calls with batch calls +// batch for all rqb cases, just replace simple calls with batch calls diff --git a/integration-tests/tests/d1.test.ts b/integration-tests/tests/d1.test.ts index 05d490e11..04092ced5 100644 --- a/integration-tests/tests/d1.test.ts +++ b/integration-tests/tests/d1.test.ts @@ -1424,7 +1424,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users).all(); @@ -1483,7 +1483,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users).all(); @@ -1669,16 +1669,16 @@ test.serial('insert with onConflict do update where', async (t) => { await db .insert(usersTable) - .values([{ id: 1, name: "John", verified: 0 }]) + .values([{ id: 1, name: 'John', verified: 0 }]) .run(); await db .insert(usersTable) - .values({ id: 1, name: "John1", verified: 0 }) + .values({ id: 1, name: 'John1', verified: 0 }) .onConflictDoUpdate({ target: usersTable.id, - set: { name: "John1", verified: 1 }, - where: eq(usersTable.verified, 0) + set: { name: 'John1', verified: 1 }, + where: eq(usersTable.verified, 0), }) .run(); @@ -1688,8 +1688,8 @@ test.serial('insert with onConflict do update where', async (t) => { .where(eq(usersTable.id, 1)) .all(); - t.deepEqual(res, [{ id: 1, name: "John1", verified: 1 }]); -}) + t.deepEqual(res, [{ id: 1, name: 'John1', verified: 1 }]); +}); test.serial('insert undefined', async (t) => { const { db } = t.context; diff --git a/integration-tests/tests/imports.test.cjs b/integration-tests/tests/imports.test.cjs index a4777f055..a7b11ff80 100644 --- a/integration-tests/tests/imports.test.cjs +++ b/integration-tests/tests/imports.test.cjs @@ -28,6 +28,10 @@ require('drizzle-orm/sql-js/migrator'); require('drizzle-orm/sqlite-core'); require('drizzle-orm/sqlite-proxy'); require('drizzle-orm/sqlite-proxy/migrator'); +require('drizzle-orm/pg-proxy'); +require('drizzle-orm/pg-proxy/migrator'); +require('drizzle-orm/mysql-proxy'); +require('drizzle-orm/mysql-proxy/migrator'); require('drizzle-orm/migrator'); const { createInsertSchema: createZodInsertSchema } = require('drizzle-zod'); const { diff --git a/integration-tests/tests/imports.test.mjs b/integration-tests/tests/imports.test.mjs index 50e94b4e7..d95566b41 100644 --- a/integration-tests/tests/imports.test.mjs +++ b/integration-tests/tests/imports.test.mjs @@ -28,6 +28,10 @@ import 'drizzle-orm/sql-js/migrator'; import 'drizzle-orm/sqlite-core'; import 'drizzle-orm/sqlite-proxy'; import 'drizzle-orm/sqlite-proxy/migrator'; +import 'drizzle-orm/pg-proxy'; +import 'drizzle-orm/pg-proxy/migrator'; +import 'drizzle-orm/mysql-proxy'; +import 'drizzle-orm/mysql-proxy/migrator'; import 'drizzle-orm/migrator'; import { createInsertSchema } from 'drizzle-zod'; import { compatibilityVersion, npmVersion } from 'drizzle-orm/version'; diff --git a/integration-tests/tests/imports/index.test.ts b/integration-tests/tests/imports/index.test.ts new file mode 100644 index 000000000..f89efe00f --- /dev/null +++ b/integration-tests/tests/imports/index.test.ts @@ -0,0 +1,55 @@ +import { afterAll, expect, it } from 'vitest'; +import 'zx/globals'; +import * as fs from 'fs'; +import path from 'path'; + +const IMPORTS_FOLDER = 'tests/imports/files'; + +const folderPath = '../drizzle-orm/dist/package.json'; +const pj = JSON.parse(fs.readFileSync(folderPath, 'utf8')); + +if (!fs.existsSync(IMPORTS_FOLDER)) { + fs.mkdirSync(IMPORTS_FOLDER); +} + +it('dynamic imports check for cjs and mjs', async () => { + const promises: ProcessPromise[] = []; + for (const [i, key] of Object.keys(pj['exports']).entries()) { + const o1 = path.join('drizzle-orm', key); + fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.cjs`, 'requ'); + fs.appendFileSync(`${IMPORTS_FOLDER}/imports_${i}.cjs`, 'ire("' + o1 + '");\n', {}); + + // fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.mjs`, 'imp'); + // fs.appendFileSync(`${IMPORTS_FOLDER}/imports_${i}.mjs`, 'ort "' + o1 + '"\n', {}); + + promises.push( + $`node ${IMPORTS_FOLDER}/imports_${i}.cjs`.nothrow(), + // $`node ${IMPORTS_FOLDER}/imports_${i}.mjs`.nothrow(), + ); + } + const results = await Promise.all(promises); + + for (const result of results) { + expect(result.exitCode, result.message).toBe(0); + } +}); + +// it('dynamic imports check for mjs', async () => { +// const promises: ProcessPromise[] = []; +// for (const [i, key] of Object.keys(pj['exports']).entries()) { +// const o1 = path.join('drizzle-orm', key); +// fs.writeFileSync(`${IMPORTS_FOLDER}/imports_${i}.mjs`, 'imp'); +// fs.appendFileSync(`${IMPORTS_FOLDER}/imports_${i}.mjs`, 'ort "' + o1 + '"\n', {}); +// promises.push($`node ${IMPORTS_FOLDER}/imports_${i}.mjs`.nothrow()); +// } + +// const results = await Promise.all(promises); + +// for (const result of results) { +// expect(result.exitCode, result.message).toBe(0) +// } +// }); + +afterAll(() => { + fs.rmdirSync(IMPORTS_FOLDER, { recursive: true }); +}); diff --git a/integration-tests/tests/libsql-batch.test.ts b/integration-tests/tests/libsql-batch.test.ts new file mode 100644 index 000000000..fd9c61bbd --- /dev/null +++ b/integration-tests/tests/libsql-batch.test.ts @@ -0,0 +1,569 @@ +import 'dotenv/config'; +import type { Client, ResultSet } from '@libsql/client'; +import { createClient } from '@libsql/client'; +import { eq, relations, sql } from 'drizzle-orm'; +import { drizzle, type LibSQLDatabase } from 'drizzle-orm/libsql'; +import { type AnySQLiteColumn, integer, primaryKey, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { afterAll, beforeAll, beforeEach, expect, expectTypeOf, test } from 'vitest'; + +const ENABLE_LOGGING = false; + +export const usersTable = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + verified: integer('verified').notNull().default(0), + invitedBy: integer('invited_by').references((): AnySQLiteColumn => usersTable.id), +}); +export const usersConfig = relations(usersTable, ({ one, many }) => ({ + invitee: one(usersTable, { + fields: [usersTable.invitedBy], + references: [usersTable.id], + }), + usersToGroups: many(usersToGroupsTable), + posts: many(postsTable), +})); + +export const groupsTable = sqliteTable('groups', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + description: text('description'), +}); +export const groupsConfig = relations(groupsTable, ({ many }) => ({ + usersToGroups: many(usersToGroupsTable), +})); + +export const usersToGroupsTable = sqliteTable( + 'users_to_groups', + { + id: integer('id').primaryKey({ autoIncrement: true }), + userId: integer('user_id', { mode: 'number' }).notNull().references( + () => usersTable.id, + ), + groupId: integer('group_id', { mode: 'number' }).notNull().references( + () => groupsTable.id, + ), + }, + (t) => ({ + pk: primaryKey(t.userId, t.groupId), + }), +); +export const usersToGroupsConfig = relations(usersToGroupsTable, ({ one }) => ({ + group: one(groupsTable, { + fields: [usersToGroupsTable.groupId], + references: [groupsTable.id], + }), + user: one(usersTable, { + fields: [usersToGroupsTable.userId], + references: [usersTable.id], + }), +})); + +export const postsTable = sqliteTable('posts', { + id: integer('id').primaryKey({ autoIncrement: true }), + content: text('content').notNull(), + ownerId: integer('owner_id', { mode: 'number' }).references( + () => usersTable.id, + ), + createdAt: integer('created_at', { mode: 'timestamp_ms' }) + .notNull().default(sql`current_timestamp`), +}); +export const postsConfig = relations(postsTable, ({ one, many }) => ({ + author: one(usersTable, { + fields: [postsTable.ownerId], + references: [usersTable.id], + }), + comments: many(commentsTable), +})); + +export const commentsTable = sqliteTable('comments', { + id: integer('id').primaryKey({ autoIncrement: true }), + content: text('content').notNull(), + creator: integer('creator', { mode: 'number' }).references( + () => usersTable.id, + ), + postId: integer('post_id', { mode: 'number' }).references(() => postsTable.id), + createdAt: integer('created_at', { mode: 'timestamp_ms' }) + .notNull().default(sql`current_timestamp`), +}); +export const commentsConfig = relations(commentsTable, ({ one, many }) => ({ + post: one(postsTable, { + fields: [commentsTable.postId], + references: [postsTable.id], + }), + author: one(usersTable, { + fields: [commentsTable.creator], + references: [usersTable.id], + }), + likes: many(commentLikesTable), +})); + +export const commentLikesTable = sqliteTable('comment_likes', { + id: integer('id').primaryKey({ autoIncrement: true }), + creator: integer('creator', { mode: 'number' }).references( + () => usersTable.id, + ), + commentId: integer('comment_id', { mode: 'number' }).references( + () => commentsTable.id, + ), + createdAt: integer('created_at', { mode: 'timestamp_ms' }) + .notNull().default(sql`current_timestamp`), +}); +export const commentLikesConfig = relations(commentLikesTable, ({ one }) => ({ + comment: one(commentsTable, { + fields: [commentLikesTable.commentId], + references: [commentsTable.id], + }), + author: one(usersTable, { + fields: [commentLikesTable.creator], + references: [usersTable.id], + }), +})); + +const schema = { + usersTable, + postsTable, + commentsTable, + usersToGroupsTable, + groupsTable, + commentLikesConfig, + commentsConfig, + postsConfig, + usersToGroupsConfig, + groupsConfig, + usersConfig, +}; + +let db: LibSQLDatabase; +let client: Client; + +beforeAll(async () => { + const url = process.env['LIBSQL_URL']; + const authToken = process.env['LIBSQL_AUTH_TOKEN']; + if (!url) { + throw new Error('LIBSQL_URL is not set'); + } + const sleep = 250; + let timeLeft = 5000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + client = createClient({ url, authToken }); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to libsql'); + throw lastError; + } + + db = drizzle(client, { schema, logger: ENABLE_LOGGING }); +}); + +beforeEach(async () => { + await db.run(sql`drop table if exists \`groups\``); + await db.run(sql`drop table if exists \`users\``); + await db.run(sql`drop table if exists \`users_to_groups\``); + await db.run(sql`drop table if exists \`posts\``); + await db.run(sql`drop table if exists \`comments\``); + await db.run(sql`drop table if exists \`comment_likes\``); + + await db.run( + sql` + CREATE TABLE \`users\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`verified\` integer DEFAULT 0 NOT NULL, + \`invited_by\` integer + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`groups\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`name\` text NOT NULL, + \`description\` text + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`users_to_groups\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`user_id\` integer NOT NULL, + \`group_id\` integer NOT NULL + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`posts\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`content\` text NOT NULL, + \`owner_id\` integer, + \`created_at\` integer DEFAULT current_timestamp NOT NULL + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`comments\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`content\` text NOT NULL, + \`creator\` integer, + \`post_id\` integer, + \`created_at\` integer DEFAULT current_timestamp NOT NULL + ); + `, + ); + await db.run( + sql` + CREATE TABLE \`comment_likes\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`creator\` integer, + \`comment_id\` integer, + \`created_at\` integer DEFAULT current_timestamp NOT NULL + ); + `, + ); +}); + +afterAll(async () => { + await db.run(sql`drop table if exists \`groups\``); + await db.run(sql`drop table if exists \`users\``); + await db.run(sql`drop table if exists \`users_to_groups\``); + await db.run(sql`drop table if exists \`posts\``); + await db.run(sql`drop table if exists \`comments\``); + await db.run(sql`drop table if exists \`comment_likes\``); + + client.close(); +}); + +test('batch api example', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ + id: usersTable.id, + invitedBy: usersTable.invitedBy, + }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.select().from(usersTable), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + invitedBy: number | null; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(3); + + expect(batchResponse[0]).toEqual([{ + id: 1, + invitedBy: null, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); +}); + +// batch api only relational many +test('insert + findMany', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.query.usersTable.findMany({}), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(3); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); +}); + +// batch api relational many + one +test('insert + findMany + findFirst', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.query.usersTable.findMany({}), + db.query.usersTable.findFirst({}), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + } | undefined, + ]>(); + + expect(batchResponse.length).eq(4); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual( + { id: 1, name: 'John', verified: 0, invitedBy: null }, + ); +}); + +test('insert + db.all + db.get + db.values + db.run', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.run(sql`insert into users (id, name) values (2, 'Dan')`), + db.all(sql`select * from users`), + db.values(sql`select * from users`), + db.get(sql`select * from users`), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + unknown[][], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }, + ]>(); + + expect(batchResponse.length).eq(5); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invited_by: null }, + { id: 2, name: 'Dan', verified: 0, invited_by: null }, + ]); + + expect(batchResponse[3].map((row) => Array.prototype.slice.call(row))).toEqual([ + [1, 'John', 0, null], + [2, 'Dan', 0, null], + ]); + + expect(batchResponse[4]).toEqual( + { id: 1, name: 'John', verified: 0, invited_by: null }, + ); +}); + +// batch api combined rqb + raw call +test('insert + findManyWith + db.all', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.query.usersTable.findMany({}), + db.all(sql`select * from users`), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(4); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'John', verified: 0, invitedBy: null }, + { id: 2, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual([ + { id: 1, name: 'John', verified: 0, invited_by: null }, + { id: 2, name: 'Dan', verified: 0, invited_by: null }, + ]); +}); + +// batch api for insert + update + select +test('insert + update + select + select partial', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.update(usersTable).set({ name: 'Dan' }).where(eq(usersTable.id, 1)), + db.query.usersTable.findMany({}), + db.select().from(usersTable).where(eq(usersTable.id, 1)), + db.select({ id: usersTable.id, invitedBy: usersTable.invitedBy }).from(usersTable), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + ResultSet, + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + name: string; + verified: number; + invitedBy: number | null; + }[], + { + id: number; + invitedBy: number | null; + }[], + ]>(); + + expect(batchResponse.length).eq(5); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 1n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual([ + { id: 1, name: 'Dan', verified: 0, invitedBy: null }, + ]); + + expect(batchResponse[4]).toEqual([ + { id: 1, invitedBy: null }, + ]); +}); + +// batch api for insert + delete + select +test('insert + delete + select + select partial', async () => { + const batchResponse = await db.batch([ + db.insert(usersTable).values({ id: 1, name: 'John' }).returning({ id: usersTable.id }), + db.insert(usersTable).values({ id: 2, name: 'Dan' }), + db.delete(usersTable).where(eq(usersTable.id, 1)).returning({ id: usersTable.id, invitedBy: usersTable.invitedBy }), + db.query.usersTable.findFirst({ + columns: { + id: true, + invitedBy: true, + }, + }), + ]); + + expectTypeOf(batchResponse).toEqualTypeOf<[ + { + id: number; + }[], + ResultSet, + { + id: number; + invitedBy: number | null; + }[], + { + id: number; + invitedBy: number | null; + } | undefined, + ]>(); + + expect(batchResponse.length).eq(4); + + expect(batchResponse[0]).toEqual([{ + id: 1, + }]); + + expect(batchResponse[1]).toEqual({ columns: [], rows: [], rowsAffected: 1, lastInsertRowid: 2n }); + + expect(batchResponse[2]).toEqual([ + { id: 1, invitedBy: null }, + ]); + + expect(batchResponse[3]).toEqual( + { id: 2, invitedBy: null }, + ); +}); + +// * additionally +// batch for all libsql cases, just replace simple calls with batch calls +// batch for all rqb cases, just replace simple calls with batch calls diff --git a/integration-tests/tests/libsql.test.ts b/integration-tests/tests/libsql.test.ts index e53d879f9..b8e224e1b 100644 --- a/integration-tests/tests/libsql.test.ts +++ b/integration-tests/tests/libsql.test.ts @@ -7,6 +7,7 @@ import { asc, eq, gt, + gte, inArray, type InferModel, Name, @@ -20,13 +21,20 @@ import { migrate } from 'drizzle-orm/libsql/migrator'; import { alias, blob, + except, + foreignKey, + getTableConfig, getViewConfig, + int, integer, + intersect, primaryKey, sqliteTable, sqliteTableCreator, sqliteView, text, + union, + unionAll, } from 'drizzle-orm/sqlite-core'; import { type Equal, Expect } from './utils.ts'; @@ -211,6 +219,74 @@ test.beforeEach(async (t) => { `); }); +async function setupSetOperationTest(db: LibSQLDatabase>) { + await db.run(sql`drop table if exists users2`); + await db.run(sql`drop table if exists cities`); + await db.run(sql` + create table \`cities\` ( + id integer primary key, + name text not null + ) + `); + + await db.run(sql` + create table \`users2\` ( + id integer primary key, + name text not null, + city_id integer references ${citiesTable}(${name(citiesTable.id.name)}) + ) + `); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); +} + +test.serial('table config: foreign keys name', async (t) => { + const table = sqliteTable('cities', { + id: int('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: foreignKey({ foreignColumns: [t.id], columns: [t.id], name: 'custom_fk' }), + f1: foreignKey(() => ({ foreignColumns: [t.id], columns: [t.id], name: 'custom_fk_deprecated' })), + })); + + const tableConfig = getTableConfig(table); + + t.is(tableConfig.foreignKeys.length, 2); + t.is(tableConfig.foreignKeys[0]!.getName(), 'custom_fk'); + t.is(tableConfig.foreignKeys[1]!.getName(), 'custom_fk_deprecated'); +}); + +test.serial('table config: primary keys name', async (t) => { + const table = sqliteTable('cities', { + id: int('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: primaryKey({ columns: [t.id, t.name], name: 'custom_pk' }), + })); + + const tableConfig = getTableConfig(table); + + t.is(tableConfig.primaryKeys.length, 1); + t.is(tableConfig.primaryKeys[0]!.getName(), 'custom_pk'); +}); + test.serial('insert bigint values', async (t) => { const { db } = t.context; @@ -598,7 +674,8 @@ test.serial('partial join with alias', async (t) => { const { db } = t.context; const customerAlias = alias(usersTable, 'customer'); - await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]).run(); + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db .select({ user: { @@ -611,8 +688,7 @@ test.serial('partial join with alias', async (t) => { }, }).from(usersTable) .leftJoin(customerAlias, eq(customerAlias.id, 11)) - .where(eq(usersTable.id, 10)) - .all(); + .where(eq(usersTable.id, 10)); t.deepEqual(result, [{ user: { id: 10, name: 'Ivan' }, @@ -1471,7 +1547,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users).all(); @@ -1530,7 +1606,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users).all(); @@ -1756,16 +1832,16 @@ test.serial('insert with onConflict do update where', async (t) => { await db .insert(usersTable) - .values([{ id: 1, name: "John", verified: false }]) + .values([{ id: 1, name: 'John', verified: false }]) .run(); await db .insert(usersTable) - .values({ id: 1, name: "John1", verified: true }) + .values({ id: 1, name: 'John1', verified: true }) .onConflictDoUpdate({ target: usersTable.id, - set: { name: "John1", verified: true }, - where: eq(usersTable.verified, false) + set: { name: 'John1', verified: true }, + where: eq(usersTable.verified, false), }) .run(); @@ -1775,8 +1851,8 @@ test.serial('insert with onConflict do update where', async (t) => { .where(eq(usersTable.id, 1)) .all(); - t.deepEqual(res, [{ id: 1, name: "John1", verified: true }]); -}) + t.deepEqual(res, [{ id: 1, name: 'John1', verified: true }]); +}); test.serial('insert with onConflict do update using composite pk', async (t) => { const { db } = t.context; @@ -1970,3 +2046,380 @@ test.serial('select + .get() for empty result', async (t) => { await db.run(sql`drop table ${users}`); }); + +test.serial('set operations (union) from query builder with subquery', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + ).orderBy(asc(sql`name`)).as('sq'); + + const result = await db.select().from(sq).limit(5).offset(5); + + t.assert(result.length === 5); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 7, name: 'Mary' }, + { id: 1, name: 'New York' }, + { id: 4, name: 'Peter' }, + { id: 8, name: 'Sally' }, + ]); + + t.throws(() => { + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + ).orderBy(asc(sql`name`)); + }); +}); + +test.serial('set operations (union) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + { id: 1, name: 'New York' }, + ]); + + t.throws(() => { + union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)); + }); +}); + +test.serial('set operations (union all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable), + ).orderBy(asc(citiesTable.id)).limit(5).offset(1); + + t.assert(result.length === 5); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + ).orderBy(asc(citiesTable.id)).limit(5).offset(1); + }); +}); + +test.serial('set operations (union all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 3); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + ]); + + t.throws(() => { + unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (intersect) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`name`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`name`)); + }); +}); + +test.serial('set operations (intersect) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 0); + + t.deepEqual(result, []); + + t.throws(() => { + intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (except) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + ]); + + t.throws(() => { + db + .select() + .from(citiesTable).except( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + }); +}); + +test.serial('set operations (except) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await except( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + except( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (mixed) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + t.throws(() => { + db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ); + }); +}); + +test.serial('set operations (mixed all) as function with subquery', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const sq = union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)).as('sq'); + + const result = await db.select().from(sq).limit(4).offset(1); + + t.assert(result.length === 4); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 5, name: 'Ben' }, + { id: 6, name: 'Jill' }, + ]); + + t.throws(() => { + union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); diff --git a/integration-tests/tests/mysql-proxy.test.ts b/integration-tests/tests/mysql-proxy.test.ts new file mode 100644 index 000000000..861d6811e --- /dev/null +++ b/integration-tests/tests/mysql-proxy.test.ts @@ -0,0 +1,2102 @@ +import 'dotenv/config'; + +import type { TestFn } from 'ava'; +import anyTest from 'ava'; +import Docker from 'dockerode'; +import { asc, eq, gt, inArray, Name, placeholder, sql } from 'drizzle-orm'; +import { + alias, + boolean, + date, + datetime, + getTableConfig, + getViewConfig, + int, + json, + mysqlEnum, + mysqlTable, + mysqlTableCreator, + mysqlView, + serial, + text, + time, + timestamp, + unique, + uniqueIndex, + uniqueKeyName, + year, +} from 'drizzle-orm/mysql-core'; +import { drizzle as proxyDrizzle } from 'drizzle-orm/mysql-proxy'; +import type { MySqlRemoteDatabase } from 'drizzle-orm/mysql-proxy'; +import { migrate } from 'drizzle-orm/mysql-proxy/migrator'; +import getPort from 'get-port'; +import * as mysql from 'mysql2/promise'; +import { v4 as uuid } from 'uuid'; +import { type Equal, Expect, toLocalDate } from './utils.ts'; + +const ENABLE_LOGGING = false; + +const usersTable = mysqlTable('userstest', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: json('jsonb').$type(), + createdAt: timestamp('created_at', { fsp: 2 }).notNull().defaultNow(), +}); + +const users2Table = mysqlTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').references(() => citiesTable.id), +}); + +const citiesTable = mysqlTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const datesTable = mysqlTable('datestable', { + date: date('date'), + dateAsString: date('date_as_string', { mode: 'string' }), + time: time('time', { fsp: 1 }), + datetime: datetime('datetime', { fsp: 2 }), + datetimeAsString: datetime('datetime_as_string', { fsp: 2, mode: 'string' }), + timestamp: timestamp('timestamp', { fsp: 3 }), + timestampAsString: timestamp('timestamp_as_string', { fsp: 3, mode: 'string' }), + year: year('year'), +}); + +const coursesTable = mysqlTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: int('category_id').references(() => courseCategoriesTable.id), +}); + +const courseCategoriesTable = mysqlTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const orders = mysqlTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: int('amount').notNull(), + quantity: int('quantity').notNull(), +}); + +const usersMigratorTable = mysqlTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}, (table) => { + return { + name: uniqueIndex('').on(table.name).using('btree'), + }; +}); + +// eslint-disable-next-line drizzle/require-entity-kind +class ServerSimulator { + constructor(private db: mysql.Connection) {} + + async query(sql: string, params: any[], method: 'all' | 'execute') { + if (method === 'all') { + try { + const result = await this.db.query({ + sql, + values: params, + rowsAsArray: true, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result[0] as any }; + } catch (e: any) { + return { error: e }; + } + } else if (method === 'execute') { + try { + const result = await this.db.query({ + sql, + values: params, + typeCast: function(field: any, next: any) { + if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') { + return field.string(); + } + return next(); + }, + }); + + return { data: result as any }; + } catch (e: any) { + return { error: e }; + } + } else { + return { error: 'Unknown method value' }; + } + } + + async migrations(queries: string[]) { + await this.db.query('BEGIN'); + try { + for (const query of queries) { + await this.db.query(query); + } + await this.db.query('COMMIT'); + } catch { + await this.db.query('ROLLBACK'); + } + + return {}; + } +} + +interface Context { + docker: Docker; + mysqlContainer: Docker.Container; + db: MySqlRemoteDatabase; + client: mysql.Connection; + serverSimulator: ServerSimulator; +} + +const test = anyTest as TestFn; + +async function createDockerDB(ctx: Context): Promise { + const docker = (ctx.docker = new Docker()); + const port = await getPort({ port: 3306 }); + const image = 'mysql:8'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + ctx.mysqlContainer = await docker.createContainer({ + Image: image, + Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '3306/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await ctx.mysqlContainer.start(); + + return `mysql://root:mysql@127.0.0.1:${port}/drizzle`; +} + +test.before(async (t) => { + const ctx = t.context; + const connectionString = process.env['MYSQL_CONNECTION_STRING'] ?? await createDockerDB(ctx); + + const sleep = 1000; + let timeLeft = 20000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + ctx.client = await mysql.createConnection(connectionString); + await ctx.client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to MySQL'); + await ctx.client?.end().catch(console.error); + await ctx.mysqlContainer?.stop().catch(console.error); + throw lastError; + } + + ctx.serverSimulator = new ServerSimulator(ctx.client); + + ctx.db = proxyDrizzle(async (sql, params, method) => { + try { + const response = await ctx.serverSimulator.query(sql, params, method); + + if (response.error !== undefined) { + throw response.error; + } + + return { rows: response.data }; + } catch (e: any) { + console.error('Error from mysql proxy server:', e.message); + throw e; + } + }, { logger: ENABLE_LOGGING }); +}); + +test.after.always(async (t) => { + const ctx = t.context; + await ctx.client?.end().catch(console.error); + await ctx.mysqlContainer?.stop().catch(console.error); +}); + +test.beforeEach(async (t) => { + try { + const ctx = t.context; + await ctx.db.execute(sql`drop table if exists \`userstest\``); + await ctx.db.execute(sql`drop table if exists \`users2\``); + await ctx.db.execute(sql`drop table if exists \`cities\``); + + await ctx.db.execute( + sql` + create table \`userstest\` ( + \`id\` serial primary key, + \`name\` text not null, + \`verified\` boolean not null default false, + \`jsonb\` json, + \`created_at\` timestamp not null default now() + ) + `, + ); + + await ctx.db.execute( + sql` + create table \`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int references \`cities\`(\`id\`) + ) + `, + ); + + await ctx.db.execute( + sql` + create table \`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + } catch (error) { + console.log('error', error); + throw error; + } +}); + +test.serial('table configs: unique third param', async (t) => { + const cities1Table = mysqlTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: unique('custom_name').on(t.name, t.state), + f1: unique('custom_name1').on(t.name, t.state), + })); + + const tableConfig = getTableConfig(cities1Table); + + t.assert(tableConfig.uniqueConstraints.length === 2); + + t.assert(tableConfig.uniqueConstraints[0]?.name === 'custom_name'); + t.deepEqual(tableConfig.uniqueConstraints[0]?.columns.map((t) => t.name), ['name', 'state']); + + t.assert(tableConfig.uniqueConstraints[1]?.name, 'custom_name1'); + t.deepEqual(tableConfig.uniqueConstraints[1]?.columns.map((t) => t.name), ['name', 'state']); +}); + +test.serial('table configs: unique in column', async (t) => { + const cities1Table = mysqlTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull().unique(), + state: text('state').unique('custom'), + field: text('field').unique('custom_field'), + }); + + const tableConfig = getTableConfig(cities1Table); + + const columnName = tableConfig.columns.find((it) => it.name === 'name'); + t.assert(columnName?.uniqueName === uniqueKeyName(cities1Table, [columnName!.name])); + t.assert(columnName?.isUnique); + + const columnState = tableConfig.columns.find((it) => it.name === 'state'); + t.assert(columnState?.uniqueName === 'custom'); + t.assert(columnState?.isUnique); + + const columnField = tableConfig.columns.find((it) => it.name === 'field'); + t.assert(columnField?.uniqueName === 'custom_field'); + t.assert(columnField?.isUnique); +}); + +test.serial('select all fields', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select().from(usersTable); + + t.assert(result[0]!.createdAt instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 2000); + t.deepEqual(result, [{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test.serial('select sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('select typed sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('select distinct', async (t) => { + const { db } = t.context; + + const usersDistinctTable = mysqlTable('users_distinct', { + id: int('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id int, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + t.deepEqual(users, [{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); +}); + +test.serial('insert returning sql', async (t) => { + const { db } = t.context; + + const [result, _] = await db.insert(usersTable).values({ name: 'John' }); + + t.deepEqual(result.insertId, 1); +}); + +test.serial('delete returning sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + t.is(users[0].affectedRows, 1); +}); + +test.serial('update returning sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + t.is(users[0].changedRows, 1); +}); + +test.serial('update with returning all fields', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select().from(usersTable).where(eq(usersTable.id, 1)); + + t.is(updatedUsers[0].changedRows, 1); + + t.assert(users[0]!.createdAt instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + // not timezone based timestamp, thats why it should not work here + // t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 2000); + t.deepEqual(users, [{ id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }]); +}); + +test.serial('update with returning partial', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const updatedUsers = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')); + + const users = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(updatedUsers[0].changedRows, 1); + + t.deepEqual(users, [{ id: 1, name: 'Jane' }]); +}); + +test.serial('delete with returning all fields', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + t.is(deletedUser[0].affectedRows, 1); +}); + +test.serial('delete with returning partial', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const deletedUser = await db.delete(usersTable).where(eq(usersTable.name, 'John')); + + t.is(deletedUser[0].affectedRows, 1); +}); + +test.serial('insert + select', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select().from(usersTable); + t.deepEqual(result, [{ id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }]); + + await db.insert(usersTable).values({ name: 'Jane' }); + const result2 = await db.select().from(usersTable); + t.deepEqual(result2, [ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test.serial('json insert', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }).from(usersTable); + + t.deepEqual(result, [{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test.serial('insert with overridden default values', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + t.deepEqual(result, [{ id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }]); +}); + +test.serial('insert many', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }).from(usersTable); + + t.deepEqual(result, [ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test.serial('insert many with returning', async (t) => { + const { db } = t.context; + + const result = await db.insert(usersTable).values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + + t.is(result[0].affectedRows, 4); +}); + +test.serial('select with group by as field', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.name); + + t.deepEqual(result, [{ name: 'John' }, { name: 'Jane' }]); +}); + +test.serial('select with group by as sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`); + + t.deepEqual(result, [{ name: 'John' }, { name: 'Jane' }]); +}); + +test.serial('$default function', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }); + const selectedOrder = await db.select().from(orders); + + t.deepEqual(selectedOrder, [{ + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }]); +}); + +test.serial('$default with empty array', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`s_orders\``); + await db.execute( + sql` + create table \`s_orders\` ( + \`id\` serial primary key, + \`region\` text default ('Ukraine'), + \`product\` text not null + ) + `, + ); + + const users = mysqlTable('s_orders', { + id: serial('id').primaryKey(), + region: text('region').default('Ukraine'), + product: text('product').$defaultFn(() => 'random_string'), + }); + + await db.insert(users).values({}); + const selectedOrder = await db.select().from(users); + + t.deepEqual(selectedOrder, [{ + id: 1, + region: 'Ukraine', + product: 'random_string', + }]); +}); + +test.serial('select with group by as sql + column', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id); + + t.deepEqual(result, [{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test.serial('select with group by as column + sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`); + + t.deepEqual(result, [{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); +}); + +test.serial('select with group by complex query', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db.select({ name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + t.deepEqual(result, [{ name: 'Jane' }]); +}); + +test.serial('build query', async (t) => { + const { db } = t.context; + + const query = db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + t.deepEqual(query, { + sql: `select \`id\`, \`name\` from \`userstest\` group by \`userstest\`.\`id\`, \`userstest\`.\`name\``, + params: [], + }); +}); + +test.serial('Query check: Insert all defaults in 1 row', async (t) => { + const { db } = t.context; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = db + .insert(users) + .values({}) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into `users` (`id`, `name`, `state`) values (default, default, default)', + params: [], + }); +}); + +test.serial('Query check: Insert all defaults in multiple rows', async (t) => { + const { db } = t.context; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state').default('UA'), + }); + + const query = db + .insert(users) + .values([{}, {}]) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into `users` (`id`, `name`, `state`) values (default, default, default), (default, default, default)', + params: [], + }); +}); + +test.serial('Insert all defaults in 1 row', async (t) => { + const { db } = t.context; + + const users = mysqlTable('empty_insert_single', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default ('Dan'), state text)`, + ); + + await db.insert(users).values({}); + + const res = await db.select().from(users); + + t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }]); +}); + +test.serial('Insert all defaults in multiple rows', async (t) => { + const { db } = t.context; + + const users = mysqlTable('empty_insert_multiple', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default ('Dan'), state text)`, + ); + + await db.insert(users).values([{}, {}]); + + const res = await db.select().from(users); + + t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]); +}); + +test.serial('build query insert with onDuplicate', async (t) => { + const { db } = t.context; + + const query = db.insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }) + .toSQL(); + + t.deepEqual(query, { + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test.serial('insert with onDuplicate', async (t) => { + const { db } = t.context; + + await db.insert(usersTable) + .values({ name: 'John' }); + + await db.insert(usersTable) + .values({ id: 1, name: 'John' }) + .onDuplicateKeyUpdate({ set: { name: 'John1' } }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(res, [{ id: 1, name: 'John1' }]); +}); + +test.serial('insert conflict', async (t) => { + const { db } = t.context; + + await db.insert(usersTable) + .values({ name: 'John' }); + + await t.throwsAsync( + () => db.insert(usersTable).values({ id: 1, name: 'John1' }), + { + code: 'ER_DUP_ENTRY', + message: "Duplicate entry '1' for key 'userstest.PRIMARY'", + }, + ); +}); + +test.serial('insert conflict with ignore', async (t) => { + const { db } = t.context; + + await db.insert(usersTable) + .values({ name: 'John' }); + + await db.insert(usersTable) + .ignore() + .values({ id: 1, name: 'John1' }); + + const res = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(res, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('partial join with alias', async (t) => { + const { db } = t.context; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }).from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + t.deepEqual(result, [{ + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }]); +}); + +test.serial('full join with alias', async (t) => { + const { db } = t.context; + + const mysqlTable = mysqlTableCreator((name) => `prefixed_${name}`); + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select().from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)); + + t.deepEqual(result, [{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('select from alias', async (t) => { + const { db } = t.context; + + const mysqlTable = mysqlTableCreator((name) => `prefixed_${name}`); + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)); + + t.deepEqual(result, [{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('insert with spaces', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + t.deepEqual(result, [{ id: 1, name: 'Jo h n' }]); +}); + +test.serial('prepared statement', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const statement = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .prepare(); + const result = await statement.execute(); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('prepared statement reuse', async (t) => { + const { db } = t.context; + + const stmt = db.insert(usersTable).values({ + verified: true, + name: placeholder('name'), + }).prepare(); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ name: `John ${i}` }); + } + + const result = await db.select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }).from(usersTable); + + t.deepEqual(result, [ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test.serial('prepared statement with placeholder in .where', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db.select({ + id: usersTable.id, + name: usersTable.name, + }).from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare(); + const result = await stmt.execute({ id: 1 }); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('migrator', async (t) => { + const { db, serverSimulator } = t.context; + + await db.execute(sql`drop table if exists cities_migration`); + await db.execute(sql`drop table if exists users_migration`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists __drizzle_migrations`); + + await migrate(db, async (queries) => { + try { + await serverSimulator.migrations(queries); + } catch (e) { + console.error(e); + throw new Error('Proxy server cannot run migrations'); + } + }, { migrationsFolder: './drizzle2/mysql' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + t.deepEqual(result, [{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table cities_migration`); + await db.execute(sql`drop table users_migration`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table __drizzle_migrations`); +}); + +test.serial('insert via db.execute + select via db.execute', async (t) => { + const { db } = t.context; + + await db.execute(sql`insert into ${usersTable} (${new Name(usersTable.name.name)}) values (${'John'})`); + + const result = await db.execute<{ id: number; name: string }>(sql`select id, name from ${usersTable}`); + t.deepEqual(result[0], [{ id: 1, name: 'John' }]); +}); + +test.serial('insert via db.execute w/ query builder', async (t) => { + const { db } = t.context; + + const inserted = await db.execute( + db.insert(usersTable).values({ name: 'John' }), + ); + t.is(inserted[0].affectedRows, 1); +}); + +test.serial('insert + select all possible dates', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`date\` date, + \`date_as_string\` date, + \`time\` time, + \`datetime\` datetime, + \`datetime_as_string\` datetime, + \`timestamp\` timestamp(3), + \`timestamp_as_string\` timestamp(3), + \`year\` year + ) + `, + ); + + const date = new Date('2022-11-11'); + const dateWithMilliseconds = new Date('2022-11-11 12:12:12.123'); + + await db.insert(datesTable).values({ + date: date, + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: date, + year: 22, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: dateWithMilliseconds, + timestampAsString: '2022-11-11 12:12:12.123', + }); + + const res = await db.select().from(datesTable); + + t.assert(res[0]?.date instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(res[0]?.datetime instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(typeof res[0]?.dateAsString === 'string'); + t.assert(typeof res[0]?.datetimeAsString === 'string'); + + t.deepEqual(res, [{ + date: toLocalDate(new Date('2022-11-11')), + dateAsString: '2022-11-11', + time: '12:12:12', + datetime: new Date('2022-11-11'), + year: 2022, + datetimeAsString: '2022-11-11 12:12:12', + timestamp: new Date('2022-11-11 12:12:12.123'), + timestampAsString: '2022-11-11 12:12:12.123', + }]); + + await db.execute(sql`drop table if exists \`datestable\``); +}); + +const tableWithEnums = mysqlTable('enums_test_case', { + id: serial('id').primaryKey(), + enum1: mysqlEnum('enum1', ['a', 'b', 'c']).notNull(), + enum2: mysqlEnum('enum2', ['a', 'b', 'c']).default('a'), + enum3: mysqlEnum('enum3', ['a', 'b', 'c']).notNull().default('b'), +}); + +test.serial('Mysql enum test case #1', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`enums_test_case\``); + + await db.execute(sql` + create table \`enums_test_case\` ( + \`id\` serial primary key, + \`enum1\` ENUM('a', 'b', 'c') not null, + \`enum2\` ENUM('a', 'b', 'c') default 'a', + \`enum3\` ENUM('a', 'b', 'c') not null default 'b' + ) + `); + + await db.insert(tableWithEnums).values([ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum3: 'c' }, + { id: 3, enum1: 'a' }, + ]); + + const res = await db.select().from(tableWithEnums); + + await db.execute(sql`drop table \`enums_test_case\``); + + t.deepEqual(res, [ + { id: 1, enum1: 'a', enum2: 'b', enum3: 'c' }, + { id: 2, enum1: 'a', enum2: 'a', enum3: 'c' }, + { id: 3, enum1: 'a', enum2: 'a', enum3: 'b' }, + ]); +}); + +test.serial('left join (flat object fields)', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable) + .values([{ name: 'Paris' }, { name: 'London' }]); + + await db.insert(users2Table).values([{ name: 'John', cityId: 1 }, { name: 'Jane' }]); + + const res = await db.select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)); + + t.deepEqual(res, [ + { userId: 1, userName: 'John', cityId: 1, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); +}); + +test.serial('left join (grouped fields)', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable) + .values([{ name: 'Paris' }, { name: 'London' }]); + + await db.insert(users2Table).values([{ name: 'John', cityId: 1 }, { name: 'Jane' }]); + + const res = await db.select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }).from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)); + + t.deepEqual(res, [ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: 1, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); +}); + +test.serial('left join (all fields)', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable) + .values([{ name: 'Paris' }, { name: 'London' }]); + + await db.insert(users2Table).values([{ name: 'John', cityId: 1 }, { name: 'Jane' }]); + + const res = await db.select().from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)); + + t.deepEqual(res, [ + { + users2: { + id: 1, + name: 'John', + cityId: 1, + }, + cities: { + id: 1, + name: 'Paris', + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); +}); + +test.serial('join subquery', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); + + await db.execute( + sql` + create table \`course_categories\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.execute( + sql` + create table \`courses\` ( + \`id\` serial primary key, + \`name\` text not null, + \`category_id\` int references \`course_categories\`(\`id\`) + ) + `, + ); + + await db.insert(courseCategoriesTable).values([ + { name: 'Category 1' }, + { name: 'Category 2' }, + { name: 'Category 3' }, + { name: 'Category 4' }, + ]); + + await db.insert(coursesTable).values([ + { name: 'Development', categoryId: 2 }, + { name: 'IT & Software', categoryId: 3 }, + { name: 'Marketing', categoryId: 4 }, + { name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + t.deepEqual(res, [ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); + + await db.execute(sql`drop table if exists \`courses\``); + await db.execute(sql`drop table if exists \`course_categories\``); +}); + +test.serial('with ... select', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`orders\``); + await db.execute( + sql` + create table \`orders\` ( + \`id\` serial primary key, + \`region\` text not null, + \`product\` text not null, + \`amount\` int not null, + \`quantity\` int not null + ) + `, + ); + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`cast(sum(${orders.quantity}) as unsigned)`, + productSales: sql`cast(sum(${orders.amount}) as unsigned)`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + t.deepEqual(result, [ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); +}); + +test.serial('select from subquery sql', async (t) => { + const { db } = t.context; + + await db.insert(users2Table).values([{ name: 'John' }, { name: 'Jane' }]); + + const sq = db + .select({ name: sql`concat(${users2Table.name}, " modified")`.as('name') }) + .from(users2Table) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + t.deepEqual(res, [{ name: 'John modified' }, { name: 'Jane modified' }]); +}); + +test.serial('select a field without joining its table', (t) => { + const { db } = t.context; + + t.throws(() => db.select({ name: users2Table.name }).from(usersTable).prepare()); +}); + +test.serial('select all fields from subquery without alias', (t) => { + const { db } = t.context; + + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + t.throws(() => db.select().from(sq).prepare()); +}); + +test.serial('select count()', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + t.deepEqual(res, [{ count: 2 }]); +}); + +test.serial('select for ...', (t) => { + const { db } = t.context; + + { + const query = db.select().from(users2Table).for('update').toSQL(); + t.regex(query.sql, / for update$/); + } + { + const query = db.select().from(users2Table).for('share', { skipLocked: true }).toSQL(); + t.regex(query.sql, / for share skip locked$/); + } + { + const query = db.select().from(users2Table).for('update', { noWait: true }).toSQL(); + t.regex(query.sql, / for update no wait$/); + } +}); + +test.serial('having', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable).values([{ name: 'London' }, { name: 'Paris' }, { name: 'New York' }]); + + await db.insert(users2Table).values([{ name: 'John', cityId: 1 }, { name: 'Jane', cityId: 1 }, { + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + t.deepEqual(result, [ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); +}); + +test.serial('view', async (t) => { + const { db } = t.context; + + const newYorkers1 = mysqlView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = mysqlView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = mysqlView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view new_yorkers as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]); + + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1); + t.deepEqual(result, [ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); +}); + +test.serial('select from raw sql', async (t) => { + const { db } = t.context; + + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + ]); +}); + +test.serial('select from raw sql with joins', async (t) => { + const { db } = t.context; + + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + t.deepEqual(result, [ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); +}); + +test.serial('join on aliased sql from select', async (t) => { + const { db } = t.context; + + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + t.deepEqual(result, [ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test.serial('join on aliased sql from with clause', async (t) => { + const { db } = t.context; + + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + t.deepEqual(result, [ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test.serial('prefixed table', async (t) => { + const { db } = t.context; + + const mysqlTable = mysqlTableCreator((name) => `myprefix_${name}`); + + const users = mysqlTable('test_prefixed_table_with_unique_name', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id int not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('orderBy with aliased column', (t) => { + const { db } = t.context; + + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + t.deepEqual(query.sql, 'select something as `test` from `users2` order by `test`'); +}); + +test.serial('timestamp timezone', async (t) => { + const { db } = t.context; + + const date = new Date(Date.parse('2020-01-01T12:34:56+07:00')); + + await db.insert(usersTable).values({ name: 'With default times' }); + await db.insert(usersTable).values({ + name: 'Without default times', + createdAt: date, + }); + const users = await db.select().from(usersTable); + + // check that the timestamps are set correctly for default times + t.assert(Math.abs(users[0]!.createdAt.getTime() - Date.now()) < 2000); + + // check that the timestamps are set correctly for non default times + t.assert(Math.abs(users[1]!.createdAt.getTime() - date.getTime()) < 2000); +}); + +// TODO: implement transactions +// test.serial('transaction', async (t) => { +// const { db } = t.context; + +// const users = mysqlTable('users_transactions', { +// id: serial('id').primaryKey(), +// balance: int('balance').notNull(), +// }); +// const products = mysqlTable('products_transactions', { +// id: serial('id').primaryKey(), +// price: int('price').notNull(), +// stock: int('stock').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); +// await db.execute(sql`drop table if exists ${products}`); + +// await db.execute(sql`create table users_transactions (id serial not null primary key, balance int not null)`); +// await db.execute( +// sql`create table products_transactions (id serial not null primary key, price int not null, stock int not null)`, +// ); + +// const [{ insertId: userId }] = await db.insert(users).values({ balance: 100 }); +// const user = await db.select().from(users).where(eq(users.id, userId)).then((rows) => rows[0]!); +// const [{ insertId: productId }] = await db.insert(products).values({ price: 10, stock: 10 }); +// const product = await db.select().from(products).where(eq(products.id, productId)).then((rows) => rows[0]!); + +// await db.transaction(async (tx) => { +// await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); +// await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); +// }); + +// const result = await db.select().from(users); + +// t.deepEqual(result, [{ id: 1, balance: 90 }]); + +// await db.execute(sql`drop table ${users}`); +// await db.execute(sql`drop table ${products}`); +// }); + +// TODO: implement transactions +// test.serial('transaction rollback', async (t) => { +// const { db } = t.context; + +// const users = mysqlTable('users_transactions_rollback', { +// id: serial('id').primaryKey(), +// balance: int('balance').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); + +// await db.execute( +// sql`create table users_transactions_rollback (id serial not null primary key, balance int not null)`, +// ); + +// await t.throwsAsync(async () => +// await db.transaction(async (tx) => { +// await tx.insert(users).values({ balance: 100 }); +// tx.rollback(); +// }), new TransactionRollbackError()); + +// const result = await db.select().from(users); + +// t.deepEqual(result, []); + +// await db.execute(sql`drop table ${users}`); +// }); + +// TODO: implement transactions +// test.serial('nested transaction', async (t) => { +// const { db } = t.context; + +// const users = mysqlTable('users_nested_transactions', { +// id: serial('id').primaryKey(), +// balance: int('balance').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); + +// await db.execute( +// sql`create table users_nested_transactions (id serial not null primary key, balance int not null)`, +// ); + +// await db.transaction(async (tx) => { +// await tx.insert(users).values({ balance: 100 }); + +// await tx.transaction(async (tx) => { +// await tx.update(users).set({ balance: 200 }); +// }); +// }); + +// const result = await db.select().from(users); + +// t.deepEqual(result, [{ id: 1, balance: 200 }]); + +// await db.execute(sql`drop table ${users}`); +// }); + +// TODO: implement transactions +// test.serial('nested transaction rollback', async (t) => { +// const { db } = t.context; + +// const users = mysqlTable('users_nested_transactions_rollback', { +// id: serial('id').primaryKey(), +// balance: int('balance').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); + +// await db.execute( +// sql`create table users_nested_transactions_rollback (id serial not null primary key, balance int not null)`, +// ); + +// await db.transaction(async (tx) => { +// await tx.insert(users).values({ balance: 100 }); + +// await t.throwsAsync(async () => +// await tx.transaction(async (tx) => { +// await tx.update(users).set({ balance: 200 }); +// tx.rollback(); +// }), new TransactionRollbackError()); +// }); + +// const result = await db.select().from(users); + +// t.deepEqual(result, [{ id: 1, balance: 100 }]); + +// await db.execute(sql`drop table ${users}`); +// }); + +test.serial('join subquery with join', async (t) => { + const { db } = t.context; + + const internalStaff = mysqlTable('internal_staff', { + userId: int('user_id').notNull(), + }); + + const customUser = mysqlTable('custom_user', { + id: int('id').notNull(), + }); + + const ticket = mysqlTable('ticket', { + staffId: int('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table internal_staff (user_id integer not null)`); + await db.execute(sql`create table custom_user (id integer not null)`); + await db.execute(sql`create table ticket (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + t.deepEqual(mainQuery, [{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); +}); + +test.serial('subquery with view', async (t) => { + const { db } = t.context; + + const users = mysqlTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = mysqlView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 1 }, + { name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq); + + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); + +test.serial('join view as subquery', async (t) => { + const { db } = t.context; + + const users = mysqlTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: int('city_id').notNull(), + }); + + const newYorkers = mysqlView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 1 }, + { name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)); + + t.deepEqual(result, [ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); + +// TODO: implement iterator +// test.serial('select iterator', async (t) => { +// const { db } = t.context; + +// const users = mysqlTable('users_iterator', { +// id: serial('id').primaryKey(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); +// await db.execute(sql`create table ${users} (id serial not null primary key)`); + +// await db.insert(users).values([{}, {}, {}]); + +// const iter = db.select().from(users).iterator(); +// const result: InferModel[] = []; + +// for await (const row of iter) { +// result.push(row); +// } + +// t.deepEqual(result, [{ id: 1 }, { id: 2 }, { id: 3 }]); +// }); + +// TODO: implement iterator +// test.serial('select iterator w/ prepared statement', async (t) => { +// const { db } = t.context; + +// const users = mysqlTable('users_iterator', { +// id: serial('id').primaryKey(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); +// await db.execute(sql`create table ${users} (id serial not null primary key)`); + +// await db.insert(users).values([{}, {}, {}]); + +// const prepared = db.select().from(users).prepare(); +// const iter = prepared.iterator(); +// const result: InferModel[] = []; + +// for await (const row of iter) { +// result.push(row); +// } + +// t.deepEqual(result, [{ id: 1 }, { id: 2 }, { id: 3 }]); +// }); + +test.serial('insert undefined', async (t) => { + const { db } = t.context; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await t.notThrowsAsync(async () => await db.insert(users).values({ name: undefined })); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('update undefined', async (t) => { + const { db } = t.context; + + const users = mysqlTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await t.throwsAsync(async () => await db.update(users).set({ name: undefined })); + await t.notThrowsAsync(async () => await db.update(users).set({ id: 1, name: undefined })); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('utc config for datetime', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`datetime_utc\` datetime(3), + \`datetime\` datetime(3), + \`datetime_as_string\` datetime + ) + `, + ); + const datesTable = mysqlTable('datestable', { + datetimeUTC: datetime('datetime_utc', { fsp: 3, mode: 'date' }), + datetime: datetime('datetime', { fsp: 3 }), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), + }); + + const dateObj = new Date('2022-11-11'); + const dateUtc = new Date('2022-11-11T12:12:12.122Z'); + + await db.insert(datesTable).values({ + datetimeUTC: dateUtc, + datetime: dateObj, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + const [rawSelect] = await db.execute(sql`select \`datetime_utc\` from \`datestable\``); + const selectedRow = (rawSelect as unknown as [{ datetime_utc: string }])[0]; + + t.is(selectedRow.datetime_utc, '2022-11-11 12:12:12.122'); + t.deepEqual(new Date(selectedRow.datetime_utc.replace(' ', 'T') + 'Z'), dateUtc); + + t.assert(res[0]?.datetime instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(res[0]?.datetimeUTC instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(typeof res[0]?.datetimeAsString === 'string'); + + t.deepEqual(res, [{ + datetimeUTC: dateUtc, + datetime: new Date('2022-11-11'), + datetimeAsString: '2022-11-11 12:12:12', + }]); + + await db.execute(sql`drop table if exists \`datestable\``); +}); diff --git a/integration-tests/tests/mysql-schema.test.ts b/integration-tests/tests/mysql-schema.test.ts index 08a62bd16..f82d47533 100644 --- a/integration-tests/tests/mysql-schema.test.ts +++ b/integration-tests/tests/mysql-schema.test.ts @@ -27,6 +27,7 @@ import { drizzle } from 'drizzle-orm/mysql2'; import getPort from 'get-port'; import * as mysql from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; +import { toLocalDate } from './utils'; const mySchema = mysqlSchema('mySchema'); @@ -471,7 +472,8 @@ test.serial('build query insert with onDuplicate', async (t) => { .toSQL(); t.deepEqual(query, { - sql: 'insert into `mySchema`.`userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', + sql: + 'insert into `mySchema`.`userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', params: ['John', '["foo","bar"]', 'John1'], }); }); @@ -740,7 +742,7 @@ test.serial('insert + select all possible dates', async (t) => { t.assert(typeof res[0]?.datetimeAsString === 'string'); t.deepEqual(res, [{ - date: new Date('2022-11-11'), + date: toLocalDate(new Date('2022-11-11')), dateAsString: '2022-11-11', time: '12:12:12', datetime: new Date('2022-11-11'), diff --git a/integration-tests/tests/mysql.custom.test.ts b/integration-tests/tests/mysql.custom.test.ts index e0ad8df25..c60b88e47 100644 --- a/integration-tests/tests/mysql.custom.test.ts +++ b/integration-tests/tests/mysql.custom.test.ts @@ -25,6 +25,7 @@ import { migrate } from 'drizzle-orm/mysql2/migrator'; import getPort from 'get-port'; import * as mysql from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; +import { toLocalDate } from './utils'; const customSerial = customType<{ data: number; notNull: true; default: true }>({ dataType() { @@ -486,7 +487,8 @@ test.serial('build query insert with onDuplicate', async (t) => { .toSQL(); t.deepEqual(query, { - sql: 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', + sql: + 'insert into `userstest` (`id`, `name`, `verified`, `jsonb`, `created_at`) values (default, ?, default, ?, default) on duplicate key update `name` = ?', params: ['John', '["foo","bar"]', 'John1'], }); }); @@ -777,7 +779,7 @@ test.serial('insert + select all possible dates', async (t) => { t.assert(typeof res[0]?.datetimeAsString === 'string'); t.deepEqual(res, [{ - date: new Date('2022-11-11'), + date: toLocalDate(new Date('2022-11-11')), dateAsString: '2022-11-11', time: '12:12:12', datetime: new Date('2022-11-11'), diff --git a/integration-tests/tests/mysql.prefixed.test.ts b/integration-tests/tests/mysql.prefixed.test.ts index e042dd73b..324dced00 100644 --- a/integration-tests/tests/mysql.prefixed.test.ts +++ b/integration-tests/tests/mysql.prefixed.test.ts @@ -41,7 +41,7 @@ import { migrate } from 'drizzle-orm/mysql2/migrator'; import getPort from 'get-port'; import * as mysql from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; -import { type Equal, Expect } from './utils.ts'; +import { type Equal, Expect, toLocalDate } from './utils.ts'; const ENABLE_LOGGING = false; @@ -793,7 +793,7 @@ test.serial('insert + select all possible dates', async (t) => { t.assert(typeof res[0]?.datetimeAsString === 'string'); t.deepEqual(res, [{ - date: new Date('2022-11-11'), + date: toLocalDate(new Date('2022-11-11')), dateAsString: '2022-11-11', time: '12:12:12', datetime: new Date('2022-11-11'), @@ -1484,7 +1484,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -1543,7 +1543,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); diff --git a/integration-tests/tests/mysql.test.ts b/integration-tests/tests/mysql.test.ts index 6a747e708..3b545fcd8 100644 --- a/integration-tests/tests/mysql.test.ts +++ b/integration-tests/tests/mysql.test.ts @@ -8,6 +8,7 @@ import { DefaultLogger, eq, gt, + gte, inArray, type InferModel, Name, @@ -17,21 +18,33 @@ import { } from 'drizzle-orm'; import { alias, + bigint, boolean, date, datetime, + except, + exceptAll, + foreignKey, getTableConfig, getViewConfig, int, + intersect, + intersectAll, json, + mediumint, mysqlEnum, mysqlTable, mysqlTableCreator, mysqlView, + primaryKey, serial, + smallint, text, time, timestamp, + tinyint, + union, + unionAll, unique, uniqueIndex, uniqueKeyName, @@ -43,7 +56,7 @@ import { migrate } from 'drizzle-orm/mysql2/migrator'; import getPort from 'get-port'; import * as mysql from 'mysql2/promise'; import { v4 as uuid } from 'uuid'; -import { type Equal, Expect } from './utils.ts'; +import { type Equal, Expect, toLocalDate } from './utils.ts'; const ENABLE_LOGGING = false; @@ -215,6 +228,124 @@ test.beforeEach(async (t) => { ); }); +async function setupSetOperationTest(db: MySql2Database) { + await db.execute(sql`drop table if exists \`users2\``); + await db.execute(sql`drop table if exists \`cities\``); + await db.execute( + sql` + create table \`users2\` ( + \`id\` serial primary key, + \`name\` text not null, + \`city_id\` int references \`cities\`(\`id\`) + ) + `, + ); + + await db.execute( + sql` + create table \`cities\` ( + \`id\` serial primary key, + \`name\` text not null + ) + `, + ); + + await db.insert(citiesTable).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); +} + +test.serial('table config: unsigned ints', async (t) => { + const unsignedInts = mysqlTable('cities1', { + bigint: bigint('bigint', { mode: 'number', unsigned: true }), + int: int('int', { unsigned: true }), + smallint: smallint('smallint', { unsigned: true }), + mediumint: mediumint('mediumint', { unsigned: true }), + tinyint: tinyint('tinyint', { unsigned: true }), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + t.is(bigintColumn.getSQLType(), 'bigint unsigned'); + t.is(intColumn.getSQLType(), 'int unsigned'); + t.is(smallintColumn.getSQLType(), 'smallint unsigned'); + t.is(mediumintColumn.getSQLType(), 'mediumint unsigned'); + t.is(tinyintColumn.getSQLType(), 'tinyint unsigned'); +}); + +test.serial('table config: signed ints', async (t) => { + const unsignedInts = mysqlTable('cities1', { + bigint: bigint('bigint', { mode: 'number' }), + int: int('int'), + smallint: smallint('smallint'), + mediumint: mediumint('mediumint'), + tinyint: tinyint('tinyint'), + }); + + const tableConfig = getTableConfig(unsignedInts); + + const bigintColumn = tableConfig.columns.find((c) => c.name === 'bigint')!; + const intColumn = tableConfig.columns.find((c) => c.name === 'int')!; + const smallintColumn = tableConfig.columns.find((c) => c.name === 'smallint')!; + const mediumintColumn = tableConfig.columns.find((c) => c.name === 'mediumint')!; + const tinyintColumn = tableConfig.columns.find((c) => c.name === 'tinyint')!; + + t.is(bigintColumn.getSQLType(), 'bigint'); + t.is(intColumn.getSQLType(), 'int'); + t.is(smallintColumn.getSQLType(), 'smallint'); + t.is(mediumintColumn.getSQLType(), 'mediumint'); + t.is(tinyintColumn.getSQLType(), 'tinyint'); +}); + +test.serial('table config: foreign keys name', async (t) => { + const table = mysqlTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: foreignKey({ foreignColumns: [t.id], columns: [t.id], name: 'custom_fk' }), + })); + + const tableConfig = getTableConfig(table); + + t.is(tableConfig.foreignKeys.length, 1); + t.is(tableConfig.foreignKeys[0]!.getName(), 'custom_fk'); +}); + +test.serial('table config: primary keys name', async (t) => { + const table = mysqlTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: primaryKey({ columns: [t.id, t.name], name: 'custom_pk' }), + })); + + const tableConfig = getTableConfig(table); + + t.is(tableConfig.primaryKeys.length, 1); + t.is(tableConfig.primaryKeys[0]!.getName(), 'custom_pk'); +}); + test.serial('table configs: unique third param', async (t) => { const cities1Table = mysqlTable('cities1', { id: serial('id').primaryKey(), @@ -1001,7 +1132,7 @@ test.serial('insert + select all possible dates', async (t) => { t.assert(typeof res[0]?.datetimeAsString === 'string'); t.deepEqual(res, [{ - date: new Date('2022-11-11'), + date: toLocalDate(new Date('2022-11-11')), dateAsString: '2022-11-11', time: '12:12:12', datetime: new Date('2022-11-11'), @@ -1673,7 +1804,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -1732,7 +1863,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); @@ -1967,3 +2098,559 @@ test.serial('update undefined', async (t) => { await db.execute(sql`drop table ${users}`); }); + +test.serial('utc config for datetime', async (t) => { + const { db } = t.context; + + await db.execute(sql`drop table if exists \`datestable\``); + await db.execute( + sql` + create table \`datestable\` ( + \`datetime_utc\` datetime(3), + \`datetime\` datetime(3), + \`datetime_as_string\` datetime + ) + `, + ); + const datesTable = mysqlTable('datestable', { + datetimeUTC: datetime('datetime_utc', { fsp: 3, mode: 'date' }), + datetime: datetime('datetime', { fsp: 3 }), + datetimeAsString: datetime('datetime_as_string', { mode: 'string' }), + }); + + const dateObj = new Date('2022-11-11'); + const dateUtc = new Date('2022-11-11T12:12:12.122Z'); + + await db.insert(datesTable).values({ + datetimeUTC: dateUtc, + datetime: dateObj, + datetimeAsString: '2022-11-11 12:12:12', + }); + + const res = await db.select().from(datesTable); + + const [rawSelect] = await db.execute(sql`select \`datetime_utc\` from \`datestable\``); + const selectedRow = (rawSelect as unknown as [{ datetime_utc: string }])[0]; + + t.is(selectedRow.datetime_utc, '2022-11-11 12:12:12.122'); + t.deepEqual(new Date(selectedRow.datetime_utc.replace(' ', 'T') + 'Z'), dateUtc); + + t.assert(res[0]?.datetime instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(res[0]?.datetimeUTC instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(typeof res[0]?.datetimeAsString === 'string'); + + t.deepEqual(res, [{ + datetimeUTC: dateUtc, + datetime: new Date('2022-11-11'), + datetimeAsString: '2022-11-11 12:12:12', + }]); + + await db.execute(sql`drop table if exists \`datestable\``); +}); + +test.serial('set operations (union) from query builder with subquery', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + const sq = db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).as('sq'); + + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).union( + db.select().from(sq), + ).limit(8); + + t.assert(result.length === 8); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Peter' }, + { id: 5, name: 'Ben' }, + ]); + + // union should throw if selected fields are not in the same order + t.throws(() => + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).union( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table), + ) + ); +}); + +test.serial('set operations (union) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + ]); + + t.throws(() => { + union( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (union all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)).limit(3); + + t.assert(result.length === 3); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + t.throws(() => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (union all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + ]); + + t.throws(() => { + unionAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + }); +}); + +test.serial('set operations (intersect) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + }); +}); + +test.serial('set operations (intersect) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + + t.assert(result.length === 0); + + t.deepEqual(result, []); + + t.throws(() => { + intersect( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(1); + }); +}); + +test.serial('set operations (intersect all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).intersectAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + t.throws(() => { + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).limit(2).intersectAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).limit(2), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (intersect all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await intersectAll( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + ]); + + t.throws(() => { + intersectAll( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (except) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + ]); +}); + +test.serial('set operations (except) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await except( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(3); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + except( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable), + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(3); + }); +}); + +test.serial('set operations (except all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).exceptAll( + db + .select({ id: citiesTable.id, name: citiesTable.name }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select() + .from(citiesTable).exceptAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(eq(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (except all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await exceptAll( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gt(users2Table.id, 7)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(6).orderBy(asc(sql.identifier('id'))); + + t.assert(result.length === 6); + + t.deepEqual(result, [ + { id: 2, name: 'Jane' }, + { id: 3, name: 'Jack' }, + { id: 4, name: 'Peter' }, + { id: 5, name: 'Ben' }, + { id: 6, name: 'Jill' }, + { id: 7, name: 'Mary' }, + ]); + + t.throws(() => { + exceptAll( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gt(users2Table.id, 7)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).limit(6); + }); +}); + +test.serial('set operations (mixed) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select() + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ).orderBy(asc(citiesTable.id)).limit(1).offset(1), + ); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select() + .from(citiesTable).except( + ({ unionAll }) => + unionAll( + db + .select({ name: citiesTable.name, id: citiesTable.id }) + .from(citiesTable).where(gt(citiesTable.id, 1)), + db.select().from(citiesTable).where(eq(citiesTable.id, 2)), + ), + ); + }); +}); + +test.serial('set operations (mixed all) as function with subquery', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const sq = except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).orderBy(asc(sql.identifier('id'))).as('sq'); + + const result = await union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db.select().from(sq).limit(1), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + + t.assert(result.length === 4); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + { id: 5, name: 'Ben' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 7)), + ).limit(1), + db + .select().from(citiesTable).where(gt(citiesTable.id, 1)), + ); + }); +}); diff --git a/integration-tests/tests/neon-http.test.ts b/integration-tests/tests/neon-http.test.ts index c5a7eb70e..5112fd3b1 100644 --- a/integration-tests/tests/neon-http.test.ts +++ b/integration-tests/tests/neon-http.test.ts @@ -6,6 +6,9 @@ import anyTest from 'ava'; import Docker from 'dockerode'; import { and, + arrayContained, + arrayContains, + arrayOverlaps, asc, eq, gt, @@ -1423,20 +1426,71 @@ test.serial('array types', async (t) => { test.serial('select for ...', (t) => { const { db } = t.context; - const query = db - .select() - .from(users2Table) - .for('update') - .for('no key update', { of: users2Table }) - .for('no key update', { of: users2Table, skipLocked: true }) - .for('share', { of: users2Table, noWait: true }) - .toSQL(); + { + const query = db + .select() + .from(users2Table) + .for('update') + .toSQL(); + + t.regex( + query.sql, + / for update$/, + ); + } - t.regex( - query.sql, - // eslint-disable-next-line unicorn/better-regex - / for update for no key update of "users2" for no key update of "users2" skip locked for share of "users2" no wait$/, - ); + { + const query = db + .select() + .from(users2Table) + .for('update', { of: [users2Table, coursesTable] }) + .toSQL(); + + t.regex( + query.sql, + / for update of "users2", "courses"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table }) + .toSQL(); + + t.regex( + query.sql, + /for no key update of "users2"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table, skipLocked: true }) + .toSQL(); + + t.regex( + query.sql, + / for no key update of "users2" skip locked$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('share', { of: users2Table, noWait: true }) + .toSQL(); + + t.regex( + query.sql, + // eslint-disable-next-line unicorn/better-regex + /for share of "users2" no wait$/, + ); + } }); test.serial('having', async (t) => { @@ -2016,7 +2070,7 @@ test.serial.skip('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -2079,7 +2133,7 @@ test.serial.skip('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); @@ -2314,3 +2368,49 @@ test.serial('update undefined', async (t) => { await db.execute(sql`drop table ${users}`); }); + +test.serial('array operators', async (t) => { + const { db } = t.context; + + const posts = pgTable('posts', { + id: serial('id').primaryKey(), + tags: text('tags').array(), + }); + + await db.execute(sql`drop table if exists ${posts}`); + + await db.execute( + sql`create table ${posts} (id serial primary key, tags text[])`, + ); + + await db.insert(posts).values([{ + tags: ['ORM'], + }, { + tags: ['Typescript'], + }, { + tags: ['Typescript', 'ORM'], + }, { + tags: ['Typescript', 'Frontend', 'React'], + }, { + tags: ['Typescript', 'ORM', 'Database', 'Postgres'], + }, { + tags: ['Java', 'Spring', 'OOP'], + }]); + + const contains = await db.select({ id: posts.id }).from(posts) + .where(arrayContains(posts.tags, ['Typescript', 'ORM'])); + const contained = await db.select({ id: posts.id }).from(posts) + .where(arrayContained(posts.tags, ['Typescript', 'ORM'])); + const overlaps = await db.select({ id: posts.id }).from(posts) + .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])); + const withSubQuery = await db.select({ id: posts.id }).from(posts) + .where(arrayContains( + posts.tags, + db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)), + )); + + t.deepEqual(contains, [{ id: 3 }, { id: 5 }]); + t.deepEqual(contained, [{ id: 1 }, { id: 2 }, { id: 3 }]); + t.deepEqual(overlaps, [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]); + t.deepEqual(withSubQuery, [{ id: 1 }, { id: 3 }, { id: 5 }]); +}); diff --git a/integration-tests/tests/pg-proxy.test.ts b/integration-tests/tests/pg-proxy.test.ts new file mode 100644 index 000000000..02c48cffc --- /dev/null +++ b/integration-tests/tests/pg-proxy.test.ts @@ -0,0 +1,2635 @@ +import 'dotenv/config'; + +import type { TestFn } from 'ava'; +import anyTest from 'ava'; +import Docker from 'dockerode'; +import { + and, + arrayContained, + arrayContains, + arrayOverlaps, + asc, + eq, + gt, + gte, + inArray, + lt, + name, + placeholder, + type SQL, + sql, + type SQLWrapper, +} from 'drizzle-orm'; +import { + alias, + boolean, + char, + cidr, + getMaterializedViewConfig, + getTableConfig, + getViewConfig, + inet, + integer, + jsonb, + macaddr, + macaddr8, + type PgColumn, + pgEnum, + pgMaterializedView, + pgTable, + pgTableCreator, + pgView, + serial, + text, + timestamp, + unique, + uniqueKeyName, + uuid as pgUuid, + varchar, +} from 'drizzle-orm/pg-core'; +import { drizzle as proxyDrizzle } from 'drizzle-orm/pg-proxy'; +import type { PgRemoteDatabase } from 'drizzle-orm/pg-proxy'; +import { migrate } from 'drizzle-orm/pg-proxy/migrator'; +import getPort from 'get-port'; +import pg from 'pg'; +import { v4 as uuid } from 'uuid'; +import type { Equal } from './utils.ts'; +import { Expect } from './utils.ts'; + +// eslint-disable-next-line drizzle/require-entity-kind +class ServerSimulator { + constructor(private db: pg.Client) {} + + async query(sql: string, params: any[], method: 'all' | 'execute') { + if (method === 'all') { + try { + const result = await this.db.query({ + text: sql, + values: params, + rowMode: 'array', + }); + + return { data: result.rows as any }; + } catch (e: any) { + return { error: e }; + } + } else if (method === 'execute') { + try { + const result = await this.db.query({ + text: sql, + values: params, + }); + + return { data: result.rows as any }; + } catch (e: any) { + return { error: e }; + } + } else { + return { error: 'Unknown method value' }; + } + } + + async migrations(queries: string[]) { + await this.db.query('BEGIN'); + try { + for (const query of queries) { + await this.db.query(query); + } + await this.db.query('COMMIT'); + } catch { + await this.db.query('ROLLBACK'); + } + + return {}; + } +} + +const { Client } = pg; + +const ENABLE_LOGGING = false; + +const usersTable = pgTable('users', { + id: serial('id' as string).primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: jsonb('jsonb').$type(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + +const citiesTable = pgTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: char('state', { length: 2 }), +}); + +const users2Table = pgTable('users2', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').references(() => citiesTable.id), +}); + +const coursesTable = pgTable('courses', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + categoryId: integer('category_id').references(() => courseCategoriesTable.id), +}); + +const courseCategoriesTable = pgTable('course_categories', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + +const orders = pgTable('orders', { + id: serial('id').primaryKey(), + region: text('region').notNull(), + product: text('product').notNull().$default(() => 'random_string'), + amount: integer('amount').notNull(), + quantity: integer('quantity').notNull(), +}); + +const network = pgTable('network_table', { + inet: inet('inet').notNull(), + cidr: cidr('cidr').notNull(), + macaddr: macaddr('macaddr').notNull(), + macaddr8: macaddr8('macaddr8').notNull(), +}); + +const salEmp = pgTable('sal_emp', { + name: text('name'), + payByQuarter: integer('pay_by_quarter').array(), + schedule: text('schedule').array().array(), +}); + +const usersMigratorTable = pgTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +interface Context { + docker: Docker; + pgContainer: Docker.Container; + db: PgRemoteDatabase; + client: pg.Client; + serverSimulator: ServerSimulator; +} + +const test = anyTest as TestFn; + +async function createDockerDB(ctx: Context): Promise { + const docker = (ctx.docker = new Docker()); + const port = await getPort({ port: 5432 }); + const image = 'postgres:14'; + + const pullStream = await docker.pull(image); + await new Promise((resolve, reject) => + docker.modem.followProgress(pullStream, (err) => (err ? reject(err) : resolve(err))) + ); + + ctx.pgContainer = await docker.createContainer({ + Image: image, + Env: ['POSTGRES_PASSWORD=postgres', 'POSTGRES_USER=postgres', 'POSTGRES_DB=postgres'], + name: `drizzle-integration-tests-${uuid()}`, + HostConfig: { + AutoRemove: true, + PortBindings: { + '5432/tcp': [{ HostPort: `${port}` }], + }, + }, + }); + + await ctx.pgContainer.start(); + + return `postgres://postgres:postgres@localhost:${port}/postgres`; +} + +test.before(async (t) => { + const ctx = t.context; + const connectionString = process.env['PG_CONNECTION_STRING'] ?? (await createDockerDB(ctx)); + + const sleep = 250; + let timeLeft = 5000; + let connected = false; + let lastError: unknown | undefined; + do { + try { + ctx.client = new Client(connectionString); + await ctx.client.connect(); + connected = true; + break; + } catch (e) { + lastError = e; + await new Promise((resolve) => setTimeout(resolve, sleep)); + timeLeft -= sleep; + } + } while (timeLeft > 0); + if (!connected) { + console.error('Cannot connect to Postgres'); + await ctx.client?.end().catch(console.error); + await ctx.pgContainer?.stop().catch(console.error); + throw lastError; + } + + ctx.serverSimulator = new ServerSimulator(ctx.client); + + ctx.db = proxyDrizzle(async (sql, params, method) => { + try { + const response = await ctx.serverSimulator.query(sql, params, method); + + if (response.error !== undefined) { + throw response.error; + } + + return { rows: response.data }; + } catch (e: any) { + console.error('Error from pg proxy server:', e.message); + throw e; + } + }, { + logger: ENABLE_LOGGING, + }); +}); + +test.after.always(async (t) => { + const ctx = t.context; + await ctx.client?.end().catch(console.error); + await ctx.pgContainer?.stop().catch(console.error); +}); + +test.beforeEach(async (t) => { + const ctx = t.context; + await ctx.db.execute(sql`drop schema public cascade`); + await ctx.db.execute(sql`create schema public`); + await ctx.db.execute( + sql` + create table users ( + id serial primary key, + name text not null, + verified boolean not null default false, + jsonb jsonb, + created_at timestamptz not null default now() + ) + `, + ); + await ctx.db.execute( + sql` + create table cities ( + id serial primary key, + name text not null, + state char(2) + ) + `, + ); + await ctx.db.execute( + sql` + create table users2 ( + id serial primary key, + name text not null, + city_id integer references cities(id) + ) + `, + ); + await ctx.db.execute( + sql` + create table course_categories ( + id serial primary key, + name text not null + ) + `, + ); + await ctx.db.execute( + sql` + create table courses ( + id serial primary key, + name text not null, + category_id integer references course_categories(id) + ) + `, + ); + await ctx.db.execute( + sql` + create table orders ( + id serial primary key, + region text not null, + product text not null, + amount integer not null, + quantity integer not null + ) + `, + ); + await ctx.db.execute( + sql` + create table network_table ( + inet inet not null, + cidr cidr not null, + macaddr macaddr not null, + macaddr8 macaddr8 not null + ) + `, + ); + await ctx.db.execute( + sql` + create table sal_emp ( + name text not null, + pay_by_quarter integer[] not null, + schedule text[][] not null + ) + `, + ); + await ctx.db.execute( + sql` + create table tictactoe ( + squares integer[3][3] not null + ) + `, + ); +}); + +test.serial('table configs: unique third param', async (t) => { + const cities1Table = pgTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: char('state', { length: 2 }), + }, (t) => ({ + f: unique('custom_name').on(t.name, t.state).nullsNotDistinct(), + f1: unique('custom_name1').on(t.name, t.state), + })); + + const tableConfig = getTableConfig(cities1Table); + + t.assert(tableConfig.uniqueConstraints.length === 2); + + t.assert(tableConfig.uniqueConstraints[0]?.name === 'custom_name'); + t.assert(tableConfig.uniqueConstraints[0]?.nullsNotDistinct); + t.deepEqual(tableConfig.uniqueConstraints[0]?.columns.map((t) => t.name), ['name', 'state']); + + t.assert(tableConfig.uniqueConstraints[1]?.name, 'custom_name1'); + t.assert(!tableConfig.uniqueConstraints[1]?.nullsNotDistinct); + t.deepEqual(tableConfig.uniqueConstraints[0]?.columns.map((t) => t.name), ['name', 'state']); +}); + +test.serial('table configs: unique in column', async (t) => { + const cities1Table = pgTable('cities1', { + id: serial('id').primaryKey(), + name: text('name').notNull().unique(), + state: char('state', { length: 2 }).unique('custom'), + field: char('field', { length: 2 }).unique('custom_field', { nulls: 'not distinct' }), + }); + + const tableConfig = getTableConfig(cities1Table); + + const columnName = tableConfig.columns.find((it) => it.name === 'name'); + t.assert(columnName?.uniqueName === uniqueKeyName(cities1Table, [columnName!.name])); + t.assert(columnName?.isUnique); + + const columnState = tableConfig.columns.find((it) => it.name === 'state'); + t.assert(columnState?.uniqueName === 'custom'); + t.assert(columnState?.isUnique); + + const columnField = tableConfig.columns.find((it) => it.name === 'field'); + t.assert(columnField?.uniqueName === 'custom_field'); + t.assert(columnField?.isUnique); + t.assert(columnField?.uniqueType === 'not distinct'); +}); + +test.serial('select all fields', async (t) => { + const { db } = t.context; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select().from(usersTable); + + t.assert(result[0]!.createdAt instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 100); + t.deepEqual(result, [ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }, + ]); +}); + +test.serial('select sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .select({ + name: sql`upper(${usersTable.name})`, + }) + .from(usersTable); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('select typed sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + + const users = await db.select({ + name: sql`upper(${usersTable.name})`, + }).from(usersTable); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('$default function', async (t) => { + const { db } = t.context; + + const insertedOrder = await db.insert(orders).values({ id: 1, region: 'Ukraine', amount: 1, quantity: 1 }) + .returning(); + const selectedOrder = await db.select().from(orders); + + t.deepEqual(insertedOrder, [{ + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }]); + + t.deepEqual(selectedOrder, [{ + id: 1, + amount: 1, + quantity: 1, + region: 'Ukraine', + product: 'random_string', + }]); +}); + +test.serial('select distinct', async (t) => { + const { db } = t.context; + + const usersDistinctTable = pgTable('users_distinct', { + id: integer('id').notNull(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${usersDistinctTable}`); + await db.execute(sql`create table ${usersDistinctTable} (id integer, name text)`); + + await db.insert(usersDistinctTable).values([ + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + { id: 2, name: 'John' }, + { id: 1, name: 'Jane' }, + ]); + const users1 = await db.selectDistinct().from(usersDistinctTable).orderBy( + usersDistinctTable.id, + usersDistinctTable.name, + ); + const users2 = await db.selectDistinctOn([usersDistinctTable.id]).from(usersDistinctTable).orderBy( + usersDistinctTable.id, + ); + const users3 = await db.selectDistinctOn([usersDistinctTable.name], { name: usersDistinctTable.name }).from( + usersDistinctTable, + ).orderBy(usersDistinctTable.name); + + await db.execute(sql`drop table ${usersDistinctTable}`); + + t.deepEqual(users1, [{ id: 1, name: 'Jane' }, { id: 1, name: 'John' }, { id: 2, name: 'John' }]); + + t.deepEqual(users2.length, 2); + t.deepEqual(users2[0]?.id, 1); + t.deepEqual(users2[1]?.id, 2); + + t.deepEqual(users3.length, 2); + t.deepEqual(users3[0]?.name, 'Jane'); + t.deepEqual(users3[1]?.name, 'John'); +}); + +test.serial('insert returning sql', async (t) => { + const { db } = t.context; + + const users = await db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('delete returning sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .delete(usersTable) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JOHN' }]); +}); + +test.serial('update returning sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + name: sql`upper(${usersTable.name})`, + }); + + t.deepEqual(users, [{ name: 'JANE' }]); +}); + +test.serial('update with returning all fields', async (t) => { + const { db } = t.context; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning(); + + t.assert(users[0]!.createdAt instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); + t.deepEqual(users, [ + { id: 1, name: 'Jane', verified: false, jsonb: null, createdAt: users[0]!.createdAt }, + ]); +}); + +test.serial('update with returning partial', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db + .update(usersTable) + .set({ name: 'Jane' }) + .where(eq(usersTable.name, 'John')) + .returning({ + id: usersTable.id, + name: usersTable.name, + }); + + t.deepEqual(users, [{ id: 1, name: 'Jane' }]); +}); + +test.serial('delete with returning all fields', async (t) => { + const { db } = t.context; + + const now = Date.now(); + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning(); + + t.assert(users[0]!.createdAt instanceof Date); // eslint-disable-line no-instanceof/no-instanceof + t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); + t.deepEqual(users, [ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: users[0]!.createdAt }, + ]); +}); + +test.serial('delete with returning partial', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning({ + id: usersTable.id, + name: usersTable.name, + }); + + t.deepEqual(users, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert + select', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const result = await db.select().from(usersTable); + t.deepEqual(result, [ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result[0]!.createdAt }, + ]); + + await db.insert(usersTable).values({ name: 'Jane' }); + const result2 = await db.select().from(usersTable); + t.deepEqual(result2, [ + { id: 1, name: 'John', verified: false, jsonb: null, createdAt: result2[0]!.createdAt }, + { id: 2, name: 'Jane', verified: false, jsonb: null, createdAt: result2[1]!.createdAt }, + ]); +}); + +test.serial('json insert', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John', jsonb: ['foo', 'bar'] }); + const result = await db + .select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }) + .from(usersTable); + + t.deepEqual(result, [{ id: 1, name: 'John', jsonb: ['foo', 'bar'] }]); +}); + +test.serial('char insert', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable).values({ name: 'Austin', state: 'TX' }); + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name, state: citiesTable.state }) + .from(citiesTable); + + t.deepEqual(result, [{ id: 1, name: 'Austin', state: 'TX' }]); +}); + +test.serial('char update', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable).values({ name: 'Austin', state: 'TX' }); + await db.update(citiesTable).set({ name: 'Atlanta', state: 'GA' }).where(eq(citiesTable.id, 1)); + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name, state: citiesTable.state }) + .from(citiesTable); + + t.deepEqual(result, [{ id: 1, name: 'Atlanta', state: 'GA' }]); +}); + +test.serial('char delete', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable).values({ name: 'Austin', state: 'TX' }); + await db.delete(citiesTable).where(eq(citiesTable.state, 'TX')); + const result = await db + .select({ id: citiesTable.id, name: citiesTable.name, state: citiesTable.state }) + .from(citiesTable); + + t.deepEqual(result, []); +}); + +test.serial('insert with overridden default values', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John', verified: true }); + const result = await db.select().from(usersTable); + + t.deepEqual(result, [ + { id: 1, name: 'John', verified: true, jsonb: null, createdAt: result[0]!.createdAt }, + ]); +}); + +test.serial('insert many', async (t) => { + const { db } = t.context; + + await db + .insert(usersTable) + .values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]); + const result = await db + .select({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }) + .from(usersTable); + + t.deepEqual(result, [ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test.serial('insert many with returning', async (t) => { + const { db } = t.context; + + const result = await db + .insert(usersTable) + .values([ + { name: 'John' }, + { name: 'Bruce', jsonb: ['foo', 'bar'] }, + { name: 'Jane' }, + { name: 'Austin', verified: true }, + ]) + .returning({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + verified: usersTable.verified, + }); + + t.deepEqual(result, [ + { id: 1, name: 'John', jsonb: null, verified: false }, + { id: 2, name: 'Bruce', jsonb: ['foo', 'bar'], verified: false }, + { id: 3, name: 'Jane', jsonb: null, verified: false }, + { id: 4, name: 'Austin', jsonb: null, verified: true }, + ]); +}); + +test.serial('select with group by as field', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.name); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by as sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(sql`${usersTable.name}`); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by as sql + column', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(sql`${usersTable.name}`, usersTable.id); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by as column + sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`); + + t.deepEqual(result, [{ name: 'Jane' }, { name: 'Jane' }, { name: 'John' }]); +}); + +test.serial('select with group by complex query', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }, { name: 'Jane' }]); + + const result = await db + .select({ name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, sql`${usersTable.name}`) + .orderBy(asc(usersTable.name)) + .limit(1); + + t.deepEqual(result, [{ name: 'Jane' }]); +}); + +test.serial('build query', async (t) => { + const { db } = t.context; + + const query = db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .groupBy(usersTable.id, usersTable.name) + .toSQL(); + + t.deepEqual(query, { + sql: 'select "id", "name" from "users" group by "users"."id", "users"."name"', + params: [], + }); +}); + +test.serial('insert sql', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: sql`${'John'}` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('partial join with alias', async (t) => { + const { db } = t.context; + const customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }) + .from(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + t.deepEqual(result, [ + { + user: { id: 10, name: 'Ivan' }, + customer: { id: 11, name: 'Hans' }, + }, + ]); +}); + +test.serial('full join with alias', async (t) => { + const { db } = t.context; + + const pgTable = pgTableCreator((name) => `prefixed_${name}`); + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(users) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(users.id, 10)); + + t.deepEqual(result, [{ + users: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('select from alias', async (t) => { + const { db } = t.context; + + const pgTable = pgTableCreator((name) => `prefixed_${name}`); + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} (id serial primary key, name text not null)`); + + const user = alias(users, 'user'); + const customers = alias(users, 'customer'); + + await db.insert(users).values([{ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }]); + const result = await db + .select() + .from(user) + .leftJoin(customers, eq(customers.id, 11)) + .where(eq(user.id, 10)); + + t.deepEqual(result, [{ + user: { + id: 10, + name: 'Ivan', + }, + customer: { + id: 11, + name: 'Hans', + }, + }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('insert with spaces', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: sql`'Jo h n'` }); + const result = await db.select({ id: usersTable.id, name: usersTable.name }).from(usersTable); + + t.deepEqual(result, [{ id: 1, name: 'Jo h n' }]); +}); + +test.serial('prepared statement', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const statement = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .prepare('statement1'); + const result = await statement.execute(); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('prepared statement reuse', async (t) => { + const { db } = t.context; + + const stmt = db + .insert(usersTable) + .values({ + verified: true, + name: placeholder('name'), + }) + .prepare('stmt2'); + + for (let i = 0; i < 10; i++) { + await stmt.execute({ name: `John ${i}` }); + } + + const result = await db + .select({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }) + .from(usersTable); + + t.deepEqual(result, [ + { id: 1, name: 'John 0', verified: true }, + { id: 2, name: 'John 1', verified: true }, + { id: 3, name: 'John 2', verified: true }, + { id: 4, name: 'John 3', verified: true }, + { id: 5, name: 'John 4', verified: true }, + { id: 6, name: 'John 5', verified: true }, + { id: 7, name: 'John 6', verified: true }, + { id: 8, name: 'John 7', verified: true }, + { id: 9, name: 'John 8', verified: true }, + { id: 10, name: 'John 9', verified: true }, + ]); +}); + +test.serial('prepared statement with placeholder in .where', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .prepare('stmt3'); + const result = await stmt.execute({ id: 1 }); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('prepared statement with placeholder in .limit', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, placeholder('id'))) + .limit(placeholder('limit')) + .prepare('stmt_limit'); + + const result = await stmt.execute({ id: 1, limit: 1 }); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); + t.is(result.length, 1); +}); + +test.serial('prepared statement with placeholder in .offset', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .offset(placeholder('offset')) + .prepare('stmt_offset'); + + const result = await stmt.execute({ offset: 1 }); + + t.deepEqual(result, [{ id: 2, name: 'John1' }]); +}); + +// TODO change tests to new structure +test.serial('migrator', async (t) => { + const { db, serverSimulator } = t.context; + + await db.execute(sql`drop table if exists all_columns`); + await db.execute(sql`drop table if exists users12`); + await db.execute(sql`drop table if exists "drizzle"."__drizzle_migrations"`); + + await migrate(db, async (queries) => { + try { + await serverSimulator.migrations(queries); + } catch (e) { + console.error(e); + throw new Error('Proxy server cannot run migrations'); + } + }, { migrationsFolder: './drizzle2/pg' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select().from(usersMigratorTable); + + t.deepEqual(result, [{ id: 1, name: 'John', email: 'email' }]); + + await db.execute(sql`drop table all_columns`); + await db.execute(sql`drop table users12`); + await db.execute(sql`drop table "drizzle"."__drizzle_migrations"`); +}); + +test.serial('insert via db.execute + select via db.execute', async (t) => { + const { db } = t.context; + + await db.execute( + sql`insert into ${usersTable} (${name(usersTable.name.name)}) values (${'John'})`, + ); + + const result = await db.execute<{ id: number; name: string }>( + sql`select id, name from "users"`, + ); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert via db.execute + returning', async (t) => { + const { db } = t.context; + + const inserted = await db.execute<{ id: number; name: string }>( + sql`insert into ${usersTable} (${ + name( + usersTable.name.name, + ) + }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, + ); + t.deepEqual(inserted, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert via db.execute w/ query builder', async (t) => { + const { db } = t.context; + + const inserted = await db.execute>( + db + .insert(usersTable) + .values({ name: 'John' }) + .returning({ id: usersTable.id, name: usersTable.name }), + ); + t.deepEqual(inserted, [{ id: 1, name: 'John' }]); +}); + +test.serial('Query check: Insert all defaults in 1 row', async (t) => { + const { db } = t.context; + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + const query = db + .insert(users) + .values({}) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into "users" ("id", "name", "state") values (default, default, default)', + params: [], + }); +}); + +test.serial('Query check: Insert all defaults in multiple rows', async (t) => { + const { db } = t.context; + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state').default('UA'), + }); + + const query = db + .insert(users) + .values([{}, {}]) + .toSQL(); + + t.deepEqual(query, { + sql: 'insert into "users" ("id", "name", "state") values (default, default, default), (default, default, default)', + params: [], + }); +}); + +test.serial('Insert all defaults in 1 row', async (t) => { + const { db } = t.context; + + const users = pgTable('empty_insert_single', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values({}); + + const res = await db.select().from(users); + + t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }]); +}); + +test.serial('Insert all defaults in multiple rows', async (t) => { + const { db } = t.context; + + const users = pgTable('empty_insert_multiple', { + id: serial('id').primaryKey(), + name: text('name').default('Dan'), + state: text('state'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial primary key, name text default 'Dan', state text)`, + ); + + await db.insert(users).values([{}, {}]); + + const res = await db.select().from(users); + + t.deepEqual(res, [{ id: 1, name: 'Dan', state: null }, { id: 2, name: 'Dan', state: null }]); +}); + +test.serial('build query insert with onConflict do update', async (t) => { + const { db } = t.context; + + const query = db + .insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }) + .toSQL(); + + t.deepEqual(query, { + sql: + 'insert into "users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict ("id") do update set "name" = $3', + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test.serial('build query insert with onConflict do update / multiple columns', async (t) => { + const { db } = t.context; + + const query = db + .insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoUpdate({ target: [usersTable.id, usersTable.name], set: { name: 'John1' } }) + .toSQL(); + + t.deepEqual(query, { + sql: + 'insert into "users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict ("id","name") do update set "name" = $3', + params: ['John', '["foo","bar"]', 'John1'], + }); +}); + +test.serial('build query insert with onConflict do nothing', async (t) => { + const { db } = t.context; + + const query = db + .insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoNothing() + .toSQL(); + + t.deepEqual(query, { + sql: + 'insert into "users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict do nothing', + params: ['John', '["foo","bar"]'], + }); +}); + +test.serial('build query insert with onConflict do nothing + target', async (t) => { + const { db } = t.context; + + const query = db + .insert(usersTable) + .values({ name: 'John', jsonb: ['foo', 'bar'] }) + .onConflictDoNothing({ target: usersTable.id }) + .toSQL(); + + t.deepEqual(query, { + sql: + 'insert into "users" ("id", "name", "verified", "jsonb", "created_at") values (default, $1, default, $2, default) on conflict ("id") do nothing', + params: ['John', '["foo","bar"]'], + }); +}); + +test.serial('insert with onConflict do update', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + + await db + .insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoUpdate({ target: usersTable.id, set: { name: 'John1' } }); + + const res = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .where(eq(usersTable.id, 1)); + + t.deepEqual(res, [{ id: 1, name: 'John1' }]); +}); + +test.serial('insert with onConflict do nothing', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + + await db.insert(usersTable).values({ id: 1, name: 'John' }).onConflictDoNothing(); + + const res = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .where(eq(usersTable.id, 1)); + + t.deepEqual(res, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert with onConflict do nothing + target', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values({ name: 'John' }); + + await db + .insert(usersTable) + .values({ id: 1, name: 'John' }) + .onConflictDoNothing({ target: usersTable.id }); + + const res = await db + .select({ id: usersTable.id, name: usersTable.name }) + .from(usersTable) + .where(eq(usersTable.id, 1)); + + t.deepEqual(res, [{ id: 1, name: 'John' }]); +}); + +test.serial('left join (flat object fields)', async (t) => { + const { db } = t.context; + + const { id: cityId } = await db + .insert(citiesTable) + .values([{ name: 'Paris' }, { name: 'London' }]) + .returning({ id: citiesTable.id }) + .then((rows) => rows[0]!); + + await db.insert(users2Table).values([{ name: 'John', cityId }, { name: 'Jane' }]); + + const res = await db + .select({ + userId: users2Table.id, + userName: users2Table.name, + cityId: citiesTable.id, + cityName: citiesTable.name, + }) + .from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)); + + t.deepEqual(res, [ + { userId: 1, userName: 'John', cityId, cityName: 'Paris' }, + { userId: 2, userName: 'Jane', cityId: null, cityName: null }, + ]); +}); + +test.serial('left join (grouped fields)', async (t) => { + const { db } = t.context; + + const { id: cityId } = await db + .insert(citiesTable) + .values([{ name: 'Paris' }, { name: 'London' }]) + .returning({ id: citiesTable.id }) + .then((rows) => rows[0]!); + + await db.insert(users2Table).values([{ name: 'John', cityId }, { name: 'Jane' }]); + + const res = await db + .select({ + id: users2Table.id, + user: { + name: users2Table.name, + nameUpper: sql`upper(${users2Table.name})`, + }, + city: { + id: citiesTable.id, + name: citiesTable.name, + nameUpper: sql`upper(${citiesTable.name})`, + }, + }) + .from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)); + + t.deepEqual(res, [ + { + id: 1, + user: { name: 'John', nameUpper: 'JOHN' }, + city: { id: cityId, name: 'Paris', nameUpper: 'PARIS' }, + }, + { + id: 2, + user: { name: 'Jane', nameUpper: 'JANE' }, + city: null, + }, + ]); +}); + +test.serial('left join (all fields)', async (t) => { + const { db } = t.context; + + const { id: cityId } = await db + .insert(citiesTable) + .values([{ name: 'Paris' }, { name: 'London' }]) + .returning({ id: citiesTable.id }) + .then((rows) => rows[0]!); + + await db.insert(users2Table).values([{ name: 'John', cityId }, { name: 'Jane' }]); + + const res = await db + .select() + .from(users2Table) + .leftJoin(citiesTable, eq(users2Table.cityId, citiesTable.id)); + + t.deepEqual(res, [ + { + users2: { + id: 1, + name: 'John', + cityId, + }, + cities: { + id: cityId, + name: 'Paris', + state: null, + }, + }, + { + users2: { + id: 2, + name: 'Jane', + cityId: null, + }, + cities: null, + }, + ]); +}); + +test.serial('join subquery', async (t) => { + const { db } = t.context; + + await db + .insert(courseCategoriesTable) + .values([ + { name: 'Category 1' }, + { name: 'Category 2' }, + { name: 'Category 3' }, + { name: 'Category 4' }, + ]); + + await db + .insert(coursesTable) + .values([ + { name: 'Development', categoryId: 2 }, + { name: 'IT & Software', categoryId: 3 }, + { name: 'Marketing', categoryId: 4 }, + { name: 'Design', categoryId: 1 }, + ]); + + const sq2 = db + .select({ + categoryId: courseCategoriesTable.id, + category: courseCategoriesTable.name, + total: sql`count(${courseCategoriesTable.id})`, + }) + .from(courseCategoriesTable) + .groupBy(courseCategoriesTable.id, courseCategoriesTable.name) + .as('sq2'); + + const res = await db + .select({ + courseName: coursesTable.name, + categoryId: sq2.categoryId, + }) + .from(coursesTable) + .leftJoin(sq2, eq(coursesTable.categoryId, sq2.categoryId)) + .orderBy(coursesTable.name); + + t.deepEqual(res, [ + { courseName: 'Design', categoryId: 1 }, + { courseName: 'Development', categoryId: 2 }, + { courseName: 'IT & Software', categoryId: 3 }, + { courseName: 'Marketing', categoryId: 4 }, + ]); +}); + +test.serial('with ... select', async (t) => { + const { db } = t.context; + + await db.insert(orders).values([ + { region: 'Europe', product: 'A', amount: 10, quantity: 1 }, + { region: 'Europe', product: 'A', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 20, quantity: 2 }, + { region: 'Europe', product: 'B', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 30, quantity: 3 }, + { region: 'US', product: 'A', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 40, quantity: 4 }, + { region: 'US', product: 'B', amount: 50, quantity: 5 }, + ]); + + const regionalSales = db + .$with('regional_sales') + .as( + db + .select({ + region: orders.region, + totalSales: sql`sum(${orders.amount})`.as('total_sales'), + }) + .from(orders) + .groupBy(orders.region), + ); + + const topRegions = db + .$with('top_regions') + .as( + db + .select({ + region: regionalSales.region, + }) + .from(regionalSales) + .where( + gt( + regionalSales.totalSales, + db.select({ sales: sql`sum(${regionalSales.totalSales})/10` }).from(regionalSales), + ), + ), + ); + + const result = await db + .with(regionalSales, topRegions) + .select({ + region: orders.region, + product: orders.product, + productUnits: sql`sum(${orders.quantity})::int`, + productSales: sql`sum(${orders.amount})::int`, + }) + .from(orders) + .where(inArray(orders.region, db.select({ region: topRegions.region }).from(topRegions))) + .groupBy(orders.region, orders.product) + .orderBy(orders.region, orders.product); + + t.deepEqual(result, [ + { + region: 'Europe', + product: 'A', + productUnits: 3, + productSales: 30, + }, + { + region: 'Europe', + product: 'B', + productUnits: 5, + productSales: 50, + }, + { + region: 'US', + product: 'A', + productUnits: 7, + productSales: 70, + }, + { + region: 'US', + product: 'B', + productUnits: 9, + productSales: 90, + }, + ]); +}); + +test.serial('select from subquery sql', async (t) => { + const { db } = t.context; + + await db.insert(users2Table).values([{ name: 'John' }, { name: 'Jane' }]); + + const sq = db + .select({ name: sql`${users2Table.name} || ' modified'`.as('name') }) + .from(users2Table) + .as('sq'); + + const res = await db.select({ name: sq.name }).from(sq); + + t.deepEqual(res, [{ name: 'John modified' }, { name: 'Jane modified' }]); +}); + +test.serial('select a field without joining its table', (t) => { + const { db } = t.context; + + t.throws(() => db.select({ name: users2Table.name }).from(usersTable).prepare('query')); +}); + +test.serial('select all fields from subquery without alias', (t) => { + const { db } = t.context; + + const sq = db.$with('sq').as(db.select({ name: sql`upper(${users2Table.name})` }).from(users2Table)); + + t.throws(() => db.select().from(sq).prepare('query')); +}); + +test.serial('select count()', async (t) => { + const { db } = t.context; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: sql`count(*)` }).from(usersTable); + + t.deepEqual(res, [{ count: '2' }]); +}); + +test.serial('select count w/ custom mapper', async (t) => { + const { db } = t.context; + + function count(value: PgColumn | SQLWrapper): SQL; + function count(value: PgColumn | SQLWrapper, alias: string): SQL.Aliased; + function count(value: PgColumn | SQLWrapper, alias?: string): SQL | SQL.Aliased { + const result = sql`count(${value})`.mapWith(Number); + if (!alias) { + return result; + } + return result.as(alias); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'Jane' }]); + + const res = await db.select({ count: count(sql`*`) }).from(usersTable); + + t.deepEqual(res, [{ count: 2 }]); +}); + +test.serial('network types', async (t) => { + const { db } = t.context; + + const value: typeof network.$inferSelect = { + inet: '127.0.0.1', + cidr: '192.168.100.128/25', + macaddr: '08:00:2b:01:02:03', + macaddr8: '08:00:2b:01:02:03:04:05', + }; + + await db.insert(network).values(value); + + const res = await db.select().from(network); + + t.deepEqual(res, [value]); +}); + +test.serial('array types', async (t) => { + const { db } = t.context; + + const values: typeof salEmp.$inferSelect[] = [ + { + name: 'John', + payByQuarter: [10000, 10000, 10000, 10000], + schedule: [['meeting', 'lunch'], ['training', 'presentation']], + }, + { + name: 'Carol', + payByQuarter: [20000, 25000, 25000, 25000], + schedule: [['breakfast', 'consulting'], ['meeting', 'lunch']], + }, + ]; + + await db.insert(salEmp).values(values); + + const res = await db.select().from(salEmp); + + t.deepEqual(res, values); +}); + +test.serial('select for ...', (t) => { + const { db } = t.context; + + { + const query = db + .select() + .from(users2Table) + .for('update') + .toSQL(); + + t.regex( + query.sql, + / for update$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('update', { of: [users2Table, coursesTable] }) + .toSQL(); + + t.regex( + query.sql, + / for update of "users2", "courses"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table }) + .toSQL(); + + t.regex( + query.sql, + /for no key update of "users2"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table, skipLocked: true }) + .toSQL(); + + t.regex( + query.sql, + / for no key update of "users2" skip locked$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('share', { of: users2Table, noWait: true }) + .toSQL(); + + t.regex( + query.sql, + // eslint-disable-next-line unicorn/better-regex + /for share of "users2" no wait$/, + ); + } +}); + +test.serial('having', async (t) => { + const { db } = t.context; + + await db.insert(citiesTable).values([{ name: 'London' }, { name: 'Paris' }, { name: 'New York' }]); + + await db.insert(users2Table).values([{ name: 'John', cityId: 1 }, { name: 'Jane', cityId: 1 }, { + name: 'Jack', + cityId: 2, + }]); + + const result = await db + .select({ + id: citiesTable.id, + name: sql`upper(${citiesTable.name})`.as('upper_name'), + usersCount: sql`count(${users2Table.id})::int`.as('users_count'), + }) + .from(citiesTable) + .leftJoin(users2Table, eq(users2Table.cityId, citiesTable.id)) + .where(({ name }) => sql`length(${name}) >= 3`) + .groupBy(citiesTable.id) + .having(({ usersCount }) => sql`${usersCount} > 0`) + .orderBy(({ name }) => name); + + t.deepEqual(result, [ + { + id: 1, + name: 'LONDON', + usersCount: 2, + }, + { + id: 2, + name: 'PARIS', + usersCount: 1, + }, + ]); +}); + +test.serial('view', async (t) => { + const { db } = t.context; + + const newYorkers1 = pgView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = pgView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = pgView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).existing(); + + await db.execute(sql`create view ${newYorkers1} as ${getViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]); + + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1); + t.deepEqual(result, [ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop view ${newYorkers1}`); +}); + +test.serial('materialized view', async (t) => { + const { db } = t.context; + + const newYorkers1 = pgMaterializedView('new_yorkers') + .as((qb) => qb.select().from(users2Table).where(eq(users2Table.cityId, 1))); + + const newYorkers2 = pgMaterializedView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).as(sql`select * from ${users2Table} where ${eq(users2Table.cityId, 1)}`); + + const newYorkers3 = pgMaterializedView('new_yorkers', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }).existing(); + + await db.execute(sql`create materialized view ${newYorkers1} as ${getMaterializedViewConfig(newYorkers1).query}`); + + await db.insert(citiesTable).values([{ name: 'New York' }, { name: 'Paris' }]); + + await db.insert(users2Table).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 1 }, + { name: 'Jack', cityId: 2 }, + ]); + + { + const result = await db.select().from(newYorkers1); + t.deepEqual(result, []); + } + + await db.refreshMaterializedView(newYorkers1); + + { + const result = await db.select().from(newYorkers1); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers2); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select().from(newYorkers3); + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 1 }, + ]); + } + + { + const result = await db.select({ name: newYorkers1.name }).from(newYorkers1); + t.deepEqual(result, [ + { name: 'John' }, + { name: 'Jane' }, + ]); + } + + await db.execute(sql`drop materialized view ${newYorkers1}`); +}); + +// TODO: copy to SQLite and MySQL, add to docs +test.serial('select from raw sql', async (t) => { + const { db } = t.context; + + const result = await db.select({ + id: sql`id`, + name: sql`name`, + }).from(sql`(select 1 as id, 'John' as name) as users`); + + Expect>; + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + ]); +}); + +test.serial('select from raw sql with joins', async (t) => { + const { db } = t.context; + + const result = await db + .select({ + id: sql`users.id`, + name: sql`users.name`, + userCity: sql`users.city`, + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, sql`cities.id = users.id`); + + Expect>; + + t.deepEqual(result, [ + { id: 1, name: 'John', userCity: 'New York', cityName: 'Paris' }, + ]); +}); + +test.serial('join on aliased sql from select', async (t) => { + const { db } = t.context; + + const result = await db + .select({ + userId: sql`users.id`.as('userId'), + name: sql`users.name`, + userCity: sql`users.city`, + cityId: sql`cities.id`.as('cityId'), + cityName: sql`cities.name`, + }) + .from(sql`(select 1 as id, 'John' as name, 'New York' as city) as users`) + .leftJoin(sql`(select 1 as id, 'Paris' as name) as cities`, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + t.deepEqual(result, [ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test.serial('join on aliased sql from with clause', async (t) => { + const { db } = t.context; + + const users = db.$with('users').as( + db.select({ + id: sql`id`.as('userId'), + name: sql`name`.as('userName'), + city: sql`city`.as('city'), + }).from( + sql`(select 1 as id, 'John' as name, 'New York' as city) as users`, + ), + ); + + const cities = db.$with('cities').as( + db.select({ + id: sql`id`.as('cityId'), + name: sql`name`.as('cityName'), + }).from( + sql`(select 1 as id, 'Paris' as name) as cities`, + ), + ); + + const result = await db + .with(users, cities) + .select({ + userId: users.id, + name: users.name, + userCity: users.city, + cityId: cities.id, + cityName: cities.name, + }) + .from(users) + .leftJoin(cities, (cols) => eq(cols.cityId, cols.userId)); + + Expect>; + + t.deepEqual(result, [ + { userId: 1, name: 'John', userCity: 'New York', cityId: 1, cityName: 'Paris' }, + ]); +}); + +test.serial('prefixed table', async (t) => { + const { db } = t.context; + + const pgTable = pgTableCreator((name) => `myprefix_${name}`); + + const users = pgTable('test_prefixed_table_with_unique_name', { + id: integer('id').primaryKey(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table myprefix_test_prefixed_table_with_unique_name (id integer not null primary key, name text not null)`, + ); + + await db.insert(users).values({ id: 1, name: 'John' }); + + const result = await db.select().from(users); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('select from enum', async (t) => { + const { db } = t.context; + + const muscleEnum = pgEnum('muscle', [ + 'abdominals', + 'hamstrings', + 'adductors', + 'quadriceps', + 'biceps', + 'shoulders', + 'chest', + 'middle_back', + 'calves', + 'glutes', + 'lower_back', + 'lats', + 'triceps', + 'traps', + 'forearms', + 'neck', + 'abductors', + ]); + + const forceEnum = pgEnum('force', ['isometric', 'isotonic', 'isokinetic']); + + const levelEnum = pgEnum('level', ['beginner', 'intermediate', 'advanced']); + + const mechanicEnum = pgEnum('mechanic', ['compound', 'isolation']); + + const equipmentEnum = pgEnum('equipment', ['barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'kettlebell']); + + const categoryEnum = pgEnum('category', ['upper_body', 'lower_body', 'full_body']); + + const exercises = pgTable('exercises', { + id: serial('id').primaryKey(), + name: varchar('name').notNull(), + force: forceEnum('force'), + level: levelEnum('level'), + mechanic: mechanicEnum('mechanic'), + equipment: equipmentEnum('equipment'), + instructions: text('instructions'), + category: categoryEnum('category'), + primaryMuscles: muscleEnum('primary_muscles').array(), + secondaryMuscles: muscleEnum('secondary_muscles').array(), + createdAt: timestamp('created_at').notNull().default(sql`now()`), + updatedAt: timestamp('updated_at').notNull().default(sql`now()`), + }); + + await db.execute(sql`drop table if exists ${exercises}`); + await db.execute(sql`drop type if exists ${name(muscleEnum.enumName)}`); + await db.execute(sql`drop type if exists ${name(forceEnum.enumName)}`); + await db.execute(sql`drop type if exists ${name(levelEnum.enumName)}`); + await db.execute(sql`drop type if exists ${name(mechanicEnum.enumName)}`); + await db.execute(sql`drop type if exists ${name(equipmentEnum.enumName)}`); + await db.execute(sql`drop type if exists ${name(categoryEnum.enumName)}`); + + await db.execute( + sql`create type ${ + name(muscleEnum.enumName) + } as enum ('abdominals', 'hamstrings', 'adductors', 'quadriceps', 'biceps', 'shoulders', 'chest', 'middle_back', 'calves', 'glutes', 'lower_back', 'lats', 'triceps', 'traps', 'forearms', 'neck', 'abductors')`, + ); + await db.execute(sql`create type ${name(forceEnum.enumName)} as enum ('isometric', 'isotonic', 'isokinetic')`); + await db.execute(sql`create type ${name(levelEnum.enumName)} as enum ('beginner', 'intermediate', 'advanced')`); + await db.execute(sql`create type ${name(mechanicEnum.enumName)} as enum ('compound', 'isolation')`); + await db.execute( + sql`create type ${ + name(equipmentEnum.enumName) + } as enum ('barbell', 'dumbbell', 'bodyweight', 'machine', 'cable', 'kettlebell')`, + ); + await db.execute(sql`create type ${name(categoryEnum.enumName)} as enum ('upper_body', 'lower_body', 'full_body')`); + await db.execute(sql` + create table ${exercises} ( + id serial primary key, + name varchar not null, + force force, + level level, + mechanic mechanic, + equipment equipment, + instructions text, + category category, + primary_muscles muscle[], + secondary_muscles muscle[], + created_at timestamp not null default now(), + updated_at timestamp not null default now() + ) + `); + + await db.insert(exercises).values({ + name: 'Bench Press', + force: 'isotonic', + level: 'beginner', + mechanic: 'compound', + equipment: 'barbell', + instructions: + 'Lie on your back on a flat bench. Grasp the barbell with an overhand grip, slightly wider than shoulder width. Unrack the barbell and hold it over you with your arms locked. Lower the barbell to your chest. Press the barbell back to the starting position.', + category: 'upper_body', + primaryMuscles: ['chest', 'triceps'], + secondaryMuscles: ['shoulders', 'traps'], + }); + + const result = await db.select().from(exercises); + + t.deepEqual(result, [ + { + id: 1, + name: 'Bench Press', + force: 'isotonic', + level: 'beginner', + mechanic: 'compound', + equipment: 'barbell', + instructions: + 'Lie on your back on a flat bench. Grasp the barbell with an overhand grip, slightly wider than shoulder width. Unrack the barbell and hold it over you with your arms locked. Lower the barbell to your chest. Press the barbell back to the starting position.', + category: 'upper_body', + primaryMuscles: ['chest', 'triceps'], + secondaryMuscles: ['shoulders', 'traps'], + createdAt: result[0]!.createdAt, + updatedAt: result[0]!.updatedAt, + }, + ]); + + await db.execute(sql`drop table ${exercises}`); + await db.execute(sql`drop type ${name(muscleEnum.enumName)}`); + await db.execute(sql`drop type ${name(forceEnum.enumName)}`); + await db.execute(sql`drop type ${name(levelEnum.enumName)}`); + await db.execute(sql`drop type ${name(mechanicEnum.enumName)}`); + await db.execute(sql`drop type ${name(equipmentEnum.enumName)}`); + await db.execute(sql`drop type ${name(categoryEnum.enumName)}`); +}); + +test.serial('orderBy with aliased column', (t) => { + const { db } = t.context; + + const query = db.select({ + test: sql`something`.as('test'), + }).from(users2Table).orderBy((fields) => fields.test).toSQL(); + + t.deepEqual(query.sql, 'select something as "test" from "users2" order by "test"'); +}); + +test.serial('select from sql', async (t) => { + const { db } = t.context; + + const metricEntry = pgTable('metric_entry', { + id: pgUuid('id').notNull(), + createdAt: timestamp('created_at').notNull(), + }); + + await db.execute(sql`drop table if exists ${metricEntry}`); + await db.execute(sql`create table ${metricEntry} (id uuid not null, created_at timestamp not null)`); + + const metricId = uuid(); + + const intervals = db.$with('intervals').as( + db + .select({ + startTime: sql`(date'2023-03-01'+ x * '1 day'::interval)`.as('start_time'), + endTime: sql`(date'2023-03-01'+ (x+1) *'1 day'::interval)`.as('end_time'), + }) + .from(sql`generate_series(0, 29, 1) as t(x)`), + ); + + await t.notThrowsAsync(() => + db + .with(intervals) + .select({ + startTime: intervals.startTime, + endTime: intervals.endTime, + count: sql`count(${metricEntry})`, + }) + .from(metricEntry) + .rightJoin( + intervals, + and( + eq(metricEntry.id, metricId), + gte(metricEntry.createdAt, intervals.startTime), + lt(metricEntry.createdAt, intervals.endTime), + ), + ) + .groupBy(intervals.startTime, intervals.endTime) + .orderBy(asc(intervals.startTime)) + ); +}); + +test.serial('timestamp timezone', async (t) => { + const { db } = t.context; + + const usersTableWithAndWithoutTimezone = pgTable('users_test_with_and_without_timezone', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp('updated_at', { withTimezone: false }).notNull().defaultNow(), + }); + + await db.execute(sql`drop table if exists ${usersTableWithAndWithoutTimezone}`); + + await db.execute( + sql` + create table users_test_with_and_without_timezone ( + id serial not null primary key, + name text not null, + created_at timestamptz not null default now(), + updated_at timestamp not null default now() + ) + `, + ); + + const date = new Date(Date.parse('2020-01-01T00:00:00+04:00')); + + await db.insert(usersTableWithAndWithoutTimezone).values({ name: 'With default times' }); + await db.insert(usersTableWithAndWithoutTimezone).values({ + name: 'Without default times', + createdAt: date, + updatedAt: date, + }); + const users = await db.select().from(usersTableWithAndWithoutTimezone); + + // check that the timestamps are set correctly for default times + t.assert(Math.abs(users[0]!.updatedAt.getTime() - Date.now()) < 2000); + t.assert(Math.abs(users[0]!.createdAt.getTime() - Date.now()) < 2000); + + // check that the timestamps are set correctly for non default times + t.assert(Math.abs(users[1]!.updatedAt.getTime() - date.getTime()) < 2000); + t.assert(Math.abs(users[1]!.createdAt.getTime() - date.getTime()) < 2000); +}); + +// TODO: implement transaction +// test.serial('transaction', async (t) => { +// const { db } = t.context; + +// const users = pgTable('users_transactions', { +// id: serial('id').primaryKey(), +// balance: integer('balance').notNull(), +// }); +// const products = pgTable('products_transactions', { +// id: serial('id').primaryKey(), +// price: integer('price').notNull(), +// stock: integer('stock').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); +// await db.execute(sql`drop table if exists ${products}`); + +// await db.execute(sql`create table users_transactions (id serial not null primary key, balance integer not null)`); +// await db.execute( +// sql`create table products_transactions (id serial not null primary key, price integer not null, stock integer not null)`, +// ); + +// const user = await db.insert(users).values({ balance: 100 }).returning().then((rows) => rows[0]!); +// const product = await db.insert(products).values({ price: 10, stock: 10 }).returning().then((rows) => rows[0]!); + +// await db.transaction(async (tx) => { +// await tx.update(users).set({ balance: user.balance - product.price }).where(eq(users.id, user.id)); +// await tx.update(products).set({ stock: product.stock - 1 }).where(eq(products.id, product.id)); +// }); + +// const result = await db.select().from(users); + +// t.deepEqual(result, [{ id: 1, balance: 90 }]); + +// await db.execute(sql`drop table ${users}`); +// await db.execute(sql`drop table ${products}`); +// }); + +// TODO: implement transaction +// test.serial('transaction rollback', async (t) => { + +// const { db } = t.context; + +// const users = pgTable('users_transactions_rollback', { +// id: serial('id').primaryKey(), +// balance: integer('balance').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); + +// await db.execute( +// sql`create table users_transactions_rollback (id serial not null primary key, balance integer not null)`, +// ); + +// await t.throwsAsync(async () => +// await db.transaction(async (tx) => { +// await tx.insert(users).values({ balance: 100 }); +// tx.rollback(); +// }), new TransactionRollbackError()); + +// const result = await db.select().from(users); + +// t.deepEqual(result, []); + +// await db.execute(sql`drop table ${users}`); +// }); + +// TODO: implement transaction +// test.serial('nested transaction', async (t) => { +// const { db } = t.context; + +// const users = pgTable('users_nested_transactions', { +// id: serial('id').primaryKey(), +// balance: integer('balance').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); + +// await db.execute( +// sql`create table users_nested_transactions (id serial not null primary key, balance integer not null)`, +// ); + +// await db.transaction(async (tx) => { +// await tx.insert(users).values({ balance: 100 }); + +// await tx.transaction(async (tx) => { +// await tx.update(users).set({ balance: 200 }); +// }); +// }); + +// const result = await db.select().from(users); + +// t.deepEqual(result, [{ id: 1, balance: 200 }]); + +// await db.execute(sql`drop table ${users}`); +// }); + +// TODO: implement transaction +// test.serial('nested transaction rollback', async (_t) => { +// const { db } = t.context; + +// const users = pgTable('users_nested_transactions_rollback', { +// id: serial('id').primaryKey(), +// balance: integer('balance').notNull(), +// }); + +// await db.execute(sql`drop table if exists ${users}`); + +// await db.execute( +// sql`create table users_nested_transactions_rollback (id serial not null primary key, balance integer not null)`, +// ); + +// await db.transaction(async (tx) => { +// await tx.insert(users).values({ balance: 100 }); + +// await t.throwsAsync(async () => +// await tx.transaction(async (tx) => { +// await tx.update(users).set({ balance: 200 }); +// tx.rollback(); +// }), new TransactionRollbackError()); +// }); + +// const result = await db.select().from(users); + +// t.deepEqual(result, [{ id: 1, balance: 100 }]); + +// await db.execute(sql`drop table ${users}`); +// }); + +test.serial('join subquery with join', async (t) => { + const { db } = t.context; + + const internalStaff = pgTable('internal_staff', { + userId: integer('user_id').notNull(), + }); + + const customUser = pgTable('custom_user', { + id: integer('id').notNull(), + }); + + const ticket = pgTable('ticket', { + staffId: integer('staff_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${internalStaff}`); + await db.execute(sql`drop table if exists ${customUser}`); + await db.execute(sql`drop table if exists ${ticket}`); + + await db.execute(sql`create table internal_staff (user_id integer not null)`); + await db.execute(sql`create table custom_user (id integer not null)`); + await db.execute(sql`create table ticket (staff_id integer not null)`); + + await db.insert(internalStaff).values({ userId: 1 }); + await db.insert(customUser).values({ id: 1 }); + await db.insert(ticket).values({ staffId: 1 }); + + const subq = db + .select() + .from(internalStaff) + .leftJoin(customUser, eq(internalStaff.userId, customUser.id)) + .as('internal_staff'); + + const mainQuery = await db + .select() + .from(ticket) + .leftJoin(subq, eq(subq.internal_staff.userId, ticket.staffId)); + + t.deepEqual(mainQuery, [{ + ticket: { staffId: 1 }, + internal_staff: { + internal_staff: { userId: 1 }, + custom_user: { id: 1 }, + }, + }]); + + await db.execute(sql`drop table ${internalStaff}`); + await db.execute(sql`drop table ${customUser}`); + await db.execute(sql`drop table ${ticket}`); +}); + +test.serial('subquery with view', async (t) => { + const { db } = t.context; + + const users = pgTable('users_subquery_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }); + + const newYorkers = pgView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 1 }, + { name: 'Jill', cityId: 2 }, + ]); + + const sq = db.$with('sq').as(db.select().from(newYorkers)); + const result = await db.with(sq).select().from(sq); + + t.deepEqual(result, [ + { id: 1, name: 'John', cityId: 1 }, + { id: 3, name: 'Jack', cityId: 1 }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); + +test.serial('join view as subquery', async (t) => { + const { db } = t.context; + + const users = pgTable('users_join_view', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }); + + const newYorkers = pgView('new_yorkers').as((qb) => qb.select().from(users).where(eq(users.cityId, 1))); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`drop view if exists ${newYorkers}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + await db.execute(sql`create view ${newYorkers} as select * from ${users} where city_id = 1`); + + await db.insert(users).values([ + { name: 'John', cityId: 1 }, + { name: 'Jane', cityId: 2 }, + { name: 'Jack', cityId: 1 }, + { name: 'Jill', cityId: 2 }, + ]); + + const sq = db.select().from(newYorkers).as('new_yorkers_sq'); + + const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id)); + + t.deepEqual(result, [ + { + users_join_view: { id: 1, name: 'John', cityId: 1 }, + new_yorkers_sq: { id: 1, name: 'John', cityId: 1 }, + }, + { + users_join_view: { id: 2, name: 'Jane', cityId: 2 }, + new_yorkers_sq: null, + }, + { + users_join_view: { id: 3, name: 'Jack', cityId: 1 }, + new_yorkers_sq: { id: 3, name: 'Jack', cityId: 1 }, + }, + { + users_join_view: { id: 4, name: 'Jill', cityId: 2 }, + new_yorkers_sq: null, + }, + ]); + + await db.execute(sql`drop view ${newYorkers}`); + await db.execute(sql`drop table ${users}`); +}); + +test.serial('table selection with single table', async (t) => { + const { db } = t.context; + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + cityId: integer('city_id').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text not null, city_id integer not null)`, + ); + + await db.insert(users).values({ name: 'John', cityId: 1 }); + + const result = await db.select({ users }).from(users); + + t.deepEqual(result, [{ users: { id: 1, name: 'John', cityId: 1 } }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('set null to jsonb field', async (t) => { + const { db } = t.context; + + const users = pgTable('users', { + id: serial('id').primaryKey(), + jsonb: jsonb('jsonb'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, jsonb jsonb)`, + ); + + const result = await db.insert(users).values({ jsonb: null }).returning(); + + t.deepEqual(result, [{ id: 1, jsonb: null }]); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('insert undefined', async (t) => { + const { db } = t.context; + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await t.notThrowsAsync(async () => await db.insert(users).values({ name: undefined })); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('update undefined', async (t) => { + const { db } = t.context; + + const users = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name'), + }); + + await db.execute(sql`drop table if exists ${users}`); + + await db.execute( + sql`create table ${users} (id serial not null primary key, name text)`, + ); + + await t.throwsAsync(async () => await db.update(users).set({ name: undefined })); + await t.notThrowsAsync(async () => await db.update(users).set({ id: 1, name: undefined })); + + await db.execute(sql`drop table ${users}`); +}); + +test.serial('array operators', async (t) => { + const { db } = t.context; + + const posts = pgTable('posts', { + id: serial('id').primaryKey(), + tags: text('tags').array(), + }); + + await db.execute(sql`drop table if exists ${posts}`); + + await db.execute( + sql`create table ${posts} (id serial primary key, tags text[])`, + ); + + await db.insert(posts).values([{ + tags: ['ORM'], + }, { + tags: ['Typescript'], + }, { + tags: ['Typescript', 'ORM'], + }, { + tags: ['Typescript', 'Frontend', 'React'], + }, { + tags: ['Typescript', 'ORM', 'Database', 'Postgres'], + }, { + tags: ['Java', 'Spring', 'OOP'], + }]); + + const contains = await db.select({ id: posts.id }).from(posts) + .where(arrayContains(posts.tags, ['Typescript', 'ORM'])); + const contained = await db.select({ id: posts.id }).from(posts) + .where(arrayContained(posts.tags, ['Typescript', 'ORM'])); + const overlaps = await db.select({ id: posts.id }).from(posts) + .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])); + const withSubQuery = await db.select({ id: posts.id }).from(posts) + .where(arrayContains( + posts.tags, + db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)), + )); + + t.deepEqual(contains, [{ id: 3 }, { id: 5 }]); + t.deepEqual(contained, [{ id: 1 }, { id: 2 }, { id: 3 }]); + t.deepEqual(overlaps, [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]); + t.deepEqual(withSubQuery, [{ id: 1 }, { id: 3 }, { id: 5 }]); +}); diff --git a/integration-tests/tests/pg.test.ts b/integration-tests/tests/pg.test.ts index f9a50b563..38fd1a8a3 100644 --- a/integration-tests/tests/pg.test.ts +++ b/integration-tests/tests/pg.test.ts @@ -5,6 +5,9 @@ import anyTest from 'ava'; import Docker from 'dockerode'; import { and, + arrayContained, + arrayContains, + arrayOverlaps, asc, eq, gt, @@ -25,27 +28,35 @@ import { boolean, char, cidr, + except, + exceptAll, + foreignKey, getMaterializedViewConfig, getTableConfig, getViewConfig, inet, integer, + intersect, + intersectAll, jsonb, macaddr, macaddr8, type PgColumn, - pgEnum, pgMaterializedView, pgTable, pgTableCreator, pgView, + primaryKey, serial, text, timestamp, + union, + unionAll, unique, uniqueKeyName, uuid as pgUuid, varchar, + pgEnum, } from 'drizzle-orm/pg-core'; import getPort from 'get-port'; import pg from 'pg'; @@ -70,6 +81,11 @@ const citiesTable = pgTable('cities', { state: char('state', { length: 2 }), }); +const cities2Table = pgTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), +}); + const users2Table = pgTable('users2', { id: serial('id').primaryKey(), name: text('name').notNull(), @@ -278,6 +294,45 @@ test.beforeEach(async (t) => { ); }); +async function setupSetOperationTest(db: NodePgDatabase) { + await db.execute(sql`drop table if exists users2`); + await db.execute(sql`drop table if exists cities`); + await db.execute( + sql` + create table cities ( + id serial primary key, + name text not null + ) + `, + ); + await db.execute( + sql` + create table users2 ( + id serial primary key, + name text not null, + city_id integer references cities(id) + ) + `, + ); + + await db.insert(cities2Table).values([ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + await db.insert(users2Table).values([ + { id: 1, name: 'John', cityId: 1 }, + { id: 2, name: 'Jane', cityId: 2 }, + { id: 3, name: 'Jack', cityId: 3 }, + { id: 4, name: 'Peter', cityId: 3 }, + { id: 5, name: 'Ben', cityId: 2 }, + { id: 6, name: 'Jill', cityId: 1 }, + { id: 7, name: 'Mary', cityId: 2 }, + { id: 8, name: 'Sally', cityId: 1 }, + ]); +} + test.serial('table configs: unique third param', async (t) => { const cities1Table = pgTable('cities1', { id: serial('id').primaryKey(), @@ -325,6 +380,36 @@ test.serial('table configs: unique in column', async (t) => { t.assert(columnField?.uniqueType === 'not distinct'); }); +test.serial('table config: foreign keys name', async (t) => { + const table = pgTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: foreignKey({ foreignColumns: [t.id], columns: [t.id], name: 'custom_fk' }), + })); + + const tableConfig = getTableConfig(table); + + t.is(tableConfig.foreignKeys.length, 1); + t.is(tableConfig.foreignKeys[0]!.getName(), 'custom_fk'); +}); + +test.serial('table config: primary keys name', async (t) => { + const table = pgTable('cities', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + state: text('state'), + }, (t) => ({ + f: primaryKey({ columns: [t.id, t.name], name: 'custom_pk' }), + })); + + const tableConfig = getTableConfig(table); + + t.is(tableConfig.primaryKeys.length, 1); + t.is(tableConfig.primaryKeys[0]!.getName(), 'custom_pk'); +}); + test.serial('select all fields', async (t) => { const { db } = t.context; @@ -1573,20 +1658,71 @@ test.serial('array types', async (t) => { test.serial('select for ...', (t) => { const { db } = t.context; - const query = db - .select() - .from(users2Table) - .for('update') - .for('no key update', { of: users2Table }) - .for('no key update', { of: users2Table, skipLocked: true }) - .for('share', { of: users2Table, noWait: true }) - .toSQL(); + { + const query = db + .select() + .from(users2Table) + .for('update') + .toSQL(); + + t.regex( + query.sql, + / for update$/, + ); + } - t.regex( - query.sql, - // eslint-disable-next-line unicorn/better-regex - / for update for no key update of "users2" for no key update of "users2" skip locked for share of "users2" no wait$/, - ); + { + const query = db + .select() + .from(users2Table) + .for('update', { of: [users2Table, coursesTable] }) + .toSQL(); + + t.regex( + query.sql, + / for update of "users2", "courses"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table }) + .toSQL(); + + t.regex( + query.sql, + /for no key update of "users2"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table, skipLocked: true }) + .toSQL(); + + t.regex( + query.sql, + / for no key update of "users2" skip locked$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('share', { of: users2Table, noWait: true }) + .toSQL(); + + t.regex( + query.sql, + // eslint-disable-next-line unicorn/better-regex + /for share of "users2" no wait$/, + ); + } }); test.serial('having', async (t) => { @@ -2162,7 +2298,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -2221,7 +2357,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); @@ -2456,3 +2592,562 @@ test.serial('update undefined', async (t) => { await db.execute(sql`drop table ${users}`); }); + +test.serial('array operators', async (t) => { + const { db } = t.context; + + const posts = pgTable('posts', { + id: serial('id').primaryKey(), + tags: text('tags').array(), + }); + + await db.execute(sql`drop table if exists ${posts}`); + + await db.execute( + sql`create table ${posts} (id serial primary key, tags text[])`, + ); + + await db.insert(posts).values([{ + tags: ['ORM'], + }, { + tags: ['Typescript'], + }, { + tags: ['Typescript', 'ORM'], + }, { + tags: ['Typescript', 'Frontend', 'React'], + }, { + tags: ['Typescript', 'ORM', 'Database', 'Postgres'], + }, { + tags: ['Java', 'Spring', 'OOP'], + }]); + + const contains = await db.select({ id: posts.id }).from(posts) + .where(arrayContains(posts.tags, ['Typescript', 'ORM'])); + const contained = await db.select({ id: posts.id }).from(posts) + .where(arrayContained(posts.tags, ['Typescript', 'ORM'])); + const overlaps = await db.select({ id: posts.id }).from(posts) + .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])); + const withSubQuery = await db.select({ id: posts.id }).from(posts) + .where(arrayContains( + posts.tags, + db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)), + )); + + t.deepEqual(contains, [{ id: 3 }, { id: 5 }]); + t.deepEqual(contained, [{ id: 1 }, { id: 2 }, { id: 3 }]); + t.deepEqual(overlaps, [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]); + t.deepEqual(withSubQuery, [{ id: 1 }, { id: 3 }, { id: 5 }]); +}); + +test.serial('set operations (union) from query builder with subquery', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const sq = db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).as('sq'); + + const result = await db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).union( + db.select().from(sq), + ).orderBy(asc(sql`name`)).limit(2).offset(1); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 3, name: 'Jack' }, + { id: 2, name: 'Jane' }, + ]); + + t.throws(() => { + db + .select({ id: cities2Table.id, name: citiesTable.name, name2: users2Table.name }) + .from(cities2Table).union( + // @ts-expect-error + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + ).orderBy(asc(sql`name`)); + }); +}); + +test.serial('set operations (union) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)).limit(1).offset(1); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + ]); + + t.throws(() => { + union( + db + .select({ name: citiesTable.name, id: cities2Table.id }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`name`)); + }); +}); + +test.serial('set operations (union all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).limit(2).unionAll( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).limit(2), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 4); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + { id: 2, name: 'London' }, + ]); + + t.throws(() => { + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).limit(2).unionAll( + db + .select({ name: citiesTable.name, id: cities2Table.id }) + .from(cities2Table).limit(2), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (union all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await unionAll( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 3); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 1, name: 'John' }, + { id: 1, name: 'John' }, + ]); + + t.throws(() => { + unionAll( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (intersect) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).intersect( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`name`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).intersect( + // @ts-expect-error + db + .select({ id: cities2Table.id, name: citiesTable.name, id2: cities2Table.id }) + .from(cities2Table).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`name`)); + }); +}); + +test.serial('set operations (intersect) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await intersect( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 0); + + t.deepEqual(result, []); + + t.throws(() => { + intersect( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (intersect all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).limit(2).intersectAll( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).limit(2), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + { id: 2, name: 'London' }, + ]); + + t.throws(() => { + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).limit(2).intersectAll( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(cities2Table).limit(2), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (intersect all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await intersectAll( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + ]); + + t.throws(() => { + intersectAll( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ); + }); +}); + +test.serial('set operations (except) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(cities2Table).except( + db + .select() + .from(cities2Table).where(gt(citiesTable.id, 1)), + ); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + ]); + + t.throws(() => { + db + .select() + .from(cities2Table).except( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(cities2Table).where(gt(citiesTable.id, 1)), + ); + }); +}); + +test.serial('set operations (except) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await except( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table), + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + except( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (except all) from query builder', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await db + .select() + .from(cities2Table).exceptAll( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 2); + + t.deepEqual(result, [ + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + ]); + + t.throws(() => { + db + .select({ name: cities2Table.name, id: cities2Table.id }) + .from(cities2Table).exceptAll( + db + .select({ id: cities2Table.id, name: citiesTable.name }) + .from(cities2Table).where(eq(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (except all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await exceptAll( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gt(users2Table.id, 7)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)).limit(5).offset(2); + + t.assert(result.length === 4); + + t.deepEqual(result, [ + { id: 4, name: 'Peter' }, + { id: 5, name: 'Ben' }, + { id: 6, name: 'Jill' }, + { id: 7, name: 'Mary' }, + ]); + + t.throws(() => { + exceptAll( + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gt(users2Table.id, 7)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); + +test.serial('set operations (mixed) from query builder with subquery', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + const sq = db + .select() + .from(cities2Table).where(gt(citiesTable.id, 1)).as('sq'); + + const result = await db + .select() + .from(cities2Table).except( + ({ unionAll }) => + unionAll( + db.select().from(sq), + db.select().from(cities2Table).where(eq(citiesTable.id, 2)), + ), + ); + + t.assert(result.length === 1); + + t.deepEqual(result, [ + { id: 1, name: 'New York' }, + ]); + + t.throws(() => { + db + .select() + .from(cities2Table).except( + ({ unionAll }) => + unionAll( + db + .select({ name: cities2Table.name, id: cities2Table.id }) + .from(cities2Table).where(gt(citiesTable.id, 1)), + db.select().from(cities2Table).where(eq(citiesTable.id, 2)), + ), + ); + }); +}); + +test.serial('set operations (mixed all) as function', async (t) => { + const { db } = t.context; + + await setupSetOperationTest(db); + + const result = await union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 7)), + ), + db + .select().from(cities2Table).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + + t.assert(result.length === 6); + + t.deepEqual(result, [ + { id: 1, name: 'John' }, + { id: 2, name: 'London' }, + { id: 3, name: 'Tampa' }, + { id: 5, name: 'Ben' }, + { id: 6, name: 'Jill' }, + { id: 8, name: 'Sally' }, + ]); + + t.throws(() => { + union( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(eq(users2Table.id, 1)), + except( + db + .select({ id: users2Table.id, name: users2Table.name }) + .from(users2Table).where(gte(users2Table.id, 5)), + db + .select({ name: users2Table.name, id: users2Table.id }) + .from(users2Table).where(eq(users2Table.id, 7)), + ), + db + .select().from(cities2Table).where(gt(citiesTable.id, 1)), + ).orderBy(asc(sql`id`)); + }); +}); diff --git a/integration-tests/tests/planetscale-serverless/mysql.test.ts b/integration-tests/tests/planetscale-serverless/mysql.test.ts index 0006eed77..3d5ddafec 100644 --- a/integration-tests/tests/planetscale-serverless/mysql.test.ts +++ b/integration-tests/tests/planetscale-serverless/mysql.test.ts @@ -775,7 +775,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -834,7 +834,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); diff --git a/integration-tests/tests/postgres.js.test.ts b/integration-tests/tests/postgres.js.test.ts index fb657d41b..a1f979f60 100644 --- a/integration-tests/tests/postgres.js.test.ts +++ b/integration-tests/tests/postgres.js.test.ts @@ -5,8 +5,10 @@ import anyTest from 'ava'; import Docker from 'dockerode'; import { and, + arrayContained, + arrayContains, + arrayOverlaps, asc, - DrizzleError, eq, gt, gte, @@ -18,6 +20,7 @@ import { type SQL, sql, type SQLWrapper, + TransactionRollbackError, } from 'drizzle-orm'; import { alias, @@ -1304,20 +1307,71 @@ test.serial('select count w/ custom mapper', async (t) => { test.serial('select for ...', (t) => { const { db } = t.context; - const query = db - .select() - .from(users2Table) - .for('update') - .for('no key update', { of: users2Table }) - .for('no key update', { of: users2Table, skipLocked: true }) - .for('share', { of: users2Table, noWait: true }) - .toSQL(); + { + const query = db + .select() + .from(users2Table) + .for('update') + .toSQL(); + + t.regex( + query.sql, + / for update$/, + ); + } - t.regex( - query.sql, - // eslint-disable-next-line unicorn/better-regex - /select ("(id|name|city_id)"(, )?){3} from "users2" for update for no key update of "users2" for no key update of "users2" skip locked for share of "users2" no wait/, - ); + { + const query = db + .select() + .from(users2Table) + .for('update', { of: [users2Table, coursesTable] }) + .toSQL(); + + t.regex( + query.sql, + / for update of "users2", "courses"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table }) + .toSQL(); + + t.regex( + query.sql, + /for no key update of "users2"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table, skipLocked: true }) + .toSQL(); + + t.regex( + query.sql, + / for no key update of "users2" skip locked$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('share', { of: users2Table, noWait: true }) + .toSQL(); + + t.regex( + query.sql, + // eslint-disable-next-line unicorn/better-regex + /for share of "users2" no wait$/, + ); + } }); test.serial('having', async (t) => { @@ -1851,7 +1905,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); await tx.rollback(); - }), new DrizzleError('Rollback')); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -1910,7 +1964,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); await tx.rollback(); - }), new DrizzleError('Rollback')); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); @@ -2062,3 +2116,49 @@ test.serial('update undefined', async (t) => { await db.execute(sql`drop table ${users}`); }); + +test.serial('array operators', async (t) => { + const { db } = t.context; + + const posts = pgTable('posts', { + id: serial('id').primaryKey(), + tags: text('tags').array(), + }); + + await db.execute(sql`drop table if exists ${posts}`); + + await db.execute( + sql`create table ${posts} (id serial primary key, tags text[])`, + ); + + await db.insert(posts).values([{ + tags: ['ORM'], + }, { + tags: ['Typescript'], + }, { + tags: ['Typescript', 'ORM'], + }, { + tags: ['Typescript', 'Frontend', 'React'], + }, { + tags: ['Typescript', 'ORM', 'Database', 'Postgres'], + }, { + tags: ['Java', 'Spring', 'OOP'], + }]); + + const contains = await db.select({ id: posts.id }).from(posts) + .where(arrayContains(posts.tags, ['Typescript', 'ORM'])); + const contained = await db.select({ id: posts.id }).from(posts) + .where(arrayContained(posts.tags, ['Typescript', 'ORM'])); + const overlaps = await db.select({ id: posts.id }).from(posts) + .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])); + const withSubQuery = await db.select({ id: posts.id }).from(posts) + .where(arrayContains( + posts.tags, + db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)), + )); + + t.deepEqual(contains, [{ id: 3 }, { id: 5 }]); + t.deepEqual(contained, [{ id: 1 }, { id: 2 }, { id: 3 }]); + t.deepEqual(overlaps, [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]); + t.deepEqual(withSubQuery, [{ id: 1 }, { id: 3 }, { id: 5 }]); +}); diff --git a/integration-tests/tests/relational/bettersqlite.test.ts b/integration-tests/tests/relational/bettersqlite.test.ts index 6e4bcb750..ff423c2de 100644 --- a/integration-tests/tests/relational/bettersqlite.test.ts +++ b/integration-tests/tests/relational/bettersqlite.test.ts @@ -5978,6 +5978,13 @@ test('async api - sync() + prepare', () => { expect(users).toEqual([{ id: 1, name: 'Dan', verified: 0, invitedBy: null }]); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // + custom + where + orderby // + custom + where + orderby + limit diff --git a/integration-tests/tests/relational/mysql.planetscale.test.ts b/integration-tests/tests/relational/mysql.planetscale.test.ts index a87355141..e6dd96fa4 100644 --- a/integration-tests/tests/relational/mysql.planetscale.test.ts +++ b/integration-tests/tests/relational/mysql.planetscale.test.ts @@ -5966,6 +5966,13 @@ test('Get groups with users + custom', async () => { }); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // + custom + where + orderby // + custom + where + orderby + limit diff --git a/integration-tests/tests/relational/mysql.test.ts b/integration-tests/tests/relational/mysql.test.ts index b2b526a53..001a94bf2 100644 --- a/integration-tests/tests/relational/mysql.test.ts +++ b/integration-tests/tests/relational/mysql.test.ts @@ -6186,6 +6186,13 @@ test('Get groups with users + custom', async (t) => { }); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // + custom + where + orderby // + custom + where + orderby + limit diff --git a/integration-tests/tests/relational/pg.postgresjs.test.ts b/integration-tests/tests/relational/pg.postgresjs.test.ts index bced334dc..85a455e80 100644 --- a/integration-tests/tests/relational/pg.postgresjs.test.ts +++ b/integration-tests/tests/relational/pg.postgresjs.test.ts @@ -6166,6 +6166,13 @@ test('Get groups with users + custom', async (t) => { }); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // + custom + where + orderby // + custom + where + orderby + limit diff --git a/integration-tests/tests/relational/pg.schema.ts b/integration-tests/tests/relational/pg.schema.ts index b17bafa60..05f06aaa1 100644 --- a/integration-tests/tests/relational/pg.schema.ts +++ b/integration-tests/tests/relational/pg.schema.ts @@ -30,7 +30,7 @@ export const usersToGroupsTable = pgTable('users_to_groups', { userId: integer('user_id').notNull().references(() => usersTable.id), groupId: integer('group_id').notNull().references(() => groupsTable.id), }, (t) => ({ - pk: primaryKey(t.userId, t.groupId), + pk: primaryKey(t.groupId,t.userId), })); export const usersToGroupsConfig = relations(usersToGroupsTable, ({ one }) => ({ diff --git a/integration-tests/tests/relational/pg.test.ts b/integration-tests/tests/relational/pg.test.ts index 02f7fcbec..faff8f07f 100644 --- a/integration-tests/tests/relational/pg.test.ts +++ b/integration-tests/tests/relational/pg.test.ts @@ -6185,6 +6185,13 @@ test('Filter by columns not present in select', async (t) => { expect(response).toEqual({ id: 1 }); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // test('Filter by relational column', async (t) => { // const { pgDb: db } = t; diff --git a/integration-tests/tests/relational/turso.test.ts b/integration-tests/tests/relational/turso.test.ts index d534fb7ee..ab37569fb 100644 --- a/integration-tests/tests/relational/turso.test.ts +++ b/integration-tests/tests/relational/turso.test.ts @@ -46,14 +46,14 @@ beforeAll(async () => { }); beforeEach(async () => { - db.run(sql`drop table if exists \`groups\``); - db.run(sql`drop table if exists \`users\``); - db.run(sql`drop table if exists \`users_to_groups\``); - db.run(sql`drop table if exists \`posts\``); - db.run(sql`drop table if exists \`comments\``); - db.run(sql`drop table if exists \`comment_likes\``); - - db.run( + await db.run(sql`drop table if exists \`groups\``); + await db.run(sql`drop table if exists \`users\``); + await db.run(sql`drop table if exists \`users_to_groups\``); + await db.run(sql`drop table if exists \`posts\``); + await db.run(sql`drop table if exists \`comments\``); + await db.run(sql`drop table if exists \`comment_likes\``); + + await db.run( sql` CREATE TABLE \`users\` ( \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -63,7 +63,7 @@ beforeEach(async () => { ); `, ); - db.run( + await db.run( sql` CREATE TABLE \`groups\` ( \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -72,7 +72,7 @@ beforeEach(async () => { ); `, ); - db.run( + await db.run( sql` CREATE TABLE \`users_to_groups\` ( \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -81,7 +81,7 @@ beforeEach(async () => { ); `, ); - db.run( + await db.run( sql` CREATE TABLE \`posts\` ( \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -91,7 +91,7 @@ beforeEach(async () => { ); `, ); - db.run( + await db.run( sql` CREATE TABLE \`comments\` ( \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -102,7 +102,7 @@ beforeEach(async () => { ); `, ); - db.run( + await db.run( sql` CREATE TABLE \`comment_likes\` ( \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -5990,6 +5990,13 @@ test('async api - prepare', async () => { expect(users).toEqual([{ id: 1, name: 'Dan', verified: 0, invitedBy: null }]); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // + custom + where + orderby // + custom + where + orderby + limit diff --git a/integration-tests/tests/relational/vercel.test.ts b/integration-tests/tests/relational/vercel.test.ts index e53356d84..424f25c99 100644 --- a/integration-tests/tests/relational/vercel.test.ts +++ b/integration-tests/tests/relational/vercel.test.ts @@ -6171,6 +6171,13 @@ test('Get groups with users + custom', async (t) => { }); }); +test('.toSQL()', () => { + const query = db.query.usersTable.findFirst().toSQL(); + + expect(query).toHaveProperty('sql', expect.any(String)); + expect(query).toHaveProperty('params', expect.any(Array)); +}); + // + custom + where + orderby // + custom + where + orderby + limit diff --git a/integration-tests/tests/replicas/mysql.test.ts b/integration-tests/tests/replicas/mysql.test.ts new file mode 100644 index 000000000..62fa6af41 --- /dev/null +++ b/integration-tests/tests/replicas/mysql.test.ts @@ -0,0 +1,719 @@ +import { sql } from 'drizzle-orm'; +import { boolean, mysqlTable, serial, text, withReplicas } from 'drizzle-orm/mysql-core'; +import { drizzle } from 'drizzle-orm/mysql2'; +import { describe, expect, it, vi } from 'vitest'; + +const usersTable = mysqlTable('users', { + id: serial('id' as string).primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), +}); + +describe('[select] read replicas postgres', () => { + it('primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.$primary.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica select + primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.select().from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[selectDistinct] read replicas postgres', () => { + it('primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.$primary.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica selectDistinct + primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.selectDistinct().from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[with] read replicas postgres', () => { + it('primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.$primary.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica with + primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.with(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[update] replicas postgres', () => { + it('primary update', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'update'); + const spyRead1 = vi.spyOn(read1, 'update'); + const spyRead2 = vi.spyOn(read2, 'update'); + + db.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[delete] replicas postgres', () => { + it('primary delete', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'delete'); + const spyRead1 = vi.spyOn(read1, 'delete'); + const spyRead2 = vi.spyOn(read2, 'delete'); + + db.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[insert] replicas postgres', () => { + it('primary insert', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'insert'); + const spyRead1 = vi.spyOn(read1, 'insert'); + const spyRead2 = vi.spyOn(read2, 'insert'); + + db.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[execute] replicas postgres', () => { + it('primary execute', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'execute'); + const spyRead1 = vi.spyOn(read1, 'execute'); + const spyRead2 = vi.spyOn(read2, 'execute'); + + // expect(db.execute(sql``)).rejects.toThrow(); + + try { + db.execute(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + try { + db.execute(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + try { + db.execute(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[transaction] replicas postgres', () => { + it('primary transaction', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'transaction'); + const spyRead1 = vi.spyOn(read1, 'transaction'); + const spyRead2 = vi.spyOn(read2, 'transaction'); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findFirst] read replicas postgres', () => { + it('primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.$primary.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findFirst + primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findFirst(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findMany] read replicas postgres', () => { + it('primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.$primary.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findMany + primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findMany(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read1 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + const read2 = drizzle({} as any, { schema: { usersTable }, mode: 'default' }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); \ No newline at end of file diff --git a/integration-tests/tests/replicas/postgres.test.ts b/integration-tests/tests/replicas/postgres.test.ts new file mode 100644 index 000000000..a782045c4 --- /dev/null +++ b/integration-tests/tests/replicas/postgres.test.ts @@ -0,0 +1,860 @@ +import { sql } from 'drizzle-orm'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import { boolean, jsonb, pgTable, serial, text, timestamp, withReplicas } from 'drizzle-orm/pg-core'; +import { describe, expect, it, vi } from 'vitest'; + +const usersTable = pgTable('users', { + id: serial('id' as string).primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: jsonb('jsonb').$type(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + +describe('[select] read replicas postgres', () => { + it('primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.$primary.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica select + primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.select().from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[selectDistinct] read replicas postgres', () => { + it('primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.$primary.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica selectDistinct + primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.selectDistinct().from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[selectDistinctOn] read replicas postgres', () => { + it('primary selectDistinctOn', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinctOn'); + const spyRead1 = vi.spyOn(read1, 'selectDistinctOn'); + const spyRead2 = vi.spyOn(read2, 'selectDistinctOn'); + + db.$primary.selectDistinctOn({} as any).from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica selectDistinctOn', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinctOn'); + const spyRead1 = vi.spyOn(read1, 'selectDistinctOn'); + const spyRead2 = vi.spyOn(read2, 'selectDistinctOn'); + + db.selectDistinctOn({} as any).from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinctOn({} as any).from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica selectDistinctOn', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinctOn'); + const spyRead1 = vi.spyOn(read1, 'selectDistinctOn'); + + db.selectDistinctOn({} as any).from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.selectDistinctOn({} as any).from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica selectDistinctOn + primary selectDistinctOn', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinctOn'); + const spyRead1 = vi.spyOn(read1, 'selectDistinctOn'); + + db.selectDistinctOn({} as any).from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.selectDistinctOn({} as any).from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read selectDistinctOn', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinctOn'); + const spyRead1 = vi.spyOn(read1, 'selectDistinctOn'); + const spyRead2 = vi.spyOn(read2, 'selectDistinctOn'); + + db.selectDistinctOn({} as any).from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinctOn({} as any).from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[with] read replicas postgres', () => { + it('primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.$primary.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica with + primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.with(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[update] replicas postgres', () => { + it('primary update', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'update'); + const spyRead1 = vi.spyOn(read1, 'update'); + const spyRead2 = vi.spyOn(read2, 'update'); + + db.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[delete] replicas postgres', () => { + it('primary delete', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'delete'); + const spyRead1 = vi.spyOn(read1, 'delete'); + const spyRead2 = vi.spyOn(read2, 'delete'); + + db.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[insert] replicas postgres', () => { + it('primary insert', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'insert'); + const spyRead1 = vi.spyOn(read1, 'insert'); + const spyRead2 = vi.spyOn(read2, 'insert'); + + db.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[execute] replicas postgres', () => { + it('primary execute', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'execute'); + const spyRead1 = vi.spyOn(read1, 'execute'); + const spyRead2 = vi.spyOn(read2, 'execute'); + + // expect(db.execute(sql``)).rejects.toThrow(); + + try { + db.execute(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + try { + db.execute(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + try { + db.execute(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[transaction] replicas postgres', () => { + it('primary transaction', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'transaction'); + const spyRead1 = vi.spyOn(read1, 'transaction'); + const spyRead2 = vi.spyOn(read2, 'transaction'); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[refreshView] replicas postgres', () => { + it('primary refreshView', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'refreshMaterializedView'); + const spyRead1 = vi.spyOn(read1, 'refreshMaterializedView'); + const spyRead2 = vi.spyOn(read2, 'refreshMaterializedView'); + + db.refreshMaterializedView({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.refreshMaterializedView({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.refreshMaterializedView({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findFirst] read replicas postgres', () => { + it('primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.$primary.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findFirst + primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findFirst(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findMany] read replicas postgres', () => { + it('primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.$primary.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findMany + primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findMany(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); diff --git a/integration-tests/tests/replicas/sqlite.test.ts b/integration-tests/tests/replicas/sqlite.test.ts new file mode 100644 index 000000000..b607ce1a0 --- /dev/null +++ b/integration-tests/tests/replicas/sqlite.test.ts @@ -0,0 +1,718 @@ +import { sql } from 'drizzle-orm'; +import { sqliteTable, int, text, withReplicas } from 'drizzle-orm/sqlite-core'; +import { drizzle } from 'drizzle-orm/libsql'; +import { describe, expect, it, vi } from 'vitest'; + +const usersTable = sqliteTable('users', { + id: int('id' as string).primaryKey(), + name: text('name').notNull(), +}); + +describe('[select] read replicas postgres', () => { + it('primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.$primary.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica select + primary select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.select().from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read select', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'select'); + const spyRead1 = vi.spyOn(read1, 'select'); + const spyRead2 = vi.spyOn(read2, 'select'); + + db.select().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.select().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[selectDistinct] read replicas postgres', () => { + it('primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.$primary.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica selectDistinct + primary selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.selectDistinct().from({} as any); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read selectDistinct', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'selectDistinct'); + const spyRead1 = vi.spyOn(read1, 'selectDistinct'); + const spyRead2 = vi.spyOn(read2, 'selectDistinct'); + + db.selectDistinct().from({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.selectDistinct().from({} as any); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[with] read replicas postgres', () => { + it('primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.$primary.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica with + primary with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.with(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read with', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb, 'with'); + const spyRead1 = vi.spyOn(read1, 'with'); + const spyRead2 = vi.spyOn(read2, 'with'); + + db.with(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.with(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[update] replicas postgres', () => { + it('primary update', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'update'); + const spyRead1 = vi.spyOn(read1, 'update'); + const spyRead2 = vi.spyOn(read2, 'update'); + + db.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.update({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[delete] replicas postgres', () => { + it('primary delete', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'delete'); + const spyRead1 = vi.spyOn(read1, 'delete'); + const spyRead2 = vi.spyOn(read2, 'delete'); + + db.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.delete({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[insert] replicas postgres', () => { + it('primary insert', () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'insert'); + const spyRead1 = vi.spyOn(read1, 'insert'); + const spyRead2 = vi.spyOn(read2, 'insert'); + + db.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.$primary.insert({} as any); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[execute] replicas postgres', () => { + it('primary execute', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'all'); + const spyRead1 = vi.spyOn(read1, 'all'); + const spyRead2 = vi.spyOn(read2, 'all'); + + // expect(db.execute(sql``)).rejects.toThrow(); + + try { + db.all(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + try { + db.all(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + try { + db.all(sql``); + } catch { /* empty */ } + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[transaction] replicas postgres', () => { + it('primary transaction', async () => { + const primaryDb = drizzle({} as any); + const read1 = drizzle({} as any); + const read2 = drizzle({} as any); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb, 'transaction'); + const spyRead1 = vi.spyOn(read1, 'transaction'); + const spyRead2 = vi.spyOn(read2, 'transaction'); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(2); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + + expect(db.transaction(async (tx) => { + tx.select().from({} as any); + })).rejects.toThrow(); + + expect(spyPrimary).toHaveBeenCalledTimes(3); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findFirst] read replicas postgres', () => { + it('primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.$primary.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findFirst + primary findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findFirst(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findFirst', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findFirst'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findFirst'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findFirst'); + + db.query.usersTable.findFirst(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findFirst(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); + +describe('[findMany] read replicas postgres', () => { + it('primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.$primary.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(0); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); + + it('random replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const randomMockReplica = vi.fn().mockReturnValueOnce(read1).mockReturnValueOnce(read2); + + const db = withReplicas(primaryDb, [read1, read2], () => { + return randomMockReplica(); + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(1); + }); + + it('single read replica findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(2); + }); + + it('single read replica findMany + primary findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1]); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + + db.$primary.query.usersTable.findMany(); + expect(spyPrimary).toHaveBeenCalledTimes(1); + expect(spyRead1).toHaveBeenCalledTimes(1); + }); + + it('always first read findMany', () => { + const primaryDb = drizzle({} as any, { schema: { usersTable } }); + const read1 = drizzle({} as any, { schema: { usersTable } }); + const read2 = drizzle({} as any, { schema: { usersTable } }); + + const db = withReplicas(primaryDb, [read1, read2], (replicas) => { + return replicas[0]!; + }); + + const spyPrimary = vi.spyOn(primaryDb['query']['usersTable'], 'findMany'); + const spyRead1 = vi.spyOn(read1['query']['usersTable'], 'findMany'); + const spyRead2 = vi.spyOn(read2['query']['usersTable'], 'findMany'); + + db.query.usersTable.findMany(); + + expect(spyPrimary).toHaveBeenCalledTimes(0); + expect(spyRead1).toHaveBeenCalledTimes(1); + expect(spyRead2).toHaveBeenCalledTimes(0); + + db.query.usersTable.findMany(); + expect(spyRead1).toHaveBeenCalledTimes(2); + expect(spyRead2).toHaveBeenCalledTimes(0); + }); +}); \ No newline at end of file diff --git a/integration-tests/tests/sql.js.test.ts b/integration-tests/tests/sql.js.test.ts index 38d638fe1..7e4df8036 100644 --- a/integration-tests/tests/sql.js.test.ts +++ b/integration-tests/tests/sql.js.test.ts @@ -1341,7 +1341,7 @@ test.serial('transaction rollback', (t) => { db.transaction((tx) => { tx.insert(users).values({ balance: 100 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = db.select().from(users).all(); @@ -1400,7 +1400,7 @@ test.serial('nested transaction rollback', (t) => { tx.transaction((tx) => { tx.update(users).set({ balance: 200 }).run(); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = db.select().from(users).all(); diff --git a/integration-tests/tests/utils.ts b/integration-tests/tests/utils.ts index 199ed1a57..2d021a2e3 100644 --- a/integration-tests/tests/utils.ts +++ b/integration-tests/tests/utils.ts @@ -3,3 +3,9 @@ export function Expect() {} export type Equal = (() => T extends X ? 1 : 2) extends (() => T extends Y ? 1 : 2) ? true : false; + +export function toLocalDate(date: Date) { + const localTime = new Date(date.getTime() - date.getTimezoneOffset() * 60000); + localTime.setUTCHours(0); + return localTime; +} diff --git a/integration-tests/tests/vercel-pg.test.ts b/integration-tests/tests/vercel-pg.test.ts index 2a02cc98d..c51f2bd62 100644 --- a/integration-tests/tests/vercel-pg.test.ts +++ b/integration-tests/tests/vercel-pg.test.ts @@ -6,6 +6,9 @@ import anyTest from 'ava'; import Docker from 'dockerode'; import { and, + arrayContained, + arrayContains, + arrayOverlaps, asc, eq, gt, @@ -1409,20 +1412,71 @@ test.serial('array types', async (t) => { test.serial('select for ...', (t) => { const { db } = t.context; - const query = db - .select() - .from(users2Table) - .for('update') - .for('no key update', { of: users2Table }) - .for('no key update', { of: users2Table, skipLocked: true }) - .for('share', { of: users2Table, noWait: true }) - .toSQL(); + { + const query = db + .select() + .from(users2Table) + .for('update') + .toSQL(); + + t.regex( + query.sql, + / for update$/, + ); + } - t.regex( - query.sql, - // eslint-disable-next-line unicorn/better-regex - / for update for no key update of "users2" for no key update of "users2" skip locked for share of "users2" no wait$/, - ); + { + const query = db + .select() + .from(users2Table) + .for('update', { of: [users2Table, coursesTable] }) + .toSQL(); + + t.regex( + query.sql, + / for update of "users2", "courses"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table }) + .toSQL(); + + t.regex( + query.sql, + /for no key update of "users2"$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('no key update', { of: users2Table, skipLocked: true }) + .toSQL(); + + t.regex( + query.sql, + / for no key update of "users2" skip locked$/, + ); + } + + { + const query = db + .select() + .from(users2Table) + .for('share', { of: users2Table, noWait: true }) + .toSQL(); + + t.regex( + query.sql, + // eslint-disable-next-line unicorn/better-regex + /for share of "users2" no wait$/, + ); + } }); test.serial('having', async (t) => { @@ -1998,7 +2052,7 @@ test.serial('transaction rollback', async (t) => { await db.transaction(async (tx) => { await tx.insert(users).values({ balance: 100 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); const result = await db.select().from(users); @@ -2057,7 +2111,7 @@ test.serial('nested transaction rollback', async (t) => { await tx.transaction(async (tx) => { await tx.update(users).set({ balance: 200 }); tx.rollback(); - }), new TransactionRollbackError()); + }), { instanceOf: TransactionRollbackError }); }); const result = await db.select().from(users); @@ -2292,3 +2346,49 @@ test.serial('update undefined', async (t) => { await db.execute(sql`drop table ${users}`); }); + +test.serial('array operators', async (t) => { + const { db } = t.context; + + const posts = pgTable('posts', { + id: serial('id').primaryKey(), + tags: text('tags').array(), + }); + + await db.execute(sql`drop table if exists ${posts}`); + + await db.execute( + sql`create table ${posts} (id serial primary key, tags text[])`, + ); + + await db.insert(posts).values([{ + tags: ['ORM'], + }, { + tags: ['Typescript'], + }, { + tags: ['Typescript', 'ORM'], + }, { + tags: ['Typescript', 'Frontend', 'React'], + }, { + tags: ['Typescript', 'ORM', 'Database', 'Postgres'], + }, { + tags: ['Java', 'Spring', 'OOP'], + }]); + + const contains = await db.select({ id: posts.id }).from(posts) + .where(arrayContains(posts.tags, ['Typescript', 'ORM'])); + const contained = await db.select({ id: posts.id }).from(posts) + .where(arrayContained(posts.tags, ['Typescript', 'ORM'])); + const overlaps = await db.select({ id: posts.id }).from(posts) + .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM'])); + const withSubQuery = await db.select({ id: posts.id }).from(posts) + .where(arrayContains( + posts.tags, + db.select({ tags: posts.tags }).from(posts).where(eq(posts.id, 1)), + )); + + t.deepEqual(contains, [{ id: 3 }, { id: 5 }]); + t.deepEqual(contained, [{ id: 1 }, { id: 2 }, { id: 3 }]); + t.deepEqual(overlaps, [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]); + t.deepEqual(withSubQuery, [{ id: 1 }, { id: 3 }, { id: 5 }]); +}); diff --git a/integration-tests/tsconfig.json b/integration-tests/tsconfig.json index 72238c14f..a80bcaf56 100644 --- a/integration-tests/tsconfig.json +++ b/integration-tests/tsconfig.json @@ -1,14 +1,11 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "module": "esnext", - "target": "esnext", - "moduleResolution": "NodeNext", - "allowImportingTsExtensions": true, "noEmit": true, "paths": { "~/*": ["./tests/*"] } }, - "include": ["tests", "type-tests"] + "include": ["tests", "type-tests"], + "exclude": ["**/playground"] } diff --git a/integration-tests/vitest.config.ts b/integration-tests/vitest.config.ts index 75a12a4ec..261754895 100644 --- a/integration-tests/vitest.config.ts +++ b/integration-tests/vitest.config.ts @@ -4,7 +4,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { - include: ['tests/relational/**/*.test.ts'], + include: ['tests/relational/**/*.test.ts', 'tests/libsql-batch.test.ts', 'tests/d1-batch.test.ts', 'tests/replicas/**/*', 'tests/imports/**/*'], exclude: [ ...(process.env.SKIP_PLANETSCALE_TESTS ? ['tests/relational/mysql.planetscale.test.ts'] : []), 'tests/relational/vercel.test.ts', @@ -12,8 +12,8 @@ export default defineConfig({ typecheck: { tsconfig: 'tsconfig.json', }, - testTimeout: 40000, - hookTimeout: 40000, + testTimeout: 100000, + hookTimeout: 100000, // deps: { // inline: true, // }, diff --git a/package.json b/package.json index 3bbb6b284..89f2e6f17 100755 --- a/package.json +++ b/package.json @@ -11,30 +11,34 @@ "lint": "eslint --ext ts ." }, "devDependencies": { + "@arethetypeswrong/cli": "^0.12.1", "@trivago/prettier-plugin-sort-imports": "^4.2.0", - "@typescript-eslint/eslint-plugin": "^6.4.1", + "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/experimental-utils": "^5.62.0", - "@typescript-eslint/parser": "^6.4.1", - "bun-types": "^0.7.3", + "@typescript-eslint/parser": "^6.7.3", + "bun-types": "^1.0.3", "concurrently": "^8.2.1", - "dprint": "^0.40.2", + "dprint": "^0.41.0", "drizzle-kit": "^0.19.13", "drizzle-orm": "workspace:./drizzle-orm/dist", "drizzle-orm-old": "npm:drizzle-orm@^0.27.2", - "eslint": "^8.47.0", + "eslint": "^8.50.0", "eslint-plugin-drizzle": "link:eslint/eslint-plugin-drizzle", "eslint-plugin-import": "^2.28.1", "eslint-plugin-no-instanceof": "^1.0.1", "eslint-plugin-unicorn": "^48.0.1", "eslint-plugin-unused-imports": "^3.0.0", - "prettier": "^3.0.2", - "resolve-tspaths": "^0.8.15", - "turbo": "^1.10.13", - "typescript": "5.1.6" + "glob": "^10.3.10", + "prettier": "^3.0.3", + "recast": "^0.23.4", + "resolve-tspaths": "^0.8.16", + "tsup": "^7.2.0", + "turbo": "^1.10.14", + "typescript": "5.2.2" }, "pnpm": { "patchedDependencies": { - "typescript@5.1.6": "patches/typescript@5.1.6.patch" + "typescript@5.2.2": "patches/typescript@5.2.2.patch" } } } diff --git a/patches/typescript@5.1.6.patch b/patches/typescript@5.2.2.patch similarity index 65% rename from patches/typescript@5.1.6.patch rename to patches/typescript@5.2.2.patch index 0af94f800..e054837f8 100644 --- a/patches/typescript@5.1.6.patch +++ b/patches/typescript@5.2.2.patch @@ -1,8 +1,8 @@ diff --git a/lib/tsserver.js b/lib/tsserver.js -index 2329a12e68fc1788ad518eef084b69767f0e1a6c..9044051c1457ac05d13c9a16ddc7a8f9dc9d3640 100644 +index 382e1e2937fd02bed4c84b52f366049f2060ef1f..3ac8abaa9b30f0bcfb504220775ef8f3ee63eac3 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js -@@ -14987,7 +14987,7 @@ function isRestParameter(node) { +@@ -15053,7 +15053,7 @@ function isRestParameter(node) { // src/compiler/utilities.ts var resolvingEmptyArray = []; var externalHelpersModuleNameText = "tslib"; @@ -10,4 +10,4 @@ index 2329a12e68fc1788ad518eef084b69767f0e1a6c..9044051c1457ac05d13c9a16ddc7a8f9 +var defaultMaximumTruncationLength = 1e6; var noTruncationMaximumTruncationLength = 1e6; function getDeclarationOfKind(symbol, kind) { - const declarations = symbol.declarations; \ No newline at end of file + const declarations = symbol.declarations; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2eaae777..15af08a5e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,35 +5,38 @@ settings: excludeLinksFromLockfile: false patchedDependencies: - typescript@5.1.6: - hash: nqltnu2tftypeoe37zeioxuuuq - path: patches/typescript@5.1.6.patch + typescript@5.2.2: + hash: wmhs4olj6eveeldp6si4l46ssq + path: patches/typescript@5.2.2.patch importers: .: devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.12.1 + version: 0.12.1 '@trivago/prettier-plugin-sort-imports': specifier: ^4.2.0 - version: 4.2.0(prettier@3.0.2) + version: 4.2.0(prettier@3.0.3) '@typescript-eslint/eslint-plugin': - specifier: ^6.4.1 - version: 6.4.1(@typescript-eslint/parser@6.4.1)(eslint@8.47.0)(typescript@5.1.6) + specifier: ^6.7.3 + version: 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2) '@typescript-eslint/experimental-utils': specifier: ^5.62.0 - version: 5.62.0(eslint@8.47.0)(typescript@5.1.6) + version: 5.62.0(eslint@8.50.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: ^6.4.1 - version: 6.4.1(eslint@8.47.0)(typescript@5.1.6) + specifier: ^6.7.3 + version: 6.7.3(eslint@8.50.0)(typescript@5.2.2) bun-types: - specifier: ^0.7.3 - version: 0.7.3 + specifier: ^1.0.3 + version: 1.0.3 concurrently: specifier: ^8.2.1 version: 8.2.1 dprint: - specifier: ^0.40.2 - version: 0.40.2 + specifier: ^0.41.0 + version: 0.41.0 drizzle-kit: specifier: ^0.19.13 version: 0.19.13 @@ -42,37 +45,46 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: /drizzle-orm@0.27.2(bun-types@0.7.3) + version: /drizzle-orm@0.27.2(bun-types@1.0.3) eslint: - specifier: ^8.47.0 - version: 8.47.0 + specifier: ^8.50.0 + version: 8.50.0 eslint-plugin-drizzle: specifier: link:eslint/eslint-plugin-drizzle version: link:eslint/eslint-plugin-drizzle eslint-plugin-import: specifier: ^2.28.1 - version: 2.28.1(@typescript-eslint/parser@6.4.1)(eslint@8.47.0) + version: 2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.50.0) eslint-plugin-no-instanceof: specifier: ^1.0.1 version: 1.0.1 eslint-plugin-unicorn: specifier: ^48.0.1 - version: 48.0.1(eslint@8.47.0) + version: 48.0.1(eslint@8.50.0) eslint-plugin-unused-imports: specifier: ^3.0.0 - version: 3.0.0(@typescript-eslint/eslint-plugin@6.4.1)(eslint@8.47.0) + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.50.0) + glob: + specifier: ^10.3.10 + version: 10.3.10 prettier: - specifier: ^3.0.2 - version: 3.0.2 + specifier: ^3.0.3 + version: 3.0.3 + recast: + specifier: ^0.23.4 + version: 0.23.4 resolve-tspaths: - specifier: ^0.8.15 - version: 0.8.15(typescript@5.1.6) + specifier: ^0.8.16 + version: 0.8.16(typescript@5.2.2) + tsup: + specifier: ^7.2.0 + version: 7.2.0(typescript@5.2.2) turbo: - specifier: ^1.10.13 - version: 1.10.13 + specifier: ^1.10.14 + version: 1.10.14 typescript: - specifier: 5.1.6 - version: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + specifier: 5.2.2 + version: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) drizzle-orm: devDependencies: @@ -80,8 +92,8 @@ importers: specifier: ^3.344.0 version: 3.344.0 '@cloudflare/workers-types': - specifier: ^4.20230518.0 - version: 4.20230518.0 + specifier: ^4.20230904.0 + version: 4.20230904.0 '@libsql/client': specifier: ^0.1.6 version: 0.1.6 @@ -97,15 +109,6 @@ importers: '@planetscale/database': specifier: ^1.7.0 version: 1.7.0 - '@rollup/plugin-json': - specifier: ^6.0.0 - version: 6.0.0(rollup@3.27.2) - '@rollup/plugin-replace': - specifier: ^5.0.2 - version: 5.0.2(rollup@3.27.2) - '@rollup/plugin-typescript': - specifier: ^11.1.1 - version: 11.1.1(rollup@3.27.2)(tslib@2.5.2)(typescript@5.1.6) '@types/better-sqlite3': specifier: ^7.6.4 version: 7.6.4 @@ -130,9 +133,6 @@ importers: cpy: specifier: ^10.1.0 version: 10.1.0 - cpy-cli: - specifier: ^5.0.0 - version: 5.0.0 knex: specifier: ^2.4.2 version: 2.4.2(better-sqlite3@8.4.0)(mysql2@3.3.3)(pg@8.11.0)(sqlite3@5.1.6) @@ -148,18 +148,6 @@ importers: postgres: specifier: ^3.3.5 version: 3.3.5 - rimraf: - specifier: ^5.0.0 - version: 5.0.0 - rollup: - specifier: ^3.27.2 - version: 3.27.2 - rollup-plugin-dts: - specifier: ^5.3.1 - version: 5.3.1(rollup@3.27.2)(typescript@5.1.6) - rollup-plugin-typescript2: - specifier: ^0.35.0 - version: 0.35.0(rollup@3.27.2)(typescript@5.1.6) sql.js: specifier: ^1.8.0 version: 1.8.0 @@ -174,10 +162,10 @@ importers: version: 3.12.7 vite-tsconfig-paths: specifier: ^4.2.0 - version: 4.2.0(typescript@5.1.6) + version: 4.2.0(typescript@5.2.2)(vite@4.3.9) vitest: specifier: ^0.31.4 - version: 0.31.4 + version: 0.31.4(@vitest/ui@0.31.4) zod: specifier: ^3.20.2 version: 3.21.4 @@ -192,7 +180,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.5.2)(typescript@5.1.6) + version: 11.1.1(rollup@3.27.2)(typescript@5.2.2) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 @@ -228,7 +216,7 @@ importers: version: 0.4.1(rollup@3.27.2) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.1(rollup@3.27.2)(tslib@2.5.2)(typescript@5.1.6) + version: 11.1.1(rollup@3.27.2)(typescript@5.2.2) '@sinclair/typebox': specifier: ^0.29.6 version: 0.29.6 @@ -267,7 +255,7 @@ importers: version: 0.4.1(rollup@3.20.7) '@rollup/plugin-typescript': specifier: ^11.1.0 - version: 11.1.0(rollup@3.20.7)(typescript@5.1.6) + version: 11.1.0(rollup@3.20.7)(typescript@5.2.2) '@types/node': specifier: ^18.15.10 version: 18.15.10 @@ -424,7 +412,10 @@ importers: version: 4.3.9(@types/node@20.2.5) vite-tsconfig-paths: specifier: ^4.2.0 - version: 4.2.0(typescript@5.1.6)(vite@4.3.9) + version: 4.2.0(typescript@5.2.2)(vite@4.3.9) + zx: + specifier: ^7.2.2 + version: 7.2.2 packages: @@ -433,6 +424,39 @@ packages: engines: {node: '>=0.10.0'} dev: true + /@andrewbranch/untar.js@1.0.2: + resolution: {integrity: sha512-hL80MHK3b++pEp6K23+Nl5r5D1F19DRagp2ruCBIv4McyCiLKq67vUNvEQY1aGCAKNZ8GxV23n5MhOm7RwO8Pg==} + dev: true + + /@arethetypeswrong/cli@0.12.1: + resolution: {integrity: sha512-5nA91oqi8GPv9NkxgcjdpyKSMJ0WCcX8YYcxlZS5XBqY6cau0pMt5S0CXU3QGgl9qDryrok1QaM1xtUUhBKTAA==} + hasBin: true + dependencies: + '@arethetypeswrong/core': 0.12.1 + chalk: 4.1.2 + cli-table3: 0.6.3 + commander: 10.0.1 + marked: 5.1.2 + marked-terminal: 5.2.0(marked@5.1.2) + node-fetch: 2.6.11 + semver: 7.5.4 + transitivePeerDependencies: + - encoding + dev: true + + /@arethetypeswrong/core@0.12.1: + resolution: {integrity: sha512-1XCwz+IRSptRu1Y48D462vu3de8sLFrtXaXkgthIZ8+iRhEBIZtu+q7MwrfR3hWbYIgUsBj2WugtIgaPAdX9FA==} + dependencies: + '@andrewbranch/untar.js': 1.0.2 + fetch-ponyfill: 7.1.0 + fflate: 0.7.4 + semver: 7.5.4 + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) + validate-npm-package-name: 5.0.0 + transitivePeerDependencies: + - encoding + dev: true + /@aws-crypto/crc32@3.0.0: resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} dependencies: @@ -481,7 +505,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/client-cognito-identity@3.345.0: resolution: {integrity: sha512-KHpJ7jZq0OGXNIJ+K0U4DcVubroXq92TD7rQi16TU7q8AnjrCoMuJz32QJI+9FEFbjmTIJ/tts9rma0PqR30bw==} @@ -522,7 +546,7 @@ packages: '@aws-sdk/util-utf8': 3.310.0 '@smithy/protocol-http': 1.0.1 '@smithy/types': 1.0.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -651,7 +675,7 @@ packages: '@aws-sdk/util-utf8': 3.310.0 '@smithy/protocol-http': 1.0.1 '@smithy/types': 1.0.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: true @@ -692,7 +716,7 @@ packages: '@aws-sdk/util-utf8': 3.310.0 '@smithy/protocol-http': 1.0.1 '@smithy/types': 1.0.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -733,7 +757,7 @@ packages: '@aws-sdk/util-utf8': 3.310.0 '@smithy/protocol-http': 1.0.1 '@smithy/types': 1.0.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: true @@ -774,7 +798,7 @@ packages: '@aws-sdk/util-utf8': 3.310.0 '@smithy/protocol-http': 1.0.1 '@smithy/types': 1.0.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -864,7 +888,7 @@ packages: '@smithy/protocol-http': 1.0.1 '@smithy/types': 1.0.0 fast-xml-parser: 4.1.2 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -885,7 +909,7 @@ packages: '@aws-sdk/client-cognito-identity': 3.345.0 '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -896,7 +920,7 @@ packages: dependencies: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/credential-provider-imds@3.342.0: resolution: {integrity: sha512-ReaHwFLfcsEYjDFvi95OFd+IU8frPwuAygwL56aiMT7Voc0oy3EqB3MFs3gzFxdLsJ0vw9TZMRbaouepAEVCkA==} @@ -906,7 +930,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/types': 3.342.0 '@aws-sdk/url-parser': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/credential-provider-ini@3.344.0: resolution: {integrity: sha512-21awwuyIG0qXirgeDdq9EbyXzk/5pZswfBem8W2EAtwNPI8HO84S0EHyHybj/5l5QdPrKd/W3ohRkKY0uXSEcQ==} @@ -920,7 +944,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: true @@ -937,7 +961,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -973,7 +997,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -985,7 +1009,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/credential-provider-sso@3.344.0: resolution: {integrity: sha512-uS8iKMyjSQch/oKSDno6k3TZ0lr/kL6ZzvBRXcOsmprgW+ffP6ZcRVOPHIwUbjLyuZtDHRq4QcSBGXCnazar+Q==} @@ -996,7 +1020,7 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/token-providers': 3.344.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: true @@ -1010,7 +1034,7 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/token-providers': 3.345.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -1021,7 +1045,7 @@ packages: dependencies: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/credential-providers@3.345.0: resolution: {integrity: sha512-rTbc1asHXnVFFiTnQBn90N7rU3ICDaFpsivkzXlo5MEbRRkxswM5QUDm0iO1g4EnGEWTNwTb6T5kwPqg+8GfVw==} @@ -1051,7 +1075,7 @@ packages: '@aws-crypto/crc32': 3.0.0 '@aws-sdk/types': 3.342.0 '@aws-sdk/util-hex-encoding': 3.310.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/fetch-http-handler@3.342.0: resolution: {integrity: sha512-zsC23VUQMHEu4OKloLCVyWLG0ns6n+HKZ9euGLnNO3l0VSRne9qj/94yR+4jr/h04M7MhGf9mlczGfnZUFxs5w==} @@ -1081,7 +1105,7 @@ packages: resolution: {integrity: sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/middleware-content-length@3.342.0: resolution: {integrity: sha512-7LUMZqhihSAptGRFFQvuwt9nCLNzNPkGd1oU1RpVXw6YPQfKP9Ec5tgg4oUlv1t58IYQvdVj5ITKp4X2aUJVPg==} @@ -1142,7 +1166,7 @@ packages: dependencies: '@aws-sdk/middleware-signing': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/middleware-serde@3.342.0: resolution: {integrity: sha512-WRD+Cyu6+h1ymfPnAw4fI2q3zXjihJ55HFe1uRF8VPN4uBbJNfN3IqL38y/SMEdZ0gH9zNlRNxZLhR0q6SNZEQ==} @@ -1185,7 +1209,7 @@ packages: '@aws-sdk/protocol-http': 3.342.0 '@aws-sdk/types': 3.342.0 '@aws-sdk/util-endpoints': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 dev: false /@aws-sdk/node-config-provider@3.342.0: @@ -1212,14 +1236,14 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/protocol-http@3.342.0: resolution: {integrity: sha512-zuF2urcTJBZ1tltPdTBQzRasuGB7+4Yfs9i5l0F7lE0luK5Azy6G+2r3WWENUNxFTYuP94GrrqaOhVyj8XXLPQ==} engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/querystring-builder@3.342.0: resolution: {integrity: sha512-tb3FbtC36a7XBYeupdKm60LeM0etp73I6/7pDAkzAlw7zJdvY0aQIvj1c0U6nZlwZF8sSSxC7vlamR+wCspdMw==} @@ -1227,14 +1251,14 @@ packages: dependencies: '@aws-sdk/types': 3.342.0 '@aws-sdk/util-uri-escape': 3.310.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/querystring-parser@3.342.0: resolution: {integrity: sha512-6svvr/LZW1EPJaARnOpjf92FIiK25wuO7fRq05gLTcTRAfUMDvub+oDg3Ro9EjJERumrYQrYCem5Qi4X9w8K2g==} engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/service-error-classification@3.342.0: resolution: {integrity: sha512-MwHO5McbdAVKxfQj1yhleboAXqrzcGoi9ODS+bwCwRfe2lakGzBBhu8zaGDlKYOdv5rS+yAPP/5fZZUiuZY8Bw==} @@ -1245,7 +1269,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/signature-v4@3.342.0: resolution: {integrity: sha512-OWrGO2UOa1ENpy0kYd2shK4sklQygWUqvWLx9FotDbjIeUIEfAnqoPq/QqcXVrNyT/UvPi4iIrjHJEO8JCNRmA==} @@ -1258,7 +1282,7 @@ packages: '@aws-sdk/util-middleware': 3.342.0 '@aws-sdk/util-uri-escape': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/smithy-client@3.342.0: resolution: {integrity: sha512-HQ4JejjHU2X7OAZPwixFG+EyPSjmoZqll7EvWjPSKyclWrM320haWWz1trVzjG/AgPfeDLfRkH/JoMr13lECew==} @@ -1276,7 +1300,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: true @@ -1289,7 +1313,7 @@ packages: '@aws-sdk/property-provider': 3.342.0 '@aws-sdk/shared-ini-file-loader': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - aws-crt dev: false @@ -1330,13 +1354,13 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/is-array-buffer': 3.310.0 - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-config-provider@3.310.0: resolution: {integrity: sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-defaults-mode-browser@3.342.0: resolution: {integrity: sha512-N1ZRvCLbrt4Re9MKU3pLYR0iO+H7GU7RsXG4yAq6DtSWT9WCw6xhIUpeV2T5uxWKL92o3WHNiGjwcebq+N73Bg==} @@ -1369,19 +1393,19 @@ packages: resolution: {integrity: sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-locate-window@3.310.0: resolution: {integrity: sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-middleware@3.342.0: resolution: {integrity: sha512-P2LYyMP4JUFZBy9DcMvCDxWU34mlShCyrqBZ1ouuGW7UMgRb1PTEvpLAVndIWn9H+1KGDFjMqOWp1FZHr4YZOA==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-retry@3.342.0: resolution: {integrity: sha512-U1LXXtOMAQjU4H9gjYZng8auRponAH0t3vShHMKT8UQggT6Hwz1obdXUZgcLCtcjp/1aEK4MkDwk2JSjuUTaZw==} @@ -1394,7 +1418,7 @@ packages: resolution: {integrity: sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-user-agent-browser@3.342.0: resolution: {integrity: sha512-FWHiBi1xaebzmq3LJsizgd2LCix/bKHUTOjTeO6hEYny5DyrOl0liwIA0mqgvfgwIoMOF/l6FGg7kTfKtNgkEA==} @@ -1409,7 +1433,7 @@ packages: dependencies: '@aws-sdk/types': 3.342.0 bowser: 2.11.0 - tslib: 2.5.3 + tslib: 2.6.2 dev: false /@aws-sdk/util-user-agent-node@3.342.0: @@ -1437,13 +1461,13 @@ packages: dependencies: '@aws-sdk/node-config-provider': 3.342.0 '@aws-sdk/types': 3.342.0 - tslib: 2.5.3 + tslib: 2.6.2 dev: false /@aws-sdk/util-utf8-browser@3.259.0: resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} dependencies: - tslib: 2.5.3 + tslib: 2.6.2 /@aws-sdk/util-utf8@3.310.0: resolution: {integrity: sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==} @@ -1461,6 +1485,15 @@ packages: chalk: 2.4.2 dev: true + /@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + requiresBuild: true + dependencies: + '@babel/highlight': 7.22.20 + chalk: 2.4.2 + dev: true + /@babel/generator@7.17.7: resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} engines: {node: '>=6.9.0'} @@ -1502,6 +1535,12 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + requiresBuild: true + dev: true + /@babel/helper-validator-identifier@7.22.5: resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} engines: {node: '>=6.9.0'} @@ -1518,6 +1557,15 @@ packages: js-tokens: 4.0.0 dev: true + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + /@babel/parser@7.22.10: resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} engines: {node: '>=6.0.0'} @@ -1581,52 +1629,59 @@ packages: resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} dev: false - /@cloudflare/workers-types@4.20230518.0: - resolution: {integrity: sha512-A0w1V+5SUawGaaPRlhFhSC/SCDT9oQG8TMoWOKFLA4qbqagELqEAFD4KySBIkeVOvCBLT1DZSYBMCxbXddl0kw==} + /@cloudflare/workers-types@4.20230904.0: + resolution: {integrity: sha512-IX4oJCe14ctblSPZBlW64BVZ9nYLUo6sD2I5gu3hX0ywByYWm1OuoKm9Xb/Zpbj8Ph18Z7Ryii6u2/ocnncXdA==} dev: true - /@dprint/darwin-arm64@0.40.2: - resolution: {integrity: sha512-qharMFhxpNq9brgvHLbqzzAgVgPWSHLfzNLwWWhKcGOUUDUIilfAo3SlvOz6w4nQiIifLpYZOvZqK7Lpf9mSSw==} + /@colors/colors@1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@dprint/darwin-arm64@0.41.0: + resolution: {integrity: sha512-P9PtcQI0mrI4U6yyd+/iI664BHSqC9KTS6ogq0ptEdnLtlaWzf09D1nv6FBaHiG9m3conuBRlPsoUqt3j6PZ2w==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@dprint/darwin-x64@0.40.2: - resolution: {integrity: sha512-FPDdOTVr1JfqtLBTCvqlihWslTy3LBUoi3H1gaqIazCKMj2dB9voFWkBiMT+REMHDrlVsoSpFAfsliNr/y7HPA==} + /@dprint/darwin-x64@0.41.0: + resolution: {integrity: sha512-mSYnSoH0uyCkjgIWTny2DZAcaiRTe3kRWY5SeZECLGO37e+SdVg+ZjSzndhOvvEb9pv8EeBO1NJ9gHOSceT5Xw==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@dprint/linux-arm64-glibc@0.40.2: - resolution: {integrity: sha512-GmUWfKwEwXA+onvewX9hEJSMcd9V184+uRbEhI5tG28tBP9+IjQhrY7jCjxPvaZA+EvzNPnAy5D1wbJdlNLBNA==} + /@dprint/linux-arm64-glibc@0.41.0: + resolution: {integrity: sha512-U4xWzjjO/aAct8cSSMZFhg8l1jWy6VahXh8zWjGBufwX7t3xEcxMG9RyAp/ioYSY6wl4YXAmnUHywhC+wSjDHQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@dprint/linux-x64-glibc@0.40.2: - resolution: {integrity: sha512-vMHAHdsOY+2thieSWbIrIioDfPgvipwUgd0MZUWOqycTrXU6kLyi2B+5J/2Jc+QO3CiLIbumQd2FH/0vB1eWqA==} + /@dprint/linux-x64-glibc@0.41.0: + resolution: {integrity: sha512-wjv5l4mGns7E8i32E8FfAk45tw5O7v4NM17gtvhe6ggOiOD6quHowOH00pLfEakMLMF9y0J5ZO2hxJ/w06bXmQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@dprint/linux-x64-musl@0.40.2: - resolution: {integrity: sha512-nFSbDWd9ORyOhJ7a+RmE39WbuPoQ3OQutIgfAmfikiu/wENzEwxxv4QJ7aFnBaoZb0wuVEEpXShr8vY4p0exkg==} + /@dprint/linux-x64-musl@0.41.0: + resolution: {integrity: sha512-ZZOqiur9Xi/2uhz0Ce215VTSajAlSrduX/5k/hpIjI7Rgz22Vn77p5fmYxzWkTt/Li1zq5zboTvmGYx0QVNMrQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@dprint/win32-x64@0.40.2: - resolution: {integrity: sha512-qF4VCQzFTZYD61lbQqXLU/IwUTbLK22CancO+uVtXmZRoKU9GaVjcBhMUB7URxsa8rvxWHhHT6ldillI/aOWCg==} + /@dprint/win32-x64@0.41.0: + resolution: {integrity: sha512-mFx6x4Hn848/D4gPbDm7g1wlnOh2SGoVF9c9HMGCuOobUU2WIBztzV4L5qlFCB3gprlS0ru9BhlMpGhrp0CBYA==} cpu: [x64] os: [win32] requiresBuild: true @@ -2041,18 +2096,18 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.47.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.50.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.47.0 + eslint: 8.50.0 eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/regexpp@4.7.0: - resolution: {integrity: sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA==} + /@eslint-community/regexpp@4.9.0: + resolution: {integrity: sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true @@ -2063,7 +2118,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 9.6.1 - globals: 13.21.0 + globals: 13.22.0 ignore: 5.2.4 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -2073,8 +2128,8 @@ packages: - supports-color dev: true - /@eslint/js@8.47.0: - resolution: {integrity: sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==} + /@eslint/js@8.50.0: + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -2083,8 +2138,8 @@ packages: requiresBuild: true optional: true - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} + /@humanwhocodes/config-array@0.11.11: + resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -2107,6 +2162,18 @@ packages: resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} dev: false + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} @@ -2322,33 +2389,6 @@ packages: /@polka/url@1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} - /@rollup/plugin-json@6.0.0(rollup@3.27.2): - resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.27.2) - rollup: 3.27.2 - dev: true - - /@rollup/plugin-replace@5.0.2(rollup@3.27.2): - resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.27.2) - magic-string: 0.27.0 - rollup: 3.27.2 - dev: true - /@rollup/plugin-terser@0.4.1(rollup@3.20.7): resolution: {integrity: sha512-aKS32sw5a7hy+fEXVy+5T95aDIwjpGHCTv833HXVtyKMDoVS7pBr5K3L9hEQoNqbJFjfANPrNpIXlTQ7is00eA==} engines: {node: '>=14.0.0'} @@ -2379,7 +2419,7 @@ packages: terser: 5.17.1 dev: true - /@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(typescript@5.1.6): + /@rollup/plugin-typescript@11.1.0(rollup@3.20.7)(typescript@5.2.2): resolution: {integrity: sha512-86flrfE+bSHB69znnTV6kVjkncs2LBMhcTCyxWgRxLyfXfQrxg4UwlAqENnjrrxnSNS/XKCDJCl8EkdFJVHOxw==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2395,10 +2435,10 @@ packages: '@rollup/pluginutils': 5.0.2(rollup@3.20.7) resolve: 1.22.1 rollup: 3.20.7 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) dev: true - /@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(tslib@2.5.2)(typescript@5.1.6): + /@rollup/plugin-typescript@11.1.1(rollup@3.27.2)(typescript@5.2.2): resolution: {integrity: sha512-Ioir+x5Bejv72Lx2Zbz3/qGg7tvGbxQZALCLoJaGrkNXak/19+vKgKYJYM3i/fJxvsb23I9FuFQ8CUBEfsmBRg==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2414,16 +2454,7 @@ packages: '@rollup/pluginutils': 5.0.2(rollup@3.27.2) resolve: 1.22.2 rollup: 3.27.2 - tslib: 2.5.2 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) - dev: true - - /@rollup/pluginutils@4.2.1: - resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} - engines: {node: '>= 8.0.0'} - dependencies: - estree-walker: 2.0.2 - picomatch: 2.3.1 + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) dev: true /@rollup/pluginutils@5.0.2(rollup@3.20.7): @@ -2479,7 +2510,7 @@ packages: requiresBuild: true optional: true - /@trivago/prettier-plugin-sort-imports@4.2.0(prettier@3.0.2): + /@trivago/prettier-plugin-sort-imports@4.2.0(prettier@3.0.3): resolution: {integrity: sha512-YBepjbt+ZNBVmN3ev1amQH3lWCmHyt5qTbLCp/syXJRu/Kw2koXh44qayB1gMRxcL/gV8egmjN5xWSrYyfUtyw==} peerDependencies: '@vue/compiler-sfc': 3.x @@ -2494,7 +2525,7 @@ packages: '@babel/types': 7.17.0 javascript-natural-sort: 0.7.1 lodash: 4.17.21 - prettier: 3.0.2 + prettier: 3.0.3 transitivePeerDependencies: - supports-color dev: true @@ -2577,13 +2608,17 @@ packages: resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==} dependencies: '@types/jsonfile': 6.1.1 - '@types/node': 20.2.5 + '@types/node': 20.8.7 dev: true /@types/json-schema@7.0.12: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true + /@types/json-schema@7.0.13: + resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==} + dev: true + /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true @@ -2591,7 +2626,7 @@ packages: /@types/jsonfile@6.1.1: resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} dependencies: - '@types/node': 20.2.5 + '@types/node': 20.8.7 dev: true /@types/mime@3.0.1: @@ -2605,7 +2640,7 @@ packages: /@types/node-fetch@2.6.4: resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==} dependencies: - '@types/node': 20.2.5 + '@types/node': 20.8.7 form-data: 3.0.1 /@types/node@18.15.10: @@ -2619,6 +2654,11 @@ packages: /@types/node@20.2.5: resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==} + /@types/node@20.8.7: + resolution: {integrity: sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==} + dependencies: + undici-types: 5.25.3 + /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true @@ -2654,6 +2694,10 @@ packages: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true + /@types/semver@7.5.3: + resolution: {integrity: sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==} + dev: true + /@types/serve-static@1.15.1: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: @@ -2685,10 +2729,10 @@ packages: /@types/ws@8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 20.2.5 + '@types/node': 20.8.7 - /@typescript-eslint/eslint-plugin@6.4.1(@typescript-eslint/parser@6.4.1)(eslint@8.47.0)(typescript@5.1.6): - resolution: {integrity: sha512-3F5PtBzUW0dYlq77Lcqo13fv+58KDwUib3BddilE8ajPJT+faGgxmI9Sw+I8ZS22BYwoir9ZhNXcLi+S+I2bkw==} + /@typescript-eslint/eslint-plugin@6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -2698,39 +2742,39 @@ packages: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.7.0 - '@typescript-eslint/parser': 6.4.1(eslint@8.47.0)(typescript@5.1.6) - '@typescript-eslint/scope-manager': 6.4.1 - '@typescript-eslint/type-utils': 6.4.1(eslint@8.47.0)(typescript@5.1.6) - '@typescript-eslint/utils': 6.4.1(eslint@8.47.0)(typescript@5.1.6) - '@typescript-eslint/visitor-keys': 6.4.1 + '@eslint-community/regexpp': 4.9.0 + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/type-utils': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 - eslint: 8.47.0 + eslint: 8.50.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.2(typescript@5.1.6) - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils@5.62.0(eslint@8.47.0)(typescript@5.1.6): + /@typescript-eslint/experimental-utils@5.62.0(eslint@8.50.0)(typescript@5.2.2): resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.47.0)(typescript@5.1.6) - eslint: 8.47.0 + '@typescript-eslint/utils': 5.62.0(eslint@8.50.0)(typescript@5.2.2) + eslint: 8.50.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser@6.4.1(eslint@8.47.0)(typescript@5.1.6): - resolution: {integrity: sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg==} + /@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2739,13 +2783,13 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.4.1 - '@typescript-eslint/types': 6.4.1 - '@typescript-eslint/typescript-estree': 6.4.1(typescript@5.1.6) - '@typescript-eslint/visitor-keys': 6.4.1 + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 - eslint: 8.47.0 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + eslint: 8.50.0 + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) transitivePeerDependencies: - supports-color dev: true @@ -2758,16 +2802,16 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@6.4.1: - resolution: {integrity: sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A==} + /@typescript-eslint/scope-manager@6.7.3: + resolution: {integrity: sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.4.1 - '@typescript-eslint/visitor-keys': 6.4.1 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 dev: true - /@typescript-eslint/type-utils@6.4.1(eslint@8.47.0)(typescript@5.1.6): - resolution: {integrity: sha512-7ON8M8NXh73SGZ5XvIqWHjgX2f+vvaOarNliGhjrJnv1vdjG0LVIz+ToYfPirOoBi56jxAKLfsLm40+RvxVVXA==} + /@typescript-eslint/type-utils@6.7.3(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2776,12 +2820,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.4.1(typescript@5.1.6) - '@typescript-eslint/utils': 6.4.1(eslint@8.47.0)(typescript@5.1.6) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) + '@typescript-eslint/utils': 6.7.3(eslint@8.50.0)(typescript@5.2.2) debug: 4.3.4 - eslint: 8.47.0 - ts-api-utils: 1.0.2(typescript@5.1.6) - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + eslint: 8.50.0 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) transitivePeerDependencies: - supports-color dev: true @@ -2791,12 +2835,12 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types@6.4.1: - resolution: {integrity: sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg==} + /@typescript-eslint/types@6.7.3: + resolution: {integrity: sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==} engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@5.62.0(typescript@5.1.6): + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.2.2): resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2811,14 +2855,14 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.4.1(typescript@5.1.6): - resolution: {integrity: sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg==} + /@typescript-eslint/typescript-estree@6.7.3(typescript@5.2.2): + resolution: {integrity: sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -2826,31 +2870,31 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.4.1 - '@typescript-eslint/visitor-keys': 6.4.1 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.2(typescript@5.1.6) - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.47.0)(typescript@5.1.6): + /@typescript-eslint/utils@5.62.0(eslint@8.50.0)(typescript@5.2.2): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) - eslint: 8.47.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2) + eslint: 8.50.0 eslint-scope: 5.1.1 semver: 7.5.4 transitivePeerDependencies: @@ -2858,19 +2902,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.4.1(eslint@8.47.0)(typescript@5.1.6): - resolution: {integrity: sha512-F/6r2RieNeorU0zhqZNv89s9bDZSovv3bZQpUNOmmQK1L80/cV4KEu95YUJWi75u5PhboFoKUJBnZ4FQcoqhDw==} + /@typescript-eslint/utils@6.7.3(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0) - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.4.1 - '@typescript-eslint/types': 6.4.1 - '@typescript-eslint/typescript-estree': 6.4.1(typescript@5.1.6) - eslint: 8.47.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.13 + '@types/semver': 7.5.3 + '@typescript-eslint/scope-manager': 6.7.3 + '@typescript-eslint/types': 6.7.3 + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) + eslint: 8.50.0 semver: 7.5.4 transitivePeerDependencies: - supports-color @@ -2885,11 +2929,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.4.1: - resolution: {integrity: sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ==} + /@typescript-eslint/visitor-keys@6.7.3: + resolution: {integrity: sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.4.1 + '@typescript-eslint/types': 6.7.3 eslint-visitor-keys: 3.4.3 dev: true @@ -3050,6 +3094,13 @@ packages: engines: {node: '>=6'} dev: true + /ansi-escapes@6.2.0: + resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} + engines: {node: '>=14.16'} + dependencies: + type-fest: 3.13.1 + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3082,6 +3133,14 @@ packages: engines: {node: '>=12'} dev: true + /ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + dev: true + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -3210,9 +3269,26 @@ packages: safer-buffer: 2.1.2 dev: false + /assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + dependencies: + call-bind: 1.0.2 + is-nan: 1.3.2 + object-is: 1.1.5 + object.assign: 4.1.4 + util: 0.12.5 + dev: true + /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + /ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.2 + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -3464,15 +3540,24 @@ packages: /builtins@5.0.1: resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} dependencies: - semver: 7.5.1 - dev: false + semver: 7.5.4 /bun-types@0.6.6: resolution: {integrity: sha512-/LL3zPv7d+ZvHSD6TIhVB7l8h1rrMvuGlwILTGHrJJeAaHKq+7RgIV6N8A8kzhkYMFuTq9o2P/2o8gUL7RHtzg==} dev: true - /bun-types@0.7.3: - resolution: {integrity: sha512-kssLD5mDLoawmLZFgQRRq0Wy+dca/os6TZ0MHWyFVoVAEwSrpAxmNCZ1K1GUelfhlDaL2FikRxeF9GkATdzXZg==} + /bun-types@1.0.3: + resolution: {integrity: sha512-XlyKVdYCHa7K5PHYGcwOVOrGE/bMnLS51y7zFA3ZAAXyiQ6dTaNXNCWTTufgII/6ruN770uhAXphQmzvU/r2fQ==} + dev: true + + /bundle-require@4.0.2(esbuild@0.18.20): + resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.18.20 + load-tsconfig: 0.2.5 dev: true /busboy@1.6.0: @@ -3539,6 +3624,14 @@ packages: engines: {node: '>=14.16'} dev: true + /cardinal@2.1.1: + resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} + hasBin: true + dependencies: + ansicolors: 0.3.2 + redeyed: 2.1.1 + dev: true + /cbor@8.1.0: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} @@ -3659,6 +3752,15 @@ packages: timers-ext: 0.1.7 dev: true + /cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + dev: true + /cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3725,6 +3827,11 @@ packages: dependencies: delayed-stream: 1.0.0 + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + dev: true + /commander@11.0.0: resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} engines: {node: '>=16'} @@ -3734,6 +3841,11 @@ packages: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + /commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -3743,10 +3855,6 @@ packages: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} dev: true - /commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - dev: true - /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} requiresBuild: true @@ -3824,19 +3932,10 @@ packages: requiresBuild: true dependencies: buildcheck: 0.0.6 - nan: 2.17.0 + nan: 2.18.0 dev: false optional: true - /cpy-cli@5.0.0: - resolution: {integrity: sha512-fb+DZYbL9KHc0BC4NYqGRrDIJZPXUmjjtqdw4XRRg8iV8dIfghUX/WiL+q4/B/KFTy3sK6jsbUhBaz0/Hxg7IQ==} - engines: {node: '>=16'} - hasBin: true - dependencies: - cpy: 10.1.0 - meow: 12.1.0 - dev: true - /cpy@10.1.0: resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} engines: {node: '>=16'} @@ -4061,17 +4160,17 @@ packages: engines: {node: '>=12'} dev: false - /dprint@0.40.2: - resolution: {integrity: sha512-3LdyUV0itEW59UPtsRA2StOWOu8FyOW+BgvJpH/tACRHKi0z5gaQnvSxdS3mbG7dgtEhdRnGg6JoiQyGib6NTg==} + /dprint@0.41.0: + resolution: {integrity: sha512-9Ctv6EnwOy5Ai566DczI/QhAC6y+AhWDA2gFU8Zz4xezUy1BevHaIYhfdLWZQxh4Qf4H28lRu1Lq+hhIm1US9w==} hasBin: true requiresBuild: true optionalDependencies: - '@dprint/darwin-arm64': 0.40.2 - '@dprint/darwin-x64': 0.40.2 - '@dprint/linux-arm64-glibc': 0.40.2 - '@dprint/linux-x64-glibc': 0.40.2 - '@dprint/linux-x64-musl': 0.40.2 - '@dprint/win32-x64': 0.40.2 + '@dprint/darwin-arm64': 0.41.0 + '@dprint/darwin-x64': 0.41.0 + '@dprint/linux-arm64-glibc': 0.41.0 + '@dprint/linux-x64-glibc': 0.41.0 + '@dprint/linux-x64-musl': 0.41.0 + '@dprint/win32-x64': 0.41.0 dev: true /dreamopt@0.8.0: @@ -4101,7 +4200,7 @@ packages: - supports-color dev: true - /drizzle-orm@0.27.2(bun-types@0.7.3): + /drizzle-orm@0.27.2(bun-types@1.0.3): resolution: {integrity: sha512-ZvBvceff+JlgP7FxHKe0zOU9CkZ4RcOtibumIrqfYzDGuOeF0YUY0F9iMqYpRM7pxnLRfC+oO7rWOUH3T5oFQA==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' @@ -4163,7 +4262,7 @@ packages: sqlite3: optional: true dependencies: - bun-types: 0.7.3 + bun-types: 1.0.3 dev: true /duplexer@0.1.2: @@ -4185,6 +4284,7 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + requiresBuild: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -4645,7 +4745,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-node@0.3.9)(eslint@8.47.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -4666,15 +4766,15 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.4.1(eslint@8.47.0)(typescript@5.1.6) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) debug: 3.2.7 - eslint: 8.47.0 + eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.4.1)(eslint@8.47.0): + /eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.3)(eslint@8.50.0): resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} engines: {node: '>=4'} peerDependencies: @@ -4684,16 +4784,16 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.4.1(eslint@8.47.0)(typescript@5.1.6) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) array-includes: 3.1.6 array.prototype.findlastindex: 1.2.2 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.47.0 + eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-node@0.3.9)(eslint@8.47.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3)(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -4713,17 +4813,17 @@ packages: resolution: {integrity: sha512-zlqQ7EsfzbRO68uI+p8FIE7zYB4njs+nNbkNjSb5QmLi2et67zQLqSeaao5U9SpnlZTTJC87nS2oyHo2ACtajw==} dev: true - /eslint-plugin-unicorn@48.0.1(eslint@8.47.0): + /eslint-plugin-unicorn@48.0.1(eslint@8.50.0): resolution: {integrity: sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==} engines: {node: '>=16'} peerDependencies: eslint: '>=8.44.0' dependencies: '@babel/helper-validator-identifier': 7.22.5 - '@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) ci-info: 3.8.0 clean-regexp: 1.0.0 - eslint: 8.47.0 + eslint: 8.50.0 esquery: 1.5.0 indent-string: 4.0.0 is-builtin-module: 3.2.1 @@ -4737,7 +4837,7 @@ packages: strip-indent: 3.0.0 dev: true - /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.4.1)(eslint@8.47.0): + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.50.0): resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -4747,8 +4847,8 @@ packages: '@typescript-eslint/eslint-plugin': optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.4.1(@typescript-eslint/parser@6.4.1)(eslint@8.47.0)(typescript@5.1.6) - eslint: 8.47.0 + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2) + eslint: 8.50.0 eslint-rule-composer: 0.3.0 dev: true @@ -4778,16 +4878,16 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.47.0: - resolution: {integrity: sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==} + /eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0) - '@eslint-community/regexpp': 4.7.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.9.0 '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.47.0 - '@humanwhocodes/config-array': 0.11.10 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.11 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 @@ -4805,7 +4905,7 @@ packages: file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.21.0 + globals: 13.22.0 graphemer: 1.4.0 ignore: 5.2.4 imurmurhash: 0.1.4 @@ -4900,6 +5000,21 @@ packages: through: 2.3.8 dev: true + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + /execa@6.1.0: resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5024,6 +5139,14 @@ packages: web-streams-polyfill: 3.2.1 dev: true + /fetch-ponyfill@7.1.0: + resolution: {integrity: sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==} + dependencies: + node-fetch: 2.6.11 + transitivePeerDependencies: + - encoding + dev: true + /fflate@0.7.4: resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} @@ -5039,7 +5162,7 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flat-cache: 3.0.4 + flat-cache: 3.1.0 dev: true /file-uri-to-path@1.0.0: @@ -5066,15 +5189,6 @@ packages: - supports-color dev: false - /find-cache-dir@3.3.2: - resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} - engines: {node: '>=8'} - dependencies: - commondir: 1.0.1 - make-dir: 3.1.0 - pkg-dir: 4.2.0 - dev: true - /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5099,17 +5213,22 @@ packages: path-exists: 5.0.0 dev: true - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} + /flat-cache@3.1.0: + resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} + engines: {node: '>=12.0.0'} dependencies: - flatted: 3.2.7 + flatted: 3.2.9 + keyv: 4.5.3 rimraf: 3.0.2 dev: true /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + /follow-redirects@1.15.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} @@ -5175,15 +5294,6 @@ packages: /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - /fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.0 - dev: true - /fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} @@ -5302,7 +5412,6 @@ packages: /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - dev: false /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} @@ -5348,6 +5457,29 @@ packages: path-scurry: 1.7.0 dev: true + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.1 + minipass: 5.0.0 + path-scurry: 1.10.1 + dev: true + + /glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} requiresBuild: true @@ -5375,8 +5507,8 @@ packages: engines: {node: '>=4'} dev: true - /globals@13.21.0: - resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==} + /globals@13.22.0: + resolution: {integrity: sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -5417,7 +5549,7 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: dir-glob: 3.0.1 - fast-glob: 3.2.12 + fast-glob: 3.3.1 ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 @@ -5537,6 +5669,11 @@ packages: transitivePeerDependencies: - supports-color + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + /human-signals@3.0.1: resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} engines: {node: '>=12.20.0'} @@ -5645,6 +5782,14 @@ packages: engines: {node: '>=8'} dev: true + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -5726,12 +5871,20 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + requiresBuild: true /is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} dev: true + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -5743,6 +5896,14 @@ packages: requiresBuild: true optional: true + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + dev: true + /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -5804,6 +5965,11 @@ packages: call-bind: 1.0.2 dev: true + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5857,10 +6023,24 @@ packages: '@pkgjs/parseargs': 0.11.0 dev: true + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + /javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} dev: true + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: true + /js-base64@3.7.5: resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==} @@ -5905,6 +6085,10 @@ packages: hasBin: true dev: true + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + /json-diff@0.9.0: resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==} hasBin: true @@ -5963,6 +6147,12 @@ packages: engines: {node: '>=12.20'} dev: true + /keyv@4.5.3: + resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} + dependencies: + json-buffer: 3.0.1 + dev: true + /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -6031,6 +6221,11 @@ packages: type-check: 0.4.0 dev: true + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -6040,6 +6235,11 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} @@ -6069,6 +6269,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + dev: true + /lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} dev: true @@ -6110,31 +6314,17 @@ packages: es5-ext: 0.10.62 dev: true - /magic-string@0.27.0: - resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /magic-string@0.30.0: resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - /magic-string@0.30.2: - resolution: {integrity: sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: - semver: 6.3.0 + semver: 6.3.1 /make-fetch-happen@9.1.0: resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} @@ -6173,6 +6363,27 @@ packages: resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} dev: true + /marked-terminal@5.2.0(marked@5.1.2): + resolution: {integrity: sha512-Piv6yNwAQXGFjZSaiNljyNFw7jKDdGrw70FSbtxEyldLsyeuV5ZHm/1wW++kWbrOF1VPnUgYOhB2oLL0ZpnekA==} + engines: {node: '>=14.13.1 || >=16.0.0'} + peerDependencies: + marked: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + dependencies: + ansi-escapes: 6.2.0 + cardinal: 2.1.1 + chalk: 5.3.0 + cli-table3: 0.6.3 + marked: 5.1.2 + node-emoji: 1.11.0 + supports-hyperlinks: 2.3.0 + dev: true + + /marked@5.1.2: + resolution: {integrity: sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg==} + engines: {node: '>= 16'} + hasBin: true + dev: true + /matcher@5.0.0: resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6212,18 +6423,12 @@ packages: timers-ext: 0.1.7 dev: true - /meow@12.1.0: - resolution: {integrity: sha512-SvSqzS5ktjGoySdCwxQI16iO/ID1LtxM03QvJ4FF2H5cCtXLN7YbfKBCL9btqXSSuJ5TNG4UH6wvWtXZuvgvrw==} - engines: {node: '>=16.10'} - dev: true - /merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} dev: false /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: false /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -6257,6 +6462,11 @@ packages: hasBin: true dev: false + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -6415,14 +6625,22 @@ packages: seq-queue: 0.0.5 sqlstring: 2.3.3 + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + /named-placeholders@1.1.3: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} dependencies: lru-cache: 7.18.3 - /nan@2.17.0: - resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} + /nan@2.18.0: + resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} requiresBuild: true dev: false optional: true @@ -6456,7 +6674,7 @@ packages: resolution: {integrity: sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==} engines: {node: '>=10'} dependencies: - semver: 7.5.1 + semver: 7.5.4 /node-addon-api@4.3.0: resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} @@ -6466,6 +6684,12 @@ packages: engines: {node: '>=10.5.0'} dev: true + /node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + dependencies: + lodash: 4.17.21 + dev: true + /node-fetch@2.6.11: resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==} engines: {node: 4.x || >=6.0.0} @@ -6548,6 +6772,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + /npm-run-path@5.1.0: resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6579,7 +6810,7 @@ packages: dependencies: execa: 6.1.0 parse-package-name: 1.0.0 - semver: 7.5.1 + semver: 7.5.4 validate-npm-package-name: 4.0.0 dev: false @@ -6590,6 +6821,14 @@ packages: /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + /object-is@1.1.5: + resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + dev: true + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -6647,6 +6886,13 @@ packages: dependencies: wrappy: 1.0.2 + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -6769,7 +7015,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.22.10 + '@babel/code-frame': 7.22.13 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -6817,6 +7063,14 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 9.1.2 + minipass: 5.0.0 + dev: true + /path-scurry@1.7.0: resolution: {integrity: sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==} engines: {node: '>=16 || 14 >=14.17'} @@ -6929,6 +7183,11 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + /pkg-conf@4.0.0: resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6937,13 +7196,6 @@ packages: load-json-file: 7.0.1 dev: true - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - dev: true - /pkg-types@1.0.3: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} dependencies: @@ -6963,6 +7215,22 @@ packages: engines: {node: '>=4'} dev: true + /postcss-load-config@4.0.1: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + yaml: 2.3.1 + dev: true + /postcss@8.4.24: resolution: {integrity: sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==} engines: {node: ^10 || ^12 || >=14} @@ -7036,8 +7304,8 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier@3.0.2: - resolution: {integrity: sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==} + /prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} engines: {node: '>=14'} hasBin: true dev: true @@ -7184,6 +7452,17 @@ packages: picomatch: 2.3.1 dev: true + /recast@0.23.4: + resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==} + engines: {node: '>= 4'} + dependencies: + assert: 2.1.0 + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tslib: 2.6.2 + dev: true + /rechoir@0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} @@ -7191,6 +7470,12 @@ packages: resolve: 1.22.2 dev: true + /redeyed@2.1.1: + resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==} + dependencies: + esprima: 4.0.1 + dev: true + /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} dev: true @@ -7237,8 +7522,8 @@ packages: engines: {node: '>=8'} dev: true - /resolve-tspaths@0.8.15(typescript@5.1.6): - resolution: {integrity: sha512-uqxasvZ7WGMfaozpwSLo5nEV/TBnbwMSV7df7hLfwtmGNQlqO1ljcTJ5s8EX9MidKlMQLnczCwur9gFtbOc6pA==} + /resolve-tspaths@0.8.16(typescript@5.2.2): + resolution: {integrity: sha512-5c90plgcKFcCk66Ve1vFh6tm0fLKmSz6vaW4CezP6i69Q8fgWX3YGPYmKPEughem+nPHT1358P+rXrhw5pibwg==} hasBin: true peerDependencies: typescript: '>=3.0.3' @@ -7246,7 +7531,7 @@ packages: ansi-colors: 4.1.3 commander: 11.0.0 fast-glob: 3.3.1 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) dev: true /resolve@1.22.1: @@ -7300,35 +7585,6 @@ packages: glob: 10.2.2 dev: true - /rollup-plugin-dts@5.3.1(rollup@3.27.2)(typescript@5.1.6): - resolution: {integrity: sha512-gusMi+Z4gY/JaEQeXnB0RUdU82h1kF0WYzCWgVmV4p3hWXqelaKuCvcJawfeg+EKn2T1Ie+YWF2OiN1/L8bTVg==} - engines: {node: '>=v14.21.3'} - peerDependencies: - rollup: ^3.0 - typescript: ^4.1 || ^5.0 - dependencies: - magic-string: 0.30.2 - rollup: 3.27.2 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) - optionalDependencies: - '@babel/code-frame': 7.22.10 - dev: true - - /rollup-plugin-typescript2@0.35.0(rollup@3.27.2)(typescript@5.1.6): - resolution: {integrity: sha512-szcIO9hPUx3PhQl91u4pfNAH2EKbtrXaES+m163xQVE5O1CC0ea6YZV/5woiDDW3CR9jF2CszPrKN+AFiND0bg==} - peerDependencies: - rollup: '>=1.26.3' - typescript: '>=2.4.0' - dependencies: - '@rollup/pluginutils': 4.2.1 - find-cache-dir: 3.3.2 - fs-extra: 10.1.0 - rollup: 3.27.2 - semver: 7.5.1 - tslib: 2.5.3 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) - dev: true - /rollup@3.20.7: resolution: {integrity: sha512-P7E2zezKSLhWnTz46XxjSmInrbOCiul1yf+kJccMxT56vxjHwCbDfoLbiqFgu+WQoo9ij2PkraYaBstgB2prBA==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -7391,14 +7647,9 @@ packages: hasBin: true dev: true - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - dev: true /semver@7.5.1: resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==} @@ -7596,6 +7847,13 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + /source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + dependencies: + whatwg-url: 7.1.0 + dev: true + /spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} dev: true @@ -7679,7 +7937,7 @@ packages: bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.9 - nan: 2.17.0 + nan: 2.18.0 dev: false /ssri@8.0.1: @@ -7791,6 +8049,11 @@ packages: engines: {node: '>=4'} dev: true + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -7820,6 +8083,20 @@ packages: /strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + /sucrase@3.34.0: + resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + /supertap@3.0.1: resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -7851,6 +8128,14 @@ packages: has-flag: 4.0.0 dev: true + /supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: true + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -7919,6 +8204,19 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + /through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} dependencies: @@ -7979,6 +8277,12 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + /tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + dependencies: + punycode: 2.3.0 + dev: true + /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -7989,16 +8293,20 @@ packages: engines: {node: '>=0.6'} dev: false - /ts-api-utils@1.0.2(typescript@5.1.6): - resolution: {integrity: sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==} + /ts-api-utils@1.0.3(typescript@5.2.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true - /tsconfck@2.1.1(typescript@5.1.6): + /tsconfck@2.1.1(typescript@5.2.2): resolution: {integrity: sha512-ZPCkJBKASZBmBUNqGHmRhdhM8pJYDdOXp4nRgj/O0JwUwsMq50lCDRQP/M5GBNAA0elPrq4gAeu4dkaVCuKWww==} engines: {node: ^14.13.1 || ^16 || >=18} hasBin: true @@ -8008,7 +8316,7 @@ packages: typescript: optional: true dependencies: - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) dev: true /tsconfig-paths@3.14.2: @@ -8032,16 +8340,51 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + /tsup@7.2.0(typescript@5.2.2): + resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} + engines: {node: '>=16.14'} + hasBin: true + peerDependencies: + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.1.0' + peerDependenciesMeta: + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.2(esbuild@0.18.20) + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.18.20 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 4.0.1 + resolve-from: 5.0.0 + rollup: 3.27.2 + source-map: 0.8.0-beta.0 + sucrase: 3.34.0 + tree-kill: 1.2.2 + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) + transitivePeerDependencies: + - supports-color + - ts-node dev: true - /tsutils@3.21.0(typescript@5.1.6): + /tsutils@3.21.0(typescript@5.2.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq) + typescript: 5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq) dev: true /tsx@3.12.6: @@ -8071,64 +8414,64 @@ packages: dependencies: safe-buffer: 5.2.1 - /turbo-darwin-64@1.10.13: - resolution: {integrity: sha512-vmngGfa2dlYvX7UFVncsNDMuT4X2KPyPJ2Jj+xvf5nvQnZR/3IeDEGleGVuMi/hRzdinoxwXqgk9flEmAYp0Xw==} + /turbo-darwin-64@1.10.14: + resolution: {integrity: sha512-I8RtFk1b9UILAExPdG/XRgGQz95nmXPE7OiGb6ytjtNIR5/UZBS/xVX/7HYpCdmfriKdVwBKhalCoV4oDvAGEg==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.10.13: - resolution: {integrity: sha512-eMoJC+k7gIS4i2qL6rKmrIQGP6Wr9nN4odzzgHFngLTMimok2cGLK3qbJs5O5F/XAtEeRAmuxeRnzQwTl/iuAw==} + /turbo-darwin-arm64@1.10.14: + resolution: {integrity: sha512-KAdUWryJi/XX7OD0alOuOa0aJ5TLyd4DNIYkHPHYcM6/d7YAovYvxRNwmx9iv6Vx6IkzTnLeTiUB8zy69QkG9Q==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.10.13: - resolution: {integrity: sha512-0CyYmnKTs6kcx7+JRH3nPEqCnzWduM0hj8GP/aodhaIkLNSAGAa+RiYZz6C7IXN+xUVh5rrWTnU2f1SkIy7Gdg==} + /turbo-linux-64@1.10.14: + resolution: {integrity: sha512-BOBzoREC2u4Vgpap/WDxM6wETVqVMRcM8OZw4hWzqCj2bqbQ6L0wxs1LCLWVrghQf93JBQtIGAdFFLyCSBXjWQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.10.13: - resolution: {integrity: sha512-0iBKviSGQQlh2OjZgBsGjkPXoxvRIxrrLLbLObwJo3sOjIH0loGmVIimGS5E323soMfi/o+sidjk2wU1kFfD7Q==} + /turbo-linux-arm64@1.10.14: + resolution: {integrity: sha512-D8T6XxoTdN5D4V5qE2VZG+/lbZX/89BkAEHzXcsSUTRjrwfMepT3d2z8aT6hxv4yu8EDdooZq/2Bn/vjMI32xw==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.10.13: - resolution: {integrity: sha512-S5XySRfW2AmnTeY1IT+Jdr6Goq7mxWganVFfrmqU+qqq3Om/nr0GkcUX+KTIo9mPrN0D3p5QViBRzulwB5iuUQ==} + /turbo-windows-64@1.10.14: + resolution: {integrity: sha512-zKNS3c1w4i6432N0cexZ20r/aIhV62g69opUn82FLVs/zk3Ie0GVkSB6h0rqIvMalCp7enIR87LkPSDGz9K4UA==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.10.13: - resolution: {integrity: sha512-nKol6+CyiExJIuoIc3exUQPIBjP9nIq5SkMJgJuxsot2hkgGrafAg/izVDRDrRduQcXj2s8LdtxJHvvnbI8hEQ==} + /turbo-windows-arm64@1.10.14: + resolution: {integrity: sha512-rkBwrTPTxNSOUF7of8eVvvM+BkfkhA2OvpHM94if8tVsU+khrjglilp8MTVPHlyS9byfemPAmFN90oRIPB05BA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.10.13: - resolution: {integrity: sha512-vOF5IPytgQPIsgGtT0n2uGZizR2N3kKuPIn4b5p5DdeLoI0BV7uNiydT7eSzdkPRpdXNnO8UwS658VaI4+YSzQ==} + /turbo@1.10.14: + resolution: {integrity: sha512-hr9wDNYcsee+vLkCDIm8qTtwhJ6+UAMJc3nIY6+PNgUTtXcQgHxCq8BGoL7gbABvNWv76CNbK5qL4Lp9G3ZYRA==} hasBin: true optionalDependencies: - turbo-darwin-64: 1.10.13 - turbo-darwin-arm64: 1.10.13 - turbo-linux-64: 1.10.13 - turbo-linux-arm64: 1.10.13 - turbo-windows-64: 1.10.13 - turbo-windows-arm64: 1.10.13 + turbo-darwin-64: 1.10.14 + turbo-darwin-arm64: 1.10.14 + turbo-linux-64: 1.10.14 + turbo-linux-arm64: 1.10.14 + turbo-windows-64: 1.10.14 + turbo-windows-arm64: 1.10.14 dev: true /tweetnacl@0.14.5: @@ -8166,6 +8509,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: true + /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -8220,8 +8568,8 @@ packages: is-typed-array: 1.1.12 dev: true - /typescript@5.1.6(patch_hash=nqltnu2tftypeoe37zeioxuuuq): - resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + /typescript@5.2.2(patch_hash=wmhs4olj6eveeldp6si4l46ssq): + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -8239,6 +8587,9 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undici-types@5.25.3: + resolution: {integrity: sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==} + /undici@5.20.0: resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==} engines: {node: '>=12.18'} @@ -8290,6 +8641,16 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.12 + which-typed-array: 1.1.11 + dev: true + /utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -8333,6 +8694,13 @@ packages: builtins: 5.0.1 dev: false + /validate-npm-package-name@5.0.0: + resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + builtins: 5.0.1 + dev: true + /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -8358,23 +8726,7 @@ packages: - supports-color - terser - /vite-tsconfig-paths@4.2.0(typescript@5.1.6): - resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - dependencies: - debug: 4.3.4 - globrex: 0.1.2 - tsconfck: 2.1.1(typescript@5.1.6) - transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /vite-tsconfig-paths@4.2.0(typescript@5.1.6)(vite@4.3.9): + /vite-tsconfig-paths@4.2.0(typescript@5.2.2)(vite@4.3.9): resolution: {integrity: sha512-jGpus0eUy5qbbMVGiTxCL1iB9ZGN6Bd37VGLJU39kTDD6ZfULTTb1bcc5IeTWqWJKiWV5YihCaibeASPiGi8kw==} peerDependencies: vite: '*' @@ -8384,7 +8736,7 @@ packages: dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 2.1.1(typescript@5.1.6) + tsconfck: 2.1.1(typescript@5.2.2) vite: 4.3.9(@types/node@20.2.5) transitivePeerDependencies: - supports-color @@ -8423,71 +8775,6 @@ packages: optionalDependencies: fsevents: 2.3.3 - /vitest@0.31.4: - resolution: {integrity: sha512-GoV0VQPmWrUFOZSg3RpQAPN+LPmHg2/gxlMNJlyxJihkz6qReHDV6b0pPDcqFLNEPya4tWJ1pgwUNP9MLmUfvQ==} - engines: {node: '>=v14.18.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - playwright: '*' - safaridriver: '*' - webdriverio: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true - dependencies: - '@types/chai': 4.3.5 - '@types/chai-subset': 1.3.3 - '@types/node': 20.2.5 - '@vitest/expect': 0.31.4 - '@vitest/runner': 0.31.4 - '@vitest/snapshot': 0.31.4 - '@vitest/spy': 0.31.4 - '@vitest/utils': 0.31.4 - acorn: 8.8.2 - acorn-walk: 8.2.0 - cac: 6.7.14 - chai: 4.3.7 - concordance: 5.0.4 - debug: 4.3.4 - local-pkg: 0.4.3 - magic-string: 0.30.0 - pathe: 1.1.1 - picocolors: 1.0.0 - std-env: 3.3.3 - strip-literal: 1.0.1 - tinybench: 2.5.0 - tinypool: 0.5.0 - vite: 4.3.9(@types/node@20.2.5) - vite-node: 0.31.4(@types/node@20.2.5) - why-is-node-running: 2.2.2 - transitivePeerDependencies: - - less - - sass - - stylus - - sugarss - - supports-color - - terser - dev: true - /vitest@0.31.4(@vitest/ui@0.31.4): resolution: {integrity: sha512-GoV0VQPmWrUFOZSg3RpQAPN+LPmHg2/gxlMNJlyxJihkz6qReHDV6b0pPDcqFLNEPya4tWJ1pgwUNP9MLmUfvQ==} engines: {node: '>=v14.18.0'} @@ -8561,6 +8848,10 @@ packages: /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + /webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + dev: true + /webpod@0.0.2: resolution: {integrity: sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==} hasBin: true @@ -8576,6 +8867,14 @@ packages: tr46: 0.0.3 webidl-conversions: 3.0.1 + /whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: true + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -8638,6 +8937,15 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -8762,7 +9070,7 @@ packages: '@types/node': 18.16.16 '@types/ps-tree': 1.1.2 '@types/which': 3.0.0 - chalk: 5.2.0 + chalk: 5.3.0 fs-extra: 11.1.1 fx: 28.0.0 globby: 13.1.4 diff --git a/tsconfig.json b/tsconfig.json index 433128324..0e998a3cf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "composite": false, "target": "esnext", "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "lib": ["es2020", "es2018", "es2017", "es7", "es6", "es5"], "declaration": false /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, "declarationMap": false, @@ -34,10 +34,8 @@ "allowUnreachableCode": false /* Disable error reporting for unreachable code. */, "skipLibCheck": true /* Skip type checking all .d.ts files. */, "noErrorTruncation": true /* Disable truncating types in error messages. */, - "checkJs": true + "checkJs": true, + "allowImportingTsExtensions": true }, - "exclude": ["**/dist"], - "ts-node": { - "require": ["tsconfig-paths/register"] - } + "exclude": ["**/dist"] } diff --git a/turbo.json b/turbo.json index 45c7fc43e..b951e6975 100644 --- a/turbo.json +++ b/turbo.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "pipeline": { "//#lint": { - "inputs": ["**/*.ts", "!**/node_modules", "!**/dist"], + "inputs": ["**/*.ts", "!**/node_modules", "!**/dist", "!**/dist-dts"], "outputMode": "new-only" }, "test:types": { @@ -24,10 +24,11 @@ "README.md", "../README.md", "tsconfig.json", - "tsconfig.build.json", - "../tsconfig.json", - "rollup.config.ts", - "rollup.dts.config.ts" + "tsconfig.*.json", + "tsup.config.ts", + "scripts/build.ts", + "scripts/fix-imports.ts", + "../tsconfig.json" ], "outputs": ["dist/**", "dist-dts/**"], "outputMode": "new-only"