D1(SQLite)でDrizzleを使いだしてちょこちょこ調べることが必要になった項目のメモ
筆者はSQLiteを使いこんだことがないので、初歩的なことが多いです。
Schema周り
AutoIncrement
SQLiteでは列がInteger型かつPrimaryKeyの場合に設定できる。
integerからprimaryKeyを生やし、中にautoIncrementをtrueとすることで設定できる。
id: integer('id').primaryKey({ autoIncrement: true }),
Boolean
SQLiteにboolean型がないので、整数型を指定し、modeにbooleanを設定します。
結果 0 or 1 で判断するようになります。
import { integer, sqliteTable } from "drizzle-orm/sqlite-core";
const table = sqliteTable('table', {
id: integer('id', { mode: 'boolean' })
});
Date型
Booleanと同じく、SQLiteではない型なので、textに保存する。
created_atなど、カラムを追加した日付を入れたい場合は、default(sql
current_date)
などを使用する。
const table = sqliteTable("table", {
time: text("time").default(sql`CURRENT_TIME`),
date: text("date").default(sql`CURRENT_DATE`),
timestamp: text("timestamp").default(sql`CURRENT_TIMESTAMP`),
});
Query周り
Select
全件取得するSELECT
const result = await db.select().from(users);
部分的なSELECT
selectにobjectとして渡すことで部分選択ができる。
SQLと同様に、任意の式を使用できる(lowerName)
const result = await db.select({
field1: users.id,
lowerName: sql<string>`lower(${users.name})`,
}).from(users);
const { field1, field2 } = result[0];
動的条件付きのSELECT
SELECT部分で、三項演算子を利用できる。
下記では、withNameで名前を返すかどうかを選択できる。
async function selectUsers(withName: boolean) {
return db
.select({
id: users.id,
...(withName ? { name: users.name } : {}),
})
.from(users);
}
WHERE
Where
フィルター演算子を利用して、クエリをフィルタリングできる。
import { eq, lt, gte, ne } from 'drizzle-orm';
await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...
select "id", "name", "age" from "users" where "id" = 42;
select "id", "name", "age" from "users" where "id" < 42;
select "id", "name", "age" from "users" where "id" >= 42;
select "id", "name", "age" from "users" where "id" <> 42;
WHEREでのAND OR
and()
or()
内で、フィルター演算子を組み合わせて、実現できます。
import { eq, and, sql } from 'drizzle-orm';
await db.select().from(users).where(
and(
eq(users.id, 42),
eq(users.name, 'Dan')
)
);
その他でよく使うWHERE系のSQLは、直感的に使えるイメージでした。 .orderBy() count("*")など。
INSERT
INSERT時にコンフリクトした場合の処理
onConflictDoNothing()
をつけることで、重複している場合は、スルーします。
await db.insert(users)
.values({ id: 1, name: 'John' })
.onConflictDoNothing();
重複した場合に、Upsertする場合は、onConflictDoUpdate
をつけて、中身にtargetとsetを指定します。
await db.insert(users)
.values({ id: 1, name: 'Dan' })
.onConflictDoUpdate({ target: users.id, set: { name: 'John' } });