{"version":3,"file":"node-postgres.mjs","names":[],"sources":["../src/adapters/node-postgres.ts"],"sourcesContent":["import pg, { DatabaseError, Pool, PoolClient, PoolConfig } from 'pg';\nimport {\n  AdapterConfigBase,\n  ColumnSchemaConfig,\n  noop,\n  QueryResult,\n  QueryResultRow,\n  RecordUnknown,\n  returnArg,\n  DefaultColumnTypes,\n  DefaultSchemaConfig,\n  DbOptions,\n  DbResult,\n  QuerySchema,\n  AdapterClass,\n  DriverAdapter,\n  defaultSchemaConfig,\n  quoteIdentifier,\n  AdapterSchemaConfigOptions,\n} from 'pqb/internal';\nimport { createDbWithAdapter } from 'pqb';\nimport { HackySavepointState, SavepointCallback } from './adapter';\n\nconst schemaConfig: AdapterSchemaConfigOptions = {\n  jsonEncodedByDriver: false,\n};\n\nexport const nodePostgresSchemaConfig = Object.assign(\n  () => defaultSchemaConfig(schemaConfig),\n  schemaConfig,\n);\n\nexport const createDb = <\n  SchemaConfig extends ColumnSchemaConfig = DefaultSchemaConfig,\n  ColumnTypes = DefaultColumnTypes<SchemaConfig>,\n>({\n  log,\n  ...options\n}: DbOptions<SchemaConfig, ColumnTypes> &\n  Omit<NodePostgresAdapterOptions, 'log'>): DbResult<ColumnTypes> => {\n  return createDbWithAdapter({\n    schemaConfig: nodePostgresSchemaConfig as unknown as () => SchemaConfig,\n    ...options,\n    log,\n    adapter: new AdapterClass({\n      driverAdapter: NodePostgresAdapter,\n      config: options,\n    }),\n  });\n};\n\nconst { types } = pg;\n\nexport interface TypeParsers {\n  [K: number]: (input: string) => unknown;\n}\n\nconst defaultTypeParsers: TypeParsers = {\n  [types.builtins.DATE]: returnArg,\n  [types.builtins.TIMESTAMP]: returnArg,\n  [types.builtins.TIMESTAMPTZ]: returnArg,\n  [types.builtins.CIRCLE]: returnArg,\n  600: returnArg, // point\n};\n\nexport interface AdapterConfig\n  extends\n    Omit<AdapterConfigBase, 'searchPath' | 'ssl'>,\n    Omit<PoolConfig, 'types' | 'connectionString'> {\n  databaseURL?: string;\n}\n\nexport interface NodePostgresAdapterOptions extends Omit<AdapterConfig, 'log'> {\n  schema?: QuerySchema;\n}\n\nconst preparedStatements = new WeakMap<\n  PoolClient,\n  { names: Map<string, string>; index: number }\n>();\n\nconst queryClient = <T = QueryResultRow>(\n  client: PoolClient,\n  text: string,\n  values?: unknown[],\n  arraysMode?: boolean,\n  prepare?: true,\n): Promise<QueryResult<T>> => {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  const params: any = {\n    text,\n    values,\n    rowMode: arraysMode ? 'array' : undefined,\n    types: defaultTypesConfig,\n  };\n\n  if (prepare) {\n    let statements = preparedStatements.get(client);\n    if (!statements) {\n      statements = { names: new Map(), index: 0 };\n      preparedStatements.set(client, statements);\n    }\n\n    let name = statements.names.get(text);\n    if (!name) {\n      name = `orchid_${statements.index++}`;\n      statements.names.set(text, name);\n    }\n    params.name = name;\n  }\n\n  // When using save points (it's in transaction), need to perform a single query at a time.\n  // stating 1 then 2 then releasing 1 would fail.\n  // Start 1, release 1, start 2, release 2, and so on.\n  const { __lock } = client as unknown as { __lock?: Promise<unknown> };\n  if (__lock) {\n    let resolve: () => void | undefined;\n    (client as unknown as RecordUnknown).__lock = new Promise<void>((res) => {\n      resolve = () => {\n        res();\n      };\n    });\n\n    return __lock.then(() => {\n      const promise = client.query(params) as Promise<QueryResult>;\n      promise.then(resolve, resolve);\n      return promise.then((result) =>\n        arraysMode ? normalizeArraysResult(result) : result,\n      ) as Promise<QueryResult<T>>;\n    });\n  }\n\n  const promise = client.query(params) as Promise<QueryResult>;\n\n  (client as unknown as { __lock?: Promise<unknown> }).__lock =\n    promise.catch(noop);\n\n  return promise.then((result) =>\n    arraysMode ? normalizeArraysResult(result) : result,\n  ) as Promise<QueryResult<T>>;\n};\n\nexport const NodePostgresAdapter: DriverAdapter = {\n  manualPool: true,\n  schemaConfig,\n  errorClass: DatabaseError,\n  errorFields: {\n    message: 'message',\n    length: 'length',\n    name: 'name',\n    severity: 'severity',\n    code: 'code',\n    detail: 'detail',\n    hint: 'hint',\n    position: 'position',\n    internalPosition: 'internalPosition',\n    internalQuery: 'internalQuery',\n    where: 'where',\n    schema: 'schema',\n    table: 'table',\n    column: 'column',\n    dataType: 'dataType',\n    constraint: 'constraint',\n    file: 'file',\n    line: 'line',\n    routine: 'routine',\n  },\n\n  configure(config: NodePostgresAdapterOptions): pg.Pool {\n    if (config.databaseURL) {\n      (config as PoolConfig).connectionString = config.databaseURL;\n    }\n\n    if (config.setConfig?.search_path) {\n      config = {\n        ...config,\n        options: `${config.options ? `${config.options} ` : ''}-c search_path=\"${config.setConfig.search_path}\"`,\n      };\n    }\n\n    return new pg.Pool(config);\n  },\n\n  queryClient,\n\n  borrow(pool: Pool): Promise<PoolClient> {\n    return pool.connect();\n  },\n\n  release(client: PoolClient): void {\n    client.release();\n  },\n\n  async begin<DriverClient, Result>(\n    pool: Pool,\n    cb: (adapter: DriverClient) => Promise<Result>,\n    options?: string,\n  ): Promise<Result> {\n    const client = await pool.connect();\n\n    try {\n      await queryClient(client, options ? 'BEGIN ' + options : 'BEGIN');\n\n      let result;\n      try {\n        result = await cb(client as DriverClient);\n      } catch (err) {\n        await queryClient(client, 'ROLLBACK');\n        throw err;\n      }\n      await queryClient(client, 'COMMIT');\n      return result as Result;\n    } finally {\n      client.release();\n    }\n  },\n\n  async savepoint<T>(\n    client: PoolClient,\n    // node-postgres doesn't need to switch the client in a savepoint\n    _setClient: (client: PoolClient) => void,\n    name: string,\n    cb: () => Promise<T>,\n    onSavepoint: SavepointCallback | undefined,\n    beforeRelease: SavepointCallback | undefined,\n    onRelease: SavepointCallback | undefined,\n    beforeRollback: SavepointCallback | undefined,\n    onRollback: SavepointCallback | undefined,\n  ): Promise<T> {\n    const safeName = quoteIdentifier(name);\n    // `ROLLBACK TO` below must not run for a savepoint that wasn't created\n    await queryClient(client, `SAVEPOINT ${safeName}`);\n    try {\n      onSavepoint?.();\n      const res = await cb();\n      beforeRelease?.();\n      await queryClient(client, `RELEASE SAVEPOINT ${safeName}`);\n      onRelease?.();\n      return res;\n    } catch (err) {\n      beforeRollback?.();\n      await queryClient(client, `ROLLBACK TO SAVEPOINT ${safeName}`);\n      onRollback?.();\n      throw err;\n    }\n  },\n\n  async hackySavepoint<T extends QueryResultRow>(\n    client: PoolClient,\n    // node-postgres doesn't need to switch the client in a savepoint\n    _setClient: (client: PoolClient) => void,\n    state: HackySavepointState,\n    text: string,\n    values?: unknown[],\n    arraysMode?: boolean,\n    prepare?: true,\n    onSavepoint?: SavepointCallback,\n    beforeRelease?: SavepointCallback,\n    onRelease?: SavepointCallback,\n    beforeRollback?: SavepointCallback,\n    onRollback?: SavepointCallback,\n  ): Promise<QueryResult<T>> {\n    const safeName = state.name.replaceAll('\"', '\"\"');\n\n    let resolve: () => void;\n    let reject: (err: unknown) => void;\n    const promise = new Promise<void>((res, rej) => {\n      resolve = res;\n      reject = rej;\n    });\n    // handled: `rollback` rejects it even after the savepoint has failed\n    promise.catch(noop);\n\n    let resultResolve: (res: QueryResult<T>) => void;\n    let resultReject: (err: unknown) => void;\n    const resultPromise = new Promise<QueryResult<T>>((res, rej) => {\n      resultResolve = res;\n      resultReject = rej;\n    });\n\n    const savepointPromise = (async () => {\n      // `ROLLBACK TO` below must not run for a savepoint that wasn't created\n      await queryClient(client, `SAVEPOINT ${safeName}`);\n      try {\n        onSavepoint?.();\n\n        try {\n          const res = await queryClient<T>(\n            client,\n            text,\n            values,\n            arraysMode,\n            prepare,\n          );\n          resultResolve!(res as QueryResult<T>);\n        } catch (err) {\n          resultReject!(err);\n          throw err;\n        }\n\n        const result = await promise;\n        beforeRelease?.();\n        await queryClient(client, `RELEASE SAVEPOINT ${safeName}`);\n        onRelease?.();\n        return result;\n      } catch (err) {\n        beforeRollback?.();\n        await queryClient(client, `ROLLBACK TO SAVEPOINT ${safeName}`);\n        onRollback?.();\n        throw err;\n      }\n    })();\n    // the query never runs when `SAVEPOINT` fails\n    savepointPromise.catch(resultReject!);\n\n    state.activeSavepoint = {\n      async release() {\n        resolve();\n        await savepointPromise;\n      },\n      async rollback(err) {\n        reject(err);\n        await savepointPromise.catch(noop);\n      },\n    };\n\n    return resultPromise;\n  },\n\n  close(pool: Pool): Promise<void> {\n    return pool.end();\n  },\n};\n\nconst defaultTypesConfig = {\n  getTypeParser(id: number, format?: 'text' | 'binary') {\n    return defaultTypeParsers[id] || types.getTypeParser(id, format as 'text');\n  },\n};\n\nconst normalizeArraysResult = <\n  // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n  R extends any[] = any[],\n>(\n  result: QueryResult,\n): QueryResult<R> => {\n  return result as unknown as QueryResult<R>;\n};\n"],"mappings":"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"}