RDBを使う

久しぶりに RDB を使いたいなと思っています。ここで悩むのが "ORM or not to ORM" の選択です。SELECT/JOIN が返す列の数はいくらでも増減するので、プログラムでその受け皿を事前に用意するのは至難です。DBとプログラム間の相性の悪さはインピーダンスミスマッチなどとよばれます。

ORM はほとんどの単純な用途をカバーしていますが、前述した受け皿の問題を解決しておらず、特に JOIN や 高度なSQL を書いたときに行き詰る印象があります。個人的にはあまり好きではありません。SQLは自由であるべきです。

人力のマッピングは面倒ですが、やることは難しくありません。

  1. データベースの型とプログラム言語の型をマッピングする関数を作る
  2. 型に詰めて返す、または型から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が使いたくなくなりました。