Skip to content

Commit 704d864

Browse files
authored
Merge pull request #633 from thomasjm/limit-offset-maybe
Add limitMaybe_, offsetMaybe_ + tests
2 parents ad12234 + deb5d2d commit 704d864

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

beam-core/Database/Beam/Query/Combinators.hs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ module Database.Beam.Query.Combinators
4141
, QIfCond, QIfElse
4242
, (<|>.)
4343

44-
, limit_, offset_
44+
, limit_, limitMaybe_
45+
, offset_, offsetMaybe_
4546

4647
, as_
4748

@@ -66,8 +67,8 @@ module Database.Beam.Query.Combinators
6667
, orderBy_, asc_, desc_, nullsFirst_, nullsLast_
6768
) where
6869

69-
import Database.Beam.Backend.Types
7070
import Database.Beam.Backend.SQL
71+
import Database.Beam.Backend.Types
7172

7273
import Database.Beam.Query.Internal
7374
import Database.Beam.Query.Ord
@@ -83,6 +84,7 @@ import Control.Applicative
8384
import Data.Maybe
8485
import Data.Proxy
8586
import Data.Time (LocalTime)
87+
import Unsafe.Coerce (unsafeCoerce)
8688

8789
import GHC.TypeLits (TypeError, ErrorMessage(Text))
8890

@@ -335,6 +337,17 @@ limit_ :: forall s a be db
335337
limit_ limit' (Q q) =
336338
Q (liftF (QLimit limit' q (rewriteThread (Proxy @s))))
337339

340+
-- | Conditionally limit the number of results returned by a query.
341+
limitMaybe_ :: forall s a be db
342+
. ( Projectible be a
343+
, ThreadRewritable (QNested s) a )
344+
=> Maybe Integer -> Q be db (QNested s) a -> Q be db s (WithRewrittenThread (QNested s) s a)
345+
limitMaybe_ (Just limit') (Q q) =
346+
Q (liftF (QLimit limit' q (rewriteThread (Proxy @s))))
347+
-- This uses unsafeCoerce, but should be safe since this function is tested.
348+
-- See discussion on https://github.com/haskell-beam/beam/pull/633.
349+
limitMaybe_ Nothing (Q q) = Q (unsafeCoerce q)
350+
338351
-- | Drop the first `offset'` results.
339352
offset_ :: forall s a be db
340353
. ( Projectible be a
@@ -343,6 +356,17 @@ offset_ :: forall s a be db
343356
offset_ offset' (Q q) =
344357
Q (liftF (QOffset offset' q (rewriteThread (Proxy @s))))
345358

359+
-- | Conditionally drop the first `offset'` results.
360+
offsetMaybe_ :: forall s a be db
361+
. ( Projectible be a
362+
, ThreadRewritable (QNested s) a )
363+
=> Maybe Integer -> Q be db (QNested s) a -> Q be db s (WithRewrittenThread (QNested s) s a)
364+
offsetMaybe_ (Just offset') (Q q) =
365+
Q (liftF (QOffset offset' q (rewriteThread (Proxy @s))))
366+
-- This uses unsafeCoerce, but should be safe since this function is tested.
367+
-- See discussion on https://github.com/haskell-beam/beam/pull/633.
368+
offsetMaybe_ Nothing (Q q) = Q (unsafeCoerce q)
369+
346370
-- | Use the SQL @EXISTS@ operator to determine if the given query returns any results
347371
exists_ :: ( BeamSqlBackend be, HasQBuilder be, Projectible be a)
348372
=> Q be db s a -> QExpr be s Bool

beam-core/test/Database/Beam/Test/SQL.hs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,9 @@ selectCombinators =
10591059
limitOffset :: TestTree
10601060
limitOffset =
10611061
testGroup "LIMIT/OFFSET support"
1062-
[ limitSupport, offsetSupport, limitOffsetSupport
1062+
[ limitSupport, maybeLimitSupportJust, maybeLimitSupportNothing
1063+
, offsetSupport, maybeOffsetSupportJust, maybeOffsetSupportNothing
1064+
, limitOffsetSupport
10631065

10641066
, limitPlacedOnUnion ]
10651067
where
@@ -1071,6 +1073,22 @@ limitOffset =
10711073
selectLimit @?= Just 20
10721074
selectOffset @?= Nothing
10731075

1076+
maybeLimitSupportJust =
1077+
testCase "Maybe LIMIT support (Just)" $
1078+
do SqlSelect Select { selectLimit, selectOffset } <-
1079+
pure $ selectMock $ limitMaybe_ (Just 20) (all_ (_employees employeeDbSettings))
1080+
1081+
selectLimit @?= Just 20
1082+
selectOffset @?= Nothing
1083+
1084+
maybeLimitSupportNothing =
1085+
testCase "Maybe LIMIT support (Nothing)" $
1086+
do SqlSelect Select { selectLimit, selectOffset } <-
1087+
pure $ selectMock $ limitMaybe_ Nothing (all_ (_employees employeeDbSettings))
1088+
1089+
selectLimit @?= Nothing
1090+
selectOffset @?= Nothing
1091+
10741092
offsetSupport =
10751093
testCase "Basic OFFSET support" $
10761094
do SqlSelect Select { selectLimit, selectOffset } <-
@@ -1079,6 +1097,22 @@ limitOffset =
10791097
selectLimit @?= Nothing
10801098
selectOffset @?= Just 102
10811099

1100+
maybeOffsetSupportJust =
1101+
testCase "Maybe OFFSET support (Just)" $
1102+
do SqlSelect Select { selectLimit, selectOffset } <-
1103+
pure $ selectMock $ offsetMaybe_ (Just 2) $ offset_ 100 (all_ (_employees employeeDbSettings))
1104+
1105+
selectLimit @?= Nothing
1106+
selectOffset @?= Just 102
1107+
1108+
maybeOffsetSupportNothing =
1109+
testCase "Maybe OFFSET support (Nothing)" $
1110+
do SqlSelect Select { selectLimit, selectOffset } <-
1111+
pure $ selectMock $ offsetMaybe_ Nothing $ offset_ 100 (all_ (_employees employeeDbSettings))
1112+
1113+
selectLimit @?= Nothing
1114+
selectOffset @?= Just 100
1115+
10821116
limitOffsetSupport =
10831117
testCase "Basic LIMIT .. OFFSET .. support" $
10841118
do SqlSelect Select { selectLimit, selectOffset } <-

0 commit comments

Comments
 (0)