UNPKG

@pgxsinkit/pgwasm

Version:
262 lines (254 loc) • 9.58 kB
// @bun import { PgwasmError2 } from "../chunk-cpsnmzrf.js"; import { DATE, TIMESTAMP, TIMESTAMPTZ, INTERVAL } from "../chunk-d82gg1hx.js"; // packages/pgwasm/src/drizzle/driver.ts import { entityKind as entityKind2 } from "drizzle-orm/entity"; import { DefaultLogger } from "drizzle-orm/logger"; import { PgAsyncDatabase } from "drizzle-orm/pg-core/async/db"; import { PgDialect } from "drizzle-orm/pg-core/dialect"; // packages/pgwasm/src/drizzle/codecs.ts import { makePgArray, parsePgArray } from "drizzle-orm/pg-core/array"; import { arrayCompatNormalize, castToText, castToTextArr, genericPgCodecs, parseGeometryTuple, parseGeometryXY, parsePgArrayAndNormalize, refineGenericPgCodecs, textToDate, textToDateWithTz } from "drizzle-orm/pg-core/codecs"; import { base64ToUint8Array } from "drizzle-orm/utils"; var drizzleParsers = { [TIMESTAMP]: (value) => value, [TIMESTAMPTZ]: (value) => value, [INTERVAL]: (value) => value, [DATE]: (value) => value, 1231: (value) => value, 1115: (value) => value, 1185: (value) => value, 1187: (value) => value, 1182: (value) => value }; var hasBuffer = typeof Buffer !== "undefined"; var pgwasmCodecs = refineGenericPgCodecs({ bigint: { cast: castToText, castArray: castToTextArr, normalize: BigInt, normalizeArray: arrayCompatNormalize(BigInt) }, "bigint:string": { cast: castToText, castArray: castToTextArr }, "bigint:number": { cast: castToText, castArray: castToTextArr }, bigserial: { normalize: BigInt, normalizeArray: arrayCompatNormalize(BigInt), cast: castToText, castArray: castToTextArr }, "bigserial:number": { cast: castToText, castArray: castToTextArr }, bytea: hasBuffer ? { normalizeInJson: genericPgCodecs.bytea?.normalizeInJson, normalizeArrayInJson: genericPgCodecs.bytea?.normalizeArrayInJson, normalize: (value) => Buffer.from(value), normalizeArray: arrayCompatNormalize((value) => Buffer.from(value)) } : { normalizeInJson: base64ToUint8Array, normalizeArrayInJson: arrayCompatNormalize(base64ToUint8Array) }, interval: { castArray: castToTextArr }, date: { castArray: castToTextArr, normalize: textToDate, normalizeArray: arrayCompatNormalize(textToDate) }, "date:string": { castArray: castToTextArr }, timestamp: { castArray: castToTextArr, normalize: textToDateWithTz, normalizeArray: arrayCompatNormalize(textToDateWithTz) }, timestamptz: { castArray: castToTextArr, normalize: textToDate, normalizeArray: arrayCompatNormalize(textToDate) }, "timestamp:string": { castArray: castToTextArr }, "timestamptz:string": { castArray: castToTextArr }, json: { normalizeParam: (value) => typeof value === "object" ? value : JSON.stringify(value) }, jsonb: { normalizeParam: (value) => typeof value === "object" ? value : JSON.stringify(value) }, "geometry(point)": { normalizeArray: parsePgArrayAndNormalize(parseGeometryXY), castParam: (name) => `${name}::geometry`, castArrayParam: (name, _column, dimensions) => `${name}::geometry${"[]".repeat(dimensions)}`, normalizeParamArray: makePgArray }, "geometry(point):tuple": { normalizeArray: parsePgArrayAndNormalize(parseGeometryTuple), castParam: (name) => `${name}::geometry`, castArrayParam: (name, _column, dimensions) => `${name}::geometry${"[]".repeat(dimensions)}`, normalizeParamArray: makePgArray }, halfvec: { castParam: (name) => `${name}::halfvec`, castArrayParam: (name, _column, dimensions) => `${name}::halfvec${"[]".repeat(dimensions)}`, normalizeParamArray: makePgArray }, vector: { castParam: (name) => `${name}::vector`, castArrayParam: (name, _column, dimensions) => `${name}::vector${"[]".repeat(dimensions)}`, normalizeParamArray: makePgArray }, sparsevec: { normalizeArray: parsePgArray, castParam: (name) => `${name}::sparsevec`, castArrayParam: (name, _column, dimensions) => `${name}::sparsevec${"[]".repeat(dimensions)}`, normalizeParamArray: makePgArray } }); // packages/pgwasm/src/drizzle/session.ts import { NoopCache } from "drizzle-orm/cache/core/cache"; import { entityKind } from "drizzle-orm/entity"; import { NoopLogger } from "drizzle-orm/logger"; import { PgAsyncPreparedQuery, PgAsyncSession, PgAsyncTransaction } from "drizzle-orm/pg-core/async/session"; import { sql } from "drizzle-orm/sql/sql"; class PgwasmSession extends PgAsyncSession { static [entityKind] = "PgwasmSession"; #client; #relations; #options; #logger; #cache; constructor(client, dialect, relations, options = {}) { super(dialect); this.#client = client; this.#relations = relations; this.#options = options; this.#logger = options.logger ?? new NoopLogger; this.#cache = options.cache ?? new NoopCache; } prepareQuery(query, mode, _name, mapper, queryMetadata, cacheConfig) { const executor = async (params) => { const result = await this.#client.query(query.sql, params, { rowMode: mode === "arrays" ? "array" : "object", parsers: drizzleParsers }); return mode === "raw" ? result : result.rows; }; return new PgAsyncPreparedQuery(executor, query, mapper, mode, this.#logger, this.#cache, queryMetadata, cacheConfig); } async transaction(transaction, config) { const client = this.#client; if (client.transaction === undefined) { throw new Error("A transaction's session cannot begin another transaction; nest with tx.transaction()."); } return await client.transaction(async (handle) => { const session = new PgwasmSession(handle, this.dialect, this.#relations, this.#options); const tx = new PgwasmTransaction(this.dialect, session, this.#relations, undefined, false); if (config) await tx.setTransaction(config); return await transaction(tx); }); } } class PgwasmTransaction extends PgAsyncTransaction { static [entityKind] = "PgwasmTransaction"; #dialect; #session; constructor(dialect, session, relations, nestedIndex, parseRqbJson) { super(dialect, session, relations, nestedIndex, parseRqbJson); this.#dialect = dialect; this.#session = session; } async transaction(transaction) { const savepointName = `sp${this.nestedIndex + 1}`; const tx = new PgwasmTransaction(this.#dialect, this.#session, this._.relations, this.nestedIndex + 1, false); await tx.execute(sql.raw(`savepoint ${savepointName}`)); try { const result = await transaction(tx); await tx.execute(sql.raw(`release savepoint ${savepointName}`)); return result; } catch (error) { await tx.execute(sql.raw(`rollback to savepoint ${savepointName}`)); throw error; } } } // packages/pgwasm/src/drizzle/driver.ts class PgwasmDatabase extends PgAsyncDatabase { static [entityKind2] = "PgwasmDatabase"; } function jitMappersUsable(requested) { if (requested !== true) return false; try { const identity = new Function("input", '"use strict"; return input;'); return identity(true) === true; } catch { return false; } } function construct(client, config = {}) { const dialect = new PgDialect({ useJitMappers: jitMappersUsable(config.jit), codecs: config.codecs ?? pgwasmCodecs }); const logger = config.logger === true ? new DefaultLogger : config.logger === false ? undefined : config.logger; const relations = config.relations ?? {}; const session = new PgwasmSession(client, dialect, relations, { ...logger ? { logger } : {}, ...config.cache ? { cache: config.cache } : {} }); const db = new PgwasmDatabase(dialect, session, relations); const cache = config.cache; if (cache) db.$cache = { invalidate: (params) => cache.onMutate(params) }; return Object.assign(db, { $client: client }); } class UnsupportedDrizzleConfigError extends PgwasmError2 { name = "UnsupportedDrizzleConfigError"; form; constructor(form) { const given = form === "connection" ? "drizzle({ connection })" : form === "connection string" ? "drizzle(connectionString)" : "a drizzle() call without a pgwasm database"; super(`@pgxsinkit/pgwasm/drizzle does not open its own database, so ${given} is not supported: create the ` + "database with createPgwasm() and pass it as drizzle(pg, config) or drizzle({ client: pg, ...config })."); this.form = form; } } function isPgwasm(value) { return typeof value === "object" && value !== null && typeof value.query === "function"; } function drizzle(clientOrConfig, config) { const given = clientOrConfig; if (isPgwasm(given)) return construct(given, config); if (typeof given === "string") throw new UnsupportedDrizzleConfigError("connection string"); if (typeof given === "object" && given !== null) { const { client, ...rest } = given; if (isPgwasm(client)) return construct(client, rest); if (client === undefined && "connection" in given) throw new UnsupportedDrizzleConfigError("connection"); } throw new UnsupportedDrizzleConfigError("no client"); } var unavailable = { query: () => { throw new Error("drizzle.mock() has no database: build queries with it, run them elsewhere."); } }; drizzle.mock = function mock(config) { const db = construct(unavailable, config); return Object.assign(db, { $client: "$client is not available on drizzle.mock()" }); }; export { PgwasmDatabase, PgwasmSession, PgwasmTransaction, UnsupportedDrizzleConfigError, drizzle, drizzleParsers, pgwasmCodecs }; //# debugId=8E6C560DBCD746D464756E2164756E21