Skip to content

Upsert uses a WHERE clause with both primary key and unique indices on Postgres #8552

@DanielleB-R

Description

@DanielleB-R

What are you doing?

I am using upsert to update models that have both a primary key and a composite unique constraint which is DEFERRABLE INITIALLY DEFERRED. When I try to change the members of the unique constraint I get a key uniqueness error.

Model:

module.exports = (sequelize, DataTypes) => {
  return sequelize.define(
    'rule',
    {
      id: {
        type: DataTypes.UUID,
        primaryKey: true,
        defaultValue: DataTypes.UUIDV4,
      },
      priority: {
        type: DataTypes.INTEGER,
        allowNull: false,
        defaultValue: 0,
        unique: 'rules_priority_parent_id'
      },
      parent_id: {
        type: DataTypes.UUID,
        allowNull: false,
        unique: 'rules_priority_parent_id'
      }
    },
    {
      tableName: 'rules',
      timestamps: true
    }
  )
}

Then do:

models.rule.create({
  id: 5,
  priority: 0,
  parent_id: 20
})

models.rule.create({
  id: 10,
  priority: 1,
  parent_id: 20
})

models.sequelize.transaction(() => (
  models.rule.upsert({
    id: 5,
    priority: 1,
    parent_id: 20
  })
    .then(() => models.rule.upsert({
      id: 10,
      priority: 0,
      parent_id: 20
    }))
))

What do you expect to happen?

The priority of the two rows to be swapped

What is actually happening?

Uniqueness constraint error

I get a constraint error on the uniqueness of the primary key.

Postgres output:

ERROR:  duplicate key value violates unique constraint "rules_pkey"
DETAIL:  Key (id)=(5) already exists.
CONTEXT:  SQL statement "UPDATE "rules" SET "priority"=1, "parent_id"=20, "id"=5, "updated_at"='2017-10-27 17:37:23.120 +00:00' WHERE ("id" = 5 OR ("priority" = 1 AND "parent_id" = 20))"
PL/pgSQL function pg_temp_3.sequelize_upsert() line 1 at SQL statement

I see a fix for sequelize@3 for the same problem (issue #6240, PR #6243), but it appears to still be a problem in sequelize@4.

Dialect: postgres
Dialect version: pg@6.4.2
Database version: 9.6.3
Sequelize version: 4.19.0
Tested with master branch: Yes

Note : Your issue may be ignored by maintainers if it's not tested against master branch OR does not follow issue template.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugDEPRECATED: replace with the "bug" issue type

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions