Open4
Cloudflare D1とDrizzleの組み合わせてで困ったこと
同名なカラム名を持つ2つのテーブルをJOINすると取得データがおかしくなる。
現象
/*
Post = sqliteTable(
'Post',
{
id: integer('id').primaryKey(),
slug: text('slug').notNull(),
userId: integer('userId'),
}
)
User = sqliteTable(
'User',
{
id: integer('id').primaryKey(),
name: text('name'),
}
)
*/
db
.select()
.from(Post)
.innerJoin(User, eq(Post.userId, User.id))
.all()
// => idというカラム列が2つのテーブルに存在して、おかしくなる。
原因
Cloudflare D1の不具合
暫定対応
- SELECT項目を絞る
- ASを付けて別名にする
- SQLの発行回数が増えるが結合せずに別々にデータを取得する
Drizzleのexists関数を使ったSQLが実行できない
現象
db
.select()
.from(User)
.where(
exists(
db
.select()
.from(Post)
.where(eq(Post.userId, User.id))
)
)
.all()
// => 吐かれるSQLが実行できない
原因
吐かれるSQLが以下となる
SELECT
"User"."id",
"User"."name"
FROM
"User"
WHERE
EXISTS((
SELECT
"Post"."id",
"Post"."slug",
"Post"."userId"
FROM
"Post"
WHERE
"Post"."userId" = "User"."id"
))
exists
関数のカッコが1つ多い状態でSQLが吐かれるため、シンタックスエラーとなる。
暫定対応
-
exists
関数を使わず自分でSQLを書く - 別のSQL(例えばGroup Byを使用したサブクエリ)に書き換える
複数のアプリケーションが同一のD1(SQLite)を参照する場合の開発環境に工夫が必要
現象
言葉では難しいが、例えばユーザ用に公開するサービス用のアプリケーションと運用者使う管理画面のアプリケーションの2つがあった場合にどちらも同じD1ないしSQLiteを参照することになると思う。この場合に以下のようなworkspaceを運用したとした場合にアプリケーションごとにSQLiteのファイルが必要にある
root
┣ packages
┃ ┣ database
┃ ┃ ┣ .wrangler // wrangler d1 migrations apply するとここにSQLiteができる
┃ ┃ ┣ migrations
┃ ┃ ┣ src
┃ ┃ ┃ ┗ schema.ts // 2つのアプリケーションが参照するDBのスキーマを格納
┃ ┃ ┗ package.json
┃ ┣ user
┃ ┃ ┣ .wrangler // 実際のアプリケーションが参照するD1(SQLiteのファイルはここ)
┃ ┃ ┗ package.json
┃ ┗ admin
┃ ┣ .wrangler // 実際のアプリケーションが参照するD1(SQLiteのファイルはここ)
┃ ┗ package.json
┗ package.json
原因
wranglerが参照するSQLiteのパスはアプリケーションディレクトリから固定のため。
暫定対応
SQLiteをレプリケーションすればいいが、開発環境なんでとりあえずSQLiteのファイルコピーで逃げる
Drizzle-kitでマイグレートの変更が検知できないバグがある
現象
具体的に遭遇したのはindexの変更。例えば以下のようにindexを変更したが、drizzle-kit generate:sqlite
では「No schema changes, nothing to migrate 😴」といって変更を検知してくれなかった
const PostTag = sqliteTable(
'PostTag',
{
id: integer('id').primaryKey(),
postId: integer('postId')
.notNull()
.references(() => Post.id),
tagId: integer('tagId')
.notNull()
.references(() => Tag.id),
},
(postTag) => ({
// uniqueIdx: index('PostTag_uniqueIdx').on( // 変更前は uniqueIndexではなく、indexとして定義していたため修正
uniqueIdx: uniqueIndex('PostTag_uniqueIdx').on(
postTag.postId,
postTag.tagId
),
postIdIdx: index('PostTag_postIdIdx').on(postTag.postId),
})
)
原因
たぶんバグ。Issueには上がってなかった。
暫定対応
とりあえず適当にカラム追加して、追加したカラムのSQLじゃなくて、DROP INDEX
と CREATE INDEX
に書き換えた。後マイグレーションのディレクトリに吐かれる meta/00xx_snapshot.json
に定義が出力されるのでそれに追加したカラム情報を消す。(indexが変更されているのはしっかり反映されてたのでバグだと思う)