* Insert or update a single row. An update will be executed if a row which matches the supplied values on either the primary key or a unique key is found. Note that the unique index must be defined in your sequelize model and not just in the table. Otherwise you may experience a unique constraint vi
(values, options)
| 2460 | * @returns {Promise<Array<Model, boolean | null>>} returns an array with two elements, the first being the new record and the second being `true` if it was just created or `false` if it already existed (except on Postgres and SQLite, which can't detect this and will always return `null` instead of a boolean). |
| 2461 | */ |
| 2462 | static async upsert(values, options) { |
| 2463 | options = { |
| 2464 | hooks: true, |
| 2465 | returning: true, |
| 2466 | validate: true, |
| 2467 | ...Utils.cloneDeep(options) |
| 2468 | }; |
| 2469 | |
| 2470 | const createdAtAttr = this._timestampAttributes.createdAt; |
| 2471 | const updatedAtAttr = this._timestampAttributes.updatedAt; |
| 2472 | const hasPrimary = this.primaryKeyField in values || this.primaryKeyAttribute in values; |
| 2473 | const instance = this.build(values); |
| 2474 | |
| 2475 | options.model = this; |
| 2476 | options.instance = instance; |
| 2477 | |
| 2478 | const changed = Array.from(instance._changed); |
| 2479 | if (!options.fields) { |
| 2480 | options.fields = changed; |
| 2481 | } |
| 2482 | |
| 2483 | if (options.validate) { |
| 2484 | await instance.validate(options); |
| 2485 | } |
| 2486 | // Map field names |
| 2487 | const updatedDataValues = _.pick(instance.dataValues, changed); |
| 2488 | const insertValues = Utils.mapValueFieldNames(instance.dataValues, Object.keys(instance.rawAttributes), this); |
| 2489 | const updateValues = Utils.mapValueFieldNames(updatedDataValues, options.fields, this); |
| 2490 | const now = Utils.now(this.sequelize.options.dialect); |
| 2491 | |
| 2492 | // Attach createdAt |
| 2493 | if (createdAtAttr && !insertValues[createdAtAttr]) { |
| 2494 | const field = this.rawAttributes[createdAtAttr].field || createdAtAttr; |
| 2495 | insertValues[field] = this._getDefaultTimestamp(createdAtAttr) || now; |
| 2496 | } |
| 2497 | if (updatedAtAttr && !insertValues[updatedAtAttr]) { |
| 2498 | const field = this.rawAttributes[updatedAtAttr].field || updatedAtAttr; |
| 2499 | insertValues[field] = updateValues[field] = this._getDefaultTimestamp(updatedAtAttr) || now; |
| 2500 | } |
| 2501 | |
| 2502 | // Db2 does not allow NULL values for unique columns. |
| 2503 | // Add dummy values if not provided by test case or user. |
| 2504 | if (this.sequelize.options.dialect === 'db2') { |
| 2505 | this.uniqno = this.sequelize.dialect.queryGenerator.addUniqueFields( |
| 2506 | insertValues, this.rawAttributes, this.uniqno); |
| 2507 | } |
| 2508 | |
| 2509 | // Build adds a null value for the primary key, if none was given by the user. |
| 2510 | // We need to remove that because of some Postgres technicalities. |
| 2511 | if (!hasPrimary && this.primaryKeyAttribute && !this.rawAttributes[this.primaryKeyAttribute].defaultValue) { |
| 2512 | delete insertValues[this.primaryKeyField]; |
| 2513 | delete updateValues[this.primaryKeyField]; |
| 2514 | } |
| 2515 | |
| 2516 | if (options.hooks) { |
| 2517 | await this.runHooks('beforeUpsert', values, options); |
| 2518 | } |
| 2519 | const result = await this.queryInterface.upsert(this.getTableName(options), insertValues, updateValues, instance.where(), options); |