遅くなりました!! tahara です。 Lisp on Rails 第7回です!
今回は ActiveRecord::Base の find メソッドの機能を多少実装してみたいと思います。
ActiveRecord::Base の find メソッドは次の4つの使い方があります。
- id で検索。
引数は
(id, *args), (id1, id2, ..., *args), ([id1, id2, ..., *args])
の3パターン。 該当するレコードがない場合はRecordNotFound
が発生する。 - 最初の1件を検索。
引数は
(:first, *args)
で、該当がない場合は nil を返す。Model.first(*args)
というショートカットがある。 - 最後の1件を検索。
引数は
(:last, *args)
で、該当がない場合は nil を返す。Model.last(*args)
というショートカットがある。 - 該当する全件を検索。
引数は
(:all, &args)
で、該当がない場合は nil を返す。Model.all(*args)
というショートカットがある。
上記の4つの使い方全てで次のハッシュオプションが使えます。
- :conditions - いわゆる検索条件。文字列またはリストで指定。
- :order - SQL の ORDEY BY
- :group - SQL の GROUP BY
- :having - SQL の HAVING
- :limit - 最大取得件数。
- :offset - 取得開始位置。
- :joins - SQL の JOIN だけど、普通次の :include を使う。
- :include - 検索時に一緒にとってくるテーブルをアソシエーション名(has_many :xxxs)で指定する。
- :select - 取得カラム。デフォルトは "*"。
- :from - SQL の FROM。ビューから検索するとき等に使える。
- :readonly - 取得結果をリードオンリー指定する。
- :lock - SQL でのロック。"FOR UPDATE" とか。
このような場合 Common Lisp ではマルチディスパッチとキーワード引数を使えばうまくいくはずです。
;; find は CL にあるので select にする (defgeneric select (class id-or-keyword &key conditions order group having limit offset joins include select from readonly lock &allow-other-keys)) (defmethod select ((class symbol) id-or-keyword &rest args) (apply #'select (find-class class) id-or-keyword args)) (defmethod select ((class active-record-class) (id integer) &rest args &key conditions) (setf conditions (append (list :id id) conditions)) ...) (defmethod select ((class active-record-class) (ids list) &rest args &key conditions) (setf conditions (append (list :id ids) conditions)) ...) (defmethod select ((class active-record-class) (keyword (eql :all)) &rest args) ...) (defmethod select ((class active-record-class) (keyword (eql :first)) &rest args &key (order "id")) ...) (defmethod select ((class active-record-class) (keyword (eql :last)) &rest args &key (order "id")) ...) (defun all (&rest args) (apply #'select (car args) :all (cdr args))) ;; first と last は CL パッケージとかぶる。
といった感じで実装してみました。 joins, include, readonly 等はまだ未実装です。
しかし Common Lisp パッケージとシンボル名(find, first, last)がかぶるのが悩ましいところです。shadowing しようかしらん。
ソースはこちらから http://github.com/quek/lisp-on-rails
第8回につづきます。