module Hasql.Encoders.Array where

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

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

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 -> TextBuilder
renderer) =
    OID
-> OID -> (Bool -> a' -> Array) -> (a' -> TextBuilder) -> Array a'
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> TextBuilder) -> 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 -> TextBuilder
renderer (a -> TextBuilder) -> (a' -> a) -> a' -> TextBuilder
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.TextBuilder) -> Array a
value :: forall a.
OID
-> OID -> (Bool -> a -> Encoding) -> (a -> TextBuilder) -> Array a
value OID
valueOID OID
arrayOID Bool -> a -> Encoding
encoder =
  OID -> OID -> (Bool -> a -> Array) -> (a -> TextBuilder) -> Array a
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> TextBuilder) -> 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.TextBuilder) -> Array (Maybe a)
nullableValue :: forall a.
OID
-> OID
-> (Bool -> a -> Encoding)
-> (a -> TextBuilder)
-> Array (Maybe a)
nullableValue OID
valueOID OID
arrayOID Bool -> a -> Encoding
encoder a -> TextBuilder
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 -> TextBuilder
maybeRenderer =
        TextBuilder -> (a -> TextBuilder) -> Maybe a -> TextBuilder
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> TextBuilder
C.string String
"null") a -> TextBuilder
renderer
   in OID
-> OID
-> (Bool -> Maybe a -> Array)
-> (Maybe a -> TextBuilder)
-> Array (Maybe a)
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> TextBuilder) -> Array a
Array OID
valueOID OID
arrayOID Bool -> Maybe a -> Array
maybeEncoder Maybe a -> TextBuilder
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 -> TextBuilder
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 -> TextBuilder
renderer c
els =
        let folded :: TextBuilder
folded =
              let step :: TextBuilder -> b -> TextBuilder
step TextBuilder
builder b
el =
                    if TextBuilder -> Bool
C.isEmpty TextBuilder
builder
                      then Char -> TextBuilder
C.char Char
'[' TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> b -> TextBuilder
elRenderer b
el
                      else TextBuilder
builder TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> String -> TextBuilder
C.string String
", " TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> b -> TextBuilder
elRenderer b
el
               in (TextBuilder -> b -> TextBuilder)
-> TextBuilder -> c -> TextBuilder
forall a. (a -> b -> a) -> a -> c -> a
fold TextBuilder -> b -> TextBuilder
step TextBuilder
forall a. Monoid a => a
mempty c
els
         in if TextBuilder -> Bool
C.isEmpty TextBuilder
folded
              then String -> TextBuilder
C.string String
"[]"
              else TextBuilder
folded TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> Char -> TextBuilder
C.char Char
']'
   in OID -> OID -> (Bool -> c -> Array) -> (c -> TextBuilder) -> Array c
forall a.
OID -> OID -> (Bool -> a -> Array) -> (a -> TextBuilder) -> Array a
Array OID
valueOID OID
arrayOID Bool -> c -> Array
encoder c -> TextBuilder
renderer