Skip to content

upsertBy only ever uses the slow default implementation #855

@limick

Description

@limick

In the module Database.Persist.Sql.Orphan.PersistUnique, upsert makes use of the backend-specific implementation (if any).
upsertBy does not appear in that module and therefore always uses the inefficient default implementation.

See output from the reproduction script below:

[Debug#SQL] INSERT INTO "person"("name","age") VALUES(?,?) RETURNING "id"; [PersistText "John Doe",PersistInt64 35]
--- Using `upsert` creates SQL a query that uses UPSERT syntax:
[Debug#SQL] INSERT INTO "person"("name","age") VALUES (?,?) ON CONFLICT ("name") DO UPDATE SET "age"=? WHERE "person"."name" =? RETURNING "person"."id", "person"."name", "person"."age"; [PersistText "John Doe",PersistNull,PersistInt64 36,PersistText "John Doe"]
--- Using `upsertBy` does not:
[Debug#SQL] SELECT "id","name","age" FROM "person" WHERE "name"=?; [PersistText "John Doe"]
[Debug#SQL] UPDATE "person" SET "age"=? WHERE "id"=? ; [PersistInt64 36,PersistInt64 24]
[Debug#SQL] SELECT "id", "name", "age" FROM "person" WHERE "id"=? ; [PersistInt64 24]
[Debug#SQL] DELETE FROM "person" WHERE "id"=? ; [PersistInt64 24]

Reproduction:

#!/usr/bin/env stack
-- stack --resolver lts-12.26 script
{-# LANGUAGE EmptyDataDecls             #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE QuasiQuotes                #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeFamilies               #-}
import Control.Monad.Logger (runStdoutLoggingT)
import Control.Monad.IO.Class  (liftIO)
import Database.Persist
import Database.Persist.Postgresql
import Database.Persist.TH
import Control.Monad.Reader

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    UniquePerson name
    deriving Show Eq
BlogPost
    title String
    authorId PersonId
    deriving Show Eq
|]

main :: IO ()
main = runStdoutLoggingT $ withPostgresqlPool "dbname=persistent" 1 $ liftSqlPersistMPool $ do
  runMigration migrateAll

  johnId <- insert $ Person "John Doe" $ Just 35
  let newJohn = Person "John Doe" Nothing

  liftIO $ putStrLn "--- Using `upsert` creates a SQL query that uses UPSERT syntax:"
  upsert newJohn [PersonAge =. Just 36]

  liftIO $ putStrLn "--- Using `upsertBy` does not:"
  upsertBy (UniquePerson "John Doe") newJohn [PersonAge =. Just 36]

  delete johnId

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions