on dev help sign in
type 2
commit22ec9503f179ed60e24c640cb5f2070b04b731ee authorEitan Chatav <eitan.chatav@gmail.com> dateMon 3 Apr 2017, 09:45 (10 years ago) parent3771b5f
4 files changed+207−1
squeel-postgresql/squeel-postgresql.cabal+2 squeel-postgresql/src/Squeel/PostgreSQL/PQ.hs+1−1 squeel-postgresql/src/Squeel/PostgreSQL/Type2.hs+66 squeel-postgresql/src/Squeel/PostgreSQL/Value2.hs+138
squeel-postgresql/squeel-postgresql.cabal+2
@@ -17,7 +17,9 @@ library
1717 Squeel.PostgreSQL.PQ
1818 Squeel.PostgreSQL.Query
1919 Squeel.PostgreSQL.Type
20+ Squeel.PostgreSQL.Type2
2021 Squeel.PostgreSQL.Value
22+ Squeel.PostgreSQL.Value2
2123 default-language: Haskell2010
2224 ghc-options: -Wall -Werror
2325 build-depends: base
squeel-postgresql/src/Squeel/PostgreSQL/PQ.hs+1−1
@@ -62,7 +62,7 @@ class MonadPQ pq where
6262 -> pq db0 db1 io (Maybe (Result xs))
6363
6464 pqExecParams
65− :: (MonadBase IO io, ToValues xs ps, ToOids ps)
65+ :: (MonadBase IO io, ToOids ps, ToValues xs ps)
6666 => Query db0 db1 ps ys
6767 -> Rec Identity xs
6868 -> pq db0 db1 io (Maybe (Result ys))
squeel-postgresql/src/Squeel/PostgreSQL/Type2.hsnew file+66
@@ -0,0 +1,66 @@
1+{-# LANGUAGE
2+ DataKinds
3+ , GADTs
4+ , PolyKinds
5+ , ScopedTypeVariables
6+ , TypeApplications
7+ , TypeFamilies
8+ , TypeOperators
9+#-}
10+
11+module Squeel.PostgreSQL.Type2 where
12+
13+import Data.Proxy
14+import GHC.TypeLits
15+
16+import qualified Database.PostgreSQL.LibPQ as LibPQ
17+
18+data PGType
19+ = PGBool
20+ | PGInt2
21+ | PGInt4
22+ | PGInt8
23+ | PGNumeric
24+ | PGFloat4
25+ | PGFloat8
26+ | PGSerial2
27+ | PGSerial4
28+ | PGSerial8
29+ | PGMoney
30+ | PGChar Nat
31+ | PGVarChar Nat
32+ | PGText
33+ | PGBytea
34+ | PGTimestamp
35+ | PGTimestampTZ
36+ | PGDate
37+ | PGTime
38+ | PGTimeTZ
39+ | PGInterval
40+ | PGUuid
41+ | PGJson
42+ | PGJsonb
43+
44+data Named k = (:=) Symbol k
45+type family Unnamed named where Unnamed (name ':= x) = x
46+type family Name k where Name (name ':= x) = name
47+type Column = Named PGType
48+type Table = Named [Column]
49+type Database = Named [Table]
50+type Schema = Named [Database]
51+data Alias (obj :: k -> *) (named :: Named k) where
52+ As :: KnownSymbol name => obj x -> Alias obj (name ':= x)
53+ Elem
54+ :: (KnownSymbol name, (name ':= x) `Elem` list ~ 'True)
55+ => Alias (obj list) (name ':= x)
56+
57+type family Elem x xs where
58+ x `Elem` '[] = 'False
59+ x `Elem` (x ': xs) = 'True
60+ x `Elem` (x' ': xs) = x `Elem` xs
61+
62+class ToOid pg where toOid :: Proxy pg -> LibPQ.Oid
63+class ToOids pgs where toOids :: Proxy pgs -> [LibPQ.Oid]
64+instance ToOids '[] where toOids _ = []
65+instance (ToOid pg, ToOids pgs) => ToOids (pg ': pgs) where
66+ toOids (_ :: Proxy (pg ': pgs)) = toOid (Proxy @pg) : toOids (Proxy @pgs)
squeel-postgresql/src/Squeel/PostgreSQL/Value2.hsnew file+138
@@ -0,0 +1,138 @@
1+{-# LANGUAGE
2+ DataKinds
3+ , FlexibleInstances
4+ , FunctionalDependencies
5+ , KindSignatures
6+ , MultiParamTypeClasses
7+ , PolyKinds
8+ , ScopedTypeVariables
9+ , TypeApplications
10+ , TypeFamilies
11+ , TypeOperators
12+#-}
13+
14+module Squeel.PostgreSQL.Value2 where
15+
16+import Control.Arrow (left)
17+import Data.Aeson (FromJSON, ToJSON, eitherDecodeStrict, encode)
18+import Data.ByteString (ByteString)
19+import Data.Int (Int16,Int32,Int64)
20+import Data.Proxy
21+import Data.Vinyl
22+import Data.Vinyl.Functor
23+import PostgreSQL.Binary.Decoder (Decoder)
24+import PostgreSQL.Binary.Encoder (Encoder)
25+import Data.Proxy (Proxy)
26+import Data.Scientific (Scientific)
27+import Data.Text (Text)
28+import Data.Time (Day, TimeOfDay, TimeZone, LocalTime, UTCTime, DiffTime)
29+import Data.UUID (UUID)
30+
31+import qualified Data.ByteString.Lazy as Lazy (ByteString, toStrict)
32+import qualified Data.Text as Text (pack)
33+import qualified Data.Text.Lazy as Lazy (Text)
34+import qualified PostgreSQL.Binary.Decoder as Decoder
35+import qualified PostgreSQL.Binary.Encoder as Encoder
36+
37+import Squeel.PostgreSQL.Type2
38+
39+decodeValue :: FromValue pg x => Proxy pg -> ByteString -> Either Text x
40+decodeValue = Decoder.run . fromValue
41+
42+class FromValue (pg :: PGType) x where
43+ fromValue :: Proxy pg -> Decoder x
44+instance FromValue 'PGInt2 Int16 where
45+ fromValue _ = Decoder.int
46+instance FromValue 'PGInt4 Int32 where
47+ fromValue _ = Decoder.int
48+instance FromValue 'PGInt8 Int64 where
49+ fromValue _ = Decoder.int
50+instance FromValue 'PGFloat4 Float where
51+ fromValue _ = Decoder.float4
52+instance FromValue 'PGFloat8 Double where
53+ fromValue _ = Decoder.float8
54+instance FromValue 'PGBool Bool where
55+ fromValue _ = Decoder.bool
56+instance FromValue 'PGBytea ByteString where
57+ fromValue _ = Decoder.bytea_strict
58+instance FromValue 'PGBytea Lazy.ByteString where
59+ fromValue _ = Decoder.bytea_lazy
60+instance FromValue 'PGText Text where
61+ fromValue _ = Decoder.text_strict
62+instance FromValue 'PGText Lazy.Text where
63+ fromValue _ = Decoder.text_lazy
64+instance FromValue ('PGChar 1) Char where
65+ fromValue _ = Decoder.char
66+instance FromValue 'PGNumeric Scientific where
67+ fromValue _ = Decoder.numeric
68+instance FromValue 'PGUuid UUID where
69+ fromValue _ = Decoder.uuid
70+instance FromJSON x => FromValue 'PGJson x where
71+ fromValue _ = Decoder.json_bytes (left Text.pack . eitherDecodeStrict)
72+instance FromJSON x => FromValue 'PGJsonb x where
73+ fromValue _ = Decoder.jsonb_bytes (left Text.pack . eitherDecodeStrict)
74+instance FromValue 'PGDate Day where
75+ fromValue _ = Decoder.date
76+instance FromValue 'PGTime TimeOfDay where
77+ fromValue _ = Decoder.time_int
78+instance FromValue 'PGTimeTZ (TimeOfDay, TimeZone) where
79+ fromValue _ = Decoder.timetz_int
80+instance FromValue 'PGTimestamp LocalTime where
81+ fromValue _ = Decoder.timestamp_int
82+instance FromValue 'PGTimestampTZ UTCTime where
83+ fromValue _ = Decoder.timestamptz_int
84+instance FromValue 'PGInterval DiffTime where
85+ fromValue _ = Decoder.interval_int
86+
87+class ToValue x (pg :: PGType) where
88+ toValue :: Proxy pg -> Encoder x
89+instance ToValue Int16 'PGInt2 where
90+ toValue _ = Encoder.int2_int16
91+instance ToValue Int32 'PGInt4 where
92+ toValue _ = Encoder.int4_int32
93+instance ToValue Int64 'PGInt8 where
94+ toValue _ = Encoder.int8_int64
95+instance ToValue Float 'PGFloat4 where
96+ toValue _ = Encoder.float4
97+instance ToValue Double 'PGFloat8 where
98+ toValue _ = Encoder.float8
99+instance ToValue Bool 'PGBool where
100+ toValue _ = Encoder.bool
101+instance ToValue ByteString 'PGBytea where
102+ toValue _ = Encoder.bytea_strict
103+instance ToValue Lazy.ByteString 'PGBytea where
104+ toValue _ = Encoder.bytea_lazy
105+instance ToValue Text 'PGText where
106+ toValue _ = Encoder.text_strict
107+instance ToValue Lazy.Text 'PGText where
108+ toValue _ = Encoder.text_lazy
109+instance ToValue Char ('PGChar 1) where
110+ toValue _ = Encoder.char
111+instance ToValue Scientific 'PGNumeric where
112+ toValue _ = Encoder.numeric
113+instance ToValue UUID 'PGUuid where
114+ toValue _ = Encoder.uuid
115+instance ToJSON x => ToValue x 'PGJson where
116+ toValue _ = Encoder.json_bytes . Lazy.toStrict . encode
117+instance ToJSON x => ToValue x 'PGJsonb where
118+ toValue _ = Encoder.jsonb_bytes . Lazy.toStrict . encode
119+instance ToValue Day 'PGDate where
120+ toValue _ = Encoder.date
121+instance ToValue TimeOfDay 'PGTime where
122+ toValue _ = Encoder.time_int
123+instance ToValue (TimeOfDay, TimeZone) 'PGTimeTZ where
124+ toValue _ = Encoder.timetz_int
125+instance ToValue LocalTime 'PGTimestamp where
126+ toValue _ = Encoder.timestamp_int
127+instance ToValue UTCTime 'PGTimestampTZ where
128+ toValue _ = Encoder.timestamptz_int
129+instance ToValue DiffTime 'PGInterval where
130+ toValue _ = Encoder.interval_int
131+
132+class ToValues xs pgs where
133+ toValues :: Proxy pgs -> Rec Identity xs -> [ByteString]
134+instance ToValues '[] '[] where toValues _ _ = []
135+instance (ToValue x pg, ToValues xs pgs)
136+ => ToValues (x ': xs) (pg ': pgs) where
137+ toValues (_ :: Proxy (pg ': pgs)) (Identity x :& xs) =
138+ Encoder.run (toValue (Proxy @pg)) x : toValues (Proxy @pgs) xs