module Sqel.Codec where import qualified Chronos as Chronos import Data.Time (Day, DiffTime, LocalTime, TimeOfDay, TimeZone, UTCTime) import Data.UUID (UUID) import qualified Hasql.Decoders as Hasql import qualified Hasql.Decoders as Decoders import Hasql.Decoders (Row, custom) import qualified Hasql.Encoders as Encoders import Hasql.Encoders (Params) import Path (Path) import qualified Sqel.Codec.PrimDecoder as PrimDecoder import Sqel.Codec.PrimDecoder (PrimDecoder) import qualified Sqel.Codec.PrimEncoder as PrimEncoder import Sqel.Codec.PrimEncoder (PrimEncoder) import Sqel.Codec.Sum (ignoreEncoder) import qualified Sqel.Data.Codec as Codec import Sqel.Data.Codec (Codec (Codec), Decoder (Decoder), Encoder (Encoder), FullCodec, ValueCodec) import Sqel.Data.PgType (PgPrimName) import Sqel.SOP.Error (Quoted, QuotedType) ignoreDecoder :: Row (Maybe a) ignoreDecoder :: forall a. Row (Maybe a) ignoreDecoder = forall (m :: * -> *) a. Monad m => m (m a) -> m a join forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> forall a. NullableOrNot Value a -> Row a Hasql.column (forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder (Maybe a) Hasql.nullable (forall a. (Bool -> ByteString -> Either Text a) -> Value a custom \ Bool _ ByteString _ -> forall (f :: * -> *) a. Applicative f => a -> f a pure forall a. Maybe a Nothing)) class ColumnEncoder f where columnEncoder :: f a -> Params a columnEncoderNullable :: f a -> Params (Maybe a) columnEncoderIgnore :: f a -> Params b instance ColumnEncoder Encoders.Value where columnEncoder :: forall a. Value a -> Params a columnEncoder = forall a. NullableOrNot Value a -> Params a Encoders.param forall b c a. (b -> c) -> (a -> b) -> a -> c . forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder a Encoders.nonNullable columnEncoderNullable :: forall a. Value a -> Params (Maybe a) columnEncoderNullable = forall a. NullableOrNot Value a -> Params a Encoders.param forall b c a. (b -> c) -> (a -> b) -> a -> c . forall (encoder :: * -> *) a. encoder a -> NullableOrNot encoder (Maybe a) Encoders.nullable columnEncoderIgnore :: forall a b. Value a -> Params b columnEncoderIgnore = forall a b. Value a -> Params b ignoreEncoder class ColumnDecoder f where columnDecoder :: f a -> Row a columnDecoderNullable :: f a -> Row (Maybe a) instance ColumnDecoder Decoders.Value where columnDecoder :: forall a. Value a -> Row a columnDecoder = forall a. NullableOrNot Value a -> Row a Decoders.column forall b c a. (b -> c) -> (a -> b) -> a -> c . forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder a Decoders.nonNullable columnDecoderNullable :: forall a. Value a -> Row (Maybe a) columnDecoderNullable = forall a. NullableOrNot Value a -> Row a Decoders.column forall b c a. (b -> c) -> (a -> b) -> a -> c . forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder (Maybe a) Decoders.nullable class PrimColumn a where primDecoder :: Decoders.Value a default primDecoder :: PrimDecoder a => Decoders.Value a primDecoder = forall a. PrimDecoder a => Value a PrimDecoder.primDecoder primEncoder :: Encoders.Value a default primEncoder :: PrimEncoder a => Encoders.Value a primEncoder = forall d. PrimEncoder d => Value d PrimEncoder.primEncoder pgType :: PgPrimName instance {-# overlappable #-} ( TypeError ( "A column of type " <> QuotedType a <> " was declared as primitive," % "but there is no instance of " <> Quoted "PrimColumn" <> " for that type." % "If it is a newtype, ensure that it has " <> Quoted "Generic" <> " and use " <> Quoted "primNewtype" <> "." ) ) => PrimColumn a where primDecoder :: Value a primDecoder = forall a. HasCallStack => [Char] -> a error [Char] "no instance for PrimColumn" primEncoder :: Value a primEncoder = forall a. HasCallStack => [Char] -> a error [Char] "no instance for PrimColumn" pgType :: PgPrimName pgType = forall a. HasCallStack => [Char] -> a error [Char] "no instance for PrimColumn" instance PrimColumn Bool where pgType :: PgPrimName pgType = PgPrimName "boolean" instance PrimColumn Int where pgType :: PgPrimName pgType = PgPrimName "bigint" instance PrimColumn Int64 where pgType :: PgPrimName pgType = PgPrimName "bigint" instance PrimColumn Double where pgType :: PgPrimName pgType = PgPrimName "double precision" instance PrimColumn Text where pgType :: PgPrimName pgType = PgPrimName "text" instance PrimColumn ByteString where pgType :: PgPrimName pgType = PgPrimName "bytes" instance PrimColumn UUID where pgType :: PgPrimName pgType = PgPrimName "uuid" instance PrimColumn Day where pgType :: PgPrimName pgType = PgPrimName "date" instance PrimColumn LocalTime where pgType :: PgPrimName pgType = PgPrimName "timestamp without time zone" instance PrimColumn UTCTime where pgType :: PgPrimName pgType = PgPrimName "timestamp with time zone" instance PrimColumn TimeOfDay where pgType :: PgPrimName pgType = PgPrimName "time without time zone" instance PrimColumn (TimeOfDay, TimeZone) where pgType :: PgPrimName pgType = PgPrimName "time with time zone" instance PrimColumn DiffTime where pgType :: PgPrimName pgType = PgPrimName "interval" instance PrimColumn Chronos.Date where pgType :: PgPrimName pgType = PgPrimName "date" instance PrimColumn Chronos.Time where pgType :: PgPrimName pgType = PgPrimName "bigint" instance PrimColumn Chronos.Datetime where pgType :: PgPrimName pgType = PgPrimName "timestamp without time zone" instance PrimDecoder (Path b t) => PrimColumn (Path b t) where pgType :: PgPrimName pgType = PgPrimName "text" instance PrimColumn () where pgType :: PgPrimName pgType = PgPrimName "boolean" fullPrimCodec :: Encoders.Value a -> Decoders.Value a -> FullCodec a fullPrimCodec :: forall a. Value a -> Value a -> FullCodec a fullPrimCodec Value a encoder Value a decoder = Codec { $sel:encoder:Codec :: Encoder a encoder = forall a. Params a -> Params () -> Encoder a Encoder (forall (f :: * -> *) a. ColumnEncoder f => f a -> Params a columnEncoder Value a encoder) (forall (f :: * -> *) a b. ColumnEncoder f => f a -> Params b columnEncoderIgnore Value a encoder), $sel:decoder:Codec :: Decoder a decoder = forall a. Row a -> Row () -> Decoder a Decoder (forall (f :: * -> *) a. ColumnDecoder f => f a -> Row a columnDecoder Value a decoder) (forall (f :: * -> *) a. Functor f => f a -> f () void forall a. Row (Maybe a) ignoreDecoder) } toFullPrimCodec :: ValueCodec a -> FullCodec a toFullPrimCodec :: forall a. ValueCodec a -> FullCodec a toFullPrimCodec (Codec Value a encoder Value a decoder) = forall a. Value a -> Value a -> FullCodec a fullPrimCodec Value a encoder Value a decoder