knex/test/integration2/query/insert/inserts.spec.js
ROUL 57419fbbea
Missing comments on delete, update and insert (#5738)
Co-authored-by: Igor Savin <iselwin@gmail.com>
2023-11-28 02:19:51 +02:00

2322 lines
83 KiB
JavaScript

'use strict';
const chai = require('chai');
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));
const expect = chai.expect;
const _ = require('lodash');
const sinon = require('sinon');
const { TEST_TIMESTAMP } = require('../../../util/constants');
const {
isRedshift,
isPostgreSQL,
isSQLite,
isMssql,
isMysql,
isOracle,
isPgBased,
} = require('../../../util/db-helpers');
const {
getAllDbs,
getKnexForDb,
} = require('../../util/knex-instance-provider');
const logger = require('../../../integration/logger');
const {
createUsers,
createAccounts,
dropTables,
createTestTableTwo,
createDataType,
} = require('../../../util/tableCreatorHelper');
const {
assertNumber,
assertJsonEquals,
} = require('../../../util/assertHelper');
describe('Inserts', function () {
getAllDbs().forEach((db) => {
describe(db, () => {
let knex;
before(async () => {
knex = logger(getKnexForDb(db));
await dropTables(knex);
await createUsers(knex);
await createAccounts(knex, true);
await createTestTableTwo(knex);
await createDataType(knex);
});
after(async () => {
await dropTables(knex);
return knex.destroy();
});
beforeEach(async () => {
await knex('accounts').truncate();
await knex('test_table_two').truncate();
});
it('should handle simple inserts', async function () {
await knex('accounts')
.insert(
{
first_name: 'Test',
last_name: 'User',
email: 'test1@example.com',
logins: 1,
about: 'Lorem ipsum Dolore labore incididunt enim.',
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
'id'
)
.testSql(function (tester) {
tester(
'mysql',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test1@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
],
[1]
);
tester(
'pg',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?) returning "id"',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test1@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
],
[{ id: '1' }]
);
tester(
'pg-redshift',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test1@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
],
1
);
tester(
'sqlite3',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?) returning `id`',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test1@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
],
[{ id: 1 }]
);
tester(
'oracledb',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?) returning "id" into ?',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test1@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
[{ id: 1 }]
);
tester(
'mssql',
'insert into [accounts] ([about], [created_at], [email], [first_name], [last_name], [logins], [updated_at]) output inserted.[id] values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test1@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
],
[{ id: '1' }]
);
});
});
it('should handle multi inserts', async function () {
await knex('accounts')
.insert(
[
{
first_name: 'Test',
last_name: 'User',
email: 'test2@example.com',
logins: 1,
about: 'Lorem ipsum Dolore labore incididunt enim.',
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
{
first_name: 'Test',
last_name: 'User',
email: 'test3@example.com',
about: 'Lorem ipsum Dolore labore incididunt enim.',
logins: 2,
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
],
'id'
)
.testSql(function (tester) {
tester(
'mysql',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test2@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test3@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[1]
);
tester(
'pg',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?) returning "id"',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test2@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test3@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: '1' }, { id: '2' }]
);
tester(
'pg-redshift',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test2@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test3@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
2
);
tester(
'sqlite3',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` union all select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` returning `id`',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test2@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test3@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: 1 }, { id: 2 }]
);
tester(
'oracledb',
'begin execute immediate \'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (:1, :2, :3, :4, :5, :6, :7) returning "id" into :8\' using ?, ?, ?, ?, ?, ?, ?, out ?; execute immediate \'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (:1, :2, :3, :4, :5, :6, :7) returning "id" into :8\' using ?, ?, ?, ?, ?, ?, ?, out ?;end;',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test2@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test3@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
[{ id: 1 }, { id: 2 }]
);
tester(
'mssql',
'insert into [accounts] ([about], [created_at], [email], [first_name], [last_name], [logins], [updated_at]) output inserted.[id] values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test2@example.com',
'Test',
'User',
1,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test3@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: '1' }, { id: '2' }]
);
});
});
it('should allow for using the `asCallback` interface', function (ok) {
knex('test_table_two')
.insert(
[
{
account_id: 1,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 0,
},
{
account_id: 2,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 1,
},
{
account_id: 3,
details: '',
status: 1,
},
],
'id'
)
.testSql(function (tester) {
tester(
'oracledb',
'begin execute immediate \'insert into "test_table_two" ("account_id", "details", "status") values (:1, :2, :3) returning "id" into :4\' using ?, ?, ?, out ?; execute immediate \'insert into "test_table_two" ("account_id", "details", "status") values (:1, :2, :3) returning "id" into :4\' using ?, ?, ?, out ?; execute immediate \'insert into "test_table_two" ("account_id", "details", "status") values (:1, :2, :3) returning "id" into :4\' using ?, ?, ?, out ?;end;',
[
1,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
2,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
1,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
3,
'',
1,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
['1', '2', '3']
);
})
.asCallback(function (err) {
if (err) return ok(err);
ok();
});
});
it('should take hashes passed into insert and keep them in the correct order', async function () {
await knex('accounts')
.insert(
[
{
first_name: 'Test',
last_name: 'User',
email: 'test4@example.com',
about: 'Lorem ipsum Dolore labore incididunt enim.',
logins: 2,
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
{
first_name: 'Test',
about: 'Lorem ipsum Dolore labore incididunt enim.',
logins: 2,
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
last_name: 'User',
email: 'test5@example.com',
},
],
'id'
)
.testSql(function (tester) {
tester(
'mysql',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test4@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[1]
);
tester(
'pg',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?) returning "id"',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test4@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: '1' }, { id: '2' }]
);
tester(
'pg-redshift',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test4@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
2
);
tester(
'sqlite3',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` union all select ? as `about`, ? as `created_at`, ? as `email`, ? as `first_name`, ? as `last_name`, ? as `logins`, ? as `updated_at` returning `id`',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test4@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: 1 }, { id: 2 }]
);
tester(
'oracledb',
'begin execute immediate \'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (:1, :2, :3, :4, :5, :6, :7) returning "id" into :8\' using ?, ?, ?, ?, ?, ?, ?, out ?; execute immediate \'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (:1, :2, :3, :4, :5, :6, :7) returning "id" into :8\' using ?, ?, ?, ?, ?, ?, ?, out ?;end;',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test4@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
[{ id: 1 }, { id: 2 }]
);
tester(
'mssql',
'insert into [accounts] ([about], [created_at], [email], [first_name], [last_name], [logins], [updated_at]) output inserted.[id] values (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test4@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: '1' }, { id: '2' }]
);
});
});
it('will fail when multiple inserts are made into a unique column', async function () {
if (isRedshift(knex)) {
return this.skip();
}
await knex('accounts').where('id', '>', 1).orWhere('x', 2).insert(
{
first_name: 'Test',
last_name: 'User',
email: 'test5@example.com',
about: 'Lorem ipsum Dolore labore incididunt enim.',
logins: 2,
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
'id'
);
await knex('accounts')
.where('id', '>', 1)
.orWhere('x', 2)
.insert(
{
first_name: 'Test',
last_name: 'User',
email: 'test5@example.com',
about: 'Lorem ipsum Dolore labore incididunt enim.',
logins: 2,
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
'id'
)
.testSql(function (tester) {
tester(
'mysql',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
]
);
tester(
'pg',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?) returning "id"',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
]
);
tester(
'sqlite3',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?) returning `id`',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
]
);
tester(
'oracledb',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?) returning "id" into ?',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
]
);
tester(
'mssql',
'insert into [accounts] ([about], [created_at], [email], [first_name], [last_name], [logins], [updated_at]) output inserted.[id] values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test5@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
]
);
})
.then(
function () {
throw new Error(
'There should be a fail when multi-insert are made in unique col.'
);
},
function () {}
);
});
it('should drop any where clause bindings', async function () {
await knex('accounts')
.where('id', '>', 1)
.orWhere('x', 2)
.insert(
{
first_name: 'Test',
last_name: 'User',
email: 'test6@example.com',
about: 'Lorem ipsum Dolore labore incididunt enim.',
logins: 2,
created_at: TEST_TIMESTAMP,
updated_at: TEST_TIMESTAMP,
},
'id'
)
.testSql(function (tester) {
tester(
'mysql',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test6@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[1]
);
tester(
'pg',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?) returning "id"',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test6@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: '1' }]
);
tester(
'pg-redshift',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test6@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
1
);
tester(
'sqlite3',
'insert into `accounts` (`about`, `created_at`, `email`, `first_name`, `last_name`, `logins`, `updated_at`) values (?, ?, ?, ?, ?, ?, ?) returning `id`',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test6@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: 1 }]
);
tester(
'oracledb',
'insert into "accounts" ("about", "created_at", "email", "first_name", "last_name", "logins", "updated_at") values (?, ?, ?, ?, ?, ?, ?) returning "id" into ?',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test6@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
[[{ id: 1 }]]
);
tester(
'mssql',
'insert into [accounts] ([about], [created_at], [email], [first_name], [last_name], [logins], [updated_at]) output inserted.[id] values (?, ?, ?, ?, ?, ?, ?)',
[
'Lorem ipsum Dolore labore incididunt enim.',
TEST_TIMESTAMP,
'test6@example.com',
'Test',
'User',
2,
TEST_TIMESTAMP,
],
[{ id: '1' }]
);
});
});
it('should not allow inserting invalid values into enum fields', async function () {
await knex('datatype_test')
.insert({ enum_value: 'd' })
.testSql(function (tester) {
tester(
'mysql',
'insert into `datatype_test` (`enum_value`) values (?)',
['d']
);
tester(
'pg',
'insert into "datatype_test" ("enum_value") values (?)',
['d']
);
tester(
'pg-redshift',
'insert into "datatype_test" ("enum_value") values (?)',
['d']
);
tester(
'sqlite3',
'insert into `datatype_test` (`enum_value`) values (?)',
['d'],
[1]
);
tester(
'oracledb',
'insert into "datatype_test" ("enum_value") values (?)',
['d']
);
tester(
'mssql',
'insert into [datatype_test] ([enum_value]) values (?)',
['d']
);
})
.then(
function () {
// No errors happen in sqlite3, which doesn't have native support
// for the enum type.
if (!isSQLite(knex)) {
throw new Error(
'There should be an error for invalid enum inserts'
);
}
},
function () {}
);
});
it('should not allow invalid uuids in postgresql', async function () {
await knex('datatype_test')
.insert({
enum_value: 'c',
uuid: 'c39d8fcf-68a0-4902-b192-1ebb6310d9ad',
})
.then(function () {
return knex('datatype_test').insert({
enum_value: 'c',
uuid: 'test',
});
})
.then(
function () {
// No errors happen in sqlite3 or mysql, which don't have native support
// for the uuid type.
if (isPostgreSQL(knex) || isMssql(knex)) {
throw new Error(
'There should be an error in postgresql for uuids'
);
}
},
function () {}
);
});
it('should not mutate the array passed in', async function () {
const a = {
enum_value: 'a',
uuid: '00419fc1-7eed-442c-9c01-cf757e74b8f0',
};
const b = {
enum_value: 'c',
uuid: '13ac5acd-c5d7-41a0-8db0-dacf64d0e4e2',
};
const x = [a, b];
await knex('datatype_test').insert(x);
expect(x).to.eql([a, b]);
});
it('should throw an error if the array passed in is empty', async function () {
await expect(knex('account').insert([])).to.be.rejectedWith(
Error,
'The query is empty'
);
});
it('should handle empty inserts', async function () {
await knex.schema.createTable('test_default_table', function (qb) {
qb.increments().primary();
qb.string('string').defaultTo('hello');
qb.tinyint('tinyint').defaultTo(0);
qb.text('text').nullable();
});
await knex('test_default_table')
.insert({}, 'id')
.testSql(function (tester) {
tester(
'mysql',
'insert into `test_default_table` () values ()',
[],
[1]
);
tester(
'pg',
'insert into "test_default_table" default values returning "id"',
[],
[{ id: 1 }]
);
tester(
'pg-redshift',
'insert into "test_default_table" default values',
[],
1
);
tester(
'sqlite3',
'insert into `test_default_table` default values',
[],
[1]
);
tester(
'oracledb',
'insert into "test_default_table" ("id") values (default) returning "id" into ?',
[
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
[{ id: 1 }]
);
tester(
'mssql',
'insert into [test_default_table] output inserted.[id] default values',
[],
[{ id: 1 }]
);
});
});
it('#5738 should handle insert with comments', async function () {
await knex('test_default_table')
.insert({}, 'id')
.comment('insert into test_default_table')
.testSql(function (tester) {
tester(
'mysql',
'/* insert into test_default_table */ insert into `test_default_table` () values ()',
[],
[2]
);
});
});
it('should handle empty arrays inserts', async function () {
await knex.schema.createTable('test_default_table2', function (qb) {
qb.increments().primary();
qb.string('string').defaultTo('hello');
qb.tinyint('tinyint').defaultTo(0);
qb.text('text').nullable();
});
await knex('test_default_table2')
.insert([{}], 'id')
.testSql(function (tester) {
tester(
'mysql',
'insert into `test_default_table2` () values ()',
[],
[1]
);
tester(
'pg',
'insert into "test_default_table2" default values returning "id"',
[],
[{ id: 1 }]
);
tester(
'pg-redshift',
'insert into "test_default_table2" default values',
[],
1
);
tester(
'sqlite3',
'insert into `test_default_table2` default values',
[],
[1]
);
tester(
'oracledb',
'insert into "test_default_table2" ("id") values (default) returning "id" into ?',
[
function (v) {
return v.toString() === '[object ReturningHelper:id]';
},
],
[{ id: 1 }]
);
tester(
'mssql',
'insert into [test_default_table2] output inserted.[id] default values',
[],
[{ id: 1 }]
);
});
});
it('should take an array of columns to return in oracle or postgres', async function () {
const insertData = {
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 0,
};
const rows = await knex('test_table_two')
.insert(insertData, ['account_id', 'details'])
.testSql(function (tester) {
tester(
'mysql',
'insert into `test_table_two` (`account_id`, `details`, `status`) values (?, ?, ?)',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
[1]
);
tester(
'pg',
'insert into "test_table_two" ("account_id", "details", "status") values (?, ?, ?) returning "account_id", "details"',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
[
{
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
},
]
);
tester(
'pg-redshift',
'insert into "test_table_two" ("account_id", "details", "status") values (?, ?, ?)',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
1
);
tester(
'sqlite3',
'insert into `test_table_two` (`account_id`, `details`, `status`) values (?, ?, ?) returning `account_id`, `details`',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
[
{
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
},
]
);
tester(
'oracledb',
`insert into "test_table_two" ("account_id", "details", "status") values (?, ?, ?) returning "account_id","details" into ?,?`,
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
function (v) {
return v.toString() === '[object ReturningHelper:account_id]';
},
function (v) {
return v.toString() === '[object ReturningHelper:details]';
},
],
[
{
account_id: '10',
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
},
]
);
tester(
'mssql',
'insert into [test_table_two] ([account_id], [details], [status]) output inserted.[account_id], inserted.[details] values (?, ?, ?)',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
[
{
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
},
]
);
});
if (isRedshift(knex)) {
return expect(rows).to.equal(1);
}
expect(rows.length).to.equal(1);
if (isPostgreSQL(knex)) {
expect(_.keys(rows[0]).length).to.equal(2);
expect(rows[0].account_id).to.equal(insertData.account_id);
expect(rows[0].details).to.equal(insertData.details);
}
});
it('should allow a * for returning in postgres and oracle', async function () {
if (isRedshift(knex)) {
return this.skip();
}
const insertData = {
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 0,
};
const returningColumn = '*';
const rows = await knex('test_table_two')
.insert(insertData, returningColumn)
.testSql(function (tester) {
tester(
['pg'],
'insert into "test_table_two" ("account_id", "details", "status") values (?, ?, ?) returning *',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
[
{
id: 1,
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 0,
},
]
);
tester(
'oracledb',
'insert into "test_table_two" ("account_id", "details", "status") values (?, ?, ?) returning "ROWID" into ?',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
function (v) {
return v.toString() === '[object ReturningHelper:ROWID]';
},
],
[
{
id: 1,
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 0,
},
]
);
tester(
'mssql',
'insert into [test_table_two] ([account_id], [details], [status]) output inserted.* values (?, ?, ?)',
[
10,
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
0,
],
[
{
id: 1,
account_id: 10,
details:
'Lorem ipsum Minim nostrud Excepteur consectetur enim ut qui sint in veniam in nulla anim do cillum sunt voluptate Duis non incididunt.',
status: 0,
},
]
);
});
expect(rows.length).to.equal(1);
if (isPgBased(knex)) {
expect(_.keys(rows[0]).length).to.equal(4);
assertNumber(knex, rows[0].account_id, insertData.account_id);
expect(rows[0].details).to.equal(insertData.details);
expect(rows[0].status).to.equal(insertData.status);
}
});
describe('batchInsert', function () {
const fiftyLengthString =
'rO8F8YrFS6uoivuRiVnwrO8F8YrFS6uoivuRiVnwuoivuRiVnw';
const items = [];
const amountOfItems = 100;
const amountOfColumns = 30;
for (let i = 0; i < amountOfItems; i++) {
const item = {};
for (let x = 0; x < amountOfColumns; x++) {
item['Col' + x] = fiftyLengthString;
}
items.push(item);
}
beforeEach(async () => {
await knex.schema.dropTableIfExists('BatchInsert');
await knex.schema.createTable('BatchInsert', (table) => {
for (let i = 0; i < amountOfColumns; i++) {
table.string('Col' + i, 50);
}
});
});
it('#757 - knex.batchInsert(tableName, bulk, chunkSize)', async function () {
this.timeout(30000);
const result = await knex
.batchInsert('BatchInsert', items, 30)
.returning(['Col1', 'Col2']);
//Returning only supported by some dialects.
if (isPostgreSQL(knex) || isOracle(knex)) {
result.forEach(function (item) {
expect(item.Col1).to.equal(fiftyLengthString);
expect(item.Col2).to.equal(fiftyLengthString);
});
}
const selectResult = await knex('BatchInsert').select();
const count = selectResult.length;
expect(count).to.equal(amountOfItems);
});
it('#1880 - Duplicate keys in batchInsert should not throw unhandled exception', async function () {
if (isRedshift(knex)) {
return this.skip();
}
this.timeout(10000);
const fn = sinon.stub();
process.on('unhandledRejection', fn);
await knex.schema.dropTableIfExists('batchInsertDuplicateKey');
await knex.schema.createTable(
'batchInsertDuplicateKey',
function (table) {
table.string('col').notNullable();
table.primary('col');
}
);
const rows = [{ col: 'a' }, { col: 'a' }];
try {
await knex.batchInsert(
'batchInsertDuplicateKey',
rows,
rows.length
);
} catch (err) {
//Should reach this point before timeout of 10s
expect(err.message.toLowerCase()).to.include(
'batchinsertduplicatekey'
);
expect(fn).have.not.been.called;
process.removeListener('unhandledRejection', fn);
return;
}
expect.fail('Should not reach this point');
});
it('knex.batchInsert with specified transaction', async function () {
await knex.transaction(function (tr) {
knex
.batchInsert('BatchInsert', items, 30)
.returning(['Col1', 'Col2'])
.transacting(tr)
.then(tr.commit)
.catch(tr.rollback);
});
});
it('transaction.batchInsert using specified transaction', async function () {
await knex.transaction(function (tr) {
return tr
.batchInsert('BatchInsert', items, 30)
.returning(['Col1', 'Col2']);
});
});
});
it('should validate batchInsert batchSize parameter', async function () {
//Should not throw, batchSize default
await knex.batchInsert('test', []);
try {
knex.batchInsert('test', [], null);
} catch (error) {
expect(error.message).to.equal('Invalid chunkSize: null');
try {
knex.batchInsert('test', [], 0);
} catch (error) {
expect(error.message).to.equal('Invalid chunkSize: 0');
try {
//Also faulty
knex.batchInsert('test', [], 'still no good');
} catch (error) {
expect(error.message).to.equal(
'Invalid chunkSize: still no good'
);
return true;
}
}
}
});
it('should replace undefined keys in multi insert with DEFAULT', async function () {
if (isSQLite(knex)) {
return true;
}
await knex('accounts').insert(
[
{
last_name: 'First Item',
email: 'single-test1@example.com',
about: 'Lorem ipsum Dolore labore incididunt enim.',
created_at: new Date(),
updated_at: new Date(),
},
{
last_name: 'Second Item',
email: 'double-test1@example.com',
logins: 2,
created_at: new Date(),
updated_at: new Date(),
},
],
'*'
);
const results = await knex('accounts')
.whereIn('email', [
'single-test1@example.com',
'double-test1@example.com',
])
.orderBy('email', 'desc');
assertNumber(knex, results[0].logins, 1);
expect(results[1].about).to.equal(null);
// cleanup to prevent needs for too much changes to other tests
await knex('accounts')
.delete()
.whereIn(
'id',
results.map(function (row) {
return row.id;
})
);
});
it('will silently do nothing when multiple inserts are made into a unique column and ignore is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert({
email: 'ignoretest1@example.com',
name: 'BEFORE',
});
// Test: Insert..ignore with same email as existing row
try {
await knex('upsert_tests')
.insert(
{ email: 'ignoretest1@example.com', name: 'AFTER' },
'email'
)
.onConflict('email')
.ignore()
.testSql(function (tester) {
tester(
'mysql',
'insert ignore into `upsert_tests` (`email`, `name`) values (?, ?)',
['ignoretest1@example.com', 'AFTER']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict ("email") do nothing returning "email"',
['ignoretest1@example.com', 'AFTER']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do nothing returning `email`',
['ignoretest1@example.com', 'AFTER']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Assert: there is still only 1 row, and that it HAS NOT been updated
const rows = await knex('upsert_tests')
.where({ email: 'ignoretest1@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('BEFORE');
});
it('will still silently do nothing when multiple inserts are made into a unique column and ignore is specified with no columns', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert({
email: 'ignoretest1@example.com',
name: 'BEFORE',
});
// Test: Insert..ignore with same email as existing row
try {
await knex('upsert_tests')
.insert(
{ email: 'ignoretest1@example.com', name: 'AFTER' },
'email'
)
.onConflict()
.ignore()
.testSql(function (tester) {
tester(
'mysql',
'insert ignore into `upsert_tests` (`email`, `name`) values (?, ?)',
['ignoretest1@example.com', 'AFTER']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict do nothing returning "email"',
['ignoretest1@example.com', 'AFTER']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict do nothing returning `email`',
['ignoretest1@example.com', 'AFTER']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Assert: there is still only 1 row, and that it HAS NOT been updated
const rows = await knex('upsert_tests')
.where({ email: 'ignoretest1@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('BEFORE');
});
it('will silently do nothing when multiple inserts are made into a composite unique column and ignore is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_composite_key_tests');
await knex.schema.createTable('upsert_composite_key_tests', (table) => {
table.string('name');
table.string('email');
table.string('org');
table.unique(['org', 'email']);
});
// Setup: Create row to conflict against
await knex('upsert_composite_key_tests').insert({
org: 'acme-inc',
email: 'ignoretest1@example.com',
name: 'BEFORE',
});
// Test: Insert..ignore with same email as existing row
try {
await knex('upsert_composite_key_tests')
.insert(
{
org: 'acme-inc',
email: 'ignoretest1@example.com',
name: 'AFTER',
},
'email'
)
.onConflict(['org', 'email'])
.ignore()
.testSql(function (tester) {
tester(
'mysql',
'insert ignore into `upsert_composite_key_tests` (`email`, `name`, `org`) values (?, ?, ?)',
['ignoretest1@example.com', 'AFTER', 'acme-inc']
);
tester(
'pg',
'insert into "upsert_composite_key_tests" ("email", "name", "org") values (?, ?, ?) on conflict ("org", "email") do nothing returning "email"',
['ignoretest1@example.com', 'AFTER', 'acme-inc']
);
tester(
'sqlite3',
'insert into `upsert_composite_key_tests` (`email`, `name`, `org`) values (?, ?, ?) on conflict (`org`, `email`) do nothing returning `email`',
['ignoretest1@example.com', 'AFTER', 'acme-inc']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Assert: there is still only 1 row, and that it HAS NOT been updated
const rows = await knex('upsert_composite_key_tests')
.where({ email: 'ignoretest1@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('BEFORE');
});
it('updates columns when inserting a duplicate key to unique column and merge is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert({
email: 'mergetest1@example.com',
name: 'BEFORE',
});
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert({ email: 'mergetest1@example.com', name: 'AFTER' }, 'email')
.onConflict('email')
.merge()
.testSql(function (tester) {
tester(
'mysql',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on duplicate key update `email` = values(`email`), `name` = values(`name`)',
['mergetest1@example.com', 'AFTER']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict ("email") do update set "email" = excluded."email", "name" = excluded."name" returning "email"',
['mergetest1@example.com', 'AFTER']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` returning `email`',
['mergetest1@example.com', 'AFTER']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests')
.where({ email: 'mergetest1@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('AFTER');
});
it('conditionally updates rows when inserting a duplicate key to unique column and merge with where clause matching row(s) is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.string('role');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert({
email: 'mergetest1@example.com',
role: 'tester',
name: 'BEFORE',
});
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert({ email: 'mergetest1@example.com', name: 'AFTER' }, 'email')
.onConflict('email')
.merge()
.where('upsert_tests.role', 'tester')
.testSql(function (tester) {
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict ("email") do update set "email" = excluded."email", "name" = excluded."name" where "upsert_tests"."role" = ? returning "email"',
['mergetest1@example.com', 'AFTER', 'tester']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` where `upsert_tests`.`role` = ? returning `email`',
['mergetest1@example.com', 'AFTER', 'tester']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
if (isMysql(knex)) {
expect(err).to.be.an('error');
if (
err.message.includes(
'.onConflict().merge().where() is not supported for'
)
)
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests')
.where({ email: 'mergetest1@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('AFTER');
});
it('will silently do nothing when inserting a duplicate key to unique column and merge with where clause matching no rows is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.string('role');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert({
email: 'mergetest1@example.com',
role: 'tester',
name: 'BEFORE',
});
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert({ email: 'mergetest1@example.com', name: 'AFTER' }, 'email')
.onConflict('email')
.merge()
.where('upsert_tests.role', 'fake-role')
.testSql(function (tester) {
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict ("email") do update set "email" = excluded."email", "name" = excluded."name" where "upsert_tests"."role" = ? returning "email"',
['mergetest1@example.com', 'AFTER', 'fake-role']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` where `upsert_tests`.`role` = ? returning `email`',
['mergetest1@example.com', 'AFTER', 'fake-role']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
if (isMysql(knex)) {
expect(err).to.be.an('error');
if (
err.message.includes(
'.onConflict().merge().where() is not supported for'
)
)
return;
}
throw err;
}
// Check that row HAS NOT been updated
const rows = await knex('upsert_tests')
.where({ email: 'mergetest1@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('BEFORE');
});
it('updates all columns with raw value when inserting a duplicate key to unique column and merge is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert([
{ email: 'mergesource@example.com', name: 'SOURCE' },
{ email: 'mergedest@example.com', name: 'DEST' },
]);
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert(
{
email: 'mergedest@example.com',
name: knex.raw(
"(SELECT name FROM (SELECT * FROM upsert_tests) AS t WHERE email = 'mergesource@example.com')"
),
},
'email'
)
.onConflict('email')
.merge()
.testSql(function (tester) {
tester(
'mysql',
"insert into `upsert_tests` (`email`, `name`) values (?, (SELECT name FROM (SELECT * FROM upsert_tests) AS t WHERE email = 'mergesource@example.com')) on duplicate key update `email` = values(`email`), `name` = values(`name`)",
['mergedest@example.com']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, (SELECT name FROM (SELECT * FROM upsert_tests) AS t WHERE email = \'mergesource@example.com\')) on conflict ("email") do update set "email" = excluded."email", "name" = excluded."name" returning "email"',
['mergedest@example.com']
);
tester(
'sqlite3',
"insert into `upsert_tests` (`email`, `name`) values (?, (SELECT name FROM (SELECT * FROM upsert_tests) AS t WHERE email = 'mergesource@example.com')) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` returning `email`",
['mergedest@example.com']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests')
.where({ email: 'mergedest@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('SOURCE');
});
it('updates columns with raw value when inserting a duplicate key to unique column and merge with update data is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup table for testing knex.raw with
await knex.schema.dropTableIfExists('upsert_value_source');
await knex.schema.createTable('upsert_value_source', (table) => {
table.string('name');
});
await knex('upsert_value_source').insert([{ name: 'SOURCE' }]);
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert([
{ email: 'mergedest@example.com', name: 'DEST' },
]);
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert(
{ email: 'mergedest@example.com', name: 'SHOULD NOT BE USED' },
'email'
)
.onConflict('email')
.merge({ name: knex.raw('(SELECT name FROM upsert_value_source)') })
.testSql(function (tester) {
tester(
'mysql',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on duplicate key update `name` = (SELECT name FROM upsert_value_source)',
['mergedest@example.com', 'SHOULD NOT BE USED']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict ("email") do update set "name" = (SELECT name FROM upsert_value_source) returning "email"',
['mergedest@example.com', 'SHOULD NOT BE USED']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `name` = (SELECT name FROM upsert_value_source) returning `email`',
['mergedest@example.com', 'SHOULD NOT BE USED']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests')
.where({ email: 'mergedest@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('SOURCE');
});
it('updates specified columns with insert value when inserting a duplicate key to unique column and merge with update columns is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup table for testing knex.raw with
await knex.schema.dropTableIfExists('upsert_value_source');
await knex.schema.createTable('upsert_value_source', (table) => {
table.string('name');
});
await knex('upsert_value_source').insert([{ name: 'SOURCE' }]);
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert([
{ email: 'mergedest@example.com', name: 'DEST' },
]);
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert(
{ email: 'mergedest@example.com', name: 'SHOULD BE USED' },
'email'
)
.onConflict('email')
.merge(['name'])
.testSql(function (tester) {
tester(
'mysql',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on duplicate key update `name` = values(`name`)',
['mergedest@example.com', 'SHOULD BE USED']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?) on conflict ("email") do update set "name" = excluded."name" returning "email"',
['mergedest@example.com', 'SHOULD BE USED']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) values (?, ?) on conflict (`email`) do update set `name` = excluded.`name` returning `email`',
['mergedest@example.com', 'SHOULD BE USED']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests')
.where({ email: 'mergedest@example.com' })
.select();
expect(rows.length).to.equal(1);
expect(rows[0].name).to.equal('SHOULD BE USED');
});
it('updates and inserts columns when inserting multiple rows merge is specified', async function () {
if (isRedshift(knex)) {
return this.skip();
}
// Setup: Create table with unique email column
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('email');
table.unique('email');
});
// Setup: Create row to conflict against
await knex('upsert_tests').insert([
{ email: 'one@example.com', name: 'BEFORE' },
{ email: 'two@example.com', name: 'BEFORE' },
]);
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert(
[
{ email: 'two@example.com', name: 'AFTER' },
{ email: 'three@example.com', name: 'AFTER' },
],
'email'
)
.onConflict('email')
.merge()
.testSql(function (tester) {
tester(
'mysql',
'insert into `upsert_tests` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `email` = values(`email`), `name` = values(`name`)',
['two@example.com', 'AFTER', 'three@example.com', 'AFTER']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name") values (?, ?), (?, ?) on conflict ("email") do update set "email" = excluded."email", "name" = excluded."name" returning "email"',
['two@example.com', 'AFTER', 'three@example.com', 'AFTER']
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` where true on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name` returning `email`',
['two@example.com', 'AFTER', 'three@example.com', 'AFTER']
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests').select();
expect(rows.length).to.equal(3);
const row1 = rows.find((row) => row.email === 'one@example.com');
expect(row1 && row1.name).to.equal('BEFORE');
const row2 = rows.find((row) => row.email === 'two@example.com');
expect(row2 && row2.name).to.equal('AFTER');
const row3 = rows.find((row) => row.email === 'three@example.com');
expect(row3 && row3.name).to.equal('AFTER');
});
it('update values on conflict with "where" condition and partial unique index #4590', async function () {
if (!isPostgreSQL(knex) && !isSQLite(knex)) {
return this.skip();
}
await knex.schema.dropTableIfExists('upsert_tests');
await knex.schema.createTable('upsert_tests', (table) => {
table.string('name');
table.string('type');
table.string('email');
});
await knex.raw(
'create unique index email_type1 ' +
'on upsert_tests(email) ' +
"where type = 'type1'"
);
await knex('upsert_tests').insert([
{ email: 'one@example.com', name: 'BEFORE', type: 'type1' },
{ email: 'two@example.com', name: 'BEFORE', type: 'type1' },
{ email: 'two@example.com', name: 'BEFORE', type: 'type2' },
]);
// Perform insert..merge (upsert)
try {
await knex('upsert_tests')
.insert([
{ email: 'one@example.com', name: 'AFTER', type: 'type1' },
{ email: 'two@example.com', name: 'AFTER', type: 'type1' },
{ email: 'three@example.com', name: 'AFTER', type: 'type1' },
])
.onConflict(knex.raw("(email) where type = 'type1'"))
.merge()
.testSql(function (tester) {
tester(
'mysql',
'insert into `upsert_tests` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `email` = values(`email`), `name` = values(`name`)',
['two@example.com', 'AFTER', 'three@example.com', 'AFTER']
);
tester(
'pg',
'insert into "upsert_tests" ("email", "name", "type") values (?, ?, ?), (?, ?, ?), (?, ?, ?) on conflict (email) where type = \'type1\' do update set "email" = excluded."email", "name" = excluded."name", "type" = excluded."type"',
[
'one@example.com',
'AFTER',
'type1',
'two@example.com',
'AFTER',
'type1',
'three@example.com',
'AFTER',
'type1',
]
);
tester(
'sqlite3',
'insert into `upsert_tests` (`email`, `name`, `type`) select ? as `email`, ? as `name`, ? as `type` union all select ? as `email`, ? as `name`, ? as `type` union all select ? as `email`, ? as `name`, ? as `type` where true ' +
"on conflict (email) where type = 'type1' do update set `email` = excluded.`email`, `name` = excluded.`name`, `type` = excluded.`type`",
[
'one@example.com',
'AFTER',
'type1',
'two@example.com',
'AFTER',
'type1',
'three@example.com',
'AFTER',
'type1',
]
);
});
} catch (err) {
if (isOracle(knex) || isMssql(knex)) {
expect(err).to.be.an('error');
if (err.message.includes('.onConflict() is not supported for'))
return;
}
throw err;
}
// Check that row HAS been updated
const rows = await knex('upsert_tests')
.select()
.orderBy(['email', 'name']);
expect(rows.length).to.equal(4);
expect(rows).to.eql([
{ email: 'one@example.com', name: 'AFTER', type: 'type1' }, // type1 => updated
{ email: 'three@example.com', name: 'AFTER', type: 'type1' },
{ email: 'two@example.com', name: 'AFTER', type: 'type1' }, // type1 => updated
{ email: 'two@example.com', name: 'BEFORE', type: 'type2' }, // type2 => not updated
]);
});
it('#1423 should replace undefined keys in single insert with DEFAULT also in transacting query', async function () {
if (isSQLite(knex)) {
return true;
}
await knex.transaction(function (trx) {
return trx('accounts')
.insert({
last_name: 'First Item',
email: 'findme@example.com',
logins: undefined,
about: 'Lorem ipsum Dolore labore incididunt enim.',
created_at: new Date(),
updated_at: new Date(),
})
.then(function (results) {
return trx('accounts').where('email', 'findme@example.com');
})
.then(function (results) {
assertNumber(knex, results[0].logins, 1);
// cleanup to prevent needs for too much changes to other tests
return trx('accounts').delete().where('id', results[0].id);
});
});
});
it('should insert arrays into postgres array columns #5365', async function () {
if (!isPostgreSQL(knex)) {
return this.skip();
}
await knex.schema.dropTableIfExists('redirect_array');
await knex.schema.createTable('redirect_array', (table) => {
table.increments();
table.string('name');
table.specificType('redirect_urls', 'text ARRAY');
});
await knex('redirect_array')
.insert(
{
name: 'knex',
redirect_urls: [
'https://knexjs.org/',
'https://knexjs.org/guide/',
],
},
'id'
)
.testSql(function (tester) {
tester(
'pg',
'insert into "redirect_array" ("name", "redirect_urls") values (?, ?) returning "id"',
['knex', ['https://knexjs.org/', 'https://knexjs.org/guide/']],
[{ id: 1 }]
);
});
});
it('insert json object to json column', async function () {
if (!isPostgreSQL(knex)) {
return this.skip();
}
const tableName = 'json';
const jsonObject = {
foo: {
bar: 'baz',
},
};
await knex.schema.dropTableIfExists(tableName);
await knex.schema.createTable(tableName, (table) => {
table.increments();
table.string('name');
table.jsonb('content');
});
await knex(tableName)
.insert(
{
name: 'json_object',
content: jsonObject,
},
'id'
)
.testSql(function (tester) {
tester(
'pg',
`insert into "${tableName}" ("content", "name") values (?, ?) returning "id"`,
[JSON.stringify(jsonObject), 'json_object']
);
})
.then(([insertResult]) =>
knex(tableName).where('id', insertResult.id)
)
.then((result) => {
expect(result.length).to.equal(1);
assertJsonEquals(result[0].content, jsonObject);
});
});
it('insert number array to integer ARRAY column', async function () {
if (!isPostgreSQL(knex)) {
return this.skip();
}
const tableName = 'integer_array';
const integerArrayContent = [1, 2, 3, 42, -100];
await knex.schema.dropTableIfExists(tableName);
await knex.schema.createTable(tableName, (table) => {
table.increments();
table.string('name');
table.specificType('content', 'integer ARRAY');
});
await knex(tableName)
.insert(
{
name: 'integer_array',
content: integerArrayContent,
},
'id'
)
.testSql(function (tester) {
tester(
'pg',
`insert into "${tableName}" ("content", "name") values (?, ?) returning "id"`,
[integerArrayContent, 'integer_array']
);
})
.then(([insertResult]) =>
knex(tableName).where('id', insertResult.id)
)
.then((result) => {
expect(result.length).to.equal(1);
assertJsonEquals(result[0].content, integerArrayContent);
});
});
describe('text array', () => {
const tableName = 'text_array';
beforeEach(async () => {
if (!isPostgreSQL(knex)) {
return true;
}
await knex.schema.dropTableIfExists(tableName);
await knex.schema.createTable(tableName, (table) => {
table.increments();
table.string('name');
table.specificType('content', 'text ARRAY');
});
});
it('#5365 should insert string array to text ARRAY column', async function () {
if (!isPostgreSQL(knex)) {
return this.skip();
}
const stringArrayContent = ['SOME TEXT', 'SOME OTHER TEXT'];
await knex(tableName)
.insert(
{
name: 'array_of_string',
content: stringArrayContent,
},
'id'
)
.testSql(function (tester) {
tester(
'pg',
`insert into "${tableName}" ("content", "name") values (?, ?) returning "id"`,
[stringArrayContent, 'array_of_string'],
[{ id: 1 }]
);
})
.then(([insertResult]) =>
knex(tableName).where('id', insertResult.id)
)
.then((result) => {
expect(result.length).to.equal(1);
expect(result[0].content).to.deep.equal(stringArrayContent);
});
});
it(`#5430 should insert data to text array column if it's an array of object`, async function () {
if (!isPostgreSQL(knex)) {
return this.skip();
}
const arrayOfObject = [
{
foo: {
bar: 'baz',
},
},
];
await knex(tableName)
.insert(
{
name: 'array_of_object',
content: arrayOfObject,
},
'id'
)
.testSql(function (tester) {
tester(
'pg',
`insert into "${tableName}" ("content", "name") values (?, ?) returning "id"`,
[arrayOfObject, 'array_of_object'],
[{ id: 1 }]
);
})
.then(([insertResult]) =>
knex(tableName).where('id', insertResult.id)
)
.then((result) => {
expect(result.length).to.equal(1);
assertJsonEquals(result[0].content, arrayOfObject);
});
});
});
});
});
});