objection.js icon indicating copy to clipboard operation
objection.js copied to clipboard

onConflict returns wrong values when there is a conflict

Open rockrepIGN opened this issue 1 year ago • 5 comments

Objection.js v3.0.1 Knex v1.0.7 pg v8.7.1. (postgres)

Inserting records via Objection behaves differently than does inserting records via Knex when onConflict().ignore() is used and a conflict occurs. The Knex behavior seems correct to me.

Table schema:

  await knex.schema.createTable('user_platform', table => {
    table.integer('user_id')
    table.integer('platform_id')
    table.unique(['user_id', 'platform_id'])
  })

DB class:

const { Model } = require('objection')

class UserPlatform extends Model {
  static get tableName() {
    return 'userPlatform'
  }

  static get idColumn() {
    return ['userId', 'platformId']
  }

  static insertWithKnex(userPlatforms = []) {
    const knex = this.knex()
    return knex('userPlatform').insert(userPlatforms).onConflict(this.idColumn).ignore().returning('*')
  }

  static insertWithObjection(userPlatforms = []) {
    return this.query().insert(userPlatforms).onConflict(this.idColumn).ignore().returning('*')
  }

  static get relationMappings() {
    return {},
  }
}

module.exports = UserPlatform

Test Cases:

  describe('insert', () => {

    const userPlatforms = [
      { userId: 1, platformId: 11 },
      { userId: 1, platformId: 12 },
    ]
    console.log({existing: userPlatforms})
   
    it('Knex version - should NOT raise, but ignore, on insertion of duplicate records, existing or provided, returning only those actually added', async () => {
      expect.assertions(1)
      await db.UserPlatformDB.insert(userPlatforms)
      const inserts = userPlatforms.concat([
        { userId: 1, platformId: 13 },
        { userId: 1, platformId: 13 },
      ])
      console.log({ inserts })
      const response = await db.UserPlatformDB.insertWithKnex(inserts)
      console.log({ response })
      expect(response.map(rs => rs.platformId)).toEqual([13])
    })

    it('Objection version - should NOT raise, but ignore, on insertion of duplicate records, existing or provided, returning only those actually added', async () => {
      expect.assertions(1)
      await db.UserPlatformDB.insert(userPlatforms)
      const inserts = userPlatforms.concat([
        { userId: 1, platformId: 13 },
        { userId: 1, platformId: 13 },
      ])
      console.log({ inserts })
      const response = await db.UserPlatformDB.insertWithObjection(inserts)
      console.log({ response })
      expect(response.map(rs => rs.platformId)).toEqual([13])
    }) 

Test Output from Knex test:

console.log
   {
     existing: [
        { userId: 1, platformId: 11 },
        { userId: 1, platformId: 12 },
     ]
   }

console.log
    {
      inserts: [
        { userId: 1, platformId: 11 },
        { userId: 1, platformId: 12 },
        { userId: 1, platformId: 13 },
        { userId: 1, platformId: 13 }
      ]
    }

  console.log
    {
      response: [
        { userId: 1, platformId: 13 }
      ]
    }
User Platform
    insert
      ✓ Knex version - should NOT raise, but ignore, on insertion of duplicate records, existing or provided, returning only those actually added (957 ms)

Test output from Objection test:

console.log
   {
     existing: [
        { userId: 1, platformId: 11 },
        { userId: 1, platformId: 12 },
     ]
   }

 console.log
    {
      inserts: [
        { userId: 1, platformId: 11 },
        { userId: 1, platformId: 12 },
        { userId: 1, platformId: 13 },
        { userId: 1, platformId: 13 }
      ]
    }

  console.log
    {
      response: [
        extended(UserPlatform) {
          userId: 1,
          platformId: 13
        },
        extended(UserPlatform) {
          userId: 1,
          platformId: 12
        },
        extended(UserPlatform) {
          userId: 1,
          platformId: 13
        },
        extended(UserPlatform) {
          userId: 1,
          platformId: 13
        }
      ]
    }


 FAIL  tests/db/user-platform.test.js
  User Platform
    insert
      ✕ Objection version - should NOT raise, but ignore, on insertion of duplicate records, existing or provided, returning only those actually added (548 ms)

 User Platform › insert › Objection version - should NOT raise, bug ignore, on insertion of duplicate records, existing or provided, returning only those actually added

    expect(received).toEqual(expected) // deep equality

    - Expected  - 0
    + Received  + 3

      Array [
        13,
    +   12,
    +   13,
    +   13,
      ]

      155 |       const response = await db.UserPlatformDB.insertWithObjection(inserts)
      156 |       console.log({ added: response })
    > 157 |       expect(response.map(rs => rs.platformId)).toEqual([13])
          |                  
      160 |     })

rockrepIGN avatar Sep 09 '22 22:09 rockrepIGN