diff --git a/adonis-typings/database.ts b/adonis-typings/database.ts
index f503a14b..dd8a768f 100644
--- a/adonis-typings/database.ts
+++ b/adonis-typings/database.ts
@@ -9,20 +9,151 @@
///
-declare module '@ioc:Adonis/Addons/Database' {
+declare module '@ioc:Adonis/Lucid/Database' {
import { Pool } from 'tarn'
import * as knex from 'knex'
import { EventEmitter } from 'events'
- import { ProfilerRowContract } from '@poppinss/profiler'
+ import { Dictionary } from 'ts-essentials'
+ import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
import {
RawContract,
- RawBuilderContract,
- QueryClientContract,
- TransactionClientContract,
- InsertQueryBuilderContract,
DatabaseQueryBuilderContract,
- } from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
+ InsertQueryBuilderContract,
+ StrictValuesWithoutRaw,
+ SelectTable,
+ Table,
+ } from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'
+
+ /**
+ * A executable query builder will always have these methods on it.
+ */
+ interface ExcutableQueryBuilderContract extends Promise {
+ debug (debug: boolean): this
+ timeout (time: number, options?: { cancel: boolean }): this
+ useTransaction (trx: TransactionClientContract): this
+ toQuery (): string
+ exec (): Promise
+ toSQL (): knex.Sql
+ }
+
+ /**
+ * Shape of the query client, that is used to retrive instances
+ * of query builder
+ */
+ interface QueryClientContract {
+ /**
+ * Custom profiler to time queries
+ */
+ profiler?: ProfilerRowContract | ProfilerContract
+
+ /**
+ * Tells if client is a transaction client or not
+ */
+ isTransaction: boolean
+
+ /**
+ * The database dialect in use
+ */
+ dialect: string
+
+ /**
+ * The client mode in which it is execute queries
+ */
+ mode: 'dual' | 'write' | 'read'
+
+ /**
+ * The name of the connnection from which the client
+ * was originated
+ */
+ connectionName: string
+
+ /**
+ * Returns the read and write clients
+ */
+ getReadClient (): knex | knex.Transaction
+ getWriteClient (): knex | knex.Transaction
+
+ /**
+ * Get new query builder instance for select, update and
+ * delete calls
+ */
+ query<
+ Record extends any = any,
+ Result extends any = any,
+ > (): DatabaseQueryBuilderContract & ExcutableQueryBuilderContract,
+
+ /**
+ * Get new query builder instance inserts
+ */
+ insertQuery<
+ Record extends any = any,
+ ReturnColumns extends any = any[]
+ > (): InsertQueryBuilderContract & ExcutableQueryBuilderContract,
+
+ /**
+ * Get raw query builder instance
+ */
+ raw<
+ Result extends any = any
+ > (
+ sql: string,
+ bindings?: { [key: string]: StrictValuesWithoutRaw } | StrictValuesWithoutRaw,
+ ): RawContract & ExcutableQueryBuilderContract
+
+ /**
+ * Truncate a given table
+ */
+ truncate (table: string): Promise,
+
+ /**
+ * Returns columns info for a given table
+ */
+ columnsInfo (table: string): Promise<{ [column: string]: knex.ColumnInfo }>,
+ columnsInfo (table: string, column: string): Promise,
+
+ /**
+ * Same as `query()`, but also selects the table for the query. The `from` method
+ * doesn't allow defining the return type and one must use `query` to define
+ * that.
+ */
+ from: SelectTable>,
+
+ /**
+ * Same as `insertQuery()`, but also selects the table for the query. The `table`
+ * method doesn't allow defining the return type and one must use `insertQuery`
+ * to define that.
+ */
+ table: Table>,
+
+ /**
+ * Get instance of transaction client
+ */
+ transaction (): Promise,
+ }
+
+ /**
+ * The shape of transaction client to run queries under a given
+ * transaction on a single connection
+ */
+ interface TransactionClientContract extends QueryClientContract {
+ knexClient: knex.Transaction,
+
+ /**
+ * Is transaction completed or not
+ */
+ isCompleted: boolean,
+
+ /**
+ * Commit transaction
+ */
+ commit (): Promise,
+
+ /**
+ * Rollback transaction
+ */
+ rollback (): Promise
+ }
/**
* Connection node used by majority of database
@@ -338,6 +469,9 @@ declare module '@ioc:Adonis/Addons/Database' {
client?: knex,
readClient?: knex,
+ /**
+ * Property to find if explicit read/write is enabled
+ */
hasReadWriteReplicas: boolean,
/**
@@ -381,36 +515,86 @@ declare module '@ioc:Adonis/Addons/Database' {
getClient (mode?: 'write' | 'read'): QueryClientContract,
}
+ type DatabaseClientOptions = Partial<{
+ mode: 'read' | 'write',
+ profiler: ProfilerRowContract | ProfilerContract,
+ }>
+
/**
* Database contract serves as the main API to interact with multiple
* database connections
*/
export interface DatabaseContract {
+ /**
+ * Name of the primary connection defined inside `config/database.ts`
+ * file
+ */
primaryConnectionName: string,
- getRawConnection: ConnectionManagerContract['get']
+
+ /**
+ * Reference to the connection manager
+ */
manager: ConnectionManagerContract,
- connection (
- connectionName: string,
- options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract }>,
- ): QueryClientContract
+ /**
+ * Returns the raw connection instance
+ */
+ getRawConnection: ConnectionManagerContract['get'],
- query (
- options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract }>,
- ): DatabaseQueryBuilderContract
+ /**
+ * Get query client for a given connection. Optionally one can also define
+ * the mode of the connection and profiler row
+ */
+ connection (connectionName: string, options?: DatabaseClientOptions): QueryClientContract
- insertQuery (
- options?: Partial<{ profiler: ProfilerRowContract }>,
- ): InsertQueryBuilderContract
+ /**
+ * Get query builder instance for a given connection.
+ */
+ query<
+ Record extends any = any,
+ Result extends any = any,
+ > (
+ options?: DatabaseClientOptions,
+ ): DatabaseQueryBuilderContract & ExcutableQueryBuilderContract,
- from (table: string): DatabaseQueryBuilderContract
- table (table: string): InsertQueryBuilderContract
- transaction (): Promise
+ /**
+ * Get insert query builder instance for a given connection.
+ */
+ insertQuery<
+ Record extends any = any,
+ ReturnColumns extends any = any
+ > (
+ options?: DatabaseClientOptions,
+ ): InsertQueryBuilderContract & ExcutableQueryBuilderContract,
- raw (
+ /**
+ * Get raw query builder instance
+ */
+ raw<
+ Result extends any = any
+ > (
sql: string,
- bindings?: any,
- options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract }>,
- ): RawContract
+ bindings?: { [key: string]: StrictValuesWithoutRaw } | StrictValuesWithoutRaw[],
+ options?: DatabaseClientOptions,
+ ): RawContract & ExcutableQueryBuilderContract
+
+ /**
+ * Selects a table on the default connection by instantiating a new query
+ * builder instance. This method provides no control over the client
+ * mode and one must use `query` for that
+ */
+ from: QueryClientContract['from']
+
+ /**
+ * Selects a table on the default connection by instantiating a new query
+ * builder instance. This method provides no control over the client
+ * mode and one must use `insertQuery` for that
+ */
+ table: QueryClientContract['table']
+
+ /**
+ * Start a new transaction
+ */
+ transaction (): Promise
}
}
diff --git a/adonis-typings/querybuilder.ts b/adonis-typings/querybuilder.ts
index c7705984..b4353624 100644
--- a/adonis-typings/querybuilder.ts
+++ b/adonis-typings/querybuilder.ts
@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
-declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
+declare module '@ioc:Adonis/Lucid/DatabaseQueryBuilder' {
import * as knex from 'knex'
import { Dictionary } from 'ts-essentials'
import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
@@ -35,7 +35,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
* A known set of values allowed when defining values for different
* clauses
*/
- type StrictValues =
+ export type StrictValues =
| string
| number
| boolean
@@ -47,24 +47,16 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
| Buffer
| RawContract
- /**
- * Shape of raw query builder. The builder is a method used to build
- * raw queries.
- */
- interface RawBuilderContract {
- (sql: string): RawContract
- (sql: string, bindings: { [key: string]: Exclude }): RawContract
- (sql: string, bindings: Exclude[]): RawContract
- }
+ export type StrictValuesWithoutRaw = Exclude
/**
* A builder method to allow raw queries. However, the return type is the
* instance of current query builder. This is used for `.{verb}Raw` methods.
*/
- interface RawQueryBuilderContract {
+ interface RawQueryFn {
(sql: string): Builder
- (sql: string, bindings: { [key: string]: Exclude }): Builder
- (sql: string, bindings: Exclude[]): Builder
+ (sql: string, bindings: { [key: string]: StrictValuesWithoutRaw }): Builder
+ (sql: string, bindings: StrictValuesWithoutRaw[]): Builder
(sql: RawContract): Builder
}
@@ -375,8 +367,8 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
* result set. Unlike knex, we force defining aliases for each aggregate.
*/
interface Aggregate <
+ Builder extends ChainableContract,
Record extends Dictionary,
- Result extends any,
> {
/**
* Accepting a typed column with the alias for the count. Unlike knex
@@ -386,7 +378,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
(
column: OneOrMany,
alias: Alias,
- ): DatabaseQueryBuilderContract>
+ ): Builder
/**
* Accepting an object for multiple counts in a single query. Again
@@ -398,7 +390,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
Columns extends Dictionary, Alias>,
>(
columns: Columns,
- ): DatabaseQueryBuilderContract
+ ): Builder
/**
* Accepting an un typed column with the alias for the count.
@@ -406,7 +398,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
(
column: OneOrMany>,
alias: Alias,
- ): DatabaseQueryBuilderContract>
+ ): Builder
/**
* Accepting an object for multiple counts in a single query. Again
@@ -417,7 +409,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
Columns extends Dictionary>, Alias>,
>(
columns: Columns,
- ): DatabaseQueryBuilderContract
+ ): Builder
}
/**
@@ -673,18 +665,6 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
(values: { [P in K]: number }): Builder
}
- /**
- * A executable query builder will always have these methods on it.
- */
- interface ExcutableQueryBuilderContract extends Promise {
- debug (debug: boolean): this
- timeout (time: number, options?: { cancel: boolean }): this
- useTransaction (trx: TransactionClientContract): this
- toQuery (): string
- exec (): Promise
- toSQL (): knex.Sql
- }
-
/**
* Possible signatures for an insert query
*/
@@ -714,6 +694,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
Record extends Dictionary = Dictionary,
> {
from: SelectTable
+ select: DatabaseQueryBuilderSelect
where: Where
orWhere: Where
@@ -755,9 +736,9 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
orWhereNotBetween: WhereBetween
andWhereNotBetween: WhereBetween
- whereRaw: RawQueryBuilderContract
- orWhereRaw: RawQueryBuilderContract
- andWhereRaw: RawQueryBuilderContract
+ whereRaw: RawQueryFn
+ orWhereRaw: RawQueryFn
+ andWhereRaw: RawQueryFn
join: Join
innerJoin: Join
@@ -767,7 +748,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
rightOuterJoin: Join
fullOuterJoin: Join
crossJoin: Join
- joinRaw: RawQueryBuilderContract
+ joinRaw: RawQueryFn
having: Having
orHaving: Having
@@ -805,17 +786,17 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
orHavingNotBetween: HavingBetween
andHavingNotBetween: HavingBetween
- havingRaw: RawQueryBuilderContract
- orHavingRaw: RawQueryBuilderContract
- andHavingRaw: RawQueryBuilderContract
+ havingRaw: RawQueryFn
+ orHavingRaw: RawQueryFn
+ andHavingRaw: RawQueryFn
distinct: Distinct
groupBy: GroupBy
- groupByRaw: RawQueryBuilderContract
+ groupByRaw: RawQueryFn
orderBy: OrderBy
- orderByRaw: RawQueryBuilderContract
+ orderByRaw: RawQueryFn
union: Union
unionAll: UnionAll
@@ -844,30 +825,21 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
}
/**
- * Database query builder interface. Some of the methods on the Database
- * query builder and Model query builder will behave differently.
+ * Shape of the raw query that can also be passed as a value to
+ * other queries
*/
+ interface RawContract {
+ wrap (before: string, after: string): this
+ }
+
+ /**
+ * Database query builder interface. It will use the `Executable` trait
+ * and hence must be typed properly for that.
+ */
export interface DatabaseQueryBuilderContract <
Record extends Dictionary = Dictionary,
Result extends any = Record,
- > extends ChainableContract, ExcutableQueryBuilderContract {
- select: DatabaseQueryBuilderSelect
-
- /**
- * Aggregates
- */
- count: Aggregate
- countDistinct: Aggregate
- min: Aggregate
- max: Aggregate
- sum: Aggregate
- avg: Aggregate
- avgDistinct: Aggregate
-
- returning: Returning
- update: Update
- increment: Counter
- decrement: Counter
+ > extends ChainableContract {
del (): this
/**
@@ -882,15 +854,34 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
* Execute and get first result
*/
first (): Promise
+
+ /**
+ * Aggregates
+ */
+ count: Aggregate
+ countDistinct: Aggregate
+ min: Aggregate
+ max: Aggregate
+ sum: Aggregate
+ avg: Aggregate
+ avgDistinct: Aggregate
+
+ /**
+ * Mutations
+ */
+ update: Update
+ increment: Counter
+ decrement: Counter
}
/**
- * Insert query builder to perform database inserts
+ * Insert query builder to perform database inserts. It will use the
+ * `Executable` trait and hence must be typed property for that.
*/
export interface InsertQueryBuilderContract<
Record extends Dictionary = Dictionary,
- ReturnColumns extends any[] = any[]
- > extends ExcutableQueryBuilderContract {
+ ReturnColumns extends any = any[]
+ > {
/**
* Table for the insert query
*/
@@ -911,114 +902,4 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' {
*/
multiInsert: MultiInsert
}
-
- /**
- * Shape of raw query instance
- */
- interface RawContract extends ExcutableQueryBuilderContract {
- wrap (before: string, after: string): this
- }
-
- /**
- * Shape of the query client, that is used to retrive instances
- * of query builder
- */
- interface QueryClientContract {
- /**
- * Custom profiler to time queries
- */
- profiler?: ProfilerRowContract | ProfilerContract
-
- /**
- * Tells if client is a transaction client or not
- */
- isTransaction: boolean
-
- /**
- * The database dialect in use
- */
- dialect: string
-
- /**
- * The client mode in which it is execute queries
- */
- mode: 'dual' | 'write' | 'read'
-
- /**
- * The name of the connnection from which the client
- * was originated
- */
- connectionName: string
-
- /**
- * Returns the read and write clients
- */
- getReadClient (): knex | knex.Transaction
- getWriteClient (): knex | knex.Transaction
-
- /**
- * Get new query builder instance for select, update and
- * delete calls
- */
- query (): DatabaseQueryBuilderContract,
-
- /**
- * Get new query builder instance inserts
- */
- insertQuery (): InsertQueryBuilderContract,
-
- /**
- * Get raw query builder instance
- */
- raw: RawBuilderContract,
-
- /**
- * Truncate a given table
- */
- truncate (table: string): Promise,
-
- /**
- * Returns columns info for a given table
- */
- columnsInfo (table: string): Promise<{ [column: string]: knex.ColumnInfo }>,
- columnsInfo (table: string, column: string): Promise,
-
- /**
- * Same as `query()`, but also selects the table for the query
- */
- from: DatabaseQueryBuilderContract['from'],
-
- /**
- * Same as `insertQuery()`, but also selects the table for the query
- */
- table: InsertQueryBuilderContract['table'],
-
- /**
- * Get instance of transaction client
- */
- transaction (): Promise,
- }
-
- /**
- * The shape of transaction client to run queries under a given
- * transaction on a single connection
- */
- interface TransactionClientContract extends QueryClientContract {
- knexClient: knex.Transaction,
-
- /**
- * Is transaction completed or not
- */
- isCompleted: boolean,
-
- /**
- * Commit transaction
- */
- commit (): Promise,
-
- /**
- * Rollback transaction
- */
- rollback (): Promise
- }
}
diff --git a/package.json b/package.json
index 5f4cd0f5..e0952e0b 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"dependencies": {
"@poppinss/logger": "^1.1.2",
"@poppinss/profiler": "^1.1.0",
+ "@poppinss/traits": "^1.0.0",
"@poppinss/utils": "^1.0.4",
"knex": "^0.19.2",
"knex-dynamic-connection": "^1.0.0",
diff --git a/src/Connection/Manager.ts b/src/Connection/Manager.ts
index 3edb6ef8..dcb9bec3 100644
--- a/src/Connection/Manager.ts
+++ b/src/Connection/Manager.ts
@@ -14,10 +14,10 @@ import { Exception } from '@poppinss/utils'
import { LoggerContract } from '@poppinss/logger'
import {
- ConnectionConfigContract,
ConnectionContract,
+ ConnectionConfigContract,
ConnectionManagerContract,
-} from '@ioc:Adonis/Addons/Database'
+} from '@ioc:Adonis/Lucid/Database'
import { Connection } from './index'
diff --git a/src/Connection/index.ts b/src/Connection/index.ts
index f122a8eb..a3dc19af 100644
--- a/src/Connection/index.ts
+++ b/src/Connection/index.ts
@@ -15,8 +15,8 @@ import { EventEmitter } from 'events'
import { Exception } from '@poppinss/utils'
import { LoggerContract } from '@poppinss/logger'
import { patchKnex } from 'knex-dynamic-connection'
+import { ConnectionConfigContract, ConnectionContract } from '@ioc:Adonis/Lucid/Database'
-import { ConnectionConfigContract, ConnectionContract } from '@ioc:Adonis/Addons/Database'
import { QueryClient } from '../Database/QueryClient'
/**
diff --git a/src/Database/QueryBuilder/Chainable.ts b/src/Database/QueryBuilder/Chainable.ts
index 1dd6c3d5..045a205e 100644
--- a/src/Database/QueryBuilder/Chainable.ts
+++ b/src/Database/QueryBuilder/Chainable.ts
@@ -10,7 +10,7 @@
///
import * as knex from 'knex'
-import { ChainableContract, QueryCallback } from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
+import { ChainableContract, QueryCallback } from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'
import { RawQueryBuilder } from './Raw'
@@ -29,7 +29,7 @@ type DBQueryCallback = (userFn: QueryCallback) => ((builder:
*/
export abstract class Chainable implements ChainableContract {
constructor (
- protected $knexBuilder: knex.QueryBuilder,
+ public $knexBuilder: knex.QueryBuilder, // Needs to be public for Executable trait
private _queryCallback: DBQueryCallback,
) {}
@@ -90,6 +90,14 @@ export abstract class Chainable implements ChainableContract {
return value
}
+ /**
+ * Define columns for selection
+ */
+ public select (): this {
+ this.$knexBuilder.select(...arguments)
+ return this
+ }
+
/**
* Select table for the query. Re-calling this method multiple times will
* use the last selected table
diff --git a/src/Database/QueryBuilder/Database.ts b/src/Database/QueryBuilder/Database.ts
index 797dd6db..abfab2b2 100644
--- a/src/Database/QueryBuilder/Database.ts
+++ b/src/Database/QueryBuilder/Database.ts
@@ -11,16 +11,17 @@
import * as knex from 'knex'
import { Exception } from '@poppinss/utils'
+import { trait } from '@poppinss/traits'
import {
DatabaseQueryBuilderContract,
QueryCallback,
- TransactionClientContract,
- QueryClientContract,
- } from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
+} from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'
+
+import { QueryClientContract } from '@ioc:Adonis/Lucid/Database'
import { Chainable } from './Chainable'
-import { executeQuery, isInTransaction } from '../../utils'
+import { Executable, ExecutableConstrutor } from '../Traits/Executable'
/**
* Wrapping the user function for a query callback and give them
@@ -37,8 +38,9 @@ function queryCallback (userFn: QueryCallback) {
* Database query builder exposes the API to construct and run queries for selecting,
* updating and deleting records.
*/
+@trait(Executable)
export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuilderContract {
- constructor (builder: knex.QueryBuilder, private _client?: QueryClientContract) {
+ constructor (builder: knex.QueryBuilder, public client?: QueryClientContract) {
super(builder, queryCallback)
}
@@ -47,65 +49,11 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
* client
*/
private _ensureCanPerformWrites () {
- if (this._client && this._client.mode === 'read') {
+ if (this.client && this.client.mode === 'read') {
throw new Exception('Updates and deletes cannot be performed in read mode')
}
}
- /**
- * Raises exception when client is not defined
- */
- private _ensureClient () {
- if (!this._client) {
- throw new Exception('Cannot execute query without query client', 500, 'E_PROGRAMMING_EXCEPTION')
- }
- }
-
- /**
- * Returns the client to be used for the query. This method relies on the
- * query method and will choose the read or write connection whenever
- * required.
- */
- private _getQueryClient () {
- /**
- * Return undefined when no parent client is defined or dialect
- * is sqlite
- */
- if (this._client!.dialect === 'sqlite3') {
- return
- }
-
- /**
- * Use transaction client directly, since it preloads the
- * connection
- */
- if (isInTransaction(this.$knexBuilder, this._client!)) {
- return
- }
-
- /**
- * Use write client for updates and deletes
- */
- if (['update', 'del'].includes(this.$knexBuilder['_method'])) {
- return this._client!.getWriteClient().client
- }
-
- return this._client!.getReadClient().client
- }
-
- /**
- * Returns the profiler data
- */
- private _getProfilerData () {
- if (!this._client!.profiler) {
- return {}
- }
-
- return {
- connection: this._client!.connectionName,
- }
- }
-
/**
* Normalizes the columns aggregates functions to something
* knex can process.
@@ -125,14 +73,6 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
return { [alias]: this.$transformValue(columns) }
}
- /**
- * Define columns for selection
- */
- public select (): this {
- this.$knexBuilder.select(...arguments)
- return this
- }
-
/**
* Count rows for the current query
*/
@@ -220,7 +160,7 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
* Clone the current query builder
*/
public clone (): DatabaseQueryBuilder {
- return new DatabaseQueryBuilder(this.$knexBuilder.clone(), this._client)
+ return new DatabaseQueryBuilder(this.$knexBuilder.clone(), this.client)
}
/**
@@ -230,7 +170,7 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
/**
* Do not chain `returning` in sqlite3 to avoid knex warnings
*/
- if (this._client && this._client.dialect === 'sqlite3') {
+ if (this.client && this.client.dialect === 'sqlite3') {
return this
}
@@ -252,88 +192,27 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
* will implicitly set a `limit` on the query
*/
public async first (): Promise {
- const result = await this.limit(1).exec()
+ const result = await this.limit(1)['exec']()
return result[0] || null
}
/**
- * Required when Promises are extended
- */
- public get [Symbol.toStringTag] () {
- return this.constructor.name
- }
-
- /**
- * Turn on/off debugging for this query
- */
- public debug (debug: boolean): this {
- this.$knexBuilder.debug(debug)
- return this
- }
-
- /**
- * Define query timeout
- */
- public timeout (time: number, options?: { cancel: boolean }): this {
- this.$knexBuilder['timeout'](time, options)
- return this
- }
-
- /**
- * Use transaction connection
- */
- public useTransaction (trx: TransactionClientContract): this {
- this.$knexBuilder.transacting(trx.knexClient)
- return this
- }
-
- /**
- * Returns SQL query as a string
- */
- public toQuery (): string {
- return this.$knexBuilder.toQuery()
- }
-
- /**
- * Executes the query
- */
- public async exec (): Promise {
- this._ensureClient()
-
- const result = await executeQuery(
- this.$knexBuilder,
- this._getQueryClient(),
- this._client!.profiler,
- this._getProfilerData(),
- )
- return result
- }
-
- /**
- * Get sql representation of the query
- */
- public toSQL (): knex.Sql {
- return this.$knexBuilder.toSQL()
- }
-
- /**
- * Implementation of `then` for the promise API
- */
- public then (resolve: any, reject?: any): any {
- return this.exec().then(resolve, reject)
- }
-
- /**
- * Implementation of `catch` for the promise API
+ * Returns the client to be used for the query. This method relies on the
+ * query method and will choose the read or write connection whenever
+ * required.
+ *
+ * This method is invoked by the `Executable` Trait, only when actually
+ * query isn't using the transaction
*/
- public catch (reject: any): any {
- return this.exec().catch(reject)
- }
+ public getQueryClient () {
+ /**
+ * Use write client for updates and deletes
+ */
+ if (['update', 'del'].includes(this.$knexBuilder['_method'])) {
+ this._ensureCanPerformWrites()
+ return this.client!.getWriteClient().client
+ }
- /**
- * Implementation of `finally` for the promise API
- */
- public finally (fullfilled: any) {
- return this.exec().finally(fullfilled)
+ return this.client!.getReadClient().client
}
}
diff --git a/src/Database/QueryBuilder/Insert.ts b/src/Database/QueryBuilder/Insert.ts
index 2be5b129..70ed24cf 100644
--- a/src/Database/QueryBuilder/Insert.ts
+++ b/src/Database/QueryBuilder/Insert.ts
@@ -10,30 +10,19 @@
///
import * as knex from 'knex'
-import { Exception } from '@poppinss/utils'
+import { trait } from '@poppinss/traits'
-import {
- InsertQueryBuilderContract,
- TransactionClientContract,
- QueryClientContract,
-} from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
+import { QueryClientContract } from '@ioc:Adonis/Lucid/Database'
+import { InsertQueryBuilderContract } from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'
-import { executeQuery, isInTransaction } from '../../utils'
+import { Executable, ExecutableConstrutor } from '../Traits/Executable'
/**
* Exposes the API for performing SQL inserts
*/
+@trait(Executable)
export class InsertQueryBuilder implements InsertQueryBuilderContract {
- constructor (protected $knexBuilder: knex.QueryBuilder, private _client?: QueryClientContract) {
- }
-
- /**
- * Raises exception when client is not defined
- */
- private _ensureClient () {
- if (!this._client) {
- throw new Exception('Cannot execute query without query client', 500, 'E_PROGRAMMING_EXCEPTION')
- }
+ constructor (public $knexBuilder: knex.QueryBuilder, public client?: QueryClientContract) {
}
/**
@@ -42,40 +31,11 @@ export class InsertQueryBuilder implements InsertQueryBuilderContract {
* self defining the connection, so that we can discover any bugs during
* this process.
*/
- private _getQueryClient () {
- /**
- * Return undefined when no parent client is defined or dialect
- * is sqlite
- */
- if (this._client!.dialect === 'sqlite3') {
- return
- }
-
- /**
- * Use transaction client directly, since it preloads the
- * connection
- */
- if (isInTransaction(this.$knexBuilder, this._client!)) {
- return
- }
-
+ public getQueryClient () {
/**
* Always use write client for write queries
*/
- return this._client!.getWriteClient().client
- }
-
- /**
- * Returns the profiler data
- */
- private _getProfilerData () {
- if (!this._client!.profiler) {
- return {}
- }
-
- return {
- connection: this._client!.connectionName,
- }
+ return this.client!.getWriteClient().client
}
/**
@@ -93,7 +53,7 @@ export class InsertQueryBuilder implements InsertQueryBuilderContract {
/**
* Do not chain `returning` in sqlite3 to avoid knex warnings
*/
- if (this._client && this._client.dialect === 'sqlite3') {
+ if (this.client && this.client.dialect === 'sqlite3') {
return this
}
@@ -115,85 +75,4 @@ export class InsertQueryBuilder implements InsertQueryBuilderContract {
public multiInsert (columns: any): this {
return this.insert(columns)
}
-
- /**
- * Required when Promises are extended
- */
- public get [Symbol.toStringTag] () {
- return this.constructor.name
- }
-
- /**
- * Turn on/off debugging for this query
- */
- public debug (debug: boolean): this {
- this.$knexBuilder.debug(debug)
- return this
- }
-
- /**
- * Define query timeout
- */
- public timeout (time: number, options?: { cancel: boolean }): this {
- this.$knexBuilder['timeout'](time, options)
- return this
- }
-
- /**
- * Use transaction connection
- */
- public useTransaction (trx: TransactionClientContract): this {
- this.$knexBuilder.transacting(trx.knexClient)
- return this
- }
-
- /**
- * Returns SQL query as a string
- */
- public toQuery (): string {
- return this.$knexBuilder.toQuery()
- }
-
- /**
- * Executes the query
- */
- public async exec (): Promise {
- this._ensureClient()
-
- const result = await executeQuery(
- this.$knexBuilder,
- this._getQueryClient(),
- this._client!.profiler,
- this._getProfilerData(),
- )
- return result
- }
-
- /**
- * Get sql representation of the query
- */
- public toSQL (): knex.Sql {
- return this.$knexBuilder.toSQL()
- }
-
- /**
- * Implementation of `then` for the promise API
- */
- public then (resolve: any, reject?: any): any {
- return this.exec().then(resolve, reject)
- }
-
- /**
- * Implementation of `catch` for the promise API
- */
- public catch (reject: any): any {
- return this.exec().catch(reject)
- }
-
- /**
- * Implementation of `finally` for the promise API
- */
- public finally (fullfilled: any) {
- return this.exec().finally(fullfilled)
- }
}
diff --git a/src/Database/QueryBuilder/Raw.ts b/src/Database/QueryBuilder/Raw.ts
index 69e54a40..d779b4be 100644
--- a/src/Database/QueryBuilder/Raw.ts
+++ b/src/Database/QueryBuilder/Raw.ts
@@ -10,42 +10,27 @@
///
import * as knex from 'knex'
-import { Exception } from '@poppinss/utils'
+import { trait } from '@poppinss/traits'
-import {
- RawContract,
- TransactionClientContract,
- QueryClientContract,
-} from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
-import { executeQuery } from '../../utils'
+import { QueryClientContract } from '@ioc:Adonis/Lucid/Database'
+import { RawContract } from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'
+
+import { Executable, ExecutableConstrutor } from '../Traits/Executable'
/**
* Exposes the API to execute raw queries
*/
+@trait(Executable)
export class RawQueryBuilder implements RawContract {
- constructor (protected $knexBuilder: knex.Raw, private _client?: QueryClientContract) {
+ constructor (public $knexBuilder: knex.Raw, public client?: QueryClientContract) {
}
/**
- * Raises exception when client is not defined
+ * It's impossible to judge the client for the raw query and
+ * hence we always use the default client
*/
- private _ensureClient () {
- if (!this._client) {
- throw new Exception('Cannot execute query without query client', 500, 'E_PROGRAMMING_EXCEPTION')
- }
- }
-
- /**
- * Returns the profiler data
- */
- private _getProfilerData () {
- if (!this._client!.profiler) {
- return {}
- }
-
- return {
- connection: this._client!.connectionName,
- }
+ public getQueryClient () {
+ return undefined
}
/**
@@ -55,85 +40,4 @@ export class RawQueryBuilder implements RawContract {
this.$knexBuilder.wrap(before, after)
return this
}
-
- /**
- * Required when Promises are extended
- */
- public get [Symbol.toStringTag] () {
- return this.constructor.name
- }
-
- /**
- * Turn on/off debugging for this query
- */
- public debug (debug: boolean): this {
- this.$knexBuilder.debug(debug)
- return this
- }
-
- /**
- * Define query timeout
- */
- public timeout (time: number, options?: { cancel: boolean }): this {
- this.$knexBuilder['timeout'](time, options)
- return this
- }
-
- /**
- * Use transaction connection
- */
- public useTransaction (trx: TransactionClientContract): this {
- this.$knexBuilder.transacting(trx.knexClient)
- return this
- }
-
- /**
- * Returns SQL query as a string
- */
- public toQuery (): string {
- return this.$knexBuilder.toQuery()
- }
-
- /**
- * Executes the query
- */
- public async exec (): Promise {
- this._ensureClient()
-
- const result = await executeQuery(
- this.$knexBuilder,
- undefined,
- this._client!.profiler,
- this._getProfilerData(),
- )
- return result
- }
-
- /**
- * Get sql representation of the query
- */
- public toSQL (): knex.Sql {
- return this.$knexBuilder.toSQL()
- }
-
- /**
- * Implementation of `then` for the promise API
- */
- public then (resolve: any, reject?: any): any {
- return this.exec().then(resolve, reject)
- }
-
- /**
- * Implementation of `catch` for the promise API
- */
- public catch (reject: any): any {
- return this.exec().catch(reject)
- }
-
- /**
- * Implementation of `finally` for the promise API
- */
- public finally (fullfilled: any) {
- return this.exec().finally(fullfilled)
- }
}
diff --git a/src/Database/QueryClient/index.ts b/src/Database/QueryClient/index.ts
index 35c42fcd..ffa27d52 100644
--- a/src/Database/QueryClient/index.ts
+++ b/src/Database/QueryClient/index.ts
@@ -11,27 +11,26 @@
import * as knex from 'knex'
import { Exception } from '@poppinss/utils'
-import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
import { resolveClientNameWithAliases } from 'knex/lib/helpers'
+import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
import {
- RawContract,
+ ConnectionContract,
QueryClientContract,
TransactionClientContract,
- InsertQueryBuilderContract,
- DatabaseQueryBuilderContract,
-} from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
-
-import { ConnectionContract } from '@ioc:Adonis/Addons/Database'
+} from '@ioc:Adonis/Lucid/Database'
-import { TransactionClient } from '../TransactionClient'
import { RawQueryBuilder } from '../QueryBuilder/Raw'
+import { TransactionClient } from '../TransactionClient'
import { InsertQueryBuilder } from '../QueryBuilder/Insert'
import { DatabaseQueryBuilder } from '../QueryBuilder/Database'
/**
* Query client exposes the API to fetch instance of different query builders
* to perform queries on a selection connection.
+ *
+ * Many of the methods returns `any`, since this class is type casted to an interface,
+ * it doesn't real matter what are the return types from this class
*/
export class QueryClient implements QueryClientContract {
/**
@@ -58,18 +57,7 @@ export class QueryClient implements QueryClientContract {
public mode: 'dual' | 'write' | 'read',
private _connection: ConnectionContract,
) {
- this.dialect = resolveClientNameWithAliases(this._getAvailableClient().client.config.client)
- }
-
- /**
- * Returns any of the available clients, giving preference to the
- * write client.
- *
- * One client will always exists, otherwise instantiation of this
- * class will fail.
- */
- private _getAvailableClient () {
- return this._connection.client!
+ this.dialect = resolveClientNameWithAliases(this._connection.config.client)
}
/**
@@ -131,28 +119,28 @@ export class QueryClient implements QueryClientContract {
* Returns instance of a query builder for selecting, updating
* or deleting rows
*/
- public query (): DatabaseQueryBuilderContract {
- return new DatabaseQueryBuilder(this._getAvailableClient().queryBuilder(), this)
+ public query (): any {
+ return new DatabaseQueryBuilder(this._connection.client!.queryBuilder(), this)
}
/**
* Returns instance of a query builder for inserting rows
*/
- public insertQuery (): InsertQueryBuilderContract {
+ public insertQuery (): any {
return new InsertQueryBuilder(this.getWriteClient().queryBuilder(), this)
}
/**
* Returns instance of raw query builder
*/
- public raw (sql: any, bindings?: any): RawContract {
- return new RawQueryBuilder(this._getAvailableClient().raw(sql, bindings), this)
+ public raw (sql: any, bindings?: any): any {
+ return new RawQueryBuilder(this._connection.client!.raw(sql, bindings), this)
}
/**
* Returns instance of a query builder and selects the table
*/
- public from (table: any): DatabaseQueryBuilderContract {
+ public from (table: any): any {
return this.query().from(table)
}
@@ -160,7 +148,7 @@ export class QueryClient implements QueryClientContract {
* Returns instance of a query builder and selects the table
* for an insert query
*/
- public table (table: any): InsertQueryBuilderContract {
+ public table (table: any): any {
return this.insertQuery().table(table)
}
}
diff --git a/src/Database/Traits/Executable.ts b/src/Database/Traits/Executable.ts
new file mode 100644
index 00000000..1b40dded
--- /dev/null
+++ b/src/Database/Traits/Executable.ts
@@ -0,0 +1,223 @@
+/*
+ * @adonisjs/lucid
+ *
+ * (c) Harminder Virk
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+*/
+
+///
+
+import knex from 'knex'
+import { Exception } from '@poppinss/utils'
+import { ProfilerActionContract } from '@poppinss/profiler/build/src/Contracts'
+
+import {
+ QueryClientContract,
+ TransactionClientContract,
+ ExcutableQueryBuilderContract,
+} from '@ioc:Adonis/Lucid/Database'
+
+/**
+ * Enforcing constructor on the destination class
+ */
+export type ExecutableConstrutor undefined | knex,
+ client?: QueryClientContract,
+}> = { new (...args: any[]): T }
+
+/**
+ * To be used as a trait for executing a query that has a public
+ * `$knexBuilder`
+ */
+export class Executable implements ExcutableQueryBuilderContract {
+ protected $knexBuilder: knex.QueryBuilder | knex.Raw
+ protected client: QueryClientContract
+ protected getQueryClient: () => undefined | knex
+
+ /**
+ * Returns the profiler action
+ */
+ private _getProfilerAction () {
+ if (!this.client.profiler) {
+ return null
+ }
+
+ return this.client.profiler.profile('sql:query', Object.assign(this.toSQL(), {
+ connection: this.client.connectionName,
+ }))
+ }
+
+ /**
+ * Ends the profile action
+ */
+ private _endProfilerAction (action: null | ProfilerActionContract, error?: any) {
+ if (!action) {
+ return
+ }
+
+ error ? action.end({ error }) : action.end()
+ }
+
+ /**
+ * Executes the knex query builder
+ */
+ private async _executeQuery () {
+ const action = this._getProfilerAction()
+ try {
+ const result = await this.$knexBuilder
+ this._endProfilerAction(action)
+ return result
+ } catch (error) {
+ this._endProfilerAction(action, error)
+ throw error
+ }
+ }
+
+ /**
+ * Executes the query by acquiring a connection from a custom
+ * knex client
+ */
+ private async _executeQueryWithCustomConnection (knexClient: knex) {
+ const action = this._getProfilerAction()
+
+ /**
+ * Acquire connection from the client and set it as the
+ * connection to be used for executing the query
+ */
+ const connection = await knexClient['acquireConnection']()
+ this.$knexBuilder.connection(connection)
+
+ let queryError: any = null
+ let queryResult: any = null
+
+ /**
+ * Executing the query and catching exceptions so that we can
+ * dispose the connection before raising exception from this
+ * method
+ */
+ try {
+ queryResult = await this.$knexBuilder
+ this._endProfilerAction(action)
+ } catch (error) {
+ queryError = error
+ this._endProfilerAction(action, error)
+ }
+
+ /**
+ * Releasing the connection back to pool
+ */
+ knexClient['releaseConnection'](connection)
+
+ /**
+ * Re-throw if there was an exception
+ */
+ if (queryError) {
+ throw queryError
+ }
+
+ /**
+ * Return result
+ */
+ return queryResult
+ }
+
+ /**
+ * Turn on/off debugging for this query
+ */
+ public debug (debug: boolean): this {
+ this.$knexBuilder.debug(debug)
+ return this
+ }
+
+ /**
+ * Define query timeout
+ */
+ public timeout (time: number, options?: { cancel: boolean }): this {
+ this.$knexBuilder['timeout'](time, options)
+ return this
+ }
+
+ /**
+ * Returns SQL query as a string
+ */
+ public toQuery (): string {
+ return this.$knexBuilder.toQuery()
+ }
+
+ /**
+ * Run query inside the given transaction
+ */
+ public useTransaction (transaction: TransactionClientContract) {
+ this.$knexBuilder.transacting(transaction.knexClient)
+ return this
+ }
+
+ /**
+ * Executes the query
+ */
+ public async exec (): Promise {
+ /**
+ * Raise exception when client is missing, since we need one to execute
+ * the query
+ */
+ if (!this.client) {
+ throw new Exception('Cannot execute query without query client', 500, 'E_RUNTIME_EXCEPTION')
+ }
+
+ /**
+ * Execute the query as it is when using `sqlite3` or query builder is part of a
+ * transaction
+ */
+ if (
+ this.client.dialect === 'sqlite3'
+ || this.client.isTransaction
+ || this.$knexBuilder['client'].transacting
+ ) {
+ return this._executeQuery()
+ }
+
+ /**
+ * Executing the query with a custom knex client when it exits
+ */
+ const knexClient = this.getQueryClient()
+ return knexClient ? this._executeQueryWithCustomConnection(knexClient) : this._executeQuery()
+ }
+
+ /**
+ * Get sql representation of the query
+ */
+ public toSQL (): knex.Sql {
+ return this.$knexBuilder.toSQL()
+ }
+
+ /**
+ * Implementation of `then` for the promise API
+ */
+ public then (resolve: any, reject?: any): any {
+ return this.exec().then(resolve, reject)
+ }
+
+ /**
+ * Implementation of `catch` for the promise API
+ */
+ public catch (reject: any): any {
+ return this.exec().catch(reject)
+ }
+
+ /**
+ * Implementation of `finally` for the promise API
+ */
+ public finally (fullfilled: any) {
+ return this.exec().finally(fullfilled)
+ }
+
+ /**
+ * Required when Promises are extended
+ */
+ public get [Symbol.toStringTag] () {
+ return this.constructor.name
+ }
+}
diff --git a/src/Database/TransactionClient/index.ts b/src/Database/TransactionClient/index.ts
index 0abaa52a..d200bf3d 100644
--- a/src/Database/TransactionClient/index.ts
+++ b/src/Database/TransactionClient/index.ts
@@ -10,14 +10,8 @@
///
import * as knex from 'knex'
+import { TransactionClientContract } from '@ioc:Adonis/Lucid/Database'
import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
-import { TransactionClientContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
-
-import {
- RawContract,
- InsertQueryBuilderContract,
- DatabaseQueryBuilderContract,
-} from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
import { RawQueryBuilder } from '../QueryBuilder/Raw'
import { InsertQueryBuilder } from '../QueryBuilder/Insert'
@@ -94,14 +88,14 @@ export class TransactionClient implements TransactionClientContract {
/**
* Get a new query builder instance
*/
- public query (): DatabaseQueryBuilderContract {
+ public query (): any {
return new DatabaseQueryBuilder(this.knexClient.queryBuilder(), this)
}
/**
* Get a new insert query builder instance
*/
- public insertQuery (): InsertQueryBuilderContract {
+ public insertQuery (): any {
return new InsertQueryBuilder(this.knexClient.queryBuilder(), this)
}
@@ -118,21 +112,21 @@ export class TransactionClient implements TransactionClientContract {
/**
* Execute raw query on transaction
*/
- public raw (sql: any, bindings?: any): RawContract {
+ public raw (sql: any, bindings?: any): any {
return new RawQueryBuilder(this.knexClient.raw(sql, bindings), this)
}
/**
* Same as [[Transaction.query]] but also selects the table
*/
- public from (table: any): DatabaseQueryBuilderContract {
+ public from (table: any): any {
return this.query().from(table)
}
/**
* Same as [[Transaction.insertTable]] but also selects the table
*/
- public table (table: any): InsertQueryBuilderContract {
+ public table (table: any): any {
return this.insertQuery().table(table)
}
diff --git a/src/Database/index.ts b/src/Database/index.ts
index d5010419..dc84c94d 100644
--- a/src/Database/index.ts
+++ b/src/Database/index.ts
@@ -11,13 +11,14 @@
import { Exception } from '@poppinss/utils'
import { LoggerContract } from '@poppinss/logger'
-import { ProfilerContract, ProfilerRowContract } from '@poppinss/profiler'
+import { ProfilerContract } from '@poppinss/profiler'
import {
ConnectionManagerContract,
DatabaseConfigContract,
+ DatabaseClientOptions,
DatabaseContract,
-} from '@ioc:Adonis/Addons/Database'
+} from '@ioc:Adonis/Lucid/Database'
import { ConnectionManager } from '../Connection/Manager'
@@ -65,10 +66,7 @@ export class Database implements DatabaseContract {
/**
* Returns the query client for a given connection
*/
- public connection (
- connection: string = this.primaryConnectionName,
- options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract | ProfilerContract }>,
- ) {
+ public connection (connection: string = this.primaryConnectionName, options?: DatabaseClientOptions) {
options = options || {}
if (!options.profiler) {
@@ -113,7 +111,7 @@ export class Database implements DatabaseContract {
/**
* Returns query builder. Optionally one can define the mode as well
*/
- public query (options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract }>) {
+ public query (options?: DatabaseClientOptions) {
return this.connection(this.primaryConnectionName, options).query()
}
@@ -122,7 +120,7 @@ export class Database implements DatabaseContract {
* hence it doesn't matter, since in both `dual` and `write` mode,
* the `write` connection is always used.
*/
- public insertQuery (options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract }>) {
+ public insertQuery (options?: DatabaseClientOptions) {
return this.connection(this.primaryConnectionName, options).insertQuery()
}
@@ -153,11 +151,7 @@ export class Database implements DatabaseContract {
* defined the `read/write` mode in which to execute the
* query
*/
- public raw (
- sql: string,
- bindings?: any,
- options?: Partial<{ mode: 'read' | 'write', profiler: ProfilerRowContract }>,
- ) {
+ public raw (sql: string, bindings?: any, options?: DatabaseClientOptions) {
return this.connection(this.primaryConnectionName, options).raw(sql, bindings)
}
}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index b4413569..d2994cac 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -1,121 +1,121 @@
-/*
-* @adonisjs/lucid
-*
-* (c) Harminder Virk
-*
-* For the full copyright and license information, please view the LICENSE
-* file that was distributed with this source code.
-*/
-
-///
-
-import * as knex from 'knex'
-import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
-import { ProfilerActionContract } from '@poppinss/profiler/build/src/Contracts'
-import { QueryClientContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
-
-/**
- * Returns the profiler action for the SQL query. `null` is
- * returned when profiler doesn't exists.
- */
-function getProfilerAction (
- builder: knex.QueryBuilder | knex.Raw,
- profiler?: ProfilerRowContract | ProfilerContract,
- profilerData?: any,
-) {
- if (!profiler) {
- return null
- }
-
- return profiler.profile('sql:query', Object.assign(builder.toSQL(), profilerData))
-}
-
-/**
- * Ends the profiler action
- */
-function endProfilerAction (action: null | ProfilerActionContract, error?: any) {
- if (!action) {
- return
- }
-
- error ? action.end({ error }) : action.end()
-}
-
-/**
- * Returns a boolean telling if query builder or query client
- * is in transaction mode
- */
-export function isInTransaction (
- builder: knex.QueryBuilder | knex.Raw,
- client: QueryClientContract,
-) {
- if (client.isTransaction) {
- return true
- }
-
- return builder['client'].transacting
-}
-
-/**
- * Executes the knex query with an option to manually pull connection from
- * a dedicated knex client.
- */
-export async function executeQuery (
- builder: knex.QueryBuilder | knex.Raw,
- knexClient?: knex,
- profiler?: ProfilerRowContract | ProfilerContract,
- profilerData?: any,
-) {
- let action = getProfilerAction(builder, profiler, profilerData)
-
- if (!knexClient) {
- try {
- const result = await builder
- endProfilerAction(action)
- return result
- } catch (error) {
- endProfilerAction(action, error)
- throw error
- }
- }
-
- /**
- * Acquire connection from the client and set it as the
- * connection to be used for executing the query
- */
- const connection = await knexClient['acquireConnection']()
- builder.connection(connection)
-
- let queryError: any = null
- let queryResult: any = null
-
- /**
- * Executing the query and catching exceptions so that we can
- * dispose the connection before raising exception from this
- * method
- */
- try {
- queryResult = await builder
- endProfilerAction(action)
- } catch (error) {
- queryError = error
- endProfilerAction(action, error)
- }
-
- /**
- * Releasing the connection back to pool
- */
- knexClient['releaseConnection'](connection)
-
- /**
- * Re-throw if there was an exception
- */
- if (queryError) {
- throw queryError
- }
-
- /**
- * Return result
- */
- return queryResult
-}
+// /*
+// * @adonisjs/lucid
+// *
+// * (c) Harminder Virk
+// *
+// * For the full copyright and license information, please view the LICENSE
+// * file that was distributed with this source code.
+// */
+
+// ///
+
+// import * as knex from 'knex'
+// import { ProfilerRowContract, ProfilerContract } from '@poppinss/profiler'
+// import { ProfilerActionContract } from '@poppinss/profiler/build/src/Contracts'
+// import { QueryClientContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
+
+// /**
+// * Returns the profiler action for the SQL query. `null` is
+// * returned when profiler doesn't exists.
+// */
+// function getProfilerAction (
+// builder: knex.QueryBuilder | knex.Raw,
+// profiler?: ProfilerRowContract | ProfilerContract,
+// profilerData?: any,
+// ) {
+// if (!profiler) {
+// return null
+// }
+
+// return profiler.profile('sql:query', Object.assign(builder.toSQL(), profilerData))
+// }
+
+// /**
+// * Ends the profiler action
+// */
+// function endProfilerAction (action: null | ProfilerActionContract, error?: any) {
+// if (!action) {
+// return
+// }
+
+// error ? action.end({ error }) : action.end()
+// }
+
+// /**
+// * Returns a boolean telling if query builder or query client
+// * is in transaction mode
+// */
+// export function isInTransaction (
+// builder: knex.QueryBuilder | knex.Raw,
+// client: QueryClientContract,
+// ) {
+// if (client.isTransaction) {
+// return true
+// }
+
+// return builder['client'].transacting
+// }
+
+// /**
+// * Executes the knex query with an option to manually pull connection from
+// * a dedicated knex client.
+// */
+// export async function executeQuery (
+// builder: knex.QueryBuilder | knex.Raw,
+// knexClient?: knex,
+// profiler?: ProfilerRowContract | ProfilerContract,
+// profilerData?: any,
+// ) {
+// let action = getProfilerAction(builder, profiler, profilerData)
+
+// if (!knexClient) {
+// try {
+// const result = await builder
+// endProfilerAction(action)
+// return result
+// } catch (error) {
+// endProfilerAction(action, error)
+// throw error
+// }
+// }
+
+// /**
+// * Acquire connection from the client and set it as the
+// * connection to be used for executing the query
+// */
+// const connection = await knexClient['acquireConnection']()
+// builder.connection(connection)
+
+// let queryError: any = null
+// let queryResult: any = null
+
+// /**
+// * Executing the query and catching exceptions so that we can
+// * dispose the connection before raising exception from this
+// * method
+// */
+// try {
+// queryResult = await builder
+// endProfilerAction(action)
+// } catch (error) {
+// queryError = error
+// endProfilerAction(action, error)
+// }
+
+// /**
+// * Releasing the connection back to pool
+// */
+// knexClient['releaseConnection'](connection)
+
+// /**
+// * Re-throw if there was an exception
+// */
+// if (queryError) {
+// throw queryError
+// }
+
+// /**
+// * Return result
+// */
+// return queryResult
+// }
diff --git a/test-helpers/index.ts b/test-helpers/index.ts
index 58012830..03e27dfd 100644
--- a/test-helpers/index.ts
+++ b/test-helpers/index.ts
@@ -16,13 +16,16 @@ import { FakeLogger } from '@poppinss/logger'
import { Profiler } from '@poppinss/profiler'
import { Filesystem } from '@poppinss/dev-utils'
-import { ConnectionConfigContract } from '@ioc:Adonis/Addons/Database'
+import {
+ ConnectionConfigContract,
+ QueryClientContract,
+ ExcutableQueryBuilderContract,
+} from '@ioc:Adonis/Lucid/Database'
import {
RawContract,
InsertQueryBuilderContract,
DatabaseQueryBuilderContract,
- QueryClientContract,
-} from '@ioc:Adonis/Addons/DatabaseQueryBuilder'
+} from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'
import { RawQueryBuilder } from '../src/Database/QueryBuilder/Raw'
import { InsertQueryBuilder } from '../src/Database/QueryBuilder/Insert'
@@ -124,7 +127,7 @@ export function getQueryBuilder (client: QueryClientContract) {
return new DatabaseQueryBuilder(
client.getWriteClient().queryBuilder(),
client,
- ) as unknown as DatabaseQueryBuilderContract
+ ) as unknown as DatabaseQueryBuilderContract & ExcutableQueryBuilderContract
}
/**
@@ -135,7 +138,7 @@ export function getRawQueryBuilder (client: QueryClientContract, sql: string, bi
return new RawQueryBuilder(
bindings ? writeClient.raw(sql, bindings) : writeClient.raw(sql),
client,
- ) as unknown as RawContract
+ ) as unknown as RawContract & ExcutableQueryBuilderContract
}
/**
@@ -145,7 +148,7 @@ export function getInsertBuilder (client: QueryClientContract) {
return new InsertQueryBuilder(
client.getWriteClient().queryBuilder(),
client,
- ) as unknown as InsertQueryBuilderContract
+ ) as unknown as InsertQueryBuilderContract & ExcutableQueryBuilderContract
}
/**
diff --git a/test/connection.spec.ts b/test/connection.spec.ts
index d4f51538..21df5f11 100644
--- a/test/connection.spec.ts
+++ b/test/connection.spec.ts
@@ -10,7 +10,7 @@
///
import * as test from 'japa'
-import { MysqlConfigContract } from '@ioc:Adonis/Addons/Database'
+import { MysqlConfigContract } from '@ioc:Adonis/Lucid/Database'
import { Connection } from '../src/Connection'
import { getConfig, setup, cleanup, resetTables, getLogger } from '../test-helpers'
diff --git a/test/query-builder.spec.ts b/test/query-builder.spec.ts
index 69b640ed..ec3aa751 100644
--- a/test/query-builder.spec.ts
+++ b/test/query-builder.spec.ts
@@ -45,7 +45,7 @@ if (process.env.DB !== 'sqlite') {
}
db.select('*').from('users')
- db['_getQueryClient']()
+ db['getQueryClient']()
})
test('use write client for update', (assert) => {
@@ -61,7 +61,7 @@ if (process.env.DB !== 'sqlite') {
}
db.from('users').update('username', 'virk')
- db['_getQueryClient']()
+ db['getQueryClient']()
})
test('use write client for delete', (assert) => {
@@ -77,11 +77,10 @@ if (process.env.DB !== 'sqlite') {
}
db.from('users').del()
- db['_getQueryClient']()
+ db['getQueryClient']()
})
- test('use transaction client when query is used inside a transaction', async (assert) => {
- assert.plan(1)
+ test('use transaction client when query is used inside a transaction', async () => {
const connection = new Connection('primary', getConfig(), getLogger())
connection.connect()
const client = connection.getClient()
@@ -92,13 +91,11 @@ if (process.env.DB !== 'sqlite') {
}
const trx = await client.transaction()
- db.select('*').from('users').useTransaction(trx)
-
- assert.isUndefined(db['_getQueryClient']())
+ await db.select('*').from('users').useTransaction(trx).exec()
+ await trx.commit()
})
- test('use transaction client when insert query is used inside a transaction', async (assert) => {
- assert.plan(1)
+ test('use transaction client when insert query is used inside a transaction', async () => {
const connection = new Connection('primary', getConfig(), getLogger())
connection.connect()
const client = connection.getClient()
@@ -109,13 +106,11 @@ if (process.env.DB !== 'sqlite') {
}
const trx = await client.transaction()
- db.table('users').useTransaction(trx)
-
- assert.isUndefined(db['_getQueryClient']())
+ await db.table('users').useTransaction(trx).insert({ username: 'virk' }).exec()
+ await trx.rollback()
})
- test('use transaction client when query is issued from transaction client', async (assert) => {
- assert.plan(1)
+ test('use transaction client when query is issued from transaction client', async () => {
const connection = new Connection('primary', getConfig(), getLogger())
connection.connect()
const client = connection.getClient()
@@ -125,14 +120,11 @@ if (process.env.DB !== 'sqlite') {
}
const trx = await client.transaction()
- const db = trx.query()
-
- db.select('*').from('users')
- assert.isUndefined(db['_getQueryClient']())
+ await trx.query().select('*').from('users').exec()
+ await trx.commit()
})
- test('use transaction client when insert query is issued from transaction client', async (assert) => {
- assert.plan(1)
+ test('use transaction client when insert query is issued from transaction client', async () => {
const connection = new Connection('primary', getConfig(), getLogger())
connection.connect()
const client = connection.getClient()
@@ -142,10 +134,8 @@ if (process.env.DB !== 'sqlite') {
throw new Error('Never expected to reach here')
}
- const db = trx.insertQuery()
- db.table('users').useTransaction(trx)
-
- assert.isUndefined(db['_getQueryClient']())
+ await trx.insertQuery().table('users').insert({ username: 'virk' }).exec()
+ await trx.commit()
})
})
}
diff --git a/tsconfig.json b/tsconfig.json
index ff4e2734..77ab327f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,3 +1,6 @@
{
- "extends": "./node_modules/@adonisjs/mrm-preset/_tsconfig"
+ "extends": "./node_modules/@adonisjs/mrm-preset/_tsconfig",
+ "compilerOptions": {
+ "experimentalDecorators": true
+ }
}