module Opaleye.SQLite.Order (module Opaleye.SQLite.Order, O.Order) where

import qualified Opaleye.SQLite.Column as C
import           Opaleye.SQLite.QueryArr (Query)
import qualified Opaleye.SQLite.Internal.QueryArr as Q
import qualified Opaleye.SQLite.Internal.Order as O
import qualified Opaleye.SQLite.PGTypes as T

import qualified Opaleye.SQLite.Internal.HaskellDB.PrimQuery as HPQ

{-| Order the rows of a `Query` according to the `Order`.

@
import Data.Monoid (\<\>)

\-- Order by the first column ascending.  When first columns are equal
\-- order by second column descending.
example :: 'Query' ('C.Column' 'T.PGInt4', 'C.Column' 'T.PGText')
        -> 'Query' ('C.Column' 'T.PGInt4', 'C.Column' 'T.PGText')
example = 'orderBy' ('asc' fst \<\> 'desc' snd)
@

-}
orderBy :: O.Order a -> Query a -> Query a
orderBy :: Order a -> Query a -> Query a
orderBy Order a
os Query a
q =
  (((), Tag) -> (a, PrimQuery, Tag)) -> Query a
forall a b. ((a, Tag) -> (b, PrimQuery, Tag)) -> QueryArr a b
Q.simpleQueryArr (Order a -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
forall a. Order a -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
O.orderByU Order a
os ((a, PrimQuery, Tag) -> (a, PrimQuery, Tag))
-> (((), Tag) -> (a, PrimQuery, Tag))
-> ((), Tag)
-> (a, PrimQuery, Tag)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query a -> ((), Tag) -> (a, PrimQuery, Tag)
forall a b. QueryArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
Q.runSimpleQueryArr Query a
q)

-- | Specify an ascending ordering by the given expression.
--   (Any NULLs appear last)
asc :: PGOrd b => (a -> C.Column b) -> O.Order a
asc :: (a -> Column b) -> Order a
asc = OrderOp -> (a -> Column b) -> Order a
forall a b. OrderOp -> (a -> Column b) -> Order a
O.order OrderOp :: OrderDirection -> OrderNulls -> OrderOp
HPQ.OrderOp { orderDirection :: OrderDirection
HPQ.orderDirection = OrderDirection
HPQ.OpAsc
                          , orderNulls :: OrderNulls
HPQ.orderNulls     = OrderNulls
HPQ.NullsLast }

-- | Specify an descending ordering by the given expression.
--   (Any NULLs appear first)
desc :: PGOrd b => (a -> C.Column b) -> O.Order a
desc :: (a -> Column b) -> Order a
desc = OrderOp -> (a -> Column b) -> Order a
forall a b. OrderOp -> (a -> Column b) -> Order a
O.order OrderOp :: OrderDirection -> OrderNulls -> OrderOp
HPQ.OrderOp { orderDirection :: OrderDirection
HPQ.orderDirection = OrderDirection
HPQ.OpDesc
                           , orderNulls :: OrderNulls
HPQ.orderNulls     = OrderNulls
HPQ.NullsFirst }

-- | Specify an ascending ordering by the given expression.
--   (Any NULLs appear first)
ascNullsFirst :: PGOrd b => (a -> C.Column b) -> O.Order a
ascNullsFirst :: (a -> Column b) -> Order a
ascNullsFirst = OrderOp -> (a -> Column b) -> Order a
forall a b. OrderOp -> (a -> Column b) -> Order a
O.order OrderOp :: OrderDirection -> OrderNulls -> OrderOp
HPQ.OrderOp { orderDirection :: OrderDirection
HPQ.orderDirection = OrderDirection
HPQ.OpAsc
                                    , orderNulls :: OrderNulls
HPQ.orderNulls     = OrderNulls
HPQ.NullsFirst }


-- | Specify an descending ordering by the given expression.
--   (Any NULLs appear last)
descNullsLast :: PGOrd b => (a -> C.Column b) -> O.Order a
descNullsLast :: (a -> Column b) -> Order a
descNullsLast = OrderOp -> (a -> Column b) -> Order a
forall a b. OrderOp -> (a -> Column b) -> Order a
O.order OrderOp :: OrderDirection -> OrderNulls -> OrderOp
HPQ.OrderOp { orderDirection :: OrderDirection
HPQ.orderDirection = OrderDirection
HPQ.OpDesc
                                    , orderNulls :: OrderNulls
HPQ.orderNulls     = OrderNulls
HPQ.NullsLast }

{- |
Limit the results of the given query to the given maximum number of
items.
-}
limit :: Int -> Query a -> Query a
limit :: Int -> Query a -> Query a
limit Int
n Query a
a = (((), Tag) -> (a, PrimQuery, Tag)) -> Query a
forall a b. ((a, Tag) -> (b, PrimQuery, Tag)) -> QueryArr a b
Q.simpleQueryArr (Int -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
forall a. Int -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
O.limit' Int
n ((a, PrimQuery, Tag) -> (a, PrimQuery, Tag))
-> (((), Tag) -> (a, PrimQuery, Tag))
-> ((), Tag)
-> (a, PrimQuery, Tag)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query a -> ((), Tag) -> (a, PrimQuery, Tag)
forall a b. QueryArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
Q.runSimpleQueryArr Query a
a)

{- |
Offset the results of the given query by the given amount, skipping
that many result rows.
-}
offset :: Int -> Query a -> Query a
offset :: Int -> Query a -> Query a
offset Int
n Query a
a = (((), Tag) -> (a, PrimQuery, Tag)) -> Query a
forall a b. ((a, Tag) -> (b, PrimQuery, Tag)) -> QueryArr a b
Q.simpleQueryArr (Int -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
forall a. Int -> (a, PrimQuery, Tag) -> (a, PrimQuery, Tag)
O.offset' Int
n ((a, PrimQuery, Tag) -> (a, PrimQuery, Tag))
-> (((), Tag) -> (a, PrimQuery, Tag))
-> ((), Tag)
-> (a, PrimQuery, Tag)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query a -> ((), Tag) -> (a, PrimQuery, Tag)
forall a b. QueryArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
Q.runSimpleQueryArr Query a
a)

-- | Typeclass for Postgres types which support ordering operations.
class PGOrd a where

instance PGOrd T.PGBool
instance PGOrd T.PGDate
instance PGOrd T.PGFloat8
instance PGOrd T.PGFloat4
instance PGOrd T.PGInt8
instance PGOrd T.PGInt4
instance PGOrd T.PGInt2
instance PGOrd T.PGNumeric
instance PGOrd T.PGText
instance PGOrd T.PGTime
instance PGOrd T.PGTimestamptz
instance PGOrd T.PGTimestamp
instance PGOrd T.PGCitext