12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070 |
- 'use strict';
- const { expect } = require('chai');
- const sinon = require('sinon');
- const { beforeEach2, sequelize } = require('../support');
- const { DataTypes, Sequelize, sql } = require('@sequelize/core');
- const dialectName = sequelize.dialect.name;
- describe('Model', () => {
- before(function () {
- this.clock = sinon.useFakeTimers();
- });
- after(function () {
- this.clock.restore();
- });
- beforeEach(function () {
- this.clock.reset();
- });
- beforeEach(async function () {
- this.User = this.sequelize.define('user', {
- username: DataTypes.STRING,
- foo: {
- unique: 'foobar',
- type: DataTypes.STRING,
- },
- bar: {
- unique: 'foobar',
- type: DataTypes.INTEGER,
- },
- counter: {
- type: DataTypes.INTEGER,
- defaultValue: 0,
- },
- baz: {
- type: DataTypes.STRING,
- field: 'zab',
- defaultValue: 'BAZ_DEFAULT_VALUE',
- },
- blob: DataTypes.BLOB,
- });
- this.ModelWithFieldPK = this.sequelize.define('ModelWithFieldPK', {
- userId: {
- field: 'user_id',
- type: DataTypes.INTEGER,
- autoIncrement: true,
- primaryKey: true,
- },
- foo: {
- type: DataTypes.STRING,
- unique: true,
- },
- });
- await this.sequelize.sync({ force: true });
- });
- if (sequelize.dialect.supports.upserts) {
- describe('upsert', () => {
- it('works with upsert on id', async function () {
- const [, created0] = await this.User.upsert({ id: 42, username: 'john' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.true;
- }
- this.clock.tick(1000);
- const [, created] = await this.User.upsert({ id: 42, username: 'doe' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await this.User.findByPk(42);
- expect(user.createdAt).to.be.ok;
- expect(user.username).to.equal('doe');
- expect(user.updatedAt).to.be.afterTime(user.createdAt);
- });
- it('works with upsert on a composite key', async function () {
- const [, created0] = await this.User.upsert({ foo: 'baz', bar: 19, username: 'john' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.true;
- }
- this.clock.tick(1000);
- const [, created] = await this.User.upsert({ foo: 'baz', bar: 19, username: 'doe' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await this.User.findOne({ where: { foo: 'baz', bar: 19 } });
- expect(user.createdAt).to.be.ok;
- expect(user.username).to.equal('doe');
- expect(user.updatedAt).to.be.afterTime(user.createdAt);
- });
- it('should work with UUIDs wth default values', async function () {
- const User = this.sequelize.define('User', {
- id: {
- primaryKey: true,
- allowNull: false,
- unique: true,
- type: DataTypes.UUID,
- defaultValue: sql.uuidV4,
- },
- name: {
- type: DataTypes.STRING,
- },
- });
- await User.sync({ force: true });
- await User.upsert({ name: 'John Doe' });
- });
- it('works with upsert on a composite primary key', async function () {
- const User = this.sequelize.define('user', {
- a: {
- type: DataTypes.STRING,
- primaryKey: true,
- },
- b: {
- type: DataTypes.STRING,
- primaryKey: true,
- },
- username: DataTypes.STRING,
- });
- await User.sync({ force: true });
- const [created1, created2] = await Promise.all([
- // Create two users
- User.upsert({ a: 'a', b: 'b', username: 'john' }),
- User.upsert({ a: 'a', b: 'a', username: 'curt' }),
- ]);
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created1[1]).to.be.null;
- expect(created2[1]).to.be.null;
- } else {
- expect(created1[1]).to.be.true;
- expect(created2[1]).to.be.true;
- }
- this.clock.tick(1000);
- // Update the first one
- const [, created] = await User.upsert({ a: 'a', b: 'b', username: 'doe' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user1 = await User.findOne({ where: { a: 'a', b: 'b' } });
- expect(user1.createdAt).to.be.ok;
- expect(user1.username).to.equal('doe');
- expect(user1.updatedAt).to.be.afterTime(user1.createdAt);
- const user2 = await User.findOne({ where: { a: 'a', b: 'a' } });
- // The second one should not be updated
- expect(user2.createdAt).to.be.ok;
- expect(user2.username).to.equal('curt');
- expect(user2.updatedAt).to.equalTime(user2.createdAt);
- });
- it('supports validations', async function () {
- const User = this.sequelize.define('user', {
- email: {
- type: DataTypes.STRING,
- validate: {
- isEmail: true,
- },
- },
- });
- await expect(User.upsert({ email: 'notanemail' })).to.eventually.be.rejectedWith(
- Sequelize.ValidationError,
- );
- });
- it('supports skipping validations', async function () {
- const User = this.sequelize.define('user', {
- email: {
- type: DataTypes.STRING,
- validate: {
- isEmail: true,
- },
- },
- });
- const options = { validate: false };
- await User.sync({ force: true });
- const [, created] = await User.upsert({ id: 1, email: 'notanemail' }, options);
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.true;
- }
- });
- it('works with BLOBs', async function () {
- const [, created0] = await this.User.upsert({
- id: 42,
- username: 'john',
- blob: Buffer.from('kaj'),
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- this.clock.tick(1000);
- const [, created] = await this.User.upsert({
- id: 42,
- username: 'doe',
- blob: Buffer.from('andrea'),
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await this.User.findByPk(42);
- expect(user.createdAt).to.be.ok;
- expect(user.username).to.equal('doe');
- expect(user.blob.toString()).to.equal('andrea');
- expect(user.updatedAt).to.be.afterTime(user.createdAt);
- });
- it('works with .field', async function () {
- const [, created0] = await this.User.upsert({ id: 42, baz: 'foo' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- const [, created] = await this.User.upsert({ id: 42, baz: 'oof' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await this.User.findByPk(42);
- expect(user.baz).to.equal('oof');
- });
- it('works with primary key using .field', async function () {
- const [, created0] = await this.ModelWithFieldPK.upsert({ userId: 42, foo: 'first' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- this.clock.tick(1000);
- const [, created] = await this.ModelWithFieldPK.upsert({ userId: 42, foo: 'second' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const instance = await this.ModelWithFieldPK.findOne({ where: { userId: 42 } });
- expect(instance.foo).to.equal('second');
- });
- it('works with database functions', async function () {
- const [, created0] = await this.User.upsert({
- id: 42,
- username: 'john',
- foo: this.sequelize.fn('upper', 'mixedCase1'),
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- this.clock.tick(1000);
- const [, created] = await this.User.upsert({
- id: 42,
- username: 'doe',
- foo: this.sequelize.fn('upper', 'mixedCase2'),
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await this.User.findByPk(42);
- expect(user.createdAt).to.be.ok;
- expect(user.username).to.equal('doe');
- expect(user.foo).to.equal('MIXEDCASE2');
- });
- it('does not overwrite createdAt time on update', async function () {
- await this.User.create({ id: 42, username: 'john' });
- const user0 = await this.User.findByPk(42);
- const originalCreatedAt = user0.createdAt;
- const originalUpdatedAt = user0.updatedAt;
- this.clock.tick(5000);
- await this.User.upsert({ id: 42, username: 'doe' });
- const user = await this.User.findByPk(42);
- expect(user.updatedAt).to.be.gt(originalUpdatedAt);
- expect(user.createdAt).to.deep.equal(originalCreatedAt);
- this.clock.restore();
- });
- it('does not overwrite createdAt when supplied as an explicit insert value when using fields', async function () {
- const originalCreatedAt = new Date('2010-01-01T12:00:00.000Z');
- await this.User.upsert(
- { id: 42, username: 'john', createdAt: originalCreatedAt },
- { fields: ['id', 'username'] },
- );
- const user = await this.User.findByPk(42);
- expect(user.createdAt).to.deep.equal(originalCreatedAt);
- this.clock.restore();
- });
- it('falls back to a noop if no update values are found in the upsert data', async function () {
- const User = this.sequelize.define(
- 'user',
- {
- username: DataTypes.STRING,
- email: {
- type: DataTypes.STRING,
- field: 'email_address',
- defaultValue: 'xxx@yyy.zzz',
- },
- },
- {
- // note, timestamps: false is important here because this test is attempting to see what happens
- // if there are NO updatable fields (including timestamp values).
- timestamps: false,
- },
- );
- await User.sync({ force: true });
- // notice how the data does not actually have the update fields.
- await User.upsert({ id: 42, username: 'jack' }, { fields: ['email'] });
- await User.upsert({ id: 42, username: 'jill' }, { fields: ['email'] });
- const user = await User.findByPk(42);
- // just making sure the user exists, i.e. the insert happened.
- expect(user).to.be.ok;
- expect(user.username).to.equal('jack'); // second upsert should not have updated username.
- });
- it('does not update using default values', async function () {
- await this.User.create({ id: 42, username: 'john', baz: 'new baz value' });
- const user0 = await this.User.findByPk(42);
- // 'username' should be 'john' since it was set
- expect(user0.username).to.equal('john');
- // 'baz' should be 'new baz value' since it was set
- expect(user0.baz).to.equal('new baz value');
- await this.User.upsert({ id: 42, username: 'doe' });
- const user = await this.User.findByPk(42);
- // 'username' was updated
- expect(user.username).to.equal('doe');
- // 'baz' should still be 'new baz value' since it was not updated
- expect(user.baz).to.equal('new baz value');
- });
- it('does not update when setting current values', async function () {
- await this.User.create({ id: 42, username: 'john' });
- const user = await this.User.findByPk(42);
- const [, created] = await this.User.upsert({ id: user.id, username: user.username });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- // After set node-mysql flags = '-FOUND_ROWS' / foundRows=false
- // result from upsert should be false when upsert a row to its current value
- // https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
- expect(created).to.equal(false);
- }
- });
- it('works when two separate uniqueKeys are passed', async function () {
- const User = this.sequelize.define('User', {
- username: {
- type: DataTypes.STRING,
- unique: true,
- },
- email: {
- type: DataTypes.STRING,
- unique: true,
- },
- city: {
- type: DataTypes.STRING,
- },
- });
- await User.sync({ force: true });
- const [, created0] = await User.upsert({
- username: 'user1',
- email: 'user1@domain.ext',
- city: 'City',
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- const [, created] = await User.upsert({
- username: 'user1',
- email: 'user1@domain.ext',
- city: 'New City',
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await User.findOne({
- where: { username: 'user1', email: 'user1@domain.ext' },
- });
- expect(user.createdAt).to.be.ok;
- expect(user.city).to.equal('New City');
- });
- it('works when indexes are created via indexes array', async function () {
- const User = this.sequelize.define(
- 'User',
- {
- username: DataTypes.STRING,
- email: DataTypes.STRING,
- city: DataTypes.STRING,
- },
- {
- indexes: [
- {
- unique: true,
- fields: ['username'],
- },
- {
- unique: true,
- fields: ['email'],
- },
- ],
- },
- );
- await User.sync({ force: true });
- const [, created0] = await User.upsert({
- username: 'user1',
- email: 'user1@domain.ext',
- city: 'City',
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- const [, created] = await User.upsert({
- username: 'user1',
- email: 'user1@domain.ext',
- city: 'New City',
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- const user = await User.findOne({
- where: { username: 'user1', email: 'user1@domain.ext' },
- });
- expect(user.createdAt).to.be.ok;
- expect(user.city).to.equal('New City');
- });
- it('works when composite indexes are created via indexes array', async () => {
- const User = sequelize.define(
- 'User',
- {
- name: DataTypes.STRING,
- address: DataTypes.STRING,
- city: DataTypes.STRING,
- },
- {
- indexes: [
- {
- unique: 'users_name_address',
- fields: ['name', 'address'],
- },
- ],
- },
- );
- await User.sync({ force: true });
- const [, created0] = await User.upsert({ name: 'user1', address: 'address', city: 'City' });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.ok;
- }
- const [, created] = await User.upsert({
- name: 'user1',
- address: 'address',
- city: 'New City',
- });
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).not.to.be.ok;
- }
- const user = await User.findOne({ where: { name: 'user1', address: 'address' } });
- expect(user.createdAt).to.be.ok;
- expect(user.city).to.equal('New City');
- });
- if (dialectName === 'mssql') {
- it('Should throw foreignKey violation for MERGE statement as ForeignKeyConstraintError', async function () {
- const User = this.sequelize.define('User', {
- username: {
- type: DataTypes.STRING,
- primaryKey: true,
- },
- });
- const Posts = this.sequelize.define('Posts', {
- title: {
- type: DataTypes.STRING,
- primaryKey: true,
- },
- username: DataTypes.STRING,
- });
- Posts.belongsTo(User, { foreignKey: 'username' });
- await this.sequelize.sync({ force: true });
- await User.create({ username: 'user1' });
- await expect(
- Posts.upsert({ title: 'Title', username: 'user2' }),
- ).to.eventually.be.rejectedWith(Sequelize.ForeignKeyConstraintError);
- });
- }
- if (dialectName.startsWith('postgres')) {
- it('works when deletedAt is Infinity and part of primary key', async function () {
- const User = this.sequelize.define(
- 'User',
- {
- name: {
- type: DataTypes.STRING,
- primaryKey: true,
- },
- address: DataTypes.STRING,
- deletedAt: {
- type: DataTypes.DATE,
- primaryKey: true,
- allowNull: true,
- defaultValue: Number.POSITIVE_INFINITY,
- },
- },
- {
- paranoid: true,
- },
- );
- await User.sync({ force: true });
- await Promise.all([
- User.create({ name: 'user1' }),
- User.create({ name: 'user2', deletedAt: Number.POSITIVE_INFINITY }),
- // this record is soft deleted
- User.create({ name: 'user3', deletedAt: Number.NEGATIVE_INFINITY }),
- ]);
- await User.upsert({ name: 'user1', address: 'address' });
- const users = await User.findAll({
- where: { address: null },
- });
- expect(users).to.have.lengthOf(2);
- });
- }
- if (dialectName === 'mysql' || dialectName === 'mariadb') {
- it('should allow to use calculated values on duplicate', async function () {
- await this.User.upsert({
- id: 1,
- counter: this.sequelize.literal('`counter` + 1'),
- });
- await this.User.upsert({
- id: 1,
- counter: this.sequelize.literal('`counter` + 1'),
- });
- const user = await this.User.findByPk(1);
- expect(user.counter).to.equal(2);
- });
- }
- if (sequelize.dialect.supports.returnValues) {
- describe('returns values', () => {
- it('works with upsert on id', async function () {
- const [user0, created0] = await this.User.upsert(
- { id: 42, username: 'john' },
- { returning: true },
- );
- expect(user0.get('id')).to.equal(42);
- expect(user0.get('username')).to.equal('john');
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.true;
- }
- const [user, created] = await this.User.upsert(
- { id: 42, username: 'doe' },
- { returning: true },
- );
- expect(user.get('id')).to.equal(42);
- expect(user.get('username')).to.equal('doe');
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- });
- it('works for table with custom primary key field', async function () {
- const User = this.sequelize.define('User', {
- id: {
- type: DataTypes.INTEGER,
- autoIncrement: true,
- primaryKey: true,
- field: 'id_the_primary',
- },
- username: {
- type: DataTypes.STRING,
- },
- });
- await User.sync({ force: true });
- const [user0, created0] = await User.upsert(
- { id: 42, username: 'john' },
- { returning: true },
- );
- expect(user0.get('id')).to.equal(42);
- expect(user0.get('username')).to.equal('john');
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.true;
- }
- const [user, created] = await User.upsert(
- { id: 42, username: 'doe' },
- { returning: true },
- );
- expect(user.get('id')).to.equal(42);
- expect(user.get('username')).to.equal('doe');
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- });
- it('works for non incrementing primaryKey', async function () {
- const User = this.sequelize.define('User', {
- id: {
- type: DataTypes.STRING,
- primaryKey: true,
- field: 'id_the_primary',
- },
- username: {
- type: DataTypes.STRING,
- },
- });
- await User.sync({ force: true });
- const [user0, created0] = await User.upsert(
- { id: 'surya', username: 'john' },
- { returning: true },
- );
- expect(user0.get('id')).to.equal('surya');
- expect(user0.get('username')).to.equal('john');
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created0).to.be.null;
- } else {
- expect(created0).to.be.true;
- }
- const [user, created] = await User.upsert(
- { id: 'surya', username: 'doe' },
- { returning: true },
- );
- expect(user.get('id')).to.equal('surya');
- expect(user.get('username')).to.equal('doe');
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.false;
- }
- });
- it('should return default value set by the database (upsert)', async function () {
- const User = this.sequelize.define('User', {
- name: { type: DataTypes.STRING, primaryKey: true },
- code: { type: DataTypes.INTEGER, defaultValue: Sequelize.literal(2020) },
- });
- await User.sync({ force: true });
- const [user, created] = await User.upsert(
- { name: 'Test default value' },
- { returning: true },
- );
- expect(user.name).to.equal('Test default value');
- expect(user.code).to.equal(2020);
- if (['db2', 'sqlite3', 'postgres'].includes(dialectName)) {
- expect(created).to.be.null;
- } else {
- expect(created).to.be.true;
- }
- });
- });
- }
- if (sequelize.dialect.supports.inserts.conflictFields) {
- describe('conflictFields', () => {
- const vars = beforeEach2(async () => {
- // An Abstract joiner table. Unique constraint deliberately removed
- // to ensure that `conflictFields` is actually respected, not inferred.
- const Memberships = sequelize.define('memberships', {
- user_id: DataTypes.INTEGER,
- group_id: DataTypes.INTEGER,
- permissions: DataTypes.ENUM('admin', 'member'),
- });
- await Memberships.sync({ force: true });
- await sequelize.queryInterface.addConstraint('memberships', {
- type: 'UNIQUE',
- fields: ['user_id', 'group_id'],
- });
- return { Memberships };
- });
- it('should insert with no other rows', async () => {
- const { Memberships } = vars;
- const [newRow] = await Memberships.upsert(
- {
- user_id: 1,
- group_id: 1,
- permissions: 'member',
- },
- {
- conflictFields: ['user_id', 'group_id'],
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.permissions).to.eq('member');
- });
- it('should use conflictFields as upsertKeys', async () => {
- const { Memberships } = vars;
- const [originalMembership] = await Memberships.upsert(
- {
- user_id: 1,
- group_id: 1,
- permissions: 'member',
- },
- {
- conflictFields: ['user_id', 'group_id'],
- },
- );
- expect(originalMembership).to.not.eq(null);
- expect(originalMembership.permissions).to.eq('member');
- const [updatedMembership] = await Memberships.upsert(
- {
- user_id: 1,
- group_id: 1,
- permissions: 'admin',
- },
- {
- conflictFields: ['user_id', 'group_id'],
- },
- );
- expect(updatedMembership).to.not.eq(null);
- expect(updatedMembership.permissions).to.eq('admin');
- expect(updatedMembership.id).to.eq(originalMembership.id);
- const [otherMembership] = await Memberships.upsert(
- {
- user_id: 2,
- group_id: 1,
- permissions: 'member',
- },
- {
- conflictFields: ['user_id', 'group_id'],
- },
- );
- expect(otherMembership).to.not.eq(null);
- expect(otherMembership.permissions).to.eq('member');
- expect(otherMembership.id).to.not.eq(originalMembership.id);
- });
- it('should map conflictFields to column names', async () => {
- const Employees = sequelize.define('employees', {
- employeeId: {
- type: DataTypes.INTEGER,
- field: 'Employee_ID',
- },
- departmentId: {
- type: DataTypes.INTEGER,
- field: 'Department_ID',
- },
- position: DataTypes.ENUM('junior', 'senior'),
- });
- await Employees.sync({ force: true });
- await sequelize.queryInterface.addConstraint('employees', {
- type: 'UNIQUE',
- fields: ['Employee_ID', 'Department_ID'],
- });
- const [originalEmployee] = await Employees.upsert(
- {
- employeeId: 1,
- departmentId: 1,
- position: 'junior',
- },
- {
- conflictFields: ['employeeId', 'departmentId'],
- },
- );
- expect(originalEmployee).to.not.eq(null);
- expect(originalEmployee.position).to.eq('junior');
- const [updatedEmployee] = await Employees.upsert(
- {
- employeeId: 1,
- departmentId: 1,
- position: 'senior',
- },
- {
- conflictFields: ['employeeId', 'departmentId'],
- },
- );
- expect(updatedEmployee).to.not.eq(null);
- expect(updatedEmployee.position).to.eq('senior');
- expect(updatedEmployee.id).to.eq(originalEmployee.id);
- const [otherEmployee] = await Employees.upsert(
- {
- employeeId: 2,
- departmentId: 1,
- position: 'senior',
- },
- {
- conflictFields: ['employeeId', 'departmentId'],
- },
- );
- expect(otherEmployee).to.not.eq(null);
- expect(otherEmployee.position).to.eq('senior');
- expect(otherEmployee.id).to.not.eq(originalEmployee.id);
- });
- });
- }
- if (sequelize.dialect.supports.inserts.onConflictWhere) {
- describe('conflictWhere', () => {
- const vars = beforeEach2(async () => {
- const User = sequelize.define(
- 'users',
- {
- name: DataTypes.STRING,
- bio: DataTypes.STRING,
- isUnique: DataTypes.BOOLEAN,
- },
- {
- indexes: [
- {
- unique: true,
- fields: ['name'],
- where: { isUnique: true },
- },
- ],
- },
- );
- await User.sync({ force: true });
- return { User };
- });
- it('should insert with no other rows', async () => {
- const { User } = vars;
- const [newRow] = await User.upsert(
- {
- name: 'John',
- isUnique: true,
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('John');
- });
- it('should update with another unique user', async () => {
- const { User } = vars;
- let [newRow] = await User.upsert(
- {
- name: 'John',
- isUnique: true,
- bio: 'before',
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('John');
- expect(newRow.bio).to.eq('before');
- [newRow] = await User.upsert(
- {
- name: 'John',
- isUnique: true,
- bio: 'after',
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('John');
- expect(newRow.bio).to.eq('after');
- const rowCount = await User.count();
- expect(rowCount).to.eq(1);
- });
- it('allows both unique and non-unique users with the same name', async () => {
- const { User } = vars;
- let [newRow] = await User.upsert(
- {
- name: 'John',
- isUnique: true,
- bio: 'first',
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('John');
- expect(newRow.bio).to.eq('first');
- [newRow] = await User.upsert(
- {
- name: 'John',
- isUnique: false,
- bio: 'second',
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('John');
- expect(newRow.bio).to.eq('second');
- const rowCount = await User.count();
- expect(rowCount).to.eq(2);
- });
- it('allows for multiple unique users with different names', async () => {
- const { User } = vars;
- let [newRow] = await User.upsert(
- {
- name: 'John',
- isUnique: true,
- bio: 'first',
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('John');
- expect(newRow.bio).to.eq('first');
- [newRow] = await User.upsert(
- {
- name: 'Bob',
- isUnique: false,
- bio: 'second',
- },
- {
- conflictWhere: {
- isUnique: true,
- },
- },
- );
- expect(newRow).to.not.eq(null);
- expect(newRow.name).to.eq('Bob');
- expect(newRow.bio).to.eq('second');
- const rowCount = await User.count();
- expect(rowCount).to.eq(2);
- });
- });
- }
- });
- }
- });
|