content: {-# language DuplicateRecordFields #-}
  {-# language FlexibleContexts #-}
  {-# language GADTs #-}
  {-# language NamedFieldPuns #-}
  {-# language RecordWildCards #-}
  {-# language StandaloneKindSignatures #-}
  {-# language StrictData #-}
  
  module Rel8.Statement.Delete
    ( Delete(..)
    , delete
    , ppDelete
    )
  where
  
  -- base
  import Data.Kind ( Type )
  import Prelude
  
  -- opaleye
  import qualified Opaleye.Internal.Tag as Opaleye
  
  -- pretty
  import Text.PrettyPrint ( Doc, (<+>), ($$), text )
  
  -- rel8
  import Rel8.Expr ( Expr )
  import Rel8.Query ( Query )
  import Rel8.Schema.Name ( Selects )
  import Rel8.Schema.Table ( TableSchema, ppTable )
  import Rel8.Statement (Statement)
  import Rel8.Statement.Returning (Returning, ppReturning, runReturning)
  import Rel8.Statement.Using ( ppUsing )
  import Rel8.Statement.Where ( ppWhere )
  
  -- transformers
  import Control.Monad.Trans.State.Strict (State)
  
  
  -- | The constituent parts of a @DELETE@ statement.
  type Delete :: Type -> Type
  data Delete a where
    Delete :: Selects names exprs =>
      { from :: TableSchema names
        -- ^ Which table to delete from.
      , using :: Query using
        -- ^ @USING@ clause — this can be used to join against other tables,
        -- and its results can be referenced in the @WHERE@ clause
      , deleteWhere :: using -> exprs -> Expr Bool
        -- ^ Which rows should be selected for deletion.
      , returning :: Returning names a
        -- ^ What to return from the @DELETE@ statement.
      }
      -> Delete a
  
  
  -- | Build a @DELETE@ 'Statement'.
  delete :: Delete a -> Statement a
  delete statement@Delete {returning} =
    runReturning (ppDelete statement) returning
  
  
  ppDelete :: Delete a -> State Opaleye.Tag Doc
  ppDelete Delete {..} = do
    musing <- ppUsing using
    pure $ case musing of
      Nothing ->
        text "DELETE FROM" <+> ppTable from $$
        text "WHERE false"
      Just (usingDoc, i) ->
        text "DELETE FROM" <+> ppTable from $$
        usingDoc $$
        ppWhere from (deleteWhere i) $$
        ppReturning from returning
  