Yesod で使われている Database.Persist ですが、どうも型シグニチャとかごちゃごちゃしててわかりにくいので、型を簡略化して説明を加えてみました。
参考: [persistent-1.1.3.2] (http://hackage.haskell.org/packages/archive/persistent/1.1.3.2/doc/html/Database-Persist.html)
はじめに
型シグニチャは簡略化しています。haddock との対応は
-
値
→val
-
キー
→Key val
-
ユニークキー
→Unique val
-
フィルタ
→[Filter val]
-
オプション
→[SelectOpt val]
-
更新内容
→[Update val]
といった感じです。
また、値とエンティティの違いですが、値はデータベースと関係なく存在するデータとすると、エンティティはデータベース上のレコードに対応し、キーの情報を持っています。
型シグニチャ中の m
は、その関数が使えるモナドみたいなもんです…(うまく説明できない)。Scaffold された Yesod サイトであれば、runDB $ do 〜 の中に書くやつです。
PersistStore のメソッド
insert :: 値 -> m キー
値を挿入して新規発行されたキーを返す
insertKey :: キー -> 値 -> m ()
値を、キーを指定して挿入する
repsert :: キー -> 値 -> m ()
キーに対応するエンティティが存在すれば置き換える。でなければ insertKey と同じ
replace :: キー -> 値 -> m ()
キーに対応するエンティティが存在すれば置き換える。存在しない場合の動作は未定義
delete :: キー -> m ()
指定したキーに対応するエンティティを削除する。存在しなければ何もしない
get :: キー -> m (Maybe 値)
キーを指定して値を取得する。存在しないかもしれないので Maybe でくるんである。
PersistUnique のメソッド
getBy :: ユニークキー -> m (Maybe エンティティ)
ユニークキーをもとにエンティティを取得する。
deleteBy :: ユニークキー -> m ()
ユニークキーをもとにエンティティを削除する。
insertUnique :: 値 -> m (Maybe キー)
insert に似ているが、ユニークキー制約を満たさない場合は Nothing を返す
PersistQuery のメソッド
update :: キー -> 更新内容 -> m ()
指定したキーに対応するエンティティを更新する
updateGet :: キー -> 更新内容 -> m 値
update と同時に更新後の値を取得する
updateWhere :: フィルタ -> 更新内容 -> m ()
フィルタに該当するエンティティをすべて更新する
deleteWhere :: フィルタ -> m ()
フィルタに該当するエンティティをすべて削除する。
selectSource :: フィルタ -> オプション -> Source m エンティティ
指定したフィルタとオプションでエンティティを選択し、結果を Source で受け取る(よく知らない)
selectFirst :: フィルタ -> オプション -> m (Maybe エンティティ)
指定したフィルタとオプションで選択された最初のエンティティを Maybe で返す(該当するものがない場合は Nothing)。
selectKeys :: フィルタ -> オプション -> Source m キー
指定したフィルタとオプションでキーを選択し、結果を Source で受け取る
count :: フィルタ -> m Int
フィルタに該当するエンティティの数を Int で返す
その他の関数
insertBy :: 値 -> m (Either エンティティ キー)
値を挿入するが、ユニークキー制約を満たさない場合、その原因となったエンティティを Left で返す。成功すれば挿入されたエンティティのキーを Right で返す
getJust :: キー -> m 値
get に似ているが、キーに対応するエンティティが存在することを想定しているので返り値は Maybe ではない。安全性に欠ける。
belongsTo :: (子の値 -> Maybe 親のキー) -> 子の値 -> m (Maybe 親の値)
一対多の親子関係を形成するエンティティ同士において、親エンティティのキーを Maybe で定義している場合(取得関数を childParentMaybeId とする)に、belongsTo childParentMaybeId child などとして親の値を Maybe で得る
belongsToJust :: (子の値 -> 親のキー) -> 子の値 -> m 親の値
一対多の親子関係を形成するエンティティ同士において、親エンティティのキー取得関数を childParentId とするとき、belongsToJust childParentId child などとして親の値を得る
getByValue :: 値 -> m (Maybe エンティティ)
指定した値と同等のユニークキー制約を満たすエンティティを一つ取得する。ユニークキーを一つだけもつエンティティで意味を持つ。
checkUnique :: 値 -> m Bool
指定した値(挿入前の値など)がユニークキー制約にひっかからなければ True を返す。
selectList :: フィルタ -> オプション -> m [エンティティ]
指定したフィルタとオプションでエンティティを選択し、結果を List で受け取る。
deleteCascadeWhere :: フィルタ -> m ()
関連モデルも削除するための機能のようだが、ちょっとわかりません。
Yesod での使用例
makeFormLesson :: Entity Lesson -> Handler FormLesson
makeFormLesson eLesson = do
let (Entity lessonId lesson) = eLesson
title <- runDB $ belongsToJust lessonTitleId lesson
meLessonAttribute <- runDB $ getBy (UniqueAttribute lessonId)
attributes <- case meLessonAttribute of
Just eLessonAttribute -> return $
(,,) <$> lessonAttributePartialAttendable
<*> lessonAttributeObservable
<*> lessonAttributeExperienceable
$ entityVal eLessonAttribute
Nothing -> do
let (pa, o, e) = defaultLessonAttributes
_ <- runDB $ insert $ LessonAttribute lessonId pa o e
return (pa, o, e)
return $ FormLesson <$> const title
<*> lessonTeacherId
<*> lessonSeason
<*> lessonSchoolId
<*> const attributes
<*> lessonDescription
<*> lessonPrerequisite
$ lesson
FormLesson
という型に意味はありませんので気にしないでください。runDB
の呼び出しに注目してください 。関連するエンティティをいくつかの方法で取り出しています。