chreekat · GitHub

Upsert is an either/or. Either the row exists and is updated, or it does not exist and is inserted.

Persistent, however, implements a function that inserts and then updates a row that does not exist. The tests expect that behavior, even though it is incorrect. What's more, Persistent's version of upsert replaces a row that exists, rather than just updating it![*] Nowhere have I read that to be the desired behavior.

[*] An existing row is only replaced if upsert's second argument is [], but I still think that's a bug.

In short:

Expected Actual
Row Exists updated replaced if updates == []
Row Doesn't Exist inserted inserted and then updated

Correct me if I'm wrong. I'll be sending along a patch soon in the meanwhile.


Upsert: An operation that inserts rows into a database table if they do not already exist, or updates them if they do.
https://en.wiktionary.org/wiki/upsert

\

A relational database management system uses SQL MERGE (also called upsert) statements to INSERT new records or UPDATE existing records depending on whether [the given] condition matches.
https://en.wikipedia.org/wiki/Merge_(SQL)

\

"UPSERT" is a DBMS feature that allows a DML statement's author to atomically either insert a row, or on the basis of the row already existing, UPDATE that existing row instead....
https://wiki.postgresql.org/wiki/UPSERT

\

Illustrative (questionable) test:

it "upsert with updates" $ db $ do
    deleteWhere ([] :: [Filter Upsert])
    let email = "dude@example.com"
    Nothing :: Maybe (Entity Upsert) <- getBy $ UniqueUpsert email
    let up0 = Upsert email 0
    Entity _ up1 <- upsert up0 [UpsertCounter +=. 1]
    upsertCounter up1 @== 1

https://github.com/yesodweb/persistent/blob/master/persistent-test/src/PersistentTest.hs#L509

upsertCounter up1 should be 0.

Read the original on github.com ↗