Обработка списков типов с помощью Esqueleto

У меня есть типы данных, определенные как:

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

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

Теперь, поскольку это так, у меня есть Persistent model, определяемая как:

Person
  name  Text

Committee
  name  Text

CommitteePerson
  personId    PersonId
  committeeId CommitteeId

Я могу довольно легко создать запрос для заполнения КомитетаView, используя Esqueleto. Это будет выглядеть примерно так:

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. В принципе, мы получаем достаточно данных для заполнения, выполнив подзапрос в указанном выше запросе. Хорошо, справедливо. Теперь, как я могу использовать "группу по Haskell-списку", например group by в SQL? Как я могу свернуть строки, чтобы я мог составить список списков людей?

У меня создается впечатление, что esqueleto не может обрабатывать этот случай как таковой (т.е. он не имеет комбинатора, который бы это сделал). И моя базовая база данных, очевидно, не поддерживает списки Haskell в качестве столбца. Но, конечно, я не могу быть единственным человеком, который столкнулся бы с этой проблемой. Какова эффективная стратегия? Складывание n-списка списков в n-список? Или запустить n+1 запросы? Есть ли другие варианты?

Ответ 1

Esqueleto NOT предназначен для обработки списка подсписок (многомерный список) из коробки! Data.List.groupBy, который советует вам "cdk", вы можете группировать только сам список, но не то, о чем вы просите.

В вашем случае я настоятельно рекомендую вам использовать классические SQL-запросы. Вы можете запускать n + 1 запросов, но делайте это только в том случае, если это редкая и не часто используемая функция, которая, например, готовит кэшированные данные (на основе ваших имен переменных, я полагаю, что она не может быть тяжелой и стоит попробовать). Для интенсивного использования вы должны без сомнения использовать классический SQL.

Если вы перейдете в https://github.com/prowdsponsor/esqueleto, вы обнаружите, что:

Не все функции SQL доступны, но большинство из них могут быть легко добавлены (особенно функции).

чтобы вы могли попросить новую функцию. Удачи!