module Hasql.Engine.Decoders.Row where

import Hasql.Codecs.Decoders
import Hasql.Codecs.Decoders.Value qualified as Value
import Hasql.Codecs.RequestingOid qualified as RequestingOid
import Hasql.Comms.RowDecoder qualified
import Hasql.Platform.Prelude
import PostgreSQL.Binary.Decoding qualified as Binary

-- |
-- Decoder of an individual row,
-- which gets composed of column value decoders.
-- E.g.:
--
-- @
-- x :: 'Row' (Maybe Int64, Text, TimeOfDay)
-- x = (,,) '<$>' ('column' . 'nullable') 'int8' '<*>' ('column' . 'nonNullable') 'text' '<*>' ('column' . 'nonNullable') 'time'
-- @
newtype Row a
  = Row (RequestingOid.RequestingOid (Hasql.Comms.RowDecoder.RowDecoder a))
  deriving
    ((forall a b. (a -> b) -> Row a -> Row b)
-> (forall a b. a -> Row b -> Row a) -> Functor Row
forall a b. a -> Row b -> Row a
forall a b. (a -> b) -> Row a -> Row b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Row a -> Row b
fmap :: forall a b. (a -> b) -> Row a -> Row b
$c<$ :: forall a b. a -> Row b -> Row a
<$ :: forall a b. a -> Row b -> Row a
Functor, Functor Row
Functor Row =>
(forall a. a -> Row a)
-> (forall a b. Row (a -> b) -> Row a -> Row b)
-> (forall a b c. (a -> b -> c) -> Row a -> Row b -> Row c)
-> (forall a b. Row a -> Row b -> Row b)
-> (forall a b. Row a -> Row b -> Row a)
-> Applicative Row
forall a. a -> Row a
forall a b. Row a -> Row b -> Row a
forall a b. Row a -> Row b -> Row b
forall a b. Row (a -> b) -> Row a -> Row b
forall a b c. (a -> b -> c) -> Row a -> Row b -> Row c
forall (f :: * -> *).
Functor f =>
(forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
$cpure :: forall a. a -> Row a
pure :: forall a. a -> Row a
$c<*> :: forall a b. Row (a -> b) -> Row a -> Row b
<*> :: forall a b. Row (a -> b) -> Row a -> Row b
$cliftA2 :: forall a b c. (a -> b -> c) -> Row a -> Row b -> Row c
liftA2 :: forall a b c. (a -> b -> c) -> Row a -> Row b -> Row c
$c*> :: forall a b. Row a -> Row b -> Row b
*> :: forall a b. Row a -> Row b -> Row b
$c<* :: forall a b. Row a -> Row b -> Row a
<* :: forall a b. Row a -> Row b -> Row a
Applicative, Functor Row
Functor Row =>
(forall a b. (a -> Maybe b) -> Row a -> Row b)
-> (forall a. Row (Maybe a) -> Row a)
-> (forall a. (a -> Bool) -> Row a -> Row a)
-> (forall a b. Row a -> Row b)
-> Filterable Row
forall a. Row (Maybe a) -> Row a
forall a. (a -> Bool) -> Row a -> Row a
forall a b. Row a -> Row b
forall a b. (a -> Maybe b) -> Row a -> Row b
forall (f :: * -> *).
Functor f =>
(forall a b. (a -> Maybe b) -> f a -> f b)
-> (forall a. f (Maybe a) -> f a)
-> (forall a. (a -> Bool) -> f a -> f a)
-> (forall a b. f a -> f b)
-> Filterable f
$cmapMaybe :: forall a b. (a -> Maybe b) -> Row a -> Row b
mapMaybe :: forall a b. (a -> Maybe b) -> Row a -> Row b
$ccatMaybes :: forall a. Row (Maybe a) -> Row a
catMaybes :: forall a. Row (Maybe a) -> Row a
$cfilter :: forall a. (a -> Bool) -> Row a -> Row a
filter :: forall a. (a -> Bool) -> Row a -> Row a
$cdrain :: forall a b. Row a -> Row b
drain :: forall a b. Row a -> Row b
Filterable)
    via (Compose RequestingOid.RequestingOid Hasql.Comms.RowDecoder.RowDecoder)

toDecoder ::
  Row a ->
  RequestingOid.RequestingOid (Hasql.Comms.RowDecoder.RowDecoder a)
toDecoder :: forall a. Row a -> RequestingOid (RowDecoder a)
toDecoder (Row RequestingOid (RowDecoder a)
f) = RequestingOid (RowDecoder a)
f

-- |
-- Lift an individual value decoder to a composable row decoder.
{-# INLINEABLE column #-}
column :: NullableOrNot Value a -> Row a
column :: forall a. NullableOrNot Value a -> Row a
column = \case
  Nullable Value a1
valueDecoder ->
    RequestingOid (RowDecoder a) -> Row a
forall a. RequestingOid (RowDecoder a) -> Row a
Row case Value a1 -> Maybe Word32
forall a. Value a -> Maybe Word32
Value.toOid Value a1
valueDecoder of
      Just Word32
oid ->
        (Value a1 -> RowDecoder a)
-> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a1)
-> RequestingOid (RowDecoder a)
forall a b.
(a -> b)
-> LookingUp (Maybe Text, Text) (Word32, Word32) a
-> LookingUp (Maybe Text, Text) (Word32, Word32) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
          (Maybe Word32
-> (ByteString -> Either Text a1) -> RowDecoder (Maybe a1)
forall a.
Maybe Word32
-> (ByteString -> Either Text a) -> RowDecoder (Maybe a)
Hasql.Comms.RowDecoder.nullableColumn (Word32 -> Maybe Word32
forall a. a -> Maybe a
Just Word32
oid) ((ByteString -> Either Text a1) -> RowDecoder (Maybe a1))
-> (Value a1 -> ByteString -> Either Text a1)
-> Value a1
-> RowDecoder (Maybe a1)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Value a1 -> ByteString -> Either Text a1
forall a. Value a -> ByteString -> Either Text a
Binary.valueParser)
          (Value a1
-> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a1)
forall a. Value a -> RequestingOid (Value a)
Value.toDecoder Value a1
valueDecoder)
      Maybe Word32
