summaryrefslogtreecommitdiffhomepage
path: root/cloud/core/src/drizzle
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-08-08 13:22:54 -0400
committerFrank <[email protected]>2025-08-08 13:24:32 -0400
commit183e0911b76025a1f2a82e979d9834fec2131d0e (patch)
tree9987c1753bd64d1ce1d174ab397f1a8c681f642c /cloud/core/src/drizzle
parentc7bb19ad0712469063eab35589aa5d3602b0c5b1 (diff)
downloadopencode-183e0911b76025a1f2a82e979d9834fec2131d0e.tar.gz
opencode-183e0911b76025a1f2a82e979d9834fec2131d0e.zip
wip: gateway
Diffstat (limited to 'cloud/core/src/drizzle')
-rw-r--r--cloud/core/src/drizzle/index.ts94
-rw-r--r--cloud/core/src/drizzle/types.ts29
2 files changed, 123 insertions, 0 deletions
diff --git a/cloud/core/src/drizzle/index.ts b/cloud/core/src/drizzle/index.ts
new file mode 100644
index 000000000..76220f2a2
--- /dev/null
+++ b/cloud/core/src/drizzle/index.ts
@@ -0,0 +1,94 @@
+import { drizzle } from "drizzle-orm/postgres-js"
+import { Resource } from "sst"
+export * from "drizzle-orm"
+import postgres from "postgres"
+
+function createClient() {
+ const client = postgres({
+ idle_timeout: 30000,
+ connect_timeout: 30000,
+ host: Resource.Database.host,
+ database: Resource.Database.database,
+ user: Resource.Database.username,
+ password: Resource.Database.password,
+ port: Resource.Database.port,
+ ssl: {
+ rejectUnauthorized: false,
+ },
+ max: 1,
+ })
+
+ return drizzle(client, {})
+}
+
+import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core"
+import type { ExtractTablesWithRelations } from "drizzle-orm"
+import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js"
+import { Context } from "../context"
+
+export namespace Database {
+ export type Transaction = PgTransaction<
+ PostgresJsQueryResultHKT,
+ Record<string, unknown>,
+ ExtractTablesWithRelations<Record<string, unknown>>
+ >
+
+ export type TxOrDb = Transaction | ReturnType<typeof createClient>
+
+ const TransactionContext = Context.create<{
+ tx: TxOrDb
+ effects: (() => void | Promise<void>)[]
+ }>()
+
+ export async function use<T>(callback: (trx: TxOrDb) => Promise<T>) {
+ try {
+ const { tx } = TransactionContext.use()
+ return tx.transaction(callback)
+ } catch (err) {
+ if (err instanceof Context.NotFound) {
+ const client = createClient()
+ const effects: (() => void | Promise<void>)[] = []
+ const result = await TransactionContext.provide(
+ {
+ effects,
+ tx: client,
+ },
+ () => callback(client),
+ )
+ await Promise.all(effects.map((x) => x()))
+ return result
+ }
+ throw err
+ }
+ }
+ export async function fn<Input, T>(callback: (input: Input, trx: TxOrDb) => Promise<T>) {
+ return (input: Input) => use(async (tx) => callback(input, tx))
+ }
+
+ export async function effect(effect: () => any | Promise<any>) {
+ try {
+ const { effects } = TransactionContext.use()
+ effects.push(effect)
+ } catch {
+ await effect()
+ }
+ }
+
+ export async function transaction<T>(callback: (tx: TxOrDb) => Promise<T>, config?: PgTransactionConfig) {
+ try {
+ const { tx } = TransactionContext.use()
+ return callback(tx)
+ } catch (err) {
+ if (err instanceof Context.NotFound) {
+ const client = createClient()
+ const effects: (() => void | Promise<void>)[] = []
+ const result = await client.transaction(async (tx) => {
+ return TransactionContext.provide({ tx, effects }, () => callback(tx))
+ }, config)
+ await Promise.all(effects.map((x) => x()))
+ return result
+ }
+ throw err
+ }
+ }
+}
diff --git a/cloud/core/src/drizzle/types.ts b/cloud/core/src/drizzle/types.ts
new file mode 100644
index 000000000..5ae95d011
--- /dev/null
+++ b/cloud/core/src/drizzle/types.ts
@@ -0,0 +1,29 @@
+import { bigint, timestamp, varchar } from "drizzle-orm/pg-core"
+
+export const ulid = (name: string) => varchar(name, { length: 30 })
+
+export const workspaceColumns = {
+ get id() {
+ return ulid("id").notNull()
+ },
+ get workspaceID() {
+ return ulid("workspace_id").notNull()
+ },
+}
+
+export const id = () => ulid("id").notNull()
+
+export const utc = (name: string) =>
+ timestamp(name, {
+ withTimezone: true,
+ })
+
+export const currency = (name: string) =>
+ bigint(name, {
+ mode: "number",
+ })
+
+export const timestamps = {
+ timeCreated: utc("time_created").notNull().defaultNow(),
+ timeDeleted: utc("time_deleted"),
+}