{"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} from 'pqb/internal';\nimport { createDbWithAdapter } from 'pqb';\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    ...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\nfor (const key in types.builtins) {\n  const id = types.builtins[key as keyof typeof types.builtins];\n  defaultTypeParsers[id] = types.getTypeParser(id);\n}\n\n[\n  types.builtins.DATE,\n  types.builtins.TIMESTAMP,\n  types.builtins.TIMESTAMPTZ,\n  types.builtins.CIRCLE,\n  types.builtins.BYTEA,\n].forEach((id) => {\n  delete defaultTypeParsers[id];\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 queryClient = <T extends QueryResultRow = QueryResultRow>(\n  client: PoolClient,\n  text: string,\n  values?: unknown[],\n  // only has effect in a transaction\n  startingSavepoint?: string,\n  releasingSavepoint?: string,\n  // SQL session state (role and setConfig) from async storage\n  arraysMode?: boolean,\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  // 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 =\n        startingSavepoint || releasingSavepoint\n          ? performQueryOnClientWithSavepoint(\n              client,\n              params,\n              startingSavepoint,\n              releasingSavepoint,\n            )\n          : client.query(params);\n      promise.then(resolve, resolve);\n      return promise;\n    });\n  }\n\n  const promise =\n    startingSavepoint || releasingSavepoint\n      ? performQueryOnClientWithSavepoint(\n          client,\n          params,\n          startingSavepoint,\n          releasingSavepoint,\n        )\n      : client.query(params);\n\n  (client as unknown as { __lock?: Promise<unknown> }).__lock =\n    promise.catch(noop);\n\n  return promise;\n};\n\nexport const NodePostgresAdapter: DriverAdapter = {\n  manualPool: true,\n\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  close(pool: Pool): Promise<void> {\n    return pool.end();\n  },\n};\n\nconst defaultTypesConfig = {\n  getTypeParser(id: number) {\n    return defaultTypeParsers[id] || returnArg;\n  },\n};\n\nconst performQueryOnClientWithSavepoint = (\n  client: PoolClient,\n  params: unknown,\n  startingSavepoint?: string,\n  releasingSavepoint?: string,\n) => {\n  let promise = startingSavepoint\n    ? client\n        .query(`SAVEPOINT \"${startingSavepoint}\"`)\n        .then(() => client.query(params as never))\n    : client.query(params as never);\n\n  if (releasingSavepoint) {\n    promise = promise.then(\n      async (res) => {\n        await client.query(`RELEASE SAVEPOINT \"${releasingSavepoint}\"`);\n        return res;\n      },\n      async (err) => {\n        await client.query(`ROLLBACK TO SAVEPOINT \"${releasingSavepoint}\"`);\n        throw err;\n      },\n    );\n  }\n\n  return promise;\n};\n"],"mappings":"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"}