@@ -1,7 +1,9 @@
11{-# LANGUAGE
22 DataKinds
3+ , FlexibleContexts
34 , FlexibleInstances
45 , GADTs
6+ , LambdaCase
57 , MagicHash
68 , MultiParamTypeClasses
79 , PolyKinds
@@ -11,137 +13,133 @@
1113
1214module Squeel.PostgreSQL.Binary where
1315
14−import Control.Arrow (left)
15−import Data.Aeson (FromJSON, ToJSON, eitherDecodeStrict, encode)
1616import Data.ByteString (ByteString)
1717import Data.Int (Int16,Int32,Int64)
18−import Data.Vinyl
19−import Data.Vinyl.Functor
20−import PostgreSQL.Binary.Decoding (Value)
21−import PostgreSQL.Binary.Encoding (Encoding)
18+import Generics.SOP
2219import Data.Scientific (Scientific)
2320import Data.Text (Text)
2421import Data.Time (Day, TimeOfDay, TimeZone, LocalTime, UTCTime, DiffTime)
2522import Data.UUID (UUID)
26−import GHC.Exts
2723
28−import qualified Data.ByteString.Lazy as Lazy (ByteString, toStrict)
29−import qualified Data.Text as Text (pack)
24+import qualified Data.Aeson as Aeson
25+import qualified Data.ByteString.Lazy as Lazy (ByteString)
3026import qualified Data.Text.Lazy as Lazy (Text)
3127import qualified PostgreSQL.Binary.Decoding as Decoder
3228import qualified PostgreSQL.Binary.Encoding as Encoder
3329
3430import Squeel.PostgreSQL.Schema
3531
36−decodeValue :: FromValue pg x => Proxy# pg -> ByteString -> Either Text x
37−decodeValue p = Decoder.valueParser $ fromValue p
32+decodeValue :: HasDecoding pg x => proxy pg -> ByteString -> Either Text x
33+decodeValue p = Decoder.valueParser $ decoding p
3834
39−class FromValue pg x where
40− fromValue :: Proxy# pg -> Value x
41−instance FromValue 'PGInt2 Int16 where
42− fromValue _ = Decoder.int
43−instance FromValue 'PGInt4 Int32 where
44− fromValue _ = Decoder.int
45−instance FromValue 'PGInt8 Int64 where
46− fromValue _ = Decoder.int
47−instance FromValue 'PGFloat4 Float where
48− fromValue _ = Decoder.float4
49−instance FromValue 'PGFloat8 Double where
50− fromValue _ = Decoder.float8
51−instance FromValue 'PGBool Bool where
52− fromValue _ = Decoder.bool
53−instance FromValue 'PGBytea ByteString where
54− fromValue _ = Decoder.bytea_strict
55−instance FromValue 'PGBytea Lazy.ByteString where
56− fromValue _ = Decoder.bytea_lazy
57−instance FromValue 'PGText Text where
58− fromValue _ = Decoder.text_strict
59−instance FromValue 'PGText Lazy.Text where
60− fromValue _ = Decoder.text_lazy
61−instance FromValue ('PGChar 1) Char where
62− fromValue _ = Decoder.char
63−instance FromValue 'PGNumeric Scientific where
64− fromValue _ = Decoder.numeric
65−instance FromValue 'PGUuid UUID where
66− fromValue _ = Decoder.uuid
67−instance FromJSON x => FromValue 'PGJson x where
68− fromValue _ = Decoder.json_bytes (left Text.pack . eitherDecodeStrict)
69−instance FromJSON x => FromValue 'PGJsonb x where
70− fromValue _ = Decoder.jsonb_bytes (left Text.pack . eitherDecodeStrict)
71−instance FromValue 'PGDate Day where
72− fromValue _ = Decoder.date
73−instance FromValue 'PGTime TimeOfDay where
74− fromValue _ = Decoder.time_int
75−instance FromValue 'PGTimeTZ (TimeOfDay, TimeZone) where
76− fromValue _ = Decoder.timetz_int
77−instance FromValue 'PGTimestamp LocalTime where
78− fromValue _ = Decoder.timestamp_int
79−instance FromValue 'PGTimestampTZ UTCTime where
80− fromValue _ = Decoder.timestamptz_int
81−instance FromValue 'PGInterval DiffTime where
82− fromValue _ = Decoder.interval_int
83−instance FromValue pg ty => FromValue (column ::: 'Required ('NotNull pg)) ty where
84− fromValue _ = fromValue (proxy# :: Proxy# pg)
35+class HasDecoding pg x where
36+ decoding :: proxy pg -> Decoder.Value x
37+instance HasDecoding (column ::: 'Required ('NotNull 'PGInt2)) Int16 where
38+ decoding _ = Decoder.int
39+instance HasDecoding (column ::: 'Required ('NotNull 'PGInt4)) Int32 where
40+ decoding _ = Decoder.int
41+instance HasDecoding (column ::: 'Required ('NotNull 'PGInt8)) Int64 where
42+ decoding _ = Decoder.int
43+instance HasDecoding (column ::: 'Required ('NotNull 'PGFloat4)) Float where
44+ decoding _ = Decoder.float4
45+instance HasDecoding (column ::: 'Required ('NotNull 'PGFloat8)) Double where
46+ decoding _ = Decoder.float8
47+instance HasDecoding (column ::: 'Required ('NotNull 'PGBool)) Bool where
48+ decoding _ = Decoder.bool
49+instance HasDecoding (column ::: 'Required ('NotNull 'PGBytea)) ByteString where
50+ decoding _ = Decoder.bytea_strict
51+instance HasDecoding (column ::: 'Required ('NotNull 'PGBytea)) Lazy.ByteString where
52+ decoding _ = Decoder.bytea_lazy
53+instance HasDecoding (column ::: 'Required ('NotNull 'PGText)) Text where
54+ decoding _ = Decoder.text_strict
55+instance HasDecoding (column ::: 'Required ('NotNull 'PGText)) Lazy.Text where
56+ decoding _ = Decoder.text_lazy
57+instance HasDecoding (column ::: 'Required ('NotNull ('PGChar 1))) Char where
58+ decoding _ = Decoder.char
59+instance HasDecoding (column ::: 'Required ('NotNull 'PGNumeric)) Scientific where
60+ decoding _ = Decoder.numeric
61+instance HasDecoding (column ::: 'Required ('NotNull 'PGUuid)) UUID where
62+ decoding _ = Decoder.uuid
63+instance HasDecoding (column ::: 'Required ('NotNull 'PGJson)) Aeson.Value where
64+ decoding _ = Decoder.json_ast
65+instance HasDecoding (column ::: 'Required ('NotNull 'PGJsonb)) Aeson.Value where
66+ decoding _ = Decoder.jsonb_ast
67+instance HasDecoding (column ::: 'Required ('NotNull 'PGDate)) Day where
68+ decoding _ = Decoder.date
69+instance HasDecoding (column ::: 'Required ('NotNull 'PGTime)) TimeOfDay where
70+ decoding _ = Decoder.time_int
71+instance HasDecoding (column ::: 'Required ('NotNull 'PGTimeTZ)) (TimeOfDay, TimeZone) where
72+ decoding _ = Decoder.timetz_int
73+instance HasDecoding (column ::: 'Required ('NotNull 'PGTimestamp)) LocalTime where
74+ decoding _ = Decoder.timestamp_int
75+instance HasDecoding (column ::: 'Required ('NotNull 'PGTimestampTZ)) UTCTime where
76+ decoding _ = Decoder.timestamptz_int
77+instance HasDecoding (column ::: 'Required ('NotNull 'PGInterval)) DiffTime where
78+ decoding _ = Decoder.interval_int
8579
86−class FromValues pgs xs where
87− decodeValues :: Proxy# pgs -> Rec (Const ByteString) xs -> Rec (Either Text) xs
88−instance FromValues '[] '[] where decodeValues _ _ = RNil
89−instance (FromValue pg x, FromValues pgs xs)
90− => FromValues (pg ': pgs) (x ': xs) where
91− decodeValues _ (Const result :& results) =
92− decodeValue (proxy# :: Proxy# pg) result
93− :& decodeValues (proxy# :: Proxy# pgs) results
80+decodings
81+ :: AllZip HasDecoding pgs xs
82+ => proxy pgs
83+ -> NP (K ByteString) xs -> Either Text (NP I xs)
84+decodings _ Nil = return Nil
85+decodings (_ :: proxy pgs) (K bytestring :* bytestrings) =
86+ case (hpure Proxy :: NP Proxy pgs) of
87+ proxy :* proxies -> (:*)
88+ <$> (I <$> Decoder.valueParser (decoding proxy) bytestring)
89+ <*> decodings proxies bytestrings
9490
95−class ToValue x pg where
96− toValue :: Proxy# pg -> x -> Encoding
97−instance ToValue Int16 'PGInt2 where
98− toValue _ = Encoder.int2_int16
99−instance ToValue Int32 'PGInt4 where
100− toValue _ = Encoder.int4_int32
101−instance ToValue Int64 'PGInt8 where
102− toValue _ = Encoder.int8_int64
103−instance ToValue Float 'PGFloat4 where
104− toValue _ = Encoder.float4
105−instance ToValue Double 'PGFloat8 where
106− toValue _ = Encoder.float8
107−instance ToValue Bool 'PGBool where
108− toValue _ = Encoder.bool
109−instance ToValue ByteString 'PGBytea where
110− toValue _ = Encoder.bytea_strict
111−instance ToValue Lazy.ByteString 'PGBytea where
112− toValue _ = Encoder.bytea_lazy
113−instance ToValue Text 'PGText where
114− toValue _ = Encoder.text_strict
115−instance ToValue Lazy.Text 'PGText where
116− toValue _ = Encoder.text_lazy
117−instance ToValue Char ('PGChar 1) where
118− toValue _ = Encoder.char_utf8
119−instance ToValue Scientific 'PGNumeric where
120− toValue _ = Encoder.numeric
121−instance ToValue UUID 'PGUuid where
122− toValue _ = Encoder.uuid
123−instance ToJSON x => ToValue x 'PGJson where
124− toValue _ = Encoder.json_bytes . Lazy.toStrict . encode
125−instance ToJSON x => ToValue x 'PGJsonb where
126− toValue _ = Encoder.jsonb_bytes . Lazy.toStrict . encode
127−instance ToValue Day 'PGDate where
128− toValue _ = Encoder.date
129−instance ToValue TimeOfDay 'PGTime where
130− toValue _ = Encoder.time_int
131−instance ToValue (TimeOfDay, TimeZone) 'PGTimeTZ where
132− toValue _ = Encoder.timetz_int
133−instance ToValue LocalTime 'PGTimestamp where
134− toValue _ = Encoder.timestamp_int
135−instance ToValue UTCTime 'PGTimestampTZ where
136− toValue _ = Encoder.timestamptz_int
137−instance ToValue DiffTime 'PGInterval where
138− toValue _ = Encoder.interval_int
91+class HasEncoding pg x where
92+ encoding :: proxy pg -> x -> Encoder.Encoding
93+instance HasEncoding ('Required ('NotNull 'PGInt2)) Int16 where
94+ encoding _ = Encoder.int2_int16
95+instance HasEncoding ('Required ('NotNull 'PGInt4)) Int32 where
96+ encoding _ = Encoder.int4_int32
97+instance HasEncoding ('Required ('NotNull 'PGInt8)) Int64 where
98+ encoding _ = Encoder.int8_int64
99+instance HasEncoding ('Required ('NotNull 'PGFloat4)) Float where
100+ encoding _ = Encoder.float4
101+instance HasEncoding ('Required ('NotNull 'PGFloat8)) Double where
102+ encoding _ = Encoder.float8
103+instance HasEncoding ('Required ('NotNull 'PGBool)) Bool where
104+ encoding _ = Encoder.bool
105+instance HasEncoding ('Required ('NotNull 'PGBytea)) ByteString where
106+ encoding _ = Encoder.bytea_strict
107+instance HasEncoding ('Required ('NotNull 'PGBytea)) Lazy.ByteString where
108+ encoding _ = Encoder.bytea_lazy
109+instance HasEncoding ('Required ('NotNull 'PGText)) Text where
110+ encoding _ = Encoder.text_strict
111+instance HasEncoding ('Required ('NotNull 'PGText)) Lazy.Text where
112+ encoding _ = Encoder.text_lazy
113+instance HasEncoding ('Required ('NotNull ('PGChar 1))) Char where
114+ encoding _ = Encoder.char_utf8
115+instance HasEncoding ('Required ('NotNull 'PGNumeric)) Scientific where
116+ encoding _ = Encoder.numeric
117+instance HasEncoding ('Required ('NotNull 'PGUuid)) UUID where
118+ encoding _ = Encoder.uuid
119+instance HasEncoding ('Required ('NotNull 'PGJson)) Aeson.Value where
120+ encoding _ = Encoder.json_ast
121+instance HasEncoding ('Required ('NotNull 'PGJsonb)) Aeson.Value where
122+ encoding _ = Encoder.jsonb_ast
123+instance HasEncoding ('Required ('NotNull 'PGDate)) Day where
124+ encoding _ = Encoder.date
125+instance HasEncoding ('Required ('NotNull 'PGTime)) TimeOfDay where
126+ encoding _ = Encoder.time_int
127+instance HasEncoding ('Required ('NotNull 'PGTimeTZ)) (TimeOfDay, TimeZone) where
128+ encoding _ = Encoder.timetz_int
129+instance HasEncoding ('Required ('NotNull 'PGTimestamp)) LocalTime where
130+ encoding _ = Encoder.timestamp_int
131+instance HasEncoding ('Required ('NotNull 'PGTimestampTZ)) UTCTime where
132+ encoding _ = Encoder.timestamptz_int
133+instance HasEncoding ('Required ('NotNull 'PGInterval)) DiffTime where
134+ encoding _ = Encoder.interval_int
139135
140−class ToValues xs pgs where
141− toValues :: Proxy# pgs -> Rec Identity xs -> [ByteString]
142−instance ToValues '[] '[] where toValues _ _ = []
143−instance (ToValue x pg, ToValues xs pgs)
144− => ToValues (x ': xs) (pg ': pgs) where
145− toValues _ (Identity x :& xs)
146− = Encoder.encodingBytes ((toValue (proxy# :: Proxy# pg)) x)
147− : toValues (proxy# :: Proxy# pgs) xs
136+encodings
137+ :: AllZip HasEncoding pgs xs
138+ => proxy pgs
139+ -> NP I xs
140+ -> [ByteString]
141+encodings _ Nil = []
142+encodings (_ :: proxy pgs) (I x :* xs) =
143+ case (hpure Proxy :: NP Proxy pgs) of
144+ proxy :* proxies -> Encoder.encodingBytes (encoding proxy x)
145+ : encodings proxies xs