module Hasql.Encoders.Array where

import Hasql.PostgresTypeInfo qualified as B
import Hasql.Prelude
import PostgreSQL.Binary.Encoding qualified as A
import Text.Builder qualified as C

data Array a
  = Array B.OID B.OID (Bool -> a -> A.Array) (a -> C.Builder)

instance Contravariant Array where
  contramap :: forall a' a. (a' -> a) -> Array a -> Array a'
contramap a' -> a
fn (Array OID
valueOid OID
arrayOid Bool -> a -> Array
encoder a -> Builder
renderer) =
    OID -> OID -> (Bool -> a' -> Array) -> (a' -> Builder) -> Array a'
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> Builder) -> Array a
Array OID
valueOid OID
arrayOid (\Bool
intDateTimes -> Bool -> a -> Array
encoder Bool
intDateTimes (a -> Array) -> (a' -> a) -> a' -> Array
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
. a' -> a
fn) (a -> Builder
renderer (a -> Builder) -> (a' -> a) -> a' -> Builder
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
. a' -> a
fn)

{-# INLINE value #-}
value :: B.OID -> B.OID -> (Bool -> a -> A.Encoding) -> (a -> C.Builder) -> Array a
value :: forall a.
OID -> OID -> (Bool -> a -> Encoding) -> (a -> Builder) -> Array a
value OID
valueOID OID
arrayOID Bool -> a -> Encoding
encoder =
  OID -> OID -> (Bool -> a -> Array) -> (a -> Builder) -> Array a
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> Builder) -> Array a
Array OID
valueOID OID
arrayOID (\Bool
params -> Encoding -> Array
A.encodingArray (Encoding -> Array) -> (a -> Encoding) -> a -> Array
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
. Bool -> a -> Encoding
encoder Bool
params)

{-# INLINE nullableValue #-}
nullableValue :: B.OID -> B.OID -> (Bool -> a -> A.Encoding) -> (a -> C.Builder) -> Array (Maybe a)
nullableValue :: forall a.
OID
-> OID
-> (Bool -> a -> Encoding)
-> (a -> Builder)
-> Array (Maybe a)
nullableValue OID
valueOID OID
arrayOID Bool -> a -> Encoding
encoder a -> Builder
renderer =
  let maybeEncoder :: Bool -> Maybe a -> Array
maybeEncoder Bool
params =
        Array -> (a -> Array) -> Maybe a -> Array
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Array
A.nullArray (Encoding -> Array
A.encodingArray (Encoding -> Array) -> (a -> Encoding) -> a -> Array
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
. Bool -> a -> Encoding
encoder Bool
params)
      maybeRenderer :: Maybe a -> Builder
maybeRenderer =
        Builder -> (a -> Builder) -> Maybe a -> Builder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Builder
C.string String
"null") a -> Builder
renderer
   in OID
-> OID
-> (Bool -> Maybe a -> Array)
-> (Maybe a -> Builder)
-> Array (Maybe a)
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> Builder) -> Array a
Array OID
valueOID OID
arrayOID Bool -> Maybe a -> Array
maybeEncoder Maybe a -> Builder
maybeRenderer

{-# INLINE dimension #-}
dimension :: (forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c
dimension :: forall b c.
(forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c
dimension forall a. (a -> b -> a) -> a -> c -> a
fold (Array OID
valueOID OID
arrayOID Bool -> b -> Array
elEncoder b -> Builder
elRenderer) =
  let encoder :: Bool -> c -> Array
encoder Bool
el =
        (forall a. (a -> b -> a) -> a -> c -> a)
-> (b -> Array) -> c -> Array
forall a c.
(forall b. (b -> a -> b) -> b -> c -> b)
-> (a -> Array) -> c -> Array
A.dimensionArray (b -> b -> b) -> b -> c -> b
forall a. (a -> b -> a) -> a -> c -> a
fold (Bool -> b -> Array
elEncoder Bool
el)
      renderer :: c -> Builder
renderer c
els =
        let folded :: Builder
folded =
              let step :: Builder -> b -> Builder
step Builder
builder b
el =
                    if Builder -> Bool
C.null Builder
builder
                      then Char -> Builder
C.char Char
'[' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> b -> Builder
elRenderer b
el
                      else Builder
builder Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> String -> Builder
C.string String
", " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> b -> Builder
elRenderer b
el
               in (Builder -> b -> Builder) -> Builder -> c -> Builder
forall a. (a -> b -> a) -> a -> c -> a
fold Builder -> b -> Builder
step Builder
forall a. Monoid a => a
mempty c
els
         in if Builder -> Bool
C.null Builder
folded
              then String -> Builder
C.string String
"[]"
              else Builder
folded Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
C.char Char
']'
   in OID -> OID -> (Bool -> c -> Array) -> (c -> Builder) -> Array c
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> Builder) -> Array a
Array OID
valueOID OID
arrayOID Bool -> c -> Array
encoder c -> Builder
renderer