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というファイルに一括で書くのが普通っぽい?)