content: {-# language FlexibleContexts #-}
  {-# language TypeFamilies #-}
  {-# language ViewPatterns #-}
  
  module Rel8.Table.Bool
    ( bool
    , case_
    , nullable
    )
  where
  
  -- base
  import Prelude
  
  -- rel8
  import Rel8.Expr ( Expr )
  import Rel8.Expr.Bool ( boolExpr, caseExpr )
  import Rel8.Expr.Null ( isNull, unsafeUnnullify )
  import Rel8.Schema.HTable ( htabulate, hfield )
  import Rel8.Table ( Table, fromColumns, toColumns )
  
  
  -- | An if-then-else expression on tables.
  --
  -- @bool x y p@ returns @x@ if @p@ is @False@, and returns @y@ if @p@ is
  -- @True@.
  bool :: Table Expr a => a -> a -> Expr Bool -> a
  bool (toColumns -> false) (toColumns -> true) condition =
    fromColumns $ htabulate $ \field ->
      case (hfield false field, hfield true field) of
        (falseExpr, trueExpr) -> boolExpr falseExpr trueExpr condition
  {-# INLINABLE bool #-}
  
  
  -- | Produce a table expression from a list of alternatives. Returns the first
  -- table where the @Expr Bool@ expression is @True@. If no alternatives are
  -- true, the given default is returned.
  case_ :: Table Expr a => [(Expr Bool, a)] -> a -> a
  case_ (map (fmap toColumns) -> branches) (toColumns -> fallback) =
    fromColumns $ htabulate $ \field -> case hfield fallback field of
      fallbackExpr ->
        case map (fmap (`hfield` field)) branches of
          branchExprs -> caseExpr branchExprs fallbackExpr
  
  
  -- | Like 'maybe', but to eliminate @null@.
  nullable :: Table Expr b => b -> (Expr a -> b) -> Expr (Maybe a) -> b
  nullable b f ma = bool (f (unsafeUnnullify ma)) b (isNull ma)
  