本記事で行うこと
TypeScript用のORM「Drizzle ORM」をデータベースファーストで使う試みのPostgreSQL編です。
WebフレームワークはHonoを使用します。
関連記事
- TypeScript用ORM「Drizzle ORM」をDBファーストで使う試み(SQLite編)
- チーム開発参加の記録【2023-10~2024-03】(4) Go言語用ORM「Bun」をDBファーストで使う試み(PostgreSQL使用)」
テーブルを作る
では作業に移ります。
DBファーストですので、まずDDLを書きます。
CREATE TABLE foo
(
col_serial SERIAL NOT NULL,
col_bigserial BIGSERIAL NOT NULL,
col_boolean BOOLEAN NOT NULL,
col_boolean_null BOOLEAN,
col_smallint SMALLINT NOT NULL,
col_smallint_null SMALLINT,
col_int INTEGER NOT NULL,
col_int_null INTEGER,
col_bigint BIGINT NOT NULL,
col_bigint_null BIGINT,
col_numeric NUMERIC NOT NULL,
col_numeric_null NUMERIC,
col_real REAL NOT NULL,
col_real_null REAL,
col_double DOUBLE PRECISION NOT NULL,
col_double_null DOUBLE PRECISION,
col_text TEXT NOT NULL,
col_text_null TEXT,
col_char CHAR(1) NOT NULL,
col_char_null CHAR(1),
col_date DATE NOT NULL,
col_date_null DATE,
col_time_with TIME WITH TIME ZONE NOT NULL,
col_time_with_null TIME WITH TIME ZONE,
col_time TIME NOT NULL,
col_time_null TIME,
col_timestamp_with TIMESTAMP WITH TIME ZONE NOT NULL,
col_timestamp_with_null TIMESTAMP WITH TIME ZONE,
col_timestamp TIMESTAMP NOT NULL,
col_timestamp_null TIMESTAMP,
col_uuid UUID NOT NULL,
col_uuid_null UUID,
col_json JSONB NOT NULL,
col_json_null JSONB,
col_array INTEGER[] NOT NULL,
col_array_null INTEGER[]
);
上記DDLの意図
列について、私がプロジェクトで使うかもしれない型を広めに試します。
JSON型と配列型も試します。
複合型も試しましたが、SELECT文ではBun同様にjsonを経由することで使えたものの、更新系コマンドが未サポートの様子だったので、本記事では省きました。
テスト用データをINSERTする
作成したfooテーブルに、以下のSQLでテスト用データを2件INSERTしました。
INSERT INTO foo
(
col_boolean,
col_boolean_null,
col_smallint,
col_smallint_null,
col_int,
col_int_null,
col_bigint,
col_bigint_null,
col_numeric,
col_numeric_null,
col_real,
col_real_null,
col_double,
col_double_null,
col_text,
col_text_null,
col_char,
col_char_null,
col_date,
col_date_null,
col_time_with,
col_time_with_null,
col_time,
col_time_null,
col_timestamp_with,
col_timestamp_with_null,
col_timestamp,
col_timestamp_null,
col_uuid,
col_uuid_null,
col_json,
col_json_null,
col_array,
col_array_null
)
VALUES
(
TRUE,
NULL,
12345,
NULL,
123456789,
NULL,
1234567890123456789,
NULL,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
NULL,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
NULL,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
NULL,
'text_data',
NULL,
'c',
NULL,
'2023-01-01',
NULL,
'12:00:00',
NULL,
'12:00:00',
NULL,
'2023-12-31 23:59:59',
NULL,
'2023-12-31 23:59:59',
NULL,
GEN_RANDOM_UUID(),
NULL,
'{"a": 10, "b": "Json"}'::JSONB,
NULL,
ARRAY[10, NULL, 30]::INTEGER[],
NULL
),
(
FALSE,
FALSE,
32767,
32767,
987654321,
987654321,
876543210987654321,
876543210987654321,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117,
'text_data',
'text_data',
'c',
'c',
'2023-01-01',
'2023-01-01',
'12:00:00',
'12:00:00',
'12:00:00',
'12:00:00',
'2023-12-31 23:59:59',
'2023-12-31 23:59:59',
'2023-12-31 23:59:59',
'2023-12-31 23:59:59',
GEN_RANDOM_UUID(),
GEN_RANDOM_UUID(),
'{"a": 20, "b": null}'::JSONB,
'{"a": null, "b": "Json"}'::JSONB,
ARRAY[10, NULL, 30]::INTEGER[],
ARRAY[10, NULL, 30]::INTEGER[]
);
INSERTしたら、fooテーブルにSELECT文を発行してみます。
SELECT
*
FROM
foo;
SELECT文の結果です。
HonoとDrizzle ORMを使って、fooテーブルにCRUD操作するWeb APIサーバーを作ってみる
それでは、TypeScriptからDrizzle ORMを使っていきます。
プロジェクト作成
プロジェクト名は「exercise_drizzle_postgres」にしました。
どのテンプレートを使うか聞かれたので、「bun」を選択しました。
参考ページ: https://hono.dev/getting-started/basic
bunx create-hono exercise_drizzle_postgres
パッケージインストール
プロジェクトディレクトリ直下で、以下を実行しました。
参考ページ: https://orm.drizzle.team/docs/get-started-postgresql#supabase
bun add drizzle-orm postgres
bun add -D drizzle-kit
DBからTypeScriptのスキーマを自動生成
DBファーストなので、コードからDBスキーマを生成するのではなく、DBスキーマからコードを生成する順になりました。
プロジェクトディレクトリ直下で、以下のdrizzle-kitコマンドを実行しました。
connectionStringオプションには、PostgreSQLの接続URLを指定します。
drizzle-kit introspect:pg --driver=pg --connectionString=postgresql://postgres:secret@localhost:5432/postgres
ディレクトリ構造とファイル
drizzle/ディレクトリ配下のファイルは、drizzle-kitコマンドを実行したときに自動生成されたものです。
Project Root
├── drizzle/
│ ├── meta/
│ │ ├── 0000_snapshot.json
│ │ └── journal.json
│ ├── 0000_fixed_toxin.sql
│ └── schema.ts
├── src/
│ └── index.ts
├── package.json
├── README.md
└── tsconfig.json
drizzle/schema.ts
自動生成されたコードです。
src/index.tsからimportして使用します。
import { pgTable, serial, bigserial, boolean, smallint, integer, bigint, numeric, real, doublePrecision, text, char, date, time, timestamp, uuid, jsonb } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"
export const foo = pgTable("foo", {
colSerial: serial("col_serial").notNull(),
colBigserial: bigserial("col_bigserial", { mode: "bigint" }).notNull(),
colBoolean: boolean("col_boolean").notNull(),
colBooleanNull: boolean("col_boolean_null"),
colSmallint: smallint("col_smallint").notNull(),
colSmallintNull: smallint("col_smallint_null"),
colInt: integer("col_int").notNull(),
colIntNull: integer("col_int_null"),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
colBigint: bigint("col_bigint", { mode: "number" }).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
colBigintNull: bigint("col_bigint_null", { mode: "number" }),
colNumeric: numeric("col_numeric").notNull(),
colNumericNull: numeric("col_numeric_null"),
colReal: real("col_real").notNull(),
colRealNull: real("col_real_null"),
colDouble: doublePrecision("col_double").notNull(),
colDoubleNull: doublePrecision("col_double_null"),
colText: text("col_text").notNull(),
colTextNull: text("col_text_null"),
colChar: char("col_char", { length: 1 }).notNull(),
colCharNull: char("col_char_null", { length: 1 }),
colDate: date("col_date").notNull(),
colDateNull: date("col_date_null"),
colTimeWith: time("col_time_with", { withTimezone: true }).notNull(),
colTimeWithNull: time("col_time_with_null", { withTimezone: true }),
colTime: time("col_time").notNull(),
colTimeNull: time("col_time_null"),
colTimestampWith: timestamp("col_timestamp_with", { withTimezone: true, mode: 'string' }).notNull(),
colTimestampWithNull: timestamp("col_timestamp_with_null", { withTimezone: true, mode: 'string' }),
colTimestamp: timestamp("col_timestamp", { mode: 'string' }).notNull(),
colTimestampNull: timestamp("col_timestamp_null", { mode: 'string' }),
colUuid: uuid("col_uuid").notNull(),
colUuidNull: uuid("col_uuid_null"),
colJson: jsonb("col_json").notNull(),
colJsonNull: jsonb("col_json_null"),
colArray: integer("col_array").array().notNull(),
colArrayNull: integer("col_array_null").array(),
});
src/index.ts
メインのコードです。
import { Hono } from "hono"
import postgres from "postgres"
import { drizzle } from "drizzle-orm/postgres-js"
import { sql, eq } from "drizzle-orm"
import { foo } from "../drizzle/schema"
import {execute} from "drizzle-kit/orm-extenstions/d1-driver/wrangler-client";
const client = postgres("postgresql://postgres:secret@localhost:5432/postgres")
const db = drizzle(client, { logger: true })
const app = new Hono()
app.notFound((c) => c.json({ message: 'Not Found', ok: false }, 404))
app.get("/api/selectFoo", async (c) => {
const result = await db.select(
{
colSerial: foo.colSerial,
colBigserial: sql`CAST(col_bigserial AS TEXT)`,
colBoolean: foo.colBoolean,
colBooleanNull: foo.colBooleanNull,
colSmallint: foo.colSmallint,
colSmallintNull: foo.colSmallintNull,
colInt: foo.colInt,
colIntNull: foo.colIntNull,
colBigint: sql`CAST(col_bigint AS TEXT)`,
colBigintNull: sql`CAST(col_bigint_null AS TEXT)`,
colNumeric: sql`CAST(col_numeric AS TEXT)`,
colNumericNull: sql`CAST(col_numeric_null AS TEXT)`,
colReal: foo.colReal,
colRealNull: foo.colRealNull,
colDouble: foo.colDouble,
colDoubleNull: foo.colDoubleNull,
colText: foo.colText,
colTextNull: foo.colTextNull,
colChar: foo.colChar,
colCharNull: foo.colCharNull,
colDate: sql`CAST(col_date AS TEXT)`,
colDateNull: sql`CAST(col_date_null AS TEXT)`,
colTimeWith: foo.colTimeWith,
colTimeWithNull: foo.colTimeWithNull,
colTime: foo.colTime,
colTimeNull: foo.colTimeNull,
colTimestampWith: foo.colTimestampWith,
colTimestampWithNull: foo.colTimestampWithNull,
colTimestamp: sql`CAST(col_timestamp AS TEXT)`,
colTimestampNull: sql`CAST(col_timestamp_null AS TEXT)`,
colUuid: foo.colUuid,
colUuidNull: foo.colUuidNull,
colJson: foo.colJson,
colJsonNull: foo.colJsonNull,
colArray: foo.colArray,
colArrayNull: foo.colArrayNull
}
).from(foo)
.execute()
return c.json(result)
})
app.put("/api/updateFoo", async (c) => {
await db.update(foo)
.set({
colTextNull: "ABC",
colArray: sql`ARRAY[111, NULL, 333]::INTEGER[]`,
colArrayNull: [444, 555, 666],
colJson: sql`${{a: 777, b: null, c: "Hello"}}::JSONB`,
colJsonNull: sql`'{}'::JSONB`,
})
.where(eq(foo.colSerial, 1))
return c.json({ message: "ok", ok: true })
})
app.post("/api/insertFoo", async (c) => {
await db.insert(foo)
.values({
colBoolean: false,
colBooleanNull: null,
colSmallint: 9999,
colSmallintNull: null,
colInt: 999999999,
colIntNull: null,
colBigint: 999999999999999999n,
colBigintNull: null,
colNumeric: sql`${"2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178"}::NUMERIC`,
colNumericNull: null,
colReal: 2.71828182845904523536028747135266,
colRealNull: null,
colDouble: 2.71828182845904523536028747135266,
colDoubleNull: null,
colText: "Hello",
colTextNull: null,
colChar: "z",
colCharNull: null,
colDate: "2024-01-21",
colDateNull: null,
colTimeWith: "13:00",
colTimeWithNull: null,
colTime: "13:00",
colTimeNull: null,
colTimestampWith: "2024-01-21 13:00:00.000000",
colTimestampWithNull: null,
colTimestamp: "2024-01-21 13:00:00.000000",
colTimestampNull: null,
colUuid: sql`GEN_RANDOM_UUID()`,
colUuidNull: null,
colJson: sql`${{a: 777, b: null, c: "Hello"}}::JSONB`,
colJsonNull: sql`${{}}::JSONB`,
colArray: sql`ARRAY[111, NULL, 333]::INTEGER[]`,
colArrayNull: [444, 555, 666]
})
return c.json({ message: "ok", ok: true })
})
app.delete("/api/deleteFoo", async (c) => {
const subQuery = db.select(
{
_: sql`max(${foo.colSerial})`
}
).from(foo)
await db.delete(foo)
.where(eq(foo.colSerial, subQuery))
return c.json({ message: "ok", ok: true })
})
export default app
package.json
{
"scripts": {
"dev": "bun run --hot src/index.ts"
},
"dependencies": {
"drizzle-orm": "^0.29.3",
"hono": "^3.12.6",
"postgres": "^3.4.3"
},
"devDependencies": {
"@types/bun": "^1.0.0",
"drizzle-kit": "^0.20.13"
}
}
tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true,
"strict": true,
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}
CRUD操作
それでは、CRUD操作について一つ一つ見ていきます。
SELECT文
まずはSELECT文です。
SELECT用ハンドラの中身
ハンドラの中身を見ていきます。
SQLが透けて見えますね。
私みたいにSQLを書きたい人には、嬉しいORMだと思いました。
「sql``」で囲った部分は、Drizzle ORMがSQLを生成するときにそのまま使われるので、DB側の構文やファンクションを使用できます。
- DBでBIGSERIAL型、BIGINT型、NUMERIC型で定義された列は、TypeScriptのnumber型で受け取ると誤差が生じることがあるので、TEXT型にキャストしました。
- DBでタイムゾーンなしの日付時間型で定義された列は、TypeScriptで受け取ったらタイムゾーン付きになる現象が起きたので、TEXT型にキャストしてそれを防ぎました。
const result = await db.select(
{
colSerial: foo.colSerial,
colBigserial: sql`CAST(col_bigserial AS TEXT)`,
colBoolean: foo.colBoolean,
colBooleanNull: foo.colBooleanNull,
colSmallint: foo.colSmallint,
colSmallintNull: foo.colSmallintNull,
colInt: foo.colInt,
colIntNull: foo.colIntNull,
colBigint: sql`CAST(col_bigint AS TEXT)`,
colBigintNull: sql`CAST(col_bigint_null AS TEXT)`,
colNumeric: sql`CAST(col_numeric AS TEXT)`,
colNumericNull: sql`CAST(col_numeric_null AS TEXT)`,
colReal: foo.colReal,
colRealNull: foo.colRealNull,
colDouble: foo.colDouble,
colDoubleNull: foo.colDoubleNull,
colText: foo.colText,
colTextNull: foo.colTextNull,
colChar: foo.colChar,
colCharNull: foo.colCharNull,
colDate: sql`CAST(col_date AS TEXT)`,
colDateNull: sql`CAST(col_date_null AS TEXT)`,
colTimeWith: foo.colTimeWith,
colTimeWithNull: foo.colTimeWithNull,
colTime: foo.colTime,
colTimeNull: foo.colTimeNull,
colTimestampWith: foo.colTimestampWith,
colTimestampWithNull: foo.colTimestampWithNull,
colTimestamp: sql`CAST(col_timestamp AS TEXT)`,
colTimestampNull: sql`CAST(col_timestamp_null AS TEXT)`,
colUuid: foo.colUuid,
colUuidNull: foo.colUuidNull,
colJson: foo.colJson,
colJsonNull: foo.colJsonNull,
colArray: foo.colArray,
colArrayNull: foo.colArrayNull
}
).from(foo)
.execute()
return c.json(result)
Drizzle ORMが生成したSQL
上記コードからDrizzle ORMが生成したSQLを、整形して見やすくしました。
select
"col_serial",
CAST(col_bigserial AS TEXT),
"col_boolean",
"col_boolean_null",
"col_smallint",
"col_smallint_null",
"col_int",
"col_int_null",
CAST(col_bigint AS TEXT),
CAST(col_bigint_null AS TEXT),
CAST(col_numeric AS TEXT),
CAST(col_numeric_null AS TEXT),
"col_real",
"col_real_null",
"col_double",
"col_double_null",
"col_text",
"col_text_null",
"col_char",
"col_char_null",
CAST(col_date AS TEXT),
CAST(col_date_null AS TEXT),
"col_time_with",
"col_time_with_null",
"col_time",
"col_time_null",
"col_timestamp_with",
"col_timestamp_with_null",
CAST(col_timestamp AS TEXT),
CAST(col_timestamp_null AS TEXT),
"col_uuid",
"col_uuid_null",
"col_json",
"col_json_null",
"col_array",
"col_array_null"
from
"foo"
selectFoo APIの実行結果
selectFoo APIを呼び出した結果です。
レスポンスは、ハンドラの最後の一行で、結果表をそのままjsonにして返しているだけですが、きれいなレスポンスが生成できていますね。
シンプルなコードできれいなレスポンスを返せているのはポイントが高いです。
[
{
"colSerial": 1,
"colBigserial": "1",
"colBoolean": true,
"colBooleanNull": null,
"colSmallint": 12345,
"colSmallintNull": null,
"colInt": 123456789,
"colIntNull": null,
"colBigint": "1234567890123456789",
"colBigintNull": null,
"colNumeric": "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117",
"colNumericNull": null,
"colReal": 3.1415927,
"colRealNull": null,
"colDouble": 3.141592653589793,
"colDoubleNull": null,
"colText": "text_data",
"colTextNull": null,
"colChar": "c",
"colCharNull": null,
"colDate": "2023-01-01",
"colDateNull": null,
"colTimeWith": "12:00:00+00",
"colTimeWithNull": null,
"colTime": "12:00:00",
"colTimeNull": null,
"colTimestampWith": "2023-12-31T23:59:59.000Z",
"colTimestampWithNull": null,
"colTimestamp": "2023-12-31 23:59:59",
"colTimestampNull": null,
"colUuid": "aa4c082e-b82c-4b8f-a7a6-411a92d3c75a",
"colUuidNull": null,
"colJson": {
"a": 10,
"b": "Json"
},
"colJsonNull": null,
"colArray": [
10,
null,
30
],
"colArrayNull": null
},
{
"colSerial": 2,
"colBigserial": "2",
"colBoolean": false,
"colBooleanNull": false,
"colSmallint": 32767,
"colSmallintNull": 32767,
"colInt": 987654321,
"colIntNull": 987654321,
"colBigint": "876543210987654321",
"colBigintNull": "876543210987654321",
"colNumeric": "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117",
"colNumericNull": "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117",
"colReal": 3.1415927,
"colRealNull": 3.1415927,
"colDouble": 3.141592653589793,
"colDoubleNull": 3.141592653589793,
"colText": "text_data",
"colTextNull": "text_data",
"colChar": "c",
"colCharNull": "c",
"colDate": "2023-01-01",
"colDateNull": "2023-01-01",
"colTimeWith": "12:00:00+00",
"colTimeWithNull": "12:00:00+00",
"colTime": "12:00:00",
"colTimeNull": "12:00:00",
"colTimestampWith": "2023-12-31T23:59:59.000Z",
"colTimestampWithNull": "2023-12-31T23:59:59.000Z",
"colTimestamp": "2023-12-31 23:59:59",
"colTimestampNull": "2023-12-31 23:59:59",
"colUuid": "8a4fa849-1c61-440f-bc6e-7c780f3afda6",
"colUuidNull": "f014beb1-3bb3-4dbd-956c-6126d41f3692",
"colJson": {
"a": 20,
"b": null
},
"colJsonNull": {
"a": null,
"b": "Json"
},
"colArray": [
10,
null,
30
],
"colArrayNull": [
10,
null,
30
]
}
]
UPDATE文
次はUPDATE文を見ていきます。
UPDATE用ハンドラの中身
ハンドラのクエリー部分を見ます。
col_serial列が1の行について、TEXT型、配列型、JSON型の列をそれぞれ更新する内容です。
await db.update(foo)
.set({
colTextNull: "ABC",
colArray: sql`ARRAY[111, NULL, 333]::INTEGER[]`,
colArrayNull: [444, 555, 666],
colJson: sql`${{a: 777, b: null, c: "Hello"}}::JSONB`,
colJsonNull: sql`'{}'::JSONB`,
})
.where(eq(foo.colSerial, 1))
Drizzle ORMが生成したSQL
上記コードからDrizzle ORMが生成したSQLを、整形して見やすくしました。
update
"foo"
set
"col_text_null" = $1,
"col_array" = ARRAY[111, NULL, 333]::INTEGER[],
"col_array_null" = $2,
"col_json" = $3::JSONB,
"col_json_null" = '{}'::JSONB
where
"foo"."col_serial" = $4
-- params: [
"ABC",
"{444,555,666}",
{"a":777,"b":null,"c":"Hello"},
1
]
updateFoo APIの実行結果
updateFoo APIを呼び出した結果を見てみます。
SELECT
col_text_null,
col_array,
col_array_null,
col_json,
col_json_null
FROM
foo
WHERE
col_serial = 1;
5つの列が意図した値に更新されました。
INSERT文
次はINSERT文を見ていきます。
1行挿入する内容です。
INSERT用ハンドラの中身
ハンドラのクエリー部分を見ます。
await db.insert(foo)
.values({
colBoolean: false,
colBooleanNull: null,
colSmallint: 9999,
colSmallintNull: null,
colInt: 999999999,
colIntNull: null,
colBigint: 999999999999999999n,
colBigintNull: null,
colNumeric: sql`${"2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178"}::NUMERIC`,
colNumericNull: null,
colReal: 2.71828182845904523536028747135266,
colRealNull: null,
colDouble: 2.71828182845904523536028747135266,
colDoubleNull: null,
colText: "Hello",
colTextNull: null,
colChar: "z",
colCharNull: null,
colDate: "2024-01-21",
colDateNull: null,
colTimeWith: "13:00",
colTimeWithNull: null,
colTime: "13:00",
colTimeNull: null,
colTimestampWith: "2024-01-21 13:00:00.000000",
colTimestampWithNull: null,
colTimestamp: "2024-01-21 13:00:00.000000",
colTimestampNull: null,
colUuid: sql`GEN_RANDOM_UUID()`,
colUuidNull: null,
colJson: sql`${{a: 777, b: null, c: "Hello"}}::JSONB`,
colJsonNull: sql`${{}}::JSONB`,
colArray: sql`ARRAY[111, NULL, 333]::INTEGER[]`,
colArrayNull: [444, 555, 666]
})
Drizzle ORMが生成したSQL
上記コードからDrizzle ORMが生成したSQLを、整形して見やすくしました。
insert into "foo" (
"col_serial",
"col_bigserial",
"col_boolean",
"col_boolean_null",
"col_smallint",
"col_smallint_null",
"col_int",
"col_int_null",
"col_bigint",
"col_bigint_null",
"col_numeric",
"col_numeric_null",
"col_real",
"col_real_null",
"col_double",
"col_double_null",
"col_text",
"col_text_null",
"col_char",
"col_char_null",
"col_date",
"col_date_null",
"col_time_with",
"col_time_with_null",
"col_time",
"col_time_null",
"col_timestamp_with",
"col_timestamp_with_null",
"col_timestamp",
"col_timestamp_null",
"col_uuid",
"col_uuid_null",
"col_json",
"col_json_null",
"col_array",
"col_array_null"
)
values (
default,
default,
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9::NUMERIC,
$10,
$11,
$12,
$13,
$14,
$15,
$16,
$17,
$18,
$19,
$20,
$21,
$22,
$23,
$24,
$25,
$26,
$27,
$28,
GEN_RANDOM_UUID(),
$29,
$30::JSONB,
$31::JSONB,
ARRAY[111, NULL, 333]::INTEGER[],
$32
)
-- params: [
false,
null,
9999,
null,
999999999,
null,
999999999999999999,
null,
"2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178",
null,
2.718281828459045,
null,
2.718281828459045,
null,
"Hello",
null,
"z",
null,
"2024-01-21",
null,
"13:00",
null,
"13:00",
null,
"2024-01-21 13:00:00.000000",
null,
"2024-01-21 13:00:00.000000",
null,
null,
{"a":777,"b":null,"c":"Hello"},
{},
"{444,555,666}"
]
insertFoo APIの実行結果
insertFoo APIを呼び出した結果です。
3行目に、意図した行がINSERTされたことを確認できました。
DELETE文
次はDELETE文を見ていきます。
DELETE用ハンドラの中身
ハンドラのクエリー部分を見ます。
col_serial列==最大値の行を削除する内容です。
const subQuery = db.select(
{
_: sql`max(${foo.colSerial})`
}
).from(foo)
await db.delete(foo)
.where(eq(foo.colSerial, subQuery))
Drizzle ORMが生成したSQL
上記コードからDrizzle ORMが生成したSQLを、整形して見やすくしました。
delete from
"foo"
where
"foo"."col_serial" = (
select
max("col_serial")
from
"foo"
)
deleteFoo APIの実行結果
deleteFoo APIを呼び出した結果です。
意図した行(3行目)が正常に削除されました。
まとめ
Drizzle ORMをDBファーストで使ってみたところ、PostgreSQLでも問題なく動いてくれました。
ただし本記事執筆時点では、PostgreSQLの複合型(composite type)は、Drizzle ORMでサポートされていないようでした。