Skip to content

Commit

Permalink
Turso migration (#76)
Browse files Browse the repository at this point in the history
* Remove compose.yaml

* Migrate front-end to Turso's SQLite

* Migrate collab server to Turso

* Remove MySQL Extension
  • Loading branch information
BrianUribe6 authored Mar 11, 2024
1 parent f2e6a88 commit 38cebf0
Show file tree
Hide file tree
Showing 16 changed files with 515 additions and 207 deletions.
10 changes: 0 additions & 10 deletions .env.example

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ yarn-error.log*
# Misc
.DS_Store
*.pem

# SQLite
local.db
15 changes: 15 additions & 0 deletions apps/collab-server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The following is a sample a .env file, to get started create a copy and name
# it ".env".

NODE_ENV=development

# Must match NEXTAUTH_SECRET on front-end as it is used to sign and validate JWTs
AUTH_SECRET=secret

TURSO_DATABASE_URL=file:../../local.db

# Production

# NODE_ENV=production
# TURSO_AUTH_TOKEN=

2 changes: 2 additions & 0 deletions apps/collab-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
"@hocuspocus/extension-logger": "^2.8.1",
"@hocuspocus/extension-sqlite": "^2.8.1",
"@hocuspocus/server": "^2.8.1",
"@libsql/client": "^0.5.3",
"jose": "^5.2.2",
"mysql2": "^3.6.5",
"zod": "^3.22.4"
},
"devDependencies": {
"@jotter/typescript-config": "*",
"@types/node": "^20.10.1",
"dotenv": "^16.4.5",
"tsx": "^4.6.1",
"typescript": "^5.3.2"
}
Expand Down
16 changes: 12 additions & 4 deletions apps/collab-server/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from "zod";
import "dotenv/config";

type EnvironmentVariables = z.infer<typeof envSchema>;

Expand All @@ -12,11 +13,18 @@ declare global {
const envSchema = z.object({
NODE_ENV: z.union([z.literal("development"), z.literal("production")]),
PORT: z.optional(z.string()),
DATABASE_USER: z.string().min(1),
DATABASE_PASS: z.string().min(1),
DATABASE_HOST: z.string().min(1),
DATABASE_NAME: z.string().min(1),
AUTH_SECRET: z.string().min(1),
TURSO_DATABASE_URL: z.string().min(1),
TURSO_AUTH_TOKEN: z
.string()
.min(1)
.optional()
.refine((token) => {
if (process.env.NODE_ENV === "production") {
return Boolean(token);
}
return true;
}, "A token is required to access production database."),
});

export const env = envSchema.parse(process.env);
57 changes: 0 additions & 57 deletions apps/collab-server/src/extensions/MySQL.ts

This file was deleted.

23 changes: 4 additions & 19 deletions apps/collab-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Database } from "@hocuspocus/extension-database";
import { Logger } from "@hocuspocus/extension-logger";
import { Hocuspocus } from "@hocuspocus/server";
import MySQL from "./extensions/MySQL.js";
import { env } from "./env.js";
import { jwtVerify } from "jose";
import { env } from "./env.js";
import tursoConfiguration from "./turso-config.js";

const PORT = env.PORT ? Number(env.PORT) : 1234;
const IS_PRODUCTION = env.NODE_ENV === "production";

// Configure the server …
const server = new Hocuspocus({
Expand All @@ -16,22 +16,7 @@ const server = new Hocuspocus({
await jwtVerify(data.token, key);
},

extensions: [
new Logger(),

new MySQL({
user: env.DATABASE_USER,
host: env.DATABASE_HOST,
database: env.DATABASE_NAME,
password: env.DATABASE_PASS,

// Enable SSL on production. Production database will reject the connection
// when this flag is not set.
ssl: {
rejectUnauthorized: IS_PRODUCTION,
},
}),
],
extensions: [new Logger(), new Database(tursoConfiguration)],
});

// // … and run it!
Expand Down
41 changes: 41 additions & 0 deletions apps/collab-server/src/turso-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { DatabaseConfiguration } from "@hocuspocus/extension-database";
import { createClient } from "@libsql/client";
import { env } from "./env.js";

const client = createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN,
});

