diff options
Diffstat (limited to 'packages/db')
| -rw-r--r-- | packages/db/drizzle.config.ts | 26 | ||||
| -rw-r--r-- | packages/db/migrations/0000_brainy_saracen.sql | 62 | ||||
| -rw-r--r-- | packages/db/migrations/meta/0000_snapshot.json | 358 | ||||
| -rw-r--r-- | packages/db/migrations/meta/_journal.json | 13 | ||||
| -rw-r--r-- | packages/db/package.json | 27 | ||||
| -rw-r--r-- | packages/db/src/index.ts | 16 | ||||
| -rw-r--r-- | packages/db/src/schema.ts | 69 |
7 files changed, 571 insertions, 0 deletions
diff --git a/packages/db/drizzle.config.ts b/packages/db/drizzle.config.ts new file mode 100644 index 00000000..b003e31a --- /dev/null +++ b/packages/db/drizzle.config.ts @@ -0,0 +1,26 @@ +import type { Config } from "drizzle-kit"; +import * as dotenv from "dotenv"; + +// Load the right env file based on environment +if (process.env.NODE_ENV === "production") { + dotenv.config({ path: ".env.production" }); +} else { + dotenv.config({ path: ".env.local" }); +} + +if (!process.env.DATABASE_URL) { + throw new Error("DATABASE_URL is not set"); +} + +export default { + schema: "./src/schema.ts", + dialect: "postgresql", + migrations: { + table: "drizzle_migrations", + }, + dbCredentials: { + url: process.env.DATABASE_URL, + }, + out: "./migrations", + strict: process.env.NODE_ENV === "production", +} satisfies Config;
\ No newline at end of file diff --git a/packages/db/migrations/0000_brainy_saracen.sql b/packages/db/migrations/0000_brainy_saracen.sql new file mode 100644 index 00000000..2c6ab2b2 --- /dev/null +++ b/packages/db/migrations/0000_brainy_saracen.sql @@ -0,0 +1,62 @@ +CREATE TABLE "accounts" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL +); +--> statement-breakpoint +ALTER TABLE "accounts" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "sessions" ( + "id" text PRIMARY KEY NOT NULL, + "expires_at" timestamp NOT NULL, + "token" text NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "ip_address" text, + "user_agent" text, + "user_id" text NOT NULL, + CONSTRAINT "sessions_token_unique" UNIQUE("token") +); +--> statement-breakpoint +ALTER TABLE "sessions" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "users" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "email_verified" boolean NOT NULL, + "image" text, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + CONSTRAINT "users_email_unique" UNIQUE("email") +); +--> statement-breakpoint +ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "verifications" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); +--> statement-breakpoint +ALTER TABLE "verifications" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +CREATE TABLE "waitlist" ( + "id" text PRIMARY KEY NOT NULL, + "email" text NOT NULL, + "created_at" timestamp NOT NULL, + CONSTRAINT "waitlist_email_unique" UNIQUE("email") +); +--> statement-breakpoint +ALTER TABLE "waitlist" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "accounts" ADD CONSTRAINT "accounts_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
\ No newline at end of file diff --git a/packages/db/migrations/meta/0000_snapshot.json b/packages/db/migrations/meta/0000_snapshot.json new file mode 100644 index 00000000..bb0699e4 --- /dev/null +++ b/packages/db/migrations/meta/0000_snapshot.json @@ -0,0 +1,358 @@ +{ + "id": "33a6742f-89da-4ac5-958f-421aa1cf9bd6", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_user_id_users_id_fk": { + "name": "accounts_user_id_users_id_fk", + "tableFrom": "accounts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sessions_token_unique": { + "name": "sessions_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.verifications": { + "name": "verifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": true + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +}
\ No newline at end of file diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json new file mode 100644 index 00000000..e8c21e9e --- /dev/null +++ b/packages/db/migrations/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1750753385927, + "tag": "0000_brainy_saracen", + "breakpoints": true + } + ] +}
\ No newline at end of file diff --git a/packages/db/package.json b/packages/db/package.json new file mode 100644 index 00000000..94990dc9 --- /dev/null +++ b/packages/db/package.json @@ -0,0 +1,27 @@ +{ + "name": "@opencut/db", + "version": "0.0.0", + "description": "Database package for OpenCut", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts", + "./schema": "./src/schema.ts", + "./drizzle.config": "./drizzle.config.ts" + }, + "scripts": { + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio" + }, + "dependencies": { + "drizzle-orm": "^0.44.2", + "postgres": "^3.4.5" + }, + "devDependencies": { + "drizzle-kit": "^0.31.1", + "dotenv": "^16.4.7", + "@types/pg": "^8.11.10" + } +} diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts new file mode 100644 index 00000000..b712776c --- /dev/null +++ b/packages/db/src/index.ts @@ -0,0 +1,16 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; +import * as schema from "./schema"; + +if (!process.env.DATABASE_URL) { + throw new Error("DATABASE_URL is not set"); +} + +// Create the postgres client +const client = postgres(process.env.DATABASE_URL); + +// Create the drizzle instance +export const db = drizzle(client, { schema }); + +// Re-export schema for convenience +export * from "./schema";
\ No newline at end of file diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts new file mode 100644 index 00000000..12fc7689 --- /dev/null +++ b/packages/db/src/schema.ts @@ -0,0 +1,69 @@ +import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core"; + +export const users = pgTable("users", { + id: text("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified") + .$defaultFn(() => false) + .notNull(), + image: text("image"), + createdAt: timestamp("created_at") + .$defaultFn(() => /* @__PURE__ */ new Date()) + .notNull(), + updatedAt: timestamp("updated_at") + .$defaultFn(() => /* @__PURE__ */ new Date()) + .notNull(), +}).enableRLS(); + +export const sessions = pgTable("sessions", { + id: text("id").primaryKey(), + expiresAt: timestamp("expires_at").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), + userId: text("user_id") + .notNull() + .references(() => users.id, { onDelete: "cascade" }), +}).enableRLS(); + +export const accounts = pgTable("accounts", { + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => users.id, { onDelete: "cascade" }), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), +}).enableRLS(); + +export const verifications = pgTable("verifications", { + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at").$defaultFn( + () => /* @__PURE__ */ new Date() + ), + updatedAt: timestamp("updated_at").$defaultFn( + () => /* @__PURE__ */ new Date() + ), +}).enableRLS(); + +export const waitlist = pgTable("waitlist", { + id: text("id").primaryKey(), + email: text("email").notNull().unique(), + createdAt: timestamp("created_at") + .$defaultFn(() => /* @__PURE__ */ new Date()) + .notNull(), +}).enableRLS();
\ No newline at end of file |
