packages feed

postgresql-simple-interval 0.2025.7.10 → 0.2025.7.11

raw patch · 3 files changed

+74/−38 lines, 3 filesdep +persistentdep +textdep ~basedep ~bytestringPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependencies added: persistent, text

Dependency ranges changed: base, bytestring

API changes (from Hackage documentation)

+ Database.PostgreSQL.Simple.Interval.Unstable: instance Database.Persist.Class.PersistField.PersistField Database.PostgreSQL.Simple.Interval.Unstable.Interval
+ Database.PostgreSQL.Simple.Interval.Unstable: instance Database.Persist.Sql.Class.PersistFieldSql Database.PostgreSQL.Simple.Interval.Unstable.Interval

Files

postgresql-simple-interval.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: postgresql-simple-interval-version: 0.2025.7.10+version: 0.2025.7.11 synopsis: A simple interval type for PostgreSQL. description:   This library provides a simple interval type for PostgreSQL. It supports@@ -25,8 +25,8 @@ common library   build-depends:     attoparsec ^>=0.14.4,-    base ^>={4.19, 4.20, 4.21},-    bytestring ^>=0.12.1,+    base >=4.13 && <4.22,+    bytestring >=0.10.10 && <0.13,    default-language: Haskell2010   ghc-options:@@ -35,12 +35,18 @@     -Wno-implicit-prelude     -Wno-missing-deriving-strategies     -Wno-missing-export-lists-    -Wno-missing-kind-signatures-    -Wno-missing-safe-haskell-mode-    -Wno-prepositive-qualified-module     -Wno-safe     -Wno-unsafe +  if impl(ghc >=8.10)+    ghc-options:+      -Wno-missing-safe-haskell-mode+      -Wno-prepositive-qualified-module++  if impl(ghc >=9.2)+    ghc-options:+      -Wno-missing-kind-signatures+   if flag(pedantic)     ghc-options: -Werror @@ -54,8 +60,10 @@ library   import: library   build-depends:+    persistent ^>=2.17,     postgresql-simple ^>=0.7,     scientific ^>=0.3.8,+    text >=1.2.4 && <1.3 || >=2.0 && <2.2,    -- cabal-gild: discover source/library   exposed-modules:
source/library/Database/PostgreSQL/Simple/Interval/Unstable.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE LexicalNegation #-} {-# LANGUAGE NumDecimals #-} {-# LANGUAGE OverloadedStrings #-} @@ -10,9 +9,14 @@ import qualified Data.Bits as Bits import qualified Data.ByteString as ByteString import qualified Data.ByteString.Builder as Builder+import qualified Data.ByteString.Char8 as Ascii+import qualified Data.ByteString.Lazy as LazyByteString import qualified Data.Function as Function import qualified Data.Int as Int import qualified Data.Scientific as Scientific+import qualified Data.Text as Text+import qualified Database.Persist as Persist+import qualified Database.Persist.Sql as Persist import qualified Database.PostgreSQL.Simple.FromField as Postgres import qualified Database.PostgreSQL.Simple.ToField as Postgres import qualified Database.PostgreSQL.Simple.TypeInfo.Static as Postgres@@ -26,11 +30,11 @@ -- Note that the @time@ library provides several duration types that are not -- appropriate to use as PostgreSQL intervals: ----- - @NominalDiffTime@: Does not handle days or months. Allows up to picosecond---   precision. Is not bounded.--- - @CalendarDiffTime@: Does not handle days. Embeds a @NominalDiffTime@. Is---   not bounded.--- - @CalendarDiffDays@: Does not handle seconds. Is not bounded.+-- - 'Data.Time.NominalDiffTime': Does not handle days or months. Allows up to+--   picosecond precision. Is not bounded.+-- - 'Data.Time.CalendarDiffTime': Does not handle days. Embeds a+--   @NominalDiffTime@. Is not bounded.+-- - 'Data.Time.CalendarDiffDays': Does not handle seconds. Is not bounded. data Interval = MkInterval   { months :: !Int.Int32,     days :: !Int.Int32,@@ -43,10 +47,35 @@   fromField = Postgres.attoFieldParser (== Postgres.intervalOid) parse  -- | Uses 'render'. Always includes an @interval@ prefix, like--- @interval '2 months 3 days 4 microseconds'@.+-- @interval '\@ 0 mon -1 day +2 us'@. instance Postgres.ToField Interval where-  toField = Postgres.Plain . ("interval " <>) . Postgres.inQuotes . render+  toField = Postgres.Plain . ("interval '" <>) . (<> "'") . render +-- | Behaves the same as the 'Postgres.FromField' and 'Postgres.ToField'+-- instances.+instance Persist.PersistField Interval where+  fromPersistValue persistValue = case persistValue of+    Persist.PersistLiteralEscaped byteString+      | Right interval <- A.parseOnly parse byteString ->+          Right interval+    Persist.PersistLiteral byteString+      | Just withoutPrefix <- Ascii.stripPrefix "interval '" byteString,+        Just withoutSuffix <- Ascii.stripSuffix "'" withoutPrefix,+        Right interval <- A.parseOnly parse withoutSuffix ->+          Right interval+    _ -> Left $ "Invalid interval: " <> Text.pack (show persistValue)+  toPersistValue =+    Persist.PersistLiteral+      . LazyByteString.toStrict+      . Builder.toLazyByteString+      . ("interval '" <>)+      . (<> "'")+      . render++-- | @'Persist.SqlOther' "interval"@+instance Persist.PersistFieldSql Interval where+  sqlType = const $ Persist.SqlOther "interval"+ -- | The empty interval, representing no time at all. -- -- >>> zero@@ -336,13 +365,13 @@  negateComponent :: Component -> Component negateComponent c = case c of-  Years y -> Years -y-  Months m -> Months -m-  Days d -> Days -d-  Hours h -> Hours -h-  Minutes m -> Minutes -m-  Seconds u -> Seconds -u-  Microseconds u -> Microseconds -u+  Years y -> Years (-y)+  Months m -> Months (-m)+  Days d -> Days (-d)+  Hours h -> Hours (-h)+  Minutes m -> Minutes (-m)+  Seconds u -> Seconds (-u)+  Microseconds u -> Microseconds (-u)  negateComponentsWhen :: (Functor f) => Bool -> f Component -> f Component negateComponentsWhen p = if p then fmap negateComponent else id
source/test-suite/Main.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE LexicalNegation #-} {-# LANGUAGE NumDecimals #-} {-# LANGUAGE OverloadedStrings #-} @@ -30,7 +29,7 @@       actual `H.shouldBe` Nothing      H.it "fails with negative month overflow" $ do-      let actual = I.add (I.fromMonths minBound) (I.fromMonths -1)+      let actual = I.add (I.fromMonths minBound) (I.fromMonths (-1))       actual `H.shouldBe` Nothing      H.it "fails with positive day overflow" $ do@@ -38,7 +37,7 @@       actual `H.shouldBe` Nothing      H.it "fails with negative day overflow" $ do-      let actual = I.add (I.fromDays minBound) (I.fromDays -1)+      let actual = I.add (I.fromDays minBound) (I.fromDays (-1))       actual `H.shouldBe` Nothing      H.it "fails with positive microsecond overflow" $ do@@ -46,7 +45,7 @@       actual `H.shouldBe` Nothing      H.it "fails with negative microsecond overflow" $ do-      let actual = I.add (I.fromMicroseconds minBound) (I.fromMicroseconds -1)+      let actual = I.add (I.fromMicroseconds minBound) (I.fromMicroseconds (-1))       actual `H.shouldBe` Nothing    H.describe "fromMicroseconds" $ do@@ -113,7 +112,7 @@       actual `H.shouldBe` "@ +1 mon +2 day +3 us"      H.it "works with negative components" $ do-      let actual = Builder.toLazyByteString . I.render $ I.MkInterval -3 -2 -1+      let actual = Builder.toLazyByteString . I.render $ I.MkInterval (-3) (-2) (-1)       actual `H.shouldBe` "@ -3 mon -2 day -1 us"    H.describe "parse" $ do@@ -190,36 +189,36 @@ examples =   [ mkExample 0 0 0 "PT0S" "00:00:00" "@ 0" "0",     mkExample 1 0 0 "P1M" "1 mon" "@ 1 mon" "0-1",-    mkExample -1 0 0 "P-1M" "-1 mons" "@ 1 mon ago" "-0-1",+    mkExample (-1) 0 0 "P-1M" "-1 mons" "@ 1 mon ago" "-0-1",     mkExample 3 0 0 "P3M" "3 mons" "@ 3 mons" "0-3",     mkExample 6 0 0 "P6M" "6 mons" "@ 6 mons" "0-6",     mkExample 12 0 0 "P1Y" "1 year" "@ 1 year" "1-0",-    mkExample -12 0 0 "P-1Y" "-1 years" "@ 1 year ago" "-1-0",+    mkExample (-12) 0 0 "P-1Y" "-1 years" "@ 1 year ago" "-1-0",     mkExample 13 0 0 "P1Y1M" "1 year 1 mon" "@ 1 year 1 mon" "1-1",-    mkExample -13 0 0 "P-1Y-1M" "-1 years -1 mons" "@ 1 year 1 mon ago" "-1-1",+    mkExample (-13) 0 0 "P-1Y-1M" "-1 years -1 mons" "@ 1 year 1 mon ago" "-1-1",     mkExample 24 0 0 "P2Y" "2 years" "@ 2 years" "2-0",     mkExample 0 1 0 "P1D" "1 day" "@ 1 day" "1 0:00:00",-    mkExample 0 -1 0 "P-1D" "-1 days" "@ 1 day ago" "-1 0:00:00",+    mkExample 0 (-1) 0 "P-1D" "-1 days" "@ 1 day ago" "-1 0:00:00",     mkExample 0 2 0 "P2D" "2 days" "@ 2 days" "2 0:00:00",     mkExample 0 7 0 "P7D" "7 days" "@ 7 days" "7 0:00:00",     mkExample 0 0 1 "PT0.000001S" "00:00:00.000001" "@ 0.000001 secs" "0:00:00.000001",-    mkExample 0 0 -1 "PT-0.000001S" "-00:00:00.000001" "@ 0.000001 secs ago" "-0:00:00.000001",+    mkExample 0 0 (-1) "PT-0.000001S" "-00:00:00.000001" "@ 0.000001 secs ago" "-0:00:00.000001",     mkExample 0 0 1e3 "PT0.001S" "00:00:00.001" "@ 0.001 secs" "0:00:00.001",     mkExample 0 0 1e6 "PT1S" "00:00:01" "@ 1 sec" "0:00:01",-    mkExample 0 0 -1e6 "PT-1S" "-00:00:01" "@ 1 sec ago" "-0:00:01",+    mkExample 0 0 (-1e6) "PT-1S" "-00:00:01" "@ 1 sec ago" "-0:00:01",     mkExample 0 0 2e6 "PT2S" "00:00:02" "@ 2 secs" "0:00:02",     mkExample 0 0 60e6 "PT1M" "00:01:00" "@ 1 min" "0:01:00",-    mkExample 0 0 -60e6 "PT-1M" "-00:01:00" "@ 1 min ago" "-0:01:00",+    mkExample 0 0 (-60e6) "PT-1M" "-00:01:00" "@ 1 min ago" "-0:01:00",     mkExample 0 0 120e6 "PT2M" "00:02:00" "@ 2 mins" "0:02:00",     mkExample 0 0 3600e6 "PT1H" "01:00:00" "@ 1 hour" "01:00:00",-    mkExample 0 0 -3600e6 "PT-1H" "-01:00:00" "@ 1 hour ago" "-01:00:00",+    mkExample 0 0 (-3600e6) "PT-1H" "-01:00:00" "@ 1 hour ago" "-01:00:00",     mkExample 0 0 7200e6 "PT2H" "02:00:00" "@ 2 hours" "02:00:00",     mkExample 0 0 86400e6 "PT24H" "24:00:00" "@ 24 hours" "24:00:00",     mkExample 1 1 1e6 "P1M1DT1S" "1 mon 1 day 00:00:01" "@ 1 mon 1 day 1 sec" "+0-1 +1 +0:00:01",-    mkExample -1 -1 -1e6 "P-1M-1DT-1S" "-1 mons -1 days -00:00:01" "@ 1 mon 1 day 1 sec ago" "-0-1 -1 -0:00:01",-    mkExample -1 1 1e6 "P-1M1DT1S" "-1 mons +1 day 00:00:01" "@ 1 mon -1 days -1 sec ago" "-0-1 +1 +0:00:01",-    mkExample 1 -1 1e6 "P1M-1DT1S" "1 mon -1 days +00:00:01" "@ 1 mon -1 days 1 sec" "+0-1 -1 +0:00:01",-    mkExample 1 1 -1e6 "P1M1DT-1S" "1 mon 1 day -00:00:01" "@ 1 mon 1 day -1 sec" "+0-1 +1 -0:00:01",+    mkExample (-1) (-1) (-1e6) "P-1M-1DT-1S" "-1 mons -1 days -00:00:01" "@ 1 mon 1 day 1 sec ago" "-0-1 -1 -0:00:01",+    mkExample (-1) 1 1e6 "P-1M1DT1S" "-1 mons +1 day 00:00:01" "@ 1 mon -1 days -1 sec ago" "-0-1 +1 +0:00:01",+    mkExample 1 (-1) 1e6 "P1M-1DT1S" "1 mon -1 days +00:00:01" "@ 1 mon -1 days 1 sec" "+0-1 -1 +0:00:01",+    mkExample 1 1 (-1e6) "P1M1DT-1S" "1 mon 1 day -00:00:01" "@ 1 mon 1 day -1 sec" "+0-1 +1 -0:00:01",     mkExample 14 3 14706000007 "P1Y2M3DT4H5M6.000007S" "1 year 2 mons 3 days 04:05:06.000007" "@ 1 year 2 mons 3 days 4 hours 5 mins 6.000007 secs" "+1-2 +3 +4:05:06.000007",     mkExample maxBound 0 0 "P178956970Y7M" "178956970 years 7 mons" "@ 178956970 years 7 mons" "178956970-7",     mkExample minBound 0 0 "P-178956970Y-8M" "-178956970 years -8 mons" "@ 178956970 years 8 mons ago" "-178956970-8",