packages feed

poppy-1.0.0: test/Schema/Include/Chapter.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoFieldSelectors #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Schema.Include.Chapter
  ( ChapterInclude (..)
  , ChapterWith (..)
  , ChapterWithPicked (..)
  , ChapterSections
  , ChapterResult
  , ChapterRead
  , LoadChapter (..)
  , toChapterWithPicked
  )
where

import Poppy.Internal.Generated
  ( Db,
    IncludeFor,
    Load (..),
    Skip (..),
    Skipped,
    ValidEdge,
    skipped,
    OmitSelect (..),
    findByIn,
    indexHasMany,
    lookupGroups
  )
import Schema.Chapter (ChapterPicked, ChapterRow (..), ChapterSelect, toChapterPicked)
import qualified Schema.Section as Section
import Schema.Section (SectionRow (..), SectionTable)

data ChapterInclude sections = ChapterInclude
  { sections :: sections
  }
  deriving (Show, Eq)

data ChapterWith sections = ChapterWith
  { chapter :: ChapterRow,
    sections :: ChapterSections sections
  }

deriving instance (Eq ChapterRow, Eq (ChapterSections sections)) => Eq (ChapterWith sections)
deriving instance (Show ChapterRow, Show (ChapterSections sections)) => Show (ChapterWith sections)

data ChapterWithPicked sections = ChapterWithPicked
  { chapter :: ChapterPicked,
    sections :: ChapterSections sections
  }

deriving instance (Eq ChapterPicked, Eq (ChapterSections sections)) => Eq (ChapterWithPicked sections)
deriving instance (Show ChapterPicked, Show (ChapterSections sections)) => Show (ChapterWithPicked sections)

toChapterWithPicked :: ChapterSelect -> ChapterWith sections -> ChapterWithPicked sections
toChapterWithPicked select_ nested =
  ChapterWithPicked
    { chapter = toChapterPicked select_ nested.chapter,
      sections = nested.sections
    }

type family ChapterSections edge where
  ChapterSections Skip = Skipped "sections" [SectionRow]
  ChapterSections (Load SectionTable ()) = [SectionRow]

type family ChapterResult include where
  ChapterResult () = ChapterRow
  ChapterResult (ChapterInclude sections) = ChapterWith sections

type family ChapterRead include select where
  ChapterRead () OmitSelect = ChapterRow
  ChapterRead () ChapterSelect = ChapterPicked
  ChapterRead (ChapterInclude sections) OmitSelect = ChapterWith sections
  ChapterRead (ChapterInclude sections) ChapterSelect = ChapterWithPicked sections

class LoadChapterSections edge where
  loadChapterSections :: edge -> [ChapterRow] -> Db [ChapterSections edge]

instance LoadChapterSections Skip where
  loadChapterSections Skip roots = pure (map (const skipped) roots)

instance LoadChapterSections (Load SectionTable ()) where
  loadChapterSections edge roots = do
    rows <- findByIn @SectionTable @SectionRow Section.sectionChapterRef (map (.id) roots) edge.where_ edge.orderBy_ edge.take_
    let grouped = indexHasMany (.chapterRef) rows
    pure [lookupGroups root.id grouped | root <- roots]

instance {-# OVERLAPPABLE #-} (ValidEdge "Section" edge) => LoadChapterSections edge where
  loadChapterSections _ roots = pure (map (const skipped) roots)

class LoadChapter sections where
  loadChapter :: ChapterInclude sections -> [ChapterRow] -> Db [ChapterWith sections]

instance (LoadChapterSections sections, ValidEdge "Section" sections) => LoadChapter sections where
  loadChapter include roots = do
    sectionsLoaded <- loadChapterSections include.sections roots
    pure
      [ ChapterWith
          { chapter = root,
            sections = sectionsLoaded !! n
          }
      | (n, root) <- zip [0 :: Int ..] roots
      ]

instance (ValidEdge "Section" sections) => IncludeFor "Chapter" (ChapterInclude sections)