Comparing version 0.95.11 to 0.95.12-rc1
@@ -101,4 +101,4 @@ const { Pool, TimeoutError } = require('tarn'); | ||
tableBuilder(type, tableName, fn) { | ||
return new TableBuilder(this, type, tableName, fn); | ||
tableBuilder(type, tableName, tableNameLike, fn) { | ||
return new TableBuilder(this, type, tableName, tableNameLike, fn); | ||
} | ||
@@ -105,0 +105,0 @@ |
@@ -15,4 +15,6 @@ // The client names we'll allow in the `{name: lib}` pairing. | ||
'postgres', | ||
'pgnative', | ||
'redshift', | ||
'sqlite3', | ||
'cockroachdb', | ||
].concat(Object.keys(CLIENT_ALIASES)) | ||
@@ -27,4 +29,6 @@ ); | ||
PostgreSQL: 'pg', | ||
PgNative: 'pgnative', | ||
Redshift: 'pg-redshift', | ||
SQLite: 'sqlite3', | ||
CockroachDB: 'cockroachdb', | ||
}); | ||
@@ -31,0 +35,0 @@ |
@@ -8,2 +8,3 @@ // MSSQL Query Compiler | ||
const isEmpty = require('lodash/isEmpty'); | ||
const Raw = require('../../../raw.js'); | ||
@@ -230,2 +231,17 @@ const components = [ | ||
_formatGroupsItemValue(value, nulls) { | ||
const column = super._formatGroupsItemValue(value); | ||
// MSSQL dont support 'is null' syntax in order by, | ||
// so we override this function and add MSSQL specific syntax. | ||
if (nulls && !(value instanceof Raw)) { | ||
const collNulls = `IIF(${column} is null,`; | ||
if (nulls === 'first') { | ||
return `${collNulls}0,1)`; | ||
} else if (nulls === 'last') { | ||
return `${collNulls}1,0)`; | ||
} | ||
} | ||
return column; | ||
} | ||
standardUpdate() { | ||
@@ -232,0 +248,0 @@ const top = this.top(); |
@@ -7,2 +7,3 @@ /* eslint max-len:0 */ | ||
const helpers = require('../../../util/helpers'); | ||
const { isObject } = require('../../../util/is'); | ||
@@ -17,15 +18,21 @@ // Table Compiler | ||
createQuery(columns, ifNot) { | ||
const createStatement = ifNot | ||
? `if object_id('${this.tableName()}', 'U') is null CREATE TABLE ` | ||
: 'CREATE TABLE '; | ||
const sql = | ||
createStatement + | ||
this.tableName() + | ||
(this._formatting ? ' (\n ' : ' (') + | ||
columns.sql.join(this._formatting ? ',\n ' : ', ') + | ||
')'; | ||
createQuery(columns, ifNot, like) { | ||
let createStatement = ifNot | ||
? `if object_id('${this.tableName()}', 'U') is null ` | ||
: ''; | ||
this.pushQuery(sql); | ||
if (like) { | ||
// This query copy only columns and not all indexes and keys like other databases. | ||
createStatement += `SELECT * INTO ${this.tableName()} FROM ${this.tableNameLike()} WHERE 0=1`; | ||
} else { | ||
createStatement += | ||
'CREATE TABLE ' + | ||
this.tableName() + | ||
(this._formatting ? ' (\n ' : ' (') + | ||
columns.sql.join(this._formatting ? ',\n ' : ', ') + | ||
')'; | ||
} | ||
this.pushQuery(createStatement); | ||
if (this.single.comment) { | ||
@@ -228,3 +235,18 @@ this.comment(this.single.comment); | ||
/** | ||
* Create a primary key. | ||
* | ||
* @param {undefined | string | string[]} columns | ||
* @param {string | {constraintName: string, deferrable?: 'not deferrable'|'deferred'|'immediate' }} constraintName | ||
*/ | ||
primary(columns, constraintName) { | ||
let deferrable; | ||
if (isObject(constraintName)) { | ||
({ constraintName, deferrable } = constraintName); | ||
} | ||
if (deferrable && deferrable !== 'not deferrable') { | ||
this.client.logger.warn( | ||
`mssql: primary key constraint [${constraintName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.` | ||
); | ||
} | ||
constraintName = constraintName | ||
@@ -248,3 +270,19 @@ ? this.formatter.wrap(constraintName) | ||
/** | ||
* Create a unique index. | ||
* | ||
* @param {string | string[]} columns | ||
* @param {string | {indexName: undefined | string, deferrable?: 'not deferrable'|'deferred'|'immediate' }} indexName | ||
*/ | ||
unique(columns, indexName) { | ||
/** @type {string | undefined} */ | ||
let deferrable; | ||
if (isObject(indexName)) { | ||
({ indexName, deferrable } = indexName); | ||
} | ||
if (deferrable && deferrable !== 'not deferrable') { | ||
this.client.logger.warn( | ||
`mssql: unique index [${indexName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.` | ||
); | ||
} | ||
indexName = indexName | ||
@@ -251,0 +289,0 @@ ? this.formatter.wrap(indexName) |
@@ -167,7 +167,3 @@ // MySQL Client | ||
try { | ||
return await this._query(conn, { | ||
sql: 'KILL QUERY ?', | ||
bindings: [connectionToKill.threadId], | ||
options: {}, | ||
}); | ||
return await this._wrappedCancelQueryCall(conn, connectionToKill); | ||
} finally { | ||
@@ -180,2 +176,10 @@ await this.destroyRawConnection(conn); | ||
} | ||
_wrappedCancelQueryCall(conn, connectionToKill) { | ||
return this._query(conn, { | ||
sql: 'KILL QUERY ?', | ||
bindings: [connectionToKill.threadId], | ||
options: {}, | ||
}); | ||
} | ||
} | ||
@@ -182,0 +186,0 @@ |
@@ -123,4 +123,3 @@ // MySQL Query Compiler | ||
return { | ||
sql: | ||
'select * from information_schema.columns where table_name = ? and table_schema = ?', | ||
sql: 'select * from information_schema.columns where table_name = ? and table_schema = ?', | ||
bindings: [table, this.client.database()], | ||
@@ -127,0 +126,0 @@ output(resp) { |
@@ -6,2 +6,3 @@ /* eslint max-len:0*/ | ||
const TableCompiler = require('../../../schema/tablecompiler'); | ||
const { isObject } = require('../../../util/is'); | ||
@@ -16,3 +17,3 @@ // Table Compiler | ||
createQuery(columns, ifNot) { | ||
createQuery(columns, ifNot, like) { | ||
const createStatement = ifNot | ||
@@ -23,4 +24,9 @@ ? 'create table if not exists ' | ||
let conn = {}; | ||
const columnsSql = ' (' + columns.sql.join(', ') + ')'; | ||
let sql = | ||
createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')'; | ||
createStatement + | ||
this.tableName() + | ||
(like && this.tableNameLike() | ||
? ' like ' + this.tableNameLike() | ||
: columnsSql); | ||
@@ -36,4 +42,3 @@ // Check if the connection settings are set. | ||
// var conn = builder.client.connectionSettings; | ||
if (charset) sql += ` default character set ${charset}`; | ||
if (charset && !like) sql += ` default character set ${charset}`; | ||
if (collation) sql += ` collate ${collation}`; | ||
@@ -225,2 +230,11 @@ if (engine) sql += ` engine = ${engine}`; | ||
primary(columns, constraintName) { | ||
let deferrable; | ||
if (isObject(constraintName)) { | ||
({ constraintName, deferrable } = constraintName); | ||
} | ||
if (deferrable && deferrable !== 'not deferrable') { | ||
this.client.logger.warn( | ||
`mysql: primary key constraint \`${constraintName}\` will not be deferrable ${deferrable} because mysql does not support deferred constraints.` | ||
); | ||
} | ||
constraintName = constraintName | ||
@@ -237,2 +251,11 @@ ? this.formatter.wrap(constraintName) | ||
unique(columns, indexName) { | ||
let deferrable; | ||
if (isObject(indexName)) { | ||
({ indexName, deferrable } = indexName); | ||
} | ||
if (deferrable && deferrable !== 'not deferrable') { | ||
this.client.logger.warn( | ||
`mysql: unique index \`${indexName}\` will not be deferrable ${deferrable} because mysql does not support deferred constraints.` | ||
); | ||
} | ||
indexName = indexName | ||
@@ -239,0 +262,0 @@ ? this.formatter.wrap(indexName) |
@@ -56,4 +56,9 @@ /* eslint max-len:0 */ | ||
// Adds the "create" query to the query sequence. | ||
createQuery(columns, ifNot) { | ||
const sql = `create table ${this.tableName()} (${columns.sql.join(', ')})`; | ||
createQuery(columns, ifNot, like) { | ||
const columnsSql = | ||
like && this.tableNameLike() | ||
? ' as (select * from ' + this.tableNameLike() + ' where 0=1)' | ||
: ' (' + columns.sql.join(', ') + ')'; | ||
const sql = `create table ${this.tableName()}${columnsSql}`; | ||
this.pushQuery({ | ||
@@ -60,0 +65,0 @@ // catch "name is already used by an existing object" for workaround for "if not exists" |
@@ -46,4 +46,4 @@ function generateCombinedName(logger, postfix, name, subNames) { | ||
return [ | ||
'DPI-1010', // not connected | ||
'DPI-1080', // connection was closed by ORA-%d | ||
'DPI-1010', // not connected | ||
'DPI-1080', // connection was closed by ORA-%d | ||
'ORA-03114', // not connected to ORACLE | ||
@@ -50,0 +50,0 @@ 'ORA-03113', // end-of-file on communication channel |
@@ -65,2 +65,8 @@ // PostgreSQL | ||
_acquireOnlyConnection() { | ||
const connection = new this.driver.Client(this.connectionSettings); | ||
return connection.connect().then(() => connection); | ||
} | ||
// Get a raw connection, called by the `pool` whenever a new | ||
@@ -70,26 +76,26 @@ // connection needs to be added to the pool. | ||
const client = this; | ||
return new Promise(function (resolver, rejecter) { | ||
const connection = new client.driver.Client(client.connectionSettings); | ||
connection.connect(function (err, connection) { | ||
if (err) { | ||
return rejecter(err); | ||
} | ||
return this._acquireOnlyConnection() | ||
.then(function (connection) { | ||
connection.on('error', (err) => { | ||
connection.__knex__disposed = err; | ||
}); | ||
connection.on('end', (err) => { | ||
connection.__knex__disposed = err || 'Connection ended unexpectedly'; | ||
}); | ||
if (!client.version) { | ||
return client.checkVersion(connection).then(function (version) { | ||
client.version = version; | ||
resolver(connection); | ||
return connection; | ||
}); | ||
} | ||
resolver(connection); | ||
return connection; | ||
}) | ||
.then(function setSearchPath(connection) { | ||
client.setSchemaSearchPath(connection); | ||
return connection; | ||
}); | ||
}).then(function setSearchPath(connection) { | ||
client.setSchemaSearchPath(connection); | ||
return connection; | ||
}); | ||
} | ||
@@ -107,6 +113,6 @@ | ||
checkVersion(connection) { | ||
return new Promise(function (resolver, rejecter) { | ||
connection.query('select version();', function (err, resp) { | ||
if (err) return rejecter(err); | ||
resolver(/^PostgreSQL (.*?)( |$)/.exec(resp.rows[0].version)[1]); | ||
return new Promise((resolve, reject) => { | ||
connection.query('select version();', (err, resp) => { | ||
if (err) return reject(err); | ||
resolve(this._parseVersion(resp.rows[0].version)); | ||
}); | ||
@@ -116,2 +122,6 @@ }); | ||
_parseVersion(versionString) { | ||
return /^PostgreSQL (.*?)( |$)/.exec(versionString)[1]; | ||
} | ||
// Position the bindings for the query. The escape sequence for question mark | ||
@@ -118,0 +128,0 @@ // is \? (e.g. knex.raw("\\?") since javascript requires '\' to be escaped too...) |
@@ -125,4 +125,9 @@ // PostgreSQL Column Compiler | ||
function jsonColumn(client, jsonb) { | ||
if (!client.version || parseFloat(client.version) >= 9.2) | ||
if ( | ||
!client.version || | ||
client.config.client === 'cockroachdb' || | ||
parseFloat(client.version) >= 9.2 | ||
) { | ||
return jsonb ? 'jsonb' : 'json'; | ||
} | ||
return 'text'; | ||
@@ -129,0 +134,0 @@ } |
@@ -78,8 +78,16 @@ // PostgreSQL Schema Compiler | ||
dropSchema(schemaName) { | ||
this.pushQuery(`drop schema ${this.formatter.wrap(schemaName)}`); | ||
dropSchema(schemaName, cascade = false) { | ||
this.pushQuery( | ||
`drop schema ${this.formatter.wrap(schemaName)}${ | ||
cascade ? ' cascade' : '' | ||
}` | ||
); | ||
} | ||
dropSchemaIfExists(schemaName) { | ||
this.pushQuery(`drop schema if exists ${this.formatter.wrap(schemaName)}`); | ||
dropSchemaIfExists(schemaName, cascade = false) { | ||
this.pushQuery( | ||
`drop schema if exists ${this.formatter.wrap(schemaName)}${ | ||
cascade ? ' cascade' : '' | ||
}` | ||
); | ||
} | ||
@@ -86,0 +94,0 @@ |
@@ -43,8 +43,13 @@ /* eslint max-len: 0 */ | ||
// Adds the "create" query to the query sequence. | ||
createQuery(columns, ifNot) { | ||
createQuery(columns, ifNot, like) { | ||
const createStatement = ifNot | ||
? 'create table if not exists ' | ||
: 'create table '; | ||
const columnsSql = ' (' + columns.sql.join(', ') + ')'; | ||
let sql = | ||
createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')'; | ||
createStatement + | ||
this.tableName() + | ||
(like && this.tableNameLike() | ||
? ' (like ' + this.tableNameLike() + ' including all)' | ||
: columnsSql); | ||
if (this.single.inherits) | ||
@@ -51,0 +56,0 @@ sql += ` inherits (${this.formatter.wrap(this.single.inherits)})`; |
@@ -29,8 +29,13 @@ /* eslint max-len: 0 */ | ||
// Adds the "create" query to the query sequence. | ||
createQuery(columns, ifNot) { | ||
createQuery(columns, ifNot, like) { | ||
const createStatement = ifNot | ||
? 'create table if not exists ' | ||
: 'create table '; | ||
const columnsSql = ' (' + columns.sql.join(', ') + ')'; | ||
let sql = | ||
createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')'; | ||
createStatement + | ||
this.tableName() + | ||
(like && this.tableNameLike() | ||
? ' (like ' + this.tableNameLike() + ')' | ||
: columnsSql); | ||
if (this.single.inherits) | ||
@@ -37,0 +42,0 @@ sql += ` like (${this.formatter.wrap(this.single.inherits)})`; |
@@ -347,2 +347,36 @@ // SQLite3_DDL | ||
setNullable(column, isNullable) { | ||
return this.client.transaction( | ||
async (trx) => { | ||
this.trx = trx; | ||
const { createTable, createIndices } = await this.getTableSql(); | ||
const parsedTable = parseCreateTable(createTable); | ||
const parsedColumn = parsedTable.columns.find((c) => | ||
isEqualId(column, c.name) | ||
); | ||
if (!parsedColumn) { | ||
throw new Error( | ||
`.setNullable: Column ${column} does not exist in table ${this.tableName()}.` | ||
); | ||
} | ||
parsedColumn.constraints.notnull = isNullable | ||
? null | ||
: { name: null, conflict: null }; | ||
parsedColumn.constraints.null = isNullable | ||
? parsedColumn.constraints.null | ||
: null; | ||
const newTable = compileCreateTable(parsedTable, this.wrap); | ||
return this.generateAlterCommands(newTable, createIndices); | ||
}, | ||
{ connection: this.connection } | ||
); | ||
} | ||
async alter(newSql, createIndices, columns) { | ||
@@ -349,0 +383,0 @@ await this.createNewTable(newSql); |
@@ -24,6 +24,8 @@ const ColumnCompiler = require('../../../schema/columncompiler'); | ||
ColumnCompiler_SQLite3.prototype.jsonb = 'json'; | ||
ColumnCompiler_SQLite3.prototype.double = ColumnCompiler_SQLite3.prototype.decimal = ColumnCompiler_SQLite3.prototype.floating = | ||
'float'; | ||
ColumnCompiler_SQLite3.prototype.double = | ||
ColumnCompiler_SQLite3.prototype.decimal = | ||
ColumnCompiler_SQLite3.prototype.floating = | ||
'float'; | ||
ColumnCompiler_SQLite3.prototype.timestamp = 'datetime'; | ||
module.exports = ColumnCompiler_SQLite3; |
const filter = require('lodash/filter'); | ||
const values = require('lodash/values'); | ||
const identity = require('lodash/identity'); | ||
const { isObject } = require('../../../util/is'); | ||
@@ -14,16 +15,19 @@ const TableCompiler = require('../../../schema/tablecompiler'); | ||
// Create a new table. | ||
createQuery(columns, ifNot) { | ||
createQuery(columns, ifNot, like) { | ||
const createStatement = ifNot | ||
? 'create table if not exists ' | ||
: 'create table '; | ||
let sql = | ||
createStatement + this.tableName() + ' (' + columns.sql.join(', '); | ||
// SQLite forces primary keys to be added when the table is initially created | ||
// so we will need to check for a primary key commands and add the columns | ||
// to the table's declaration here so they can be created on the tables. | ||
sql += this.foreignKeys() || ''; | ||
sql += this.primaryKeys() || ''; | ||
sql += ')'; | ||
let sql = createStatement + this.tableName(); | ||
if (like && this.tableNameLike()) { | ||
sql += ' as select * from ' + this.tableNameLike() + ' where 0=1'; | ||
} else { | ||
// so we will need to check for a primary key commands and add the columns | ||
// to the table's declaration here so they can be created on the tables. | ||
sql += ' (' + columns.sql.join(', '); | ||
sql += this.foreignKeys() || ''; | ||
sql += this.primaryKeys() || ''; | ||
sql += ')'; | ||
} | ||
this.pushQuery(sql); | ||
@@ -126,2 +130,11 @@ } | ||
unique(columns, indexName) { | ||
let deferrable; | ||
if (isObject(indexName)) { | ||
({ indexName, deferrable } = indexName); | ||
} | ||
if (deferrable && deferrable !== 'not deferrable') { | ||
this.client.logger.warn( | ||
`sqlite3: unique index \`${indexName}\` will not be deferrable ${deferrable} because sqlite3 does not support deferred constraints.` | ||
); | ||
} | ||
indexName = indexName | ||
@@ -163,2 +176,12 @@ ? this.formatter.wrap(indexName) | ||
); | ||
let deferrable; | ||
if (isObject(constraintName)) { | ||
({ constraintName, deferrable } = constraintName); | ||
} | ||
if (deferrable && deferrable !== 'not deferrable') { | ||
this.client.logger.warn( | ||
`sqlite3: primary key constraint \`${constraintName}\` will not be deferrable ${deferrable} because sqlite3 does not support deferred constraints.` | ||
); | ||
} | ||
constraintName = this.client.customWrapIdentifier(constraintName, identity); | ||
@@ -272,4 +295,12 @@ | ||
_setNullableState(column, isNullable) { | ||
const fnCalled = isNullable ? '.setNullable' : '.dropNullable'; | ||
throw new Error(`${fnCalled} is not supported for SQLite.`); | ||
const compiler = this; | ||
this.pushQuery({ | ||
sql: `PRAGMA table_info(${this.tableName()})`, | ||
statementsProducer(pragma, connection) { | ||
return compiler.client | ||
.ddl(compiler, pragma, connection) | ||
.setNullable(column, isNullable); | ||
}, | ||
}); | ||
} | ||
@@ -276,0 +307,0 @@ |
@@ -7,4 +7,11 @@ const chunk = require('lodash/chunk'); | ||
function batchInsert(client, tableName, batch, chunkSize = 1000) { | ||
let returning = void 0; | ||
let returning = undefined; | ||
let transaction = null; | ||
if (!isNumber(chunkSize) || chunkSize < 1) { | ||
throw new TypeError(`Invalid chunkSize: ${chunkSize}`); | ||
} | ||
if (!Array.isArray(batch)) { | ||
throw new TypeError(`Invalid batch: Expected array, got ${typeof batch}`); | ||
} | ||
const chunks = chunk(batch, chunkSize); | ||
@@ -20,14 +27,2 @@ const runInTransaction = (cb) => { | ||
Promise.resolve().then(async () => { | ||
if (!isNumber(chunkSize) || chunkSize < 1) { | ||
throw new TypeError(`Invalid chunkSize: ${chunkSize}`); | ||
} | ||
if (!Array.isArray(batch)) { | ||
throw new TypeError( | ||
`Invalid batch: Expected array, got ${typeof batch}` | ||
); | ||
} | ||
const chunks = chunk(batch, chunkSize); | ||
//Next tick to ensure wrapper functions are called if needed | ||
@@ -34,0 +29,0 @@ await delay(1); |
@@ -269,4 +269,4 @@ // Transaction | ||
catch(onReject) { | ||
return this._promise.catch(onReject); | ||
catch(...args) { | ||
return this._promise.catch(...args); | ||
} | ||
@@ -273,0 +273,0 @@ |
@@ -25,5 +25,3 @@ const Client = require('../../client'); | ||
// If user provided Client constructor as a parameter, use it | ||
else if ( | ||
typeof parsedConfig.client === 'function' | ||
) { | ||
else if (typeof parsedConfig.client === 'function') { | ||
Dialect = parsedConfig.client; | ||
@@ -30,0 +28,0 @@ } |
@@ -186,3 +186,4 @@ const { EventEmitter } = require('events'); | ||
this.userParams.wrapIdentifier = this.client.config.wrapIdentifier; | ||
this.userParams.postProcessResponse = this.client.config.postProcessResponse; | ||
this.userParams.postProcessResponse = | ||
this.client.config.postProcessResponse; | ||
this.client.config.wrapIdentifier = null; | ||
@@ -200,3 +201,4 @@ this.client.config.postProcessResponse = null; | ||
this.client.config.wrapIdentifier = this.userParams.wrapIdentifier; | ||
this.client.config.postProcessResponse = this.userParams.postProcessResponse; | ||
this.client.config.postProcessResponse = | ||
this.userParams.postProcessResponse; | ||
this.userParams.isProcessingDisabled = false; | ||
@@ -203,0 +205,0 @@ }, |
@@ -353,73 +353,70 @@ // Migrator | ||
// Run a batch of current migrations, in sequence. | ||
_runBatch(migrations, direction, trx) { | ||
return ( | ||
this._getLock(trx) | ||
// When there is a wrapping transaction, some migrations | ||
// could have been done while waiting for the lock: | ||
.then(() => | ||
trx | ||
? migrationListResolver.listCompleted( | ||
this.config.tableName, | ||
this.config.schemaName, | ||
trx | ||
) | ||
: [] | ||
) | ||
.then( | ||
(completed) => | ||
(migrations = getNewMigrations( | ||
this.config.migrationSource, | ||
migrations, | ||
completed | ||
)) | ||
) | ||
.then(() => | ||
Promise.all( | ||
migrations.map(this._validateMigrationStructure.bind(this)) | ||
async _runBatch(migrations, direction, trx) { | ||
const canGetLockInTransaction = | ||
this.knex.client.driverName !== 'cockroachdb'; | ||
try { | ||
await this._getLock(canGetLockInTransaction ? trx : undefined); | ||
// When there is a wrapping transaction, some migrations | ||
// could have been done while waiting for the lock: | ||
const completed = trx | ||
? await migrationListResolver.listCompleted( | ||
this.config.tableName, | ||
this.config.schemaName, | ||
trx | ||
) | ||
) | ||
.then(() => this._latestBatchNumber(trx)) | ||
.then((batchNo) => { | ||
if (direction === 'up') batchNo++; | ||
return batchNo; | ||
}) | ||
.then((batchNo) => { | ||
return this._waterfallBatch(batchNo, migrations, direction, trx); | ||
}) | ||
.then(async (res) => { | ||
await this._freeLock(trx); | ||
return res; | ||
}) | ||
.catch(async (error) => { | ||
let cleanupReady = Promise.resolve(); | ||
: []; | ||
if (error instanceof LockError) { | ||
// If locking error do not free the lock. | ||
this.knex.client.logger.warn( | ||
`Can't take lock to run migrations: ${error.message}` | ||
); | ||
this.knex.client.logger.warn( | ||
'If you are sure migrations are not running you can release the ' + | ||
"lock manually by running 'knex migrate:unlock'" | ||
); | ||
} else { | ||
if (this._activeMigration.fileName) { | ||
this.knex.client.logger.warn( | ||
`migration file "${this._activeMigration.fileName}" failed` | ||
); | ||
} | ||
this.knex.client.logger.warn( | ||
`migration failed with error: ${error.message}` | ||
); | ||
// If the error was not due to a locking issue, then remove the lock. | ||
cleanupReady = this._freeLock(trx); | ||
} | ||
migrations = getNewMigrations( | ||
this.config.migrationSource, | ||
migrations, | ||
completed | ||
); | ||
try { | ||
await cleanupReady; | ||
// eslint-disable-next-line no-empty | ||
} catch (e) {} | ||
throw error; | ||
}) | ||
); | ||
await Promise.all( | ||
migrations.map(this._validateMigrationStructure.bind(this)) | ||
); | ||
let batchNo = await this._latestBatchNumber(trx); | ||
if (direction === 'up') batchNo++; | ||
const res = await this._waterfallBatch( | ||
batchNo, | ||
migrations, | ||
direction, | ||
trx | ||
); | ||
await this._freeLock(canGetLockInTransaction ? trx : undefined); | ||
return res; | ||
} catch (error) { | ||
let cleanupReady = Promise.resolve(); | ||
if (error instanceof LockError) { | ||
// If locking error do not free the lock. | ||
this.knex.client.logger.warn( | ||
`Can't take lock to run migrations: ${error.message}` | ||
); | ||
this.knex.client.logger.warn( | ||
'If you are sure migrations are not running you can release the ' + | ||
"lock manually by running 'knex migrate:unlock'" | ||
); | ||
} else { | ||
if (this._activeMigration.fileName) { | ||
this.knex.client.logger.warn( | ||
`migration file "${this._activeMigration.fileName}" failed` | ||
); | ||
} | ||
this.knex.client.logger.warn( | ||
`migration failed with error: ${error.message}` | ||
); | ||
// If the error was not due to a locking issue, then remove the lock. | ||
cleanupReady = this._freeLock( | ||
canGetLockInTransaction ? trx : undefined | ||
); | ||
} | ||
try { | ||
await cleanupReady; | ||
// eslint-disable-next-line no-empty | ||
} catch (e) {} | ||
throw error; | ||
} | ||
} | ||
@@ -426,0 +423,0 @@ |
@@ -10,3 +10,2 @@ const { | ||
const lockTable = getLockTableName(tableName); | ||
const lockTableWithSchema = getLockTableNameWithSchema(tableName, schemaName); | ||
return getSchemaBuilder(trxOrKnex, schemaName) | ||
@@ -30,4 +29,3 @@ .hasTable(tableName) | ||
return ( | ||
!data.length && | ||
trxOrKnex.into(lockTableWithSchema).insert({ is_locked: 0 }) | ||
!data.length && _insertLockRowIfNeeded(tableName, schemaName, trxOrKnex) | ||
); | ||
@@ -59,2 +57,13 @@ }); | ||
function _insertLockRowIfNeeded(tableName, schemaName, trxOrKnex) { | ||
const lockTableWithSchema = getLockTableNameWithSchema(tableName, schemaName); | ||
return trxOrKnex | ||
.from(trxOrKnex.raw('?? (??)', [lockTableWithSchema, 'is_locked'])) | ||
.insert(function () { | ||
return this.select(trxOrKnex.raw('?', [0])).whereNotExists(function () { | ||
return this.select('*').from(lockTableWithSchema); | ||
}); | ||
}); | ||
} | ||
//Get schema-aware schema builder for a given schema nam | ||
@@ -61,0 +70,0 @@ function getSchemaBuilder(trxOrKnex, schemaName) { |
@@ -634,3 +634,3 @@ // Builder | ||
// Adds a `order by` clause to the query. | ||
orderBy(column, direction) { | ||
orderBy(column, direction, nulls = '') { | ||
if (Array.isArray(column)) { | ||
@@ -644,2 +644,3 @@ return this._orderByArray(column); | ||
direction, | ||
nulls, | ||
}); | ||
@@ -659,2 +660,3 @@ return this; | ||
direction: columnInfo['order'], | ||
nulls: columnInfo['nulls'], | ||
}); | ||
@@ -1424,5 +1426,5 @@ } else if (isString(columnInfo)) { | ||
const [query, columnList] = | ||
typeof nothingOrStatement === 'undefined' | ||
? [statementOrColumnList, undefined] | ||
: [nothingOrStatement, statementOrColumnList]; | ||
typeof nothingOrStatement === 'undefined' | ||
? [statementOrColumnList, undefined] | ||
: [nothingOrStatement, statementOrColumnList]; | ||
if (typeof alias !== 'string') { | ||
@@ -1429,0 +1431,0 @@ throw new Error(`${method}() first argument must be a string`); |
@@ -1229,4 +1229,11 @@ // Query Compiler | ||
_formatGroupsItemValue(value) { | ||
_formatGroupsItemValue(value, nulls) { | ||
const { formatter } = this; | ||
let nullOrder = ''; | ||
if (nulls === 'last') { | ||
nullOrder = ' is null'; | ||
} else if (nulls === 'first') { | ||
nullOrder = ' is not null'; | ||
} | ||
if (value instanceof Raw) { | ||
@@ -1240,4 +1247,4 @@ return unwrapRaw_( | ||
); | ||
} else if (value instanceof QueryBuilder) { | ||
return '(' + formatter.columnize(value) + ')'; | ||
} else if (value instanceof QueryBuilder || nulls) { | ||
return '(' + formatter.columnize(value) + nullOrder + ')'; | ||
} else { | ||
@@ -1253,3 +1260,3 @@ return formatter.columnize(value); | ||
const sql = items.map((item) => { | ||
const column = this._formatGroupsItemValue(item.value); | ||
const column = this._formatGroupsItemValue(item.value, item.nulls); | ||
const direction = | ||
@@ -1256,0 +1263,0 @@ type === 'order' && item.type !== 'orderByRaw' |
@@ -48,2 +48,3 @@ const { EventEmitter } = require('events'); | ||
'createTableIfNotExists', | ||
'createTableLike', | ||
'createSchema', | ||
@@ -50,0 +51,0 @@ 'createSchemaIfNotExists', |
@@ -65,5 +65,6 @@ const extend = require('lodash/extend'); | ||
ColumnBuilder.prototype.notNull = ColumnBuilder.prototype.notNullable = function notNullable() { | ||
return this.nullable(false); | ||
}; | ||
ColumnBuilder.prototype.notNull = ColumnBuilder.prototype.notNullable = | ||
function notNullable() { | ||
return this.nullable(false); | ||
}; | ||
@@ -70,0 +71,0 @@ ['index', 'primary', 'unique'].forEach(function (method) { |
@@ -152,4 +152,6 @@ // Column Compiler | ||
'integer not null' + (primaryKey ? ' primary key' : '') + ' autoincrement'; | ||
ColumnCompiler.prototype.integer = ColumnCompiler.prototype.smallint = ColumnCompiler.prototype.mediumint = | ||
'integer'; | ||
ColumnCompiler.prototype.integer = | ||
ColumnCompiler.prototype.smallint = | ||
ColumnCompiler.prototype.mediumint = | ||
'integer'; | ||
ColumnCompiler.prototype.biginteger = 'bigint'; | ||
@@ -156,0 +158,0 @@ ColumnCompiler.prototype.text = 'text'; |
@@ -85,2 +85,3 @@ const { | ||
SchemaCompiler.prototype.createTableIfNotExists = buildTable('createIfNot'); | ||
SchemaCompiler.prototype.createTableLike = buildTable('createLike'); | ||
@@ -92,5 +93,3 @@ SchemaCompiler.prototype.pushQuery = pushQuery; | ||
function buildTable(type) { | ||
return function (tableName, fn) { | ||
const builder = this.client.tableBuilder(type, tableName, fn); | ||
function build(builder) { | ||
// pass queryContext down to tableBuilder but do not overwrite it if already set | ||
@@ -108,3 +107,20 @@ const queryContext = this.builder.queryContext(); | ||
} | ||
}; | ||
} | ||
if (type === 'createLike') { | ||
return function (tableName, tableNameLike, fn) { | ||
const builder = this.client.tableBuilder( | ||
type, | ||
tableName, | ||
tableNameLike, | ||
fn | ||
); | ||
build.call(this, builder); | ||
}; | ||
} else { | ||
return function (tableName, fn) { | ||
const builder = this.client.tableBuilder(type, tableName, null, fn); | ||
build.call(this, builder); | ||
}; | ||
} | ||
} | ||
@@ -111,0 +127,0 @@ |
@@ -16,3 +16,3 @@ // TableBuilder | ||
class TableBuilder { | ||
constructor(client, method, tableName, fn) { | ||
constructor(client, method, tableName, tableNameLike, fn) { | ||
this.client = client; | ||
@@ -23,6 +23,7 @@ this._fn = fn; | ||
this._tableName = tableName; | ||
this._tableNameLike = tableNameLike; | ||
this._statements = []; | ||
this._single = {}; | ||
if (!isFunction(this._fn)) { | ||
if (!tableNameLike && !isFunction(this._fn)) { | ||
throw new TypeError( | ||
@@ -46,3 +47,6 @@ 'A callback function must be supplied to calls against `.createTable` ' + | ||
} | ||
this._fn.call(this, this); | ||
// With 'create table ... like' callback function is useless. | ||
if (this._fn) { | ||
this._fn.call(this, this); | ||
} | ||
return this.client.tableCompiler(this).toSQL(); | ||
@@ -49,0 +53,0 @@ } |
@@ -24,2 +24,3 @@ /* eslint max-len:0 */ | ||
this.tableNameRaw = tableBuilder._tableName; | ||
this.tableNameLikeRaw = tableBuilder._tableNameLike; | ||
this.single = tableBuilder._single; | ||
@@ -49,3 +50,3 @@ this.grouped = groupBy(tableBuilder._statements, 'grouping'); | ||
// and then run through anything else and push it to the query sequence. | ||
create(ifNot) { | ||
create(ifNot, like) { | ||
const columnBuilders = this.getColumns(); | ||
@@ -57,3 +58,3 @@ const columns = columnBuilders.map((col) => col.toSQL()); | ||
} | ||
this.createQuery(columnTypes, ifNot); | ||
this.createQuery(columnTypes, ifNot, like); | ||
this.columnQueries(columns); | ||
@@ -69,2 +70,10 @@ delete this.single.comment; | ||
createLike() { | ||
this.create(false, true); | ||
} | ||
createLikeIfNot() { | ||
this.create(true, true); | ||
} | ||
// If we're altering the table, we need to one-by-one | ||
@@ -226,2 +235,10 @@ // go through and handle each of the queries associated | ||
tableNameLike() { | ||
const name = this.schemaNameRaw | ||
? `${this.schemaNameRaw}.${this.tableNameLikeRaw}` | ||
: this.tableNameLikeRaw; | ||
return this.formatter.wrap(name); | ||
} | ||
// Generate all of the alter column statements necessary for the query. | ||
@@ -228,0 +245,0 @@ alterTable() { |
{ | ||
"name": "knex", | ||
"version": "0.95.11", | ||
"description": "A batteries-included SQL query & schema builder for Postgres, MySQL and SQLite3 and the Browser", | ||
"version": "0.95.12-rc1", | ||
"description": "A batteries-included SQL query & schema builder for PostgresSQL, MySQL, CockroachDB, MSSQL and SQLite3", | ||
"main": "knex", | ||
@@ -32,2 +32,4 @@ "types": "types/index.d.ts", | ||
"test:postgres": "cross-env DB=postgres npm run test:db", | ||
"test:cockroachdb": "cross-env DB=cockroachdb npm run test:db", | ||
"test:pgnative": "cross-env DB=pgnative npm run test:db", | ||
"test:tape": "node test/tape/index.js | tap-spec", | ||
@@ -40,4 +42,10 @@ "test:cli": "cross-env KNEX_PATH=../knex.js KNEX=bin/cli.js jake -f test/jake/Jakefile", | ||
"db:stop:postgres": "docker-compose -f scripts/docker-compose.yml down", | ||
"db:start:pgnative": "docker-compose -f scripts/docker-compose.yml up --build -d pgnative && docker-compose -f scripts/docker-compose.yml up waitpgnative", | ||
"db:stop:pgnative": "docker-compose -f scripts/docker-compose.yml down", | ||
"db:start:mysql": "docker-compose -f scripts/docker-compose.yml up --build -d mysql && docker-compose -f scripts/docker-compose.yml up waitmysql", | ||
"db:stop:mysql": "docker-compose -f scripts/docker-compose.yml down", | ||
"db:start:mssql": "docker-compose -f scripts/docker-compose.yml up --build -d mssql && docker-compose -f scripts/docker-compose.yml up waitmssql", | ||
"db:stop:mssql": "docker-compose -f scripts/docker-compose.yml down", | ||
"db:start:cockroachdb": "docker-compose -f scripts/docker-compose.yml up --build -d cockroachdb && docker-compose -f scripts/docker-compose.yml up waitcockroachdb", | ||
"db:stop:cockroachdb": "docker-compose -f scripts/docker-compose.yml down", | ||
"db:start:oracle": "docker-compose -f scripts/docker-compose.yml up --build -d oracledbxe && docker-compose -f scripts/docker-compose.yml up waitoracledbxe", | ||
@@ -50,3 +58,3 @@ "db:stop:oracle": "docker-compose -f scripts/docker-compose.yml down", | ||
"dependencies": { | ||
"colorette": "1.2.1", | ||
"colorette": "2.0.16", | ||
"commander": "^7.1.0", | ||
@@ -78,2 +86,5 @@ "debug": "4.3.2", | ||
}, | ||
"pg-native": { | ||
"optional": true | ||
}, | ||
"sqlite3": { | ||
@@ -90,3 +101,3 @@ "optional": true | ||
"devDependencies": { | ||
"@types/node": "^16.7.10", | ||
"@types/node": "^16.10.3", | ||
"chai": "^4.3.4", | ||
@@ -106,3 +117,3 @@ "chai-as-promised": "^7.1.1", | ||
"lint-staged": "^11.1.2", | ||
"mocha": "^9.1.1", | ||
"mocha": "^9.1.2", | ||
"mock-fs": "^4.13.0", | ||
@@ -115,3 +126,3 @@ "mysql": "^2.18.1", | ||
"pg-query-stream": "^4.2.1", | ||
"prettier": "2.3.2", | ||
"prettier": "2.4.1", | ||
"rimraf": "^3.0.2", | ||
@@ -124,7 +135,7 @@ "sinon": "^11.1.2", | ||
"tape": "^5.3.1", | ||
"tedious": "^11.4.0", | ||
"tedious": "^12.2.0", | ||
"toxiproxy-node-client": "^2.0.6", | ||
"ts-node": "^10.2.1", | ||
"tsd": "^0.17.0", | ||
"typescript": "4.4.2" | ||
"typescript": "4.4.3" | ||
}, | ||
@@ -146,3 +157,5 @@ "buildDependencies": [ | ||
"postgresql", | ||
"postgres", | ||
"mysql", | ||
"cockroachdb", | ||
"sqlite3", | ||
@@ -189,2 +202,3 @@ "oracle", | ||
"pg": false, | ||
"pg-native": false, | ||
"pg-query-stream": false, | ||
@@ -191,0 +205,0 @@ "oracle": false, |
@@ -13,3 +13,3 @@ # [knex.js](http://knexjs.org) | ||
A batteries-included, multi-dialect (MSSQL, MySQL, PostgreSQL, SQLite3, Oracle (including Oracle Wallet Authentication)) query builder for | ||
A batteries-included, multi-dialect (PostgreSQL, MySQL, CockroachDB, MSSQL, SQLite3, Oracle (including Oracle Wallet Authentication)) query builder for | ||
Node.js, featuring: | ||
@@ -16,0 +16,0 @@ |
@@ -16,2 +16,9 @@ const Knex = require('../../lib'); | ||
const pgnative = Knex({ | ||
client: 'pgnative', | ||
connection: | ||
'postgres://postgres:postgresrootpassword@localhost:25433/postgres', | ||
pool: { max: 50 }, | ||
}); | ||
const mysql2 = Knex({ | ||
@@ -95,6 +102,6 @@ client: 'mysql2', | ||
async function killConnectionsPg() { | ||
return pg.raw(`SELECT pg_terminate_backend(pg_stat_activity.pid) | ||
async function killConnectionsPg(client) { | ||
return client.raw(`SELECT pg_terminate_backend(pg_stat_activity.pid) | ||
FROM pg_stat_activity | ||
WHERE pg_stat_activity.datname = 'postgres' | ||
WHERE pg_stat_activity.datname = 'postgres' | ||
AND pid <> pg_backend_pid()`); | ||
@@ -159,2 +166,3 @@ } | ||
await recreateProxy('postgresql', 25432, 5432); | ||
await recreateProxy('postgresql', 25433, 5433); | ||
await recreateProxy('mysql', 23306, 3306); | ||
@@ -170,2 +178,5 @@ await recreateProxy('oracledbxe', 21521, 1521); | ||
loopQueries('PGNATIVE:', pgnative.raw('select 1')); | ||
loopQueries('PGNATIVE TO:', pgnative.raw('select 1').timeout(20)); | ||
loopQueries('MYSQL:', mysql.raw('select 1')); | ||
@@ -188,3 +199,4 @@ loopQueries('MYSQL TO:', mysql.raw('select 1').timeout(20)); | ||
await Promise.all([ | ||
killConnectionsPg(), | ||
killConnectionsPg(pg), | ||
killConnectionsPg(pgnative), | ||
killConnectionsMyslq(mysql), | ||
@@ -191,0 +203,0 @@ // killConnectionsMyslq(mysql2), |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
743019
162
19521
+ Addedcolorette@2.0.16(transitive)
- Removedcolorette@1.2.1(transitive)
Updatedcolorette@2.0.16