簡単なTodoリストAPIのためにD1とDrizzleに触れる
HonoとCloudfrare Workersで簡単なTodoリストAPIを作っていて、いまはローカルのモックデータを使ってAPIのガワだけできたところ。
ローカルのデータを何かしらに永続化したくて、「KVとD1のどっちかかなあ」ってなって(よく知らない)、TodoだけじゃなくてUserも登場させたい・プロパティごとに書き込みをやりたい、あたりの理由でKVじゃきつそうってなって、D1使うならDrizzleがいいらしいってmizchiさんの記事で読んだなあってなって、とりあえずスクラップを開いた。
DBとかORMの類にふれること自体が初めて
D1に公式対応しているらしいのでDrizzle側から攻める
Drizzle ORM is a headless TypeScript ORM with a head.
どういうこと?
Drizzle lets you define and manage database schema in typescript, lets you access your data in SQL-like or relational way, has a massive variety of opt-in tools which makes Drizzle an ultimate tool for managing and accessing your SQL data.
"SQL-like or relational way"この2つで何が対比されているのかもよくわかってない
あ、すぐ下に書いてあった。これがSQL-likeということらしい。
// Access your data
await db
.select()
.from(countries)
.leftJoin(cities, eq(cities.countryId, countries.id))
.where(eq(countries.id, 10))
あー、で、SQLっぽくない抽象化を施したやつがrelational wayってことなのかな?
const result = await db.query.users.findMany({
with: {
posts: true
},
});
あんまりよくわかってないけどとりあえずDrizzle for D1のページ
D1のset upはさすがに公式読むか
手元にWorkersプロジェクト自体はすでにあるので、wrangler d1 create todo-list
から
吐き出されたbindingをwrangler.tomlに書いた
うーん、ここからDrizzleでスキーマ定義とかしたい
ここらへんを見てる
これでいいのかなあ
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", {
userId: integer("userId").primaryKey().notNull(),
name: text("name").notNull(),
iconUrl: text("iconUrl"),
createdAt: integer("createdAt", { mode: "timestamp" }).notNull(),
});
export const todos = sqliteTable("todos", {
id: integer("id").primaryKey().notNull(),
title: text("title").notNull(),
status: text("status", { enum: ["todo", "doing", "done"] }).notNull(),
assigneeId: integer("assigneeId"),
createdAt: integer("createdAt", { mode: "timestamp" }).notNull(),
});
見てる
ni drizzle-kit drizzle-orm -D
してpnpm drizzle-kit generate:sqlite --out migrations --schema src/schema.ts
したらこれが出てきた
CREATE TABLE `todos` (
`id` integer PRIMARY KEY NOT NULL,
`title` text NOT NULL,
`status` text NOT NULL,
`assigneeId` integer,
`createdAt` integer NOT NULL
);
--> statement-breakpoint
CREATE TABLE `users` (
`userId` integer PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`iconUrl` text,
`createdAt` integer NOT NULL
);
mizchiさんの記事のとおりにやって.wrangler/state/v3/d1/206039d5-f4d4-4648-bf12-49fe93704edf/db.sqlite
が生成された
Honoだとnew Hono()
のときにbindingsをかませることによってcontextからD1にアクセスできるらしい。
import type { Config } from "drizzle-kit";
export default {
schema: "./src/schema.ts",
driver: "better-sqlite",
dbCredentials: {
url: ".wrangler/state/v3/d1/206039d5-f4d4-4648-bf12-49fe93704edf/db.sqlite",
},
} satisfies Config;
これで立ち上げることができた。絶対shadcn/ui。
型は別に効いてないっぽい。そういうもんか?
あ、Add recordのsave changeのときに型があってないとこうなる
えー、適当な値をinsertしたいときにはどこからやればいいのだろう
export const users = sqliteTable("users", {
userId: text("userId").primaryKey().notNull().$defaultFn(generateId),
name: text("name").notNull().default(""),
iconUrl: text("iconUrl"),
createdAt: integer("createdAt", { mode: "timestamp" })
.notNull()
.$defaultFn(() => new Date()),
});
defaultFnを設定すればstudioからでも自動で値が挿入されるかなと思ったら、datetype mismatchと怒られてできなかった。原因わからず。
ためしにcreatedAtのプロパティを消してもdatetype mismatchになるなあ、なんで?
キャッシュだったっぽい?色々消して新しく作り直したらいけた。
Date問題をイマイチ解決できないまま、一旦いやになったのでClose