From 8e24a2519167569bb4ba81c1c43605803b35dfea Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 26 Jan 2023 14:13:03 +0200 Subject: [PATCH 1/5] Move aws data api to new structure --- drizzle-orm/package.json | 7 +- drizzle-orm/src/aws-dataapi/driver.ts | 47 ++ drizzle-orm/src/aws-dataapi/index.ts | 2 + drizzle-orm/src/aws-dataapi/migrator.ts | 46 ++ drizzle-orm/src/aws-dataapi/session.ts | 198 +++++ integration-tests/tests/awsdatapi.test.ts | 669 +++++++++++++++++ pnpm-lock.yaml | 839 +++++++++++++++++++--- 7 files changed, 1724 insertions(+), 84 deletions(-) create mode 100644 drizzle-orm/src/aws-dataapi/driver.ts create mode 100644 drizzle-orm/src/aws-dataapi/index.ts create mode 100644 drizzle-orm/src/aws-dataapi/migrator.ts create mode 100644 drizzle-orm/src/aws-dataapi/session.ts create mode 100644 integration-tests/tests/awsdatapi.test.ts diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index 75ec6376b..d0689bf41 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -39,12 +39,13 @@ "@types/pg": "*", "@types/sql.js": "*", "better-sqlite3": ">=7 <9", + "bun-types": "*", "mysql2": ">=2 <3", "pg": ">=8 <9", "postgres": ">=3 <4", "sql.js": ">=1 <2", "sqlite3": ">=5 <6", - "bun-types": "*" + "@aws-sdk/client-rds-data": ">=3 <4" }, "peerDependenciesMeta": { "mysql2": { @@ -82,9 +83,13 @@ }, "bun-types": { "optional": true + }, + "@aws-sdk/client-rds-data": { + "optional": true } }, "devDependencies": { + "@aws-sdk/client-rds-data": "^3.257.0", "@cloudflare/workers-types": "^3.18.0", "@neondatabase/serverless": "^0.1.13", "@types/better-sqlite3": "^7.6.2", diff --git a/drizzle-orm/src/aws-dataapi/driver.ts b/drizzle-orm/src/aws-dataapi/driver.ts new file mode 100644 index 000000000..8edf3be81 --- /dev/null +++ b/drizzle-orm/src/aws-dataapi/driver.ts @@ -0,0 +1,47 @@ +import { Logger } from '~/logger'; +import { PgDatabase } from '~/pg-core/db'; +import { PgDialect } from '~/pg-core/dialect'; +import { AwsDataApiClient, AwsDataApiPgQueryResultHKT, AwsDataApiSession } from './session'; + +export interface PgDriverOptions { + logger?: Logger; + database: string, + resourceArn: string, + secretArn: string, +} + +export class AwsDataApiDriver { + constructor( + private client: AwsDataApiClient, + private dialect: PgDialect, + private options: PgDriverOptions, + ) { + this.initMappers(); + } + + createSession(): AwsDataApiSession { + return new AwsDataApiSession(this.client, this.dialect, this.options); + } + + initMappers() { + // types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); + // types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); + // types.setTypeParser(types.builtins.DATE, (val) => val); + } +} + +export interface DrizzleConfig { + logger?: Logger; + database: string, + resourceArn: string, + secretArn: string, +} + +export type AwsDataApiPgDatabase = PgDatabase; + +export function drizzle(client: AwsDataApiClient, config: DrizzleConfig): AwsDataApiPgDatabase { + const dialect = new PgDialect(); + const driver = new AwsDataApiDriver(client, dialect, config); + const session = driver.createSession(); + return new PgDatabase(dialect, session); +} \ No newline at end of file diff --git a/drizzle-orm/src/aws-dataapi/index.ts b/drizzle-orm/src/aws-dataapi/index.ts new file mode 100644 index 000000000..dab649b2b --- /dev/null +++ b/drizzle-orm/src/aws-dataapi/index.ts @@ -0,0 +1,2 @@ +export * from './driver'; +export * from './session'; \ No newline at end of file diff --git a/drizzle-orm/src/aws-dataapi/migrator.ts b/drizzle-orm/src/aws-dataapi/migrator.ts new file mode 100644 index 000000000..18ba64b24 --- /dev/null +++ b/drizzle-orm/src/aws-dataapi/migrator.ts @@ -0,0 +1,46 @@ +import { MigrationConfig, readMigrationFiles } from '~/migrator'; +import { sql } from '~/sql'; +import { AwsDataApiPgDatabase } from './driver'; +import { AwsDataApiSession } from './session'; + +export async function migrate(db: AwsDataApiPgDatabase, config: string | MigrationConfig) { + const migrations = readMigrationFiles(config); + + // Write own aws datapi migrator + const session = db.session as AwsDataApiSession; + + const migrationTableCreate = sql`CREATE TABLE IF NOT EXISTS "drizzle"."__drizzle_migrations" ( + id SERIAL PRIMARY KEY, + hash text NOT NULL, + created_at bigint + )`; + await session.execute(sql`CREATE SCHEMA IF NOT EXISTS "drizzle"`); + await session.execute(migrationTableCreate); + + const dbMigrations = await session.execute<{ id: number; hash: string; created_at: string }[]>( + sql`SELECT id, hash, created_at FROM "drizzle"."__drizzle_migrations" ORDER BY created_at DESC LIMIT 1`, + ); + + const lastDbMigration = dbMigrations[0]; + const transactionId = await session.beginTransaction(); + + try { + for await (const migration of migrations) { + if ( + !lastDbMigration + || parseInt(lastDbMigration.created_at, 10) < migration.folderMillis + ) { + await session.executeWithTransaction(sql.raw(migration.sql), transactionId); + await session.executeWithTransaction( + sql`INSERT INTO "drizzle"."__drizzle_migrations" ("hash", "created_at") VALUES(${migration.hash}, ${migration.folderMillis})`, + transactionId + ); + } + } + + await session.commitTransaction(transactionId!); + } catch (e) { + await session.rollbackTransaction(transactionId!); + throw e; + } +} \ No newline at end of file diff --git a/drizzle-orm/src/aws-dataapi/session.ts b/drizzle-orm/src/aws-dataapi/session.ts new file mode 100644 index 000000000..1c4910803 --- /dev/null +++ b/drizzle-orm/src/aws-dataapi/session.ts @@ -0,0 +1,198 @@ +import { + BeginTransactionCommand, + BeginTransactionCommandInput, + CommitTransactionCommand, + CommitTransactionCommandInput, + ExecuteStatementCommand, + ExecuteStatementRequest, + Field, + RDSDataClient, + RollbackTransactionCommand, + RollbackTransactionCommandInput, +} from '@aws-sdk/client-rds-data'; +import { Logger } from '~/logger'; +import { SelectFieldsOrdered } from '~/operations'; +import { PgDialect, PgSession, PreparedQuery, PreparedQueryConfig, QueryResultHKT } from '~/pg-core'; +import { fillPlaceholders, Query, SQL } from '~/sql'; +import { mapResultRow } from '~/utils'; + +export type AwsDataApiClient = RDSDataClient; + +export class AwsDataApiPreparedQuery extends PreparedQuery { + private rawQuery: ExecuteStatementCommand; + + constructor( + private client: AwsDataApiClient, + queryString: string, + private params: unknown[], + private options: AwsDataApiSessionOptions, + private fields: SelectFieldsOrdered | undefined, + name: string | undefined, + transactionId: string | undefined, + ) { + super(); + this.rawQuery = new ExecuteStatementCommand({ + sql: queryString, + parameters: [], + secretArn: options.secretArn, + resourceArn: options.resourceArn, + database: options.database, + transactionId, + }); + } + + private getValueFromDataApi(row: Field) { + if (typeof row.stringValue !== 'undefined') { + return row.stringValue; + } else if (typeof row.booleanValue !== 'undefined') { + return row.booleanValue; + } else if (typeof row.doubleValue !== 'undefined') { + return row.doubleValue; + } else if (typeof row.isNull !== 'undefined') { + return null; + } else if (typeof row.longValue !== 'undefined') { + return row.longValue; + } else if (typeof row.blobValue !== 'undefined') { + return row.blobValue; + } else if (typeof row.arrayValue !== 'undefined') { + if (typeof row.arrayValue.stringValues !== 'undefined') { + return row.arrayValue.stringValues; + } + throw Error('Unknown array type'); + } else { + throw Error('Unknown type'); + } + } + + private toValueParam(row: any): Field { + if (typeof row === 'string') { + return { stringValue: row }; + } else if (typeof row === 'number' && Number.isInteger(row)) { + return { longValue: row }; + } else if (typeof row === 'number' && !Number.isInteger(row)) { + return { doubleValue: row }; + } else if (typeof row === 'boolean') { + return { booleanValue: row }; + } else { + throw Error('Unknown type'); + } + } + + async execute(placeholderValues: Record | undefined = {}): Promise { + const params = fillPlaceholders(this.params, placeholderValues); + + this.options.logger?.logQuery(this.rawQuery.input.sql!, params); + + this.rawQuery.input.parameters = params.map((param, _) => ({ name: `${_ + 1}`, value: this.toValueParam(param) })); + + const { fields } = this; + if (!fields) { + return (await this.client.send(this.rawQuery)).records; + } + + const result = await this.client.send(this.rawQuery); + + return result.records?.map((result) => { + const mappedResult = result.map((res) => this.getValueFromDataApi(res)); + return mapResultRow(fields, mappedResult); + }); + } + + all(placeholderValues?: Record | undefined): Promise { + throw new Error('Method not implemented.'); + } + + values(placeholderValues?: Record | undefined): Promise { + throw new Error('Method not implemented.'); + } +} + +export interface AwsDataApiSessionOptions { + logger?: Logger; + database: string; + resourceArn: string; + secretArn: string; +} + +export class AwsDataApiSession extends PgSession { + private rawQuery: BeginTransactionCommandInput | CommitTransactionCommandInput | RollbackTransactionCommandInput; + + constructor( + private client: AwsDataApiClient, + dialect: PgDialect, + private options: AwsDataApiSessionOptions, + ) { + super(dialect); + this.rawQuery = { + secretArn: options.secretArn, + resourceArn: options.resourceArn, + database: options.database, + }; + } + + prepareQuery( + query: Query, + fields: SelectFieldsOrdered | undefined, + name: string | undefined, + ): PreparedQuery { + return new AwsDataApiPreparedQuery(this.client, query.sql, query.params, this.options, fields, name, undefined); + } + + prepareQueryWithTransaction( + query: Query, + fields: SelectFieldsOrdered | undefined, + name: string | undefined, + transactionId: string | undefined, + ): PreparedQuery { + return new AwsDataApiPreparedQuery(this.client, query.sql, query.params, this.options, fields, name, transactionId); + } + + executeWithTransaction(query: SQL, transactionId: string | undefined): Promise { + return this.prepareQueryWithTransaction( + query.toQuery({ + escapeName: (num) => { + return `"${num}"`; + }, + escapeParam: (num) => { + return `:${num + 1}`; + }, + }), + undefined, + undefined, + transactionId, + ).execute(); + } + + override execute(query: SQL): Promise { + return this.prepareQuery( + query.toQuery({ + escapeName: (num) => { + return `"${num}"`; + }, + escapeParam: (num) => { + return `:${num + 1}`; + }, + }), + undefined, + undefined, + ).execute(); + } + + async beginTransaction(): Promise { + const transactionRes = await this.client.send(new BeginTransactionCommand(this.rawQuery)); + return transactionRes.transactionId; + } + + async commitTransaction(transactionId: string): Promise { + await this.client.send(new CommitTransactionCommand({ ...this.rawQuery, transactionId })); + } + + async rollbackTransaction(transactionId: string): Promise { + await this.client.send(new RollbackTransactionCommand({ ...this.rawQuery, transactionId })); + } +} + +export interface AwsDataApiPgQueryResultHKT extends QueryResultHKT { + // check types and get from aws dataapi + type: any; +} \ No newline at end of file diff --git a/integration-tests/tests/awsdatapi.test.ts b/integration-tests/tests/awsdatapi.test.ts new file mode 100644 index 000000000..dd0bd6e00 --- /dev/null +++ b/integration-tests/tests/awsdatapi.test.ts @@ -0,0 +1,669 @@ +import anyTest, { TestFn } from 'ava'; +import Docker from 'dockerode'; +import { sql } from 'drizzle-orm'; +import { asc, eq } from 'drizzle-orm/expressions'; +import { drizzle, NodePgDatabase } from 'drizzle-orm/node-pg'; +import { migrate } from 'drizzle-orm/node-pg/migrator'; +import { alias, boolean, InferModel, jsonb, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; +import { name, placeholder } from 'drizzle-orm/sql'; +import getPort from 'get-port'; +import { Client } from 'pg'; +import { v4 as uuid } from 'uuid'; + +const usersTable = pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + verified: boolean('verified').notNull().default(false), + jsonb: jsonb('jsonb'), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + +const usersMigratorTable = pgTable('users12', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + email: text('email').notNull(), +}); + +interface Context { + docker: Docker; + pgContainer: Docker.Container; + db: NodePgDatabase; + client: Client; +} + +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))) + ); + + const pgContainer = (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 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); + + let 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'); + throw lastError; + } + ctx.db = drizzle(ctx.client /* , { logger: new DefaultLogger() } */); +}); + +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() + )`, + ); +}); + +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(usersTable); + + t.assert(result[0]!.createdAt instanceof Date); + 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(usersTable).fields({ + name: sql`upper(${usersTable.name})`, + }); + + 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(usersTable).fields({ + name: sql`upper(${usersTable.name})`.as(), + }); + + t.deepEqual(users, [{ 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); + 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); + 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(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(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(usersTable).fields({ + id: usersTable.id, + name: usersTable.name, + jsonb: usersTable.jsonb, + }); + + 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(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(usersTable).fields({ + 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('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(usersTable) + .fields({ name: usersTable.name }) + .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(usersTable) + .fields({ name: usersTable.name }) + .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(usersTable) + .fields({ name: usersTable.name }) + .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(usersTable) + .fields({ name: usersTable.name }) + .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(usersTable) + .fields({ name: usersTable.name }) + .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(usersTable) + .fields({ id: usersTable.id, name: usersTable.name }) + .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(usersTable).fields({ id: usersTable.id, name: usersTable.name }); + 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(usersTable) + .fields({ + user: { + id: usersTable.id, + name: usersTable.name, + }, + customer: { + id: customerAlias.id, + name: customerAlias.name, + }, + }) + .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 customerAlias = alias(usersTable, 'customer'); + + await db.insert(usersTable).values({ id: 10, name: 'Ivan' }, { id: 11, name: 'Hans' }); + + const result = await db + .select(usersTable) + .leftJoin(customerAlias, eq(customerAlias.id, 11)) + .where(eq(usersTable.id, 10)); + + t.deepEqual(result, [{ + users: { + id: 10, + name: 'Ivan', + verified: false, + jsonb: null, + createdAt: result[0]!.users.createdAt, + }, + customer: { + id: 11, + name: 'Hans', + verified: false, + jsonb: null, + createdAt: result[0]!.customer!.createdAt, + }, + }]); +}); + +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(usersTable).fields({ id: usersTable.id, name: usersTable.name }); + + 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(usersTable) + .fields({ + id: usersTable.id, + name: usersTable.name, + }) + .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(usersTable).fields({ + id: usersTable.id, + name: usersTable.name, + verified: usersTable.verified, + }); + + 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(usersTable) + .fields({ + id: usersTable.id, + name: usersTable.name, + }) + .where(eq(usersTable.id, placeholder('id'))) + .prepare('stmt3'); + const result = await stmt.execute({ id: 1 }); + + t.deepEqual(result, [{ id: 1, name: 'John' }]); +}); + +test.serial('migrator', async (t) => { + const { db } = t.context; + await migrate(db, { migrationsFolder: './drizzle/pg' }); + + await db.insert(usersMigratorTable).values({ name: 'John', email: 'email' }); + + const result = await db.select(usersMigratorTable); + + t.deepEqual(result, [{ id: 1, name: 'John', email: 'email' }]); +}); + +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.rows, [{ 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.rows, [{ id: 1, name: 'John' }]); +}); + +test.serial('insert via db.execute w/ query builder', async (t) => { + const { db } = t.context; + + const inserted = await db.execute, 'id' | 'name'>>( + db.insert(usersTable).values({ name: 'John' }).returning({ id: usersTable.id, name: usersTable.name }), + ); + t.deepEqual(inserted.rows, [{ id: 1, name: 'John' }]); +}); + +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" ("name", "jsonb") values ($1, $2) 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" ("name", "jsonb") values ($1, $2) 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" ("name", "jsonb") values ($1, $2) 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" ("name", "jsonb") values ($1, $2) 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(usersTable).fields({ id: usersTable.id, name: usersTable.name }).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(usersTable).fields({ id: usersTable.id, name: usersTable.name }).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(usersTable).fields({ id: usersTable.id, name: usersTable.name }).where( + eq(usersTable.id, 1), + ); + + t.deepEqual(res, [{ id: 1, name: 'John' }]); +}); + +test.after.always(async (t) => { + const ctx = t.context; + await ctx.client?.end().catch(console.error); + await ctx.pgContainer?.stop().catch(console.error); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 378e5ddef..6ea15064e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,7 @@ importers: drizzle-orm: specifiers: + '@aws-sdk/client-rds-data': ^3.257.0 '@cloudflare/workers-types': ^3.18.0 '@neondatabase/serverless': ^0.1.13 '@types/better-sqlite3': ^7.6.2 @@ -43,6 +44,7 @@ importers: sql.js: ^1.8.0 sqlite3: ^5.1.2 devDependencies: + '@aws-sdk/client-rds-data': 3.257.0 '@cloudflare/workers-types': 3.18.0 '@neondatabase/serverless': 0.1.13 '@types/better-sqlite3': 7.6.3 @@ -57,63 +59,15 @@ importers: sql.js: 1.8.0 sqlite3: 5.1.4 - drizzle-orm-mysql: - specifiers: - '@types/node': ^18.11.12 - drizzle-orm: link:../drizzle-orm/dist - mysql2: ^2.3.3 - devDependencies: - '@types/node': 18.11.18 - drizzle-orm: link:../drizzle-orm/dist - mysql2: 2.3.3 - - drizzle-orm-pg: - specifiers: - '@neondatabase/serverless': ^0.1.13 - '@types/pg': ^8.6.5 - drizzle-orm: link:../drizzle-orm/dist - pg: ^8.8.0 - postgres: ^3.3.3 - devDependencies: - '@neondatabase/serverless': 0.1.13 - '@types/pg': 8.6.6 - drizzle-orm: link:../drizzle-orm/dist - pg: 8.8.0 - postgres: 3.3.3 - - drizzle-orm-sqlite: - specifiers: - '@cloudflare/workers-types': ^3.18.0 - '@types/better-sqlite3': ^7.6.2 - '@types/sql.js': ^1.4.4 - better-sqlite3: ^7.6.2 - drizzle-orm: link:../drizzle-orm/dist - sql.js: ^1.8.0 - sqlite3: ^5.1.2 - devDependencies: - '@cloudflare/workers-types': 3.18.0 - '@types/better-sqlite3': 7.6.3 - '@types/sql.js': 1.4.4 - better-sqlite3: 7.6.2 - drizzle-orm: link:../drizzle-orm/dist - sql.js: 1.8.0 - sqlite3: 5.1.4 - drizzle-zod: specifiers: ava: ^5.1.0 drizzle-orm: link:../drizzle-orm/dist - drizzle-orm-mysql: link:../drizzle-orm-mysql/dist - drizzle-orm-pg: link:../drizzle-orm-pg/dist - drizzle-orm-sqlite: link:../drizzle-orm-sqlite/dist tsx: ^3.12.2 zod: ^3.20.2 devDependencies: ava: 5.1.1 drizzle-orm: link:../drizzle-orm/dist - drizzle-orm-mysql: link:../drizzle-orm-mysql/dist - drizzle-orm-pg: link:../drizzle-orm-pg/dist - drizzle-orm-sqlite: link:../drizzle-orm-sqlite/dist tsx: 3.12.2 zod: 3.20.2 @@ -124,14 +78,12 @@ importers: better-sqlite3: ^8.0.0 drizzle-kit: ^0.12.18 drizzle-orm: 0.14.2 - drizzle-orm-sqlite: 0.14.2 itty-router: ^2.6.6 itty-router-extras: ^0.4.2 typescript: ^4.9.3 wrangler: ^2.4.2 dependencies: - drizzle-orm: 0.14.2_drizzle-orm-sqlite@0.14.2 - drizzle-orm-sqlite: 0.14.2_zlc2hznpyo77b3lwadvfeyduza + drizzle-orm: 0.14.2 itty-router: 2.6.6 itty-router-extras: 0.4.2 devDependencies: @@ -154,9 +106,6 @@ importers: better-sqlite3: ^7.6.2 dockerode: ^3.3.4 drizzle-orm: workspace:../drizzle-orm/dist - drizzle-orm-mysql: workspace:../drizzle-orm-mysql/dist - drizzle-orm-pg: workspace:../drizzle-orm-pg/dist - drizzle-orm-sqlite: workspace:../drizzle-orm-sqlite/dist get-port: ^6.1.2 mysql2: ^2.3.3 pg: ^8.8.0 @@ -170,9 +119,6 @@ importers: better-sqlite3: 7.6.2 dockerode: 3.3.4 drizzle-orm: link:../drizzle-orm/dist - drizzle-orm-mysql: link:../drizzle-orm-mysql/dist - drizzle-orm-pg: link:../drizzle-orm-pg/dist - drizzle-orm-sqlite: link:../drizzle-orm-sqlite/dist get-port: 6.1.2 mysql2: 2.3.3 pg: 8.8.0 @@ -201,6 +147,732 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true + /@aws-crypto/ie11-detection/3.0.0: + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + dependencies: + tslib: 1.14.1 + dev: true + + /@aws-crypto/sha256-browser/3.0.0: + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + dependencies: + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-locate-window': 3.208.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/sha256-js/3.0.0: + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + dependencies: + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.257.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/supports-web-crypto/3.0.0: + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + dependencies: + tslib: 1.14.1 + dev: true + + /@aws-crypto/util/3.0.0: + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + dependencies: + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + tslib: 1.14.1 + dev: true + + /@aws-sdk/abort-controller/3.257.0: + resolution: {integrity: sha512-ekWy391lOerS0ZECdhp/c+X7AToJIpfNrCPjuj3bKr+GMQYckGsYsdbm6AUD4sxBmfvuaQmVniSXWovaxwcFcQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/client-rds-data/3.257.0: + resolution: {integrity: sha512-9Tx61790pBKwhVFM+F0iQ0tXsykIXvuypILwepkv3p+6j5DkAIrCL/7UN1jyl1vmPZhYjCp3z96/+d91bW6sNw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.257.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/client-sso-oidc/3.257.0: + resolution: {integrity: sha512-yXf53Zc7DYt/4j7xGXgWaDVhE/XMDLoid5l8bOb4aDJN6kxgl5bXV/sH3DwND/fA09EQHU1W+9oe/8InVqsliw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/client-sso/3.257.0: + resolution: {integrity: sha512-sD0yTTctLbjDoSV3hJem+xz9BzusmkkU/4Fts9gEs4C5NjS0YrfPAvQWE++yRzPLPR/dMhDFVCOs7voTzUhUWQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/client-sts/3.257.0: + resolution: {integrity: sha512-AVNngoDGACR7xs9wTU7hrZSvMfNOGvWP/B/ieA0au3H3KDucjCZzBd3j2vYkR6Cph9dY7YkpU2Gtzn+JXD0b1g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-sdk-sts': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8-browser': 3.188.0 + '@aws-sdk/util-utf8-node': 3.208.0 + fast-xml-parser: 4.0.11 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/config-resolver/3.257.0: + resolution: {integrity: sha512-jChjr8ayaXoAcUgrRr+JRIJ6bPtEoS+/xW9khpHOmrEX+uBJ7xLPfdS4e6nmxAQpbem9AsUVvf57DXhSh5/nLg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-config-provider': 3.208.0 + '@aws-sdk/util-middleware': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/credential-provider-env/3.257.0: + resolution: {integrity: sha512-GsmBi5Di6hk1JAi1iB6/LCY8o+GmlCvJoB7wuoVmXI3VxRVwptUVjuj8EtJbIrVGrF9dSuIRPCzUoSuzEzYGlg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/credential-provider-imds/3.257.0: + resolution: {integrity: sha512-UrxYkHWndy6s/bZZWH2poIyqdISTbILGTcK9tT8cFaUUrNIEFXiVESZMNNaagy0Dyy9wr80ndumxRkutYga9VA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/credential-provider-ini/3.257.0: + resolution: {integrity: sha512-69jW9/Os2zGBATQR8Urde+IlzicgJPCO/gAWpm4AYJYT5LSGc0pOuZflSXq+ZfKy3jcSoN0yOFxkoMnmZb8pzg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.257.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/credential-provider-node/3.257.0: + resolution: {integrity: sha512-yXVNOml/w4ipWiRgLWUphGwISqJQRPjALgTsRa0O+CzpaEc/0HRqM8I78VzCzjsb+QE4EP7MZej6tkEAZYgTlg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-ini': 3.257.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.257.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/credential-provider-process/3.257.0: + resolution: {integrity: sha512-xK8uYeNXaclaBCGrLi4z2pxPRngqLf5BM5jg2fn57zqvlL9V5gJF972FehrVBL0bfp1/laG0ZJtD2K2sapyWAw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/credential-provider-sso/3.257.0: + resolution: {integrity: sha512-I/1TQm6WruqxTTPH+Wo2o+YCLenEY0bWq97EQn+d8Cp0N7cNJUDt8BHF22dQtUzd7bvSspVK5M4qCZKAh3fhOg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/token-providers': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/credential-provider-web-identity/3.257.0: + resolution: {integrity: sha512-Cm0uvRv4JuIbD0Kp3W0J/vwjADIyCx8HoZi5yg+QIi5nilocuTQ3ajvLeuPVSvFvdy+yaxSc5FxNXquWt7Mngw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/fetch-http-handler/3.257.0: + resolution: {integrity: sha512-zOF+RzQ+wfF7tq7tGUdPcqUTh3+k2f8KCVJE07A8kCopVq4nBu4NH6Eq29Tjpwdya3YlKvE+kFssuQRRRRex+Q==} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/querystring-builder': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/hash-node/3.257.0: + resolution: {integrity: sha512-W/USUuea5Ep3OJ2U7Ve8/5KN1YsDun2WzOFUxc1PyxXP5pW6OgC15/op0e+bmWPG851clvp5S8ZuroUr3aKi3Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-buffer-from': 3.208.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/invalid-dependency/3.257.0: + resolution: {integrity: sha512-T68SAPRNMEhpke0wlxURgogL7q0B8dfqZsSeS20BVR/lksJxLse9+pbmCDxiu1RrXoEIsEwl5rbLN+Hw8BFFYw==} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/is-array-buffer/3.201.0: + resolution: {integrity: sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-content-length/3.257.0: + resolution: {integrity: sha512-yiawbV2azm6QnMY1L2ypG8PDRdjOcEIvFmT0T7y0F49rfbKJOu21j1ONAoCkLrINK6kMqcD5JSQLVCoURxiTxQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-endpoint/3.257.0: + resolution: {integrity: sha512-RQNQe/jeVuWZtXXfcOm+e3qMFICY6ERsXUrbt0rjHgvajZCklcrRJgxJSCwrcS7Le3nl9azFPMAMj9L7uSK28g==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-config-provider': 3.208.0 + '@aws-sdk/util-middleware': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-host-header/3.257.0: + resolution: {integrity: sha512-gEi9AJdJfRfU8Qr6HK1hfhxTzyV3Giq4B/h7um99hIFAT/GCg9xiPvAOKPo6UeuiKEv3b7RpSL4s6cBvnJMJBA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-logger/3.257.0: + resolution: {integrity: sha512-8RDXW/VbMKBsXDfcCLmROZcWKyrekyiPa3J1aIaBy0tq9o4xpGoXw/lwwIrNVvISAFslb57rteup34bfn6ta6w==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-recursion-detection/3.257.0: + resolution: {integrity: sha512-rUCih6zHh8k9Edf5N5Er4s508FYbwLM0MWTD2axzlj9TjLqEQ9OKED3wHaLffXSDzodd3oTAfJCLPbWQyoZ3ZQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-retry/3.257.0: + resolution: {integrity: sha512-vDOy4PbSRW2gtgoJZ+yvgyxdlTwbZGpuv/rA2+XYxURmhPMzpmqs4o1DR37LG8O41WouI1rPzA7E+Ffo+iNWjw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/service-error-classification': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-middleware': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + tslib: 2.4.1 + uuid: 8.3.2 + dev: true + + /@aws-sdk/middleware-sdk-sts/3.257.0: + resolution: {integrity: sha512-d6IJCLRi3O2tm4AFK60WNhIwmMmspj1WzKR1q1TaoPzoREPG2xg+Am18wZBRkCyYuRPPrbizmkvAmAJiUolMAw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-serde/3.257.0: + resolution: {integrity: sha512-/JasfXPWFq24mnCrx9fxW/ISBSp07RJwhsF14qzm8Qy3Z0z470C+QRM6otTwAkYuuVt1wuLjja5agq3Jtzq7dQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-signing/3.257.0: + resolution: {integrity: sha512-hCH3D83LHmm6nqmtNrGTWZCVjsQXrGHIXbd17/qrw7aPFvcAhsiiCncGFP+XsUXEKa2ZqcSNMUyPrx69ofNRZQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/signature-v4': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-middleware': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-stack/3.257.0: + resolution: {integrity: sha512-awg2F0SvwACBaw4HIObK8pQGfSqAc4Vy+YFzWSfZNVC35oRO6RsRdKHVU99lRC0LrT2Ptmfghl2DMPSrRDbvlQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/middleware-user-agent/3.257.0: + resolution: {integrity: sha512-37rt75LZyD0UWpbcFuxEGqwF3DZKSixQPl7AsDe6q3KtrO5gGQB+diH5vbY0txNNYyv5IK9WMwvY73mVmoWRmw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/node-config-provider/3.257.0: + resolution: {integrity: sha512-IfGF7+cU0PyB7RpHlgc445ZAUZDWn4ij2HTB6N+xULwFw2TxnyQ2tvo3Gp5caW9VlJ3eXE9wFrynv+JXUIH7Bg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/node-http-handler/3.257.0: + resolution: {integrity: sha512-8KnWHVVwaGKyTlkTU9BSOAiSovNDoagxemU2l10QqBbzUCVpljCUMUkABEGRJ1yoQCl6DJ7RtNkAyZ8Ne/E15A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/abort-controller': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/querystring-builder': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/property-provider/3.257.0: + resolution: {integrity: sha512-3rUbRAcF0GZ5PhDiXhS4yREfZ5hOEtvYEa9S/19OdM5eoypOaLU5XnFcCKfnccSP8SkdgpJujzxOMRWNWadlAQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/protocol-http/3.257.0: + resolution: {integrity: sha512-xt7LGOgZIvbLS3418AYQLacOqx+mo5j4mPiIMz7f6AaUg+/fBUgESVsncKDqxbEJVwwCXSka8Ca0cntJmoeMSw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/querystring-builder/3.257.0: + resolution: {integrity: sha512-mZHWLP7XIkzx1GIXO5WfX/iJ+aY9TWs02RE9FkdL2+by0HEMR65L3brQTbU1mIBJ7BjaPwYH24dljUOSABX7yg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-uri-escape': 3.201.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/querystring-parser/3.257.0: + resolution: {integrity: sha512-UDrE1dEwWrWT8dG2VCrGYrPxCWOkZ1fPTPkjpkR4KZEdQDZBqU5gYZF2xPj8Nz7pjQVHFuW2wFm3XYEk56GEjg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/service-error-classification/3.257.0: + resolution: {integrity: sha512-FAyR0XsueGkkqDtkP03cTJQk52NdQ9sZelLynmmlGPUP75LApRPvFe1riKrou6+LsDbwVNVffj6mbDfIcOhaOw==} + engines: {node: '>=14.0.0'} + dev: true + + /@aws-sdk/shared-ini-file-loader/3.257.0: + resolution: {integrity: sha512-HNjC1+Wx3xHiJc+CP14GhIdVhfQGSjroAsWseRxAhONocA9Fl1ZX4hx7+sA5c9nOoMVOovi6ivJ/6lCRPTDRrQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/signature-v4/3.257.0: + resolution: {integrity: sha512-aLQQN59X/D0+ShzPD3Anj5ntdMA/RFeNLOUCDyDvremViGi6yxUS98usQ/8bG5Rq0sW2GGMdbFUFmrDvqdiqEQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.201.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/util-hex-encoding': 3.201.0 + '@aws-sdk/util-middleware': 3.257.0 + '@aws-sdk/util-uri-escape': 3.201.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/smithy-client/3.257.0: + resolution: {integrity: sha512-Vy/en+llpslHG6WZ2yuN+On6u7p2hROEURwAST/lpReAwBETjbsxylkWvP8maeGKQ54u9uC6lIZAOJut2I3INw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/token-providers/3.257.0: + resolution: {integrity: sha512-Ysd1dpWiI2oBOrJpkSJkgPsY0dwMtavIBzF3d5JYN1HCl14Aqc2jcNqBjD+7nEeL6CHXcFeyB7jmCDqiuP0V3A==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso-oidc': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: true + + /@aws-sdk/types/3.257.0: + resolution: {integrity: sha512-LmqXuBQBGeaGi/3Rp7XiEX1B5IPO2UUfBVvu0wwGqVsmstT0SbOVDZGPmxygACbm64n+PRx3uTSDefRfoiWYZg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/url-parser/3.257.0: + resolution: {integrity: sha512-Qe/AcFe/NFZHa6cN2afXEQn9ehXxh57dWGdRjfjd2lQqNV4WW1R2pl2Tm1ZJ1dwuCNLJi4NHLMk8lrD3QQ8rdg==} + dependencies: + '@aws-sdk/querystring-parser': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-base64/3.208.0: + resolution: {integrity: sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.208.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-body-length-browser/3.188.0: + resolution: {integrity: sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-body-length-node/3.208.0: + resolution: {integrity: sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-buffer-from/3.208.0: + resolution: {integrity: sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/is-array-buffer': 3.201.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-config-provider/3.208.0: + resolution: {integrity: sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-defaults-mode-browser/3.257.0: + resolution: {integrity: sha512-nkfK+MNacVd3Px/fcAvU0hDeh+r7d+RLLt3sJ5Zc0gGd+i3OQEP58V8QzR9PYMvUvSvGQP16fQVQHSbRZtuWyQ==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + bowser: 2.11.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-defaults-mode-node/3.257.0: + resolution: {integrity: sha512-qsIb7aPbGFcKbBGoAQmlzv1gMcscgbpfrRh4rgNqkJXVbJ52Ql6+vXXfBmlWaBho0fcsNh5XnYu1fzdCuu+N7g==} + engines: {node: '>= 10.0.0'} + dependencies: + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-endpoints/3.257.0: + resolution: {integrity: sha512-3bvmRn5XGYzPPWjLuvHBKdJOb+fijnb8Ungu9bfXnTYFsng/ndHUWeHC22O/p8w3OWoRYUIMaZHxdxe27BFozg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-hex-encoding/3.201.0: + resolution: {integrity: sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-locate-window/3.208.0: + resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-middleware/3.257.0: + resolution: {integrity: sha512-F9ieon8B8eGVs5tyZtAIG3DZEObDvujkspho0qRbUTHUosM0ylJLsMU800fmC/uRHLRrZvb/RSp59+kNDwSAMw==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-retry/3.257.0: + resolution: {integrity: sha512-l9TOsOAYtZxwW3q5fQKW4rsD9t2HVaBfQ4zBamHkNTfB4vBVvCnz4oxkvSvA2MlxCA6am+K1K/oj917Tpqk53g==} + engines: {node: '>= 14.0.0'} + dependencies: + '@aws-sdk/service-error-classification': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-uri-escape/3.201.0: + resolution: {integrity: sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-user-agent-browser/3.257.0: + resolution: {integrity: sha512-YdavWK6/8Cw6mypEgysGGX/dT9p9qnzFbnN5PQsUY+JJk2Nx8fKFydjGiQ+6rWPeW17RAv9mmbboh9uPVWxVlw==} + dependencies: + '@aws-sdk/types': 3.257.0 + bowser: 2.11.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-user-agent-node/3.257.0: + resolution: {integrity: sha512-fOHh80kiVomUkABmOv3ZxB/SNLnOPAja7uhQmGWfKHXBkcxTVfWO2KBs5vzU5qhVZA0c1zVEvZPcBdRsonnhlw==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-utf8-browser/3.188.0: + resolution: {integrity: sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==} + dependencies: + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-utf8-node/3.208.0: + resolution: {integrity: sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.208.0 + tslib: 2.4.1 + dev: true + + /@aws-sdk/util-utf8/3.254.0: + resolution: {integrity: sha512-14Kso/eIt5/qfIBmhEL9L1IfyUqswjSTqO2mY7KOzUZ9SZbwn3rpxmtkhmATkRjD7XIlLKaxBkI7tU9Zjzj8Kw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/util-buffer-from': 3.208.0 + tslib: 2.4.1 + dev: true + /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -450,6 +1122,7 @@ packages: /@cloudflare/workers-types/3.18.0: resolution: {integrity: sha512-ehKOJVLMeR+tZkYhWEaLYQxl0TaIZu/kE86HF3/RidR8Xv5LuQxpbh+XXAoKVqsaphWLhIgBhgnlN5HGdheXSQ==} + dev: true /@esbuild-kit/cjs-loader/2.4.1: resolution: {integrity: sha512-lhc/XLith28QdW0HpHZvZKkorWgmCNT7sVelMHDj3HFdTfdqkwEKvT+aXVQtNAmCC39VJhunDkWhONWB7335mg==} @@ -1140,6 +1813,7 @@ packages: dependencies: bindings: 1.5.0 prebuild-install: 7.1.1 + dev: true /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} @@ -1166,6 +1840,10 @@ packages: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: true + /bowser/2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: true + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -1656,30 +2334,7 @@ packages: - supports-color dev: true - /drizzle-orm-sqlite/0.14.2_zlc2hznpyo77b3lwadvfeyduza: - resolution: {integrity: sha512-q5lB0A2rHLNEkBK5ROj/y9hB1e7cCB7aPQ8borFdl4oBwDkWtEpy90FCa/nWv/dUx5SQ0gaoT1hEL4G30FWQnA==} - peerDependencies: - '@cloudflare/workers-types': '>=3 <4' - '@types/better-sqlite3': '>=7 <9' - better-sqlite3: '>=7 <9' - drizzle-orm: '>=0.14 <0.15' - sqlite3: '>=5 <6' - peerDependenciesMeta: - '@cloudflare/workers-types': - optional: true - '@types/better-sqlite3': - optional: true - better-sqlite3: - optional: true - sqlite3: - optional: true - dependencies: - '@cloudflare/workers-types': 3.18.0 - better-sqlite3: 8.0.1 - drizzle-orm: 0.14.2_drizzle-orm-sqlite@0.14.2 - dev: false - - /drizzle-orm/0.14.2_drizzle-orm-sqlite@0.14.2: + /drizzle-orm/0.14.2: resolution: {integrity: sha512-5eUH81oXQ1GCpsEDPlX3LqX5RzDuO3uWp50yEKMb5GYyWkA0t5gBbMxpIdjYoxeP3xv4g+IkhlTuxXkK/70/5g==} peerDependencies: drizzle-orm-mysql: '>=0.14 <0.15' @@ -1692,8 +2347,6 @@ packages: optional: true drizzle-orm-sqlite: optional: true - dependencies: - drizzle-orm-sqlite: 0.14.2_zlc2hznpyo77b3lwadvfeyduza dev: false /eastasianwidth/0.2.0: @@ -2291,6 +2944,13 @@ packages: micromatch: 4.0.5 dev: true + /fast-xml-parser/4.0.11: + resolution: {integrity: sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: true + /fastq/1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -3776,6 +4436,10 @@ packages: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + /strnum/1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: true + /supertap/3.0.1: resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3882,6 +4546,10 @@ packages: hasBin: true dev: true + /tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} dev: true @@ -4028,6 +4696,11 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + /uuid/9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true From cce94a78e706c9c32ef086256980416a91db0d1e Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 26 Jan 2023 15:16:04 +0200 Subject: [PATCH 2/5] Add dataapi connection to tests --- integration-tests/package.json | 1 + integration-tests/tests/awsdatapi.test.ts | 128 ++++++++++++---------- pnpm-lock.yaml | 72 +----------- 3 files changed, 72 insertions(+), 129 deletions(-) diff --git a/integration-tests/package.json b/integration-tests/package.json index b228dbcef..ce46139a3 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -33,6 +33,7 @@ "tsx": "^3.12.2" }, "dependencies": { + "@aws-sdk/client-rds-data": "^3.257.0", "better-sqlite3": "^7.6.2", "dockerode": "^3.3.4", "drizzle-orm": "workspace:../drizzle-orm/dist", diff --git a/integration-tests/tests/awsdatapi.test.ts b/integration-tests/tests/awsdatapi.test.ts index dd0bd6e00..cc1727c1d 100644 --- a/integration-tests/tests/awsdatapi.test.ts +++ b/integration-tests/tests/awsdatapi.test.ts @@ -1,14 +1,13 @@ +import { RDSDataClient } from '@aws-sdk/client-rds-data'; import anyTest, { TestFn } from 'ava'; import Docker from 'dockerode'; import { sql } from 'drizzle-orm'; +import { AwsDataApiPgDatabase, drizzle } from 'drizzle-orm/aws-dataapi'; +import { migrate } from 'drizzle-orm/aws-dataapi/migrator'; import { asc, eq } from 'drizzle-orm/expressions'; -import { drizzle, NodePgDatabase } from 'drizzle-orm/node-pg'; -import { migrate } from 'drizzle-orm/node-pg/migrator'; import { alias, boolean, InferModel, jsonb, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; import { name, placeholder } from 'drizzle-orm/sql'; -import getPort from 'get-port'; import { Client } from 'pg'; -import { v4 as uuid } from 'uuid'; const usersTable = pgTable('users', { id: serial('id').primaryKey(), @@ -25,66 +24,77 @@ const usersMigratorTable = pgTable('users12', { }); interface Context { - docker: Docker; - pgContainer: Docker.Container; - db: NodePgDatabase; - client: Client; + // docker: Docker; + // pgContainer: Docker.Container; + db: AwsDataApiPgDatabase; + // client: Client; } 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))) - ); - - const pgContainer = (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 pgContainer.start(); - - return `postgres://postgres:postgres@localhost:${port}/postgres`; -} +// 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))) +// ); + +// const pgContainer = (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 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); - - let 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'); - throw lastError; - } - ctx.db = drizzle(ctx.client /* , { logger: new DefaultLogger() } */); + // const connectionString = process.env['PG_CONNECTION_STRING'] ?? await createDockerDB(ctx); + + // let 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'); + // throw lastError; + // } + + const database = process.env['AWS_DATA_API_DB']!; + const secretArn = process.env['AWS_DATA_API_SECRET_ARN']!; + const resourceArn = process.env['AWS_DATA_API_RESOURCE_ARN']!; + + const rdsClient = new RDSDataClient({}); + + ctx.db = drizzle(rdsClient, { + database, + secretArn, + resourceArn, + }); }); test.beforeEach(async (t) => { @@ -664,6 +674,6 @@ test.serial('insert with onConflict do nothing + target', async (t) => { test.after.always(async (t) => { const ctx = t.context; - await ctx.client?.end().catch(console.error); - await ctx.pgContainer?.stop().catch(console.error); + // await ctx.client?.end().catch(console.error); + // await ctx.pgContainer?.stop().catch(console.error); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ea15064e..f93b44559 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,6 +96,7 @@ importers: integration-tests: specifiers: + '@aws-sdk/client-rds-data': ^3.257.0 '@types/better-sqlite3': ^7.6.3 '@types/dockerode': ^3.3.14 '@types/node': ^18.11.18 @@ -116,6 +117,7 @@ importers: uuid: ^9.0.0 uvu: ^0.5.6 dependencies: + '@aws-sdk/client-rds-data': 3.257.0 better-sqlite3: 7.6.2 dockerode: 3.3.4 drizzle-orm: link:../drizzle-orm/dist @@ -151,7 +153,6 @@ packages: resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} dependencies: tslib: 1.14.1 - dev: true /@aws-crypto/sha256-browser/3.0.0: resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} @@ -164,7 +165,6 @@ packages: '@aws-sdk/util-locate-window': 3.208.0 '@aws-sdk/util-utf8-browser': 3.188.0 tslib: 1.14.1 - dev: true /@aws-crypto/sha256-js/3.0.0: resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} @@ -172,13 +172,11 @@ packages: '@aws-crypto/util': 3.0.0 '@aws-sdk/types': 3.257.0 tslib: 1.14.1 - dev: true /@aws-crypto/supports-web-crypto/3.0.0: resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} dependencies: tslib: 1.14.1 - dev: true /@aws-crypto/util/3.0.0: resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} @@ -186,7 +184,6 @@ packages: '@aws-sdk/types': 3.257.0 '@aws-sdk/util-utf8-browser': 3.188.0 tslib: 1.14.1 - dev: true /@aws-sdk/abort-controller/3.257.0: resolution: {integrity: sha512-ekWy391lOerS0ZECdhp/c+X7AToJIpfNrCPjuj3bKr+GMQYckGsYsdbm6AUD4sxBmfvuaQmVniSXWovaxwcFcQ==} @@ -194,7 +191,6 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/client-rds-data/3.257.0: resolution: {integrity: sha512-9Tx61790pBKwhVFM+F0iQ0tXsykIXvuypILwepkv3p+6j5DkAIrCL/7UN1jyl1vmPZhYjCp3z96/+d91bW6sNw==} @@ -238,7 +234,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/client-sso-oidc/3.257.0: resolution: {integrity: sha512-yXf53Zc7DYt/4j7xGXgWaDVhE/XMDLoid5l8bOb4aDJN6kxgl5bXV/sH3DwND/fA09EQHU1W+9oe/8InVqsliw==} @@ -279,7 +274,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/client-sso/3.257.0: resolution: {integrity: sha512-sD0yTTctLbjDoSV3hJem+xz9BzusmkkU/4Fts9gEs4C5NjS0YrfPAvQWE++yRzPLPR/dMhDFVCOs7voTzUhUWQ==} @@ -320,7 +314,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/client-sts/3.257.0: resolution: {integrity: sha512-AVNngoDGACR7xs9wTU7hrZSvMfNOGvWP/B/ieA0au3H3KDucjCZzBd3j2vYkR6Cph9dY7YkpU2Gtzn+JXD0b1g==} @@ -365,7 +358,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/config-resolver/3.257.0: resolution: {integrity: sha512-jChjr8ayaXoAcUgrRr+JRIJ6bPtEoS+/xW9khpHOmrEX+uBJ7xLPfdS4e6nmxAQpbem9AsUVvf57DXhSh5/nLg==} @@ -376,7 +368,6 @@ packages: '@aws-sdk/util-config-provider': 3.208.0 '@aws-sdk/util-middleware': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/credential-provider-env/3.257.0: resolution: {integrity: sha512-GsmBi5Di6hk1JAi1iB6/LCY8o+GmlCvJoB7wuoVmXI3VxRVwptUVjuj8EtJbIrVGrF9dSuIRPCzUoSuzEzYGlg==} @@ -385,7 +376,6 @@ packages: '@aws-sdk/property-provider': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/credential-provider-imds/3.257.0: resolution: {integrity: sha512-UrxYkHWndy6s/bZZWH2poIyqdISTbILGTcK9tT8cFaUUrNIEFXiVESZMNNaagy0Dyy9wr80ndumxRkutYga9VA==} @@ -396,7 +386,6 @@ packages: '@aws-sdk/types': 3.257.0 '@aws-sdk/url-parser': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/credential-provider-ini/3.257.0: resolution: {integrity: sha512-69jW9/Os2zGBATQR8Urde+IlzicgJPCO/gAWpm4AYJYT5LSGc0pOuZflSXq+ZfKy3jcSoN0yOFxkoMnmZb8pzg==} @@ -413,7 +402,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/credential-provider-node/3.257.0: resolution: {integrity: sha512-yXVNOml/w4ipWiRgLWUphGwISqJQRPjALgTsRa0O+CzpaEc/0HRqM8I78VzCzjsb+QE4EP7MZej6tkEAZYgTlg==} @@ -431,7 +419,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/credential-provider-process/3.257.0: resolution: {integrity: sha512-xK8uYeNXaclaBCGrLi4z2pxPRngqLf5BM5jg2fn57zqvlL9V5gJF972FehrVBL0bfp1/laG0ZJtD2K2sapyWAw==} @@ -441,7 +428,6 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/credential-provider-sso/3.257.0: resolution: {integrity: sha512-I/1TQm6WruqxTTPH+Wo2o+YCLenEY0bWq97EQn+d8Cp0N7cNJUDt8BHF22dQtUzd7bvSspVK5M4qCZKAh3fhOg==} @@ -455,7 +441,6 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/credential-provider-web-identity/3.257.0: resolution: {integrity: sha512-Cm0uvRv4JuIbD0Kp3W0J/vwjADIyCx8HoZi5yg+QIi5nilocuTQ3ajvLeuPVSvFvdy+yaxSc5FxNXquWt7Mngw==} @@ -464,7 +449,6 @@ packages: '@aws-sdk/property-provider': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/fetch-http-handler/3.257.0: resolution: {integrity: sha512-zOF+RzQ+wfF7tq7tGUdPcqUTh3+k2f8KCVJE07A8kCopVq4nBu4NH6Eq29Tjpwdya3YlKvE+kFssuQRRRRex+Q==} @@ -474,7 +458,6 @@ packages: '@aws-sdk/types': 3.257.0 '@aws-sdk/util-base64': 3.208.0 tslib: 2.4.1 - dev: true /@aws-sdk/hash-node/3.257.0: resolution: {integrity: sha512-W/USUuea5Ep3OJ2U7Ve8/5KN1YsDun2WzOFUxc1PyxXP5pW6OgC15/op0e+bmWPG851clvp5S8ZuroUr3aKi3Q==} @@ -484,21 +467,18 @@ packages: '@aws-sdk/util-buffer-from': 3.208.0 '@aws-sdk/util-utf8': 3.254.0 tslib: 2.4.1 - dev: true /@aws-sdk/invalid-dependency/3.257.0: resolution: {integrity: sha512-T68SAPRNMEhpke0wlxURgogL7q0B8dfqZsSeS20BVR/lksJxLse9+pbmCDxiu1RrXoEIsEwl5rbLN+Hw8BFFYw==} dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/is-array-buffer/3.201.0: resolution: {integrity: sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/middleware-content-length/3.257.0: resolution: {integrity: sha512-yiawbV2azm6QnMY1L2ypG8PDRdjOcEIvFmT0T7y0F49rfbKJOu21j1ONAoCkLrINK6kMqcD5JSQLVCoURxiTxQ==} @@ -507,7 +487,6 @@ packages: '@aws-sdk/protocol-http': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-endpoint/3.257.0: resolution: {integrity: sha512-RQNQe/jeVuWZtXXfcOm+e3qMFICY6ERsXUrbt0rjHgvajZCklcrRJgxJSCwrcS7Le3nl9azFPMAMj9L7uSK28g==} @@ -521,7 +500,6 @@ packages: '@aws-sdk/util-config-provider': 3.208.0 '@aws-sdk/util-middleware': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-host-header/3.257.0: resolution: {integrity: sha512-gEi9AJdJfRfU8Qr6HK1hfhxTzyV3Giq4B/h7um99hIFAT/GCg9xiPvAOKPo6UeuiKEv3b7RpSL4s6cBvnJMJBA==} @@ -530,7 +508,6 @@ packages: '@aws-sdk/protocol-http': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-logger/3.257.0: resolution: {integrity: sha512-8RDXW/VbMKBsXDfcCLmROZcWKyrekyiPa3J1aIaBy0tq9o4xpGoXw/lwwIrNVvISAFslb57rteup34bfn6ta6w==} @@ -538,7 +515,6 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-recursion-detection/3.257.0: resolution: {integrity: sha512-rUCih6zHh8k9Edf5N5Er4s508FYbwLM0MWTD2axzlj9TjLqEQ9OKED3wHaLffXSDzodd3oTAfJCLPbWQyoZ3ZQ==} @@ -547,7 +523,6 @@ packages: '@aws-sdk/protocol-http': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-retry/3.257.0: resolution: {integrity: sha512-vDOy4PbSRW2gtgoJZ+yvgyxdlTwbZGpuv/rA2+XYxURmhPMzpmqs4o1DR37LG8O41WouI1rPzA7E+Ffo+iNWjw==} @@ -560,7 +535,6 @@ packages: '@aws-sdk/util-retry': 3.257.0 tslib: 2.4.1 uuid: 8.3.2 - dev: true /@aws-sdk/middleware-sdk-sts/3.257.0: resolution: {integrity: sha512-d6IJCLRi3O2tm4AFK60WNhIwmMmspj1WzKR1q1TaoPzoREPG2xg+Am18wZBRkCyYuRPPrbizmkvAmAJiUolMAw==} @@ -572,7 +546,6 @@ packages: '@aws-sdk/signature-v4': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-serde/3.257.0: resolution: {integrity: sha512-/JasfXPWFq24mnCrx9fxW/ISBSp07RJwhsF14qzm8Qy3Z0z470C+QRM6otTwAkYuuVt1wuLjja5agq3Jtzq7dQ==} @@ -580,7 +553,6 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-signing/3.257.0: resolution: {integrity: sha512-hCH3D83LHmm6nqmtNrGTWZCVjsQXrGHIXbd17/qrw7aPFvcAhsiiCncGFP+XsUXEKa2ZqcSNMUyPrx69ofNRZQ==} @@ -592,14 +564,12 @@ packages: '@aws-sdk/types': 3.257.0 '@aws-sdk/util-middleware': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/middleware-stack/3.257.0: resolution: {integrity: sha512-awg2F0SvwACBaw4HIObK8pQGfSqAc4Vy+YFzWSfZNVC35oRO6RsRdKHVU99lRC0LrT2Ptmfghl2DMPSrRDbvlQ==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/middleware-user-agent/3.257.0: resolution: {integrity: sha512-37rt75LZyD0UWpbcFuxEGqwF3DZKSixQPl7AsDe6q3KtrO5gGQB+diH5vbY0txNNYyv5IK9WMwvY73mVmoWRmw==} @@ -608,7 +578,6 @@ packages: '@aws-sdk/protocol-http': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/node-config-provider/3.257.0: resolution: {integrity: sha512-IfGF7+cU0PyB7RpHlgc445ZAUZDWn4ij2HTB6N+xULwFw2TxnyQ2tvo3Gp5caW9VlJ3eXE9wFrynv+JXUIH7Bg==} @@ -618,7 +587,6 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/node-http-handler/3.257.0: resolution: {integrity: sha512-8KnWHVVwaGKyTlkTU9BSOAiSovNDoagxemU2l10QqBbzUCVpljCUMUkABEGRJ1yoQCl6DJ7RtNkAyZ8Ne/E15A==} @@ -629,7 +597,6 @@ packages: '@aws-sdk/querystring-builder': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/property-provider/3.257.0: resolution: {integrity: sha512-3rUbRAcF0GZ5PhDiXhS4yREfZ5hOEtvYEa9S/19OdM5eoypOaLU5XnFcCKfnccSP8SkdgpJujzxOMRWNWadlAQ==} @@ -637,7 +604,6 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/protocol-http/3.257.0: resolution: {integrity: sha512-xt7LGOgZIvbLS3418AYQLacOqx+mo5j4mPiIMz7f6AaUg+/fBUgESVsncKDqxbEJVwwCXSka8Ca0cntJmoeMSw==} @@ -645,7 +611,6 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/querystring-builder/3.257.0: resolution: {integrity: sha512-mZHWLP7XIkzx1GIXO5WfX/iJ+aY9TWs02RE9FkdL2+by0HEMR65L3brQTbU1mIBJ7BjaPwYH24dljUOSABX7yg==} @@ -654,7 +619,6 @@ packages: '@aws-sdk/types': 3.257.0 '@aws-sdk/util-uri-escape': 3.201.0 tslib: 2.4.1 - dev: true /@aws-sdk/querystring-parser/3.257.0: resolution: {integrity: sha512-UDrE1dEwWrWT8dG2VCrGYrPxCWOkZ1fPTPkjpkR4KZEdQDZBqU5gYZF2xPj8Nz7pjQVHFuW2wFm3XYEk56GEjg==} @@ -662,12 +626,10 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/service-error-classification/3.257.0: resolution: {integrity: sha512-FAyR0XsueGkkqDtkP03cTJQk52NdQ9sZelLynmmlGPUP75LApRPvFe1riKrou6+LsDbwVNVffj6mbDfIcOhaOw==} engines: {node: '>=14.0.0'} - dev: true /@aws-sdk/shared-ini-file-loader/3.257.0: resolution: {integrity: sha512-HNjC1+Wx3xHiJc+CP14GhIdVhfQGSjroAsWseRxAhONocA9Fl1ZX4hx7+sA5c9nOoMVOovi6ivJ/6lCRPTDRrQ==} @@ -675,7 +637,6 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/signature-v4/3.257.0: resolution: {integrity: sha512-aLQQN59X/D0+ShzPD3Anj5ntdMA/RFeNLOUCDyDvremViGi6yxUS98usQ/8bG5Rq0sW2GGMdbFUFmrDvqdiqEQ==} @@ -688,7 +649,6 @@ packages: '@aws-sdk/util-uri-escape': 3.201.0 '@aws-sdk/util-utf8': 3.254.0 tslib: 2.4.1 - dev: true /@aws-sdk/smithy-client/3.257.0: resolution: {integrity: sha512-Vy/en+llpslHG6WZ2yuN+On6u7p2hROEURwAST/lpReAwBETjbsxylkWvP8maeGKQ54u9uC6lIZAOJut2I3INw==} @@ -697,7 +657,6 @@ packages: '@aws-sdk/middleware-stack': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/token-providers/3.257.0: resolution: {integrity: sha512-Ysd1dpWiI2oBOrJpkSJkgPsY0dwMtavIBzF3d5JYN1HCl14Aqc2jcNqBjD+7nEeL6CHXcFeyB7jmCDqiuP0V3A==} @@ -710,14 +669,12 @@ packages: tslib: 2.4.1 transitivePeerDependencies: - aws-crt - dev: true /@aws-sdk/types/3.257.0: resolution: {integrity: sha512-LmqXuBQBGeaGi/3Rp7XiEX1B5IPO2UUfBVvu0wwGqVsmstT0SbOVDZGPmxygACbm64n+PRx3uTSDefRfoiWYZg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/url-parser/3.257.0: resolution: {integrity: sha512-Qe/AcFe/NFZHa6cN2afXEQn9ehXxh57dWGdRjfjd2lQqNV4WW1R2pl2Tm1ZJ1dwuCNLJi4NHLMk8lrD3QQ8rdg==} @@ -725,7 +682,6 @@ packages: '@aws-sdk/querystring-parser': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-base64/3.208.0: resolution: {integrity: sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==} @@ -733,20 +689,17 @@ packages: dependencies: '@aws-sdk/util-buffer-from': 3.208.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-body-length-browser/3.188.0: resolution: {integrity: sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-body-length-node/3.208.0: resolution: {integrity: sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-buffer-from/3.208.0: resolution: {integrity: sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==} @@ -754,14 +707,12 @@ packages: dependencies: '@aws-sdk/is-array-buffer': 3.201.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-config-provider/3.208.0: resolution: {integrity: sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-defaults-mode-browser/3.257.0: resolution: {integrity: sha512-nkfK+MNacVd3Px/fcAvU0hDeh+r7d+RLLt3sJ5Zc0gGd+i3OQEP58V8QzR9PYMvUvSvGQP16fQVQHSbRZtuWyQ==} @@ -771,7 +722,6 @@ packages: '@aws-sdk/types': 3.257.0 bowser: 2.11.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-defaults-mode-node/3.257.0: resolution: {integrity: sha512-qsIb7aPbGFcKbBGoAQmlzv1gMcscgbpfrRh4rgNqkJXVbJ52Ql6+vXXfBmlWaBho0fcsNh5XnYu1fzdCuu+N7g==} @@ -783,7 +733,6 @@ packages: '@aws-sdk/property-provider': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-endpoints/3.257.0: resolution: {integrity: sha512-3bvmRn5XGYzPPWjLuvHBKdJOb+fijnb8Ungu9bfXnTYFsng/ndHUWeHC22O/p8w3OWoRYUIMaZHxdxe27BFozg==} @@ -791,28 +740,24 @@ packages: dependencies: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-hex-encoding/3.201.0: resolution: {integrity: sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-locate-window/3.208.0: resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-middleware/3.257.0: resolution: {integrity: sha512-F9ieon8B8eGVs5tyZtAIG3DZEObDvujkspho0qRbUTHUosM0ylJLsMU800fmC/uRHLRrZvb/RSp59+kNDwSAMw==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-retry/3.257.0: resolution: {integrity: sha512-l9TOsOAYtZxwW3q5fQKW4rsD9t2HVaBfQ4zBamHkNTfB4vBVvCnz4oxkvSvA2MlxCA6am+K1K/oj917Tpqk53g==} @@ -820,14 +765,12 @@ packages: dependencies: '@aws-sdk/service-error-classification': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-uri-escape/3.201.0: resolution: {integrity: sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==} engines: {node: '>=14.0.0'} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-user-agent-browser/3.257.0: resolution: {integrity: sha512-YdavWK6/8Cw6mypEgysGGX/dT9p9qnzFbnN5PQsUY+JJk2Nx8fKFydjGiQ+6rWPeW17RAv9mmbboh9uPVWxVlw==} @@ -835,7 +778,6 @@ packages: '@aws-sdk/types': 3.257.0 bowser: 2.11.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-user-agent-node/3.257.0: resolution: {integrity: sha512-fOHh80kiVomUkABmOv3ZxB/SNLnOPAja7uhQmGWfKHXBkcxTVfWO2KBs5vzU5qhVZA0c1zVEvZPcBdRsonnhlw==} @@ -849,13 +791,11 @@ packages: '@aws-sdk/node-config-provider': 3.257.0 '@aws-sdk/types': 3.257.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-utf8-browser/3.188.0: resolution: {integrity: sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==} dependencies: tslib: 2.4.1 - dev: true /@aws-sdk/util-utf8-node/3.208.0: resolution: {integrity: sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==} @@ -863,7 +803,6 @@ packages: dependencies: '@aws-sdk/util-buffer-from': 3.208.0 tslib: 2.4.1 - dev: true /@aws-sdk/util-utf8/3.254.0: resolution: {integrity: sha512-14Kso/eIt5/qfIBmhEL9L1IfyUqswjSTqO2mY7KOzUZ9SZbwn3rpxmtkhmATkRjD7XIlLKaxBkI7tU9Zjzj8Kw==} @@ -871,7 +810,6 @@ packages: dependencies: '@aws-sdk/util-buffer-from': 3.208.0 tslib: 2.4.1 - dev: true /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} @@ -1842,7 +1780,6 @@ packages: /bowser/2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - dev: true /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -2949,7 +2886,6 @@ packages: hasBin: true dependencies: strnum: 1.0.5 - dev: true /fastq/1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} @@ -4438,7 +4374,6 @@ packages: /strnum/1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - dev: true /supertap/3.0.1: resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} @@ -4548,11 +4483,9 @@ packages: /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - dev: true /tsx/3.12.2: resolution: {integrity: sha512-ykAEkoBg30RXxeOMVeZwar+JH632dZn9EUJVyJwhfag62k6UO/dIyJEV58YuLF6e5BTdV/qmbQrpkWqjq9cUnQ==} @@ -4699,7 +4632,6 @@ packages: /uuid/8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - dev: true /uuid/9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} From c774111b53e8aa612963c4e484c81fb8bc8f74c9 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Thu, 26 Jan 2023 20:12:23 +0200 Subject: [PATCH 3/5] Add test connections --- integration-tests/package.json | 1 + integration-tests/tests/awsdatapi.test.ts | 3 +- pnpm-lock.yaml | 266 ++++++++++++++++++++++ 3 files changed, 269 insertions(+), 1 deletion(-) diff --git a/integration-tests/package.json b/integration-tests/package.json index ce46139a3..089f16f45 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -34,6 +34,7 @@ }, "dependencies": { "@aws-sdk/client-rds-data": "^3.257.0", + "@aws-sdk/credential-providers": "^3.258.0", "better-sqlite3": "^7.6.2", "dockerode": "^3.3.4", "drizzle-orm": "workspace:../drizzle-orm/dist", diff --git a/integration-tests/tests/awsdatapi.test.ts b/integration-tests/tests/awsdatapi.test.ts index cc1727c1d..b0d8c387e 100644 --- a/integration-tests/tests/awsdatapi.test.ts +++ b/integration-tests/tests/awsdatapi.test.ts @@ -1,4 +1,5 @@ import { RDSDataClient } from '@aws-sdk/client-rds-data'; +import { fromIni } from '@aws-sdk/credential-providers'; import anyTest, { TestFn } from 'ava'; import Docker from 'dockerode'; import { sql } from 'drizzle-orm'; @@ -88,7 +89,7 @@ test.before(async (t) => { const secretArn = process.env['AWS_DATA_API_SECRET_ARN']!; const resourceArn = process.env['AWS_DATA_API_RESOURCE_ARN']!; - const rdsClient = new RDSDataClient({}); + const rdsClient = new RDSDataClient({ credentials: fromIni({ profile: process.env['AWS_TEST_PROFILE'] }) }); ctx.db = drizzle(rdsClient, { database, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f93b44559..b5ab844a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -97,6 +97,7 @@ importers: integration-tests: specifiers: '@aws-sdk/client-rds-data': ^3.257.0 + '@aws-sdk/credential-providers': ^3.258.0 '@types/better-sqlite3': ^7.6.3 '@types/dockerode': ^3.3.14 '@types/node': ^18.11.18 @@ -118,6 +119,7 @@ importers: uvu: ^0.5.6 dependencies: '@aws-sdk/client-rds-data': 3.257.0 + '@aws-sdk/credential-providers': 3.258.0 better-sqlite3: 7.6.2 dockerode: 3.3.4 drizzle-orm: link:../drizzle-orm/dist @@ -192,6 +194,49 @@ packages: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 + /@aws-sdk/client-cognito-identity/3.258.0: + resolution: {integrity: sha512-xLKwJ2Q+KEyR4mRc1tNs6j2/O0SPzsD73Lbj4WRDP2Y+4JvZpn6JDihyc2OBs4JszObWOBmr2kotwHtG218WiA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.258.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.258.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-rds-data/3.257.0: resolution: {integrity: sha512-9Tx61790pBKwhVFM+F0iQ0tXsykIXvuypILwepkv3p+6j5DkAIrCL/7UN1jyl1vmPZhYjCp3z96/+d91bW6sNw==} engines: {node: '>=14.0.0'} @@ -275,6 +320,46 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/client-sso-oidc/3.258.0: + resolution: {integrity: sha512-YHQcoDsf5nnFfDJiG4uHxIg+DI90y7NpLrpx7233SeGuMNfzK2BOxHMNCZhMAxJHKB3TVpD0aN4NshVvBpcSdQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-sso/3.257.0: resolution: {integrity: sha512-sD0yTTctLbjDoSV3hJem+xz9BzusmkkU/4Fts9gEs4C5NjS0YrfPAvQWE++yRzPLPR/dMhDFVCOs7voTzUhUWQ==} engines: {node: '>=14.0.0'} @@ -315,6 +400,46 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/client-sso/3.258.0: + resolution: {integrity: sha512-7q5GxPUD3ME/bVUfIxDZjCpNhgM/H0Cdq3sTAbrKWsxbGZDSepeysN+oxabCj9hi2TP1SENJ4gVuArejtqqfHA==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/client-sts/3.257.0: resolution: {integrity: sha512-AVNngoDGACR7xs9wTU7hrZSvMfNOGvWP/B/ieA0au3H3KDucjCZzBd3j2vYkR6Cph9dY7YkpU2Gtzn+JXD0b1g==} engines: {node: '>=14.0.0'} @@ -359,6 +484,50 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/client-sts/3.258.0: + resolution: {integrity: sha512-L6dMn5hrHgUjoY6LebmeJ3JB/xPerkVfzjel6G0ilMYSmtdAsYDe4Ik8hvTxdg06WPT9SfnrZltilESU+T8SBw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/config-resolver': 3.257.0 + '@aws-sdk/credential-provider-node': 3.258.0 + '@aws-sdk/fetch-http-handler': 3.257.0 + '@aws-sdk/hash-node': 3.257.0 + '@aws-sdk/invalid-dependency': 3.257.0 + '@aws-sdk/middleware-content-length': 3.257.0 + '@aws-sdk/middleware-endpoint': 3.257.0 + '@aws-sdk/middleware-host-header': 3.257.0 + '@aws-sdk/middleware-logger': 3.257.0 + '@aws-sdk/middleware-recursion-detection': 3.257.0 + '@aws-sdk/middleware-retry': 3.257.0 + '@aws-sdk/middleware-sdk-sts': 3.257.0 + '@aws-sdk/middleware-serde': 3.257.0 + '@aws-sdk/middleware-signing': 3.257.0 + '@aws-sdk/middleware-stack': 3.257.0 + '@aws-sdk/middleware-user-agent': 3.257.0 + '@aws-sdk/node-config-provider': 3.257.0 + '@aws-sdk/node-http-handler': 3.257.0 + '@aws-sdk/protocol-http': 3.257.0 + '@aws-sdk/smithy-client': 3.257.0 + '@aws-sdk/types': 3.257.0 + '@aws-sdk/url-parser': 3.257.0 + '@aws-sdk/util-base64': 3.208.0 + '@aws-sdk/util-body-length-browser': 3.188.0 + '@aws-sdk/util-body-length-node': 3.208.0 + '@aws-sdk/util-defaults-mode-browser': 3.257.0 + '@aws-sdk/util-defaults-mode-node': 3.257.0 + '@aws-sdk/util-endpoints': 3.257.0 + '@aws-sdk/util-retry': 3.257.0 + '@aws-sdk/util-user-agent-browser': 3.257.0 + '@aws-sdk/util-user-agent-node': 3.257.0 + '@aws-sdk/util-utf8': 3.254.0 + fast-xml-parser: 4.0.11 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/config-resolver/3.257.0: resolution: {integrity: sha512-jChjr8ayaXoAcUgrRr+JRIJ6bPtEoS+/xW9khpHOmrEX+uBJ7xLPfdS4e6nmxAQpbem9AsUVvf57DXhSh5/nLg==} engines: {node: '>=14.0.0'} @@ -369,6 +538,18 @@ packages: '@aws-sdk/util-middleware': 3.257.0 tslib: 2.4.1 + /@aws-sdk/credential-provider-cognito-identity/3.258.0: + resolution: {integrity: sha512-V5Z+vJ4eT4Sg0u0k1OPEPmhyixwFpS094KimC/nfcGXNQnxAkIQEKT+pD1DNenxWKBta4434l+BJUozpj64oCQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-cognito-identity': 3.258.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/credential-provider-env/3.257.0: resolution: {integrity: sha512-GsmBi5Di6hk1JAi1iB6/LCY8o+GmlCvJoB7wuoVmXI3VxRVwptUVjuj8EtJbIrVGrF9dSuIRPCzUoSuzEzYGlg==} engines: {node: '>=14.0.0'} @@ -403,6 +584,23 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/credential-provider-ini/3.258.0: + resolution: {integrity: sha512-vwy3wcIzdiBUd+kX6wKqY59JHRyOKgkPgwvd2nZt4QSQUXAldGROx48fgp/SZUEVveBpHg6Zm3IrdUWaQtAemg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.258.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/credential-provider-node/3.257.0: resolution: {integrity: sha512-yXVNOml/w4ipWiRgLWUphGwISqJQRPjALgTsRa0O+CzpaEc/0HRqM8I78VzCzjsb+QE4EP7MZej6tkEAZYgTlg==} engines: {node: '>=14.0.0'} @@ -420,6 +618,24 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/credential-provider-node/3.258.0: + resolution: {integrity: sha512-2OTFqKkfpkLZ7nkxztOIsEembl3wYhl4aAutRN5bCu8tunREWzr7v7t6X96+8CuYqcCjNYHs/9ChgFh19uokEg==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-ini': 3.258.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.258.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/credential-provider-process/3.257.0: resolution: {integrity: sha512-xK8uYeNXaclaBCGrLi4z2pxPRngqLf5BM5jg2fn57zqvlL9V5gJF972FehrVBL0bfp1/laG0ZJtD2K2sapyWAw==} engines: {node: '>=14.0.0'} @@ -442,6 +658,20 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/credential-provider-sso/3.258.0: + resolution: {integrity: sha512-2QbrpBgqabcmZkvbDLZKf8Lq99K64UsJwNkSJ+6v6+ZQQgeGIlqYaAVfrsbreCazzGcxOy0xr8DiwGrI9ZE1zQ==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.258.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/token-providers': 3.258.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/credential-provider-web-identity/3.257.0: resolution: {integrity: sha512-Cm0uvRv4JuIbD0Kp3W0J/vwjADIyCx8HoZi5yg+QIi5nilocuTQ3ajvLeuPVSvFvdy+yaxSc5FxNXquWt7Mngw==} engines: {node: '>=14.0.0'} @@ -450,6 +680,29 @@ packages: '@aws-sdk/types': 3.257.0 tslib: 2.4.1 + /@aws-sdk/credential-providers/3.258.0: + resolution: {integrity: sha512-/wjbuaJCClp3Ywl50oR4AV7nbSeLTzOYLvPjFJoAXvBf7OsE1544HkJJi7Y31N/gbZKAY+ReDp0vfz3QhGdJIw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-cognito-identity': 3.258.0 + '@aws-sdk/client-sso': 3.258.0 + '@aws-sdk/client-sts': 3.258.0 + '@aws-sdk/credential-provider-cognito-identity': 3.258.0 + '@aws-sdk/credential-provider-env': 3.257.0 + '@aws-sdk/credential-provider-imds': 3.257.0 + '@aws-sdk/credential-provider-ini': 3.258.0 + '@aws-sdk/credential-provider-node': 3.258.0 + '@aws-sdk/credential-provider-process': 3.257.0 + '@aws-sdk/credential-provider-sso': 3.258.0 + '@aws-sdk/credential-provider-web-identity': 3.257.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/fetch-http-handler/3.257.0: resolution: {integrity: sha512-zOF+RzQ+wfF7tq7tGUdPcqUTh3+k2f8KCVJE07A8kCopVq4nBu4NH6Eq29Tjpwdya3YlKvE+kFssuQRRRRex+Q==} dependencies: @@ -670,6 +923,19 @@ packages: transitivePeerDependencies: - aws-crt + /@aws-sdk/token-providers/3.258.0: + resolution: {integrity: sha512-5Lme7XHlBC/iPHQOr5V+LdxHnwg2a7mhRYVy42a8OOKHN2ronDo/Wnujw2s4BOaEnlqS8OSV84bZ0bWxVYuvKw==} + engines: {node: '>=14.0.0'} + dependencies: + '@aws-sdk/client-sso-oidc': 3.258.0 + '@aws-sdk/property-provider': 3.257.0 + '@aws-sdk/shared-ini-file-loader': 3.257.0 + '@aws-sdk/types': 3.257.0 + tslib: 2.4.1 + transitivePeerDependencies: + - aws-crt + dev: false + /@aws-sdk/types/3.257.0: resolution: {integrity: sha512-LmqXuBQBGeaGi/3Rp7XiEX1B5IPO2UUfBVvu0wwGqVsmstT0SbOVDZGPmxygACbm64n+PRx3uTSDefRfoiWYZg==} engines: {node: '>=14.0.0'} From cb431d8dc3835024b95b4055c04a576516cd7301 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 31 Jan 2023 21:51:08 +0200 Subject: [PATCH 4/5] Add pg aws dataapi full support --- drizzle-orm/src/aws-data-api/common/index.ts | 72 +++ .../pg}/driver.ts | 33 +- .../{aws-dataapi => aws-data-api/pg}/index.ts | 0 .../pg}/migrator.ts | 4 +- .../pg}/session.ts | 100 ++--- .../src/mysql-core/query-builders/delete.ts | 7 +- .../src/mysql-core/query-builders/insert.ts | 7 +- .../src/mysql-core/query-builders/select.ts | 7 +- .../src/mysql-core/query-builders/update.ts | 7 +- .../src/pg-core/query-builders/delete.ts | 7 +- .../src/pg-core/query-builders/insert.ts | 7 +- .../src/pg-core/query-builders/select.ts | 7 +- .../src/pg-core/query-builders/update.ts | 7 +- drizzle-orm/src/sql/index.ts | 30 +- .../src/sqlite-core/query-builders/delete.ts | 7 +- .../src/sqlite-core/query-builders/insert.ts | 7 +- .../src/sqlite-core/query-builders/select.ts | 8 +- .../src/sqlite-core/query-builders/update.ts | 7 +- integration-tests/.env.example | 4 + .../drizzle/pg/20221207173503/migration.sql | 2 +- integration-tests/package.json | 3 + .../tests/awsdatapi.alltypes.test.ts | 409 ++++++++++++++++++ integration-tests/tests/awsdatapi.test.ts | 118 ++--- pnpm-lock.yaml | 7 + 24 files changed, 671 insertions(+), 196 deletions(-) create mode 100644 drizzle-orm/src/aws-data-api/common/index.ts rename drizzle-orm/src/{aws-dataapi => aws-data-api/pg}/driver.ts (70%) rename drizzle-orm/src/{aws-dataapi => aws-data-api/pg}/index.ts (100%) rename drizzle-orm/src/{aws-dataapi => aws-data-api/pg}/migrator.ts (98%) rename drizzle-orm/src/{aws-dataapi => aws-data-api/pg}/session.ts (63%) create mode 100644 integration-tests/tests/awsdatapi.alltypes.test.ts diff --git a/drizzle-orm/src/aws-data-api/common/index.ts b/drizzle-orm/src/aws-data-api/common/index.ts new file mode 100644 index 000000000..dbb899f04 --- /dev/null +++ b/drizzle-orm/src/aws-data-api/common/index.ts @@ -0,0 +1,72 @@ +import { Field, TypeHint } from "@aws-sdk/client-rds-data"; +import { QueryTypingsValue } from "~/sql"; + +export function getValueFromDataApi(row: Field) { + if (typeof row.stringValue !== 'undefined') { + return row.stringValue; + } else if (typeof row.booleanValue !== 'undefined') { + return row.booleanValue; + } else if (typeof row.doubleValue !== 'undefined') { + return row.doubleValue; + } else if (typeof row.isNull !== 'undefined') { + return null; + } else if (typeof row.longValue !== 'undefined') { + return row.longValue; + } else if (typeof row.blobValue !== 'undefined') { + return row.blobValue; + } else if (typeof row.arrayValue !== 'undefined') { + if (typeof row.arrayValue.stringValues !== 'undefined') { + return row.arrayValue.stringValues; + } + throw Error('Unknown array type'); + } else { + throw Error('Unknown type'); + } +} + +export function typingsToAwsTypeHint(typings?: QueryTypingsValue): TypeHint | undefined { + if (typings === 'date') { + return TypeHint.DATE; + } else if (typings === 'decimal') { + return TypeHint.DECIMAL; + } else if (typings === 'json') { + return TypeHint.JSON; + } else if (typings === 'time') { + return TypeHint.TIME; + } else if (typings === 'timestamp') { + return TypeHint.TIMESTAMP; + } else if (typings === 'uuid') { + return TypeHint.UUID; + } else { + return undefined; + } +} + +export function toValueParam(value: any, typings?: QueryTypingsValue): { value: Field; typeHint?: TypeHint } { + let response: { value: Field; typeHint?: TypeHint } = { + value: {} as any, + typeHint: typingsToAwsTypeHint(typings), + }; + + if (value === null) { + response.value = { isNull: true }; + } else if (typeof value === 'string') { + if (response.typeHint === 'DATE') { + response.value = { stringValue: value.split('T')[0]! }; + } else { + response.value = { stringValue: value }; + } + } else if (typeof value === 'number' && Number.isInteger(value)) { + response.value = { longValue: value }; + } else if (typeof value === 'number' && !Number.isInteger(value)) { + response.value = { doubleValue: value }; + } else if (typeof value === 'boolean') { + response.value = { booleanValue: value }; + } else if (value instanceof Date) { + response.value = { stringValue: value.toISOString().replace('T', ' ').replace('Z', '') }; + } else { + throw Error(`Unknown type for ${value}`); + } + + return response; +} \ No newline at end of file diff --git a/drizzle-orm/src/aws-dataapi/driver.ts b/drizzle-orm/src/aws-data-api/pg/driver.ts similarity index 70% rename from drizzle-orm/src/aws-dataapi/driver.ts rename to drizzle-orm/src/aws-data-api/pg/driver.ts index 8edf3be81..9a743b9f7 100644 --- a/drizzle-orm/src/aws-dataapi/driver.ts +++ b/drizzle-orm/src/aws-data-api/pg/driver.ts @@ -5,9 +5,9 @@ import { AwsDataApiClient, AwsDataApiPgQueryResultHKT, AwsDataApiSession } from export interface PgDriverOptions { logger?: Logger; - database: string, - resourceArn: string, - secretArn: string, + database: string; + resourceArn: string; + secretArn: string; } export class AwsDataApiDriver { @@ -16,32 +16,35 @@ export class AwsDataApiDriver { private dialect: PgDialect, private options: PgDriverOptions, ) { - this.initMappers(); } createSession(): AwsDataApiSession { return new AwsDataApiSession(this.client, this.dialect, this.options); } - - initMappers() { - // types.setTypeParser(types.builtins.TIMESTAMPTZ, (val) => val); - // types.setTypeParser(types.builtins.TIMESTAMP, (val) => val); - // types.setTypeParser(types.builtins.DATE, (val) => val); - } } export interface DrizzleConfig { logger?: Logger; - database: string, - resourceArn: string, - secretArn: string, + database: string; + resourceArn: string; + secretArn: string; } export type AwsDataApiPgDatabase = PgDatabase; +export class AwsPgDialect extends PgDialect { + override escapeName(name: string): string { + return `"${name}"`; + } + + override escapeParam(num: number): string { + return `:${num + 1}`; + } +} + export function drizzle(client: AwsDataApiClient, config: DrizzleConfig): AwsDataApiPgDatabase { - const dialect = new PgDialect(); + const dialect = new AwsPgDialect(); const driver = new AwsDataApiDriver(client, dialect, config); const session = driver.createSession(); return new PgDatabase(dialect, session); -} \ No newline at end of file +} diff --git a/drizzle-orm/src/aws-dataapi/index.ts b/drizzle-orm/src/aws-data-api/pg/index.ts similarity index 100% rename from drizzle-orm/src/aws-dataapi/index.ts rename to drizzle-orm/src/aws-data-api/pg/index.ts diff --git a/drizzle-orm/src/aws-dataapi/migrator.ts b/drizzle-orm/src/aws-data-api/pg/migrator.ts similarity index 98% rename from drizzle-orm/src/aws-dataapi/migrator.ts rename to drizzle-orm/src/aws-data-api/pg/migrator.ts index 18ba64b24..30f98853b 100644 --- a/drizzle-orm/src/aws-dataapi/migrator.ts +++ b/drizzle-orm/src/aws-data-api/pg/migrator.ts @@ -33,7 +33,7 @@ export async function migrate(db: AwsDataApiPgDatabase, config: string | Migrati await session.executeWithTransaction(sql.raw(migration.sql), transactionId); await session.executeWithTransaction( sql`INSERT INTO "drizzle"."__drizzle_migrations" ("hash", "created_at") VALUES(${migration.hash}, ${migration.folderMillis})`, - transactionId + transactionId, ); } } @@ -43,4 +43,4 @@ export async function migrate(db: AwsDataApiPgDatabase, config: string | Migrati await session.rollbackTransaction(transactionId!); throw e; } -} \ No newline at end of file +} diff --git a/drizzle-orm/src/aws-dataapi/session.ts b/drizzle-orm/src/aws-data-api/pg/session.ts similarity index 63% rename from drizzle-orm/src/aws-dataapi/session.ts rename to drizzle-orm/src/aws-data-api/pg/session.ts index 1c4910803..5a091db51 100644 --- a/drizzle-orm/src/aws-dataapi/session.ts +++ b/drizzle-orm/src/aws-data-api/pg/session.ts @@ -4,8 +4,7 @@ import { CommitTransactionCommand, CommitTransactionCommandInput, ExecuteStatementCommand, - ExecuteStatementRequest, - Field, + ExecuteStatementCommandOutput, RDSDataClient, RollbackTransactionCommand, RollbackTransactionCommandInput, @@ -13,8 +12,9 @@ import { import { Logger } from '~/logger'; import { SelectFieldsOrdered } from '~/operations'; import { PgDialect, PgSession, PreparedQuery, PreparedQueryConfig, QueryResultHKT } from '~/pg-core'; -import { fillPlaceholders, Query, SQL } from '~/sql'; +import { fillPlaceholders, Query, QueryTypingsValue, SQL } from '~/sql'; import { mapResultRow } from '~/utils'; +import { getValueFromDataApi, toValueParam } from '../common'; export type AwsDataApiClient = RDSDataClient; @@ -25,6 +25,7 @@ export class AwsDataApiPreparedQuery extends Prep private client: AwsDataApiClient, queryString: string, private params: unknown[], + private typings: QueryTypingsValue[], private options: AwsDataApiSessionOptions, private fields: SelectFieldsOrdered | undefined, name: string | undefined, @@ -41,59 +42,25 @@ export class AwsDataApiPreparedQuery extends Prep }); } - private getValueFromDataApi(row: Field) { - if (typeof row.stringValue !== 'undefined') { - return row.stringValue; - } else if (typeof row.booleanValue !== 'undefined') { - return row.booleanValue; - } else if (typeof row.doubleValue !== 'undefined') { - return row.doubleValue; - } else if (typeof row.isNull !== 'undefined') { - return null; - } else if (typeof row.longValue !== 'undefined') { - return row.longValue; - } else if (typeof row.blobValue !== 'undefined') { - return row.blobValue; - } else if (typeof row.arrayValue !== 'undefined') { - if (typeof row.arrayValue.stringValues !== 'undefined') { - return row.arrayValue.stringValues; - } - throw Error('Unknown array type'); - } else { - throw Error('Unknown type'); - } - } - - private toValueParam(row: any): Field { - if (typeof row === 'string') { - return { stringValue: row }; - } else if (typeof row === 'number' && Number.isInteger(row)) { - return { longValue: row }; - } else if (typeof row === 'number' && !Number.isInteger(row)) { - return { doubleValue: row }; - } else if (typeof row === 'boolean') { - return { booleanValue: row }; - } else { - throw Error('Unknown type'); - } - } - async execute(placeholderValues: Record | undefined = {}): Promise { const params = fillPlaceholders(this.params, placeholderValues); - this.options.logger?.logQuery(this.rawQuery.input.sql!, params); + this.rawQuery.input.parameters = params.map((param, index) => ({ + name: `${index + 1}`, + ...toValueParam(param, this.typings[index]), + })); - this.rawQuery.input.parameters = params.map((param, _) => ({ name: `${_ + 1}`, value: this.toValueParam(param) })); + this.options.logger?.logQuery(this.rawQuery.input.sql!, this.rawQuery.input.parameters); const { fields } = this; if (!fields) { - return (await this.client.send(this.rawQuery)).records; + return await this.client.send(this.rawQuery); } const result = await this.client.send(this.rawQuery); return result.records?.map((result) => { - const mappedResult = result.map((res) => this.getValueFromDataApi(res)); + const mappedResult = result.map((res) => getValueFromDataApi(res)); return mapResultRow(fields, mappedResult); }); } @@ -135,7 +102,16 @@ export class AwsDataApiSession extends PgSession { fields: SelectFieldsOrdered | undefined, name: string | undefined, ): PreparedQuery { - return new AwsDataApiPreparedQuery(this.client, query.sql, query.params, this.options, fields, name, undefined); + return new AwsDataApiPreparedQuery( + this.client, + query.sql, + query.params, + query.typings ?? [], + this.options, + fields, + name, + undefined, + ); } prepareQueryWithTransaction( @@ -144,19 +120,21 @@ export class AwsDataApiSession extends PgSession { name: string | undefined, transactionId: string | undefined, ): PreparedQuery { - return new AwsDataApiPreparedQuery(this.client, query.sql, query.params, this.options, fields, name, transactionId); + return new AwsDataApiPreparedQuery( + this.client, + query.sql, + query.params, + query.typings ?? [], + this.options, + fields, + name, + transactionId, + ); } executeWithTransaction(query: SQL, transactionId: string | undefined): Promise { return this.prepareQueryWithTransaction( - query.toQuery({ - escapeName: (num) => { - return `"${num}"`; - }, - escapeParam: (num) => { - return `:${num + 1}`; - }, - }), + this.dialect.sqlToQuery(query), undefined, undefined, transactionId, @@ -165,14 +143,7 @@ export class AwsDataApiSession extends PgSession { override execute(query: SQL): Promise { return this.prepareQuery( - query.toQuery({ - escapeName: (num) => { - return `"${num}"`; - }, - escapeParam: (num) => { - return `:${num + 1}`; - }, - }), + this.dialect.sqlToQuery(query), undefined, undefined, ).execute(); @@ -193,6 +164,5 @@ export class AwsDataApiSession extends PgSession { } export interface AwsDataApiPgQueryResultHKT extends QueryResultHKT { - // check types and get from aws dataapi - type: any; -} \ No newline at end of file + type: ExecuteStatementCommandOutput; +} diff --git a/drizzle-orm/src/mysql-core/query-builders/delete.ts b/drizzle-orm/src/mysql-core/query-builders/delete.ts index e83837ac8..23f7548ab 100644 --- a/drizzle-orm/src/mysql-core/query-builders/delete.ts +++ b/drizzle-orm/src/mysql-core/query-builders/delete.ts @@ -54,8 +54,9 @@ export class MySqlDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -63,7 +64,7 @@ export class MySqlDelete< execute: MySqlRawQueryResult; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/mysql-core/query-builders/insert.ts b/drizzle-orm/src/mysql-core/query-builders/insert.ts index 21a326e8f..7a2a7a76b 100644 --- a/drizzle-orm/src/mysql-core/query-builders/insert.ts +++ b/drizzle-orm/src/mysql-core/query-builders/insert.ts @@ -98,8 +98,9 @@ export class MySqlInsert e return this.dialect.buildInsertQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -107,7 +108,7 @@ export class MySqlInsert e execute: MySqlRawQueryResult; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index f5a7b8b60..c50cc010a 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -149,8 +149,9 @@ export class MySqlSelect< return this.dialect.buildSelectQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -158,7 +159,7 @@ export class MySqlSelect< execute: SelectResult[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.fields, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.fields, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/mysql-core/query-builders/update.ts b/drizzle-orm/src/mysql-core/query-builders/update.ts index 64f5aa472..fca54d234 100644 --- a/drizzle-orm/src/mysql-core/query-builders/update.ts +++ b/drizzle-orm/src/mysql-core/query-builders/update.ts @@ -83,8 +83,9 @@ export class MySqlUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -92,7 +93,7 @@ export class MySqlUpdate< execute: MySqlRawQueryResult; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/delete.ts b/drizzle-orm/src/pg-core/query-builders/delete.ts index 93985aa7e..08aba00a0 100644 --- a/drizzle-orm/src/pg-core/query-builders/delete.ts +++ b/drizzle-orm/src/pg-core/query-builders/delete.ts @@ -58,8 +58,9 @@ export class PgDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -67,7 +68,7 @@ export class PgDelete< execute: TReturning extends undefined ? QueryResultKind : TReturning[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/insert.ts b/drizzle-orm/src/pg-core/query-builders/insert.ts index b3cf594da..191f26e47 100644 --- a/drizzle-orm/src/pg-core/query-builders/insert.ts +++ b/drizzle-orm/src/pg-core/query-builders/insert.ts @@ -128,8 +128,9 @@ export class PgInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -137,7 +138,7 @@ export class PgInsert< execute: TReturning extends undefined ? QueryResultKind : TReturning[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/select.ts b/drizzle-orm/src/pg-core/query-builders/select.ts index 9cbae76fa..4043c0c6e 100644 --- a/drizzle-orm/src/pg-core/query-builders/select.ts +++ b/drizzle-orm/src/pg-core/query-builders/select.ts @@ -151,8 +151,9 @@ export class PgSelect< return this.dialect.buildSelectQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -160,7 +161,7 @@ export class PgSelect< execute: SelectResult[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.fields, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.fields, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/pg-core/query-builders/update.ts b/drizzle-orm/src/pg-core/query-builders/update.ts index 704eca677..23b147279 100644 --- a/drizzle-orm/src/pg-core/query-builders/update.ts +++ b/drizzle-orm/src/pg-core/query-builders/update.ts @@ -92,8 +92,9 @@ export class PgUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } private _prepare(name?: string): PreparedQuery< @@ -101,7 +102,7 @@ export class PgUpdate< execute: TReturning extends undefined ? QueryResultKind : TReturning[]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning, name); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name); } prepare(name: string): PreparedQuery< diff --git a/drizzle-orm/src/sql/index.ts b/drizzle-orm/src/sql/index.ts index 89f43c23f..28e676ead 100644 --- a/drizzle-orm/src/sql/index.ts +++ b/drizzle-orm/src/sql/index.ts @@ -1,3 +1,5 @@ +import { MySqlDate, MySqlDecimal, MySqlJson, MySqlTime, MySqlTimestamp } from '~/mysql-core'; +import { PgDate, PgJson, PgJsonb, PgNumeric, PgTime, PgTimestamp, PgUUID } from '~/pg-core'; import { AnyColumn, Column } from '../column'; import { Table } from '../table'; @@ -21,9 +23,12 @@ export interface BuildQueryConfig { escapeParam(num: number, value: unknown): string; } +export type QueryTypingsValue = 'json' | 'decimal' | 'time' | 'timestamp' | 'uuid' | 'date' | 'none'; + export interface Query { sql: string; params: unknown[]; + typings?: QueryTypingsValue[]; } export interface SQLWrapper { @@ -35,6 +40,27 @@ export function isSQLWrapper(value: unknown): value is SQLWrapper { && typeof (value as any).getSQL === 'function'; } +function prepareTyping(encoder: DriverValueEncoder): QueryTypingsValue { + if ( + encoder instanceof PgJsonb || encoder instanceof PgJson + || encoder instanceof MySqlJson + ) { + return 'json'; + } else if (encoder instanceof MySqlDecimal || encoder instanceof PgNumeric) { + return 'decimal'; + } else if (encoder instanceof PgTime || encoder instanceof MySqlTime) { + return 'time'; + } else if (encoder instanceof PgTimestamp || encoder instanceof MySqlTimestamp) { + return 'timestamp'; + } else if (encoder instanceof PgDate || encoder instanceof MySqlDate) { + return 'date'; + } else if (encoder instanceof PgUUID) { + return 'uuid'; + } else { + return 'none'; + } +} + export class SQL implements SQLWrapper { declare protected $brand: 'SQL'; @@ -42,6 +68,7 @@ export class SQL implements SQLWrapper { toQuery({ escapeName, escapeParam }: BuildQueryConfig): Query { const params: unknown[] = []; + const typings: QueryTypingsValue[] = []; const chunks = this.queryChunks.map((chunk) => { if (typeof chunk === 'string') { @@ -57,6 +84,7 @@ export class SQL implements SQLWrapper { return escapeName(chunk.table[Table.Symbol.Name]) + '.' + escapeName(chunk.name); } else if (chunk instanceof Param) { params.push(chunk.encoder.mapToDriverValue(chunk.value)); + typings.push(prepareTyping(chunk.encoder)); return escapeParam(params.length - 1, chunk.value); } else { const err = new Error('Unexpected chunk type!'); @@ -69,7 +97,7 @@ export class SQL implements SQLWrapper { .join('') .trim(); - return { sql: sqlString, params }; + return { sql: sqlString, params, typings }; } getSQL(): SQL { diff --git a/drizzle-orm/src/sqlite-core/query-builders/delete.ts b/drizzle-orm/src/sqlite-core/query-builders/delete.ts index 6430c3559..fc4c56b88 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/delete.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/delete.ts @@ -56,8 +56,9 @@ export class SQLiteDelete< return this.dialect.buildDeleteQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery<{ @@ -67,7 +68,7 @@ export class SQLiteDelete< get: TReturning extends undefined ? never : TReturning | undefined; values: TReturning extends undefined ? never : any[][]; }> { - return this.session.prepareQuery(this.toSQL(), this.config.returning); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/drizzle-orm/src/sqlite-core/query-builders/insert.ts b/drizzle-orm/src/sqlite-core/query-builders/insert.ts index 559360ebc..9ca2c5b7c 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/insert.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/insert.ts @@ -122,8 +122,9 @@ export class SQLiteInsert< return this.dialect.buildInsertQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery< @@ -135,7 +136,7 @@ export class SQLiteInsert< values: TReturning extends undefined ? never : any[][]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/drizzle-orm/src/sqlite-core/query-builders/select.ts b/drizzle-orm/src/sqlite-core/query-builders/select.ts index 03e44aeee..8089e9e4b 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/select.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/select.ts @@ -156,9 +156,9 @@ export class SQLiteSelect< return this.dialect.buildSelectQuery(this.config); } - toSQL(): Query { - const query = this.dialect.buildSelectQuery(this.config); - return this.dialect.sqlToQuery(query); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery< @@ -170,7 +170,7 @@ export class SQLiteSelect< values: any[][]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.fields); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.fields); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/drizzle-orm/src/sqlite-core/query-builders/update.ts b/drizzle-orm/src/sqlite-core/query-builders/update.ts index 68abeaabe..859e8ef95 100644 --- a/drizzle-orm/src/sqlite-core/query-builders/update.ts +++ b/drizzle-orm/src/sqlite-core/query-builders/update.ts @@ -95,8 +95,9 @@ export class SQLiteUpdate< return this.dialect.buildUpdateQuery(this.config); } - toSQL(): Query { - return this.dialect.sqlToQuery(this.getSQL()); + toSQL(): Omit { + const { typings, ...rest} = this.dialect.sqlToQuery(this.getSQL()); + return rest } prepare(): PreparedQuery< @@ -108,7 +109,7 @@ export class SQLiteUpdate< values: TReturning extends undefined ? never : any[][]; } > { - return this.session.prepareQuery(this.toSQL(), this.config.returning); + return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning); } run: ReturnType['run'] = (placeholderValues) => { diff --git a/integration-tests/.env.example b/integration-tests/.env.example index 3411cd58f..517e6f675 100644 --- a/integration-tests/.env.example +++ b/integration-tests/.env.example @@ -1 +1,5 @@ PG_CONNECTION_STRING=postgres://postgres:postgres@localhost:5432/postgres +AWS_DATA_API_DB= +AWS_DATA_API_SECRET_ARN= +AWS_DATA_API_RESOURCE_ARN= +AWS_TEST_PROFILE= \ No newline at end of file diff --git a/integration-tests/drizzle/pg/20221207173503/migration.sql b/integration-tests/drizzle/pg/20221207173503/migration.sql index b6c0d91f6..de1ab7c10 100644 --- a/integration-tests/drizzle/pg/20221207173503/migration.sql +++ b/integration-tests/drizzle/pg/20221207173503/migration.sql @@ -1,4 +1,4 @@ -CREATE TABLE users12 ( +CREATE TABLE "users12" ( "id" serial PRIMARY KEY, "name" text NOT NULL, "email" text NOT NULL diff --git a/integration-tests/package.json b/integration-tests/package.json index 8bad8560c..16bd922d6 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -9,6 +9,8 @@ "ava": { "files": [ "tests/**/*.ts", + "!tests/awsdatapi.alltypes.test.ts", + "!tests/awsdatapi.test.ts", "!tests/bun/**/*" ], "extensions": { @@ -37,6 +39,7 @@ "@aws-sdk/credential-providers": "^3.258.0", "better-sqlite3": "^7.6.2", "dockerode": "^3.3.4", + "dotenv": "^16.0.3", "drizzle-orm": "workspace:../drizzle-orm/dist", "get-port": "^6.1.2", "mysql2": "^2.3.3", diff --git a/integration-tests/tests/awsdatapi.alltypes.test.ts b/integration-tests/tests/awsdatapi.alltypes.test.ts new file mode 100644 index 000000000..81d3e32bf --- /dev/null +++ b/integration-tests/tests/awsdatapi.alltypes.test.ts @@ -0,0 +1,409 @@ +import { RDSDataClient } from '@aws-sdk/client-rds-data'; +import { fromIni } from '@aws-sdk/credential-providers'; +import anyTest, { TestFn } from 'ava'; +import * as dotenv from 'dotenv'; +import { DefaultLogger, sql } from 'drizzle-orm'; +import { AwsDataApiPgDatabase, drizzle } from 'drizzle-orm/aws-data-api/pg'; +import { + bigint, + bigserial, + boolean, + date, + decimal, + doublePrecision, + InferModel, + integer, + json, + jsonb, + numeric, + pgTable, + real, + serial, + smallint, + text, + time, + timestamp, + varchar, +} from 'drizzle-orm/pg-core'; +dotenv.config(); + +export const allColumns = pgTable('all_columns', { + sm: smallint('smallint'), + smdef: smallint('smallint_def').default(10), + int: integer('integer'), + intdef: integer('integer_def').default(10), + numeric: numeric('numeric'), + numeric2: numeric('numeric2', { precision: 5 }), + numeric3: numeric('numeric3', { scale: 2 }), + numeric4: numeric('numeric4', { precision: 5, scale: 2 }), + numericdef: numeric('numeridef').default('100'), + bigint: bigint('bigint', { mode: 'number' }), + bigintdef: bigint('bigintdef', { mode: 'number' }).default(100), + bool: boolean('boolean'), + booldef: boolean('boolean_def').default(true), + text: text('text'), + textdef: text('textdef').default('text'), + varchar: varchar('varchar'), + varchardef: varchar('varchardef').default('text'), + serial: serial('serial'), + bigserial: bigserial('bigserial', { mode: 'number' }), + decimal: decimal('decimal', { precision: 100, scale: 2 }), + decimaldef: decimal('decimaldef', { precision: 100, scale: 2 }).default('100.0'), + doublePrecision: doublePrecision('doublePrecision'), + doublePrecisiondef: doublePrecision('doublePrecisiondef').default(100.0), + real: real('real'), + realdef: real('realdef').default(100.0), + json: json<{ attr: string }>('json'), + jsondef: json<{ attr: string }>('jsondef').default({ attr: 'value' }), + jsonb: jsonb<{ attr: string }>('jsonb'), + jsonbdef: jsonb<{ attr: string }>('jsonbdef').default({ attr: 'value' }), + time: time('time'), + time2: time('time2', { precision: 6, withTimezone: true }), + timedefnow: time('timedefnow').defaultNow(), + timestamp: timestamp('timestamp'), + timestamp2: timestamp('timestamp2', { precision: 6, withTimezone: true }), + timestamp3: timestamp('timestamp3', { withTimezone: true }), + timestamp4: timestamp('timestamp4', { precision: 4 }), + timestampdef: timestamp('timestampdef').defaultNow(), + date: date('date', { mode: 'date' }), + datedef: date('datedef').defaultNow(), +}); + +interface Context { + db: AwsDataApiPgDatabase; + row: InferModel +} + +const test = anyTest as TestFn; + +test.before(async (t) => { + const ctx = t.context; + const database = process.env['AWS_DATA_API_DB']!; + const secretArn = process.env['AWS_DATA_API_SECRET_ARN']!; + const resourceArn = process.env['AWS_DATA_API_RESOURCE_ARN']!; + + const rdsClient = new RDSDataClient({ + credentials: fromIni({ profile: process.env['AWS_TEST_PROFILE'] }), + region: 'us-east-1', + }); + + ctx.db = drizzle(rdsClient, { + database, + secretArn, + resourceArn, + // logger: new DefaultLogger(), + }); + + await ctx.db.execute(sql`CREATE TABLE IF NOT EXISTS "all_columns" ( + "smallint" smallint, + "smallint_def" smallint DEFAULT 10, + "integer" integer, + "integer_def" integer DEFAULT 10, + "numeric" numeric, + "numeric2" numeric(5), + "numeric3" numeric, + "numeric4" numeric(5, 2), + "numeridef" numeric DEFAULT '100', + "bigint" bigint, + "bigintdef" bigint DEFAULT 100, + "boolean" boolean, + "boolean_def" boolean DEFAULT true, + "text" text, + "textdef" text DEFAULT 'text', + "varchar" varchar, + "varchardef" varchar DEFAULT 'text', + "serial" serial, + "bigserial" bigserial, + "decimal" numeric(100, 2), + "decimaldef" numeric(100, 2) DEFAULT '100.0', + "doublePrecision" double precision, + "doublePrecisiondef" double precision DEFAULT 100, + "real" real, + "realdef" real DEFAULT 100, + "json" json, + "jsondef" json DEFAULT '{"attr":"value"}'::json, + "jsonb" jsonb, + "jsonbdef" jsonb DEFAULT '{"attr":"value"}'::jsonb, + "time" time, + "time2" time, + "timedefnow" time DEFAULT now(), + "timestamp" timestamp, + "timestamp2" timestamp (6) with time zone, + "timestamp3" timestamp with time zone, + "timestamp4" timestamp (4), + "timestampdef" timestamp DEFAULT now(), + "date" date, + "datedef" date DEFAULT now() + )`); + + const now = new Date(); + + await ctx.db.insert(allColumns).values({ + sm: 12, + int: 22, + numeric: "1.1", + numeric2: '123.45', + numeric3: '123.45', + numeric4: '123.45', + bigint: 1578, + bool: true, + text: 'inserted_text', + varchar: 'inserted_varchar', + serial: 44, + bigserial: 63473487, + decimal: '100.1', + doublePrecision: 7384.34, + real: 73849.11, + json: { attr: 'hellohello' }, + jsonb: { attr: 'hellohello' }, + time: '11:12:00', + time2: '11:12:00', + timestamp: now, + timestamp2: now, + timestamp3: now, + timestamp4: now, + date: now, + // interval: '10 days' + }); + + const resultRows = await ctx.db.select(allColumns); + t.is(resultRows.length, 1) + + const row = resultRows[0]!; + ctx.row = row; +}); + + +test.serial('[small] serial type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.sm === 'number') + t.is(row.sm, 12) +}); + +test.serial('[small serial] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.sm === 'number') + t.is(row.smdef, 10) +}); + +test.serial('[int] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[int] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.intdef === 'number') + t.is(row.intdef, 10) +}); + +test.serial('[numeric] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric(precision)] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric(scale)] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric(precision, scale)] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[numeric] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.int === 'number') + t.is(row.int, 22) +}); + +test.serial('[bigint] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bigint === 'number') + t.is(row.bigint, 1578) +}); + +test.serial('[bigint] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bigintdef === 'number') + t.is(row.bigintdef, 100) +}); + +test.serial('[boolean] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bool === 'boolean') + t.is(row.bool, true) +}); + +test.serial('[boolean] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.booldef === 'boolean') + t.is(row.booldef, true) +}); + +test.serial('[text] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.text === 'string') + t.is(row.text, 'inserted_text') +}); + +test.serial('[text] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.textdef === 'string') + t.is(row.textdef, 'text') +}); + +test.serial('[varchar] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.varchar === 'string') + t.is(row.varchar, 'inserted_varchar') +}); + +test.serial('[varchar] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.varchardef === 'string') + t.is(row.varchardef, 'text') +}); + +test.serial('[serial] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.serial === 'number') + t.is(row.serial, 44) +}); + +test.serial('[bigserial] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.bigserial === 'number') + t.is(row.bigserial, 63473487) +}); + +test.serial('[decimal] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.decimal === 'string') + t.is(row.decimal, '100.10') +}); + +test.serial('[decimal] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.decimaldef === 'string') + t.is(row.decimaldef, '100.00') +}); + +test.serial('[double precision] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.doublePrecision === 'number') + t.is(row.doublePrecision, 7384.34) +}); + +test.serial('[double precision] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.doublePrecisiondef === 'number') + t.is(row.doublePrecisiondef, 100.0) +}); + +test.serial('[real] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.real === 'number') + t.is(row.real, 73849.11) +}); + +test.serial('[real] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.realdef === 'number') + t.is(row.realdef, 100.0) +}); + +test.serial('[json] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.json?.attr === 'string') + t.deepEqual(row.json, { attr: 'hellohello' }) +}); + +test.serial('[json] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.jsondef?.attr === 'string') + t.deepEqual(row.jsondef, { attr: 'value' }) +}); + +test.serial('[jsonb] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.jsonb?.attr === 'string') + t.deepEqual(row.jsonb, { attr: 'hellohello' }) +}); + +test.serial('[jsonb] type with default', async (t) => { + const { row } = t.context; + + t.assert(typeof row.jsonbdef?.attr === 'string') + t.deepEqual(row.jsonbdef, { attr: 'value' }) +}); + +test.serial('[time] type', async (t) => { + const { row } = t.context; + + t.assert(typeof row.time === 'string') + t.assert(typeof row.time2 === 'string') + t.assert(typeof row.timedefnow === 'string') +}); + +test.serial('[timestamp] type with default', async (t) => { + const { row } = t.context; + + t.assert(row.timestamp instanceof Date) + t.assert(row.timestamp2 instanceof Date) + t.assert(row.timestamp3 instanceof Date) + t.assert(row.timestamp4 instanceof Date) + t.assert(row.timestampdef instanceof Date) +}); + +test.serial('[date] type with default', async (t) => { + const { row } = t.context; + + t.assert(row.date instanceof Date) + t.assert(typeof row.datedef === 'string') +}); + +test.after.always(async (t) => { + const ctx = t.context; + + await ctx.db.execute(sql`drop table "all_columns"`); +}); diff --git a/integration-tests/tests/awsdatapi.test.ts b/integration-tests/tests/awsdatapi.test.ts index b0d8c387e..7124989c0 100644 --- a/integration-tests/tests/awsdatapi.test.ts +++ b/integration-tests/tests/awsdatapi.test.ts @@ -1,14 +1,22 @@ import { RDSDataClient } from '@aws-sdk/client-rds-data'; import { fromIni } from '@aws-sdk/credential-providers'; import anyTest, { TestFn } from 'ava'; -import Docker from 'dockerode'; -import { sql } from 'drizzle-orm'; -import { AwsDataApiPgDatabase, drizzle } from 'drizzle-orm/aws-dataapi'; -import { migrate } from 'drizzle-orm/aws-dataapi/migrator'; +import * as dotenv from 'dotenv'; +import { DefaultLogger, sql } from 'drizzle-orm'; +import { AwsDataApiPgDatabase, drizzle } from 'drizzle-orm/aws-data-api/pg'; +import { migrate } from 'drizzle-orm/aws-data-api/pg/migrator'; import { asc, eq } from 'drizzle-orm/expressions'; -import { alias, boolean, InferModel, jsonb, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; +import { + alias, + boolean, + jsonb, + pgTable, + serial, + text, + timestamp, +} from 'drizzle-orm/pg-core'; import { name, placeholder } from 'drizzle-orm/sql'; -import { Client } from 'pg'; +dotenv.config(); const usersTable = pgTable('users', { id: serial('id').primaryKey(), @@ -23,78 +31,28 @@ const usersMigratorTable = pgTable('users12', { name: text('name').notNull(), email: text('email').notNull(), }); - interface Context { - // docker: Docker; - // pgContainer: Docker.Container; db: AwsDataApiPgDatabase; - // client: Client; } 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))) -// ); - -// const pgContainer = (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 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); - - // let 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'); - // throw lastError; - // } - const database = process.env['AWS_DATA_API_DB']!; const secretArn = process.env['AWS_DATA_API_SECRET_ARN']!; const resourceArn = process.env['AWS_DATA_API_RESOURCE_ARN']!; - const rdsClient = new RDSDataClient({ credentials: fromIni({ profile: process.env['AWS_TEST_PROFILE'] }) }); + const rdsClient = new RDSDataClient({ + credentials: fromIni({ profile: process.env['AWS_TEST_PROFILE'] }), + region: 'us-east-1', + }); ctx.db = drizzle(rdsClient, { database, secretArn, resourceArn, + // logger: new DefaultLogger(), }); }); @@ -118,11 +76,14 @@ test.serial('select all fields', async (t) => { const now = Date.now(); - await db.insert(usersTable).values({ name: 'John' }); + const insertResult = await db.insert(usersTable).values({ name: 'John' }); + + t.is(insertResult.numberOfRecordsUpdated, 1) + const result = await db.select(usersTable); t.assert(result[0]!.createdAt instanceof Date); - t.assert(Math.abs(result[0]!.createdAt.getTime() - now) < 100); + // 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 }]); }); @@ -189,7 +150,7 @@ test.serial('update with returning all fields', async (t) => { const users = await db.update(usersTable).set({ name: 'Jane' }).where(eq(usersTable.name, 'John')).returning(); t.assert(users[0]!.createdAt instanceof Date); - t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); + // 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 }]); }); @@ -214,7 +175,7 @@ test.serial('delete with returning all fields', async (t) => { const users = await db.delete(usersTable).where(eq(usersTable.name, 'John')).returning(); t.assert(users[0]!.createdAt instanceof Date); - t.assert(Math.abs(users[0]!.createdAt.getTime() - now) < 100); + // 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 }]); }); @@ -388,6 +349,7 @@ test.serial('build query', async (t) => { t.deepEqual(query, { sql: 'select "id", "name" from "users" group by "users"."id", "users"."name"', params: [], + // typings: [] }); }); @@ -542,28 +504,28 @@ test.serial('insert via db.execute + select via db.execute', async (t) => { 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.rows, [{ id: 1, name: 'John' }]); + const result = await db.execute(sql`select id, name from "users"`); + t.deepEqual(result.records![0], [{ longValue: 1 }, { stringValue: 'John' }]); }); test.serial('insert via db.execute + returning', async (t) => { const { db } = t.context; - const inserted = await db.execute<{ id: number; name: string }>( + const inserted = await db.execute( sql`insert into ${usersTable} (${ name(usersTable.name.name) }) values (${'John'}) returning ${usersTable.id}, ${usersTable.name}`, ); - t.deepEqual(inserted.rows, [{ id: 1, name: 'John' }]); + t.deepEqual(inserted.records![0], [{ longValue: 1 }, { stringValue: 'John' }]); }); test.serial('insert via db.execute w/ query builder', async (t) => { const { db } = t.context; - const inserted = await db.execute, 'id' | 'name'>>( + const inserted = await db.execute( db.insert(usersTable).values({ name: 'John' }).returning({ id: usersTable.id, name: usersTable.name }), ); - t.deepEqual(inserted.rows, [{ id: 1, name: 'John' }]); + t.deepEqual(inserted.records![0], [{ longValue: 1 }, { stringValue: 'John' }]); }); test.serial('build query insert with onConflict do update', async (t) => { @@ -575,8 +537,9 @@ test.serial('build query insert with onConflict do update', async (t) => { .toSQL(); t.deepEqual(query, { - sql: 'insert into "users" ("name", "jsonb") values ($1, $2) on conflict ("id") do update set "name" = $3', + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict ("id") do update set "name" = :3', params: ['John', '["foo","bar"]', 'John1'], + // typings: ['none', 'json', 'none'] }); }); @@ -589,8 +552,9 @@ test.serial('build query insert with onConflict do update / multiple columns', a .toSQL(); t.deepEqual(query, { - sql: 'insert into "users" ("name", "jsonb") values ($1, $2) on conflict ("id","name") do update set "name" = $3', + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict ("id","name") do update set "name" = :3', params: ['John', '["foo","bar"]', 'John1'], + // typings: ['none', 'json', 'none'] }); }); @@ -603,8 +567,9 @@ test.serial('build query insert with onConflict do nothing', async (t) => { .toSQL(); t.deepEqual(query, { - sql: 'insert into "users" ("name", "jsonb") values ($1, $2) on conflict do nothing', + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict do nothing', params: ['John', '["foo","bar"]'], + // typings: ['none', 'json'] }); }); @@ -617,8 +582,9 @@ test.serial('build query insert with onConflict do nothing + target', async (t) .toSQL(); t.deepEqual(query, { - sql: 'insert into "users" ("name", "jsonb") values ($1, $2) on conflict ("id") do nothing', + sql: 'insert into "users" ("name", "jsonb") values (:1, :2) on conflict ("id") do nothing', params: ['John', '["foo","bar"]'], + // typings: ['none', 'json'] }); }); @@ -675,6 +641,8 @@ test.serial('insert with onConflict do nothing + target', async (t) => { test.after.always(async (t) => { const ctx = t.context; + await ctx.db.execute(sql`drop table "users"`) + await ctx.db.execute(sql`drop table "drizzle"."__drizzle_migrations"`) // await ctx.client?.end().catch(console.error); // await ctx.pgContainer?.stop().catch(console.error); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df912640e..f8ac5d2a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -107,6 +107,7 @@ importers: ava: ^5.1.0 better-sqlite3: ^7.6.2 dockerode: ^3.3.4 + dotenv: ^16.0.3 drizzle-orm: workspace:../drizzle-orm/dist get-port: ^6.1.2 mysql2: ^2.3.3 @@ -123,6 +124,7 @@ importers: '@aws-sdk/credential-providers': 3.258.0 better-sqlite3: 7.6.2 dockerode: 3.3.4 + dotenv: 16.0.3 drizzle-orm: link:../drizzle-orm/dist get-port: 6.1.2 mysql2: 2.3.3 @@ -2509,6 +2511,11 @@ packages: engines: {node: '>=10'} dev: true + /dotenv/16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + dev: false + /dprint/0.32.2: resolution: {integrity: sha512-cGKnZonCFQkcNbptAtJXlzUOqyiyYoD9pINepJ9PvkFi8iwMLChQDSjhMeqT3DDQf5Rof3pYA5LI/bafPpPknQ==} hasBin: true From afeab5b7a38349fb9434ba21601c33964c015e49 Mon Sep 17 00:00:00 2001 From: AndriiSherman Date: Tue, 31 Jan 2023 22:06:33 +0200 Subject: [PATCH 5/5] Add docs and changelogs for data api release --- changelogs/drizzle-orm/0.17.3.md | 22 ++++++++++++++++++++++ drizzle-orm/package.json | 2 +- drizzle-orm/src/pg-core/README.md | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 changelogs/drizzle-orm/0.17.3.md diff --git a/changelogs/drizzle-orm/0.17.3.md b/changelogs/drizzle-orm/0.17.3.md new file mode 100644 index 000000000..a97d45962 --- /dev/null +++ b/changelogs/drizzle-orm/0.17.3.md @@ -0,0 +1,22 @@ +We have released [AWS Data API support](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) for PostgreSQL + +--- + +Connection example + +```typescript +import { drizzle, migrate } from 'drizzle-orm/aws-data-api/pg'; + +const rdsClient = new RDSDataClient({}); + +const db = drizzle(rdsClient, { + database: '', + secretArn: '', + resourceArn: '', +}); + +await migrate(db, { migrationsFolder: '' }); +``` + +> **Note**: +> All drizzle pg data types are working well with data api, except of `interval`. This type is not yet mapped in proper way \ No newline at end of file diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index b1c017dea..a0ae76ff8 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.17.2", + "version": "0.17.3", "description": "Drizzle ORM package for SQL databases", "scripts": { "build": "tsc && resolve-tspaths && cp ../README.md package.json dist/", diff --git a/drizzle-orm/src/pg-core/README.md b/drizzle-orm/src/pg-core/README.md index 777c544c5..60911d182 100644 --- a/drizzle-orm/src/pg-core/README.md +++ b/drizzle-orm/src/pg-core/README.md @@ -15,6 +15,7 @@ Drizzle ORM is a TypeScript ORM for SQL databases designed with maximum type saf | [node-postgres](https://github.com/brianc/node-postgres) | ✅ | | driver version | | [postgres.js](https://github.com/porsager/postgres) | ✅ | [Docs](/drizzle-orm/src/postgres.js/README.md) | driver version | | [NeonDB Serverless](https://github.com/neondatabase/serverless) | ✅ | | driver version | +| [AWS Data API](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-rds-data/README.md) | ✅ | | driver version ## Installation @@ -131,6 +132,20 @@ const db = drizzle(client); const allUsers = await db.select(users); ``` +### Connect using aws data api client + +```typescript +import { drizzle, migrate } from 'drizzle-orm/aws-data-api/pg'; + +const rdsClient = new RDSDataClient({}); + +const db = drizzle(rdsClient, { + database: '', + secretArn: '', + resourceArn: '', +}); +``` + ## Schema declaration This is how you declare SQL schema in `schema.ts`. You can declare tables, indexes and constraints, foreign keys and enums. Please pay attention to `export` keyword, they are mandatory if you'll be using [drizzle-kit SQL migrations generator](#migrations).