@adonisjs/lucid
Version:
- [x] Paginate method - [x] forPage method - [ ] chunk ( removed ) - [ ] pluckAll ( removed ) - [x] withPrefix - [x] transactions - [x] global transactions
209 lines (192 loc) • 4.13 kB
JavaScript
/*
* adonis-lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
const knex = require('knex')
const _ = require('lodash')
const proxyHandler = {
get (target, name) {
if (typeof (target[name]) !== 'undefined') {
return target[name]
}
const queryBuilder = target.query()
if (typeof (queryBuilder[name]) !== 'function') {
throw new Error(`Database.${name} is not a function`)
}
/**
* Attach transacting to all the database
* queries if global transactions are on
*/
if (target._globalTrx) {
queryBuilder.transacting(target._globalTrx)
}
return queryBuilder[name].bind(queryBuilder)
}
}
/**
* The database class is a reference to knex for a single
* connection. It has couple of extra methods over knex.
*
* Note: You don't instantiate this class directly but instead
* make use of @ref('DatabaseManager')
*
* @class Database
* @constructor
* @group Database
*/
class Database {
constructor (config) {
if (config.client === 'sqlite') {
config.useNullAsDefault = _.defaultTo(config.useNullAsDefault, true)
}
this.knex = knex(config)
this._globalTrx = null
return new Proxy(this, proxyHandler)
}
/**
* The schema builder instance to be used
* for creating database schema.
*
* You should obtain a new schema instance for every
* database operation and should never use stale
* instances. For example
*
* @example
* ```js
* // WRONG
* const schema = Database.schema
* schema.createTable('users')
* schema.createTable('profiles')
* ```
*
* ```js
* // RIGHT
* Database.schema.createTable('users')
* Database.schema.createTable('profiles')
* ```
*
* @attribute schema
*
* @return {Object}
*/
get schema () {
return this.knex.schema
}
/**
* Returns the fn from knex instance
*
* @method fn
*
* @return {Object}
*/
get fn () {
return this.knex.fn
}
/**
* Method to construct raw database queries.
*
* @method raw
*
* @param {...Spread} args
*
* @return {String}
*/
raw (...args) {
return this.knex.raw(...args)
}
/**
* Returns a trx object to be used for running queries
* under transaction.
*
* @method beginTransaction
* @async
*
* @return {Object}
*
* @example
* ```js
* const trx = await Database.beginTransaction()
* await trx
* .table('users')
* .insert({ username: 'virk' })
*
* // or
* Database
* .table('users')
* .transacting(trx)
* .insert({ username: 'virk' })
* ```
*/
beginTransaction () {
return new Promise((resolve, reject) => {
this
.knex
.transaction(function (trx) {
resolve(trx)
}).catch(() => {})
})
}
/**
* Starts a global transaction, where all query builder
* methods will be part of transaction automatically.
*
* Note: You must not use it in real world apart from when
* writing tests.
*
* @method beginGlobalTransaction
* @async
*
* @return {void}
*/
async beginGlobalTransaction () {
this._globalTrx = await this.beginTransaction()
}
/**
* Rollbacks global transaction.
*
* @method rollbackGlobalTransaction
*
* @return {void}
*/
rollbackGlobalTransaction () {
this._globalTrx.rollback()
this._globalTrx = null
}
/**
* Commits global transaction.
*
* @method commitGlobalTransaction
*
* @return {void}
*/
commitGlobalTransaction () {
this._globalTrx.commit()
this._globalTrx = null
}
/**
* Return a new instance of query builder
*
* @method query
*
* @return {Object}
*/
query () {
return this.knex.queryBuilder()
}
/**
* Closes the database connection. No more queries
* can be made after this.
*
* @method close
*
* @return {Promise}
*/
close () {
return this.knex.destroy()
}
}
module.exports = Database