module Sqel.Codec.PrimEncoder where

import qualified Chronos as Chronos
import Data.Scientific (Scientific)
import Data.Time (Day (ModifiedJulianDay), DiffTime, LocalTime (LocalTime), TimeOfDay (TimeOfDay), TimeZone, UTCTime)
import Data.UUID (UUID)
import Hasql.Encoders (
  Value,
  array,
  bool,
  bytea,
  char,
  date,
  dimension,
  element,
  float4,
  float8,
  int2,
  int4,
  int8,
  interval,
  nonNullable,
  numeric,
  text,
  time,
  timestamp,
  timestamptz,
  timetz,
  uuid,
  )
import Path (Path, toFilePath)
import Prelude hiding (bool)

class PrimEncoder d where
  primEncoder :: Value d

instance PrimEncoder () where
  primEncoder :: Value ()
primEncoder =
    Bool
True forall (f :: * -> *) b a. Contravariant f => b -> f b -> f a
>$ Value Bool
bool

instance PrimEncoder Bool where
  primEncoder :: Value Bool
primEncoder =
    Value Bool
bool

instance PrimEncoder Int16 where
  primEncoder :: Value Int16
primEncoder =
    Value Int16
int2

instance PrimEncoder Int32 where
  primEncoder :: Value Int32
primEncoder =
    Value Int32
int4

instance PrimEncoder Int64 where
  primEncoder :: Value Int64
primEncoder =
    Value Int64
int8

instance PrimEncoder Int where
  primEncoder :: Value Int
primEncoder =
    forall (f :: * -> *) a' a.
Contravariant f =>
(a' -> a) -> f a -> f a'
contramap forall a b. (Integral a, Num b) => a -> b
fromIntegral Value Int64
int8

instance PrimEncoder Float where
  primEncoder :: Value Float
primEncoder =
    Value Float
float4

instance PrimEncoder Double where
  primEncoder :: Value Double
primEncoder =
    Value Double
float8

instance PrimEncoder Scientific where
  primEncoder :: Value Scientific
primEncoder =
    Value Scientific
numeric

instance PrimEncoder Char where
  primEncoder :: Value Char
primEncoder =
    Value Char
char

instance PrimEncoder Text where
  primEncoder :: Value Text
primEncoder =
    Value Text
text

instance PrimEncoder ByteString where
  primEncoder :: Value ByteString
primEncoder =
    Value ByteString
bytea

instance PrimEncoder Day where
  primEncoder :: Value Day
primEncoder =
    Value Day
date

instance PrimEncoder LocalTime where
  primEncoder :: Value LocalTime
primEncoder =
    Value LocalTime
timestamp

instance PrimEncoder UTCTime where
  primEncoder :: Value UTCTime
primEncoder =
    Value UTCTime
timestamptz

instance PrimEncoder TimeOfDay where
  primEncoder :: Value TimeOfDay
primEncoder =
    Value TimeOfDay
time

instance PrimEncoder (TimeOfDay, TimeZone) where
  primEncoder :: Value (TimeOfDay, TimeZone)
primEncoder =
    Value (TimeOfDay, TimeZone)
timetz

instance PrimEncoder DiffTime where
  primEncoder :: Value DiffTime
primEncoder =
    Value DiffTime
interval

instance PrimEncoder UUID where
  primEncoder :: Value UUID
primEncoder =
    Value UUID
uuid

instance PrimEncoder (Path b t) where
  primEncoder :: Value (Path b t)
primEncoder =
    (forall a. ToText a => a -> Text
toText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b t. Path b t -> FilePath
toFilePath) forall (f :: * -> *) a b. Contravariant f => (a -> b) -> f b -> f a
>$< Value Text
text

chronosToDay :: Chronos.Date -> Day
chronosToDay :: Date -> Day
chronosToDay =
  Integer -> Day
ModifiedJulianDay forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Day -> Int
Chronos.getDay forall b c a. (b -> c) -> (a -> b) -> a -> c
. Date -> Day
Chronos.dateToDay

instance PrimEncoder Chronos.Date where
  primEncoder :: Value Date
primEncoder =
    Date -> Day
chronosToDay forall (f :: * -> *) a b. Contravariant f => (a -> b) -> f b -> f a
>$< Value Day
date

instance PrimEncoder Chronos.Time where
  primEncoder :: Value Time
primEncoder =
    Time -> Int64
Chronos.getTime forall (f :: * -> *) a b. Contravariant f => (a -> b) -> f b -> f a
>$< Value Int64
int8

chronosToTimeOfDay :: Chronos.TimeOfDay -> TimeOfDay
chronosToTimeOfDay :: TimeOfDay -> TimeOfDay
chronosToTimeOfDay (Chronos.TimeOfDay Int
h Int
m Int64
ns) =
  Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
h Int
m (forall a. a -> Maybe a -> a
fromMaybe Pico
0 (forall a b. (Real a, Fractional b) => a -> b
realToFrac Int64
ns forall a. (Eq a, Fractional a) => a -> a -> Maybe a
/ Pico
1000000000))

datetimeToLocalTime :: Chronos.Datetime -> LocalTime
datetimeToLocalTime :: Datetime -> LocalTime
datetimeToLocalTime (Chronos.Datetime Date
d TimeOfDay
t) =
  Day -> TimeOfDay -> LocalTime
LocalTime (Date -> Day
chronosToDay Date
d) (TimeOfDay -> TimeOfDay
chronosToTimeOfDay TimeOfDay
t)

instance PrimEncoder Chronos.Datetime where
  primEncoder :: Value Datetime
primEncoder =
     Datetime -> LocalTime
datetimeToLocalTime forall (f :: * -> *) a b. Contravariant f => (a -> b) -> f b -> f a
>$< forall d. PrimEncoder d => Value d
primEncoder

arrayEncoder ::
  Foldable f =>
  Value a ->
  Value (f a)
arrayEncoder :: forall (f :: * -> *) a. Foldable f => Value a -> Value (f a)
arrayEncoder =
  forall a. Array a -> Value a
array forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  forall b c.
(forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c
dimension forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  forall a. NullableOrNot Value a -> Array a
element forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder a
nonNullable