Gestion des types de liste avec Esqueleto

144

J'ai des types de données définis comme:

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

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

Maintenant, dans l'état actuel des choses, j'ai un modèle persistant défini comme:

Person
  name  Text

Committee
  name  Text

CommitteePerson
  personId    PersonId
  committeeId CommitteeId

Je peux assez facilement créer une requête pour remplir un CommitteeView, en utilisant Esqueleto. Cela donnerait quelque chose comme ceci:

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

Maintenant, considérons le problème du peuplement CommitteesView. En principe, nous obtenons suffisamment de données à remplir en exécutant une sous-requête dans la requête ci-dessus. D'accord, très bien. Maintenant, comment puis-je utiliser "group by Haskell-list" comme group bydans SQL? Comment puis-je plier des lignes pour obtenir une liste de listes de personnes?

J'ai l'impression que je esqueletone peux pas gérer le cas en tant que tel (c'est-à-dire qu'il n'a pas de combinateur qui le ferait). Et ma base de données sous-jacente ne prend évidemment pas en charge les listes Haskell en tant que colonne. Mais, sûrement, je ne peux pas être la seule personne à faire face à ce problème. Qu'est-ce qu'une stratégie efficace? Plier une n-liste de listes en une n-liste? Ou exécuter des n+1requêtes? Il y a-t-il des alternatives?

pas d'hommes
la source
2
Avez-vous regardé Data.List.groupBy?
cdk
@cdk: Ouais, c'est ce que je fais. Cependant, il devient étonnamment poilu.
nomen

Réponses:

2

Esqueleto n'est PAS destiné à gérer la liste des sous-listes (liste multidimensionnelle) prête à l'emploi! Data.List.groupByce 'cdk' qui vous a été conseillé ne peut se grouper que lui-même, mais pas ce que vous demandiez.

Pour votre cas, je vous conseillerais avec insistance d'utiliser une requête SQL classique. Vous pouvez exécuter des requêtes n + 1, mais ne le faites que si c'est une fonction rare et pas souvent utilisable, qui prépare par exemple des données en cache (en fonction des noms de vos variables, je suppose que cela peut ne pas être lourdement utilisé et cela vaut la peine d'essayer). Pour un usage intensif, vous devriez envisager d'utiliser le SQL classique sans aucun doute.

Si vous allez sur https://github.com/prowdsponsor/esqueleto, vous trouverez que:

Toutes les fonctionnalités SQL ne sont pas disponibles, mais la plupart d'entre elles peuvent être facilement ajoutées (en particulier les fonctions).

afin que vous puissiez essayer de demander une nouvelle fonctionnalité. Bonne chance!

Kainax
la source
Avez-vous un lien vers une source à ce sujet? Je serai heureux d'attribuer la prime si quelqu'un peut vérifier que c'est la bonne réponse ou si vous pouvez fournir une sorte de documentation.
Tech Savant
@ NotoriousPet0 Si vous allez sur le site Web de haskell, vous trouverez une liste complète d'exemples et de cas d'utilisation et aucun d'entre eux n'utilise de listes multidimensionnelles, même la "jointure interne". Si vous recherchez un «groupe par» là-bas, vous constaterez qu'il peut être utilisé pour inclure plusieurs colonnes dans un tuple ou pour trier par une fonction d'agrégation supplémentaire. Il est également dit ici que les développeurs essaient de rendre Esqueleto aussi flexible pour prendre en charge n'importe quelle requête, vous pouvez donc demander une extension supplémentaire ici .
Kainax