Persistentについてメモ
このサイトのコメントシステムは実はHaskellで書かれていて、DB触る用のライブラリとしてPersistentを使っているのだが、 結構クセがあって改修を加えるたびに細かい使い方を忘れているのでメモしておく。
Persistent内部で使われるデータ型
たとえばPageという型があったとして、
Pageは普段通りにdataで定義した感じの、指定したフィールドを持った型。Entity PageはPersistentのアクションが返してくる型。インスタンスはユニークな識別子によって識別される。Key PageはEntity Pageがもっているユニークな識別子。いわゆるID。PageIdという名前でも参照できる。Entity PageからPageを得たい場合、entityValに渡せばよい。 ただし、当然ながらここからEntity Pageに戻すことはできない。
注意点としては、IDはPageの一部ではなくEntity Pageの一部として扱われるため、DBから引っ張ってきたものやupdateの結果など、
IDが取得できる過程を経たものからしかIDは取れない。
文章にすると当たり前っぽいが、Rubyなど動的型付けの言語に慣れてるとちょっとハマるかもしれない。
Entity周りはDatabase.Persist.Store
に定義がある。
RailsでいうActiveModelみたいなものという認識。
Exportで指定できる名前とできない名前がある
Template Haskellで動的に生成される名前があるため、エクスポートする名前をホワイトリストで指定すると一部指定できないものがある。 たとえば
のような定義があったとき、Pageやslugはmodule節で見えているが、UniquePageは見えない。
これに対処するためには、名前を指定しないで全部エクスポートするようにする。
どうしてもエクスポートしたくないものがある場合、hiding指定でなんとかする。
原因
不明。Template Haskellの動作に関してはまったく分からない……。
モデル定義
普通のフレームワークだとモデル定義とモデルの操作を1つのファイルに切り出す(というかモデルのメソッドとして操作を定義するため、必然的にそうなる)が、 Persistentではモデルを複数ファイルにするとMigrationがうまく動かなくなる。 たとえば
のような定義があったとき、PageとCommentを別々のファイルにすることはできるが、MigrationのときにCommentがPageの定義を見つけられなくてエラーになる。
型の定義だけをひとつのファイルにまとめ、操作をファイルごとにばらすとうまく行く。 (Yesodだとconfig/modelsというファイルに一括で書くのが普通っぽい?)