{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE OverloadedStrings #-}

module Rel8.Internal.Type.Range (
  DBRange (
    rangeTypeName, rangeDecoder, rangeEncoder,
    multirangeTypeName, multirangeDecoder, multirangeEncoder
  ),
) where

-- base
import Data.Int (Int32, Int64)

-- hasql
import qualified Hasql.Decoders as Decoder
import qualified Hasql.Encoders as Encoder

-- postgresql-binary
import qualified PostgreSQL.Binary.Range as PostgreSQL

-- rel8
import Rel8.Internal.Schema.QualifiedName (QualifiedName)
import Rel8.Internal.Type.Ord (DBOrd)

-- scientific
import Data.Scientific (Scientific)

-- time
import Data.Time.Calendar (Day)
import Data.Time.Clock (UTCTime)
import Data.Time.LocalTime (LocalTime)


class DBOrd a => DBRange a where
  rangeTypeName :: QualifiedName
  rangeDecoder :: Decoder.Value (PostgreSQL.Range a)
  rangeEncoder :: Encoder.Value (PostgreSQL.Range a)

  multirangeTypeName :: QualifiedName
  multirangeDecoder :: Decoder.Value (PostgreSQL.Multirange a)
  multirangeEncoder :: Encoder.Value (PostgreSQL.Multirange a)


instance DBRange Int32 where
  rangeTypeName :: QualifiedName
rangeTypeName = QualifiedName
"int4range"
  rangeDecoder :: Value (Range Int32)
rangeDecoder = Value (Range Int32)
Decoder.int4range
  rangeEncoder :: Value (Range Int32)
rangeEncoder = Value (Range Int32)
Encoder.int4range
  multirangeTypeName :: QualifiedName
multirangeTypeName = QualifiedName
"int4multirange"
  multirangeDecoder :: Value (Multirange Int32)
multirangeDecoder = Value (Multirange Int32)
Decoder.int4multirange
  multirangeEncoder :: Value (Multirange Int32)
multirangeEncoder = Value (Multirange Int32)
Encoder.int4multirange


instance DBRange Int64 where
  rangeTypeName :: QualifiedName
rangeTypeName = QualifiedName
"int8range"
  rangeDecoder :: Value (Range Int64)
rangeDecoder = Value (Range Int64)
Decoder.int8range
  rangeEncoder :: Value (Range Int64)
rangeEncoder = Value (Range Int64)
Encoder.int8range
  multirangeTypeName :: QualifiedName
multirangeTypeName = QualifiedName
"int8multirange"
  multirangeDecoder :: Value (Multirange Int64)
multirangeDecoder = Value (Multirange Int64)
Decoder.int8multirange
  multirangeEncoder :: Value (Multirange Int64)
multirangeEncoder = Value (Multirange Int64)
Encoder.int8multirange


instance DBRange Scientific where
  rangeTypeName :: QualifiedName
rangeTypeName = QualifiedName
"numrange"
  rangeDecoder :: Value (Range Scientific)
rangeDecoder = Value (Range Scientific)
Decoder.numrange
  rangeEncoder :: Value (Range Scientific)
rangeEncoder = Value (Range Scientific)
Encoder.numrange
  multirangeTypeName :: QualifiedName
multirangeTypeName = QualifiedName
"nummultirange"
  multirangeDecoder :: Value (Multirange Scientific)
multirangeDecoder = Value (Multirange Scientific)
Decoder.nummultirange
  multirangeEncoder :: Value (Multirange Scientific)
multirangeEncoder = Value (Multirange Scientific)
Encoder.nummultirange


instance DBRange LocalTime where
  rangeTypeName :: QualifiedName
rangeTypeName = QualifiedName
"tsrange"
  rangeDecoder :: Value (Range LocalTime)
rangeDecoder = Value (Range LocalTime)
Decoder.tsrange
  rangeEncoder :: Value (Range LocalTime)
rangeEncoder = Value (Range LocalTime)
Encoder.tsrange
  multirangeTypeName :: QualifiedName
multirangeTypeName = QualifiedName
"tsmultirange"
  multirangeDecoder :: Value (Multirange LocalTime)
multirangeDecoder = Value (Multirange LocalTime)
Decoder.tsmultirange
  multirangeEncoder :: Value (Multirange LocalTime)
multirangeEncoder = Value (Multirange LocalTime)
Encoder.tsmultirange


instance DBRange UTCTime where
  rangeTypeName :: QualifiedName
rangeTypeName = QualifiedName
"tstzrange"
  rangeDecoder :: Value (Range UTCTime)
rangeDecoder = Value (Range UTCTime)
Decoder.tstzrange
  rangeEncoder :: Value (Range UTCTime)
rangeEncoder = Value (Range UTCTime)
Encoder.tstzrange
  multirangeTypeName :: QualifiedName
multirangeTypeName = QualifiedName
"tstzmultirange"
  multirangeDecoder :: Value (Multirange UTCTime)
multirangeDecoder = Value (Multirange UTCTime)
Decoder.tstzmultirange
  multirangeEncoder :: Value (Multirange UTCTime)
multirangeEncoder = Value (Multirange UTCTime)
Encoder.tstzmultirange


instance DBRange Day where
  rangeTypeName :: QualifiedName
rangeTypeName = QualifiedName
"daterange"
  rangeDecoder :: Value (Range Day)
rangeDecoder = Value (Range Day)
Decoder.daterange
  rangeEncoder :: Value (Range Day)
rangeEncoder = Value (Range Day)
Encoder.daterange
  multirangeTypeName :: QualifiedName
multirangeTypeName = QualifiedName
"datemultirange"
  multirangeDecoder :: Value (Multirange Day)
multirangeDecoder = Value (Multirange Day)
Decoder.datemultirange
  multirangeEncoder :: Value (Multirange Day)
multirangeEncoder = Value (Multirange Day)
Encoder.datemultirange