diff --git a/beam-core/Database/Beam/Query/Combinators.hs b/beam-core/Database/Beam/Query/Combinators.hs index 8f6ce2a8..d18fa921 100644 --- a/beam-core/Database/Beam/Query/Combinators.hs +++ b/beam-core/Database/Beam/Query/Combinators.hs @@ -80,6 +80,8 @@ import Control.Monad.Identity import Control.Monad.Free import Control.Applicative +import Data.List.NonEmpty (NonEmpty) +import qualified Data.List.NonEmpty as NonEmpty import Data.Maybe import Data.Proxy import Data.Time (LocalTime) @@ -105,16 +107,22 @@ allFromView_ (DatabaseEntity vw) = (tableFieldsToExpressions (dbViewSettings vw)) (\_ -> Nothing) snd) --- | SQL @VALUES@ clause. Introduce the elements of the given list as +-- | SQL @VALUES@ clause. Introduce the elements of the given non-empty list as -- rows in a joined table. values_ :: forall be db s a . ( Projectible be a , BeamSqlBackend be ) - => [ a ] -> Q be db s a + => NonEmpty a + -> Q be db s a values_ rows = - Q $ liftF (QAll (\tblPfx -> fromTable (tableFromValues (map (\row -> project (Proxy @be) row tblPfx) rows)) . Just . (,Just fieldNames)) + Q $ liftF (QAll (\tblPfx -> + fromTable + (tableFromValues (NonEmpty.toList (NonEmpty.map (\row -> project (Proxy @be) row tblPfx) rows))) + . Just + . (,Just fieldNames)) (\tblNm' -> fst $ mkFieldNames (qualifiedField tblNm')) - (\_ -> Nothing) snd) + (\_ -> Nothing) snd + ) where fieldNames = snd $ mkFieldNames @be @a unqualifiedField diff --git a/beam-postgres/test/Database/Beam/Postgres/Test/Select.hs b/beam-postgres/test/Database/Beam/Postgres/Test/Select.hs index 797c3c63..94a050f6 100644 --- a/beam-postgres/test/Database/Beam/Postgres/Test/Select.hs +++ b/beam-postgres/test/Database/Beam/Postgres/Test/Select.hs @@ -4,6 +4,7 @@ module Database.Beam.Postgres.Test.Select (tests) where import Data.Aeson import Data.ByteString (ByteString) +import qualified Data.List.NonEmpty as NonEmpty import Data.Int import qualified Data.Vector as V import Test.Tasty @@ -82,7 +83,7 @@ testUuuidInValues getConn = testCase "UUID in values_ works" $ pgCreateExtension @UuidOssp let ext = getPgExtension $ _uuidOssp $ unCheckDatabase db runSelectReturningList $ select $ do - v <- values_ [val_ nil] + v <- values_ (NonEmpty.singleton (val_ nil)) return $ pgUuidGenerateV5 ext v "" assertEqual "result" [V5.generateNamed nil []] result diff --git a/beam-sqlite/test/Database/Beam/Sqlite/Test/Select.hs b/beam-sqlite/test/Database/Beam/Sqlite/Test/Select.hs index 511de1da..9ad3263b 100644 --- a/beam-sqlite/test/Database/Beam/Sqlite/Test/Select.hs +++ b/beam-sqlite/test/Database/Beam/Sqlite/Test/Select.hs @@ -6,6 +6,8 @@ import Data.Int (Int32) import Database.Beam import Database.Beam.Sqlite +import Data.List.NonEmpty (NonEmpty(..)) +import qualified Data.List.NonEmpty as NonEmpty import Test.Tasty import Test.Tasty.ExpectedFailure import Test.Tasty.HUnit @@ -51,5 +53,5 @@ testExceptValues :: TestTree testExceptValues = testCase "EXCEPT with VALUES works" $ withTestDb $ \conn -> do result <- runBeamSqlite conn $ runSelectReturningList $ select $ - values_ [as_ @Bool $ val_ True, val_ False] `except_` values_ [val_ False] + values_ ((as_ @Bool $ val_ True) :| [ val_ False]) `except_` values_ (NonEmpty.singleton (val_ False)) assertEqual "result" [True] result diff --git a/docs/beam-templates/chinook.hs b/docs/beam-templates/chinook.hs index 3bb22ab0..f30e98ac 100644 --- a/docs/beam-templates/chinook.hs +++ b/docs/beam-templates/chinook.hs @@ -13,6 +13,7 @@ import Control.Monad import Control.Exception import Data.IORef +import Data.List.NonEmpty (NonEmpty(..)) import Data.Monoid ((<>)) import Data.Int import Data.Text diff --git a/docs/user-guide/queries/select.md b/docs/user-guide/queries/select.md index 94975d41..efeacc99 100644 --- a/docs/user-guide/queries/select.md +++ b/docs/user-guide/queries/select.md @@ -222,7 +222,7 @@ For example, to get all customers we know to be in New York, California, and Tex ```haskell !example chinook !on:Sqlite !on:MySQL do c <- all_ (customer chinookDb) - st <- values_ [ "NY", "CA", "TX" ] + st <- values_ ("NY" :| [ "CA", "TX" ]) -- (:|) is the constructor of NonEmpty guard_' (just_ st ==?. addressState (customerAddress c)) pure c ```