読者です 読者をやめる 読者になる 読者になる

八発白中

はてなブログに引越しました。

SQLを生成するCommon Lispライブラリ「SxQL」を作りました

何か作ったときにしか更新しないブログが、最近では何か作っても「まあこの程度はブログ書くほどでもないか」と思って、更新も無いような感じになっています。

今回もそうやってスルーしようと思ったのですが妻に「ブログで紹介したらいいのに」と言われてしまい、妻と過ごす休日を潰して作ったライブラリとしては、もうこれは書かざるを得ないわけで、軽く紹介しておこうと思います。

Common Lispのデータベース周辺

Common Lispのデータベース周りではこれといった好むライブラリも無く、拙作のCL-DBIでようやく土台ができたという状態です。

ただ、依然SQLを文字列で書く必要がある。もちろんそれで困らないケースも多いのですが、WHERE句やORDER BY句だけが異なるクエリを複数回投げたいといったときにはプログラムから生成できるほうが好ましい。

PerlにはSQL::Makerというライブラリで、PerlのハッシュからSQLを生成できます。

Common LispではリストからSQLを生成できたらいいよね、ということで作りました。名前は「SxQL (S-eXpression SQL)」です。

SxQLの使い方

こんな感じで使います。

(select (:id :name :sex)
  (from (:as :person :p))
  (where (:and (:>= :age 18)
               (:< :age 65)))
  (order-by (:desc :age)))
;=> #<SXQL-STATEMENT: SELECT (id, name, sex) FROM (person AS p) WHERE ((age >= 18) AND (age < 65)) ORDER BY age DESC>

selectは文字列ではなく構造体を返すことに注意してください。文字列を得るにはyieldする必要があります。

(yield *)
;=> "SELECT id, name, sex FROM (person AS p) WHERE ((age >= ?) AND (age < ?)) ORDER BY age DESC"
;   (18 65)

似たライブラリとしてs-sqlというものがありますが、違う点はSQLの生成方法です。s-sqlは大きなマクロが一つのSQLを生成する仕組みですが、SxQLではいくつかのパーツでSQLを構成することができます。

たとえば、上述のwhereはただのシンボルではなく独立したマクロです。実行するとWHERE句を表す構造体を返します。

(where (:> :age 18))
;=> #<SXQL-CLAUSE: WHERE (`age` > 18)>

(yield *)
;=> "WHERE (age > ?)"
;   (18)

一部が異なる似たSQLが複数必要になるようなアプリケーションではこの作りは合理的でしょうし、REPLで試しながらSQLを作ったりするのに便利そうです。

最初は意図していなかったのですが、Lispボトムアップにプログラムを書いていると自然とこの形になりました。きっとこれがLispとして自然なSQLビルダなんだと思います。

現状は SELECT, INSERT, UPDATE, DELETE文 に対応しています。近いうちにCREATE TABLE文なども対応予定です。

CL-DBIと共にどうぞご利用ください。