diff --git a/.gitignore b/.gitignore index 1170717..db0e51b 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +# Wrangler cache +**/.wrangler/* diff --git a/durable-objects-database-per-user/src/durableDatabase.ts b/durable-objects-database-per-user/src/durableDatabase.ts new file mode 100644 index 0000000..8ec5d80 --- /dev/null +++ b/durable-objects-database-per-user/src/durableDatabase.ts @@ -0,0 +1,50 @@ +import { DurableObject } from 'cloudflare:workers'; +import { drizzle } from 'drizzle-orm/durable-sqlite'; +import { migrate } from 'drizzle-orm/durable-sqlite/migrator'; +import { Bindings } from '../bindings'; +import migrations from '../drizzle/migrations'; +import * as notes from "./db/index"; +import * as schema from "./db/schemas"; + +import { DB } from './db/types'; + +export class DurableDatabase extends DurableObject { + db: DB; + + constructor(ctx: DurableObjectState, env: Bindings) { + super(ctx, env); + // Initialize Drizzle with the Durable Object's storage + this.db = drizzle(ctx.storage, { schema, logger: true }); + + // Run migrations before accepting any requests + ctx.blockConcurrencyWhile(async () => { + await this._migrate(); + }); + } + + async notesCreate(note: Parameters[1]): ReturnType { + return await notes.create(this.db, note); + } + + async notesGet(params: Parameters[1]): ReturnType { + return await notes.get(this.db, params); + } + + async notesList(): ReturnType { + return await notes.list(this.db); + } + + async notesDel(params: Parameters[1]): ReturnType { + return await notes.del(this.db, params); + } + + private async _migrate() { + migrate(this.db, migrations); + } +} + +export function getDurableDatabaseStub(env: Bindings, userId: string) { + const doId = env.DurableDatabase.idFromName(userId); + return env.DurableDatabase.get(doId); +} + diff --git a/durable-objects-database-per-user/src/index.ts b/durable-objects-database-per-user/src/index.ts index 9d8d940..ea365be 100644 --- a/durable-objects-database-per-user/src/index.ts +++ b/durable-objects-database-per-user/src/index.ts @@ -1,53 +1,47 @@ -import { DurableObject } from 'cloudflare:workers'; -import { Hono } from 'hono' +import { Hono } from 'hono'; import { Bindings } from '../bindings'; -import { drizzle } from 'drizzle-orm/durable-sqlite'; -import { migrate } from 'drizzle-orm/durable-sqlite/migrator'; -import migrations from '../drizzle/migrations'; -import * as schema from "./db/schemas"; -import * as notes from "./db/index"; +import { DurableDatabase, getDurableDatabaseStub } from './durableDatabase'; +export { DurableDatabase } from './durableDatabase'; -import { DB } from './db/types'; +// Add a type for the variables stored in the Hono context +type Variables = { + stub: DurableObjectStub; +}; + +const STUB = 'stub'; -const app = new Hono<{ Bindings: Bindings }>(); +const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); app.get('/', async (c) => { return c.json({ message: "Hello World!" }) }); -export default { - async fetch(request: Request, env: Bindings, ctx: ExecutionContext): Promise { - return app.fetch(request, env, ctx); - }, -}; - -function getDurableDatabaseStub(env: Bindings, userId: string) { - const doId = env.DurableDatabase.idFromName(userId); - return env.DurableDatabase.get(doId); -} +app.use('/:userId/*', async (c, next) => { + const userId = c.req.param("userId"); + const stub = getDurableDatabaseStub(c.env, userId); + c.set(STUB, stub); + await next(); +}); // Create a note for a user app.post('/:userId', async (c) => { - const userId = c.req.param("userId"); const { text } = await c.req.json(); - const stub = getDurableDatabaseStub(c.env, userId); + const stub = c.get(STUB) as DurableObjectStub; const note = await stub.notesCreate({ text }); return c.json({ note }) }); // List all notes for a user app.get('/:userId', async (c) => { - const userId = c.req.param("userId"); - const stub = getDurableDatabaseStub(c.env, userId); + const stub = c.get(STUB) as DurableObjectStub; const notes = await stub.notesList() return c.json({ notes }) }); // Get a specific note for a user app.get('/:userId/:noteId', async (c) => { - const userId = c.req.param("userId"); const noteId = c.req.param("noteId"); - const stub = getDurableDatabaseStub(c.env, userId); + const stub = c.get(STUB) as DurableObjectStub; const note = await stub.notesGet({ id: noteId }); if (!note) { return c.notFound(); @@ -57,44 +51,10 @@ app.get('/:userId/:noteId', async (c) => { // Delete a note for a user app.delete('/:userId/:noteId', async (c) => { - const userId = c.req.param("userId"); const noteId = c.req.param("noteId"); - const stub = getDurableDatabaseStub(c.env, userId); + const stub = c.get(STUB) as DurableObjectStub; const note = await stub.notesDel({ id: noteId }); return c.json({ note }) }); -export class DurableDatabase extends DurableObject { - private db: DB; - - constructor(ctx: DurableObjectState, env: Bindings) { - super(ctx, env); - // Initialize Drizzle with the Durable Object's storage - this.db = drizzle(ctx.storage, { schema, logger: true }); - - // Run migrations before accepting any requests - ctx.blockConcurrencyWhile(async () => { - await this._migrate(); - }); - } - - async notesCreate(note: Parameters[1]): ReturnType { - return await notes.create(this.db, note); - } - - async notesGet(params: Parameters[1]): ReturnType { - return await notes.get(this.db, params); - } - - async notesList(): ReturnType { - return await notes.list(this.db); - } - - async notesDel(params: Parameters[1]): ReturnType { - return await notes.del(this.db, params); - } - - private async _migrate() { - await migrate(this.db, migrations); - } -} +export default app; \ No newline at end of file