Obsługa typów list za pomocą Esqueleto

144

Mam typy danych zdefiniowane jako:

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

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

Teraz, w obecnej formie, mam model Trwały zdefiniowany jako:

Person
  name  Text

Committee
  name  Text

CommitteePerson
  personId    PersonId
  committeeId CommitteeId

Mogę łatwo utworzyć zapytanie w celu wypełnienia CommitteeView, używając Esqueleto. To wyglądałoby mniej więcej tak:

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

Rozważmy teraz problem zaludnienia CommitteesView. Zasadniczo uzyskujemy wystarczającą ilość danych do wypełnienia, uruchamiając podzapytanie w powyższym zapytaniu. Dobra, w porządku. Jak mogę teraz używać „group by Haskell-list”, tak jak group byw SQL? Jak mogę złożyć wiersze, aby otrzymać listę osób?

Mam wrażenie, że esqueletonie poradzi sobie ze sprawą jako taką (tj. Nie ma kombinatora, który by to zrobił). A moja bazowa baza danych oczywiście nie obsługuje list Haskella jako kolumny. Ale z pewnością nie mogę być jedyną osobą, która ma do czynienia z tym problemem. Co to jest skuteczna strategia? Złożyć n-listę list do n-listy? Albo uruchamiasz n+1zapytania? Czy są jakieś inne opcje?

nomen
źródło
2
Patrzyłeś na Data.List.groupBy?
cdk
@cdk: Tak, właśnie to robię. Jednak robi się zaskakująco owłosiony.
nomen

Odpowiedzi:

2

Esqueleto NIE jest jeszcze przeznaczone do obsługi list podlist (listy wielowymiarowej) po wyjęciu z pudełka! Data.List.groupByten 'cdk' radzi ci, że możesz grupować tylko samą listę, ale nie to, o co prosiłeś.

W twoim przypadku usilnie radziłbym używać klasycznych zapytań SQL. Możesz uruchamiać zapytania n + 1, ale zrób to tylko wtedy, gdy jest to rzadka i rzadko użyteczna funkcja, która na przykład przygotowuje buforowane dane (na podstawie nazw twoich zmiennych przypuszczam, że może nie być ciężko używana i warto spróbować). W przypadku intensywnego użytkowania należy bez wątpienia rozważyć użycie klasycznego SQL.

Jeśli przejdziesz do https://github.com/prowdsponsor/esqueleto , przekonasz się, że:

Nie wszystkie funkcje SQL są dostępne, ale większość z nich można łatwo dodać (zwłaszcza funkcje).

więc możesz spróbować poprosić o nową funkcję. Powodzenia!

Kainax
źródło
Czy masz link do źródła na ten temat? Z przyjemnością przyznam nagrodę, jeśli ktoś potwierdzi, że to jest poprawna odpowiedź lub dostarczysz jakąś dokumentację.
Tech Savant,
@ NotoriousPet0 Jeśli wejdziesz na stronę haskell , znajdziesz pełną listę przykładów i przypadków użycia, a żaden z nich nie korzysta z list wielowymiarowych, nawet „złączenia wewnętrznego”. Jeśli szukasz „grupuj według” w tym miejscu, zobaczysz, że można jej użyć do umieszczenia wielu kolumn w krotce lub sortowania za pomocą dodatkowej funkcji agregującej. Mówi się tam również, że programiści starają się, aby Esqueleto był tak elastyczny, aby obsługiwał każde zapytanie, więc możesz poprosić o dodatkowe rozszerzenie tutaj .
Kainax