git.iko.soy/typeable/postgresql-simple
on master help sign in
Add additional case-insensitive text support
87c6c2dMaximilian Tagher
CHANGES.md+6
@@ -1,3 +1,9 @@
1+### Unreleased
2+
3+ * Added `ToField` instances for case-insensitive strict and lazy text.
4+ Added `citext` and `_citext` to `Database.PostgreSQL.Simple.TypeInfo.Static`.
5+ Thanks to Max Tagher for the implementation.
6+
1### Version 0.5.3.0 (2017-05-15)
7### Version 0.5.3.0 (2017-05-15)
2 * Refactored some rudimentary cursor handling code out of the
8 * Refactored some rudimentary cursor handling code out of the
3 implementation of the fold operators, into a new
9 implementation of the fold operators, into a new
postgresql-simple.cabal+1
@@ -129,6 +129,7 @@ test-suite test
129 , text
129 , text
130 , time
130 , time
131 , vector
131 , vector
132+ , case-insensitive
132
133
133 if !impl(ghc >= 7.6)
134 if !impl(ghc >= 7.6)
134 build-depends:
135 build-depends:
src/Database/PostgreSQL/Simple/ToField.hs+11
@@ -42,6 +42,8 @@ import Database.PostgreSQL.Simple.Compat (toByteString)
42
42
43import qualified Data.ByteString as SB
43import qualified Data.ByteString as SB
44import qualified Data.ByteString.Lazy as LB
44import qualified Data.ByteString.Lazy as LB
45+import Data.CaseInsensitive (CI)
46+import qualified Data.CaseInsensitive as CI
45import qualified Data.Text as ST
47import qualified Data.Text as ST
46import qualified Data.Text.Encoding as ST
48import qualified Data.Text.Encoding as ST
47import qualified Data.Text.Lazy as LT
49import qualified Data.Text.Lazy as LT
@@ -230,6 +232,15 @@ instance ToField LT.Text where
230 toField = toField . LT.toStrict
232 toField = toField . LT.toStrict
231 {-# INLINE toField #-}
233 {-# INLINE toField #-}
232
234
235+-- | citext
236+instance ToField (CI ST.Text) where
237+ toField = toField . CI.original
238+ {-# INLINE toField #-}
239+
240+-- | citext
241+instance ToField (CI LT.Text) where
242+ toField = toField . LT.toStrict . CI.original
243+ {-# INLINE toField #-}
233
244
234instance ToField UTCTime where
245instance ToField UTCTime where
235 toField = Plain . inQuotes . utcTimeToBuilder
246 toField = Plain . inQuotes . utcTimeToBuilder
src/Database/PostgreSQL/Simple/TypeInfo/Static.hs+21
@@ -132,6 +132,8 @@ module Database.PostgreSQL.Simple.TypeInfo.Static
132 , _daterange
132 , _daterange
133 , int8range
133 , int8range
134 , _int8range
134 , _int8range
135+ , citext
136+ , array_citext
135 ) where
137 ) where
136
138
137import Database.PostgreSQL.LibPQ (Oid(..))
139import Database.PostgreSQL.LibPQ (Oid(..))
@@ -253,6 +255,8 @@ staticTypeInfo (Oid x) = case x of
253 3913 -> Just _daterange
255 3913 -> Just _daterange
254 3926 -> Just int8range
256 3926 -> Just int8range
255 3927 -> Just _int8range
257 3927 -> Just _int8range
258+ 60129 -> Just citext
259+ 60134 -> Just array_citext
256 _ -> Nothing
260 _ -> Nothing
257
261
258bool :: TypeInfo
262bool :: TypeInfo
@@ -1230,3 +1234,20 @@ _int8range = Array {
1230 typname = "_int8range",
1234 typname = "_int8range",
1231 typelem = int8range
1235 typelem = int8range
1232 }
1236 }
1237+
1238+citext :: TypeInfo
1239+citext = Basic {
1240+ typoid = Oid 60129,
1241+ typcategory = 'S',
1242+ typdelim = ',',
1243+ typname = "citext"
1244+ }
1245+
1246+array_citext :: TypeInfo
1247+array_citext = Array {
1248+ typoid = Oid 60134,
1249+ typcategory = 'A',
1250+ typdelim = ',',
1251+ typname = "_citext",
1252+ typelem = citext
1253+ }
test/Main.hs+16
@@ -23,6 +23,8 @@ import Data.Aeson
23import Data.ByteString (ByteString)
23import Data.ByteString (ByteString)
24import qualified Data.ByteString as B
24import qualified Data.ByteString as B
25import qualified Data.ByteString.Lazy.Char8 as BL
25import qualified Data.ByteString.Lazy.Char8 as BL
26+import Data.CaseInsensitive (CI)
27+import qualified Data.CaseInsensitive as CI
26import Data.Map (Map)
28import Data.Map (Map)
27import qualified Data.Map as Map
29import qualified Data.Map as Map
28import Data.Text(Text)
30import Data.Text(Text)
@@ -50,6 +52,7 @@ tests env = testGroup "tests"
50 , testCase "Array" . testArray
52 , testCase "Array" . testArray
51 , testCase "Array of nullables" . testNullableArray
53 , testCase "Array of nullables" . testNullableArray
52 , testCase "HStore" . testHStore
54 , testCase "HStore" . testHStore
55+ , testCase "citext" . testCIText
53 , testCase "JSON" . testJSON
56 , testCase "JSON" . testJSON
54 , testCase "Savepoint" . testSavepoint
57 , testCase "Savepoint" . testSavepoint
55 , testCase "Unicode" . testUnicode
58 , testCase "Unicode" . testUnicode
@@ -203,6 +206,19 @@ testHStore TestEnv{..} = do
203 m' <- query conn "SELECT ?::hstore" m
206 m' <- query conn "SELECT ?::hstore" m
204 [m] @?= m'
207 [m] @?= m'
205
208
209+testCIText :: TestEnv -> Assertion
210+testCIText TestEnv{..} = do
211+ execute_ conn "CREATE EXTENSION IF NOT EXISTS citext"
212+ roundTrip (CI.mk "")
213+ roundTrip (CI.mk "UPPERCASE")
214+ roundTrip (CI.mk "lowercase")
215+ where
216+ roundTrip :: (CI Text) -> Assertion
217+ roundTrip cit = do
218+ let toPostgres = Only cit
219+ fromPostgres <- query conn "SELECT ?::citext" toPostgres
220+ [toPostgres] @?= fromPostgres
221+
206testJSON :: TestEnv -> Assertion
222testJSON :: TestEnv -> Assertion
207testJSON TestEnv{..} = do
223testJSON TestEnv{..} = do
208 roundTrip (Map.fromList [] :: Map Text Text)
224 roundTrip (Map.fromList [] :: Map Text Text)
tools/GenTypeInfo.hs+3−1
@@ -195,7 +195,9 @@ daterange
195_daterange
195_daterange
196int8range
196int8range
197_int8range
197_int8range
198−|]
198+citext
199+_citext array_citext
200+|] -- Note: You must enable the citext extension (CREATE EXTENSION IF NOT EXISTS citext) to generate the citext values
199
201
200instance IsString Blaze.Builder where
202instance IsString Blaze.Builder where
201 fromString = Blaze.fromByteString . fromString
203 fromString = Blaze.fromByteString . fromString