{"version":3,"file":"session.cjs","names":["neonConfig","PgAsyncSession","entityKind","NoopLogger","NoopCache","PgAsyncPreparedQuery","PgDialect","types","PgAsyncTransaction","sql"],"sources":["../../src/netlify-db/session.ts"],"sourcesContent":["import type { CustomTypesConfig, FullQueryResults, NeonQueryPromise, Pool, PoolClient } from '@neondatabase/serverless';\nimport { neonConfig, types } from '@neondatabase/serverless';\nimport type { BatchItem } from '~/batch.ts';\nimport type { Cache } from '~/cache/core/cache.ts';\nimport { NoopCache } from '~/cache/core/cache.ts';\nimport type { WithCacheConfig } from '~/cache/core/types.ts';\nimport { entityKind } from '~/entity.ts';\nimport type { Logger } from '~/logger.ts';\nimport { NoopLogger } from '~/logger.ts';\nimport type { NeonHttpClient, NeonHttpQueryResultHKT, NeonHttpSessionOptions } from '~/neon-http/session.ts';\nimport { PgAsyncPreparedQuery, PgAsyncSession, PgAsyncTransaction } from '~/pg-core/async/session.ts';\nimport type { PgCodecs } from '~/pg-core/codecs.ts';\nimport { PgDialect } from '~/pg-core/dialect.ts';\nimport type { PgTransactionConfig, PreparedQueryConfig } from '~/pg-core/session.ts';\nimport { preparedStatementName } from '~/query-name-generator.ts';\nimport type { AnyRelations } from '~/relations.ts';\nimport type { Query } from '~/sql/sql.ts';\nimport { sql } from '~/sql/sql.ts';\n\n/**\n * Ensures a WebSocket implementation is available for Neon's\n * serverless driver. The Neon driver checks for a global WebSocket\n * automatically, but this sets it on neonConfig explicitly so the\n * check only happens once.\n */\nfunction ensureWebSocket(): void {\n\tif (neonConfig.webSocketConstructor) return;\n\n\tif (typeof WebSocket !== 'undefined') {\n\t\tneonConfig.webSocketConstructor = WebSocket as any;\n\t}\n}\n\nexport type NetlifyDbClient = {\n\thttp: NeonHttpClient;\n\tpool: Pool;\n};\n\nexport interface NetlifyDbSessionOptions extends NeonHttpSessionOptions {\n\tuseJitMappers?: boolean | undefined;\n\ttransactionCodecs?: PgCodecs | undefined;\n}\n\nexport class NetlifyDbSession<TRelations extends AnyRelations>\n\textends PgAsyncSession<NeonHttpQueryResultHKT, TRelations>\n{\n\tstatic override readonly [entityKind]: string = 'NetlifyDbSession';\n\n\tprivate clientQuery: (sql: string, params: any[], opts: Record<string, any>) => NeonQueryPromise<any, any>;\n\tprivate logger: Logger;\n\tprivate cache: Cache;\n\n\tconstructor(\n\t\treadonly httpClient: NeonHttpClient,\n\t\treadonly pool: Pool,\n\t\tdialect: PgDialect,\n\t\tprivate relations: TRelations,\n\t\treadonly options: NetlifyDbSessionOptions,\n\t) {\n\t\tsuper(dialect);\n\t\t// `httpClient.query` is for @neondatabase/serverless v1.0.0 and up, where the\n\t\t// root query function `httpClient` is only usable as a template function;\n\t\t// `httpClient` is a fallback for earlier versions\n\t\tthis.clientQuery = (httpClient as any).query ?? httpClient as any;\n\t\tthis.logger = options.logger ?? new NoopLogger();\n\t\tthis.cache = options.cache ?? new NoopCache();\n\t}\n\n\tprepareQuery<T extends PreparedQueryConfig = PreparedQueryConfig>(\n\t\tquery: Query,\n\t\tmode: 'arrays' | 'objects' | 'raw',\n\t\t_name: string | boolean,\n\t\tmapper: ((rows: any[]) => any) | undefined,\n\t\tqueryMetadata?: {\n\t\t\ttype: 'select' | 'update' | 'delete' | 'insert';\n\t\t\ttables: string[];\n\t\t},\n\t\tcacheConfig?: WithCacheConfig,\n\t): PgAsyncPreparedQuery<T> {\n\t\tconst executor = (params?: unknown[]) => {\n\t\t\tif (mode === 'raw') {\n\t\t\t\t// otherwise raw queries with .then crash due to .then not existing on raw mode queries\n\t\t\t\treturn (async () =>\n\t\t\t\t\tthis.httpClient(query.sql, params, {\n\t\t\t\t\t\tarrayMode: false,\n\t\t\t\t\t\tfullResults: true,\n\t\t\t\t\t\tauthToken: this.options.authToken,\n\t\t\t\t\t}))();\n\t\t\t}\n\n\t\t\treturn this.httpClient(query.sql, params, {\n\t\t\t\tarrayMode: mode === 'arrays',\n\t\t\t\tfullResults: true,\n\t\t\t\tauthToken: this.options.authToken,\n\t\t\t}).then((it: any) => it.rows);\n\t\t};\n\n\t\treturn new PgAsyncPreparedQuery(executor, query, mapper, mode, this.logger, this.cache, queryMetadata, cacheConfig);\n\t}\n\n\tasync batch<U extends BatchItem<'pg'>, T extends Readonly<[U, ...U[]]>>(queries: T) {\n\t\tconst preparedQueries: PgAsyncPreparedQuery<any>[] = [];\n\t\tconst builtQueries: NeonQueryPromise<any, true>[] = [];\n\t\tconst q = this.httpClient;\n\n\t\tfor (const query of queries) {\n\t\t\tconst preparedQuery = query._prepare() as PgAsyncPreparedQuery<any>;\n\t\t\tconst builtQuery = preparedQuery.getQuery();\n\t\t\tpreparedQueries.push(preparedQuery);\n\t\t\tbuiltQueries.push(\n\t\t\t\tq(builtQuery.sql, builtQuery.params, {\n\t\t\t\t\tfullResults: true,\n\t\t\t\t\tarrayMode: preparedQuery.mode === 'arrays',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst batchResults = await this.httpClient.transaction(builtQueries, {\n\t\t\tauthToken: this.options.authToken,\n\t\t\tfullResults: true,\n\t\t\tarrayMode: true,\n\t\t});\n\t\treturn batchResults.map((result, i) =>\n\t\t\tpreparedQueries[i]!.mapper ? preparedQueries[i]!.mapper(result.rows) : result\n\t\t) as any;\n\t}\n\n\tasync query(query: string, params: unknown[]): Promise<FullQueryResults<true>> {\n\t\tthis.logger.logQuery(query, params);\n\t\tconst result = await this.clientQuery(query, params, { arrayMode: true, fullResults: true });\n\t\treturn result;\n\t}\n\n\tasync queryObjects(\n\t\tquery: string,\n\t\tparams: unknown[],\n\t): Promise<FullQueryResults<false>> {\n\t\treturn this.clientQuery(query, params, { arrayMode: false, fullResults: true });\n\t}\n\n\toverride async transaction<T>(\n\t\ttransaction: (tx: NetlifyDbTransaction<TRelations>) => Promise<T>,\n\t\tconfig: PgTransactionConfig = {},\n\t): Promise<T> {\n\t\tensureWebSocket();\n\t\tconst poolClient = await this.pool.connect();\n\t\tconst dialect = new PgDialect({\n\t\t\tuseJitMappers: this.options.useJitMappers,\n\t\t\tcodecs: this.options.transactionCodecs,\n\t\t});\n\t\tconst session = new NetlifyDbWsSession<TRelations>(\n\t\t\tpoolClient,\n\t\t\tdialect,\n\t\t\tthis.relations,\n\t\t\tthis.options,\n\t\t);\n\t\tconst tx = new NetlifyDbTransaction<TRelations>(\n\t\t\tdialect,\n\t\t\tsession,\n\t\t\tthis.relations,\n\t\t\tundefined,\n\t\t\tfalse,\n\t\t);\n\n\t\ttry {\n\t\t\tawait tx.execute(sql`begin ${tx.getTransactionConfigSQL(config)}`);\n\t\t} catch (e) {\n\t\t\tpoolClient.release();\n\t\t\tthrow e;\n\t\t}\n\n\t\ttry {\n\t\t\tif (typeof config.snapshot === 'string') {\n\t\t\t\tawait tx.execute(tx.setTransactionSnapshotSQL(config.snapshot));\n\t\t\t}\n\t\t\tconst result = await transaction(tx);\n\t\t\tawait tx.execute(sql`commit`);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tawait tx.execute(sql`rollback`);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tpoolClient.release();\n\t\t}\n\t}\n}\n\nconst noop = (val: any) => val;\nconst typeConfig: CustomTypesConfig = {\n\tgetTypeParser: <CustomTypesConfig['getTypeParser']> ((typeId, format) => {\n\t\tswitch (typeId as number) {\n\t\t\tcase types.builtins.TIMESTAMPTZ:\n\t\t\tcase types.builtins.TIMESTAMP:\n\t\t\tcase types.builtins.DATE:\n\t\t\tcase types.builtins.INTERVAL:\n\t\t\tcase 1231: // numeric[]\n\t\t\tcase 1115: // timestamp[]\n\t\t\tcase 1185: // timestamp with timezone[]\n\t\t\tcase 1187: // interval[]\n\t\t\tcase 1182: // date[]\n\t\t\t\treturn noop;\n\t\t\tdefault:\n\t\t\t\treturn types.getTypeParser(typeId, format as any);\n\t\t}\n\t}),\n};\n\n/**\n * Internal WebSocket-based session used only within transactions.\n * Delegates all queries to a PoolClient over WebSocket, using\n * NeonPreparedQuery from the neon-serverless adapter.\n */\nexport class NetlifyDbWsSession<TRelations extends AnyRelations>\n\textends PgAsyncSession<NeonHttpQueryResultHKT, TRelations>\n{\n\tstatic override readonly [entityKind]: string = 'NetlifyDbWsSession';\n\n\tprivate logger: Logger;\n\tprivate cache: Cache;\n\n\tconstructor(\n\t\tprivate client: PoolClient,\n\t\tdialect: PgDialect,\n\t\tprivate relations: TRelations,\n\t\toptions: NeonHttpSessionOptions = {},\n\t) {\n\t\tsuper(dialect);\n\t\tthis.logger = options.logger ?? new NoopLogger();\n\t\tthis.cache = options.cache ?? new NoopCache();\n\t}\n\n\tprepareQuery<T extends PreparedQueryConfig = PreparedQueryConfig>(\n\t\tquery: Query,\n\t\tmode: 'arrays' | 'objects' | 'raw',\n\t\tname: string | boolean,\n\t\tmapper: ((rows: any[]) => any) | undefined,\n\t\tqueryMetadata?: {\n\t\t\ttype: 'select' | 'update' | 'delete' | 'insert';\n\t\t\ttables: string[];\n\t\t},\n\t\tcacheConfig?: WithCacheConfig,\n\t): PgAsyncPreparedQuery<T> {\n\t\tconst queryName = typeof name === 'string'\n\t\t\t? name\n\t\t\t: name === true\n\t\t\t? preparedStatementName(query.sql, query.params)\n\t\t\t: undefined;\n\n\t\tconst executor = async (params?: unknown[]) => {\n\t\t\treturn this.client.query({\n\t\t\t\tname: queryName,\n\t\t\t\trowMode: mode === 'arrays' ? 'array' : undefined as any,\n\t\t\t\ttext: query.sql,\n\t\t\t\ttypes: typeConfig,\n\t\t\t}, params).then((r) => mode === 'raw' ? r : r.rows);\n\t\t};\n\n\t\treturn new PgAsyncPreparedQuery<T>(\n\t\t\texecutor,\n\t\t\tquery,\n\t\t\tmapper,\n\t\t\tmode,\n\t\t\tthis.logger,\n\t\t\tthis.cache,\n\t\t\tqueryMetadata,\n\t\t\tcacheConfig,\n\t\t);\n\t}\n\toverride async transaction<T>(\n\t\t_transaction: (tx: NetlifyDbTransaction<TRelations>) => Promise<T>,\n\t\t_config?: PgTransactionConfig,\n\t): Promise<T> {\n\t\tthrow new Error('Nested transactions are handled by NetlifyDbTransaction via savepoints');\n\t}\n}\n\nexport class NetlifyDbTransaction<TRelations extends AnyRelations>\n\textends PgAsyncTransaction<NeonHttpQueryResultHKT, TRelations>\n{\n\tstatic override readonly [entityKind]: string = 'NetlifyDbTransaction';\n\n\toverride async transaction<T>(\n\t\ttransaction: (tx: NetlifyDbTransaction<TRelations>) => Promise<T>,\n\t): Promise<T> {\n\t\tconst savepointName = `sp${this.nestedIndex + 1}`;\n\t\tconst tx = new NetlifyDbTransaction<TRelations>(\n\t\t\tthis.dialect,\n\t\t\tthis.session,\n\t\t\tthis._.relations,\n\t\t\tthis.nestedIndex + 1,\n\t\t\tfalse,\n\t\t);\n\t\tawait tx.execute(sql.raw(`savepoint ${savepointName}`));\n\t\ttry {\n\t\t\tconst result = await transaction(tx);\n\t\t\tawait tx.execute(sql.raw(`release savepoint ${savepointName}`));\n\t\t\treturn result;\n\t\t} catch (e) {\n\t\t\tawait tx.execute(sql.raw(`rollback to savepoint ${savepointName}`));\n\t\t\tthrow e;\n\t\t}\n\t}\n}\n"],"mappings":"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"}