index.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import { drizzle } from "drizzle-orm/postgres-js"
  2. import { Resource } from "@opencode/cloud-resource"
  3. export * from "drizzle-orm"
  4. import postgres from "postgres"
  5. const init = () => {
  6. const client = postgres({
  7. idle_timeout: 30000,
  8. connect_timeout: 30000,
  9. host: Resource.Database.host,
  10. database: Resource.Database.database,
  11. user: Resource.Database.username,
  12. password: Resource.Database.password,
  13. port: Resource.Database.port,
  14. ssl: {
  15. rejectUnauthorized: false,
  16. },
  17. max: 1,
  18. })
  19. return drizzle(client, {})
  20. }
  21. const createClient = "NODE_ENV" in process.env ? memo(init) : init
  22. import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core"
  23. import type { ExtractTablesWithRelations } from "drizzle-orm"
  24. import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js"
  25. import { Context } from "../context"
  26. import { memo } from "../util/memo"
  27. export namespace Database {
  28. export type Transaction = PgTransaction<
  29. PostgresJsQueryResultHKT,
  30. Record<string, unknown>,
  31. ExtractTablesWithRelations<Record<string, unknown>>
  32. >
  33. export type TxOrDb = Transaction | ReturnType<typeof createClient>
  34. const TransactionContext = Context.create<{
  35. tx: TxOrDb
  36. effects: (() => void | Promise<void>)[]
  37. }>()
  38. export async function use<T>(callback: (trx: TxOrDb) => Promise<T>) {
  39. try {
  40. const { tx } = TransactionContext.use()
  41. return tx.transaction(callback)
  42. } catch (err) {
  43. if (err instanceof Context.NotFound) {
  44. const client = createClient()
  45. const effects: (() => void | Promise<void>)[] = []
  46. const result = await TransactionContext.provide(
  47. {
  48. effects,
  49. tx: client,
  50. },
  51. () => callback(client),
  52. )
  53. await Promise.all(effects.map((x) => x()))
  54. return result
  55. }
  56. throw err
  57. }
  58. }
  59. export async function fn<Input, T>(callback: (input: Input, trx: TxOrDb) => Promise<T>) {
  60. return (input: Input) => use(async (tx) => callback(input, tx))
  61. }
  62. export async function effect(effect: () => any | Promise<any>) {
  63. try {
  64. const { effects } = TransactionContext.use()
  65. effects.push(effect)
  66. } catch {
  67. await effect()
  68. }
  69. }
  70. export async function transaction<T>(callback: (tx: TxOrDb) => Promise<T>, config?: PgTransactionConfig) {
  71. try {
  72. const { tx } = TransactionContext.use()
  73. return callback(tx)
  74. } catch (err) {
  75. if (err instanceof Context.NotFound) {
  76. const client = createClient()
  77. const effects: (() => void | Promise<void>)[] = []
  78. const result = await client.transaction(async (tx) => {
  79. return TransactionContext.provide({ tx, effects }, () => callback(tx))
  80. }, config)
  81. await Promise.all(effects.map((x) => x()))
  82. return result
  83. }
  84. throw err
  85. }
  86. }
  87. }