2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
import Promise from './promise';
|
|
|
|
import * as helpers from './helpers';
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
import Raw from './raw';
|
|
|
|
import Runner from './runner';
|
|
|
|
import Formatter from './formatter';
|
|
|
|
import Transaction from './transaction';
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
import QueryBuilder from './query/builder';
|
|
|
|
import QueryCompiler from './query/compiler';
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
import SchemaBuilder from './schema/builder';
|
|
|
|
import SchemaCompiler from './schema/compiler';
|
|
|
|
import TableBuilder from './schema/tablebuilder';
|
|
|
|
import TableCompiler from './schema/tablecompiler';
|
|
|
|
import ColumnBuilder from './schema/columnbuilder';
|
|
|
|
import ColumnCompiler from './schema/columncompiler';
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
import Pool2 from 'pool2';
|
|
|
|
import inherits from 'inherits';
|
|
|
|
import { EventEmitter } from 'events';
|
|
|
|
import SqlString from './query/string';
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-18 20:22:50 +10:00
|
|
|
import { assign, uniqueId, cloneDeep } from 'lodash'
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-18 19:59:24 +10:00
|
|
|
const debug = require('debug')('knex:client')
|
|
|
|
const debugQuery = require('debug')('knex:query')
|
2016-03-02 17:07:05 +01:00
|
|
|
|
|
|
|
// The base client provides the general structure
|
|
|
|
// for a dialect specific client object.
|
|
|
|
function Client(config = {}) {
|
|
|
|
this.config = config
|
|
|
|
this.connectionSettings = cloneDeep(config.connection || {})
|
|
|
|
if (this.driverName && config.connection) {
|
|
|
|
this.initializeDriver()
|
|
|
|
if (!config.pool || (config.pool && config.pool.max !== 0)) {
|
|
|
|
this.initializePool(config)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.valueForUndefined = this.raw('DEFAULT');
|
|
|
|
if (config.useNullAsDefault) {
|
|
|
|
this.valueForUndefined = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inherits(Client, EventEmitter)
|
|
|
|
|
|
|
|
assign(Client.prototype, {
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
Formatter,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
formatter() {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.Formatter(this)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
QueryBuilder,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
queryBuilder() {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.QueryBuilder(this)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
QueryCompiler,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
queryCompiler(builder) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.QueryCompiler(this, builder)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
SchemaBuilder,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
schemaBuilder() {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.SchemaBuilder(this)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
SchemaCompiler,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
schemaCompiler(builder) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.SchemaCompiler(this, builder)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
TableBuilder,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
tableBuilder(type, tableName, fn) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.TableBuilder(this, type, tableName, fn)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
TableCompiler,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
tableCompiler(tableBuilder) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.TableCompiler(this, tableBuilder)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
ColumnBuilder,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
columnBuilder(tableBuilder, type, args) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.ColumnBuilder(this, tableBuilder, type, args)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
ColumnCompiler,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
columnCompiler(tableBuilder, columnBuilder) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.ColumnCompiler(this, tableBuilder, columnBuilder)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
Runner,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
runner(connection) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.Runner(this, connection)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
SqlString,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
Transaction,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
transaction(container, config, outerTx) {
|
2016-03-02 17:07:05 +01:00
|
|
|
return new this.Transaction(this, container, config, outerTx)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
Raw,
|
2016-03-02 17:07:05 +01:00
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
raw() {
|
|
|
|
const raw = new this.Raw(this)
|
2016-03-02 17:07:05 +01:00
|
|
|
return raw.set.apply(raw, arguments)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
query(connection, obj) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (typeof obj === 'string') obj = {sql: obj}
|
|
|
|
this.emit('query', assign({__knexUid: connection.__knexUid}, obj))
|
|
|
|
debugQuery(obj.sql)
|
|
|
|
return this._query.call(this, connection, obj).catch((err) => {
|
|
|
|
err.message = SqlString.format(obj.sql, obj.bindings) + ' - ' + err.message
|
2016-03-24 18:59:37 +01:00
|
|
|
this.emit('query-error', err, assign({__knexUid: connection.__knexUid}, obj))
|
2016-03-02 17:07:05 +01:00
|
|
|
throw err
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
stream(connection, obj, stream, options) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (typeof obj === 'string') obj = {sql: obj}
|
|
|
|
this.emit('query', assign({__knexUid: connection.__knexUid}, obj))
|
|
|
|
debugQuery(obj.sql)
|
|
|
|
return this._stream.call(this, connection, obj, stream, options)
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
prepBindings(bindings) {
|
2016-05-11 21:01:56 +03:00
|
|
|
return bindings;
|
2016-03-02 17:07:05 +01:00
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
wrapIdentifier(value) {
|
|
|
|
return (value !== '*' ? `"${value.replace(/"/g, '""')}"` : '*')
|
2016-03-02 17:07:05 +01:00
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
initializeDriver() {
|
2016-03-02 17:07:05 +01:00
|
|
|
try {
|
|
|
|
this.driver = this._driver()
|
|
|
|
} catch (e) {
|
2016-05-17 01:01:34 +10:00
|
|
|
helpers.exit(`Knex: run\n$ npm install ${this.driverName} --save\n${e.stack}`)
|
2016-03-02 17:07:05 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
Pool: Pool2,
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
initializePool(config) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (this.pool) this.destroy()
|
|
|
|
this.pool = new this.Pool(assign(this.poolDefaults(config.pool || {}), config.pool))
|
|
|
|
this.pool.on('error', function(err) {
|
2016-05-17 01:01:34 +10:00
|
|
|
helpers.error(`Pool2 - ${err}`)
|
2016-03-02 17:07:05 +01:00
|
|
|
})
|
|
|
|
this.pool.on('warn', function(msg) {
|
2016-05-17 01:01:34 +10:00
|
|
|
helpers.warn(`Pool2 - ${msg}`)
|
2016-03-02 17:07:05 +01:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
poolDefaults(poolConfig) {
|
|
|
|
const client = this
|
2016-03-02 17:07:05 +01:00
|
|
|
return {
|
|
|
|
min: 2,
|
|
|
|
max: 10,
|
2016-05-17 01:01:34 +10:00
|
|
|
acquire(callback) {
|
2016-03-02 17:07:05 +01:00
|
|
|
client.acquireRawConnection()
|
|
|
|
.tap(function(connection) {
|
|
|
|
connection.__knexUid = uniqueId('__knexUid')
|
|
|
|
if (poolConfig.afterCreate) {
|
|
|
|
return Promise.promisify(poolConfig.afterCreate)(connection)
|
|
|
|
}
|
|
|
|
})
|
2016-03-15 20:51:27 +01:00
|
|
|
.asCallback(callback)
|
2016-03-02 17:07:05 +01:00
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
dispose(connection, callback) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (poolConfig.beforeDestroy) {
|
|
|
|
poolConfig.beforeDestroy(connection, function() {
|
|
|
|
if (connection !== undefined) {
|
|
|
|
client.destroyRawConnection(connection, callback)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else if (connection !== void 0) {
|
|
|
|
client.destroyRawConnection(connection, callback)
|
|
|
|
}
|
2016-03-19 19:14:46 +01:00
|
|
|
},
|
2016-05-17 01:01:34 +10:00
|
|
|
ping(resource, callback) {
|
2016-03-19 19:14:46 +01:00
|
|
|
return client.ping(resource, callback);
|
2016-03-02 17:07:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Acquire a connection from the pool.
|
2016-05-17 01:01:34 +10:00
|
|
|
acquireConnection() {
|
|
|
|
const client = this
|
2016-05-18 21:30:59 +10:00
|
|
|
let request = null
|
|
|
|
const completed = new Promise(function(resolver, rejecter) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (!client.pool) {
|
|
|
|
return rejecter(new Error('There is no pool defined on the current client'))
|
|
|
|
}
|
2016-05-09 13:58:16 -04:00
|
|
|
request = client.pool.acquire(function(err, connection) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (err) return rejecter(err)
|
2016-05-09 13:58:16 -04:00
|
|
|
debug('acquired connection from pool: %s', connection.__knexUid)
|
2016-03-02 17:07:05 +01:00
|
|
|
resolver(connection)
|
|
|
|
})
|
|
|
|
})
|
2016-05-18 21:30:59 +10:00
|
|
|
const abort = function(reason) {
|
2016-05-09 13:58:16 -04:00
|
|
|
if (request && !request.fulfilled) {
|
|
|
|
request.abort(reason)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
completed: completed,
|
|
|
|
abort: abort
|
|
|
|
}
|
2016-03-02 17:07:05 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
// Releases a connection back to the connection pool,
|
|
|
|
// returning a promise resolved when the connection is released.
|
2016-05-17 01:01:34 +10:00
|
|
|
releaseConnection(connection) {
|
|
|
|
const { pool } = this
|
2016-03-02 17:07:05 +01:00
|
|
|
return new Promise(function(resolver) {
|
|
|
|
debug('releasing connection to pool: %s', connection.__knexUid)
|
|
|
|
pool.release(connection)
|
|
|
|
resolver()
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
// Destroy the current connection pool for the client.
|
2016-05-17 01:01:34 +10:00
|
|
|
destroy(callback) {
|
|
|
|
const client = this
|
|
|
|
const promise = new Promise(function(resolver) {
|
2016-03-02 17:07:05 +01:00
|
|
|
if (!client.pool) return resolver()
|
|
|
|
client.pool.end(function() {
|
|
|
|
client.pool = undefined
|
|
|
|
resolver()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
// Allow either a callback or promise interface for destruction.
|
|
|
|
if (typeof callback === 'function') {
|
2016-03-15 20:51:27 +01:00
|
|
|
promise.asCallback(callback)
|
2016-03-02 17:07:05 +01:00
|
|
|
} else {
|
|
|
|
return promise
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Return the database being used by this client.
|
2016-05-17 01:01:34 +10:00
|
|
|
database() {
|
2016-03-02 17:07:05 +01:00
|
|
|
return this.connectionSettings.database
|
|
|
|
},
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
toString() {
|
2016-03-02 17:07:05 +01:00
|
|
|
return '[object KnexClient]'
|
2016-05-26 11:06:33 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
canCancelQuery: false,
|
|
|
|
cancelQuery() {
|
|
|
|
throw new Error("Query cancelling not supported for this dialect")
|
2016-03-02 17:07:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
2016-05-17 01:01:34 +10:00
|
|
|
export default Client
|