diff options
| author | Frank <[email protected]> | 2025-09-18 10:59:01 -0400 |
|---|---|---|
| committer | Frank <[email protected]> | 2025-09-18 10:59:01 -0400 |
| commit | 4ceabdffa07b1af8d99eb73622a4d549d99ec6d2 (patch) | |
| tree | 72e2ae62084a9e24cc76caffbd1f30dafc69ea56 /packages/console/core/src/drizzle | |
| parent | c87480cf931a6f8f8b55552558ef521f1918b578 (diff) | |
| download | opencode-4ceabdffa07b1af8d99eb73622a4d549d99ec6d2.tar.gz opencode-4ceabdffa07b1af8d99eb73622a4d549d99ec6d2.zip | |
wip: zen
Diffstat (limited to 'packages/console/core/src/drizzle')
| -rw-r--r-- | packages/console/core/src/drizzle/index.ts | 86 | ||||
| -rw-r--r-- | packages/console/core/src/drizzle/types.ts | 33 |
2 files changed, 119 insertions, 0 deletions
diff --git a/packages/console/core/src/drizzle/index.ts b/packages/console/core/src/drizzle/index.ts new file mode 100644 index 000000000..899f69148 --- /dev/null +++ b/packages/console/core/src/drizzle/index.ts @@ -0,0 +1,86 @@ +import { drizzle } from "drizzle-orm/planetscale-serverless" +import { Resource } from "@opencode/console-resource" +export * from "drizzle-orm" +import { Client } from "@planetscale/database" + +import { MySqlTransaction, type MySqlTransactionConfig } from "drizzle-orm/mysql-core" +import type { ExtractTablesWithRelations } from "drizzle-orm" +import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from "drizzle-orm/planetscale-serverless" +import { Context } from "../context" +import { memo } from "../util/memo" + +export namespace Database { + export type Transaction = MySqlTransaction< + PlanetscaleQueryResultHKT, + PlanetScalePreparedQueryHKT, + Record<string, never>, + ExtractTablesWithRelations<Record<string, never>> + > + + const client = memo(() => { + const result = new Client({ + host: Resource.Database.host, + username: Resource.Database.username, + password: Resource.Database.password, + }) + const db = drizzle(result, {}) + return db + }) + + export type TxOrDb = Transaction | ReturnType<typeof client> + + 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 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?: MySqlTransactionConfig) { + try { + const { tx } = TransactionContext.use() + return callback(tx) + } catch (err) { + if (err instanceof Context.NotFound) { + 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/packages/console/core/src/drizzle/types.ts b/packages/console/core/src/drizzle/types.ts new file mode 100644 index 000000000..f16ad5a8a --- /dev/null +++ b/packages/console/core/src/drizzle/types.ts @@ -0,0 +1,33 @@ +import { sql } from "drizzle-orm" +import { bigint, timestamp, varchar } from "drizzle-orm/mysql-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, { + fsp: 3, + }) + +export const currency = (name: string) => + bigint(name, { + mode: "number", + }) + +export const timestamps = { + timeCreated: utc("time_created").notNull().defaultNow(), + timeUpdated: utc("time_updated") + .notNull() + .default(sql`CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)`), + timeDeleted: utc("time_deleted"), +} |
