Skip to content

Commit

Permalink
Adding tests and fixing existing ones
Browse files Browse the repository at this point in the history
  • Loading branch information
code-ape committed Dec 30, 2023
1 parent 4e5c9a0 commit 128dde5
Show file tree
Hide file tree
Showing 11 changed files with 474 additions and 44 deletions.
1 change: 1 addition & 0 deletions lib/client.js
Expand Up @@ -194,6 +194,7 @@ class Client extends EventEmitter {
}

initializeDriver() {
if (this.driver) return;
try {
this.driver = this._driver();
} catch (e) {
Expand Down
11 changes: 6 additions & 5 deletions lib/dialects/sqlite3/index.js
Expand Up @@ -16,7 +16,7 @@ const ViewCompiler = require('./schema/sqlite-viewcompiler');
const SQLite3_DDL = require('./schema/ddl');
const Formatter = require('../../formatter');
const QueryBuilder = require('./query/sqlite-querybuilder');
const { parseVersion, compareVersions } = require('../../util/version');
const { parseVersion, satisfiesVersion } = require('../../util/version');

class Client_SQLite3 extends Client {
constructor(config) {
Expand All @@ -34,7 +34,7 @@ class Client_SQLite3 extends Client {
this.logger.warn(
'sqlite does not support inserting default values. Set the ' +
'`useNullAsDefault` flag to hide this warning. ' +
'(see docs http://knexjs.org/#Builder-insert).'
'(see docs https://knexjs.org/guide/query-builder.html#insert).'
);
}
}
Expand All @@ -44,12 +44,13 @@ class Client_SQLite3 extends Client {
}

/**
* Get `Version` from client or return `[0, 0, 0]`
* Get `Version` from client or return `[0, 0, 0]` on failure.
*
* @returns {[number, number, number]}
*/
_clientVersion() {
const version = parseVersion(this.client.VERSION);
this.initializeDriver();
const version = parseVersion(this.driver.VERSION);
if (!version) return [0, 0, 0];
return version;
}
Expand All @@ -62,7 +63,7 @@ class Client_SQLite3 extends Client {
* @returns {boolean}
*/
_satisfiesVersion(minVersion, maxVersion) {
return compareVersions(this._clientVersion(), minVersion, maxVersion);
return satisfiesVersion(this._clientVersion(), minVersion, maxVersion);
}

schemaCompiler() {
Expand Down
2 changes: 1 addition & 1 deletion lib/dialects/sqlite3/query/sqlite-querycompiler.js
Expand Up @@ -104,7 +104,7 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
parametersArray.push(`(${parameter})`);
}
// 'insert into TABLE_NAME (column1, column2, ...) values (v1, v2, ...), (v3, v4, ...), ...'
sql += ` values (${parametersArray.join(', ')})`;
sql += ` values ${parametersArray.join(', ')}`;

const { onConflict, ignore, merge } = this.single;
if (onConflict && ignore) sql += this._ignore(onConflict);
Expand Down
8 changes: 5 additions & 3 deletions lib/util/version.ts
Expand Up @@ -2,7 +2,7 @@
export type Version = [number, number, number];

/** Helper function to check `x` a integer where `x >= 0` */
function isNonNegInt(x: unknown): x is number {
export function isNonNegInt(x: unknown): x is number {
return typeof x === 'number' && Number.isInteger(x) && x >= 0;
}

Expand All @@ -18,7 +18,9 @@ export function isVersion(x: unknown): x is Version {
/** Parses given string into `Version` or returns `undefined` */
export function parseVersion(x: string): Version | undefined {
const versionRegex = /^(\d+)\.(\d+)\.(\d+)/m;
const versionNumbers = (versionRegex.exec(x) ?? []).slice(1, 4);
const versionNumbers = (versionRegex.exec(x) ?? [])
.slice(1, 4)
.map((x) => parseInt(x));
if (!isVersion(versionNumbers)) return undefined;
return versionNumbers;
}
Expand Down Expand Up @@ -57,7 +59,7 @@ export function compareVersions(v1: Version, v2: Version): 1 | 0 | -1 {
}

/**
* Returns `boolean` for if a given `version` satisfies the given `min` and `max`.
* Returns `boolean` for if a given `version` satisfies the given `min` (inclusive) and `max` (exclusive).
*
* This will throw an error if:
*
Expand Down
9 changes: 2 additions & 7 deletions test/cli/knexfile-test.spec.js
Expand Up @@ -4,7 +4,6 @@ const path = require('path');
const tildify = require('tildify');

const { FileTestHelper, execCommand } = require('cli-testlab');
const color = require('colorette');

const KNEX = path.normalize(__dirname + '/../../bin/cli.js');

Expand Down Expand Up @@ -101,9 +100,7 @@ module.exports = {
return execCommand(
`node ${KNEX} migrate:latest --knexfile=test/jake-util/knexfile-relative/knexfile.js --knexpath=../knex.js`,
{
expectedOutput: `Working directory changed to ${color.magenta(
expectedCWD
)}`,
expectedOutput: `Working directory changed to ${expectedCWD}`,
}
);
});
Expand All @@ -122,9 +119,7 @@ module.exports = {
return execCommand(
`node ${KNEX} migrate:latest --knexfile=test/jake-util/knexfile-relative/knexfile-with-resolve.js --knexpath=../knex.js`,
{
expectedOutput: `Working directory changed to ${color.magenta(
expectedCWD
)}`,
expectedOutput: `Working directory changed to ${expectedCWD}`,
}
);
});
Expand Down
1 change: 1 addition & 0 deletions test/db-less-test-suite.js
Expand Up @@ -11,6 +11,7 @@ describe('Util Tests', function () {
require('./unit/util/save-async-stack');
require('./unit/util/comma-no-paren-regex');
require('./unit/util/security');
require('./unit/util/version');
});

describe('Query Building Tests', function () {
Expand Down
75 changes: 70 additions & 5 deletions test/integration2/query/insert/inserts.spec.js
Expand Up @@ -256,7 +256,7 @@ describe('Inserts', function () {
);
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`',
'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,
Expand Down Expand Up @@ -474,7 +474,7 @@ describe('Inserts', function () {
);
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`',
'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,
Expand Down Expand Up @@ -1974,7 +1974,7 @@ describe('Inserts', function () {
);
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`',
'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']
);
});
Expand Down Expand Up @@ -2055,8 +2055,7 @@ describe('Inserts', function () {
);
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`",
"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',
Expand Down Expand Up @@ -2315,6 +2314,72 @@ describe('Inserts', function () {
assertJsonEquals(result[0].content, arrayOfObject);
});
});

describe(`#5769 sqlite multi-insert uses standard syntax and supports JSON`, function () {
it(`should JSON.stringify Sqlite multi-insert of Objects`, async function () {
if (!isSQLite(knex)) {
return this.skip();
}

knex(tableName)
.insert([{ data: { a: 1 } }, { data: { b: 2 } }])
.testSql(function (tester) {
tester(
'sqlite3',
`insert into \`${tableName}\` (\`data\`) values (?), (?)`,
['{"a":1}', '{"b":2}'],
[]
);
});
});

it(`should throw error if doing Sqlite multi-insert on pre-3.7.11 version`, async function () {
if (!isSQLite(knex)) {
return this.skip();
}

const realClientVersion = knex.client._clientVersion;
knex.client._clientVersion = () => [3, 7, 10];

try {
expect(() => {
knex(tableName)
.insert([{ a: 1 }, { a: 2 }])
.testSql(function (tester) {
tester('sqlite3', 'NA', [], []);
});
}).to.throw('Requires Sqlite 3.7.11 or newer to do multi-insert');
} finally {
knex.client._clientVersion = realClientVersion;
expect(knex.client._clientVersion()).to.not.equal([3, 7, 10]);
}
});

it(`should NOT throw error if doing Sqlite multi-insert on 3.7.11 version`, async function () {
if (!isSQLite(knex)) {
return this.skip();
}

const realClientVersion = knex.client._clientVersion;
knex.client._clientVersion = () => [3, 7, 11];

try {
knex(tableName)
.insert([{ id: 1 }, { id: 2 }], 'id')
.testSql(function (tester) {
tester(
'sqlite3',
`insert into \`${tableName}\` (\`id\`) values (?), (?) returning \`id\``,
[1, 2],
[]
);
});
} finally {
knex.client._clientVersion = realClientVersion;
expect(knex.client._clientVersion()).to.not.equal([3, 7, 11]);
}
});
});
});
});
});
Expand Down
1 change: 1 addition & 0 deletions test/jake-util/knexfile-relative/knexfile-with-resolve.js
Expand Up @@ -15,6 +15,7 @@ module.exports = {
connection: {
filename: __dirname + '/../test.sqlite3',
},
useNullAsDefault: true,
migrations: {
directory: MIGRATIONS_DIR,
},
Expand Down
1 change: 1 addition & 0 deletions test/jake-util/knexfile-relative/knexfile.js
Expand Up @@ -3,6 +3,7 @@ module.exports = {
connection: {
filename: __dirname + '/../test.sqlite3',
},
useNullAsDefault: true,
migrations: {
directory: './knexfile_migrations',
},
Expand Down
37 changes: 14 additions & 23 deletions test/unit/query/builder.js
Expand Up @@ -208,7 +208,8 @@ describe('Custom identifier wrapping', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
sqlite3: {
sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` union all select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` returning `id_wrapper_was_here`',
sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) values (?, ?), (?, ?) returning `id_wrapper_was_here`',
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
pg: {
sql: 'insert into "users_wrapper_was_here" ("email_wrapper_was_here", "name_wrapper_was_here") values (?, ?), (?, ?) returning "id_wrapper_was_here"',
Expand Down Expand Up @@ -260,7 +261,7 @@ describe('Custom identifier wrapping', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
sqlite3: {
sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` union all select ? as `email_wrapper_was_here`, ? as `name_wrapper_was_here` returning `id_wrapper_was_here`, `name_wrapper_was_here`',
sql: 'insert into `users_wrapper_was_here` (`email_wrapper_was_here`, `name_wrapper_was_here`) values (?, ?), (?, ?) returning `id_wrapper_was_here`, `name_wrapper_was_here`',
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
pg: {
Expand Down Expand Up @@ -5692,7 +5693,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
sqlite3: {
sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name`',
sql: 'insert into `users` (`email`, `name`) values (?, ?), (?, ?)',
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
mssql: {
Expand Down Expand Up @@ -5724,7 +5725,7 @@ describe('QueryBuilder', () => {
mysql:
"insert into `users` (`email`, `name`) values ('foo', 'taylor'), (NULL, 'dayle')",
sqlite3:
"insert into `users` (`email`, `name`) select 'foo' as `email`, 'taylor' as `name` union all select NULL as `email`, 'dayle' as `name`",
"insert into `users` (`email`, `name`) values ('foo', 'taylor'), (NULL, 'dayle')",
mssql:
"insert into [users] ([email], [name]) values ('foo', 'taylor'), (NULL, 'dayle')",
oracledb:
Expand Down Expand Up @@ -5788,7 +5789,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
sqlite3: {
sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` returning `id`',
sql: 'insert into `users` (`email`, `name`) values (?, ?), (?, ?) returning `id`',
},
pg: {
sql: 'insert into "users" ("email", "name") values (?, ?), (?, ?) returning "id"',
Expand Down Expand Up @@ -5839,7 +5840,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
sqlite3: {
sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` returning `id`, `name`',
sql: 'insert into `users` (`email`, `name`) values (?, ?), (?, ?) returning `id`, `name`',
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
pg: {
Expand Down Expand Up @@ -5921,18 +5922,8 @@ describe('QueryBuilder', () => {
bindings: [1, 2, 2, 3],
},
sqlite3: {
sql: 'insert into `table` (`a`, `b`, `c`) select ? as `a`, ? as `b`, ? as `c` union all select ? as `a`, ? as `b`, ? as `c` union all select ? as `a`, ? as `b`, ? as `c`',
bindings: [
1,
undefined,
undefined,
undefined,
2,
undefined,
2,
undefined,
3,
],
sql: 'insert into `table` (`a`, `b`, `c`) values (?, ?, ?), (?, ?, ?), (?, ?, ?)',
bindings: [1, null, null, null, 2, null, 2, null, 3],
},
mssql: {
sql: 'insert into [table] ([a], [b], [c]) values (?, DEFAULT, DEFAULT), (DEFAULT, ?, DEFAULT), (?, DEFAULT, ?)',
Expand Down Expand Up @@ -6560,7 +6551,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'bar'],
},
sqlite3: {
sql: 'insert into `users` (`email`) select ? as `email` union all select ? as `email` where true on conflict (`email`) do nothing',
sql: 'insert into `users` (`email`) values (?), (?) on conflict (`email`) do nothing',
bindings: ['foo', 'bar'],
},
}
Expand All @@ -6584,7 +6575,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'bar'],
},
sqlite3: {
sql: 'insert into `users` (`email`) select ? as `email` union all select ? as `email` where true on conflict (value) WHERE deleted_at IS NULL do nothing',
sql: 'insert into `users` (`email`) values (?), (?) on conflict (value) WHERE deleted_at IS NULL do nothing',
bindings: ['foo', 'bar'],
},
}
Expand Down Expand Up @@ -6631,7 +6622,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle', 'overidden'],
},
sqlite3: {
sql: 'insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name` where true on conflict (`email`) do update set `name` = ?',
sql: 'insert into `users` (`email`, `name`) values (?, ?), (?, ?) on conflict (`email`) do update set `name` = ?',
bindings: ['foo', 'taylor', 'bar', 'dayle', 'overidden'],
},
pg: {
Expand All @@ -6658,7 +6649,7 @@ describe('QueryBuilder', () => {
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
sqlite3: {
sql: 'insert into `users` (`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`',
sql: 'insert into `users` (`email`, `name`) values (?, ?), (?, ?) on conflict (`email`) do update set `email` = excluded.`email`, `name` = excluded.`name`',
bindings: ['foo', 'taylor', 'bar', 'dayle'],
},
pg: {
Expand Down Expand Up @@ -10057,7 +10048,7 @@ describe('QueryBuilder', () => {
bindings: ['bob', 'thisMail', 'sam', 'thatMail', 'jack'],
},
sqlite3: {
sql: 'with `withClause` as (select `foo` from `users` where `name` = ?) insert into `users` (`email`, `name`) select ? as `email`, ? as `name` union all select ? as `email`, ? as `name`',
sql: 'with `withClause` as (select `foo` from `users` where `name` = ?) insert into `users` (`email`, `name`) values (?, ?), (?, ?)',
bindings: ['bob', 'thisMail', 'sam', 'thatMail', 'jack'],
},
pg: {
Expand Down

0 comments on commit 128dde5

Please sign in to comment.