    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TypeOperators #-}

    module Database.Persist.Class.PersistUnique
        ( PersistUniqueRead(..)
        , PersistUniqueWrite(..)
        , OnlyOneUniqueKey(..)
        , onlyOneUniqueDef
        , AtLeastOneUniqueKey(..)
        , atLeastOneUniqueDef
        , NoUniqueKeysError
        , MultipleUniqueKeysError
        , getByValue
        , getByValueUniques
        , insertBy
        , insertUniqueEntity
        , replaceUnique
        , checkUnique
        , checkUniqueUpdateable
        , onlyUnique
        , defaultUpsertBy
        , defaultPutMany
        , persistUniqueKeyValues
        )
        where

    import Control.Monad (liftM)
    import Control.Monad.IO.Class (MonadIO)
    import Control.Monad.Trans.Reader (ReaderT)
    import Data.Function (on)
    import Data.List (deleteFirstsBy, (\\))
    import Data.List.NonEmpty (NonEmpty(..))
    import qualified Data.List.NonEmpty as NEL
    import qualified Data.Map as Map
    import Data.Maybe (catMaybes, isJust)
    import GHC.TypeLits (ErrorMessage(..))

    import Database.Persist.Class.PersistEntity
    import Database.Persist.Class.PersistStore
    import Database.Persist.Types

    -- | Queries against 'Unique' keys (other than the id 'Key').
    --
    -- Please read the general Persistent documentation to learn how to create
    -- 'Unique' keys.
    --
    -- Using this with an Entity without a Unique key leads to undefined
    -- behavior.  A few of these functions require a /single/ 'Unique', so using
    -- an Entity with multiple 'Unique's is also undefined. In these cases
    -- persistent's goal is to throw an exception as soon as possible, but
    -- persistent is still transitioning to that.
    --
    -- SQL backends automatically create uniqueness constraints, but for MongoDB
    -- you must manually place a unique index on a field to have a uniqueness
    -- constraint.
    --
    class PersistStoreRead backend => PersistUniqueRead backend  where
        -- | Get a record by unique key, if available. Returns also the identifier.
        --
        -- === __Example usage__
        --
        -- With <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>:
        --
        -- > getBySpjName :: MonadIO m  => ReaderT SqlBackend m (Maybe (Entity User))
        -- > getBySpjName = getBy $ UniqueUserName "SPJ"
        --
        -- > mSpjEnt <- getBySpjName
        --
        -- The above query when applied on <#dataset-persist-unique-1 dataset-1>, will get this entity:
        --
        -- > +----+------+-----+
        -- > | id | name | age |
        -- > +----+------+-----+
        -- > |  1 | SPJ  |  40 |
        -- > +----+------+-----+
        getBy
            :: forall record m. (MonadIO m, PersistRecordBackend record backend)
            => Unique record -> ReaderT backend m (Maybe (Entity record))

        -- | Returns True if a record with this unique key exists, otherwise False.
        --
        -- === __Example usage__
        --
        -- With <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>:
        --
        -- > existsBySpjName :: MonadIO m  => ReaderT SqlBackend m Bool
        -- > existsBySpjName = existsBy $ UniqueUserName "SPJ"
        --
        -- > spjEntExists <- existsBySpjName
        --
        -- The above query when applied on <#dataset-persist-unique-1 dataset-1>, will return
        -- the value True.
        --
        -- @since 2.14.5
        existsBy
            :: forall record m. (MonadIO m, PersistRecordBackend record backend)
            => Unique record -> ReaderT backend m Bool
        existsBy Unique record
    uniq = Maybe (Entity record) -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe (Entity record) -> Bool)
    -> ReaderT backend m (Maybe (Entity record))
    -> ReaderT backend m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Unique record -> ReaderT backend m (Maybe (Entity record))
    forall backend record (m :: * -> *).
    (PersistUniqueRead backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    getBy Unique record
    uniq

    -- | Some functions in this module ('insertUnique', 'insertBy', and
    -- 'replaceUnique') first query the unique indexes to check for
    -- conflicts. You could instead optimistically attempt to perform the
    -- operation (e.g. 'replace' instead of 'replaceUnique'). However,
    --
    --  * there is some fragility to trying to catch the correct exception and
    --  determing the column of failure;
    --
    --  * an exception will automatically abort the current SQL transaction.
    class (PersistUniqueRead backend, PersistStoreWrite backend) =>
          PersistUniqueWrite backend  where
        -- | Delete a specific record by unique key. Does nothing if no record
        -- matches.
        --
        -- === __Example usage__
        --
        -- With <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>,
        --
        -- > deleteBySpjName :: MonadIO m => ReaderT SqlBackend m ()
        -- > deleteBySpjName = deleteBy (UniqueUserName "SPJ")
        --
        -- The above query when applied on <#dataset-persist-unique-1 dataset-1>, will produce this:
        --
        -- > +-----+------+-----+
        -- > |id   |name  |age  |
        -- > +-----+------+-----+
        -- > |2    |Simon |41   |
        -- > +-----+------+-----+
        deleteBy
            :: forall record m. (MonadIO m, PersistRecordBackend record backend)
            => Unique record -> ReaderT backend m ()

        -- | Like 'insert', but returns 'Nothing' when the record
        -- couldn't be inserted because of a uniqueness constraint.
        --
        -- === __Example usage__
        --
        -- With <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>, we try to insert the following two records:
        --
        -- > linusId <- insertUnique $ User "Linus" 48
        -- > spjId   <- insertUnique $ User "SPJ" 90
        --
        -- > +-----+------+-----+
        -- > |id   |name  |age  |
        -- > +-----+------+-----+
        -- > |1    |SPJ   |40   |
        -- > +-----+------+-----+
        -- > |2    |Simon |41   |
        -- > +-----+------+-----+
        -- > |3    |Linus |48   |
        -- > +-----+------+-----+
        --
        -- Linus's record was inserted to <#dataset-persist-unique-1 dataset-1>, while SPJ wasn't because SPJ already exists in <#dataset-persist-unique-1 dataset-1>.
        insertUnique
            :: forall record m. (MonadIO m, PersistRecordBackend record backend, SafeToInsert record)
            => record -> ReaderT backend m (Maybe (Key record))
        insertUnique record
    datum = do
            conflict <- record -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     PersistUniqueRead backend) =>
    record -> ReaderT backend m (Maybe (Unique record))
    checkUnique record
    datum
            case conflict of
                Maybe (Unique record)
    Nothing -> Key record -> Maybe (Key record)
    forall a. a -> Maybe a
    Just (Key record -> Maybe (Key record))
    -> ReaderT backend m (Key record)
    -> ReaderT backend m (Maybe (Key record))
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    `liftM` record -> ReaderT backend m (Key record)
    forall backend record (m :: * -> *).
    (PersistStoreWrite backend, MonadIO m,
     PersistRecordBackend record backend, SafeToInsert record) =>
    record -> ReaderT backend m (Key record)
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     SafeToInsert record) =>
    record -> ReaderT backend m (Key record)
    insert record
    datum
                Just Unique record
    _ -> Maybe (Key record) -> ReaderT backend m (Maybe (Key record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Key record)
    forall a. Maybe a
    Nothing

        -- | Same as 'insertUnique' but doesn't return a @Key@.
        --
        -- === __Example usage__
        --
        -- With <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>, we try to insert the following two records:
        --
        -- > linusId <- insertUnique_ $ User "Linus" 48
        -- > spjId   <- insertUnique_ $ User "SPJ" 90
        --
        -- > +-----+------+-----+
        -- > |id   |name  |age  |
        -- > +-----+------+-----+
        -- > |1    |SPJ   |40   |
        -- > +-----+------+-----+
        -- > |2    |Simon |41   |
        -- > +-----+------+-----+
        -- > |3    |Linus |48   |
        -- > +-----+------+-----+
        --
        -- Linus's record was inserted to <#dataset-persist-unique-1 dataset-1>, while SPJ wasn't because SPJ already exists in <#dataset-persist-unique-1 dataset-1>.
        --
        -- @since 2.14.5.0
        insertUnique_
            :: forall record m. (MonadIO m, PersistRecordBackend record backend, SafeToInsert record)
            => record -> ReaderT backend m (Maybe ())
        insertUnique_ record
    datum = do
            conflict <- record -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     PersistUniqueRead backend) =>
    record -> ReaderT backend m (Maybe (Unique record))
    checkUnique record
    datum
            case conflict of
                Maybe (Unique record)
    Nothing -> () -> Maybe ()
    forall a. a -> Maybe a
    Just (() -> Maybe ())
    -> ReaderT backend m () -> ReaderT backend m (Maybe ())
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    `liftM` record -> ReaderT backend m ()
    forall backend record (m :: * -> *).
    (PersistStoreWrite backend, MonadIO m,
     PersistRecordBackend record backend, SafeToInsert record) =>
    record -> ReaderT backend m ()
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     SafeToInsert record) =>
    record -> ReaderT backend m ()
    insert_ record
    datum
                Just Unique record
    _ -> Maybe () -> ReaderT backend m (Maybe ())
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ()
    forall a. Maybe a
    Nothing

        -- | Update based on a uniqueness constraint or insert:
        --
        -- * insert the new record if it does not exist;
        -- * If the record exists (matched via it's uniqueness constraint), then update the existing record with the parameters which is passed on as list to the function.
        --
        -- === __Example usage__
        --
        -- First, we try to explain 'upsert' using <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>.
        --
        -- > upsertSpj :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User))
        -- > upsertSpj updates = upsert (User "SPJ" 999) updates
        --
        -- > mSpjEnt <- upsertSpj [UserAge +=. 15]
        --
        -- The above query when applied on <#dataset-persist-unique-1 dataset-1>, will produce this:
        --
        -- > +-----+-----+--------+
        -- > |id   |name |age     |
        -- > +-----+-----+--------+
        -- > |1    |SPJ  |40 -> 55|
        -- > +-----+-----+--------+
        -- > |2    |Simon|41      |
        -- > +-----+-----+--------+
        --
        -- > upsertX :: MonadIO m => [Update User] -> ReaderT SqlBackend m (Maybe (Entity User))
        -- > upsertX updates = upsert (User "X" 999) updates
        --
        -- > mXEnt <- upsertX [UserAge +=. 15]
        --
        -- The above query when applied on <#dataset-persist-unique-1 dataset-1>, will produce this:
        --
        -- > +-----+-----+--------+
        -- > |id   |name |age     |
        -- > +-----+-----+--------+
        -- > |1    |SPJ  |40      |
        -- > +-----+-----+--------+
        -- > |2    |Simon|41      |
        -- > +-----+-----+--------+
        -- > |3    |X    |999     |
        -- > +-----+-----+--------+
        --
        -- Next, what if the schema has two uniqueness constraints?
        -- Let's check it out using <#schema-persist-unique-2 schema-2>:
        --
        -- > mSpjEnt <- upsertSpj [UserAge +=. 15]
        --
        -- This fails with a compile-time type error alerting us to the fact
        -- that this record has multiple unique keys, and suggests that we look for
        -- 'upsertBy' to select the unique key we want.
        upsert
            :: forall record m. (MonadIO m, PersistRecordBackend record backend, OnlyOneUniqueKey record, SafeToInsert record)
            => record
            -- ^ new record to insert
            -> [Update record]
            -- ^ updates to perform if the record already exists
            -> ReaderT backend m (Entity record)
            -- ^ the record in the database after the operation
        upsert record
    record [Update record]
    updates = do
            uniqueKey <- record -> ReaderT backend m (Unique record)
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueWrite backend,
     PersistRecordBackend record backend, OnlyOneUniqueKey record) =>
    record -> ReaderT backend m (Unique record)
    onlyUnique record
    record
            upsertBy uniqueKey record updates

        -- | Update based on a given uniqueness constraint or insert:
        --
        -- * insert the new record if it does not exist;
        -- * update the existing record that matches the given uniqueness constraint.
        --
        -- === __Example usage__
        --
        -- We try to explain 'upsertBy' using <#schema-persist-unique-2 schema-2> and <#dataset-persist-unique-1 dataset-1>.
        --
        -- > upsertBySpjName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
        -- > upsertBySpjName record updates = upsertBy (UniqueUserName "SPJ") record updates
        --
        -- > mSpjEnt <- upsertBySpjName (Person "X" 999) [PersonAge += .15]
        --
        -- The above query will alter <#dataset-persist-unique-1 dataset-1> to:
        --
        -- > +-----+-----+--------+
        -- > |id   |name |age     |
        -- > +-----+-----+--------+
        -- > |1    |SPJ  |40 -> 55|
        -- > +-----+-----+--------+
        -- > |2    |Simon|41      |
        -- > +-----+-----+--------+
        --
        -- > upsertBySimonAge :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
        -- > upsertBySimonAge record updates = upsertBy (UniqueUserName "SPJ") record updates
        --
        -- > mPhilipEnt <- upsertBySimonAge (User "X" 999) [UserName =. "Philip"]
        --
        -- The above query will alter <#dataset-persist-unique-1 dataset-1> to:
        --
        -- > +----+-----------------+-----+
        -- > | id |      name       | age |
        -- > +----+-----------------+-----+
        -- > |  1 | SPJ             |  40 |
        -- > +----+-----------------+-----+
        -- > |  2 | Simon -> Philip |  41 |
        -- > +----+-----------------+-----+
        --
        -- > upsertByUnknownName :: MonadIO m => User -> [Update User] -> ReaderT SqlBackend m (Entity User)
        -- > upsertByUnknownName record updates = upsertBy (UniqueUserName "Unknown") record updates
        --
        -- > mXEnt <- upsertByUnknownName (User "X" 999) [UserAge +=. 15]
        --
        -- This query will alter <#dataset-persist-unique-1 dataset-1> to:
        --
        -- > +-----+-----+-----+
        -- > |id   |name |age  |
        -- > +-----+-----+-----+
        -- > |1    |SPJ  |40   |
        -- > +-----+-----+-----+
        -- > |2    |Simon|41   |
        -- > +-----+-----+-----+
        -- > |3    |X    |999  |
        -- > +-----+-----+-----+
        upsertBy
            :: forall record m. (MonadIO m, PersistRecordBackend record backend, SafeToInsert record)
            => Unique record
            -- ^ uniqueness constraint to find by
            -> record
            -- ^ new record to insert
            -> [Update record]
            -- ^ updates to perform if the record already exists
            -> ReaderT backend m (Entity record)
            -- ^ the record in the database after the operation
        upsertBy = Unique record
    -> record -> [Update record] -> ReaderT backend m (Entity record)
    forall record backend (m :: * -> *).
    (PersistEntityBackend record ~ BaseBackend backend,
     PersistEntity record, MonadIO m, PersistStoreWrite backend,
     PersistUniqueRead backend, SafeToInsert record) =>
    Unique record
    -> record -> [Update record] -> ReaderT backend m (Entity record)
    defaultUpsertBy

        -- | Put many records into db
        --
        -- * insert new records that do not exist (or violate any unique constraints)
        -- * replace existing records (matching any unique constraint)
        --
        -- @since 2.8.1
        putMany
            :: forall record m.
            ( MonadIO m
            , PersistRecordBackend record backend
            , SafeToInsert record
            )
            => [record]
            -- ^ A list of the records you want to insert or replace.
            -> ReaderT backend m ()
        putMany = [record] -> ReaderT backend m ()
    forall record backend (m :: * -> *).
    (PersistEntityBackend record ~ BaseBackend backend,
     PersistEntity record, MonadIO m, PersistStoreWrite backend,
     PersistUniqueRead backend, SafeToInsert record) =>
    [record] -> ReaderT backend m ()
    defaultPutMany

    -- | This class is used to ensure that 'upsert' is only called on records
    -- that have a single 'Unique' key. The quasiquoter automatically generates
    -- working instances for appropriate records, and generates 'TypeError'
    -- instances for records that have 0 or multiple unique keys.
    --
    -- @since 2.10.0
    class PersistEntity record => OnlyOneUniqueKey record where
        onlyUniqueP :: record -> Unique record

    -- | Given a proxy for a 'PersistEntity' record, this returns the sole
    -- 'UniqueDef' for that entity.
    --
    -- @since 2.13.0.0
    onlyOneUniqueDef
        :: (OnlyOneUniqueKey record, Monad proxy)
        => proxy record
        -> UniqueDef
    onlyOneUniqueDef :: forall record (proxy :: * -> *).
    (OnlyOneUniqueKey record, Monad proxy) =>
    proxy record -> UniqueDef
    onlyOneUniqueDef proxy record
    prxy =
        case EntityDef -> [UniqueDef]
    getEntityUniques (proxy record -> EntityDef
    forall record (proxy :: * -> *).
    PersistEntity record =>
    proxy record -> EntityDef
    forall (proxy :: * -> *). proxy record -> EntityDef
    entityDef proxy record
    prxy) of
            [UniqueDef
    uniq] -> UniqueDef
    uniq
            [UniqueDef]
    _ -> [Char] -> UniqueDef
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "impossible due to OnlyOneUniqueKey constraint"

    -- | This is an error message. It is used when writing instances of
    -- 'OnlyOneUniqueKey' for an entity that has no unique keys.
    --
    -- @since 2.10.0
    type NoUniqueKeysError ty =
        'Text "The entity "
            ':<>: 'ShowType ty
            ':<>: 'Text " does not have any unique keys."
        ':$$: 'Text "The function you are trying to call requires a unique key "
            ':<>: 'Text "to be defined on the entity."

    -- | This is an error message. It is used when an entity has multiple
    -- unique keys, and the function expects a single unique key.
    --
    -- @since 2.10.0
    type MultipleUniqueKeysError ty =
        'Text "The entity "
            ':<>: 'ShowType ty
            ':<>: 'Text " has multiple unique keys."
        ':$$: 'Text "The function you are trying to call requires only a single "
            ':<>: 'Text "unique key."
        ':$$: 'Text "There is probably a variant of the function with 'By' "
            ':<>: 'Text "appended that will allow you to select a unique key "
            ':<>: 'Text "for the operation."

    -- | This class is used to ensure that functions requring at least one
    -- unique key are not called with records that have 0 unique keys. The
    -- quasiquoter automatically writes working instances for appropriate
    -- entities, and generates 'TypeError' instances for records that have
    -- 0 unique keys.
    --
    -- @since 2.10.0
    class PersistEntity record => AtLeastOneUniqueKey record where
        requireUniquesP :: record -> NonEmpty (Unique record)

    -- | Given a proxy for a record that has an instance of
    -- 'AtLeastOneUniqueKey', this returns a 'NonEmpty' list of the
    -- 'UniqueDef's for that entity.
    --
    -- @since 2.10.0
    atLeastOneUniqueDef
        :: (AtLeastOneUniqueKey record, Monad proxy)
        => proxy record
        -> NonEmpty UniqueDef
    atLeastOneUniqueDef :: forall record (proxy :: * -> *).
    (AtLeastOneUniqueKey record, Monad proxy) =>
    proxy record -> NonEmpty UniqueDef
    atLeastOneUniqueDef proxy record
    prxy =
        case EntityDef -> [UniqueDef]
    getEntityUniques (proxy record -> EntityDef
    forall record (proxy :: * -> *).
    PersistEntity record =>
    proxy record -> EntityDef
    forall (proxy :: * -> *). proxy record -> EntityDef
    entityDef proxy record
    prxy) of
            (UniqueDef
    x:[UniqueDef]
    xs) -> UniqueDef
    x UniqueDef -> [UniqueDef] -> NonEmpty UniqueDef
    forall a. a -> [a] -> NonEmpty a
    :| [UniqueDef]
    xs
            [UniqueDef]
    _ ->
                [Char] -> NonEmpty UniqueDef
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "impossible due to AtLeastOneUniqueKey record constraint"

    -- | Insert a value, checking for conflicts with any unique constraints.  If a
    -- duplicate exists in the database, it is returned as 'Left'. Otherwise, the
    -- new 'Key is returned as 'Right'.
    --
    -- === __Example usage__
    --
    -- With <#schema-persist-unique-2 schema-2> and <#dataset-persist-unique-1 dataset-1>, we have following lines of code:
    --
    -- > l1 <- insertBy $ User "SPJ" 20
    -- > l2 <- insertBy $ User "XXX" 41
    -- > l3 <- insertBy $ User "SPJ" 40
    -- > r1 <- insertBy $ User "XXX" 100
    --
    -- First three lines return 'Left' because there're duplicates in given record's uniqueness constraints. While the last line returns a new key as 'Right'.
    insertBy
        :: forall record backend m.
        ( MonadIO m
        , PersistUniqueWrite backend
        , PersistRecordBackend record backend
        , AtLeastOneUniqueKey record
        , SafeToInsert record
        )
        => record -> ReaderT backend m (Either (Entity record) (Key record))
    insertBy :: forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueWrite backend,
     PersistRecordBackend record backend, AtLeastOneUniqueKey record,
     SafeToInsert record) =>
    record -> ReaderT backend m (Either (Entity record) (Key record))
    insertBy record
    val = do
        res <- record -> ReaderT backend m (Maybe (Entity record))
    forall record (m :: * -> *) backend.
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend, AtLeastOneUniqueKey record) =>
    record -> ReaderT backend m (Maybe (Entity record))
    getByValue record
    val
        case res of
            Maybe (Entity record)
    Nothing -> Key record -> Either (Entity record) (Key record)
    forall a b. b -> Either a b
    Right (Key record -> Either (Entity record) (Key record))
    -> ReaderT backend m (Key record)
    -> ReaderT backend m (Either (Entity record) (Key record))
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    `liftM` record -> ReaderT backend m (Key record)
    forall backend record (m :: * -> *).
    (PersistStoreWrite backend, MonadIO m,
     PersistRecordBackend record backend, SafeToInsert record) =>
    record -> ReaderT backend m (Key record)
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     SafeToInsert record) =>
    record -> ReaderT backend m (Key record)
    insert record
    val
            Just Entity record
    z -> Either (Entity record) (Key record)
    -> ReaderT backend m (Either (Entity record) (Key record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either (Entity record) (Key record)
     -> ReaderT backend m (Either (Entity record) (Key record)))
    -> Either (Entity record) (Key record)
    -> ReaderT backend m (Either (Entity record) (Key record))
    forall a b. (a -> b) -> a -> b
    $ Entity record -> Either (Entity record) (Key record)
    forall a b. a -> Either a b
    Left Entity record
    z

    -- | Like 'insertEntity', but returns 'Nothing' when the record
    -- couldn't be inserted because of a uniqueness constraint.
    --
    -- @since 2.7.1
    --
    -- === __Example usage__
    --
    -- We use <#schema-persist-unique-2 schema-2> and <#dataset-persist-unique-1 dataset-1> here.
    --
    -- > insertUniqueSpjEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
    -- > insertUniqueSpjEntity = insertUniqueEntity $ User "SPJ" 50
    --
    -- > mSpjEnt <- insertUniqueSpjEntity
    --
    -- The above query results 'Nothing' as SPJ already exists.
    --
    -- > insertUniqueAlexaEntity :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
    -- > insertUniqueAlexaEntity = insertUniqueEntity $ User "Alexa" 3
    --
    -- > mAlexaEnt <- insertUniqueSpjEntity
    --
    -- Because there's no such unique keywords of the given record, the above query when applied on <#dataset-persist-unique-1 dataset-1>, will produce this:
    --
    -- > +----+-------+-----+
    -- > | id | name  | age |
    -- > +----+-------+-----+
    -- > |  1 | SPJ   |  40 |
    -- > +----+-------+-----+
    -- > |  2 | Simon |  41 |
    -- > +----+-------+-----+
    -- > |  3 | Alexa |   3 |
    -- > +----+-------+-----+

    insertUniqueEntity
        :: forall record backend m
         . ( MonadIO m
           , PersistRecordBackend record backend
           , PersistUniqueWrite backend
           , SafeToInsert record
           )
        => record
        -> ReaderT backend m (Maybe (Entity record))
    insertUniqueEntity :: forall record backend (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     PersistUniqueWrite backend, SafeToInsert record) =>
    record -> ReaderT backend m (Maybe (Entity record))
    insertUniqueEntity record
    datum =
      (Key record -> Entity record)
    -> Maybe (Key record) -> Maybe (Entity record)
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (\Key record
    key -> Key record -> record -> Entity record
    forall record. Key record -> record -> Entity record
    Entity Key record
    key record
    datum) (Maybe (Key record) -> Maybe (Entity record))
    -> ReaderT backend m (Maybe (Key record))
    -> ReaderT backend m (Maybe (Entity record))
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    `liftM` record -> ReaderT backend m (Maybe (Key record))
    forall backend record (m :: * -> *).
    (PersistUniqueWrite backend, MonadIO m,
     PersistRecordBackend record backend, SafeToInsert record) =>
    record -> ReaderT backend m (Maybe (Key record))
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     SafeToInsert record) =>
    record -> ReaderT backend m (Maybe (Key record))
    insertUnique record
    datum

    -- | Return the single unique key for a record.
    --
    -- === __Example usage__
    --
    -- We use shcema-1 and <#dataset-persist-unique-1 dataset-1> here.
    --
    -- > onlySimonConst :: MonadIO m => ReaderT SqlBackend m (Unique User)
    -- > onlySimonConst = onlyUnique $ User "Simon" 999
    --
    -- > mSimonConst <- onlySimonConst
    --
    -- @mSimonConst@ would be Simon's uniqueness constraint. Note that
    -- @onlyUnique@ doesn't work if there're more than two constraints. It will
    -- fail with a type error instead.
    onlyUnique
        :: forall record backend m.
        ( MonadIO m
        , PersistUniqueWrite backend
        , PersistRecordBackend record backend
        , OnlyOneUniqueKey record
        )
        => record -> ReaderT backend m (Unique record)
    onlyUnique :: forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueWrite backend,
     PersistRecordBackend record backend, OnlyOneUniqueKey record) =>
    record -> ReaderT backend m (Unique record)
    onlyUnique = Unique record -> ReaderT backend m (Unique record)
    forall a. a -> ReaderT backend m a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Unique record -> ReaderT backend m (Unique record))
    -> (record -> Unique record)
    -> record
    -> ReaderT backend m (Unique record)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . record -> Unique record
    forall record. OnlyOneUniqueKey record => record -> Unique record
    onlyUniqueP

    -- | A modification of 'getBy', which takes the 'PersistEntity' itself instead
    -- of a 'Unique' record. Returns a record matching /one/ of the unique keys. This
    -- function makes the most sense on entities with a single 'Unique'
    -- constructor.
    --
    -- === __Example usage__
    --
    -- With <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1>,
    --
    -- getBySpjValue :: MonadIO m => ReaderT SqlBackend m (Maybe (Entity User))
    -- getBySpjValue = getByValue $ User "SPJ" 999
    --
    -- > mSpjEnt <- getBySpjValue
    --
    -- The above query when applied on <#dataset-persist-unique-1 dataset-1>, will get this record:
    --
    -- > +----+------+-----+
    -- > | id | name | age |
    -- > +----+------+-----+
    -- > |  1 | SPJ  |  40 |
    -- > +----+------+-----+
    getByValue
        :: forall record m backend.
        ( MonadIO m
        , PersistUniqueRead backend
        , PersistRecordBackend record backend
        , AtLeastOneUniqueKey record
        )
        => record -> ReaderT backend m (Maybe (Entity record))
    getByValue :: forall record (m :: * -> *) backend.
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend, AtLeastOneUniqueKey record) =>
    record -> ReaderT backend m (Maybe (Entity record))
    getByValue record
    record = do
        let uniqs :: NonEmpty (Unique record)
    uniqs = record -> NonEmpty (Unique record)
    forall record.
    AtLeastOneUniqueKey record =>
    record -> NonEmpty (Unique record)
    requireUniquesP record
    record
        [Unique record] -> ReaderT backend m (Maybe (Entity record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Entity record))
    getByValueUniques (NonEmpty (Unique record) -> [Unique record]
    forall a. NonEmpty a -> [a]
    NEL.toList NonEmpty (Unique record)
    uniqs)

    -- | Retrieve a record from the database using the given unique keys. It
    -- will attempt to find a matching record for each 'Unique' in the list,
    -- and returns the first one that has a match.
    --
    -- Returns 'Nothing' if you provide an empty list ('[]') or if no value
    -- matches in the database.
    --
    -- @since 2.10.0
    getByValueUniques
        :: forall record backend m.
        ( MonadIO m
        , PersistUniqueRead backend
        , PersistRecordBackend record backend
        )
        => [Unique record]
        -> ReaderT backend m (Maybe (Entity record))
    getByValueUniques :: forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Entity record))
    getByValueUniques [Unique record]
    uniqs =
        [Unique record] -> ReaderT backend m (Maybe (Entity record))
    forall {record} {backend} {m :: * -> *}.
    (PersistEntityBackend record ~ BaseBackend backend, MonadIO m,
     PersistUniqueRead backend, PersistEntity record) =>
    [Unique record] -> ReaderT backend m (Maybe (Entity record))
    checkUniques [Unique record]
    uniqs
      where
        checkUniques :: [Unique record] -> ReaderT backend m (Maybe (Entity record))
    checkUniques [] = Maybe (Entity record) -> ReaderT backend m (Maybe (Entity record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Entity record)
    forall a. Maybe a
    Nothing
        checkUniques (Unique record
    x:[Unique record]
    xs) = do
            y <- Unique record -> ReaderT backend m (Maybe (Entity record))
    forall backend record (m :: * -> *).
    (PersistUniqueRead backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    getBy Unique record
    x
            case y of
                Maybe (Entity record)
    Nothing -> [Unique record] -> ReaderT backend m (Maybe (Entity record))
    checkUniques [Unique record]
    xs
                Just Entity record
    z -> Maybe (Entity record) -> ReaderT backend m (Maybe (Entity record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (Entity record)
     -> ReaderT backend m (Maybe (Entity record)))
    -> Maybe (Entity record)
    -> ReaderT backend m (Maybe (Entity record))
    forall a b. (a -> b) -> a -> b
    $ Entity record -> Maybe (Entity record)
    forall a. a -> Maybe a
    Just Entity record
    z

    -- | Attempt to replace the record of the given key with the given new record.
    -- First query the unique fields to make sure the replacement maintains
    -- uniqueness constraints.
    --
    -- Return 'Nothing' if the replacement was made.
    -- If uniqueness is violated, return a 'Just' with the 'Unique' violation
    --
    -- @since 1.2.2.0
    replaceUnique
        :: forall record backend m. ( MonadIO m
           , Eq (Unique record)
           , PersistRecordBackend record backend
           , PersistUniqueWrite backend )
        => Key record -> record -> ReaderT backend m (Maybe (Unique record))
    replaceUnique :: forall record backend (m :: * -> *).
    (MonadIO m, Eq (Unique record),
     PersistRecordBackend record backend, PersistUniqueWrite backend) =>
    Key record -> record -> ReaderT backend m (Maybe (Unique record))
    replaceUnique Key record
    key record
    datumNew = Key record -> ReaderT backend m record
    forall record backend (m :: * -> *).
    (PersistStoreRead backend, PersistRecordBackend record backend,
     MonadIO m) =>
    Key record -> ReaderT backend m record
    getJust Key record
    key ReaderT backend m record
    -> (record -> ReaderT backend m (Maybe (Unique record)))
    -> ReaderT backend m (Maybe (Unique record))
    forall a b.
    ReaderT backend m a
    -> (a -> ReaderT backend m b) -> ReaderT backend m b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= record -> ReaderT backend m (Maybe (Unique record))
    replaceOriginal
      where
        uniqueKeysNew :: [Unique record]
    uniqueKeysNew = record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys record
    datumNew
        replaceOriginal :: record -> ReaderT backend m (Maybe (Unique record))
    replaceOriginal record
    original = do
            conflict <- [Unique record] -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeys [Unique record]
    changedKeys
            case conflict of
                Maybe (Unique record)
    Nothing -> Key record -> record -> ReaderT backend m ()
    forall backend record (m :: * -> *).
    (PersistStoreWrite backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Key record -> record -> ReaderT backend m ()
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Key record -> record -> ReaderT backend m ()
    replace Key record
    key record
    datumNew ReaderT backend m ()
    -> ReaderT backend m (Maybe (Unique record))
    -> ReaderT backend m (Maybe (Unique record))
    forall a b.
    ReaderT backend m a -> ReaderT backend m b -> ReaderT backend m b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Maybe (Unique record) -> ReaderT backend m (Maybe (Unique record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Unique record)
    forall a. Maybe a
    Nothing
                (Just Unique record
    conflictingKey) -> Maybe (Unique record) -> ReaderT backend m (Maybe (Unique record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (Unique record)
     -> ReaderT backend m (Maybe (Unique record)))
    -> Maybe (Unique record)
    -> ReaderT backend m (Maybe (Unique record))
    forall a b. (a -> b) -> a -> b
    $ Unique record -> Maybe (Unique record)
    forall a. a -> Maybe a
    Just Unique record
    conflictingKey
          where
            changedKeys :: [Unique record]
    changedKeys = [Unique record]
    uniqueKeysNew [Unique record] -> [Unique record] -> [Unique record]
    forall a. Eq a => [a] -> [a] -> [a]
    \\ [Unique record]
    uniqueKeysOriginal
            uniqueKeysOriginal :: [Unique record]
    uniqueKeysOriginal = record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys record
    original

    -- | Check whether there are any conflicts for unique keys with this entity and
    -- existing entities in the database.
    --
    -- Returns 'Nothing' if the entity would be unique, and could thus safely be inserted.
    -- on a conflict returns the conflicting key
    --
    -- === __Example usage__
    --
    -- We use <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1> here.
    --
    -- This would be 'Nothing':
    --
    -- > mAlanConst <- checkUnique $ User "Alan" 70
    --
    -- While this would be 'Just' because SPJ already exists:
    --
    -- > mSpjConst <- checkUnique $ User "SPJ" 60
    checkUnique
        :: forall record backend m. ( MonadIO m
           , PersistRecordBackend record backend
           , PersistUniqueRead backend)
        => record -> ReaderT backend m (Maybe (Unique record))
    checkUnique :: forall record backend (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     PersistUniqueRead backend) =>
    record -> ReaderT backend m (Maybe (Unique record))
    checkUnique = [Unique record] -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeys ([Unique record] -> ReaderT backend m (Maybe (Unique record)))
    -> (record -> [Unique record])
    -> record
    -> ReaderT backend m (Maybe (Unique record))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys

    checkUniqueKeys
        :: forall record backend m. ( MonadIO m
           , PersistUniqueRead backend
           , PersistRecordBackend record backend)
        => [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeys :: forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeys [] = Maybe (Unique record) -> ReaderT backend m (Maybe (Unique record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Unique record)
    forall a. Maybe a
    Nothing
    checkUniqueKeys (Unique record
    x:[Unique record]
    xs) = do
        y <- Unique record -> ReaderT backend m (Maybe (Entity record))
    forall backend record (m :: * -> *).
    (PersistUniqueRead backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    getBy Unique record
    x
        case y of
            Maybe (Entity record)
    Nothing -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeys [Unique record]
    xs
            Just Entity record
    _ -> Maybe (Unique record) -> ReaderT backend m (Maybe (Unique record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Unique record -> Maybe (Unique record)
    forall a. a -> Maybe a
    Just Unique record
    x)

    -- | Check whether there are any conflicts for unique keys with this entity and
    -- existing entities in the database.
    --
    -- Returns 'Nothing' if the entity would stay unique, and could thus safely be updated.
    -- on a conflict returns the conflicting key
    --
    -- This is similar to 'checkUnique', except it's useful for updating - when the
    -- particular entity already exists, it would normally conflict with itself.
    -- This variant ignores those conflicts
    --
    -- === __Example usage__
    --
    -- We use <#schema-persist-unique-1 schema-1> and <#dataset-persist-unique-1 dataset-1> here.
    --
    -- This would be 'Nothing':
    --
    -- > mAlanConst <- checkUnique $ User "Alan" 70
    --
    -- While this would be 'Just' because SPJ already exists:
    --
    -- > mSpjConst <- checkUnique $ User "SPJ" 60
    --
    -- @since 2.11.0.0
    checkUniqueUpdateable
        :: forall record backend m. ( MonadIO m
           , PersistRecordBackend record backend
           , PersistUniqueRead backend)
        => Entity record -> ReaderT backend m (Maybe (Unique record))
    checkUniqueUpdateable :: forall record backend (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     PersistUniqueRead backend) =>
    Entity record -> ReaderT backend m (Maybe (Unique record))
    checkUniqueUpdateable (Entity Key record
    key record
    record) =
        Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeysUpdateable Key record
    key (record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys record
    record)

    checkUniqueKeysUpdateable
        :: forall record backend m. ( MonadIO m
           , PersistUniqueRead backend
           , PersistRecordBackend record backend)
        => Key record -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeysUpdateable :: forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeysUpdateable Key record
    _ [] = Maybe (Unique record) -> ReaderT backend m (Maybe (Unique record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Unique record)
    forall a. Maybe a
    Nothing
    checkUniqueKeysUpdateable Key record
    key (Unique record
    x:[Unique record]
    xs) = do
        y <- Unique record -> ReaderT backend m (Maybe (Entity record))
    forall backend record (m :: * -> *).
    (PersistUniqueRead backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    getBy Unique record
    x
        case y of
            Maybe (Entity record)
    Nothing ->
                Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeysUpdateable Key record
    key [Unique record]
    xs
            Just (Entity Key record
    k record
    _)
              | Key record
    key Key record -> Key record -> Bool
    forall a. Eq a => a -> a -> Bool
    == Key record
    k ->
                  Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    Key record
    -> [Unique record] -> ReaderT backend m (Maybe (Unique record))
    checkUniqueKeysUpdateable Key record
    key [Unique record]
    xs
            Just Entity record
    _ ->
                Maybe (Unique record) -> ReaderT backend m (Maybe (Unique record))
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Unique record -> Maybe (Unique record)
    forall a. a -> Maybe a
    Just Unique record
    x)

    -- | The slow but generic 'upsertBy' implementation for any 'PersistUniqueRead'.
    -- * Lookup corresponding entities (if any) 'getBy'.
    -- * If the record exists, update using 'updateGet'.
    -- * If it does not exist, insert using 'insertEntity'.
    -- @since 2.11
    defaultUpsertBy
        :: ( PersistEntityBackend record ~ BaseBackend backend
           , PersistEntity record
           , MonadIO m
           , PersistStoreWrite backend
           , PersistUniqueRead backend
           , SafeToInsert record
           )
        => Unique record   -- ^ uniqueness constraint to find by
        -> record          -- ^ new record to insert
        -> [Update record] -- ^ updates to perform if the record already exists
        -> ReaderT backend m (Entity record) -- ^ the record in the database after the operation
    defaultUpsertBy :: forall record backend (m :: * -> *).
    (PersistEntityBackend record ~ BaseBackend backend,
     PersistEntity record, MonadIO m, PersistStoreWrite backend,
     PersistUniqueRead backend, SafeToInsert record) =>
    Unique record
    -> record -> [Update record] -> ReaderT backend m (Entity record)
    defaultUpsertBy Unique record
    uniqueKey record
    record [Update record]
    updates = do
        mrecord <- Unique record -> ReaderT backend m (Maybe (Entity record))
    forall backend record (m :: * -> *).
    (PersistUniqueRead backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Unique record -> ReaderT backend m (Maybe (Entity record))
    getBy Unique record
    uniqueKey
        maybe (insertEntity record) (`updateGetEntity` updates) mrecord
      where
        updateGetEntity :: Entity a1 -> [Update a1] -> ReaderT backend m (Entity a1)
    updateGetEntity (Entity Key a1
    k a1
    _) [Update a1]
    upds =
            (Key a1 -> a1 -> Entity a1
    forall record. Key record -> record -> Entity record
    Entity Key a1
    k) (a1 -> Entity a1)
    -> ReaderT backend m a1 -> ReaderT backend m (Entity a1)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    `liftM` (Key a1 -> [Update a1] -> ReaderT backend m a1
    forall backend record (m :: * -> *).
    (PersistStoreWrite backend, MonadIO m,
     PersistRecordBackend record backend) =>
    Key record -> [Update record] -> ReaderT backend m record
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend) =>
    Key record -> [Update record] -> ReaderT backend m record
    updateGet Key a1
    k [Update a1]
    upds)

    -- | The slow but generic 'putMany' implementation for any 'PersistUniqueRead'.
    -- * Lookup corresponding entities (if any) for each record using 'getByValue'
    -- * For pre-existing records, issue a 'replace' for each old key and new record
    -- * For new records, issue a bulk 'insertMany_'
    defaultPutMany
        :: forall record backend m. ( PersistEntityBackend record ~ BaseBackend backend
          , PersistEntity record
          , MonadIO m
          , PersistStoreWrite backend
          , PersistUniqueRead backend
          , SafeToInsert record
          )
        => [record]
        -> ReaderT backend m ()
    defaultPutMany :: forall record backend (m :: * -> *).
    (PersistEntityBackend record ~ BaseBackend backend,
     PersistEntity record, MonadIO m, PersistStoreWrite backend,
     PersistUniqueRead backend, SafeToInsert record) =>
    [record] -> ReaderT backend m ()
    defaultPutMany []   = () -> ReaderT backend m ()
    forall a. a -> ReaderT backend m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    defaultPutMany rsD :: [record]
    rsD@(record
    e:[record]
    _)  = do
        case record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys record
    e of
            [] -> [record] -> ReaderT backend m ()
    forall backend record (m :: * -> *).
    (PersistStoreWrite backend, MonadIO m,
     PersistRecordBackend record backend, SafeToInsert record) =>
    [record] -> ReaderT backend m ()
    forall record (m :: * -> *).
    (MonadIO m, PersistRecordBackend record backend,
     SafeToInsert record) =>
    [record] -> ReaderT backend m ()
    insertMany_ [record]
    rsD
            [Unique record]
    _ -> ReaderT backend m ()
    go
      where
        go :: ReaderT backend m ()
    go = do
            -- deduplicate the list of records in Haskell by unique key. The
            -- previous implementation used Data.List.nubBy which is O(n^2)
            -- complexity.
            let rs :: [record]
    rs = (([PersistValue], record) -> record)
    -> [([PersistValue], record)] -> [record]
    forall a b. (a -> b) -> [a] -> [b]
    map ([PersistValue], record) -> record
    forall a b. (a, b) -> b
    snd
                    ([([PersistValue], record)] -> [record])
    -> ([record] -> [([PersistValue], record)]) -> [record] -> [record]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Map [PersistValue] record -> [([PersistValue], record)]
    forall k a. Map k a -> [(k, a)]
    Map.toList
                    (Map [PersistValue] record -> [([PersistValue], record)])
    -> ([record] -> Map [PersistValue] record)
    -> [record]
    -> [([PersistValue], record)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [([PersistValue], record)] -> Map [PersistValue] record
    forall k a. Ord k => [(k, a)] -> Map k a
    Map.fromList
                    ([([PersistValue], record)] -> Map [PersistValue] record)
    -> ([record] -> [([PersistValue], record)])
    -> [record]
    -> Map [PersistValue] record
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (record -> ([PersistValue], record))
    -> [record] -> [([PersistValue], record)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\record
    r -> (record -> [PersistValue]
    forall record. PersistEntity record => record -> [PersistValue]
    persistUniqueKeyValues record
    r, record
    r))
                    ([record] -> [record]) -> [record] -> [record]
    forall a b. (a -> b) -> a -> b
    $ [record]
    rsD

            -- lookup record(s) by their unique key
            mEsOld <- (record -> ReaderT backend m (Maybe (Entity record)))
    -> [record] -> ReaderT backend m [Maybe (Entity record)]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM ([Unique record] -> ReaderT backend m (Maybe (Entity record))
    forall record backend (m :: * -> *).
    (MonadIO m, PersistUniqueRead backend,
     PersistRecordBackend record backend) =>
    [Unique record] -> ReaderT backend m (Maybe (Entity record))
    getByValueUniques ([Unique record] -> ReaderT backend m (Maybe (Entity record)))
    -> (record -> [Unique record])
    -> record
    -> ReaderT backend m (Maybe (Entity record))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys) [record]
    rs

            -- find pre-existing entities and corresponding (incoming) records
            let merge (Just a
    x) b
    y = (a, b) -> Maybe (a, b)
    forall a. a -> Maybe a
    Just (a
    x, b
    y)
                merge Maybe a
    _        b
    _ = Maybe (a, b)
    forall a. Maybe a
    Nothing
            let mEsOldAndRs = (Maybe (Entity record) -> record -> Maybe (Entity record, record))
    -> [Maybe (Entity record)]
    -> [record]
    -> [Maybe (Entity record, record)]
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith Maybe (Entity record) -> record -> Maybe (Entity record, record)
    forall {a} {b}. Maybe a -> b -> Maybe (a, b)
    merge [Maybe (Entity record)]
    mEsOld [record]
    rs
            let esOldAndRs = [Maybe (Entity record, record)] -> [(Entity record, record)]
    forall a. [Maybe a] -> [a]
    catMaybes [Maybe (Entity record, record)]
    mEsOldAndRs

            -- determine records to insert
            let esOld = ((Entity record, record) -> Entity record)
    -> [(Entity record, record)] -> [Entity record]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Entity record, record) -> Entity record
    forall a b. (a, b) -> a
    fst [(Entity record, record)]
    esOldAndRs
            let rsOld = (Entity record -> record) -> [Entity record] -> [record]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Entity record -> record
    forall record. Entity record -> record
    entityVal [Entity record]
    esOld
            let rsNew = (record -> record -> Bool) -> [record] -> [record] -> [record]
    forall a. (a -> a -> Bool) -> [a] -> [a] -> [a]
    deleteFirstsBy ([PersistValue] -> [PersistValue] -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) ([PersistValue] -> [PersistValue] -> Bool)
    -> (record -> [PersistValue]) -> record -> record -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` record -> [PersistValue]
    forall record. PersistEntity record => record -> [PersistValue]
    persistUniqueKeyValues) [record]
    rs [record]
    rsOld

            -- determine records to update
            let rsUpd = ((Entity record, record) -> record)
    -> [(Entity record, record)] -> [record]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Entity record, record) -> record
    forall a b. (a, b) -> b
    snd [(Entity record, record)]
    esOldAndRs
            let ksOld = (Entity record -> Key record) -> [Entity record] -> [Key record]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Entity record -> Key record
    forall record. Entity record -> Key record
    entityKey [Entity record]
    esOld
            let krs   = [Key record] -> [record] -> [(Key record, record)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Key record]
    ksOld [record]
    rsUpd

            -- insert `new` records
            insertMany_ rsNew
            -- replace existing records
            mapM_ (uncurry replace) krs

    -- | This function returns a list of 'PersistValue' that correspond to the
    -- 'Unique' keys on that record. This is useful for comparing two @record@s
    -- for equality only on the basis of their 'Unique' keys.
    persistUniqueKeyValues :: PersistEntity record => record -> [PersistValue]
    persistUniqueKeyValues :: forall record. PersistEntity record => record -> [PersistValue]
    persistUniqueKeyValues = (Unique record -> [PersistValue])
    -> [Unique record] -> [PersistValue]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Unique record -> [PersistValue]
    forall record.
    PersistEntity record =>
    Unique record -> [PersistValue]
    persistUniqueToValues ([Unique record] -> [PersistValue])
    -> (record -> [Unique record]) -> record -> [PersistValue]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . record -> [Unique record]
    forall record. PersistEntity record => record -> [Unique record]
    persistUniqueKeys