久しぶりに RDB を使いたいなと思っています。ここで悩むのが "ORM or not to ORM" の選択です。SELECT/JOIN
が返す列の数はいくらでも増減するので、プログラムでその受け皿を事前に用意するのは至難です。DBとプログラム間の相性の悪さはインピーダンスミスマッチなどとよばれます。
ORM はほとんどの単純な用途をカバーしていますが、前述した受け皿の問題を解決しておらず、特に JOIN や 高度なSQL を書いたときに行き詰る印象があります。個人的にはあまり好きではありません。SQLは自由であるべきです。
人力のマッピングは面倒ですが、やることは難しくありません。
- データベースの型とプログラム言語の型をマッピングする関数を作る
- 型に詰めて返す、または型からSQLに注入する
扱う型はデータベースによって違います。プログラミング言語では簡単に扱えない型もあります。しかしこれらは大事な関数ですし、一度用意すれば長く使えます。
SMALLINT, INTEGER, SERIAL, BIGINT ... 整数 (16,32,64bit)
NUMERIC, DECIMAL 固定小数点数
REAL, DOUBLE PRECISION 浮動小数点数
BOOLEAN 真偽値
BIT ビット配列
CHAR 固定長文字列
VARCHAR, TEXT 可変長文字列
BLOB バイナリ配列
DATE, TIME, TIMESTAMP 日付
ENUM (CREATE TYPE) 列挙
COMPOSITE (CREATE TYPE) 構造体
UUID ID
CIDR, INT, MACADDR ネットワーク
POINT, LINE, CIRCLE ... 幾何
DOMAIN ドメイン ... 型に制約を与えたもの
u64 や sum を扱うときは bigint ではなく numeric を使う、というような癖はありますが、型を間違えなければ単純なものです。データ型の範囲を意識するのはプログラミング作業でも同じです。とはいえ、ここが一番の難所かもしれません。
既存のORMを使った方が9割5分早く完成して安全なので、悩みどころです。
ORMを使わない場合、RDB の読み書きには POCO/POJO な DTO を定義して使うといい感じです。
最近では Android の Room や Go言語の sqlc のように、 SQL を構文解析してコードを自動生成してくれるツールがあります。マッピングをツールが勝手に決めるという点では ORM と似た問題が起きますが、型安全で凡ミスはなくなりますし、使い捨ての DTO を毎回書く手間が無くなるので便利です。
マイグレーターとクエリビルダを用意します。検索条件の組み合わせを事前に用意するのは無理なので、プログラムで動的に構築することになります。
データベースを扱うのは面倒ですね。RDBが使いたくなくなりました。