Nothing -> do
        (Maybe Text, Text)
-> ((Word32, Word32) -> Value a1 -> RowDecoder a)
-> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a1)
-> RequestingOid (RowDecoder a)
forall a b.
(Maybe Text, Text)
-> ((Word32, Word32) -> a -> b)
-> RequestingOid a
-> RequestingOid b
RequestingOid.hoistLookingUp
          (Value a1 -> Maybe Text
forall a. Value a -> Maybe Text
Value.toSchema Value a1
valueDecoder, Value a1 -> Text
forall a. Value a -> Text
Value.toTypeName Value a1
valueDecoder)
          ( \(Word32, Word32)
lookupResult Value a1
decoder ->
              Maybe Word32
-> (ByteString -> Either Text a1) -> RowDecoder (Maybe a1)
forall a.
Maybe Word32
-> (ByteString -> Either Text a) -> RowDecoder (Maybe a)
Hasql.Comms.RowDecoder.nullableColumn (Word32 -> Maybe Word32
forall a. a -> Maybe a
Just (Value a1 -> (Word32, Word32) -> Word32
forall {a} {b}. Value a -> (b, b) -> b
chooseLookedUpOid Value a1
valueDecoder (Word32, Word32)
lookupResult)) (Value a1 -> ByteString -> Either Text a1
forall a. Value a -> ByteString -> Either Text a
Binary.valueParser Value a1
decoder)
          )
          (Value a1
-> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a1)
forall a. Value a -> RequestingOid (Value a)
Value.toDecoder Value a1
valueDecoder)
  NonNullable Value a
valueDecoder ->
    RequestingOid (RowDecoder a) -> Row a
forall a. RequestingOid (RowDecoder a) -> Row a
Row case Value a -> Maybe Word32
forall a. Value a -> Maybe Word32
Value.toOid Value a
valueDecoder of
      Just Word32
oid ->
        (Value a -> RowDecoder a)
-> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a)
-> RequestingOid (RowDecoder a)
forall a b.
(a -> b)
-> LookingUp (Maybe Text, Text) (Word32, Word32) a
-> LookingUp (Maybe Text, Text) (Word32, Word32) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
          (Maybe Word32 -> (ByteString -> Either Text a) -> RowDecoder a
forall a.
Maybe Word32 -> (ByteString -> Either Text a) -> RowDecoder a
Hasql.Comms.RowDecoder.nonNullableColumn (Word32 -> Maybe Word32
forall a. a -> Maybe a
Just Word32
oid) ((ByteString -> Either Text a) -> RowDecoder a)
-> (Value a -> ByteString -> Either Text a)
-> Value a
-> RowDecoder a
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Value a -> ByteString -> Either Text a
forall a. Value a -> ByteString -> Either Text a
Binary.valueParser)
          (Value a -> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a)
forall a. Value a -> RequestingOid (Value a)
Value.toDecoder Value a
valueDecoder)
      Maybe Word32
Nothing -> do
        (Maybe Text, Text)
-> ((Word32, Word32) -> Value a -> RowDecoder a)
-> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a)
-> RequestingOid (RowDecoder a)
forall a b.
(Maybe Text, Text)
-> ((Word32, Word32) -> a -> b)
-> RequestingOid a
-> RequestingOid b
RequestingOid.hoistLookingUp
          (Value a -> Maybe Text
forall a. Value a -> Maybe Text
Value.toSchema Value a
valueDecoder, Value a -> Text
forall a. Value a -> Text
Value.toTypeName Value a
valueDecoder)
          (\(Word32, Word32)
lookupResult Value a
decoder -> Maybe Word32 -> (ByteString -> Either Text a) -> RowDecoder a
forall a.
Maybe Word32 -> (ByteString -> Either Text a) -> RowDecoder a
Hasql.Comms.RowDecoder.nonNullableColumn (Word32 -> Maybe Word32
forall a. a -> Maybe a
Just (Value a -> (Word32, Word32) -> Word32
forall {a} {b}. Value a -> (b, b) -> b
chooseLookedUpOid Value a
valueDecoder (Word32, Word32)
lookupResult)) (Value a -> ByteString -> Either Text a
forall a. Value a -> ByteString -> Either Text a
Binary.valueParser Value a
decoder))
          (Value a -> LookingUp (Maybe Text, Text) (Word32, Word32) (Value a)
forall a. Value a -> RequestingOid (Value a)
Value.toDecoder Value a
valueDecoder)
  where
    chooseLookedUpOid :: Value a -> (b, b) -> b
chooseLookedUpOid Value a
valueDecoder (b
elementOid, b
arrayOid) =
      if Value a -> Word
forall a. Value a -> Word
Value.toDimensionality Value a
valueDecoder Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
> Word
0
        then b
arrayOid
        else b
elementOid