Cloudflare D1 × drizzle ORMのバグ・注意点(updateメソッド)

2024/06/08に公開

はじめに

ある API の開発を以下の技術スタックでしています。

  • Hono 4.1.3
  • drizzle ORM 0.30.4
  • Cloudflare D1

Hono という edge functions 上で動作する (書き方は)express ライクなフレームワークを用いてエンドポイントを作成し、drizzle ORM を使って、Cloudflare が提供する SQLite データベースと通信をする構成です。

少しセットアップには苦戦しましたが、構築してしまえば非常に高速な API を作ることができますが、特に D1 は安定版の提供が開始したばかりでもありちょくちょくバグや注意すべきことに出くわすので、出会ったももは記事にしていこうと ✏️

update メソッドのバグ?

まずコード示します。

index.ts
import type { User } from './schema'
...

const app = new Hono()
app.patch(
  '/users',
  async (c) => {
    const userId = c.req.param('id')
    const body = await c.req.json<User>()
    const result = await db
      .update(users)
      .set(body)
      .where(eq(users.id, Number(userId)))
      .returning({ updatedUserId: users.id })

    console.log(result)

    return c.json({ ok })
  }
)
schema.ts
export const users = sqliteTable('users', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  name: text('name').unique(),
})

export type User = typeof users.$inferSelect

上記のように、指定された id のユーザーの情報を patch で更新します。更新したい値を JSON で body に渡します。以下、それぞれのパターンでどんな返り値が返ってくるか見てみます。前提として、存在しているユーザーは 1 ユーザーだけであり、その id2 とします。

存在しているユーザーに存在しているキーとその値を渡す

ユーザー ID が 2 のユーザーに{ name: 'テストユーザー' }を渡したとすると、コンソールには、

  [{ updatedUserId: 2 }]

が表示され値も更新されています。期待通りの挙動。

存在しているユーザーに存在していないキーとその値を渡す

ユーザー ID が 2 のユーザーに{ age: 28 }を渡したとすると、コンソールには、

  [{ updatedUserId: 2 }]

が表示されますが、age という列はないので、データは何も変化しません。にも関わらず、更新されたかのような返り値なので、??となりました。本来であれば、影響を与えた行がないのであれば、ユーザー ID は返ってこないはずですが、上記のように返ってきているので、drizzle ORM のバグ?なのかなと思っていますが、何か見落としがあるのかも?

存在しているユーザーに存在しているキーとその値、存在していないキーとその値の両方を渡す

ユーザー ID が 2 のユーザーに{ age: 28, name: 'テストユーザー' }を渡したとすると、コンソールには、

  [{ updatedUserId: 2 }]

が表示され、存在している name だけが更新されます。returning を使わずに result を表示させてみても、存在しないキーがあることに関する情報はないので、やはり検知はできません。

存在していないユーザーに任意の値を渡す

ユーザー ID が 10 のユーザーに任意の値を渡したとすると、コンソールには、

[]

が表示され、ユーザーが存在していないことを判別できます。

おわりに

drizzle ORM の Issue には投げましたが、
もし同様の事象に出会った方がいらっしゃればコメントお願いします 🙏

プラスクラス・スポーツ・インキュベーション株式会社

Discussion