-
-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add database to be the primary API for making queries
- Loading branch information
1 parent
069c5aa
commit 2443ce9
Showing
5 changed files
with
333 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* @adonisjs/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. | ||
*/ | ||
|
||
import { Database } from '../src/Database' | ||
|
||
export class DatabaseServiceProvider { | ||
constructor (protected $container: any) { | ||
} | ||
|
||
/** | ||
* Register database binding | ||
*/ | ||
public register () { | ||
this.$container.singleton('Adonis/Addons/Database', () => { | ||
const config = this.$container.use('Adonis/Core/Config').get('database', {}) | ||
const Logger = this.$container.use('Adonis/Core/Logger') | ||
return new Database(config, Logger) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
* @adonisjs/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. | ||
*/ | ||
|
||
/// <reference path="../../adonis-typings/database.ts" /> | ||
|
||
import { Exception } from '@poppinss/utils' | ||
import { LoggerContract } from '@poppinss/logger' | ||
|
||
import { | ||
ConnectionManagerContract, | ||
DatabaseConfigContract, | ||
DatabaseContract, | ||
} from '@ioc:Adonis/Addons/Database' | ||
|
||
import { ConnectionManager } from '../Connection/Manager' | ||
|
||
/** | ||
* Database class exposes the API to manage multiple connections and obtain an instance | ||
* of query/transaction clients. | ||
*/ | ||
export class Database implements DatabaseContract { | ||
/** | ||
* Reference to connections manager | ||
*/ | ||
public manager: ConnectionManagerContract | ||
|
||
/** | ||
* Primary connection name | ||
*/ | ||
public primaryConnectionName = this._config.connection | ||
|
||
constructor (private _config: DatabaseConfigContract, private _logger: LoggerContract) { | ||
this.manager = new ConnectionManager(this._logger) | ||
this._registerConnections() | ||
} | ||
|
||
/** | ||
* Registering all connections with the manager, so that we can fetch | ||
* and connect with them whenver required. | ||
*/ | ||
private _registerConnections () { | ||
Object.keys(this._config.connections).forEach((name) => { | ||
this.manager.add(name, this._config.connections[name]) | ||
}) | ||
} | ||
|
||
/** | ||
* Returns the connection node from the connection manager | ||
*/ | ||
public getRawConnection (name) { | ||
return this.manager.get(name) | ||
} | ||
|
||
/** | ||
* Returns the query client for a given connection | ||
*/ | ||
public connection (connection: string = this.primaryConnectionName) { | ||
const [name, mode] = connection.split('::') | ||
|
||
/** | ||
* Connect is noop when already connected | ||
*/ | ||
this.manager.connect(name) | ||
|
||
/** | ||
* Disallow modes other than `read` or `write` | ||
*/ | ||
if (mode && !['read', 'write'].includes(mode)) { | ||
throw new Exception(`Invalid mode ${mode}. Must be read or write`) | ||
} | ||
|
||
const rawConnection = this.manager.get(name)!.connection! | ||
return mode ? rawConnection.getClient(mode as ('read' | 'write')) : rawConnection.getClient() | ||
} | ||
|
||
/** | ||
* Returns query builder. Optionally one can define the mode as well | ||
*/ | ||
public query (mode?: 'read' | 'write') { | ||
return mode | ||
? this.connection(`${this.primaryConnectionName}::${mode}`).query() | ||
: this.connection().query() | ||
} | ||
|
||
/** | ||
* Returns insert query builder. Always has to be dual or write mode and | ||
* hence it doesn't matter, since in both `dual` and `write` mode, | ||
* the `write` connection is always used. | ||
*/ | ||
public insertQuery () { | ||
return this.connection().insertQuery() | ||
} | ||
|
||
/** | ||
* Returns instance of a query builder and selects the table | ||
*/ | ||
public from (table: any) { | ||
return this.connection().from(table) | ||
} | ||
|
||
/** | ||
* Returns insert query builder and selects the table | ||
*/ | ||
public table (table: any) { | ||
return this.connection().table(table) | ||
} | ||
|
||
/** | ||
* Returns a transaction instance on the default | ||
* connection | ||
*/ | ||
public transaction () { | ||
return this.connection().transaction() | ||
} | ||
|
||
/** | ||
* Returns an instance of raw query builder. Optionally one can | ||
* defined the `read/write` mode in which to execute the | ||
* query | ||
*/ | ||
public raw (sql: string, bindings?: any, mode?: 'read' | 'write') { | ||
return mode | ||
? this.connection(`${this.primaryConnectionName}::${mode}`).raw(sql, bindings) | ||
: this.connection().raw(sql, bindings) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/* | ||
* @adonisjs/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. | ||
*/ | ||
|
||
/// <reference path="../adonis-typings/database.ts" /> | ||
|
||
import * as test from 'japa' | ||
|
||
import { Database } from '../src/Database' | ||
import { getConfig, setup, cleanup, getLogger } from '../test-helpers' | ||
|
||
test.group('Database', (group) => { | ||
group.before(async () => { | ||
await setup() | ||
}) | ||
|
||
group.after(async () => { | ||
await cleanup() | ||
}) | ||
|
||
test('register all connections with the manager', (assert) => { | ||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
|
||
assert.isDefined(db.manager.connections.get('primary')) | ||
assert.equal(db.manager.connections.get('primary')!.state, 'idle') | ||
assert.isUndefined(db.manager.connections.get('primary')!.connection) | ||
}) | ||
|
||
test('make connection when db.connection is called', async (assert) => { | ||
assert.plan(1) | ||
|
||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
db.manager.on('connect', (connection) => { | ||
assert.equal(connection.name, 'primary') | ||
}) | ||
|
||
db.connection() | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('make connection to a named connection', async (assert) => { | ||
assert.plan(1) | ||
|
||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
db.manager.on('connect', (connection) => { | ||
assert.equal(connection.name, 'primary') | ||
}) | ||
|
||
db.connection('primary') | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('make connection to a named connection in write mode', async (assert) => { | ||
assert.plan(1) | ||
|
||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
const client = db.connection('primary::write') | ||
|
||
assert.equal(client.mode, 'write') | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('make connection to a named connection in read mode', async (assert) => { | ||
assert.plan(1) | ||
|
||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
const client = db.connection('primary::read') | ||
|
||
assert.equal(client.mode, 'read') | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('get transaction instance', async (assert) => { | ||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
const trx = await db.transaction() | ||
|
||
assert.equal(trx.mode, 'dual') | ||
assert.isTrue(trx.isTransaction) | ||
|
||
await trx.rollback() | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('get raw query builder instance', async (assert) => { | ||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
const result = await db.raw('select 1 + 1') | ||
assert.isDefined(result) | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('get raw query builder instance in read mode', async (assert) => { | ||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
const result = await db.raw('select 1 + 1', [], 'read') | ||
assert.isDefined(result) | ||
await db.manager.closeAll() | ||
}) | ||
|
||
test('get raw query builder instance in write mode', async (assert) => { | ||
const config = { | ||
connection: 'primary', | ||
connections: { primary: getConfig() }, | ||
} | ||
|
||
const db = new Database(config, getLogger()) | ||
const result = await db.raw('select 1 + 1', [], 'write') | ||
assert.isDefined(result) | ||
await db.manager.closeAll() | ||
}) | ||
}) |