17
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DrizzleというORMを調べる

Last updated at Posted at 2023-06-15

追記 2024年10月1日

Update: finishing pull and push logic for policies and roles and preparing for beta release

更新: ポリシーとロールのプルとプッシュのロジックを完成させ、ベータ版リリースの準備をする。

追記終了

Star History

DrizzleのこのStarの伸びがこのORMに注目した理由です。

Star History Chart

Star数

10,185 2023年6月17日

Repository

drizzle-team/drizzle-orm: TypeScript ORM that feels like writing SQL

DrizzleORM 公式サイト

DrizzleORM - next gen TypeScript ORM

Drizzleとは?

Drizzle ORMは、最大限の型安全性を考慮して設計されたSQLデータベースのためのTypeScript ORMです。SQLマイグレーションを自動生成するためのdrizzle-kit CLIコンパニオンが付属しています。

Drizzle ORMは、フレームワークではなく、ライブラリであることを意図しています。どのようなレベルであっても、常にオプトインソリューションであることに変わりはありません。

ORMの主な哲学は、「SQLが分かればDrizzle ORMも分かる」です。可能な限りSQLのような構文に従い、強い型付けを行い、実行時ではなくコンパイル時に失敗するようにしています。

drizzle 単語の意味

  • 自動 霧雨が降る、小雨が降る、細かい水でぬらす
  • 他動 〔~を〕霧雨のように降らせる
    〔~を〕細い線のようにかける
  • 名 霧雨、こぬか雨、小雨、シトシト降る雨

特徴

  • 完全な型安全性
  • スマートな自動マイグレーション生成
  • ORMの学習曲線がない
  • テーブル定義とクエリのためのSQLライクなシンタックス
  • クラス最高の完全型付きジョイン
  • あらゆる複雑さの完全型付けされた部分選択と非部分選択
  • 選択と挿入を別々に行うDBモデルのためのTS型の自動インファリング
  • Zodスキーマ生成
  • 依存関係ゼロ

I Have A New Favorite Database Tool

I Have A New Favorite Database Tool - YouTube

要約
Prismaの利用には多くの制約があるため、代替手段としてdrizzle ORMを紹介しています。drizzleは、SQLデータベースのためのTypeScript ORMであり、完全な型安全性を提供し、自動マイグレーション生成機能を備えています。また、カスタムリレーションを定義することができ、SQLクエリを1つだけ実行するため、非常に高速であることが特徴です。

drizzleの新しいリリースでは、Prismaに似たリレーショナルクエリが導入され、SQLの知識がなくても簡単に使用できるようになりました。また、drizzleは、常に1つのSQLクエリを実行するため、非常に高速であることが特徴です。drizzleの開発チームは、ドキュメントの提供や、開発者コミュニティの参加を促進しており、drizzleの利用を推奨しています。

対応するデータベース

Database Support
PostgreSQL Docs
MySQL Docs
SQLite Docs
Cloudflare D1 Docs Website
libSQL Docs Website
Turso Docs Website
PlanetScale Docs Website
Neon Docs Website
Vercel Postgres Docs Website
Supabase Docs Website
DynamoDB
MS SQL
CockroachDB

チュートリアルBlog

Drizzle ORMの使い方を理解するためのチュートリアル | アールエフェクト

という記事が見つかったので
現状のORMは?Drizzleの立ち位置はどうなっているんだ?という事が出発点になっています。

↑チュートリアルBlogを調べたときのメモ (長い)

環境の構築

インストール
mkdir drizzle

cd drizzle
npm init -y

npm install typescript ts-node @types/node --save-dev

npx tsc --init

TypeScript を利用するための設定は完了です。
データベースには SQLite を利用しています。


Drizzle のインストール

npm install drizzle-orm better-sqlite3
npm install --save-dev @types/better-sqlite3
npm install -D drizzle-kit

drizzle-kitは定義したスキーマファイルを利用して
テーブルを作成/更新するために必要な
マイグレーションファイルを作成するためのツールです。

.gitignore
node_modules/
package-lock.json


Drizzle の設定

スキーマファイルやデータベースの接続用のコードを
保存するためのプロジェクトディレクトリ直下に
dbディレクトリの作成を行います。

mkdir db


スキーマファイルの作成
スキーマファイルはDBを設計するためのファイルであり、
全ての設計を一つにまとめたり
機能毎に複数のファイルに分けて書いたりすることが出来ます。

dbディレクトリにschema.tsファイルを作成し、
todosテーブルをSQLiteデータベースに
作成するために以下のスキーマを設定します。

touch db/schema.ts

db/schema.ts
import { text, integer, sqliteTable } from 'drizzle-orm/sqlite-core';

export const todos = sqliteTable('todos', {
  id: integer('id', { mode: 'number' }).primaryKey({ autoIncrement: true }),
  name: text('name'),
  isCompleted: integer('isCompleted'),
});


Migration ファイルの作成

Drizzle Kitを利用して
スキーマファイルに記述した内容を元にマイグレーションファイルを作成します。

実行する際には—schemaオプションschema.tsファイルを指定します。

実行するとdrizzleディレクトリが作成され、
mataディレクトリとsqlファイルが作成されます。

ファイル名は自動で命名されます。

metaディレクトリの中には
マイグレーションを管理する情報が保存されます。

npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts

このコマンドを実行しただけで
データベース、テーブルが作成されるわけではありません。

SQL文が出力される

drizzle\0000_slow_martin_li.sql
名前は実行毎に変わる

drizzle\0000_slow_martin_li.sql

CREATE TABLE `todos` (
	`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
	`name` text,
	`isCompleted` integer
);

ファイルの拡張子がsqlという名前がつけている通り
↑0000_amazing_firestar.sqlの中には

DDL(DataDefinitionLanguage)が記述されており
テーブル作成に利用することができます。

SQLのcreate文が記述されています。

create文なのでそのままSQLiteに接続して実行すれば
そのままテーブルを作成することができます。


DB への接続
データベースへの接続に利用するためのコードを記述するため
db.tsファイルをdbディレクトリの下に作成します。

touch db\db.ts
touch db\db.ts
touch db\db.ts

db\db.ts
import { drizzle, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
import Database from 'better-sqlite3';

const sqlite = new Database('./db/sqlite.db');
export const db: BetterSQLite3Database = drizzle(sqlite);

migrate(db, { migrationsFolder: './drizzle' });

最後の行に migrate関数 が記述されていますが
この1行がマイグレーションファイルを元に
データベースの作成やテーブルの作成/更新などを行います。

テーブルの構成を変更した場合など必要な時にのみ実行されます。
migrationFolderプロパティに
マイグレーションファイルが
保存されているdrizzleディレクトリを指定します。

SQLiteは先ほど説明した通りファイルベースなので
sqlite.dbという名前で
dbディレクトリに保存されるように設定しています。


Drizzle の動作確認
これまでに作成した情報を利用して
データベースのテーブルを操作するコードを記述するため
プロジェクトディレクトリ直下にindex.tsファイルを作成します。

index.tsファイルではSQLiteデータベースにアクセスを行う
todosテーブルからデータを取得します。

db.select().from(todos)のfromメソッドには
データを取得していテーブルの情報を指定しています。

todosはschema.tsファイルから import しています。
すべてのデータを取得するためallメソッドを
設定しています。

touch index.ts
touch index.ts
touch index.ts

index.ts
import { db } from './db/db';
import { todos } from './db/schema';

function main() {
  const allTodo = db.select().from(todos).all();
  console.log(allTodo);
}

main();

作成した index.ts ファイルを実行します。

npx ts-node index.ts
npx ts-node index.ts
npx ts-node index.ts

実行しても todos テーブルには
何もデータが入っていないため空の配列が表示されます。

結果
[]


実行後dbディレクトリを確認すると
sqlite.dbファイルが作成されていることがわかります。


データの取得方法 (この時点ではDBに各種データは未登録)

allで
出力された10件分のデータを取得したい場合には
limitメソッドを利用することができます。
const allTodo = db.select().from(todos).liimit().all();

all メソッドで取得したデータ件数は length をつけて確認することができます。
const allTodo = db.select().from(todos).all().length();

get メソッドを利用すると 1 件のデータを取得することができます。
const singleTodo = db.select().from(todos).get();
//
const singleTodo = db.select().from(todos).limit().get();


データの登録

insert メソッドを利用してテーブルへ、データの登録を行います。
実行するためには run メソッドも必要です。

index.ts
import { db } from "./db/db"
import { todos } from "./db/schema"

async function main() {
  const result = db.insert(todos).values({ name: "VNS.BLUE", isCompleted: 0 }).run()
  console.log("result", result)

  const allTodo = db.select().from(todos).all()
  console.log("allTodo", allTodo)
}

main()

npx ts-node index.ts
npx ts-node index.ts
npx ts-node index.ts

06-15 21:41:58> npx ts-node index.ts
result { changes: 1, lastInsertRowid: 1 }
allTodo [ { id: 1, name: 'Learn Drizzle', isCompleted: 0 } ]

DrizzleORMを利用してSQLiteデータベースへ
データが登録できるようになりました。

2回実行すると
2回登録されます。
同じデータでも上書きされずに、
追加されます。


マイグレーションの動作確認

スキーマファイルの変更を行った場合の
データベースのテーブルに反映させるための方法を確認してみます。


列の追加

ユーザの ID を保存するために todos のスキーマに userId 列を追加します。

schema.ts
import { text, integer, sqliteTable } from 'drizzle-orm/sqlite-core';

export const todos = sqliteTable('todos', {
  id: integer('id', { mode: 'number' }).primaryKey({ autoIncrement: true }),
  name: text('name'),
  userId: text('useId'),				<<<<追記
  isCompleted: integer('isCompleted'),
});

schema.ts ファイルを更新後、drizzle-kit を利用して
マイグレーションファイルを作成を行います。

npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts

新たに drizzle ディレクトリに 0001_flippant_sway.sql ファイルが作成されます。
中身を確認すると追加した date 列に関する alter table 文が記述されています。

ALTER TABLE todos ADD useId text;

マイグレーションがテーブルに反映されるのか
確認するために select を実行します。

index.ts
import { db } from './db/db';
import { todos } from './db/schema';

async function main() {
  const allTodo = db.select().from(todos).all();
  console.log('allTodo', allTodo);
}

main();

npx ts-node index.ts
npx ts-node index.ts
npx ts-node index.ts

取得したデータに userId 列が追加されていることが確認できます。
値には null が設定されています。

% npx ts-node index.ts
allTodo [ { id: 1, name: 'Learn Drizzle', userId: null, isCompleted: 0 } ]


列の削除

列の追加を行うことができたので次は追加した列を
削除したい場合の動作確認を行います。

追加したuserId列を削除するために
スキーマファイルを更新します。

db\schema.ts
import { text, integer, sqliteTable } from "drizzle-orm/sqlite-core"

export const todos = sqliteTable("todos", {
  id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }),
  name: text("name"),
  isCompleted: integer("isCompleted"),
})



schema.ts ファイルを更新後、マイグレーションファイルを作成を行います。

npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts

06-15 21:51:30> npx drizzle-kit generate:sqlite --schema=./db/schema.ts
drizzle-kit: v0.18.1
drizzle-orm: v0.26.5

1 tables
todos 3 columns 0 indexes 0 fks

[✓] Your SQL migration file ➜ drizzle\0002_third_molecule_man.sql 🚀

drizzle\0002_third_molecule_man.sqlファイルには列の削除を行う
alter table 文が記述されています。

drizzle\0002_third_molecule_man.sql
ALTER TABLE `todos` DROP COLUMN `useId`;

マイグレーションの内容を反映させるために
index.tsファイルを実行します。

実行すると以下のuserIdが削除されていることが
確認できます。

npx ts-node index.ts
npx ts-node index.ts
npx ts-node index.ts

% npx ts-node index.ts

08-07 18:49:55> npx ts-node index.ts
allTodo [
{ id: 1, name: 'Learn Drizzle', userId: null, isCompleted: 0 },
{ id: 2, name: 'VNS.BLUE', userId: null, isCompleted: 0 },
{ id: 3, name: 'VNS.BLUE', userId: null, isCompleted: 0 }
]

08-07 18:55:05> npx ts-node index.ts
allTodo [
{ id: 1, name: 'Learn Drizzle', isCompleted: 0 },
{ id: 2, name: 'VNS.BLUE', isCompleted: 0 },
{ id: 3, name: 'VNS.BLUE', isCompleted: 0 }
]

userId: null の項目が消えているのが確認できた。
userId: null の項目が消えているのが確認できた。
userId: null の項目が消えているのが確認できた。

前回はここでBlogの動作と違っていて、出来ていなかった。


Drop Migration

DrizzleKit には DropMigration を行うコマンドがあります。

--outオプションにはマイグレーションディレクトリを指定します。

実行するとこれまで作成したマイグレーションの名前が表示されます。

選択することでマイグレーションファイルを削除することはできますが
削除してもデータベースのテーブルに反映されるわけではありません。

npx drizzle-kit drop --out ./drizzle
npx drizzle-kit drop --out ./drizzle
npx drizzle-kit drop --out ./drizzle

マイグレーションファイルを削除できた。
マイグレーションファイルを削除できた。
マイグレーションファイルを削除できた。


その他

設定ファイル

Drizzle Kit では設定ファイルを利用することができます。
drizzle.config.ts ファイルをプロジェクトフォルダ直下に作成して
スキーマフォルダやマイグレーションフォルダを指定することができます。

touch drizzle.config.ts
touch drizzle.config.ts
touch drizzle.config.ts

drizzle.config.ts
import type { Config } from 'drizzle-kit';

export default {
  schema: './db/schema.ts',
  out: './drizzle',
} satisfies Config;

drizzle.config.ts ファイルを作成後は
npx drizzle-kit generate
を実行する際にオプションに--schema を設定していましたが

schema の値は drizzle.config.ts ファイルに
記述されているため省略することができます。

npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts
npx drizzle-kit generate:sqlite --schema=./db/schema.ts

npx drizzle-kit generate:sqlite
npx drizzle-kit generate:sqlite
npx drizzle-kit generate:sqlite

で大丈夫になった


Type の設定(InferModel)

index.tsファイルの中でinsertの処理を
別の関数insertTodoに分けた場合に

引数に型をしない場合には todo の下に 赤線が引かれます。
引数に型をしない場合には todo の下に 赤線が引かれます。
引数に型をしない場合には todo の下に 赤線が引かれます。

index.ts
import { db } from "./db/db"
import { todos } from "./db/schema"

// 引数に型をしない場合には todo の下に 赤線が引かれます。
const insertTodo = (todo) => {
  return db.insert(todos).values(todo).run()
}

async function main() {
  const result = insertTodo({ name: "Learn TypeScript", isCompleted: 0 })
  console.log("result", result)

  const allTodo = db.select().from(todos).all()
  console.log(allTodo)
}

↑このソースにこのように↓型を追加すると、
todo の下についた赤線が消えます。

index.ts
import { db } from './db/db';
import { todos } from './db/schema';
import { InferModel } from 'drizzle-orm';

type InsertTodo = InferModel<typeof todos, 'insert'>;

const insertTodo = (todo: InsertTodo) => {
  return db.insert(todos).values(todo).run();
};

async function main() {
  const result = insertTodo({ name: 'Learn TypeScript', isCompleted: 0 });
  console.log('result', result);

  const allTodo = db.select().from(todos).all();
  console.log(allTodo);
}


これまではどのORMでも付属している機能でした。

次の項目からは、

ここまで来てようやくDrizzleを使うメリットがでてきます。


型の設定に関するメッセージ

型を設定するために InferModel を利用することができます。

InforModeを利用して作成した型 InsertTodo を
insertTodo の引数の todo の型として利用することができます。

index.ts 追加
type InsertTodo = InferModel<typeof todos, 'insert'>;
type Todo = InferModel<typeof todos, "select">

型の上にマウスカーソルを持ってくると、
型を見ることが出来ます。

InsertTodo型とTodo型は、drizzle-ormモジュールのInferModel型を使用して、todosスキーマに対するinsert操作とselect操作の型を推論しています。InferModel型は、テーブルスキーマと操作名を引数に取り、その操作に対する型を推論します。

typeof todosは、todosスキーマオブジェクトの型を取得します。"insert"と"select"は、それぞれtodosスキーマに対するinsert操作とselect操作を表します。InferModel型は、これらの引数を使用して、todosスキーマに対するinsert操作とselect操作の型を推論します。

したがって、InsertTodo型とTodo型は、todosスキーマに対するinsert操作とselect操作の型を表します。

selectから取得する値に対する型が必要な場合にも
InforMode を利用することができます。

index.ts
import { db } from "./db/db"
import { todos } from "./db/schema"
import { InferModel } from "drizzle-orm"

type InsertTodo = InferModel<typeof todos, "insert">
type Todo = InferModel<typeof todos, "select">

const insertTodo = (todo: InsertTodo) => {
  return db.insert(todos).values(todo).run()
}

async function main() {
  const result = insertTodo({ name: "VNS.BLUE", isCompleted: 0 })
  console.log("result", result)

  const allTodo: Todo[] = db.select().from(todos).all()
  console.log(allTodo)
}

main()

このコードは、TypeScriptファイルで、dbというデータベースオブジェクトと、todosというスキーマオブジェクトをdbモジュールからインポートしています。また、drizzle-ormモジュールからInferModel型をインポートしています。

InsertTodo型は、InferModel型を使用して、todosスキーマに対するinsert操作の型を推論するために使用されます。Todo型は、InferModel型を使用して、todosスキーマに対するselect操作の型を推論するために使用されます。

insertTodo関数は、InsertTodo型のtodoオブジェクトを引数に取り、db.insertメソッドを使用してtodosテーブルに挿入します。

main関数は、insertTodo関数を呼び出し、nameプロパティが"VNS.BLUE"に設定され、isCompletedプロパティが0に設定されたオブジェクトを渡します。insertTodo関数の結果はコンソールにログ出力されます。

allTodo変数は、db.selectメソッドを使用してtodosテーブルからすべての行を選択するselectクエリの結果を代入します。クエリの結果はコンソールにログ出力されます。

注意点としては、このコードは、drizzle-ormモジュールを使用しているため、drizzle-ormモジュールがインストールされている必要があります。


実行した SQL の中身

実行した SQL の中身を確認したい場合には
toSQL メソッドを利用することができます。

index.ts
import { db } from './db/db';
import { todos } from './db/schema';

async function main() {
  const query = db.select().from(todos).toSQL();
  console.log(query);
}

main();

index.ts を実行すると実行した SQL が

'select "id", "name", "isCompleted" from "todos"'
であることがわかります。

 % npx ts-node index.ts
{ sql: 'select "id", "name", "isCompleted" from "todos"', params: [] }


Logging の設定

実行した SQL の中身を確認するために logging の設定を行うことができます。

db\db.ts
import { drizzle, BetterSQLite3Database } from "drizzle-orm/better-sqlite3"
import { migrate } from "drizzle-orm/better-sqlite3/migrator"
import Database from "better-sqlite3"

const sqlite = new Database("./db/sqlite.db")
// export const db: BetterSQLite3Database = drizzle(sqlite)
// ↓ ログを取る
export const db: BetterSQLite3Database = drizzle(sqlite, { logger: true })

migrate(db, { migrationsFolder: "./drizzle" })

下記の index.ts ファイルを実行します。

index.ts
import { db } from './db/db';
import { todos } from './db/schema';

async function main() {
  const query = db.select().from(todos).toSQL();
  console.log(query);
}

main();

npx ts-node index.ts
npx ts-node index.ts
npx ts-node index.ts

↓ログが取得できています。

08-07 20:07:28> npx ts-node index.ts
Query:
                        CREATE TABLE IF NOT EXISTS "__drizzle_migrations" (
                                id SERIAL PRIMARY KEY,
                                hash text NOT NULL,
                                created_at numeric
                        )

Query: SELECT id, hash, created_at FROM "__drizzle_migrations" ORDER BY created_at DESC LIMIT 1
Query: BEGIN
Query: COMMIT
{ sql: 'select "id", "name", "isCompleted" from "todos"', params: [] }

npm trends

npm trends

ORM一覧 (2023/06/15現在)

ORM Star GitHubリポジトリ 公式サイト ドキュメント 説明
Prisma 32000 prisma 公式 Doc Node.jsとTypeScript向けの次世代ORMです。型安全で、データベーススキーマをコードで管理できます。また、Prismaは、データベースクエリを生成するために、自動的にSQLを生成するため、開発者はSQLを直接書く必要がありません。
TypeORM 31400 typeorm 公式 Doc TypeScriptで書かれたNode.js向けのORMです。TypeORMは、Active RecordパターンとData Mapperパターンの両方をサポートしています。また、TypeORMは、データベーススキーマをコードで管理することができます。
Sequelize 28000 sequelize 公式 Doc PromiseベースのNode.js ORMです。MySQL、MariaDB、SQLite、Microsoft SQLServer、Postgresで使用できます。Sequelizeは機能が多く人気があります。他のORMに比べてドキュメントも豊富です。
Mongoose 25700 mongoose 公式 Doc MongoDB用のNode.js ORMです。Mongooseは、MongoDBのドキュメント指向データベースに対してObject Document Mapping(ODM)を提供します。Mongooseは、MongoDBのドキュメント指向データベースに対してObject Document Mapping(ODM)を提供します。
Drizzle 10100 drizzle-orm 公式 Doc Node.js向けのORMです。Drizzleは、MySQLとPostgreSQLに対応しています。Drizzleは、シンプルなAPIと高速なパフォーマンスを提供します。
Objection.js 7000 objection.js 公式 Doc Node.js向けのORMです。Objection.jsは、Active RecordパターンとData Mapperパターンの両方をサポートしています。Objection.jsは、PostgreSQL、MySQL、SQLite3などのデータベースに対応しています。
Bookshelf 6300 bookshelf 公式 Doc Node.js向けのORMです。Bookshelfは、Knex Query Builderを基盤としています。Bookshelfは、Active RecordパターンとData Mapperパターンの両方をサポートしています。

Drizzleの歴史?

MySQL闇歴史 Drizzle - Qiita
https://qiita.com/RKajiyama/items/08fb46fb0d8b5ed6420d

MySQL 6.0で実現できなかった機能の実装やアーキテクチャの見直しを行ったオープンソースのプロジェクトがDrizzleです。旧MySQL社のアーキテクチャだった人物や 当時元気 だったmixiのエンジニアなどが立ち上げ、2011年3月に正式リリース。
https://www.publickey1.jp/blog/11/mysqldrizzle_1.html

霧雨のように消えていった度:★★★★★

2013年末までには新規開発をしないメンテナンスモードとなり、2016年にプロジェクト終了となった。

調査結果

drizzle.org
http://drizzle.org/
を訪ねてみると、

このドメイン名はGandi.netで登録されています。
drizzle.orgのWhois情報にアクセスして、ドメイン名の登録状況を確認しましょう。

とあったので、名前が同じで別のプロジェクトのようです。

Star Historyを見ると2023年の3月頃に急に増えているので、その頃になにかあったのかもしれません。

17
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?