const tursoConfiguration: DatabaseConfiguration = {
async fetch({ documentName }) {
const res = await client.execute({
sql: `SELECT name, data
FROM document
WHERE name = ?
`,
args: [documentName],
});

const data = res.rows[0]?.data;
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}

return null;
},

async store({ documentName, state: documentData }) {
const now = new Date().getTime();
await client.execute({
sql: `UPDATE document
SET data = ?,
modifiedOn = ?
WHERE name = ?
`,
args: [documentName, now, documentData],
});
},
};

export default tursoConfiguration;
5 changes: 1 addition & 4 deletions apps/front-end/.env
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
NEXT_PUBLIC_COLLAB_SERVER_URL=ws://localhost:1234

# Local development database
# This should match the same one configured for the collaboration server
DATABASE_URL=mysql://root:pass@localhost/jotter

TURSO_DATABASE_URL=file:../../local.db

NEXTAUTH_URL=http://localhost:3000
4 changes: 2 additions & 2 deletions apps/front-end/drizzle.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { defineConfig } from "drizzle-kit";

export default defineConfig({
schema: "./src/schema.ts",
driver: "mysql2",
driver: "libsql",
out: "./drizzle",
dbCredentials: {
uri: process.env.DATABASE_URL!,
url: process.env.TURSO_DATABASE_URL!,
},
});
9 changes: 4 additions & 5 deletions apps/front-end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
"version": "0.1.0",
"private": true,
"scripts": {
"predev": "docker compose --env-file ../../.env up -d",
"dev": "next dev",
"dev:collab": "turbo run dev --filter=front-end --filter=collab-server",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test:e2e": "playwright test",
"db:generate": "drizzle-kit generate:mysql",
"db:push": "drizzle-kit push:mysql"
"db:generate": "drizzle-kit generate:sqlite",
"db:push": "drizzle-kit push:sqlite"
},
"dependencies": {
"@auth/drizzle-adapter": "^0.7.0",
Expand All @@ -24,6 +23,7 @@
"@lexical/selection": "^0.13.0",
"@lexical/utils": "^0.13.0",
"@lexical/yjs": "^0.13.0",
"@libsql/client": "^0.5.3",
"@radix-ui/react-accordion": "^1.1.1",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-context-menu": "^2.1.3",
Expand All @@ -40,13 +40,12 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^0.2.0",
"drizzle-orm": "^0.29.3",
"drizzle-orm": "^0.29.5",
"eslint": "^8.51.0",
"eslint-config-next": "^14.1.1",
"jose": "^5.2.2",
"jotai": "^2.4.3",
"lexical": "^0.13.0",
"mysql2": "^3.9.1",
"nanoid": "^5.0.2",
"next": "^14.1.1",
"next-auth": "^4.24.5",
Expand Down
12 changes: 11 additions & 1 deletion apps/front-end/src/config/env-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ const envSchema = z.object({
DISCORD_SECRET: z.string().min(1),
DISCORD_CLIENT_ID: z.string().min(1),
NEXTAUTH_SECRET: z.string().min(1),
DATABASE_URL: z.string().min(1),
TURSO_DATABASE_URL: z.string().min(1),
TURSO_AUTH_TOKEN: z
.string()
.min(1)
.optional()
.refine((token) => {
if (process.env.NODE_ENV === "production") {
return Boolean(token);
}
return true;
}, "A token is required to access production database."),
NEXTAUTH_URL: z.string().min(1),
});

Expand Down
11 changes: 7 additions & 4 deletions apps/front-end/src/lib/db.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import mysql from "mysql2/promise";
import env from "@/config/env-server";
import { drizzle } from "drizzle-orm/mysql2";
import * as schema from "@/schema";
import { createClient } from "@libsql/client";
import { drizzle } from "drizzle-orm/libsql";

const connection = await mysql.createConnection(env.DATABASE_URL);
const connection = await createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN,
});

const db = drizzle(connection, { mode: "planetscale", schema });
const db = drizzle(connection, { schema });

export default db;
Loading

0 comments on commit 38cebf0

Please sign in to comment.