packages feed

postgresql-binary 0.2.1 → 0.2.2

raw patch · 6 files changed

+118/−26 lines, 6 files

Files

executables/Tests.hs view
@@ -107,7 +107,8 @@   void $ PQ.exec c $ mconcat $ map (<> ";") $      [        "SET client_min_messages TO WARNING",-      "SET client_encoding = 'UTF8'"+      "SET client_encoding = 'UTF8'",+      "SET intervalstyle = 'postgres'"     ]  getIntegerDatetimes :: PQ.Connection -> IO Bool@@ -134,7 +135,8 @@  microsTimeOfDayGen :: Gen TimeOfDay microsTimeOfDayGen =-  timeToTimeOfDay <$> microsDiffTimeGen+  fmap timeToTimeOfDay $ fmap picosecondsToDiffTime $ fmap (* (10^6)) $ +    choose (0, (10^6)*24*60*60)  microsLocalTimeGen :: Gen LocalTime microsLocalTimeGen = @@ -144,9 +146,12 @@ microsUTCTimeGen =   localTimeToUTC <$> timeZoneGen <*> microsLocalTimeGen -microsDiffTimeGen :: Gen DiffTime-microsDiffTimeGen = do-  fmap picosecondsToDiffTime $ fmap (* (10^6)) $ choose (0, (10^6)*24*60*60)+intervalDiffTimeGen :: Gen DiffTime+intervalDiffTimeGen = do+  unsafeCoerce ((* (10^6)) <$> choose (uMin, uMax) :: Gen Integer)+  where+    uMin = unsafeCoerce minInterval `div` 10^6+    uMax = unsafeCoerce maxInterval `div` 10^6  timeZoneGen :: Gen TimeZone timeZoneGen =@@ -184,7 +189,16 @@       where         dimensionWidth (x, _) = fromIntegral x +-- * Constants+------------------------- +maxInterval :: DiffTime = +  unsafeCoerce $ +    (truncate (1780000 * 365.2425 * 24 * 60 * 60 * 10 ^ 12 :: Rational) :: Integer)++minInterval :: DiffTime = +  negate maxInterval+ -- * Tests ------------------------- @@ -209,15 +223,36 @@       query "SELECT '550e8400-e29b-41d4-a716-446655440000' :: uuid" [] PQ.Binary  prop_interval =-  forAll microsDiffTimeGen $ +  forAll intervalDiffTimeGen $      mappingP (PTI.oidOf PTI.interval)               (nonNullRenderer Encoder.interval)              (nonNullParser Decoder.interval) -test_intervalParsing =-  assertEqual (Right (secondsToDiffTime (44 + 60 * (10 + 60 * 24 * (20 + 31 * 2))))) =<< do-    fmap (Decoder.interval . fromJust) $ -      query "SELECT 'P0000-02-20T00:10:44' :: interval" [] PQ.Binary+test_maxInterval =+  let x = maxInterval+    in +      assertEqual (Just (Right x)) =<< do+        let +          p = +            (,,)+              (PQ.Oid (fromIntegral (PTI.oidOf PTI.interval)))+              (Encoder.interval x)+              (PQ.Binary)+        (fmap . fmap) Decoder.interval $ +          query "SELECT $1" [Just p] PQ.Binary++test_minInterval =+  let x = minInterval+    in +      assertEqual (Just (Right x)) =<< do+        let +          p = +            (,,)+              (PQ.Oid (fromIntegral (PTI.oidOf PTI.interval)))+              (Encoder.interval x)+              (PQ.Binary)+        (fmap . fmap) Decoder.interval $ +          query "SELECT $1" [Just p] PQ.Binary  prop_timestamp =   forAll microsUTCTimeGen $ 
library/PostgreSQLBinary/Decoder.hs view
@@ -16,6 +16,7 @@ import qualified PostgreSQLBinary.Time as Time import qualified PostgreSQLBinary.Integral as Integral import qualified PostgreSQLBinary.Numeric as Numeric+import qualified PostgreSQLBinary.Interval as Interval   -- |@@ -155,13 +156,8 @@     ub <- state $ B.splitAt 8     db <- state $ B.splitAt 4     mb <- get-    lift $ do-      u <- int ub-      d <- int db-      m <- int mb-      return $ picosecondsToDiffTime $-        10 ^ 6 * fromIntegral (u + 10 ^ 6 * 60 * 60 * 24 * (d + 31 * m) :: Int64)-+    i <- lift $ Interval.Interval <$> int ub <*> int db <*> int mb+    return $ Interval.toDiffTime i   -- * Misc
library/PostgreSQLBinary/Encoder/Builder.hs view
@@ -15,6 +15,7 @@ import qualified PostgreSQLBinary.Array as Array import qualified PostgreSQLBinary.Time as Time import qualified PostgreSQLBinary.Numeric as Numeric+import qualified PostgreSQLBinary.Interval as Interval   {-# INLINE run #-}@@ -70,13 +71,11 @@  {-# INLINE interval #-} interval :: DiffTime -> Builder-interval x =-  flip evalState (unsafeCoerce x :: Integer) $ do-    u <- state (`divMod` (10 ^ 6))-    d <- state (`divMod` (10 ^ 6 * 60 * 60 * 24))-    m <- get-    return $-      int64BE (fromIntegral u) <> int32BE (fromIntegral d) <> int32BE (fromIntegral m)+interval =+  Interval.fromDiffTime >>> +  fromMaybe (error "Too large DiffTime value for an interval") >>>+  \(Interval.Interval u d m) -> int64BE u <> int32BE d <> int32BE m+  {-# INLINE numeric #-} numeric :: Scientific -> Builder
+ library/PostgreSQLBinary/Interval.hs view
@@ -0,0 +1,43 @@+module PostgreSQLBinary.Interval where++import PostgreSQLBinary.Prelude+import qualified PostgreSQLBinary.Time as Time+++data Interval = +  Interval {+    micros :: Int64,+    days :: Int32,+    months :: Int32+  } +  deriving (Show, Eq)+++-- |+-- Oddly enough despite a claim of support of up to 178000000 years in+-- <http://www.postgresql.org/docs/9.3/static/datatype-datetime.html Postgres' docs>+-- in practice it starts behaving unpredictable after a smaller limit.+maxDiffTime :: DiffTime = 1780000 * Time.microsToDiffTime Time.year+minDiffTime :: DiffTime = negate maxDiffTime++fromDiffTime :: DiffTime -> Maybe Interval+fromDiffTime x =+  if x > maxDiffTime || x < minDiffTime+    then Nothing+    else Just $ fromPicosUnsafe (unsafeCoerce x)++fromPicosUnsafe :: Integer -> Interval+fromPicosUnsafe =+  evalState $ do+    modify $ flip div (10^6)+    u <- state $ swap . flip divMod (10 ^ 6 * 60 * 60 * 24)+    d <- state $ swap . flip divMod (31)+    m <- get+    return $ Interval (fromIntegral u) (fromIntegral d) (fromIntegral m)++toDiffTime :: Interval -> DiffTime+toDiffTime x =+  picosecondsToDiffTime $ +    (10 ^ 6) *+      (fromIntegral (micros x) + +       10 ^ 6 * 60 * 60 * 24 * (fromIntegral (days x + 31 * months x)))
library/PostgreSQLBinary/Time.hs view
@@ -1,6 +1,6 @@ module PostgreSQLBinary.Time where -import PostgreSQLBinary.Prelude+import PostgreSQLBinary.Prelude hiding (second) import Data.Time.Calendar.Julian  @@ -58,3 +58,21 @@     let p = truncate $ toRational s * 10 ^ 12 :: Integer     return $       TimeOfDay h m (unsafeCoerce p)+++-- * Constants in microseconds according to Julian dates standard+-------------------------+-- According to+-- http://www.postgresql.org/docs/9.1/static/datatype-datetime.html+-- Postgres uses Julian dates internally+-------------------------++year   :: Int64 = truncate (365.2425 * fromIntegral day :: Rational)+day    :: Int64 = 24 * hour+hour   :: Int64 = 60 * minute+minute :: Int64 = 60 * second+second :: Int64 = 10 ^ 6 ++microsToDiffTime :: Int64 -> DiffTime+microsToDiffTime =+  unsafeCoerce . (* (10^6)) . fromIntegral
postgresql-binary.cabal view
@@ -1,7 +1,7 @@ name:   postgresql-binary version:-  0.2.1+  0.2.2 synopsis:   Encoders and decoders for the PostgreSQL's binary format description:@@ -56,6 +56,7 @@     PostgreSQLBinary.Integral     PostgreSQLBinary.Numeric     PostgreSQLBinary.Time+    PostgreSQLBinary.Interval   exposed-modules:     PostgreSQLBinary.Array     PostgreSQLBinary.Encoder