本文へ移動
章と記事の一覧

動かすストレージ

D1

SQLite。SQL、索引、課金される「行数」

エディタへ移動

export default {
  async fetch(request, env) {
    // DDL は prepare().run() で実行(exec() は改行で文を分割するため注意)
    // Execute DDL with prepare().run() (exec() splits statements on newlines)
    await env.DB.prepare(
      "CREATE TABLE IF NOT EXISTS playground_notes (id INTEGER PRIMARY KEY AUTOINCREMENT, body TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')))",
    ).run();

    // プリペアドステートメントで値を安全にバインド(SQLインジェクション防止)
    // Bind parameters safely using prepared statements (prevents SQL injection)
    await env.DB.prepare("INSERT INTO playground_notes (body) VALUES (?)")
      .bind("note " + new Date().toISOString())
      .run();

    const count = await env.DB.prepare("SELECT COUNT(*) AS n FROM playground_notes").first();
    console.log("rows =", count.n);

    // 注意: このインデックスは下の ORDER BY id では使われない。WHERE created_at … のためのもの
    // Note: this index is not used by the ORDER BY id query below; it serves WHERE created_at … queries
    await env.DB.prepare(
      "CREATE INDEX IF NOT EXISTS idx_notes_created ON playground_notes (created_at)",
    ).run();

    const { results } = await env.DB.prepare(
      "SELECT id, body, created_at FROM playground_notes ORDER BY id DESC LIMIT 5",
    ).all();

    return Response.json({ total: count.n, latest: results });
  },
};

実行結果

実行するとここに結果が出ます。ネットワークは塞がれていますが、D1・KV・R2・Durable Object の状態は訪問者全員で共有されます。