diff --git a/packages/client/package.json b/packages/client/package.json index e7325712..a8f357dd 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -42,6 +42,7 @@ "make-synchronous": "^1.0.0", "meow": "^13.1.0", "np": "github:mmkal/np#6a58244afa28fd7d3f8c4dc4b6457c22d74e82de", + "pg-promise": "^11.5.4", "pg-mem": "3.0.2", "quicktype-core": "^23.0.81", "slonik": "^37.2.0", @@ -58,6 +59,14 @@ }, "dependencies": { "pg": "~8.14.1", - "pg-promise": "^11.5.4" + "postgres": "^3.4.7" + }, + "peerDependencies": { + "pg-promise": ">=11" + }, + "peerDependenciesMeta": { + "pg-promise": { + "optional": true + } } } diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index f36e7e55..749e2d6d 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -1,6 +1,4 @@ -import * as crypto from 'node:crypto' -import TypeOverrides from 'pg/lib/type-overrides' -import pgPromise from 'pg-promise' +import {createPgPromiseDriver} from './drivers/pg-promise' import {QueryError, errorFromUnknown} from './errors' import {createSqlTag} from './sql' import {applyRecommendedTypeParsers} from './type-parsers' @@ -10,6 +8,8 @@ import { SQLQueryRowType, ClientOptions, Connection, + DriverInfo, + DriverScope, Transaction, Result, DriverQueryable, @@ -111,6 +111,18 @@ export const createQueryFn = (pgpQueryable: DriverQueryable): Queryable['query'] } } +const getCompatibilityProps = (info: DriverInfo) => { + const {name: _name, raw: _raw, ...compatibilityProps} = info + return compatibilityProps +} + +const createTransactionFactory = ( + scope: Pick, + createTransaction: (transactionScope: DriverScope) => Transaction, +): Connection['transaction'] => { + return async callback => scope.transaction(async transaction => callback(createTransaction(transaction))) +} + export const createClient = (connectionString: string, options: ClientOptions = {}): Client => { if (typeof connectionString !== 'string') throw new Error(`Expected connectionString, got ${typeof connectionString}`) if (!connectionString) throw new Error(`Expected a valid connectionString, got "${connectionString}"`) @@ -121,62 +133,54 @@ export const createClient = (connectionString: string, options: ClientOptions = ...options, } - const types = new TypeOverrides() - // note: this should be done "high up" in the app: https://stackoverflow.com/questions/34382796/where-should-i-initialize-pg-promise - const initializedPgPromise = pgPromise(options.pgpOptions?.initialize) - - options.applyTypeParsers?.({ - setTypeParser: (id, parseFn) => types.setTypeParser(id, parseFn as (input: unknown) => unknown), - builtins: initializedPgPromise.pg.types.builtins, - }) + const driver = options.driver ?? createPgPromiseDriver(options.pgpOptions) const createWrappedQueryFn: typeof createQueryFn = queryable => { const queryFn = createQueryFn(queryable) return options.wrapQueryFn ? options.wrapQueryFn(queryFn) : queryFn } - const pgPromiseClient = initializedPgPromise({ + const runtime = driver.create({ connectionString, - types, - ...options.pgpOptions?.connect, + applyTypeParsers: options.applyTypeParsers, }) - const transactionFnFromTask = - (task: pgPromise.ITask | pgPromise.IDatabase): Connection['transaction'] => - async txCallback => { - return task.tx({tag: crypto.randomUUID()}, async tx => { - const pgSuiteTransaction: Transaction = { - ...createQueryable(createWrappedQueryFn(tx)), - transactionInfo: {pgp: tx}, - connectionInfo: {pgp: task}, - transaction: transactionFnFromTask(tx), - } - return txCallback(pgSuiteTransaction) - }) + const createTransaction = (transactionScope: DriverScope, connectionInfo: DriverInfo): Transaction => { + return { + ...getCompatibilityProps(transactionScope.info), + ...createQueryable(createWrappedQueryFn(transactionScope.queryable)), + transactionInfo: transactionScope.info, + connectionInfo, + transaction: createTransactionFactory(transactionScope, nested => createTransaction(nested, connectionInfo)), } + } - const taskMethod: Client['task'] = async callback => { - return pgPromiseClient.task({tag: crypto.randomUUID()}, async task => { - const connectionInfo: Connection['connectionInfo'] = {pgp: task} - const pgSuiteConnection: Connection = { - connectionInfo, - transaction: transactionFnFromTask(task), - ...createQueryable(createWrappedQueryFn(task)), - } - - return callback(pgSuiteConnection) - }) + const createConnection = (connectionScope: DriverScope): Connection => { + const connectionInfo = connectionScope.info + return { + ...getCompatibilityProps(connectionInfo), + ...createQueryable(createWrappedQueryFn(connectionScope.queryable)), + connectionInfo, + transaction: createTransactionFactory(connectionScope, transaction => + createTransaction(transaction, connectionInfo), + ), + } } + const taskMethod: Client['task'] = async callback => + runtime.connect(async connection => callback(createConnection(connection))) + return { options, - pgp: pgPromiseClient, + ...getCompatibilityProps(runtime.info), + driverInfo: runtime.info, pgpOptions: options.pgpOptions || {}, - ...createQueryable(createWrappedQueryFn(pgPromiseClient)), + ...createQueryable(createWrappedQueryFn(runtime.queryable)), connectionString: () => connectionString, - end: async () => pgPromiseClient.$pool.end(), + end: async () => runtime.end(), connect: taskMethod, task: taskMethod, - transaction: transactionFnFromTask(pgPromiseClient), + transaction: async callback => + runtime.transaction(async transaction => callback(createTransaction(transaction, runtime.info))), } } diff --git a/packages/client/src/drivers/pg-promise.ts b/packages/client/src/drivers/pg-promise.ts new file mode 100644 index 00000000..7692c845 --- /dev/null +++ b/packages/client/src/drivers/pg-promise.ts @@ -0,0 +1,84 @@ +import * as crypto from 'node:crypto' +import TypeOverrides from 'pg/lib/type-overrides' +import {ClientDriver, DriverInfo, DriverQueryable, DriverScope, PGPOptions} from '../types' + +type PgPromiseTask = { + result(query: string, values?: unknown[]): Promise + tx(options: {tag: string}, callback: (task: PgPromiseTask) => Promise): Promise +} + +type PgPromiseDatabase = PgPromiseTask & { + task(options: {tag: string}, callback: (task: PgPromiseTask) => Promise): Promise + $pool: {end(): Promise} +} + +type PgPromiseConnector = ((connect: Record) => PgPromiseDatabase) & { + pg: {types: {builtins: Record}} +} + +type PgPromiseInitializer = (options?: unknown) => PgPromiseConnector + +export type PgPromiseDriverOptions = PGPOptions & { + pgPromise?: PgPromiseInitializer +} + +const createInfo = (raw: unknown): DriverInfo => ({name: 'pg-promise', raw, pgp: raw}) + +const createQueryable = (queryable: PgPromiseTask): DriverQueryable => ({ + result: async (query: string, values?: unknown[]) => { + return queryable.result(query, values && values.length > 0 ? values : undefined) + }, +}) + +const createScope = (queryable: PgPromiseTask, connectionInfo: DriverInfo): DriverScope => ({ + info: createInfo(queryable), + queryable: createQueryable(queryable), + transaction: async callback => { + return queryable.tx({tag: crypto.randomUUID()}, async transaction => + callback(createScope(transaction, connectionInfo)), + ) + }, +}) + +const getPgPromise = (override?: PgPromiseInitializer) => { + if (override) return override + try { + return require('pg-promise') as PgPromiseInitializer + } catch (cause) { + throw new Error('The pg-promise driver requires `pg-promise` to be installed in your app.', {cause}) + } +} + +export const createPgPromiseDriver = (options: PgPromiseDriverOptions = {}): ClientDriver => ({ + name: 'pg-promise', + create({connectionString, applyTypeParsers}) { + const pgPromise = getPgPromise(options.pgPromise) + const initializedPgPromise = pgPromise(options.initialize) + const types = new TypeOverrides() + + applyTypeParsers?.({ + setTypeParser: (id, parseFn) => types.setTypeParser(id, ((input: unknown) => parseFn(input as never)) as any), + builtins: initializedPgPromise.pg.types.builtins as any, + }) + + const database = initializedPgPromise({ + connectionString, + types, + ...options.connect, + }) + + return { + info: createInfo(database), + queryable: createQueryable(database), + end: async () => database.$pool.end(), + connect: async callback => { + return database.task({tag: crypto.randomUUID()}, async task => callback(createScope(task, createInfo(task)))) + }, + transaction: async callback => { + return database.tx({tag: crypto.randomUUID()}, async transaction => { + return callback(createScope(transaction, createInfo(database))) + }) + }, + } + }, +}) diff --git a/packages/client/src/drivers/pg.ts b/packages/client/src/drivers/pg.ts new file mode 100644 index 00000000..48dabb50 --- /dev/null +++ b/packages/client/src/drivers/pg.ts @@ -0,0 +1,84 @@ +import * as crypto from 'node:crypto' +import {Pool, PoolClient, PoolConfig, types as pgTypes} from 'pg' +import TypeOverrides from 'pg/lib/type-overrides' +import {ClientDriver, DriverInfo, DriverQueryable, DriverScope} from '../types' + +const createInfo = (raw: unknown): DriverInfo => ({name: 'pg', raw}) + +const toResult = async ( + queryable: {query(query: string, values?: unknown[]): Promise}, + query: string, + values?: unknown[], +) => { + const result = await queryable.query(query, values) + return { + rows: result.rows as T[], + fields: result.fields, + command: result.command, + rowCount: result.rowCount, + } +} + +const createQueryable = (queryable: {query(query: string, values?: unknown[]): Promise}): DriverQueryable => ({ + result: async (query: string, values?: unknown[]) => toResult(queryable, query, values), +}) + +const savepointName = () => `pgkit_${crypto.randomUUID().replaceAll('-', '_')}` + +const createScope = (client: PoolClient, connectionInfo: DriverInfo, inTransaction: boolean): DriverScope => ({ + info: createInfo(client), + queryable: createQueryable(client), + transaction: async callback => { + const savepoint = savepointName() + await client.query(inTransaction ? `savepoint ${savepoint}` : 'begin') + try { + const result = await callback(createScope(client, connectionInfo, true)) + await client.query(inTransaction ? `release savepoint ${savepoint}` : 'commit') + return result + } catch (error) { + await client.query(inTransaction ? `rollback to savepoint ${savepoint}` : 'rollback') + throw error + } + }, +}) + +export type PgDriverOptions = PoolConfig + +export const createPgDriver = (options: PgDriverOptions = {}): ClientDriver => ({ + name: 'pg', + create({connectionString, applyTypeParsers}) { + const types = new TypeOverrides() + applyTypeParsers?.({ + setTypeParser: (id, parseFn) => types.setTypeParser(id, ((input: unknown) => parseFn(input as never)) as any), + builtins: pgTypes.builtins, + }) + + const pool = new Pool({ + connectionString, + types, + ...options, + }) + + return { + info: createInfo(pool), + queryable: createQueryable(pool), + end: async () => pool.end(), + connect: async callback => { + const client = await pool.connect() + try { + return await callback(createScope(client, createInfo(client), false)) + } finally { + client.release() + } + }, + transaction: async callback => { + const client = await pool.connect() + try { + return await createScope(client, createInfo(pool), false).transaction(callback) + } finally { + client.release() + } + }, + } + }, +}) diff --git a/packages/client/src/drivers/postgres.ts b/packages/client/src/drivers/postgres.ts new file mode 100644 index 00000000..2e195cca --- /dev/null +++ b/packages/client/src/drivers/postgres.ts @@ -0,0 +1,121 @@ +import {types as pgTypes} from 'pg' +import {ClientDriver, DriverInfo, DriverQueryable, DriverScope, ParseFn, PGTypesBuiltins} from '../types' + +type PostgresSql = { + unsafe( + query: string, + values: unknown[], + ): Promise; command: string; count: number}> + reserve(): Promise}> + begin(callback: (sql: PostgresSql) => Promise): Promise + savepoint(callback: (sql: PostgresSql) => Promise): Promise + end(): Promise +} + +type PostgresModule = (connectionString?: string, options?: Record) => PostgresSql + +export type PostgresDriverOptions = Record & { + types?: Record +} + +const getPostgres = () => require('postgres') as PostgresModule + +const createInfo = (raw: unknown): DriverInfo => ({name: 'postgres', raw}) + +const createQueryable = (sql: PostgresSql): DriverQueryable => ({ + result: async (query: string, values?: unknown[]) => { + const result = await sql.unsafe(query, values ?? []) + return { + rows: result as unknown as T[], + fields: (result.columns ?? []).map((column: {name: string; type: number}) => ({ + name: column.name, + dataTypeID: column.type, + })), + command: result.command, + rowCount: result.count, + } + }, +}) + +const createScope = (sql: PostgresSql, connectionInfo: DriverInfo, inTransaction: boolean): DriverScope => ({ + info: createInfo(sql), + queryable: createQueryable(sql), + transaction: async callback => { + if (inTransaction && typeof sql.savepoint === 'function') { + return sql.savepoint(async (transaction: PostgresSql) => callback(createScope(transaction, connectionInfo, true))) + } + + if (!inTransaction && typeof sql.begin === 'function') { + return sql.begin(async (transaction: PostgresSql) => callback(createScope(transaction, connectionInfo, true))) + } + + await sql.unsafe('begin', []) + try { + const result = await callback(createScope(sql, connectionInfo, true)) + await sql.unsafe('commit', []) + return result + } catch (error) { + await sql.unsafe('rollback', []) + throw error + } + }, +}) + +const createPostgresTypes = ( + builtins: PGTypesBuiltins, + applyTypeParsers?: (params: { + setTypeParser: (oid: number, parseFn: ParseFn) => void + builtins: PGTypesBuiltins + }) => void, +) => { + if (!applyTypeParsers) return undefined + const parsers = new Map() + applyTypeParsers({ + setTypeParser: (oid, parseFn) => parsers.set(oid, parseFn), + builtins, + }) + return Object.fromEntries( + [...parsers.entries()].map(([oid, parse], index) => [ + `oid_${oid}_${index}`, + { + from: [oid], + serialize: (value: unknown) => value, + parse, + }, + ]), + ) +} + +export const createPostgresDriver = (options: PostgresDriverOptions = {}): ClientDriver => ({ + name: 'postgres', + create({connectionString, applyTypeParsers}) { + const postgres = getPostgres() + const builtins = pgTypes.builtins + const sql = postgres(connectionString, { + ...options, + types: { + ...createPostgresTypes(builtins, applyTypeParsers), + ...options.types, + }, + }) + + return { + info: createInfo(sql), + queryable: createQueryable(sql), + end: async () => { + await sql.end() + }, + connect: async callback => { + const reserved = await sql.reserve() + try { + return await callback(createScope(reserved, createInfo(reserved), false)) + } finally { + await reserved.release() + } + }, + transaction: async callback => { + return sql.begin(async (transaction: PostgresSql) => callback(createScope(transaction, createInfo(sql), true))) + }, + } + }, +}) diff --git a/packages/client/src/sql.ts b/packages/client/src/sql.ts index a24b9102..034fe1f3 100644 --- a/packages/client/src/sql.ts +++ b/packages/client/src/sql.ts @@ -1,4 +1,3 @@ -import pgPromise from 'pg-promise' import {QueryError} from './errors' import {nameQuery} from './naming' import {StandardSchemaV1} from './standard-schema/contract' @@ -24,6 +23,11 @@ const maybeAsyncMap = (thing: T | Promise, map: (value: T) => U): U | P return map(thing as T) } +const escapeLiteralValue = (value: string) => { + const escapedQuotes = value.replaceAll("'", "''") + return value.includes('\\') ? `E'${escapedQuotes.replaceAll('\\', '\\\\')}'` : `'${escapedQuotes}'` +} + /** * Template tag function. Walks through each string segment and parameter, and concatenates them into a valid SQL query. */ @@ -112,7 +116,7 @@ const sqlFnInner = ( case 'literalValue': { const [value] = param.args - segments.push(pgPromise.as.value(value)) + segments.push(escapeLiteralValue(value)) break } diff --git a/packages/client/src/type-parsers.ts b/packages/client/src/type-parsers.ts index 24b58807..c76e0b83 100644 --- a/packages/client/src/type-parsers.ts +++ b/packages/client/src/type-parsers.ts @@ -1,27 +1,27 @@ -import pgPromise from 'pg-promise' +import {types as nodePgTypes} from 'pg' import {PGTypes, ApplyTypeParsers} from './types' -export const pgTypes: PGTypes = pgPromise().pg.types +export const pgTypes: PGTypes = nodePgTypes export const applyRecommendedTypeParsers: ApplyTypeParsers = ({setTypeParser, builtins}) => { - setTypeParser(builtins.DATE, value => new Date(value)) - setTypeParser(builtins.TIMESTAMPTZ, value => new Date(value)) - setTypeParser(builtins.TIMESTAMP, value => value) - setTypeParser(builtins.INTERVAL, value => value) + setTypeParser(builtins.DATE, value => new Date(String(value))) + setTypeParser(builtins.TIMESTAMPTZ, value => new Date(String(value))) + setTypeParser(builtins.TIMESTAMP, String) + setTypeParser(builtins.INTERVAL, String) setTypeParser(builtins.NUMERIC, Number) setTypeParser(builtins.INT2, Number) setTypeParser(builtins.INT4, Number) setTypeParser(builtins.INT8, Number) - setTypeParser(builtins.BOOL, value => value === 't') + setTypeParser(builtins.BOOL, value => String(value) === 't') } /** * Equivalent of slonik type parsers in `createTypeParserPreset`. [Docs](https://www.npmjs.com/package/slonik#default-configuration) */ export const applySlonik37TypeParsers: ApplyTypeParsers = ({setTypeParser, builtins}) => { - setTypeParser(builtins.DATE, value => new Date(value)) - setTypeParser(builtins.TIMESTAMPTZ, value => new Date(value).getTime()) - setTypeParser(builtins.TIMESTAMP, value => new Date(value).getTime()) - setTypeParser(builtins.INTERVAL, value => value) + setTypeParser(builtins.DATE, value => new Date(String(value))) + setTypeParser(builtins.TIMESTAMPTZ, value => new Date(String(value)).getTime()) + setTypeParser(builtins.TIMESTAMP, value => new Date(String(value)).getTime()) + setTypeParser(builtins.INTERVAL, String) setTypeParser(builtins.NUMERIC, Number) } diff --git a/packages/client/src/types.ts b/packages/client/src/types.ts index 3a0012ca..f3e2eb39 100644 --- a/packages/client/src/types.ts +++ b/packages/client/src/types.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import pgPromise from 'pg-promise' import {StandardSchemaV1} from './standard-schema/contract' export interface SQLQuery, Values extends unknown[] = unknown[]> { @@ -47,6 +46,28 @@ export type DriverQueryable = { result: (query: string, values?: unknown[]) => Promise> } +export type DriverInfo = { + name: string + raw: unknown +} & Record + +export interface DriverScope { + info: DriverInfo + queryable: DriverQueryable + transaction(callback: (transaction: DriverScope) => Promise): Promise +} + +export interface ClientDriver { + name: string + create(params: {connectionString: string; applyTypeParsers?: ApplyTypeParsers}): { + info: DriverInfo + queryable: DriverQueryable + end(): Promise + connect(callback: (connection: DriverScope) => Promise): Promise + transaction(callback: (transaction: DriverScope) => Promise): Promise + } +} + export interface Queryable { query(query: SQLQuery): Promise> @@ -120,17 +141,18 @@ export interface Transactable extends SQLQueryable { } export interface Connection extends Transactable { // todo: consolidate this with `transactionInfo`, and include a nullable `parent` property - connectionInfo: {pgp: pgPromise.ITask | pgPromise.IDatabase} + connectionInfo: DriverInfo } export interface Transaction extends Connection { - transactionInfo: {pgp: pgPromise.ITask} + transactionInfo: DriverInfo } export interface Client extends SQLQueryable { options: ClientOptions - pgp: ReturnType> - pgpOptions: PGPOptions + driverInfo: DriverInfo + pgp?: unknown + pgpOptions?: PGPOptions connectionString(): string end(): Promise connect(callback: (connection: Connection) => Promise): Promise @@ -278,19 +300,15 @@ export type SQLMethodHelpers = { /** the full type for the `sql` tag - callable function, helpers and all */ export type SQLTag = SQLTagFunction & SQLTagHelpers & SQLMethodHelpers -/** Called `pgp` in pg-promise docs */ -export type PGPromiseInitializer = typeof pgPromise -/** Called `IMain` in pg-promise */ -export type PGPromiseDBConnector = ReturnType -/** Looks like `[cn: string | pg.IConnectionParameters, dc?: any]` in pg-promise */ -export type PGPromiseDBConnectorParameters = Parameters -/** Looks like `pg.IConnectionParameters` in pg-promise */ -export type PGPromiseDBConnectionOptions = Exclude +export type PGPromiseInitializer = unknown +export type PGPromiseDBConnector = unknown +export type PGPromiseDBConnectorParameters = unknown[] +export type PGPromiseDBConnectionOptions = Record -export type PGTypes = ReturnType['pg']['types'] +export type PGTypes = typeof import('pg').types // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export type ParseFn = Extract[number], Function> -export type PGTypesBuiltins = PGTypes['builtins'] +export type PGTypesBuiltins = typeof import('pg').types.builtins export type PGTypesBuiltinOid = PGTypesBuiltins[keyof PGTypesBuiltins] export type ApplyTypeParsers = (params: { @@ -299,11 +317,12 @@ export type ApplyTypeParsers = (params: { }) => void export type PGPOptions = { - initialize?: pgPromise.IInitOptions + initialize?: unknown connect?: PGPromiseDBConnectionOptions } export interface ClientOptions { + driver?: ClientDriver pgpOptions?: PGPOptions applyTypeParsers?: ApplyTypeParsers wrapQueryFn?: (queryFn: SQLQueryable['query']) => SQLQueryable['query'] diff --git a/packages/client/test/drivers.test.ts b/packages/client/test/drivers.test.ts new file mode 100644 index 00000000..158945f0 --- /dev/null +++ b/packages/client/test/drivers.test.ts @@ -0,0 +1,32 @@ +import {expect, test} from 'vitest' +import {createClient, createPgDriver, createPostgresDriver, sql} from '../src' + +const connectionString = 'postgresql://postgres:postgres@localhost:5432/postgres' + +test('pg driver', async () => { + const client = createClient(connectionString, { + driver: createPgDriver({application_name: 'pg-driver'}), + }) + + try { + await expect(client.one(sql`select 1 as value`)).resolves.toEqual({value: 1}) + await expect(client.transaction(async tx => tx.one(sql`select 2 as value`))).resolves.toEqual({value: 2}) + } finally { + await client.end() + } +}) + +test('postgres driver', async () => { + const client = createClient(connectionString, { + driver: createPostgresDriver({application_name: 'postgres-driver'}), + }) + + try { + await expect(client.one(sql`select 1 as value`)).resolves.toEqual({value: 1}) + await expect( + client.connect(async conn => conn.transaction(async tx => tx.one(sql`select 3 as value`))), + ).resolves.toEqual({value: 3}) + } finally { + await client.end() + } +}) diff --git a/packages/migra/test/fixtures.ts b/packages/migra/test/fixtures.ts index 759ceefb..47b39fde 100644 --- a/packages/migra/test/fixtures.ts +++ b/packages/migra/test/fixtures.ts @@ -59,7 +59,7 @@ export const setup = async (url: string, admin: Client, prefix: string, fixtures await pool.query(sql.raw(query)) - await pool.pgp.$pool.end() + await pool.end() } export const getFixtures = (prefix: string, fixturesDir: string) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c644c24..e034e8dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -331,9 +331,9 @@ importers: pg: specifier: ~8.14.1 version: 8.14.1 - pg-promise: - specifier: ^11.5.4 - version: 11.5.4 + postgres: + specifier: ^3.4.7 + version: 3.4.8 devDependencies: '@stylistic/eslint-plugin': specifier: ^1.6.0 @@ -376,7 +376,10 @@ importers: version: https://codeload.github.com/mmkal/np/tar.gz/6a58244afa28fd7d3f8c4dc4b6457c22d74e82de(typescript@5.8.2) pg-mem: specifier: 3.0.2 - version: 3.0.2(pg-promise@11.5.4)(slonik@37.2.0(zod@3.25.20)) + version: 3.0.2(pg-promise@11.5.4)(postgres@3.4.8)(slonik@37.2.0(zod@3.25.20)) + pg-promise: + specifier: ^11.5.4 + version: 11.5.4 quicktype-core: specifier: ^23.0.81 version: 23.0.81(encoding@0.1.13) @@ -7031,6 +7034,10 @@ packages: postgres-range@1.1.4: resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + postgres@3.4.8: + resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==} + engines: {node: '>=12'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -10997,6 +11004,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2)': + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/type-utils': 8.6.0(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/utils': 8.6.0(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.6.0 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2)': dependencies: '@eslint-community/regexpp': 4.10.0 @@ -12987,7 +13012,7 @@ snapshots: eslint-config-xo-typescript@1.0.1(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2))(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2) '@typescript-eslint/parser': 8.6.0(eslint@8.57.0)(typescript@5.8.2) eslint: 8.57.0 typescript: 5.8.2 @@ -13198,7 +13223,7 @@ snapshots: '@rushstack/eslint-plugin-packlets': 0.8.1(eslint@8.57.0)(typescript@5.8.2) '@rushstack/eslint-plugin-security': 0.7.1(eslint@8.57.0)(typescript@5.8.2) '@types/eslint': 8.56.6 - '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2) '@typescript-eslint/parser': 8.6.0(eslint@8.57.0)(typescript@5.8.2) eslint-config-prettier: 9.1.0(eslint@8.57.0) eslint-config-xo: 0.43.1(eslint@8.57.0) @@ -13551,7 +13576,7 @@ snapshots: '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.8.2) eslint: 8.57.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.8.2))(eslint@8.57.0)(typescript@5.8.2) vitest: 1.2.2(@types/node@20.11.17)(sass@1.71.0) transitivePeerDependencies: - supports-color @@ -16409,7 +16434,7 @@ snapshots: pg-int8@1.0.1: {} - pg-mem@3.0.2(pg-promise@11.5.4)(slonik@37.2.0(zod@3.25.20)): + pg-mem@3.0.2(pg-promise@11.5.4)(postgres@3.4.8)(slonik@37.2.0(zod@3.25.20)): dependencies: functional-red-black-tree: 1.0.1 immutable: 4.3.5 @@ -16420,6 +16445,7 @@ snapshots: pgsql-ast-parser: 12.0.1 optionalDependencies: pg-promise: 11.5.4 + postgres: 3.4.8 slonik: 37.2.0(zod@3.25.20) pg-minify@1.6.3: {} @@ -16624,6 +16650,8 @@ snapshots: postgres-range@1.1.4: {} + postgres@3.4.8: {} + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -18377,7 +18405,7 @@ snapshots: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.1.1(@types/node@20.11.21) + vite: 5.1.1(@types/node@20.11.21)(sass@1.71.0) transitivePeerDependencies: - '@types/node' - less @@ -18443,16 +18471,6 @@ snapshots: fsevents: 2.3.3 sass: 1.71.0 - vite@5.1.1(@types/node@20.11.21): - dependencies: - esbuild: 0.19.12 - postcss: 8.4.35 - rollup: 4.9.6 - optionalDependencies: - '@types/node': 20.11.21 - fsevents: 2.3.3 - optional: true - vite@5.1.1(@types/node@20.11.21)(sass@1.71.0): dependencies: esbuild: 0.19.12 @@ -18561,7 +18579,7 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.2 - vite: 5.1.1(@types/node@20.11.21) + vite: 5.1.1(@types/node@20.11.21)(sass@1.71.0) vite-node: 1.2.2(@types/node@20.11.21) why-is-node-running: 2.2.2 optionalDependencies: