こんにちは!! tahara です。 Lisp on Rails 第3回です!
今回は ActiveRecord の belongs_to アソシエーションもどきを実装したいと思います。 実行時のイメージとしては次のようになります。
(def-record post) (def-record comment (:belongs-to post)) ; comments テーブルは post_id 列を持っている。 (mapcar #'post-of (all comment)) ;; => ポストのリストを取得
これを実装するのに Common Lisp の MOP を使ってみます。 インスタンス変数とそのインスタンス変数へのアクセスを拡張することになります。
まずインスタンス変数の拡張です。 ar-belongs-to-slot-mixin に belongs_to のアソシエーションテーブルと 外部キーを持たせ、それを継承した ar-belongs-to-effective-slot-definition を belongs_to のアソシエーションのインスタンス変数とします。
(defclass ar-belongs-to-slot-mixin () ((belongs-to :initarg :belongs-to :initform nil :accessor belongs-to) (foreign-slotname :initarg :foreign-slotname :initform nil :accessor foreign-slotname))) (defclass ar-belongs-to-effective-slot-definition (ar-effective-slot-definition ar-belongs-to-slot-mixin) ())
slot-value-using-class を使い ar-belongs-to-effective-slot-definition にアクセスする際に、 foreign-slotname を外部キーとして belongs-to のテーブルから レコードを取得するようにします。
(defmethod c2mop:slot-value-using-class ((class active-record-class) instance (slot-def ar-belongs-to-effective-slot-definition)) (aif (call-next-method) it (setf (slot-value instance (belongs-to slot-def)) (select (find-class (belongs-to slot-def)) (slot-value instance (foreign-slotname slot-def))))))
以上、なんとなく belongs-to できました。 ソースはこちらから http://github.com/quek/lisp-on-rails
第4回につづきます