beam-postgres 0.5.4.3 → 0.5.4.4
raw patch · 4 files changed
+254/−2 lines, 4 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Database.Beam.Postgres: arrayAppend_ :: QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s a -> QGenExpr ctxt Postgres s (Vector a)
+ Database.Beam.Postgres: arrayPrepend_ :: QGenExpr ctxt Postgres s a -> QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s (Vector a)
+ Database.Beam.Postgres: arrayRemove_ :: QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s a -> QGenExpr ctxt Postgres s (Vector a)
+ Database.Beam.Postgres: arrayReplace_ :: QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s a -> QGenExpr ctxt Postgres s a -> QGenExpr ctxt Postgres s (Vector a)
+ Database.Beam.Postgres: arraySample_ :: Integral n => QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s n -> QGenExpr ctxt Postgres s (Vector a)
+ Database.Beam.Postgres: arrayShuffle_ :: QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s (Vector a)
+ Database.Beam.Postgres: arrayToStringWithNull_ :: QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s Text
+ Database.Beam.Postgres: arrayToString_ :: QGenExpr ctxt Postgres s (Vector a) -> QGenExpr ctxt Postgres s Text -> QGenExpr ctxt Postgres s Text
Files
- ChangeLog.md +10/−0
- Database/Beam/Postgres/PgSpecific.hs +163/−0
- beam-postgres.cabal +2/−2
- test/Database/Beam/Postgres/Test/Select.hs +79/−0
ChangeLog.md view
@@ -1,3 +1,13 @@+# 0.5.4.4++## Added features++* Added the array functions `arrayAppend_`, `arrayPrepend_`, `arrayRemove_`, `arrayReplace_`, `arrayShuffle_`, `arraySample_`, `arrayToString_`, and `arrayToStringWithNull_` (#770)++## Updated dependencies++* Updated the upper bound on `time` to include `time-1.14`+ # 0.5.4.3 ## Added features
Database/Beam/Postgres/PgSpecific.hs view
@@ -81,6 +81,9 @@ , arrayUpper_, arrayLower_ , arrayUpperUnsafe_, arrayLowerUnsafe_ , arrayLength_, arrayLengthUnsafe_+ , arrayAppend_, arrayPrepend_, arrayRemove_+ , arrayReplace_, arrayShuffle_, arraySample_+ , arrayToString_, arrayToStringWithNull_ , isSupersetOf_, isSubsetOf_ @@ -158,6 +161,7 @@ import GHC.TypeLits import GHC.Exts hiding (toList)+import Data.Text (Text) -- ** Postgres-specific functions @@ -410,6 +414,165 @@ QExpr a ++. QExpr b = QExpr (pgBinOp "||" <$> a <*> b) +-- | Postgres array_append(value) function.+--+-- Appends an element to the end of an array. Equivalent to the+-- @anycompatiblearray || anycompatible@ operator.+--+-- Notes:+-- - The array must be empty or one-dimensional (per Postgres rules for+-- concatenating an element with an array).+-- - If the array is NULL, the result is NULL. If the element is NULL,+-- a NULL element is appended.+--+-- @since 0.5.4.4+arrayAppend_+ :: QGenExpr ctxt Postgres s (V.Vector a)+ -> QGenExpr ctxt Postgres s a+ -> QGenExpr ctxt Postgres s (V.Vector a)+arrayAppend_ (QExpr arr) (QExpr el) =+ QExpr (PgExpressionSyntax . mappend (emit "array_append") . pgParens . mconcat <$> sequenceA+ [ fromPgExpression <$> arr+ , pure (emit ", ")+ , fromPgExpression <$> el+ ])++-- | Postgres array_prepend(value) function.+--+-- Prepends an element to the beginning of an array. Equivalent to the+-- @anycompatible || anycompatiblearray@ operator.+--+-- Notes:+-- - The array must be empty or one-dimensional.+-- - If the array is NULL, the result is NULL. If the element is NULL,+-- a NULL element is prepended.+--+-- @since 0.5.4.4+arrayPrepend_+ :: QGenExpr ctxt Postgres s a+ -> QGenExpr ctxt Postgres s (V.Vector a)+ -> QGenExpr ctxt Postgres s (V.Vector a)+arrayPrepend_ (QExpr el) (QExpr arr) =+ QExpr (PgExpressionSyntax . mappend (emit "array_prepend") . pgParens . mconcat <$> sequenceA+ [ fromPgExpression <$> el+ , pure (emit ", ")+ , fromPgExpression <$> arr+ ])++-- | Postgres array_remove(value) function.+--+-- Removes all elements equal to the given value from the array.+-- Comparisons use @IS NOT DISTINCT FROM@ semantics, so this can remove NULLs.+--+-- Notes:+-- - The array must be one-dimensional.+-- - Returns NULL only if the array is NULL; if the value is not present,+-- the original array is returned unchanged.+--+-- @since 0.5.4.4+arrayRemove_+ :: QGenExpr ctxt Postgres s (V.Vector a)+ -> QGenExpr ctxt Postgres s a+ -> QGenExpr ctxt Postgres s (V.Vector a)+arrayRemove_ (QExpr arr) (QExpr el) =+ QExpr (PgExpressionSyntax . mappend (emit "array_remove") . pgParens . mconcat <$> sequenceA+ [ fromPgExpression <$> arr+ , pure (emit ", ")+ , fromPgExpression <$> el+ ])++-- | Postgres array_replace(array, from, to) function.+--+-- Replaces each element equal to the second argument with the third.+--+-- Notes:+-- - Comparisons use IS NOT DISTINCT FROM semantics; can replace NULLs.+-- - The array must be one-dimensional.+--+-- Example:+--+-- @+-- select_ $ pure $ arrayReplace_ (val_ $ V.fromList [1::Int32,2,5,4]) (val_ 5) (val_ 3)+-- -- => {1,2,3,4}+-- @+--+-- @since 0.5.4.4+arrayReplace_+ :: QGenExpr ctxt Postgres s (V.Vector a) -- ^ The array to operate on+ -> QGenExpr ctxt Postgres s a -- ^ The value to be replaced+ -> QGenExpr ctxt Postgres s a -- ^ The new value+ -> QGenExpr ctxt Postgres s (V.Vector a)+arrayReplace_ (QExpr arr) (QExpr fromVal) (QExpr toVal) =+ QExpr (PgExpressionSyntax . mappend (emit "array_replace") . pgParens . mconcat <$> sequenceA+ [ fromPgExpression <$> arr+ , pure (emit ", ")+ , fromPgExpression <$> fromVal+ , pure (emit ", ")+ , fromPgExpression <$> toVal+ ])++-- | Postgres array_shuffle(array) function.+-- Randomly shuffles the first dimension.+--+-- @since 0.5.4.4+arrayShuffle_+ :: QGenExpr ctxt Postgres s (V.Vector a)+ -> QGenExpr ctxt Postgres s (V.Vector a)+arrayShuffle_ (QExpr arr) =+ QExpr (PgExpressionSyntax . mappend (emit "array_shuffle") . pgParens . fromPgExpression <$> arr)++-- | Postgres array_sample(array, n) function.+-- Randomly selects @n@ items from the array. For multidimensional arrays,+-- an "item" is a slice with a given first subscript.+--+-- Precondition: @n@ must not exceed the length of the first dimension.+-- If n is negative, it will be treated as 0.+--+-- @since 0.5.4.4+arraySample_+ :: Integral n+ => QGenExpr ctxt Postgres s (V.Vector a) -- ^ The source array+ -> QGenExpr ctxt Postgres s n -- ^ Number of elements to sample (negative values treated as 0)+ -> QGenExpr ctxt Postgres s (V.Vector a)+arraySample_ (QExpr arr) (QExpr n) =+ QExpr (PgExpressionSyntax . mappend (emit "array_sample") . pgParens . mconcat <$> sequenceA+ [ fromPgExpression <$> arr+ , pure (emit ", greatest(0, ")+ , fromPgExpression <$> n+ , pure (emit ")")+ ])++-- | Postgres array_to_string(array, delimiter) function.+-- Converts each element to text and joins with the delimiter. NULLs are omitted.+--+-- @since 0.5.4.4+arrayToString_+ :: QGenExpr ctxt Postgres s (V.Vector a)+ -> QGenExpr ctxt Postgres s Text+ -> QGenExpr ctxt Postgres s Text+arrayToString_ (QExpr arr) (QExpr delim) =+ QExpr (PgExpressionSyntax <$> do+ arrExpr <- fromPgExpression <$> arr+ delimExpr <- fromPgExpression <$> delim+ pure $ emit "array_to_string" <> pgParens (arrExpr <> emit ", " <> delimExpr))++-- | Postgres array_to_string(array, delimiter, null_string) function.+-- Converts each element to text and joins with the delimiter. NULLs are+-- represented by the provided @null_string@.+--+-- @since 0.5.4.4+arrayToStringWithNull_+ :: QGenExpr ctxt Postgres s (V.Vector a)+ -> QGenExpr ctxt Postgres s Text+ -> QGenExpr ctxt Postgres s Text+ -> QGenExpr ctxt Postgres s Text+arrayToStringWithNull_ (QExpr arr) (QExpr delim) (QExpr nullStr) =+ QExpr (PgExpressionSyntax <$> do+ arrExpr <- fromPgExpression <$> arr+ delimExpr <- fromPgExpression <$> delim+ nullStrExpr <- fromPgExpression <$> nullStr+ pure $ emit "array_to_string" <>+ pgParens (mconcat [arrExpr, emit ", ", delimExpr, emit ", ", nullStrExpr])) -- ** Array expressions -- | An expression context that determines which types of expressions can be put
beam-postgres.cabal view
@@ -1,5 +1,5 @@ name: beam-postgres-version: 0.5.4.3+version: 0.5.4.4 synopsis: Connection layer between beam and postgres description: Beam driver for <https://www.postgresql.org/ PostgreSQL>, an advanced open-source RDBMS homepage: https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres@@ -46,7 +46,7 @@ hashable >=1.1 && <1.6, lifted-base >=0.2 && <0.3, free >=4.12 && <5.3,- time >=1.6 && <1.13,+ time >=1.6 && <1.15, monad-control >=1.0 && <1.1, mtl >=2.1 && <2.4, conduit >=1.2 && <1.4,
test/Database/Beam/Postgres/Test/Select.hs view
@@ -5,6 +5,8 @@ import Data.Aeson import Data.ByteString (ByteString) import Data.Int+import Data.List (sort)+import qualified Data.Text as T import qualified Data.Vector as V import Test.Tasty import Test.Tasty.HUnit@@ -24,6 +26,16 @@ [ testGroup "JSON" [ testPgArrayToJSON getConn ]+ , testGroup "ARRAY functions"+ [ testArrayReplace getConn+ , testArrayShuffle getConn+ , testArraySample getConn+ , testArrayToStringBasic getConn+ , testArrayToStringWithNull getConn+ , testArrayAppend getConn+ , testArrayPrepend getConn+ , testArrayRemove getConn+ ] , testGroup "UUID" [ testUuidFunction getConn "uuid_nil" $ \ext -> pgUuidNil ext , testUuidFunction getConn "uuid_ns_dns" $ \ext -> pgUuidNsDns ext@@ -55,6 +67,73 @@ runBeamPostgres conn $ runSelectReturningList $ select $ return $ pgArrayToJson $ val_ $ V.fromList values assertEqual "JSON list" [PgJSON $ toJSON values] actual++testArrayReplace :: IO ByteString -> TestTree+testArrayReplace getConn = testFunction getConn "array_replace" $ \conn -> do+ let arr = V.fromList [1::Int32,2,5,4]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayReplace_ (val_ arr) (val_ (5::Int32)) (val_ (3::Int32))+ assertEqual "array_replace" [V.fromList [1,2,3,4 :: Int32]] res++testArrayShuffle :: IO ByteString -> TestTree+testArrayShuffle getConn = testFunction getConn "array_shuffle" $ \conn -> do+ let arr = V.fromList [1::Int32,2,3,4,5]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayShuffle_ (val_ arr)+ -- shuffled result has same length and elements, order may change+ case res of+ [shuf] -> do+ assertEqual "length" (V.length arr) (V.length shuf)+ assertBool "is permutation"+ (sort (V.toList arr) == sort (V.toList shuf))+ _ -> assertFailure "unexpected result"++testArraySample :: IO ByteString -> TestTree+testArraySample getConn = testFunction getConn "array_sample" $ \conn -> do+ let arr = V.fromList [1::Int32,2,3,4,5,6]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arraySample_ (val_ arr) (val_ (3::Int32))+ case res of+ [samp] -> do+ assertEqual "length 3" 3 (V.length samp)+ assertBool "subset" (V.all (`V.elem` arr) samp)+ _ -> assertFailure "unexpected result"++testArrayToStringBasic :: IO ByteString -> TestTree+testArrayToStringBasic getConn = testFunction getConn "array_to_string_basic" $ \conn -> do+ let arr = V.fromList [1::Int32,2,3]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayToString_ (val_ arr) (val_ ",")+ assertEqual "join" ["1,2,3" :: T.Text] res++testArrayToStringWithNull :: IO ByteString -> TestTree+testArrayToStringWithNull getConn = testFunction getConn "array_to_string_with_null" $ \conn -> do+ let arr :: V.Vector (Maybe T.Text)+ arr = V.fromList [Just "a", Nothing, Just "b"]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayToStringWithNull_ (val_ arr) (val_ "-") (val_ "*")+ assertEqual "join with null" ["a-*-b" :: T.Text] res++testArrayAppend :: IO ByteString -> TestTree+testArrayAppend getConn = testFunction getConn "array_append" $ \conn -> do+ let arr = V.fromList [1::Int32,2]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayAppend_ (val_ arr) (val_ (3::Int32))+ assertEqual "append" [V.fromList [1,2,3 :: Int32]] res++testArrayPrepend :: IO ByteString -> TestTree+testArrayPrepend getConn = testFunction getConn "array_prepend" $ \conn -> do+ let arr = V.fromList [2::Int32,3]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayPrepend_ (val_ (1::Int32)) (val_ arr)+ assertEqual "prepend" [V.fromList [1,2,3 :: Int32]] res++testArrayRemove :: IO ByteString -> TestTree+testArrayRemove getConn = testFunction getConn "array_remove" $ \conn -> do+ let arr = V.fromList [1::Int32,2,3,2]+ res <- runBeamPostgres conn $ runSelectReturningList $ select $ do+ pure $ arrayRemove_ (val_ arr) (val_ (2::Int32))+ assertEqual "remove" [V.fromList [1,3 :: Int32]] res data UuidSchema f = UuidSchema { _uuidOssp :: f (PgExtensionEntity UuidOssp)