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