{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Rel8.Array
  (
    -- ** @ListTable@
    ListTable
  , head, headExpr
  , index, indexExpr
  , last, lastExpr
  , length, lengthExpr
  , elem, notElem

    -- ** @NonEmptyTable@
  , NonEmptyTable
  , head1, head1Expr
  , index1, index1Expr
  , last1, last1Expr
  , length1, length1Expr
  , elem1, notElem1

    -- ** Unsafe
  , unsafeSubscript
  , unsafeSubscripts
  )
where

-- base
import Data.Int (Int32)
import Data.List.NonEmpty (NonEmpty)
import Prelude hiding (elem, head, last, length, notElem)

-- opaleye
import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye

-- rel8
import Rel8.Internal.Expr (Expr)
import Rel8.Internal.Expr.Bool (not_)
import Rel8.Internal.Expr.Function (rawFunction)
import Rel8.Internal.Expr.List
import Rel8.Internal.Expr.NonEmpty
import Rel8.Internal.Expr.Null (isNonNull, isNull)
import Rel8.Internal.Expr.Opaleye (fromPrimExpr, toPrimExpr)
import Rel8.Internal.Expr.Subscript
import Rel8.Internal.Schema.Null (Nullity (NotNull, Null), Sql, nullable)
import Rel8.Internal.Table.List
import Rel8.Internal.Table.NonEmpty
import Rel8.Internal.Type (DBType)
import Rel8.Internal.Type.Eq (DBEq)


-- | @'elem' a as@ tests whether @a@ is an element of the list @as@.
elem :: Sql DBEq a => Expr a -> Expr [a] -> Expr Bool
elem :: forall a. Sql DBEq a => Expr a -> Expr [a] -> Expr Bool
elem = Expr a -> Expr [a] -> Expr Bool
forall a (t :: * -> *).
(Sql DBEq a, DBType (t a)) =>
Expr a -> Expr (t a) -> Expr Bool
memberOf
infix 4 `elem`


-- | @'elem1' a as@ tests whether @a@ is an element of the non-empty list
-- @as@.
elem1 :: Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool
elem1 :: forall a. Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool
elem1 = Expr a -> Expr (NonEmpty a) -> Expr Bool
forall a (t :: * -> *).
(Sql DBEq a, DBType (t a)) =>
Expr a -> Expr (t a) -> Expr Bool
memberOf
infix 4 `elem1`


-- | @'notElem' a as@ tests whether @a@ is not an element of the list @as@.
notElem :: Sql DBEq a => Expr a -> Expr [a] -> Expr Bool
notElem :: forall a. Sql DBEq a => Expr a -> Expr [a] -> Expr Bool
notElem = Expr a -> Expr [a] -> Expr Bool
forall a (t :: * -> *).
(Sql DBEq a, DBType (t a)) =>
Expr a -> Expr (t a) -> Expr Bool
notMemberOf
infix 4 `notElem`


-- | @'notElem1' a as@ tests whether @a@ is not an element of the non-empty
-- list @as@.
notElem1 :: Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool
notElem1 :: forall a. Sql DBEq a => Expr a -> Expr (NonEmpty a) -> Expr Bool
notElem1 = Expr a -> Expr (NonEmpty a) -> Expr Bool
forall a (t :: * -> *).
(Sql DBEq a, DBType (t a)) =>
Expr a -> Expr (t a) -> Expr Bool
notMemberOf
infix 4 `notElem1`


memberOf :: forall a t. (Sql DBEq a, DBType (t a))
  => Expr a -> Expr (t a) -> Expr Bool
memberOf :: forall a (t :: * -> *).
(Sql DBEq a, DBType (t a)) =>
Expr a -> Expr (t a) -> Expr Bool
memberOf = case forall a. Nullable a => Nullity a
nullable @a of
  Nullity a
Null -> \Expr a
ma Expr (t a)
mas -> Expr (Maybe Int32) -> Expr Bool
forall a. Expr (Maybe a) -> Expr Bool
isNonNull (Expr (t (Maybe a1)) -> Expr (Maybe a1) -> Expr (Maybe Int32)
forall (t :: * -> *) a.
(DBType (t (Maybe a)), DBType a) =>
Expr (t (Maybe a)) -> Expr (Maybe a) -> Expr (Maybe Int32)
position Expr (t a)
Expr (t (Maybe a1))
mas Expr a
Expr (Maybe a1)
ma)
  Nullity a
NotNull -> Expr a -> Expr (t a) -> Expr Bool
forall a as. Expr a -> Expr as -> Expr Bool
eqAny


notMemberOf :: forall a t. (Sql DBEq a, DBType (t a))
  => Expr a -> Expr (t a) -> Expr Bool
notMemberOf :: forall a (t :: * -> *).
(Sql DBEq a, DBType (t a)) =>
Expr a -> Expr (t a) -> Expr Bool
notMemberOf = case forall a. Nullable a => Nullity a
nullable @a of
  Nullity a
Null -> \Expr a
ma Expr (t a)
mas -> Expr (Maybe Int32) -> Expr Bool
forall a. Expr (Maybe a) -> Expr Bool
isNull (Expr (t (Maybe a1)) -> Expr (Maybe a1) -> Expr (Maybe Int32)
forall (t :: * -> *) a.
(DBType (t (Maybe a)), DBType a) =>
Expr (t (Maybe a)) -> Expr (Maybe a) -> Expr (Maybe Int32)
position Expr (t a)
Expr (t (Maybe a1))
mas Expr a
Expr (Maybe a1)
ma)
  Nullity a
NotNull -> \Expr a
a Expr (t a)
as -> Expr Bool -> Expr Bool
not_ (Expr a -> Expr (t a) -> Expr Bool
forall a as. Expr a -> Expr as -> Expr Bool
eqAny Expr a
a Expr (t a)
as)


position :: (DBType (t (Maybe a)), DBType a)
  => Expr (t (Maybe a)) -> Expr (Maybe a) -> Expr (Maybe Int32)
position :: forall (t :: * -> *) a.
(DBType (t (Maybe a)), DBType a) =>
Expr (t (Maybe a)) -> Expr (Maybe a) -> Expr (Maybe Int32)
position Expr (t (Maybe a))
as Expr (Maybe a)
a = QualifiedName
-> (Expr (t (Maybe a)), Expr (Maybe a)) -> Expr (Maybe Int32)
forall arguments a.
Arguments arguments =>
QualifiedName -> arguments -> Expr a
rawFunction QualifiedName
"array_position" (Expr (t (Maybe a))
as, Expr (Maybe a)
a)


eqAny :: Expr a -> Expr as -> Expr Bool
eqAny :: forall a as. Expr a -> Expr as -> Expr Bool
eqAny Expr a
a Expr as
as =
  PrimExpr -> Expr Bool
forall a. PrimExpr -> Expr a
fromPrimExpr (BinOp -> PrimExpr -> PrimExpr -> PrimExpr
Opaleye.AnyExpr BinOp
(Opaleye.:==) (Expr a -> PrimExpr
forall a. Expr a -> PrimExpr
toPrimExpr Expr a
a) (Expr as -> PrimExpr
forall a. Expr a -> PrimExpr
toPrimExpr Expr as
as))