module Rel8.Query.Indexed
  ( indexed
  )
where

-- base
import Data.Int ( Int64 )
import Prelude

-- opaleye
import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
import qualified Opaleye.Internal.PackMap as Opaleye
import qualified Opaleye.Internal.PrimQuery as Opaleye
import qualified Opaleye.Internal.QueryArr as Opaleye
import qualified Opaleye.Internal.Tag as Opaleye

-- rel8
import Rel8.Expr ( Expr )
import Rel8.Expr.Opaleye ( fromPrimExpr )
import Rel8.Query ( Query )
import Rel8.Query.Opaleye ( mapOpaleye )


-- | Pair each row of a query with its index within the query.
indexed :: Query a -> Query (Expr Int64, a)
indexed :: Query a -> Query (Expr Int64, a)
indexed = (Select a -> Select (Expr Int64, a))
-> Query a -> Query (Expr Int64, a)
forall a b. (Select a -> Select b) -> Query a -> Query b
mapOpaleye ((Select a -> Select (Expr Int64, a))
 -> Query a -> Query (Expr Int64, a))
-> (Select a -> Select (Expr Int64, a))
-> Query a
-> Query (Expr Int64, a)
forall a b. (a -> b) -> a -> b
$ \(Opaleye.QueryArr ((), Tag) -> (a, Lateral -> PrimQuery -> PrimQuery, Tag)
f) -> (((), Tag)
 -> ((Expr Int64, a), Lateral -> PrimQuery -> PrimQuery, Tag))
-> Select (Expr Int64, a)
forall a b.
((a, Tag) -> (b, Lateral -> PrimQuery -> PrimQuery, Tag))
-> SelectArr a b
Opaleye.QueryArr ((((), Tag)
  -> ((Expr Int64, a), Lateral -> PrimQuery -> PrimQuery, Tag))
 -> Select (Expr Int64, a))
-> (((), Tag)
    -> ((Expr Int64, a), Lateral -> PrimQuery -> PrimQuery, Tag))
-> Select (Expr Int64, a)
forall a b. (a -> b) -> a -> b
$ \(()
_, Tag
tag) ->
  let
    (a
a, Lateral -> PrimQuery -> PrimQuery
query, Tag
tag') = ((), Tag) -> (a, Lateral -> PrimQuery -> PrimQuery, Tag)
f ((), Tag
tag)
    tag'' :: Tag
tag'' = Tag -> Tag
Opaleye.next Tag
tag'
    window :: PrimExpr
window = Literal -> PrimExpr
Opaleye.ConstExpr (Literal -> PrimExpr) -> Literal -> PrimExpr
forall a b. (a -> b) -> a -> b
$ String -> Literal
Opaleye.OtherLit String
"ROW_NUMBER() OVER () - 1"
    (PrimExpr
index, [(Symbol, PrimExpr)]
bindings) = PM [(Symbol, PrimExpr)] PrimExpr
-> (PrimExpr, [(Symbol, PrimExpr)])
forall a r. PM [a] r -> (r, [a])
Opaleye.run (PM [(Symbol, PrimExpr)] PrimExpr
 -> (PrimExpr, [(Symbol, PrimExpr)]))
-> PM [(Symbol, PrimExpr)] PrimExpr
-> (PrimExpr, [(Symbol, PrimExpr)])
forall a b. (a -> b) -> a -> b
$ String -> Tag -> PrimExpr -> PM [(Symbol, PrimExpr)] PrimExpr
forall primExpr.
String -> Tag -> primExpr -> PM [(Symbol, primExpr)] PrimExpr
Opaleye.extractAttr String
"index" Tag
tag' PrimExpr
window
    query' :: Lateral -> PrimQuery -> PrimQuery
query' Lateral
lateral = Bool -> [(Symbol, PrimExpr)] -> PrimQuery -> PrimQuery
forall a.
Bool -> [(Symbol, PrimExpr)] -> PrimQuery' a -> PrimQuery' a
Opaleye.Rebind Bool
True [(Symbol, PrimExpr)]
bindings (PrimQuery -> PrimQuery)
-> (PrimQuery -> PrimQuery) -> PrimQuery -> PrimQuery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lateral -> PrimQuery -> PrimQuery
query Lateral
lateral
  in
    ((PrimExpr -> Expr Int64
forall a. PrimExpr -> Expr a
fromPrimExpr PrimExpr
index, a
a), Lateral -> PrimQuery -> PrimQuery
query', Tag
tag'')