/** * Dialect-agnostic Drizzle schema helpers. * * Templates import `table`, `text`, `integer`, and `now` from here instead of * importing directly from `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core`. * The correct dialect is chosen at runtime based on `DATABASE_URL`. * * Usage: * import { table, text, integer, now } from "@agent-native/core/db/schema"; * * export const users = table("users", { * id: text("id").primaryKey(), * name: text("name").notNull(), * active: integer("active", { mode: "boolean" }).notNull().default(true), * createdAt: text("created_at").notNull().default(now()), * }); */ import { sql } from "drizzle-orm"; import { pgTable, alias as pgAlias, index as pgIndex, text as pgText, integer as pgInteger, boolean as pgBoolean, doublePrecision as pgDoublePrecision, uniqueIndex as pgUniqueIndex, } from "drizzle-orm/pg-core"; import { sqliteTable, alias as sqliteAlias, index as sqliteIndex, text as sqliteText, integer as sqliteInteger, real as sqliteReal, uniqueIndex as sqliteUniqueIndex, } from "drizzle-orm/sqlite-core"; import { getDialect } from "./client.js"; // No caching — getDialect() handles its own caching once env is available. // On CF Workers, this runs at import time before env bindings are set, so // caching here would lock in the wrong dialect. function pg(): boolean { return getDialect() === "postgres"; } /** * Define a table. Delegates to `pgTable` or `sqliteTable` based on dialect. */ export const table: typeof sqliteTable = ((...args: any[]) => pg() ? (pgTable as any)(...args) : (sqliteTable as any)(...args)) as any; export const alias: typeof sqliteAlias = ((...args: any[]) => pg() ? (pgAlias as any)(...args) : (sqliteAlias as any)(...args)) as any; export const index: typeof sqliteIndex = ((...args: any[]) => pg() ? (pgIndex as any)(...args) : (sqliteIndex as any)(...args)) as any; export const uniqueIndex: typeof sqliteUniqueIndex = ((...args: any[]) => pg() ? (pgUniqueIndex as any)(...args) : (sqliteUniqueIndex as any)(...args)) as any; /** * Text column. Works identically in both dialects. * Supports `{ enum: [...] }` config in both. */ export const text: typeof sqliteText = ((...args: any[]) => pg() ? (pgText as any)(...args) : (sqliteText as any)(...args)) as any; /** * Integer column. * * Handles `{ mode: "boolean" }` transparently — maps to Postgres `boolean` * type when running against Postgres, and SQLite `integer` with boolean * coercion when running against SQLite. */ export const integer: typeof sqliteInteger = ((...args: any[]) => { if (pg() && args[1]?.mode === "boolean") { return (pgBoolean as any)(args[0]); } return pg() ? (pgInteger as any)(...args) : (sqliteInteger as any)(...args); }) as any; /** * Real/float column. * * Maps to `real` on SQLite and `double precision` on Postgres. * Use for decimal values like weight, macros, etc. */ export const real: typeof sqliteReal = ((...args: any[]) => { return pg() ? (pgDoublePrecision as any)(...args) : (sqliteReal as any)(...args); }) as any; /** * Dialect-agnostic "current timestamp" SQL expression. * Use with `.default(now())` on text columns storing timestamps. * * - Postgres: `now()` * - SQLite: `(datetime('now'))` */ export function now() { return pg() ? sql`now()` : sql`(datetime('now'))`; } export { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm"; // Ownership / sharing primitives — templates opt a resource into the framework // sharing system by spreading ownableColumns() into the table and pairing it // with createSharesTable(). See .agents/skills/sharing/SKILL.md. export { ownableColumns, createSharesTable, type Visibility, type ShareRole, type PrincipalType, } from "../sharing/schema.js";