module ClickHaskell.Columns where

-- Internal
import ClickHaskell.Primitive

-- GHC included
import Data.Binary.Get
import Data.ByteString.Builder
import Data.ByteString.Char8 as BS8 (pack)
import Data.Traversable (forM)
import Data.Int
import Data.Kind
import Data.Coerce
import Data.Typeable (Proxy (..))
import Data.Bits (Bits ((.&.)))
import GHC.TypeLits (ErrorMessage (..), KnownSymbol, Symbol, TypeError, symbolVal)

-- External
import Data.WideWord (Int128 (..))

-- * Column

data Columns (columns :: [Type]) where
  Empty :: Columns '[]
  AddColumn
    :: KnownColumn (Column name chType)
    => Column name chType
    -> Columns columns
    -> Columns (Column name chType ': columns)


{- |
Column declaration

For example:

@
type MyColumn = Column "myColumn" ChString
@
-}
data Column (name :: Symbol) (chType :: Type) where
  UInt8Column   :: [UInt8]   -> Column name UInt8
  Int8Column   :: [Int8]   -> Column name Int8
  UInt16Column  :: [UInt16]  -> Column name UInt16
  Int16Column  :: [Int16]  -> Column name Int16
  UInt32Column  :: [UInt32]  -> Column name UInt32
  Int32Column  :: [Int32]  -> Column name Int32
  UInt64Column  :: [UInt64]  -> Column name UInt64
  Int64Column  :: [Int64]  -> Column name Int64
  UInt128Column :: [UInt128] -> Column name UInt128
  Int128Column :: [Int128] -> Column name Int128
  UInt256Column :: [UInt256] -> Column name UInt256
  DateTimeColumn :: [DateTime tz] -> Column name (DateTime tz)
  DateTime64Column :: [DateTime64 precision tz] -> Column name (DateTime64 precision tz)
  DateColumn :: [Date] -> Column name Date
  UUIDColumn :: [UUID] -> Column name UUID
  StringColumn :: [ChString] -> Column name ChString
  ArrayColumn :: [Array chType] -> Column name (Array chType)
  NullableColumn :: [Nullable chType] -> Column name (Nullable chType)
  LowCardinalityColumn :: [chType] -> Column name (LowCardinality chType)

type family GetColumnName column :: Symbol where GetColumnName (Column name columnType) = name
type family GetColumnType column :: Type   where GetColumnType (Column name columnType) = columnType


class
  ( IsChType (GetColumnType column)
  , KnownSymbol (GetColumnName column)
  ) =>
  KnownColumn column where
  renderColumnName :: Builder
  renderColumnName = (String -> Builder
stringUtf8 (String -> Builder)
-> (Proxy (GetColumnName column) -> String)
-> Proxy (GetColumnName column)
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal @(GetColumnName column)) Proxy (GetColumnName column)
forall {k} (t :: k). Proxy t
Proxy

  renderColumnType :: Builder
  renderColumnType = StrictByteString -> Builder
byteString (StrictByteString -> Builder)
-> (String -> StrictByteString) -> String -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> StrictByteString
BS8.pack (String -> Builder) -> String -> Builder
forall a b. (a -> b) -> a -> b
$ forall chType. IsChType chType => String
chTypeName @(GetColumnType column)

  toColumn :: [GetColumnType column] -> Column (GetColumnName column) (GetColumnType column)
  fromColumn :: Column (GetColumnName column) (GetColumnType column) -> [GetColumnType column]

instance KnownSymbol name => KnownColumn (Column name UInt8) where
  toColumn :: [GetColumnType (Column name UInt8)]
-> Column
     (GetColumnName (Column name UInt8))
     (GetColumnType (Column name UInt8))
toColumn = [UInt8] -> Column name UInt8
[GetColumnType (Column name UInt8)]
-> Column
     (GetColumnName (Column name UInt8))
     (GetColumnType (Column name UInt8))
forall (name :: Symbol). [UInt8] -> Column name UInt8
UInt8Column
  fromColumn :: Column
  (GetColumnName (Column name UInt8))
  (GetColumnType (Column name UInt8))
-> [GetColumnType (Column name UInt8)]
fromColumn (UInt8Column [UInt8]
values) = [UInt8]
[GetColumnType (Column name UInt8)]
values

instance KnownSymbol name => KnownColumn (Column name UInt16) where
  toColumn :: [GetColumnType (Column name UInt16)]
-> Column
     (GetColumnName (Column name UInt16))
     (GetColumnType (Column name UInt16))
toColumn = [UInt16] -> Column name UInt16
[GetColumnType (Column name UInt16)]
-> Column
     (GetColumnName (Column name UInt16))
     (GetColumnType (Column name UInt16))
forall (name :: Symbol). [UInt16] -> Column name UInt16
UInt16Column
  fromColumn :: Column
  (GetColumnName (Column name UInt16))
  (GetColumnType (Column name UInt16))
-> [GetColumnType (Column name UInt16)]
fromColumn (UInt16Column [UInt16]
values) = [UInt16]
[GetColumnType (Column name UInt16)]
values

instance KnownSymbol name => KnownColumn (Column name UInt32) where
  toColumn :: [GetColumnType (Column name UInt32)]
-> Column
     (GetColumnName (Column name UInt32))
     (GetColumnType (Column name UInt32))
toColumn = [UInt32] -> Column name UInt32
[GetColumnType (Column name UInt32)]
-> Column
     (GetColumnName (Column name UInt32))
     (GetColumnType (Column name UInt32))
forall (name :: Symbol). [UInt32] -> Column name UInt32
UInt32Column
  fromColumn :: Column
  (GetColumnName (Column name UInt32))
  (GetColumnType (Column name UInt32))
-> [GetColumnType (Column name UInt32)]
fromColumn (UInt32Column [UInt32]
values) = [UInt32]
[GetColumnType (Column name UInt32)]
values

instance KnownSymbol name => KnownColumn (Column name UInt64) where
  toColumn :: [GetColumnType (Column name UInt64)]
-> Column
     (GetColumnName (Column name UInt64))
     (GetColumnType (Column name UInt64))
toColumn = [UInt64] -> Column name UInt64
[GetColumnType (Column name UInt64)]
-> Column
     (GetColumnName (Column name UInt64))
     (GetColumnType (Column name UInt64))
forall (name :: Symbol). [UInt64] -> Column name UInt64
UInt64Column
  fromColumn :: Column
  (GetColumnName (Column name UInt64))
  (GetColumnType (Column name UInt64))
-> [GetColumnType (Column name UInt64)]
fromColumn (UInt64Column [UInt64]
values) = [UInt64]
[GetColumnType (Column name UInt64)]
values

instance KnownSymbol name => KnownColumn (Column name UInt128) where
  toColumn :: [GetColumnType (Column name UInt128)]
-> Column
     (GetColumnName (Column name UInt128))
     (GetColumnType (Column name UInt128))
toColumn = [UInt128] -> Column name UInt128
[GetColumnType (Column name UInt128)]
-> Column
     (GetColumnName (Column name UInt128))
     (GetColumnType (Column name UInt128))
forall (name :: Symbol). [UInt128] -> Column name UInt128
UInt128Column
  fromColumn :: Column
  (GetColumnName (Column name UInt128))
  (GetColumnType (Column name UInt128))
-> [GetColumnType (Column name UInt128)]
fromColumn (UInt128Column [UInt128]
values) = [UInt128]
[GetColumnType (Column name UInt128)]
values

instance KnownSymbol name => KnownColumn (Column name UInt256) where
  toColumn :: [GetColumnType (Column name UInt256)]
-> Column
     (GetColumnName (Column name UInt256))
     (GetColumnType (Column name UInt256))
toColumn = [UInt256] -> Column name UInt256
[GetColumnType (Column name UInt256)]
-> Column
     (GetColumnName (Column name UInt256))
     (GetColumnType (Column name UInt256))
forall (name :: Symbol). [UInt256] -> Column name UInt256
UInt256Column
  fromColumn :: Column
  (GetColumnName (Column name UInt256))
  (GetColumnType (Column name UInt256))
-> [GetColumnType (Column name UInt256)]
fromColumn (UInt256Column [UInt256]
values) = [UInt256]
[GetColumnType (Column name UInt256)]
values

instance KnownSymbol name => KnownColumn (Column name Int8)  where
  toColumn :: [GetColumnType (Column name Int8)]
-> Column
     (GetColumnName (Column name Int8))
     (GetColumnType (Column name Int8))
toColumn = [Int8] -> Column name Int8
[GetColumnType (Column name Int8)]
-> Column
     (GetColumnName (Column name Int8))
     (GetColumnType (Column name Int8))
forall (name :: Symbol). [Int8] -> Column name Int8
Int8Column
  fromColumn :: Column
  (GetColumnName (Column name Int8))
  (GetColumnType (Column name Int8))
-> [GetColumnType (Column name Int8)]
fromColumn (Int8Column [Int8]
values) = [Int8]
[GetColumnType (Column name Int8)]
values

instance KnownSymbol name => KnownColumn (Column name Int16) where
  toColumn :: [GetColumnType (Column name Int16)]
-> Column
     (GetColumnName (Column name Int16))
     (GetColumnType (Column name Int16))
toColumn = [Int16] -> Column name Int16
[GetColumnType (Column name Int16)]
-> Column
     (GetColumnName (Column name Int16))
     (GetColumnType (Column name Int16))
forall (name :: Symbol). [Int16] -> Column name Int16
Int16Column
  fromColumn :: Column
  (GetColumnName (Column name Int16))
  (GetColumnType (Column name Int16))
-> [GetColumnType (Column name Int16)]
fromColumn (Int16Column [Int16]
values) = [Int16]
[GetColumnType (Column name Int16)]
values

instance KnownSymbol name => KnownColumn (Column name Int32) where
  toColumn :: [GetColumnType (Column name Int32)]
-> Column
     (GetColumnName (Column name Int32))
     (GetColumnType (Column name Int32))
toColumn = [Int32] -> Column name Int32
[GetColumnType (Column name Int32)]
-> Column
     (GetColumnName (Column name Int32))
     (GetColumnType (Column name Int32))
forall (name :: Symbol). [Int32] -> Column name Int32
Int32Column
  fromColumn :: Column
  (GetColumnName (Column name Int32))
  (GetColumnType (Column name Int32))
-> [GetColumnType (Column name Int32)]
fromColumn (Int32Column [Int32]
values) = [Int32]
[GetColumnType (Column name Int32)]
values

instance KnownSymbol name => KnownColumn (Column name Int64) where
  toColumn :: [GetColumnType (Column name Int64)]
-> Column
     (GetColumnName (Column name Int64))
     (GetColumnType (Column name Int64))
toColumn = [Int64] -> Column name Int64
[GetColumnType (Column name Int64)]
-> Column
     (GetColumnName (Column name Int64))
     (GetColumnType (Column name Int64))
forall (name :: Symbol). [Int64] -> Column name Int64
Int64Column
  fromColumn :: Column
  (GetColumnName (Column name Int64))
  (GetColumnType (Column name Int64))
-> [GetColumnType (Column name Int64)]
fromColumn (Int64Column [Int64]
values) = [Int64]
[GetColumnType (Column name Int64)]
values

instance KnownSymbol name => KnownColumn (Column name Int128) where
  toColumn :: [GetColumnType (Column name Int128)]
-> Column
     (GetColumnName (Column name Int128))
     (GetColumnType (Column name Int128))
toColumn = [Int128] -> Column name Int128
[GetColumnType (Column name Int128)]
-> Column
     (GetColumnName (Column name Int128))
     (GetColumnType (Column name Int128))
forall (name :: Symbol). [Int128] -> Column name Int128
Int128Column
  fromColumn :: Column
  (GetColumnName (Column name Int128))
  (GetColumnType (Column name Int128))
-> [GetColumnType (Column name Int128)]
fromColumn (Int128Column [Int128]
values) = [Int128]
[GetColumnType (Column name Int128)]
values

instance KnownSymbol name => KnownColumn (Column name Date) where
  toColumn :: [GetColumnType (Column name Date)]
-> Column
     (GetColumnName (Column name Date))
     (GetColumnType (Column name Date))
toColumn = [Date] -> Column name Date
[GetColumnType (Column name Date)]
-> Column
     (GetColumnName (Column name Date))
     (GetColumnType (Column name Date))
forall (name :: Symbol). [Date] -> Column name Date
DateColumn
  fromColumn :: Column
  (GetColumnName (Column name Date))
  (GetColumnType (Column name Date))
-> [GetColumnType (Column name Date)]
fromColumn (DateColumn [Date]
values) = [Date]
[GetColumnType (Column name Date)]
values

instance
  ( KnownSymbol name
  , IsChType (DateTime tz)
  ) =>
  KnownColumn (Column name (DateTime tz))
  where
  toColumn :: [GetColumnType (Column name (DateTime tz))]
-> Column
     (GetColumnName (Column name (DateTime tz)))
     (GetColumnType (Column name (DateTime tz)))
toColumn = [DateTime tz] -> Column name (DateTime tz)
[GetColumnType (Column name (DateTime tz))]
-> Column
     (GetColumnName (Column name (DateTime tz)))
     (GetColumnType (Column name (DateTime tz)))
forall (chType :: Symbol) (name :: Symbol).
[DateTime chType] -> Column name (DateTime chType)
DateTimeColumn
  fromColumn :: Column
  (GetColumnName (Column name (DateTime tz)))
  (GetColumnType (Column name (DateTime tz)))
-> [GetColumnType (Column name (DateTime tz))]
fromColumn (DateTimeColumn [DateTime tz]
values) = [DateTime tz]
[GetColumnType (Column name (DateTime tz))]
values

instance
  ( KnownSymbol name
  , IsChType (DateTime64 precision tz)
  ) =>
  KnownColumn (Column name (DateTime64 precision tz))
  where
  toColumn :: [GetColumnType (Column name (DateTime64 precision tz))]
-> Column
     (GetColumnName (Column name (DateTime64 precision tz)))
     (GetColumnType (Column name (DateTime64 precision tz)))
toColumn = [DateTime64 precision tz] -> Column name (DateTime64 precision tz)
[GetColumnType (Column name (DateTime64 precision tz))]
-> Column
     (GetColumnName (Column name (DateTime64 precision tz)))
     (GetColumnType (Column name (DateTime64 precision tz)))
forall (chType :: Nat) (tz :: Symbol) (name :: Symbol).
[DateTime64 chType tz] -> Column name (DateTime64 chType tz)
DateTime64Column
  fromColumn :: Column
  (GetColumnName (Column name (DateTime64 precision tz)))
  (GetColumnType (Column name (DateTime64 precision tz)))
-> [GetColumnType (Column name (DateTime64 precision tz))]
fromColumn (DateTime64Column [DateTime64 precision tz]
values) = [DateTime64 precision tz]
[GetColumnType (Column name (DateTime64 precision tz))]
values

instance KnownSymbol name => KnownColumn (Column name UUID) where
  toColumn :: [GetColumnType (Column name UUID)]
-> Column
     (GetColumnName (Column name UUID))
     (GetColumnType (Column name UUID))
toColumn = [UUID] -> Column name UUID
[GetColumnType (Column name UUID)]
-> Column
     (GetColumnName (Column name UUID))
     (GetColumnType (Column name UUID))
forall (name :: Symbol). [UUID] -> Column name UUID
UUIDColumn
  fromColumn :: Column
  (GetColumnName (Column name UUID))
  (GetColumnType (Column name UUID))
-> [GetColumnType (Column name UUID)]
fromColumn (UUIDColumn [UUID]
values) = [UUID]
[GetColumnType (Column name UUID)]
values

instance
  ( KnownSymbol name
  , IsChType chType
  , IsChType (Nullable chType)
  ) =>
  KnownColumn (Column name (Nullable chType))
  where
  toColumn :: [GetColumnType (Column name (Nullable chType))]
-> Column
     (GetColumnName (Column name (Nullable chType)))
     (GetColumnType (Column name (Nullable chType)))
toColumn = [Nullable chType] -> Column name (Nullable chType)
[GetColumnType (Column name (Nullable chType))]
-> Column
     (GetColumnName (Column name (Nullable chType)))
     (GetColumnType (Column name (Nullable chType)))
forall chType (name :: Symbol).
[Nullable chType] -> Column name (Nullable chType)
NullableColumn
  fromColumn :: Column
  (GetColumnName (Column name (Nullable chType)))
  (GetColumnType (Column name (Nullable chType)))
-> [GetColumnType (Column name (Nullable chType))]
fromColumn (NullableColumn [Maybe chType]
values)  = [Maybe chType]
[GetColumnType (Column name (Nullable chType))]
values

instance KnownSymbol name => KnownColumn (Column name ChString) where
  toColumn :: [GetColumnType (Column name ChString)]
-> Column
     (GetColumnName (Column name ChString))
     (GetColumnType (Column name ChString))
toColumn = [ChString] -> Column name ChString
[GetColumnType (Column name ChString)]
-> Column
     (GetColumnName (Column name ChString))
     (GetColumnType (Column name ChString))
forall (name :: Symbol). [ChString] -> Column name ChString
StringColumn
  fromColumn :: Column
  (GetColumnName (Column name ChString))
  (GetColumnType (Column name ChString))
-> [GetColumnType (Column name ChString)]
fromColumn (StringColumn [ChString]
values) = [ChString]
[GetColumnType (Column name ChString)]
values

instance
  ( KnownSymbol name
  , IsChType (LowCardinality chType)
  , IsLowCardinalitySupported chType
  ) =>
  KnownColumn (Column name (LowCardinality chType))
  where
  toColumn :: [GetColumnType (Column name (LowCardinality chType))]
-> Column
     (GetColumnName (Column name (LowCardinality chType)))
     (GetColumnType (Column name (LowCardinality chType)))
toColumn = [chType] -> Column name (LowCardinality chType)
forall chType (name :: Symbol).
[chType] -> Column name (LowCardinality chType)
LowCardinalityColumn ([chType] -> Column name (LowCardinality chType))
-> ([LowCardinality chType] -> [chType])
-> [LowCardinality chType]
-> Column name (LowCardinality chType)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (LowCardinality chType -> chType)
-> [LowCardinality chType] -> [chType]
forall a b. (a -> b) -> [a] -> [b]
map LowCardinality chType -> chType
forall a b. Coercible a b => a -> b
coerce
  fromColumn :: Column
  (GetColumnName (Column name (LowCardinality chType)))
  (GetColumnType (Column name (LowCardinality chType)))
-> [GetColumnType (Column name (LowCardinality chType))]
fromColumn (LowCardinalityColumn [chType]
values) = (chType -> LowCardinality chType)
-> [chType] -> [LowCardinality chType]
forall a b. (a -> b) -> [a] -> [b]
map chType -> LowCardinality chType
forall a b. Coercible a b => a -> b
coerce [chType]
values

instance KnownSymbol name => KnownColumn (Column name (Array ChString)) where
  toColumn :: [GetColumnType (Column name (Array ChString))]
-> Column
     (GetColumnName (Column name (Array ChString)))
     (GetColumnType (Column name (Array ChString)))
toColumn = [Array ChString] -> Column name (Array ChString)
[GetColumnType (Column name (Array ChString))]
-> Column
     (GetColumnName (Column name (Array ChString)))
     (GetColumnType (Column name (Array ChString)))
forall chType (name :: Symbol).
[Array chType] -> Column name (Array chType)
ArrayColumn
  fromColumn :: Column
  (GetColumnName (Column name (Array ChString)))
  (GetColumnType (Column name (Array ChString)))
-> [GetColumnType (Column name (Array ChString))]
fromColumn (ArrayColumn [Array chType]
values) = [Array chType]
[GetColumnType (Column name (Array ChString))]
values


class KnownColumn column => SerializableColumn column where
  deserializeColumn :: ProtocolRevision -> UVarInt -> (GetColumnType column -> a) -> Get [a]
  serializeColumn :: ProtocolRevision -> (a -> GetColumnType column) -> [a] -> Builder

instance
  ( KnownColumn (Column name chType)
  , Serializable chType
  , IsChType chType
  ) =>
  SerializableColumn (Column name chType) where
  {-# INLINE deserializeColumn #-}
  deserializeColumn :: forall a.
ProtocolRevision
-> UVarInt -> (GetColumnType (Column name chType) -> a) -> Get [a]
deserializeColumn ProtocolRevision
rev UVarInt
rows GetColumnType (Column name chType) -> a
f = (chType -> a) -> [chType] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map chType -> a
GetColumnType (Column name chType) -> a
f ([chType] -> [a]) -> Get [chType] -> Get [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ProtocolRevision -> UVarInt -> Get [chType]
forall chType.
Serializable chType =>
ProtocolRevision -> UVarInt -> Get [chType]
replicateGet ProtocolRevision
rev UVarInt
rows

  {-# INLINE serializeColumn #-}
  serializeColumn :: forall a.
ProtocolRevision
-> (a -> GetColumnType (Column name chType)) -> [a] -> Builder
serializeColumn ProtocolRevision
rev a -> GetColumnType (Column name chType)
f [a]
column  = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((a -> Builder) -> [a] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (forall chType.
Serializable chType =>
ProtocolRevision -> chType -> Builder
serialize @chType ProtocolRevision
rev (chType -> Builder) -> (a -> chType) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> chType
a -> GetColumnType (Column name chType)
f) [a]
column)

instance {-# OVERLAPPING #-}
  ( KnownColumn (Column name (Nullable chType))
  , Serializable chType
  , IsChType chType
  ) =>
  SerializableColumn (Column name (Nullable chType)) where
  {-# INLINE deserializeColumn #-}

  deserializeColumn :: forall a.
ProtocolRevision
-> UVarInt
-> (GetColumnType (Column name (Nullable chType)) -> a)
-> Get [a]
deserializeColumn ProtocolRevision
rev UVarInt
rows GetColumnType (Column name (Nullable chType)) -> a
f = do
    [UInt8]
nulls <- forall chType.
Serializable chType =>
ProtocolRevision -> UVarInt -> Get [chType]
replicateGet @UInt8 ProtocolRevision
rev UVarInt
rows
    [UInt8] -> (UInt8 -> Get a) -> Get [a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM
        [UInt8]
nulls
        (\case
          UInt8
0 -> Nullable chType -> a
GetColumnType (Column name (Nullable chType)) -> a
f (Nullable chType -> a)
-> (chType -> Nullable chType) -> chType -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. chType -> Nullable chType
forall a. a -> Maybe a
Just (chType -> a) -> Get chType -> Get a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall chType.
Serializable chType =>
ProtocolRevision -> Get chType
deserialize @chType ProtocolRevision
rev
          UInt8
_ -> (GetColumnType (Column name (Nullable chType)) -> a
f Nullable chType
GetColumnType (Column name (Nullable chType))
forall a. Maybe a
Nothing a -> Get chType -> Get a
forall a b. a -> Get b -> Get a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall chType.
Serializable chType =>
ProtocolRevision -> Get chType
deserialize @chType ProtocolRevision
rev)
        )

  {-# INLINE serializeColumn #-}
  serializeColumn :: forall a.
ProtocolRevision
-> (a -> GetColumnType (Column name (Nullable chType)))
-> [a]
-> Builder
serializeColumn ProtocolRevision
rev a -> GetColumnType (Column name (Nullable chType))
f [a]
column
    =  [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((a -> Builder) -> [a] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (forall chType.
Serializable chType =>
ProtocolRevision -> chType -> Builder
serialize @UInt8 ProtocolRevision
rev (UInt8 -> Builder) -> (a -> UInt8) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UInt8 -> (chType -> UInt8) -> Nullable chType -> UInt8
forall b a. b -> (a -> b) -> Maybe a -> b
maybe UInt8
1 (UInt8 -> chType -> UInt8
forall a b. a -> b -> a
const UInt8
0) (Nullable chType -> UInt8) -> (a -> Nullable chType) -> a -> UInt8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Nullable chType
a -> GetColumnType (Column name (Nullable chType))
f) [a]
column)
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ((a -> Builder) -> [a] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (forall chType.
Serializable chType =>
ProtocolRevision -> chType -> Builder
serialize @chType ProtocolRevision
rev (chType -> Builder) -> (a -> chType) -> a -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. chType -> (chType -> chType) -> Nullable chType -> chType
forall b a. b -> (a -> b) -> Maybe a -> b
maybe chType
forall chType. IsChType chType => chType
defaultValueOfTypeName chType -> chType
forall a. a -> a
id (Nullable chType -> chType)
-> (a -> Nullable chType) -> a -> chType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Nullable chType
a -> GetColumnType (Column name (Nullable chType))
f) [a]
column)

instance {-# OVERLAPPING #-}
  ( KnownColumn (Column name (LowCardinality chType))
  , Serializable chType
  , IsLowCardinalitySupported chType
  , TypeError ('Text "LowCardinality deserialization still unsupported")
  ) =>
  SerializableColumn (Column name (LowCardinality chType)) where
  {-# INLINE deserializeColumn #-}
  deserializeColumn :: forall a.
ProtocolRevision
-> UVarInt
-> (GetColumnType (Column name (LowCardinality chType)) -> a)
-> Get [a]
deserializeColumn ProtocolRevision
rev UVarInt
rows GetColumnType (Column name (LowCardinality chType)) -> a
f = do
    UInt64
_serializationType <- (UInt64 -> UInt64 -> UInt64
forall a. Bits a => a -> a -> a
.&. UInt64
0xf) (UInt64 -> UInt64) -> Get UInt64 -> Get UInt64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall chType.
Serializable chType =>
ProtocolRevision -> Get chType
deserialize @UInt64 ProtocolRevision
rev
    Int64
_index_size <- forall chType.
Serializable chType =>
ProtocolRevision -> Get chType
deserialize @Int64 ProtocolRevision
rev
    -- error $ "Trace | " <> show _serializationType <> " : " <> show _index_size
    (LowCardinality chType -> a) -> [LowCardinality chType] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map LowCardinality chType -> a
GetColumnType (Column name (LowCardinality chType)) -> a
f ([LowCardinality chType] -> [a])
-> ([chType] -> [LowCardinality chType]) -> [chType] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [chType] -> [LowCardinality chType]
forall a b. Coercible a b => a -> b
coerce
      ([chType] -> [a]) -> Get [chType] -> Get [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall chType.
Serializable chType =>
ProtocolRevision -> UVarInt -> Get [chType]
replicateGet @chType ProtocolRevision
rev UVarInt
rows

  {-# INLINE serializeColumn #-}
  serializeColumn :: forall a.
ProtocolRevision
-> (a -> GetColumnType (Column name (LowCardinality chType)))
-> [a]
-> Builder
serializeColumn ProtocolRevision
_rev a -> GetColumnType (Column name (LowCardinality chType))
column = (a -> LowCardinality chType) -> [a] -> Builder
forall a. HasCallStack => a
undefined a -> LowCardinality chType
a -> GetColumnType (Column name (LowCardinality chType))
column

instance {-# OVERLAPPING #-}
  ( KnownColumn (Column name (Array chType))
  , Serializable chType
  , TypeError ('Text "Arrays deserialization still unsupported")
  )
  => SerializableColumn (Column name (Array chType)) where
  {-# INLINE deserializeColumn #-}
  deserializeColumn :: forall a.
ProtocolRevision
-> UVarInt
-> (GetColumnType (Column name (Array chType)) -> a)
-> Get [a]
deserializeColumn ProtocolRevision
rev UVarInt
_rows GetColumnType (Column name (Array chType)) -> a
_f = do
    (UInt64
arraySize, [UInt64]
_offsets) <- ProtocolRevision -> Get (UInt64, [UInt64])
readOffsets ProtocolRevision
rev
    [chType]
_types <- forall chType.
Serializable chType =>
ProtocolRevision -> UVarInt -> Get [chType]
replicateGet @chType ProtocolRevision
rev (UInt64 -> UVarInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral UInt64
arraySize)
    [a] -> Get [a]
forall a. a -> Get a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([a] -> Get [a]) -> [a] -> Get [a]
forall a b. (a -> b) -> a -> b
$ []
    where
    readOffsets :: ProtocolRevision -> Get (UInt64, [UInt64])
    readOffsets :: ProtocolRevision -> Get (UInt64, [UInt64])
readOffsets ProtocolRevision
revivion = do
      UInt64
size <- forall chType.
Serializable chType =>
ProtocolRevision -> Get chType
deserialize @UInt64 ProtocolRevision
rev
      (UInt64
size, ) ([UInt64] -> (UInt64, [UInt64]))
-> Get [UInt64] -> Get (UInt64, [UInt64])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> UInt64 -> Get [UInt64]
goArrayOffsets UInt64
size
      where
      goArrayOffsets :: UInt64 -> Get [UInt64]
goArrayOffsets UInt64
arraySize =
        do
        UInt64
nextOffset <- forall chType.
Serializable chType =>
ProtocolRevision -> Get chType
deserialize @UInt64 ProtocolRevision
revivion
        if UInt64
arraySize UInt64 -> UInt64 -> Bool
forall a. Ord a => a -> a -> Bool
>= UInt64
nextOffset
          then [UInt64] -> Get [UInt64]
forall a. a -> Get a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [UInt64
nextOffset]
          else (UInt64
nextOffset UInt64 -> [UInt64] -> [UInt64]
forall a. a -> [a] -> [a]
:) ([UInt64] -> [UInt64]) -> Get [UInt64] -> Get [UInt64]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> UInt64 -> Get [UInt64]
goArrayOffsets UInt64
arraySize

  {-# INLINE serializeColumn #-}
  serializeColumn :: forall a.
ProtocolRevision
-> (a -> GetColumnType (Column name (Array chType)))
-> [a]
-> Builder
serializeColumn ProtocolRevision
_rev a -> GetColumnType (Column name (Array chType))
_column = [a] -> Builder
forall a. HasCallStack => a
undefined