diff --git a/apps/server/package.json b/apps/server/package.json index fe27248..f180f29 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -32,6 +32,7 @@ "postgres": "catalog:", "react": "catalog:", "react-dom": "catalog:", + "uuid": "catalog:", "zod": "catalog:" }, "devDependencies": { diff --git a/apps/server/src/db/schema.ts b/apps/server/src/db/schema.ts deleted file mode 100644 index 23d4231..0000000 --- a/apps/server/src/db/schema.ts +++ /dev/null @@ -1 +0,0 @@ -export { todoTable } from '@furtherverse/database/postgres/schema/index' diff --git a/apps/server/src/db/schema/index.ts b/apps/server/src/db/schema/index.ts new file mode 100644 index 0000000..a1cad6c --- /dev/null +++ b/apps/server/src/db/schema/index.ts @@ -0,0 +1 @@ +export * from './todo' diff --git a/apps/server/src/db/schema/todo.ts b/apps/server/src/db/schema/todo.ts new file mode 100644 index 0000000..d6ee127 --- /dev/null +++ b/apps/server/src/db/schema/todo.ts @@ -0,0 +1,8 @@ +import { boolean, pgTable, text } from 'drizzle-orm/pg-core' +import { generatedFields } from './utils/field' + +export const todoTable = pgTable('todo', { + ...generatedFields, + title: text('title').notNull(), + completed: boolean('completed').notNull().default(false), +}) diff --git a/apps/server/src/db/schema/utils/field.ts b/apps/server/src/db/schema/utils/field.ts new file mode 100644 index 0000000..4ba0ef9 --- /dev/null +++ b/apps/server/src/db/schema/utils/field.ts @@ -0,0 +1,58 @@ +import { sql } from 'drizzle-orm' +import { timestamp, uuid } from 'drizzle-orm/pg-core' +import { v7 as uuidv7 } from 'uuid' + +// id + +export const id = (name: string) => uuid(name) +export const pk = (name: string, strategy?: 'native' | 'extension') => { + switch (strategy) { + // PG 18+ + case 'native': + return id(name).primaryKey().default(sql`uuidv7()`) + + // PG 13+ with extension + case 'extension': + return id(name).primaryKey().default(sql`uuid_generate_v7()`) + + // Any PG version + default: + return id(name) + .primaryKey() + .$defaultFn(() => uuidv7()) + } +} + +// timestamp + +export const createdAt = (name = 'created_at') => + timestamp(name, { withTimezone: true }).notNull().defaultNow() + +export const updatedAt = (name = 'updated_at') => + timestamp(name, { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdateFn(() => new Date()) + +// generated fields + +export const generatedFields = { + id: pk('id'), + createdAt: createdAt('created_at'), + updatedAt: updatedAt('updated_at'), +} + +// Helper to create omit keys from generatedFields +const createGeneratedFieldKeys = >( + fields: T, +): Record => { + return Object.keys(fields).reduce( + (acc, key) => { + acc[key as keyof T] = true + return acc + }, + {} as Record, + ) +} + +export const generatedFieldKeys = createGeneratedFieldKeys(generatedFields) diff --git a/bun.lock b/bun.lock index 1ccb37e..e389d09 100644 --- a/bun.lock +++ b/bun.lock @@ -37,6 +37,7 @@ "postgres": "catalog:", "react": "catalog:", "react-dom": "catalog:", + "uuid": "catalog:", "zod": "catalog:", }, "devDependencies": {