-
-
Save laiso/fe4ddd71f3f041db47daddc35b31c5c2 to your computer and use it in GitHub Desktop.
Prisma D1 Todo App https://prisma-d1.pages.dev/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createRoot } from "react-dom/client"; | |
import { InferRequestType, hc } from "hono/client"; | |
import { AppType } from "."; | |
import useSWR from "swr"; | |
import { useState } from "react"; | |
interface TodoListProps {} | |
const client = hc<AppType>("/"); | |
function TodoList(props: TodoListProps) { | |
const [title, setTitle] = useState(""); | |
const $get = client.todos.$get; | |
const fetcher = (arg: InferRequestType<typeof $get>) => async () => { | |
const res = await $get(arg); | |
return await res.json(); | |
}; | |
const { data, error, isLoading, mutate } = useSWR( | |
"/todos", | |
fetcher({ | |
query: { | |
name: "SWR", | |
}, | |
}) | |
); | |
if (error) return <div>failed to load</div>; | |
if (isLoading) return <div>loading...</div>; | |
return ( | |
<div> | |
<table> | |
<thead> | |
<tr> | |
<th>Title</th> | |
<th>Action</th> | |
</tr> | |
</thead> | |
<tbody> | |
{data.todos.map((todo: { id: number; title: string }) => ( | |
<tr key={todo.id}> | |
<td>{todo.title}</td> | |
<td> | |
<button | |
onClick={async () => { | |
const response = await client.todos[":id"].$delete({ | |
param: { | |
id: todo.id, | |
}, | |
}); | |
mutate(response.todos); | |
}} | |
> | |
Delete | |
</button> | |
</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
<table> | |
<tr> | |
<td> | |
<input | |
type="text" | |
name="title" | |
value={title} | |
onChange={(e) => setTitle(e.target.value)} | |
/> | |
</td> | |
<td> | |
<button | |
type="submit" | |
onClick={async () => { | |
setTitle(""); | |
const response = await client.todos.$post({ | |
form: { | |
title, | |
}, | |
}); | |
mutate(response.todos); | |
}} | |
> | |
Add | |
</button> | |
</td> | |
</tr> | |
</table> | |
</div> | |
); | |
} | |
const domNode = document.getElementById("root")!; | |
const root = createRoot(domNode); | |
root.render(<TodoList />); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charSet="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> | |
<link rel="stylesheet" href="src/styles.css" /> | |
<script type="module" src="src/client.tsx"></script> | |
<title>Prisma D1 Todo App</title> | |
</head> | |
<body> | |
<h1>Prisma D1 Todo App</h1> | |
<p> | |
<a href="https://www.npmjs.com/package/@prisma/adapter-d1?activeTab=readme"> | |
Prisma driver adapter for Cloudflare D1. | |
</a> | |
</p> | |
<div id="root"></div> | |
<footer><a href="https://gist.github.com/laiso/fe4ddd71f3f041db47daddc35b31c5c2">source code(gist.github.com)</a> | |
</footer> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Hono } from "hono"; | |
import { z } from "zod"; | |
import { zValidator } from "@hono/zod-validator"; | |
import { PrismaClient } from "@prisma/client"; | |
import { PrismaD1 } from "@prisma/adapter-d1"; | |
import { type D1Database } from "@cloudflare/workers-types"; | |
type Bindings = { | |
MY_DATABASE: D1Database; | |
ASSETS: any; | |
}; | |
function createPrismaClient(env: Bindings) { | |
const adapter = new PrismaD1(env.MY_DATABASE); | |
return new PrismaClient({ adapter }); | |
} | |
const app = new Hono<{ | |
Bindings: Bindings; | |
}>(); | |
const schema = z.object({ | |
title: z.string().min(1), | |
}); | |
app.get("/todos", async (c) => { | |
const prisma = createPrismaClient(c.env); | |
const todos = await prisma.todo.findMany(); | |
return c.json({ todos }); | |
}); | |
app.post("/todos", zValidator("form", schema), async (c) => { | |
const { title } = c.req.valid("form"); | |
const prisma = createPrismaClient(c.env); | |
const todo = await prisma.todo.create({ | |
data: { | |
title, | |
}, | |
}); | |
const todos = await prisma.todo.findMany(); | |
return c.json({ todos }); | |
}); | |
app.delete("/todos/:id", async (c) => { | |
const id = c.req.param("id"); | |
const prisma = createPrismaClient(c.env); | |
await prisma.todo.delete({ | |
where: { | |
id: Number(id), | |
}, | |
}); | |
const todos = await prisma.todo.findMany(); | |
return c.json({ todos }); | |
}); | |
app.get("/*", async (ctx) => { | |
return await ctx.env.ASSETS.fetch(ctx.req.raw); | |
}); | |
export type AppType = typeof app; | |
export default app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
generator client { | |
provider = "prisma-client-js" | |
previewFeatures = ["driverAdapters"] | |
} | |
datasource db { | |
provider = "sqlite" | |
url = "file:./dev.db" | |
} | |
model Todo { | |
id Int @id @default(autoincrement()) | |
title String | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font-family: Arial, sans-serif; | |
margin: 0; | |
padding: 20px; | |
background-color: #f5f5f5; | |
max-width: 500px; | |
} | |
#root { | |
max-width: 600px; | |
margin: 0 auto; | |
background-color: #fff; | |
padding: 20px; | |
border-radius: 5px; | |
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); | |
} | |
table { | |
width: 100%; | |
border-collapse: collapse; | |
margin-bottom: 20px; | |
} | |
th, td { | |
padding: 10px; | |
text-align: left; | |
border-bottom: 1px solid #ddd; | |
} | |
th { | |
background-color: #f5f5f5; | |
font-weight: bold; | |
} | |
input[type="text"] { | |
width: 100%; | |
padding: 8px; | |
border: 1px solid #ddd; | |
border-radius: 3px; | |
box-sizing: border-box; | |
} | |
button { | |
padding: 8px 12px; | |
background-color: #4CAF50; | |
color: #fff; | |
border: none; | |
border-radius: 3px; | |
cursor: pointer; | |
} | |
button:hover { | |
background-color: #45a049; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment