web-dev-qa-db-ja.com

Esqueletoでリスト型を処理する

次のように定義されたデータ型があります。

data ComitteeView = CommitteeView { committeeId :: CommitteeId
                                  , committeeMembers :: [Person] 
                                  }

data CommitteesView = CommitteesView { committeeView :: [CommitteeView] }

さて、現状では、次のように定義された永続モデルがあります。

Person
  name  Text

Committee
  name  Text

CommitteePerson
  personId    PersonId
  committeeId CommitteeId

Esqueletoを使用すると、CommitteetViewにデータを入力するクエリを簡単に作成できます。それは次のようなものになります:

getCommitteeView cid = 
  CommitteeView <$> runDB $ 
    select $
      from (person `InnerJoin` pxc `InnerJoin` committee) -> do
        on  (committee ^. CommitteeId ==. pxc ^. CommitteePersonCommitteeId)
        on  (person ^. PersonId       ==. pxc ^. CommitteePersonPersonId)
        where_ (committee ^. CommitteePersonCommitteeId ==. val cid)
        return person

次に、CommitteesViewへの入力の問題を考えます。原則として、上記のクエリでサブクエリを実行することで、入力するのに十分なデータを取得します。わかりました。では、SQLでgroup byのような「group by Haskell-list」をどのように使用できますか?行を折り畳んで、人のリストのリストを作成するにはどうすればよいですか?

esqueletoはそのようなケースを処理できない(つまり、それを行うコンビネーターがない)という印象を受けます。そして、私の基になるデータベースは明らかに列としてのHaskellリストをサポートしていません。しかし、確かに、この問題に直面するのは私だけではありません。効果的な戦略とは何ですか?リストのnリストをnリストに折りたたみますか?またはn+1クエリを実行していますか?他のオプションはありますか?

144
nomen

Esqueletoは[〜#〜]ではありません[〜#〜]は、サブリストのリスト(多次元リスト)をそのまま使用できることを意味します! Data.List.groupBy「cdk」があなたに忠告したのは、リスト自体だけで、あなたが求めていたものはグループ化できないということです。

あなたのケースでは、私はしつこく古典的なSQLクエリを使用することをお勧めします。 n + 1クエリを実行することはできますが、それが実行されるのはまれで、頻繁に使用できる機能ではない場合のみです。たとえば、キャッシュされたデータを準備します(変数名に基づいて、頻繁に使用されることはなく、試してみる価値があると思います)。頻繁に使用する場合は、疑いなくクラシックSQLの使用を検討してください。

https://github.com/prowdsponsor/esqueleto にアクセスすると、次のことがわかります。

すべてのSQL機能が使用できるわけではありませんが、それらのほとんど(特に関数)は簡単に追加できます。

新しい機能をリクエストしてみてください。幸運を!

2
Kainax