From d5555467829aeee8dc05e2d210e323be27b8f64e Mon Sep 17 00:00:00 2001 From: Cyber Date: Sat, 9 Aug 2025 21:32:13 +0200 Subject: [PATCH] feat: add pglite support (#138) --- .env.example | 2 ++ .gitignore | 3 +++ README.md | 2 +- apps/web/src/env.ts | 2 +- .../migrations/20250508083758_SetupTables.sql | 2 +- packages/db/package.json | 1 + packages/db/src/client.ts | 13 +++++++++++- pnpm-lock.yaml | 20 ++++++++++++++----- 8 files changed, 36 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index 42668521..817416dc 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,8 @@ # Required environment variables NEXT_PUBLIC_BASE_URL= # e.g. https://kan.bn BETTER_AUTH_SECRET= # Random 32+ char string (can gen with: openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32) + +# Fill if you want to use an external database POSTGRES_URL= # e.g. postgresql://kan:your_password@your_host:5432/kan # Only required if deploying from compose diff --git a/.gitignore b/.gitignore index 1aa31415..55f41119 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ docker-compose.override.yml # runtime env __ENV.js i18n.cache + +# pgdata +/apps/web/pgdata diff --git a/README.md b/README.md index 805b8108..a061cad8 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ pnpm dev | Variable | Description | Required | Example | | -------------------------------- | -------------------------------------------------------- | ------------------ | --------------------------------------------- | -| `POSTGRES_URL` | PostgreSQL connection URL | Yes | `postgres://user:pass@localhost:5432/db` | +| `POSTGRES_URL` | PostgreSQL connection URL | To use external database | `postgres://user:pass@localhost:5432/db` | | `EMAIL_FROM` | Sender email address | For Email | `"Kan "` | | `SMTP_HOST` | SMTP server hostname | For Email | `smtp.resend.com` | | `SMTP_PORT` | SMTP server port | For Email | `465` | diff --git a/apps/web/src/env.ts b/apps/web/src/env.ts index a3cba6ae..e9be5344 100644 --- a/apps/web/src/env.ts +++ b/apps/web/src/env.ts @@ -24,7 +24,7 @@ export const env = createEnv({ s.split(",").every((l) => z.string().url().safeParse(l).success), ) .optional(), - POSTGRES_URL: z.string().url(), + POSTGRES_URL: z.string().url().optional().or(z.literal('')), TRELLO_APP_API_KEY: z.string().optional(), TRELLO_APP_SECRET: z.string().optional(), STRIPE_SECRET_KEY: z.string().optional(), diff --git a/packages/db/migrations/20250508083758_SetupTables.sql b/packages/db/migrations/20250508083758_SetupTables.sql index ab14b2e7..b9a54227 100644 --- a/packages/db/migrations/20250508083758_SetupTables.sql +++ b/packages/db/migrations/20250508083758_SetupTables.sql @@ -1,4 +1,4 @@ -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS "uuid-ossp";--> statement-breakpoint CREATE TYPE "public"."board_visibility" AS ENUM('private', 'public');--> statement-breakpoint CREATE TYPE "public"."card_activity_type" AS ENUM('card.created', 'card.updated.title', 'card.updated.description', 'card.updated.index', 'card.updated.list', 'card.updated.label.added', 'card.updated.label.removed', 'card.updated.member.added', 'card.updated.member.removed', 'card.updated.comment.added', 'card.updated.comment.updated', 'card.updated.comment.deleted', 'card.archived');--> statement-breakpoint diff --git a/packages/db/package.json b/packages/db/package.json index 92f5d73f..4bfa25c9 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -39,6 +39,7 @@ "with-env": "dotenv -e ../../.env --" }, "dependencies": { + "@electric-sql/pglite": "^0.3.7", "@kan/shared": "workspace:^", "drizzle-orm": "^0.42.0", "drizzle-zod": "^0.5.1", diff --git a/packages/db/src/client.ts b/packages/db/src/client.ts index eae8f1d2..da504a08 100644 --- a/packages/db/src/client.ts +++ b/packages/db/src/client.ts @@ -1,8 +1,12 @@ import type { NodePgDatabase } from "drizzle-orm/node-postgres"; +import { drizzle as drizzlePgLite } from "drizzle-orm/pglite"; +import { uuid_ossp } from "@electric-sql/pglite/contrib/uuid_ossp"; import { drizzle as drizzlePg } from "drizzle-orm/node-postgres"; import { Pool } from "pg"; import * as schema from "./schema"; +import { PGlite } from "@electric-sql/pglite"; +import { migrate } from "drizzle-orm/pglite/migrator"; export type dbClient = NodePgDatabase & { $client: Pool; @@ -12,7 +16,14 @@ export const createDrizzleClient = (): dbClient => { const connectionString = process.env.POSTGRES_URL; if (!connectionString) { - throw new Error("POSTGRES_URL environment variable is not set"); + console.log("POSTGRES_URL environment variable is not set, using PGLite"); + + const client = new PGlite({ dataDir: "./pgdata", extensions: { uuid_ossp }}); + const db = drizzlePgLite(client, { schema }); + + migrate(db, { migrationsFolder: "../../packages/db/migrations" }); + + return db as unknown as dbClient; } const pool = new Pool({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d764094e..3e65d041 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -360,15 +360,18 @@ importers: packages/db: dependencies: + '@electric-sql/pglite': + specifier: ^0.3.7 + version: 0.3.7 '@kan/shared': specifier: workspace:^ version: link:../shared drizzle-orm: specifier: ^0.42.0 - version: 0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5) + version: 0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5) drizzle-zod: specifier: ^0.5.1 - version: 0.5.1(drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0) + version: 0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0) pg: specifier: ^8.11.3 version: 8.13.1 @@ -888,6 +891,9 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@electric-sql/pglite@0.3.7': + resolution: {integrity: sha512-5c3mybVrhxu5s47zFZtIGdG8YHkKCBENOmqxnNBjY53ZoDhADY/c5UqBDl159b7qtkzNPtbbb893wL9zi1kAuw==} + '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} @@ -6484,6 +6490,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -7852,6 +7859,8 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} + '@electric-sql/pglite@0.3.7': {} + '@emnapi/runtime@1.3.1': dependencies: tslib: 2.8.1 @@ -10845,8 +10854,9 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5): + drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5): optionalDependencies: + '@electric-sql/pglite': 0.3.7 '@neondatabase/serverless': 0.10.4 '@types/pg': 8.11.6 '@vercel/postgres': 0.10.0(utf-8-validate@6.0.3) @@ -10854,9 +10864,9 @@ snapshots: pg: 8.13.1 postgres: 3.4.5 - drizzle-zod@0.5.1(drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0): + drizzle-zod@0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0): dependencies: - drizzle-orm: 0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5) + drizzle-orm: 0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5) zod: 3.24.0 dunder-proto@1.0.0: