From 701cccfb2b496b69ee368020af780a81b3031ef9 Mon Sep 17 00:00:00 2001 From: Cavdy Date: Thu, 3 Sep 2026 00:46:42 +0100 Subject: [PATCH 1/2] add support for multiple where conditions for update --- src/Database/PostgreSQL/Entity.hs | 62 ++++++++++++++++++++++++++----- test/EntitySpec.hs | 14 +++++++ 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/Database/PostgreSQL/Entity.hs b/src/Database/PostgreSQL/Entity.hs index 94c2ace..44fc819 100644 --- a/src/Database/PostgreSQL/Entity.hs +++ b/src/Database/PostgreSQL/Entity.hs @@ -43,6 +43,7 @@ module Database.PostgreSQL.Entity -- ** Update , update , updateFieldsBy + , updateFieldsWhere -- ** Deletion , delete @@ -73,6 +74,7 @@ module Database.PostgreSQL.Entity , _updateBy , _updateFields , _updateFieldsBy + , _updateFieldsWhere -- ** Deletion , _delete @@ -361,6 +363,28 @@ updateFieldsBy -> DBT m Int64 updateFieldsBy fs (f, oldValue) newValue = execute (_updateFieldsBy @e fs f) (toRow newValue ++ toRow (Only oldValue)) +{-| Update rows of an entity matching the given values + + == Example + + > let newName = "Tiberus McElroy" :: Text + > let oldName = "Johnson McElroy" :: Text + > updateFieldsWhere @Author [[field| name |]] [[field| name |]] (newName,oldName) + + @since 0.0.1.0 +-} +updateFieldsWhere + :: forall e values m + . (Entity e, MonadIO m, ToRow values) + => Vector Field + -- ^ Fields to change + -> Vector Field + -- ^ Field on which to match and its value + -> values + -- ^ Values of those fields + -> DBT m Int64 +updateFieldsWhere fs f values = execute (_updateFieldsWhere @e fs f) values + {-| Delete an entity according to its primary key. @since 0.0.1.0 @@ -683,25 +707,25 @@ _updateBy f = _updateFieldsBy @e (fields @e) f _updateFields :: forall e. Entity e => Vector Field -> Query _updateFields fs = _updateFieldsBy @e fs (primaryKey @e) -{-| Produce an UPDATE statement for the given entity and fields, by the specified field. +{-| Produce an UPDATE statement for the given entity and fields, by the specified fields. - >>> _updateFieldsBy @Author [ [field| name |] ] [field| name |] - "UPDATE \"authors\" SET (\"name\") = ROW(?) WHERE \"name\" = ?" + >>> _updateFieldsWhere @Author [[field| name |]] [[field| author_id |], [field| name |]] + "UPDATE \"authors\" SET (\"name\") = ROW(?) WHERE \"author_id\" = ? AND \"name\" = ?" - >>> _updateFieldsBy @BlogPost [[field| author_id |], [field| title |]] [field| title |] - "UPDATE \"blogposts\" SET (\"author_id\", \"title\") = ROW(?, ?) WHERE \"title\" = ?" + >>> _updateFieldsWhere @BlogPost [[field| author_id |], [field| title |]] [[field| blogpost_id |], [field| title |]] + "UPDATE \"blogposts\" SET (\"author_id\", \"title\") = ROW(?, ?) WHERE \"blogpost_id\" = ? AND \"title\" = ?" @since 0.0.1.0 -} -_updateFieldsBy +_updateFieldsWhere :: forall e . Entity e => Vector Field -- ^ Field names to update - -> Field + -> Vector Field -- ^ Field on which to match -> Query -_updateFieldsBy fs' f = +_updateFieldsWhere fs' f = textToQuery ( "UPDATE " <> getTableName @e @@ -710,7 +734,7 @@ _updateFieldsBy fs' f = <> " = " <> newValues ) - <> _where [f] + <> _where f where fs = V.filter (/= (primaryKey @e)) fs' newValues = "ROW" <> inParens (generatePlaceholders fs) @@ -718,6 +742,26 @@ _updateFieldsBy fs' f = inParens $ V.foldl1' (\element acc -> element <> ", " <> acc) (quoteName . fieldName <$> fs) +{-| Produce an UPDATE statement for the given entity and fields, by the specified field. + + >>> _updateFieldsBy @Author [ [field| name |] ] [field| name |] + "UPDATE \"authors\" SET (\"name\") = ROW(?) WHERE \"name\" = ?" + + >>> _updateFieldsBy @BlogPost [[field| author_id |], [field| title |]] [field| title |] + "UPDATE \"blogposts\" SET (\"author_id\", \"title\") = ROW(?, ?) WHERE \"title\" = ?" + + @since 0.0.1.0 +-} +_updateFieldsBy + :: forall e + . Entity e + => Vector Field + -- ^ Field names to update + -> Field + -- ^ Field on which to match + -> Query +_updateFieldsBy fs' = _updateFieldsWhere @e fs' . V.singleton + {-| Produce a DELETE statement for the given entity, with a match on the Primary Key __Examples__ diff --git a/test/EntitySpec.hs b/test/EntitySpec.hs index 4554ef7..6b399c8 100644 --- a/test/EntitySpec.hs +++ b/test/EntitySpec.hs @@ -32,6 +32,7 @@ import Database.PostgreSQL.Entity , selectWhereNull , update , updateFieldsBy + , updateFieldsWhere , _joinSelectWithFields , _where ) @@ -165,6 +166,19 @@ changeAuthorName = do result3 <- liftDB $ updateFieldsBy @Author [[field| name |]] ([field| name |], oldName) (Only newName) U.assertEqual 1 result3 + let staleName = "Jane McElroy" :: Text + liftDB $ instantiateRandomAuthor randomAuthorTemplate{generateName = pure staleName} + let freshName = "Sarah McElroy" :: Text + result4 <- liftDB $ updateFieldsWhere @Author [[field| name |]] [[field| name |]] (freshName, staleName) + U.assertEqual 1 result4 + + let previousName = "Andrew Garfield" :: Text + currentName = "Cat Garfield" :: Text + author3 <- liftDB $ instantiateRandomAuthor randomAuthorTemplate{generateName = pure previousName} + let newAuthor3Id = UUID.toText $ getAuthorId $ #authorId author3 :: Text + result5 <- liftDB $ updateFieldsWhere @Author [[field| name |]] [[field| author_id |], [field| name |]] (currentName, newAuthor3Id, previousName) + U.assertEqual 1 result5 + selectWhereIn :: TestM () selectWhereIn = do author <- liftDB $ instantiateRandomAuthor randomAuthorTemplate From b65cceea114cf24ef8307886fe7b1756eaad2378 Mon Sep 17 00:00:00 2001 From: Cavdy Date: Thu, 3 Sep 2026 10:13:50 +0100 Subject: [PATCH 2/2] add support for multiple where conditions for update --- src/Database/PostgreSQL/Entity.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Database/PostgreSQL/Entity.hs b/src/Database/PostgreSQL/Entity.hs index 44fc819..20f7f25 100644 --- a/src/Database/PostgreSQL/Entity.hs +++ b/src/Database/PostgreSQL/Entity.hs @@ -371,7 +371,7 @@ updateFieldsBy fs (f, oldValue) newValue = execute (_updateFieldsBy @e fs f) (to > let oldName = "Johnson McElroy" :: Text > updateFieldsWhere @Author [[field| name |]] [[field| name |]] (newName,oldName) - @since 0.0.1.0 + @since TODO -} updateFieldsWhere :: forall e values m @@ -715,7 +715,7 @@ _updateFields fs = _updateFieldsBy @e fs (primaryKey @e) >>> _updateFieldsWhere @BlogPost [[field| author_id |], [field| title |]] [[field| blogpost_id |], [field| title |]] "UPDATE \"blogposts\" SET (\"author_id\", \"title\") = ROW(?, ?) WHERE \"blogpost_id\" = ? AND \"title\" = ?" - @since 0.0.1.0 + @since TODO -} _updateFieldsWhere :: forall e