Persistentについてメモ

このサイトのコメントシステムは実はHaskellで書かれていて、DB触る用のライブラリとしてPersistentを使っているのだが、 結構クセがあって改修を加えるたびに細かい使い方を忘れているのでメモしておく。

Persistent内部で使われるデータ型

たとえばPageという型があったとして、

注意点としては、IDはPageの一部ではなくEntity Pageの一部として扱われるため、DBから引っ張ってきたものやupdateの結果など、 IDが取得できる過程を経たものからしかIDは取れない。 文章にすると当たり前っぽいが、Rubyなど動的型付けの言語に慣れてるとちょっとハマるかもしれない。

Entity周りはDatabase.Persist.Store に定義がある。 RailsでいうActiveModelみたいなものという認識。

Exportで指定できる名前とできない名前がある

Template Haskellで動的に生成される名前があるため、エクスポートする名前をホワイトリストで指定すると一部指定できないものがある。 たとえば

1[share mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase|
2Page
3    slug String
4    UniquePage slug
5|]

のような定義があったとき、Pageslugmodule節で見えているが、UniquePageは見えない。 これに対処するためには、名前を指定しないで全部エクスポートするようにする。 どうしてもエクスポートしたくないものがある場合、hiding指定でなんとかする。

原因

不明。Template Haskellの動作に関してはまったく分からない……。

モデル定義

普通のフレームワークだとモデル定義とモデルの操作を1つのファイルに切り出す(というかモデルのメソッドとして操作を定義するため、必然的にそうなる)が、 Persistentではモデルを複数ファイルにするとMigrationがうまく動かなくなる。 たとえば

1Page
2    slug String
3    UniquePage slug
4Comment
5    body String
6    pageId PageId Eq

のような定義があったとき、PageCommentを別々のファイルにすることはできるが、MigrationのときにCommentがPageの定義を見つけられなくてエラーになる。

型の定義だけをひとつのファイルにまとめ、操作をファイルごとにばらすとうまく行く。 (Yesodだとconfig/modelsというファイルに一括で書くのが普通っぽい?)