From cbd9fc37482008bba0ec4c054d018d9799aa34b7 Mon Sep 17 00:00:00 2001 From: Harminder virk Date: Fri, 16 Aug 2019 10:23:56 +0530 Subject: [PATCH] feat: finish query builder with read/write support --- .env | 4 +- Dockerfile | 3 - adonis-typings/database.ts | 208 +++- adonis-typings/querybuilder.ts | 481 +++++--- index.ts | 141 --- package.json | 18 +- .../index.ts => Connection/Manager.ts} | 33 +- src/Connection/index.ts | 365 +++++- src/Database/index.ts | 88 -- src/InsertQueryBuilder/index.ts | 79 -- .../index.ts => QueryBuilder/Chainable.ts} | 131 ++- src/QueryBuilder/Database.ts | 277 +++++ src/QueryBuilder/Insert.ts | 149 +++ src/QueryBuilder/Raw.ts | 103 ++ src/RawQueryBuilder/index.ts | 31 - src/Transaction/index.ts | 131 +++ src/utils/index.ts | 58 + test-helpers/index.ts | 55 +- test/connection-manager.spec.ts | 18 +- test/connection.spec.ts | 183 ++- test/insert-query-builder.spec.ts | 20 +- test/query-builder.spec.ts | 1034 +++++++++-------- test/transactions.spec.ts | 100 ++ 23 files changed, 2505 insertions(+), 1205 deletions(-) rename src/{ConnectionManager/index.ts => Connection/Manager.ts} (82%) delete mode 100644 src/Database/index.ts delete mode 100644 src/InsertQueryBuilder/index.ts rename src/{BaseQueryBuilder/index.ts => QueryBuilder/Chainable.ts} (88%) create mode 100644 src/QueryBuilder/Database.ts create mode 100644 src/QueryBuilder/Insert.ts create mode 100644 src/QueryBuilder/Raw.ts delete mode 100644 src/RawQueryBuilder/index.ts create mode 100644 src/Transaction/index.ts create mode 100644 src/utils/index.ts create mode 100644 test/transactions.spec.ts diff --git a/.env b/.env index 31ad2276..c2504c93 100644 --- a/.env +++ b/.env @@ -1,12 +1,12 @@ DB=pg DB_NAME=lucid -MYSQL_HOST=0.0.0.0 +MYSQL_HOST=mysql MYSQL_PORT=3306 MYSQL_USER=virk MYSQL_PASSWORD=password -PG_HOST=0.0.0.0 +PG_HOST=pg PG_PORT=5432 PG_USER=virk PG_PASSWORD=password diff --git a/Dockerfile b/Dockerfile index 2b02858f..71a4f541 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,5 @@ WORKDIR /usr/src/app COPY package*.json ./ RUN npm install -RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O /wait-for-it.sh -RUN chmod +x /wait-for-it.sh - COPY . . RUN npm run build diff --git a/adonis-typings/database.ts b/adonis-typings/database.ts index b9e4e819..23ae8da6 100644 --- a/adonis-typings/database.ts +++ b/adonis-typings/database.ts @@ -10,22 +10,27 @@ /// declare module '@ioc:Adonis/Addons/Database' { - import * as knex from 'knex' import { Pool } from 'tarn' + import * as knex from 'knex' import { EventEmitter } from 'events' - import { DatabaseQueryBuilderContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' + import { + DatabaseQueryBuilderContract, + InsertQueryBuilderContract, + RawBuilderContract, + QueryClientContract, + } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' /** * Connection node used by majority of database * clients */ type SharedConnectionNode = { - host: string, - user: string, - password: string, - database: string, - port: number, + host?: string, + user?: string, + password?: string, + database?: string, + port?: number, } /** @@ -63,6 +68,7 @@ declare module '@ioc:Adonis/Addons/Database' { filename: string, mode?: any, }, + replicas?: never, } /** @@ -72,22 +78,34 @@ declare module '@ioc:Adonis/Addons/Database' { * Knex forwards all config options to the driver directly. So feel * free to define them (let us know, in case any options are missing) */ + type MysqlConnectionNode = { + socketPath?: string, + localAddress?: string, + charset?: string, + timezone?: string, + stringifyObjects?: boolean, + insecureAuth?: boolean, + typeCast?: boolean, + supportBigNumbers?: boolean, + bigNumberStrings?: boolean, + dateStrings?: boolean | string[], + flags?: string, + ssl?: any, + } + export type MysqlConfigContract = SharedConfigNode & { client: 'mysql', version?: string, - connection: SharedConnectionNode & { - socketPath?: string, - localAddress?: string, - charset?: string, - timezone?: string, - stringifyObjects?: boolean, - insecureAuth?: boolean, - typeCast?: boolean, - supportBigNumbers?: boolean, - bigNumberStrings?: boolean, - dateStrings?: boolean | string[], - flags?: string, - ssl?: any, + connection?: SharedConnectionNode & MysqlConnectionNode, + replicas?: { + write: { + connection: MysqlConfigContract['connection'], + pool?: MysqlConfigContract['pool'], + } + read: { + connection: MysqlConfigContract['connection'][], + pool?: MysqlConfigContract['pool'], + }, }, } @@ -116,7 +134,17 @@ declare module '@ioc:Adonis/Addons/Database' { client: 'pg' | 'postgres' | 'postgresql', version?: string, returning?: string, - connection: string | SharedConnectionNode, + connection?: string | SharedConnectionNode, + replicas?: { + write: { + connection: PostgreConfigContract['connection'], + pool?: PostgreConfigContract['pool'], + } + read: { + connection: PostgreConfigContract['connection'][], + pool?: PostgreConfigContract['pool'], + }, + }, searchPath?: string[], } @@ -139,18 +167,30 @@ declare module '@ioc:Adonis/Addons/Database' { * config values. * https://oracle.github.io/node-oracledb/doc/api.html#oracledbproperties */ + type OracleConnectionNode = { + autoCommit?: boolean, + connectionClass?: string, + edition?: string, + externalAuth?: boolean, + fetchArraySize?: number, + fetchAsBuffer?: any[], + lobPrefetchSize?: number, + maxRows?: number, + oracleClientVersion?: number, + } + export type OracleConfigContract = SharedConfigNode & { client: 'oracledb', - connection: SharedConnectionNode & { - autoCommit?: boolean, - connectionClass?: string, - edition?: string, - externalAuth?: boolean, - fetchArraySize?: number, - fetchAsBuffer?: any[], - lobPrefetchSize?: number, - maxRows?: number, - oracleClientVersion?: number, + connection?: SharedConnectionNode & OracleConnectionNode, + replicas?: { + write: { + connection: OracleConfigContract['connection'], + pool?: OracleConfigContract['pool'], + } + read: { + connection: OracleConfigContract['connection'][], + pool?: OracleConfigContract['pool'], + }, }, fetchAsString?: any[], } @@ -162,14 +202,26 @@ declare module '@ioc:Adonis/Addons/Database' { * Knex forwards all config options to the driver directly. So feel * free to define them (let us know, in case any options are missing) */ + type MssqlConnectionNode = { + domain?: string, + connectionTimeout?: number, + requestTimeout?: number, + parseJSON?: boolean, + } + export type MssqlConfigContract = SharedConfigNode & { client: 'mssql', version?: string, - connection: SharedConnectionNode & { - domain?: string, - connectionTimeout?: number, - requestTimeout?: number, - parseJSON?: boolean, + connection?: SharedConnectionNode & MssqlConnectionNode, + replicas?: { + write: { + connection: MssqlConfigContract['connection'], + pool?: MssqlConfigContract['pool'], + } + read: { + connection: MssqlConfigContract['connection'][], + pool?: MssqlConfigContract['pool'], + }, }, } @@ -206,19 +258,64 @@ declare module '@ioc:Adonis/Addons/Database' { * connections. */ export interface ConnectionManagerContract extends EventEmitter { + /** + * List of registered connection. You must check the connection state + * to understand, if it is connected or not + */ connections: Map - on (event: 'connect', callback: (connection: ConnectionContract) => void) - on (event: 'disconnect', callback: (connection: ConnectionContract) => void) + /** + * Everytime a connection is created + */ + on (event: 'connect', callback: (connection: ConnectionContract) => void): this + /** + * Everytime a connection leaves + */ + on (event: 'disconnect', callback: (connection: ConnectionContract) => void): this + + /** + * Add a new connection to the list of managed connection. You must call + * connect seperately to instantiate a connection instance + */ add (connectionName: string, config: ConnectionConfigContract): void + + /** + * Instantiate a connection. It is a noop, when connection for the given + * name is already instantiated + */ connect (connectionName: string): void + + /** + * Get connection node + */ get (connectionName: string): ConnectionManagerConnectionNode | undefined + + /** + * Find if a connection name is managed by the manager or not + */ has (connectionName: string): boolean + + /** + * Find if a managed connection is instantiated or not + */ isConnected (connectionName: string): boolean + /** + * Close a given connection. This is also kill the underlying knex connection + * pool + */ close (connectionName: string, release?: boolean): Promise + + /** + * Close all managed connections + */ closeAll (release?: boolean): Promise + + /** + * Release a given connection. Releasing a connection means, you will have to + * re-add it using the `add` method + */ release (connectionName: string): Promise } @@ -226,26 +323,39 @@ declare module '@ioc:Adonis/Addons/Database' { * Connection represents a single knex instance with inbuilt * pooling capabilities. */ - export interface ConnectionContract extends EventEmitter { - client?: knex, + export interface ConnectionContract extends EventEmitter, QueryClientContract { + /** + * Read/write connection pools + */ pool: null | Pool, + readPool: null | Pool, + + /** + * Name of the connection + */ name: string, + + /** + * Untouched config + */ config: ConnectionConfigContract, /** * List of emitted events */ - on (event: 'connect', callback: (connection: ConnectionContract) => void) - on (event: 'error', callback: (connection: ConnectionContract, error: Error) => void) - on (event: 'disconnect', callback: (connection: ConnectionContract) => void) - on (event: 'disconnect:error', callback: (connection: ConnectionContract, error: Error) => void) + on (event: 'connect', callback: (connection: ConnectionContract) => void): this + on (event: 'error', callback: (connection: ConnectionContract, error: Error) => void): this + on (event: 'disconnect', callback: (connection: ConnectionContract) => void): this + on (event: 'disconnect:error', callback: (connection: ConnectionContract, error: Error) => void): this + /** + * Make knex connection + */ connect (): void, - disconnect (): Promise, - } - export interface DatabaseContract { - query (): DatabaseQueryBuilderContract, - from: DatabaseQueryBuilderContract['from'], + /** + * Disconnect knex + */ + disconnect (): Promise, } } diff --git a/adonis-typings/querybuilder.ts b/adonis-typings/querybuilder.ts index a506b887..cd71848e 100644 --- a/adonis-typings/querybuilder.ts +++ b/adonis-typings/querybuilder.ts @@ -8,14 +8,27 @@ */ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { + import * as knex from 'knex' import { Dictionary } from 'ts-essentials' - import { JoinCallback, Sql, Raw } from 'knex' - export interface Registery { + /** + * The types for values for the aggregates. We need this coz of + * the history with bigints in Javascript + */ + export interface AggregatesRegistry { Count: number, } - type OneOrMany = T | T[] + /** + * Get one or many of a generic + */ + type OneOrMany = T | T[] + + /** + * Allowing a generic value along with raw query instance or a subquery + * instance + */ + type ValueWithSubQueries = T | ChainableContract | RawContract /** * A known set of values allowed when defining values for different @@ -34,22 +47,8 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { | RawContract /** - * Allowing a generic value along with raw query instance or a subquery - * instance - */ - type ValueWithSubQueries = T | ChainableContract | RawContract - - /** - * Shape of raw query instance - */ - interface RawContract { - wrap (before: string, after: string): this - toQuery (): string - toSQL (): Sql - } - - /** - * Shape of raw query builder + * Shape of raw query builder. The builder is a method used to build + * raw queries. */ interface RawBuilderContract { (sql: string): RawContract @@ -58,8 +57,8 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { } /** - * Shape of raw query builder. The different is, it will return - * the existing query builder chain instead of `RawContract` + * 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 { (sql: string): Builder @@ -69,56 +68,61 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { } /** - * Query callback is used to write wrapped queries. + * Query callback is used to write wrapped queries. We get rid of `this` from + * knex, since it makes everything confusing. */ type QueryCallback = ( (builder: Builder) => void ) /** - * Possible signatures for a select method on database query builder. - * The models query builder may have a different signature all - * together. + * Possible signatures for a select method on database query builder. The select narrows the result + * based upon many factors. + * + * 1. select(*) uses the main result generic. Which means everything is returned. + * 2. select(columns) narrows the result set to explicitly defined keys. + * 3. Calling `select(columns)` for multiple times appends to the explicit result set. + * 4. Calling `select(*)` after named selects will append all columns to the named columns. + * 5. Aliases defined as object will return typed output. */ interface DatabaseQueryBuilderSelect< - Record extends Dictionary, - Result extends any = Record + Builder extends ChainableContract, + Record extends Dictionary, > { /** * Selecting named columns as array */ - (columns: K[]): DatabaseQueryBuilderContract + (columns: K[]): Builder /** * Selecting named columns as spread */ - (...columns: K[]): DatabaseQueryBuilderContract + (...columns: K[]): Builder /** * Selecting columns as a dictionary with key as the alias and value is * the original column. When aliases are defined, the return output * will have the alias columns and not the original one's */ - > ( - columns: Columns, - ): DatabaseQueryBuilderContract + (columns: Dictionary): Builder /** * String fallback when columns to be selected aren't derived from * record. Here we allow subqueries, raw queries or an array * of strings. */ - (columns: (string | ChainableContract | RawContract)[]): DatabaseQueryBuilderContract + (columns: ValueWithSubQueries[]): Builder /** * Selecting columns as spread */ - (...columns: (string | ChainableContract | RawContract)[]): DatabaseQueryBuilderContract + (...columns: ValueWithSubQueries[]): Builder /** - * Wildcard selector + * Wildcard selector. Fallback to original `Result` type, since we are + * selecting everything. */ - (column: '*'): DatabaseQueryBuilderContract + (column: '*'): Builder } /** @@ -126,7 +130,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface Where< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * Callback for wrapped clauses @@ -155,6 +159,12 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { operator: string, value: ValueWithSubQueries, ): Builder + + /** + * Accepting any string as a key for supporting `dot` aliases + */ + (key: string, value: StrictValues | ChainableContract): Builder + (key: string, operator: string, value: StrictValues | ChainableContract): Builder } /** @@ -162,7 +172,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface WhereIn< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * A named column as the key and an array of values including a literal @@ -177,13 +187,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { * A named column as the key along with a sub query. The subquery must yield * an array of values to be valid at runtime */ - (key: K, subquery: ChainableContract): Builder - - /** - * A named column as the key along with a query callback. The query callback - * must yield an array of values to be valid at runtime. - */ - (key: K, callback: QueryCallback): Builder + (key: K, value: ChainableContract | QueryCallback): Builder /** * Accepting multiple columns and 2d array of values. The values must be @@ -239,6 +243,15 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { * Typed array of columns, with untyped values */ (key: K[], value: (StrictValues | ChainableContract)[][]): Builder + + /** + * Allowing any string key (mainly for prefixed columns) with all + * possible values + */ + (K: string, value: (StrictValues | ChainableContract)[]): Builder + (K: string[], value: (StrictValues | ChainableContract)[][]): Builder + (k: string, subquery: ChainableContract | QueryCallback): Builder + (k: string[], subquery: ChainableContract): Builder } /** @@ -246,9 +259,10 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface WhereNull< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { (key: K): Builder + (key: string): Builder } /** @@ -263,7 +277,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface WhereBetween< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * Typed column with an tuple of a literal value, a raw query or @@ -273,12 +287,14 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { ValueWithSubQueries, ValueWithSubQueries, ]): Builder - } - /** - * Possibles signatures for a raw where clause. - */ - interface WhereRaw extends RawQueryBuilderContract { + /** + * Accept any string as a key for supporting prefix columns + */ + (key: string, value: [ + StrictValues | ChainableContract, + StrictValues | ChainableContract, + ]): Builder } /** @@ -307,13 +323,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { * Join with a callback. The callback receives an array of join class from * knex directly. */ - (table: string, callback: JoinCallback): Builder - } - - /** - * Possible signatures for a raw join - */ - interface JoinRaw extends RawQueryBuilderContract { + (table: string, callback: knex.JoinCallback): Builder } /** @@ -321,7 +331,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface Distinct< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * Named keys @@ -355,23 +365,17 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface GroupBy< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > extends Distinct { } /** - * GroupByRaw is same as `RawQueryBuilderContract` - */ - interface GroupByRaw extends RawQueryBuilderContract { - } - - /** - * Possible signatures for aggregate functions. It will append - * to the pre existing result + * Possible signatures for aggregate functions. Aggregates will push to the + * result set. Unlike knex, we force defining aliases for each aggregate. */ interface Aggregate < - Record extends Dictionary, - Result extends any = Record, + Record extends Dictionary, + Result extends any, > { /** * Accepting a typed column with the alias for the count. Unlike knex @@ -381,7 +385,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { ( column: OneOrMany, alias: Alias, - ): DatabaseQueryBuilderContract)> + ): DatabaseQueryBuilderContract> /** * Accepting an object for multiple counts in a single query. Again @@ -393,7 +397,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { Columns extends Dictionary, Alias>, >( columns: Columns, - ): DatabaseQueryBuilderContract + ): DatabaseQueryBuilderContract /** * Accepting an un typed column with the alias for the count. @@ -401,7 +405,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { ( column: OneOrMany>, alias: Alias, - ): DatabaseQueryBuilderContract)> + ): DatabaseQueryBuilderContract> /** * Accepting an object for multiple counts in a single query. Again @@ -412,7 +416,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { Columns extends Dictionary>, Alias>, >( columns: Columns, - ): DatabaseQueryBuilderContract + ): DatabaseQueryBuilderContract } /** @@ -420,7 +424,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface OrderBy< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * Order by a named column and optional direction @@ -453,12 +457,6 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { (columns: { column: string, order?: 'asc' | 'desc' }[]): Builder } - /** - * OrderByRaw is same as RawQueryBuilderContract - */ - interface OrderByRaw extends RawQueryBuilderContract { - } - /** * Possible signatures for a union clause */ @@ -499,8 +497,8 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface Having< Builder extends ChainableContract, - Record extends Dictionary, - > extends RawQueryBuilderContract { + Record extends Dictionary, + > { /** * A subquery callback */ @@ -535,7 +533,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface HavingIn< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * A typed key, along with an array of literal values, a raw queries or @@ -560,12 +558,8 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface HavingNull< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > extends WhereNull { - /** - * Supporting untyped keys, since having clause can refer alias columns as well. - */ - (key: string): Builder } /** @@ -583,7 +577,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { */ interface HavingBetween< Builder extends ChainableContract, - Record extends Dictionary, + Record extends Dictionary, > { /** * A typed key, along with a tuple of literal values, raw queries or @@ -605,9 +599,10 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { } /** - * Possibles signatures for a raw where clause. + * Possible signatures of `with` CTE */ - interface HavingRaw extends RawQueryBuilderContract { + interface With { + (alias: string, query: RawContract | ChainableContract): Builder } /** @@ -618,20 +613,95 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { (table: Dictionary): Builder } + /** + * Possible signatures for defining table for a select query. A query + * callback is allowed for select queries for computing a value + * from a subquery + */ + interface SelectTable extends Table { + (callback: QueryCallback): Builder + } + + /** + * Possible signatures for the `returning` method. + */ + interface Returning< + Builder, + Record extends Dictionary + > { + /** + * Mark return columns as a single array of value type for the given + * key + */ + (column: K): Builder + + /** + * Mark return columns as an array of key/value pair with correct types. + */ + (columns: K[]): Builder + } + /** * Possible signatures for performing an update */ - interface Update { + interface Update< + Builder extends ChainableContract, + Record extends Dictionary + > { /** * Accepts an array of object of named key/value pair and returns an array * of Generic return columns. */ - (values: { [P in K]: Record[P] }): Promise + (values: { [P in K]: Record[P] }): Builder /** * Accepts a key/value pair to update. */ - (column: K, value: Record[K]): Promise + (column: K, value: Record[K]): Builder + } + + /** + * Possible signatures for incrementing/decrementing + * values + */ + interface Counter< + Builder extends ChainableContract, + Record extends Dictionary + > { + (column: K, counter?: number): Builder + (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 + */ + interface Insert< + Builder extends InsertQueryBuilderContract, + Record extends Dictionary + > { + (values: { [P in K]: Record[P] }): Builder + } + + /** + * Possible signatures for doing multiple inserts in a single query + */ + interface MultiInsert< + Builder extends InsertQueryBuilderContract, + Record extends Dictionary + > { + (values: { [P in K]: Record[P] }[]): Builder } /** @@ -640,9 +710,9 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { * methods to execute a query. */ export interface ChainableContract < - Record extends Dictionary = Dictionary, + Record extends Dictionary = Dictionary, > { - from: Table + from: SelectTable where: Where orWhere: Where @@ -684,9 +754,9 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { orWhereNotBetween: WhereBetween andWhereNotBetween: WhereBetween - whereRaw: WhereRaw - orWhereRaw: WhereRaw - andWhereRaw: WhereRaw + whereRaw: RawQueryBuilderContract + orWhereRaw: RawQueryBuilderContract + andWhereRaw: RawQueryBuilderContract join: Join innerJoin: Join @@ -696,7 +766,7 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { rightOuterJoin: Join fullOuterJoin: Join crossJoin: Join - joinRaw: JoinRaw + joinRaw: RawQueryBuilderContract having: Having orHaving: Having @@ -734,23 +804,29 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { orHavingNotBetween: HavingBetween andHavingNotBetween: HavingBetween - havingRaw: HavingRaw - orHavingRaw: HavingRaw - andHavingRaw: HavingRaw + havingRaw: RawQueryBuilderContract + orHavingRaw: RawQueryBuilderContract + andHavingRaw: RawQueryBuilderContract distinct: Distinct groupBy: GroupBy - groupByRaw: GroupByRaw + groupByRaw: RawQueryBuilderContract orderBy: OrderBy - orderByRaw: OrderByRaw + orderByRaw: RawQueryBuilderContract union: Union unionAll: UnionAll intersect: Intersect + with: With, + withRecursive: With, + + withSchema (schema: string): this, + as (name: string): this + offset (offset: number): this limit (limit: number): this @@ -764,9 +840,6 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { skipLocked (): this noWait (): this - - toSQL (): Sql - toString (): string } /** @@ -774,123 +847,161 @@ declare module '@ioc:Adonis/Addons/DatabaseQueryBuilder' { * query builder and Model query builder will behave differently. */ export interface DatabaseQueryBuilderContract < - Record extends Dictionary = Dictionary, + Record extends Dictionary = Dictionary, Result extends any = Record, - > extends ChainableContract, Promise { - select: DatabaseQueryBuilderSelect, + > extends ChainableContract, ExcutableQueryBuilderContract { + select: DatabaseQueryBuilderSelect + + /** + * Aggregates + */ + count: Aggregate + countDistinct: Aggregate + min: Aggregate + max: Aggregate + sum: Aggregate + avg: Aggregate + avgDistinct: Aggregate - count: Aggregate, - countDistinct: Aggregate, - min: Aggregate, - max: Aggregate, - sum: Aggregate, - avg: Aggregate, - avgDistinct: Aggregate, + returning: Returning + update: Update + increment: Counter + decrement: Counter + del (): this /** - * Returns the first row + * Clone current query */ - first (): Result + clone< + ClonedRecord extends Dictionary = Record, + ClonedResult = Result, + > (): DatabaseQueryBuilderContract + + /** + * Execute and get first result + */ + first (): Promise } /** - * Possible signatures for the `returning` method when called on - * the insert query builder. + * Insert query builder to perform database inserts */ - interface InsertReturning> { + export interface InsertQueryBuilderContract< + Record extends Dictionary = Dictionary, + ReturnColumns extends any[] = any[] + > extends ExcutableQueryBuilderContract { /** - * Mark return columns as a single array of value type for the given - * key + * Table for the insert query */ - ( - column: K, - ): InsertQueryBuilderContract + table: Table /** - * Mark return columns as an array of key/value pair with correct types. + * Define returning columns */ - ( - columns: K[], - ): InsertQueryBuilderContract - } + returning: Returning - /** - * Possible signatures for an insert query - */ - interface Insert< - Record extends Dictionary, - ReturnColumns extends any[] - > { /** - * Defers the `insert` to `exec` method + * Inserting a single record. */ - ( - columns: { [P in K]: Record[P] }, - defer: true, - ): InsertQueryBuilderContract + insert: Insert /** - * Performs the insert right away when defer is not defined or is set to false + * Inserting multiple columns at once */ - (columns: { [P in K]: Record[P] }, defer?: boolean): Promise + multiInsert: MultiInsert } /** - * Possible signatures for doing multiple inserts in a single query + * Shape of raw query instance */ - interface MultiInsert< - Record extends Dictionary, - ReturnColumns extends any[] - > { + 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 { /** - * Defers the `insert` to `exec` method + * Tells if client is a transaction client or not */ - ( - values: { [P in K]: Record[P] }[], - defer: true, - ): InsertQueryBuilderContract + isTransaction: boolean /** - * Accepts an array of object of named key/value pair and returns an array - * of Generic return columns. + * The database dialect in use */ - (values: { [P in K]: Record[P] }[], defer?: boolean): Promise - } + dialect: string - /** - * Insert query builder can be obtained by specifying return columns - * using `returning` method - */ - export interface InsertQueryBuilderContract < - Record extends Dictionary = Dictionary, - ReturnColumns extends any[] = number[] - > { - table: Table + /** + * Returns the read and write clients + */ + getReadClient (): knex | knex.Transaction + getWriteClient (): knex | knex.Transaction /** - * Define returning columns + * Get new query builder instance for select, update and + * delete calls */ - returning: InsertReturning + query (): DatabaseQueryBuilderContract, /** - * Inserting a single record. + * Get new query builder instance inserts */ - insert: Insert + insertQuery (): InsertQueryBuilderContract, /** - * In single insert, we always know that one item inside an array is returned, so - * instead of using `val[]`, we make use of `[val]`. However, in `multiInsert`, - * we need the `val[]`. So that's why, we pick the insert item of the - * `ReturnColumns` and return an array of it. COMPLEX 🤷 + * Get raw query builder instance */ - multiInsert: MultiInsert + raw: RawBuilderContract, /** - * Execute the insert + * Truncate a given table */ - exec (): Promise + truncate (table: string): Promise, - toSQL (): Sql - toString (): string + /** + * 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/index.ts b/index.ts index 28f22d70..e69de29b 100644 --- a/index.ts +++ b/index.ts @@ -1,141 +0,0 @@ -// import * as Knex from 'knex' -// // // import { join } from 'path' -// import { DatabaseQueryBuilderContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' - -// const knex = Knex({ -// client: 'pg', -// connection: { -// host: '0.0.0.0', -// user: 'virk', -// password: '', -// database: 'directory-service', -// }, -// pool: { -// min: 0, -// max: 5, -// idleTimeoutMillis: 30000, -// }, -// useNullAsDefault: true, -// }) - -// knex() -// .from('foo') -// .havingIn('f', ['a']) - -// // // let i = 0; -// // knex['_context'].client.pool.on('destroySuccess', _eventId => { -// // // i++ -// // console.log( -// // knex['_context'].client.pool.numUsed(), -// // knex['_context'].client.pool.numFree(), -// // knex['_context'].client.pool.numPendingAcquires(), -// // ) - -// // // if (i === 3) { -// // // knex['_context'].client.pool.destroy() -// // // } -// // }); - -// // knex['_context'].client.pool.on('poolDestroySuccess', _resource => { -// // console.log('poolDestroySuccess>>>') -// // }); - -// // // setInterval(() => { -// // // console.log('ping') -// // // }, 1000) - -// // // type User = { -// // // id: number, -// // // } - -// // // console.log(knex.raw(['10']).toQuery()) - -// // // knex.schema.createTable('users', (table) => { -// // // table.increments('id') -// // // table.string('username') -// // // table.integer('age') -// // // table.timestamps() -// // // }).then(() => console.log('created')) - -// // // knex.table('users').insert([ -// // // { username: 'virk', age: 29 }, { username: 'nikk', age: 28 }, { username: 'prasan', age: 29 }, -// // // ]).then(console.log) - -// // Promise.all([ -// // knex -// // .select('*') -// // .from('users') -// // .debug(true) -// // .then((result) => { -// // console.log(result) -// // }), -// // knex -// // .select('*') -// // .from('users') -// // .debug(true) -// // .then((result) => { -// // console.log(result) -// // }), -// // knex -// // .select('*') -// // .from('users') -// // .debug(true) -// // .then((result) => { -// // console.log(result) -// // }), -// // knex -// // .select('*') -// // .from('users') -// // .debug(true) -// // .then((result) => { -// // console.log(result) -// // }), -// // knex -// // .select('*') -// // .from('users') -// // .debug(true) -// // .then((result) => { -// // console.log(result) -// // }), -// // ]).then(() => { -// // }) - -// // // knex.transaction().then((trx) => { -// // // }) - -// // // console.log(query.toSQL()) - -// // // type FilteredKeys = { [P in keyof T]: T[P] extends Function ? never : P }[keyof T] - -// // // type GetRefs = T['refs'] extends object ? { -// // // [P in keyof T['refs']]: InstanceType[P] -// // // } : { -// // // [P in FilteredKeys>]: InstanceType[P] -// // // } - -// // // class BaseModel { -// // // public static refs: unknown - -// // // public static query ( -// // // this: T, -// // // ): DatabaseQueryBuilderContract, InstanceType> { -// // // return {} as DatabaseQueryBuilderContract, InstanceType> -// // // } -// // // } - -// // // class User extends BaseModel { -// // // public username: string -// // // public age: number - -// // // public castToInt (): number { -// // // return 22 -// // // } -// // // } - -// // // class Post extends BaseModel { -// // // } - -// const foo: DatabaseQueryBuilderContract<{ username: string, age: number, email: string }> = {} -// foo.whereIn(['username', 'age', 'email'], [ -// ['foo', 22, 'a'], ['bar', 22, 'a'], ['virk', 22, 'a'], -// ]) diff --git a/package.json b/package.json index bd0bd21e..93a2d62f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "test:mysql": "DB=mysql node japaFile.js", "test:pg": "DB=pg node japaFile.js", "test:docker": "npm run test:sqlite && npm run test:mysql && npm run test:pg", - "test": "docker-compose build && docker-compose run --rm test", + "test": "docker-compose -f docker-compose.yml -f docker-compose-test.yml build && docker-compose -f docker-compose.yml -f docker-compose-test.yml run --rm test", "prepublishOnly": "npm run build", "lint": "tslint --project tsconfig.json", "clean": "del build", @@ -28,26 +28,28 @@ }, "homepage": "https://github.com/adonisjs/adonis-lucid#readme", "dependencies": { + "@poppinss/logger": "^1.1.2", "@poppinss/utils": "^1.0.4", "knex": "^0.19.1", - "ts-essentials": "^3.0.0" + "knex-dynamic-connection": "^1.0.0", + "ts-essentials": "^3.0.1" }, "devDependencies": { "@adonisjs/mrm-preset": "^2.0.3", "@poppinss/dev-utils": "^1.0.0", "@types/dotenv": "^6.1.1", - "@types/node": "^12.6.9", + "@types/node": "^12.7.1", "clone": "^2.1.2", "commitizen": "^4.0.3", "cz-conventional-changelog": "^3.0.2", "del-cli": "^2.0.0", "doctoc": "^1.4.0", "dotenv": "^8.0.0", - "husky": "^3.0.2", + "husky": "^3.0.3", "japa": "^2.0.10", "mrm": "^1.2.2", "mysql": "^2.17.1", - "pg": "^7.12.0", + "pg": "^7.12.1", "pkg-ok": "^2.3.1", "sqlite3": "^4.0.9", "ts-node": "^8.3.0", @@ -83,5 +85,9 @@ "commitizen": { "path": "cz-conventional-changelog" } - } + }, + "directories": { + "test": "test" + }, + "keywords": [] } diff --git a/src/ConnectionManager/index.ts b/src/Connection/Manager.ts similarity index 82% rename from src/ConnectionManager/index.ts rename to src/Connection/Manager.ts index 8afb788a..99921a57 100644 --- a/src/ConnectionManager/index.ts +++ b/src/Connection/Manager.ts @@ -11,6 +11,7 @@ import { EventEmitter } from 'events' import { Exception } from '@poppinss/utils' +import { LoggerContract } from '@poppinss/logger' import { ConnectionConfigContract, @@ -18,16 +19,20 @@ import { ConnectionManagerContract, } from '@ioc:Adonis/Addons/Database' -import { Connection } from '../Connection' +import { Connection } from './index' /** - * Connection class manages a given database connection. Internally it uses - * knex to build the database connection with appropriate database - * driver. + * Connection manager job is to manage multiple named connections. You can add any number + * or connections by registering their config only once and then make use of `connect` + * and `close` methods to create and destroy db connections. */ export class ConnectionManager extends EventEmitter implements ConnectionManagerContract { public connections: ConnectionManagerContract['connections'] = new Map() + constructor (private _logger: LoggerContract) { + super() + } + /** * Monitors a given connection by listening for lifecycle events */ @@ -48,6 +53,8 @@ export class ConnectionManager extends EventEmitter implements ConnectionManager } this.emit('disconnect', $connection) + this._logger.trace({ connection: internalConnection.name }, 'disconnecting connection inside manager') + delete internalConnection.connection internalConnection.state = 'closed' }) @@ -88,6 +95,7 @@ export class ConnectionManager extends EventEmitter implements ConnectionManager ) } + this._logger.trace({ connection: connectionName }, 'adding new connection to the manager') this.connections.set(connectionName, { name: connectionName, config: config, @@ -104,22 +112,21 @@ export class ConnectionManager extends EventEmitter implements ConnectionManager throw new Exception( `Cannot connect to unregisted connection ${connectionName}`, 500, - 'E_MISSING_DB_CONNECTION_CONFIG', + 'E_UNMANAGED_DB_CONNECTION', ) } /** - * Do not do anything when `connection` property already exists, since it will - * always be set to `undefined` for a closed connection + * Ignore when the there is already a connection. */ - if (connection.connection) { + if (this.isConnected(connection.name)) { return } /** * Create a new connection and monitor it's state */ - connection.connection = new Connection(connection.name, connection.config) + connection.connection = new Connection(connection.name, connection.config, this._logger) this._monitorConnection(connection.connection) connection.connection.connect() } @@ -157,13 +164,13 @@ export class ConnectionManager extends EventEmitter implements ConnectionManager * Closes a given connection and can optionally release it from the * tracking list */ - public async close (connectioName: string, release: boolean = false) { - if (this.isConnected(connectioName)) { - await this.get(connectioName)!.connection!.disconnect() + public async close (connectionName: string, release: boolean = false) { + if (this.isConnected(connectionName)) { + await this.get(connectionName)!.connection!.disconnect() } if (release) { - await this.release(connectioName) + await this.release(connectionName) } } diff --git a/src/Connection/index.ts b/src/Connection/index.ts index b54f3ce5..4fb38ddf 100644 --- a/src/Connection/index.ts +++ b/src/Connection/index.ts @@ -12,8 +12,25 @@ import { Pool } from 'tarn' import * as knex from 'knex' import { EventEmitter } from 'events' +import { Exception } from '@poppinss/utils' +import { LoggerContract } from '@poppinss/logger' +import { patchKnex } from 'knex-dynamic-connection' +import { resolveClientNameWithAliases } from 'knex/lib/helpers' + import { ConnectionConfigContract, ConnectionContract } from '@ioc:Adonis/Addons/Database' +import { + DatabaseQueryBuilderContract, + RawContract, + InsertQueryBuilderContract, + TransactionClientContract, +} from '@ioc:Adonis/Addons/DatabaseQueryBuilder' + +import { Transaction } from '../Transaction' +import { RawQueryBuilder } from '../QueryBuilder/Raw' +import { InsertQueryBuilder } from '../QueryBuilder/Insert' +import { DatabaseQueryBuilder } from '../QueryBuilder/Database' + /** * Connection class manages a given database connection. Internally it uses * knex to build the database connection with appropriate database @@ -24,43 +41,251 @@ export class Connection extends EventEmitter implements ConnectionContract { * Reference to knex. The instance is created once the `open` * method is invoked */ - public client?: knex + private _client?: knex + + /** + * Read client when read/write replicas are defined in the config, otherwise + * it is a reference to the `client`. + */ + private _readClient?: knex - constructor (public name: string, public config: ConnectionConfigContract) { + /** + * Not a transaction client + */ + public isTransaction = false + + /** + * The name of the dialect in use + */ + public dialect = resolveClientNameWithAliases(this.config.client) + + /** + * Config for one or more read replicas. Only exists, when replicas are + * defined + */ + private _readReplicas: any[] = [] + + /** + * The round robin counter for reading config + */ + private _roundRobinCounter = 0 + + constructor ( + public name: string, + public config: ConnectionConfigContract, + private _logger: LoggerContract, + ) { super() + this._validateConfig() } /** - * Does cleanup by removing knex reference and removing - * all listeners + * Raises exception when client or readClient are not defined */ - private _monitorPoolResources () { - this.pool!.on('destroySuccess', () => { - /** - * Force close when `numUsed` and `numFree` both are zero. This happens - * when `min` resources inside the pool are set to `0`. - */ - if (this.pool!.numFree() === 0 && this.pool!.numUsed() === 0) { - this.disconnect() + private _ensureClients () { + if (!this._client || !this._readClient) { + throw new Exception('Connection is not in ready state. Make sure to call .connect first') + } + } + + /** + * Validates the config to ensure that read/write replicas are defined + * properly. + */ + private _validateConfig () { + if (this.config.replicas) { + if (!this.config.replicas.read || !this.config.replicas.write) { + throw new Exception( + 'Make sure to define read/write replicas or use connection property', + 500, + 'E_INCOMPLETE_REPLICAS_CONFIG', + ) } - }) + if (!this.config.replicas.read.connection || !this.config.replicas.read.connection) { + throw new Exception( + 'Make sure to define connection property inside read/write replicas', + 500, + 'E_INVALID_REPLICAS_CONFIG', + ) + } + } + } + + /** + * Cleanup references + */ + private _cleanup () { + this._client = undefined + this._readClient = undefined + this._readReplicas = [] + } + + /** + * Does cleanup by removing knex reference and removing all listeners. + * For the same of simplicity, we get rid of both read and write + * clients, when anyone of them disconnects. + */ + private _monitorPoolResources () { /** * Pool has destroyed and hence we must cleanup resources * as well. */ this.pool!.on('poolDestroySuccess', () => { - this.client = undefined + this._logger.trace({ connection: this.name }, 'pool destroyed, cleaning up resource') + this._cleanup() this.emit('disconnect', this) this.removeAllListeners() }) + + if (this.readPool !== this.pool) { + this._logger.trace({ connection: this.name }, 'pool destroyed, cleaning up resource') + this.readPool!.on('poolDestroySuccess', () => { + this._cleanup() + this.emit('disconnect', this) + this.removeAllListeners() + }) + } + } + + /** + * Returns a boolean telling if config has read/write + * connection settings vs a single connection + * object. + */ + private _hasReadWriteReplicas (): boolean { + return !!(this.config.replicas && this.config.replicas.read && this.config.replicas.write) + } + + /** + * Returns normalized config object for write replica to be + * used by knex + */ + private _getWriteConfig (): knex.Config { + if (!this.config.replicas) { + return this.config + } + + const { replicas, ...config } = this.config + + /** + * Give preference to the replica write connection when and merge values from + * the main connection object when defined. + */ + if (typeof (replicas.write.connection) === 'string' || typeof (config.connection) === 'string') { + config.connection = replicas.write.connection + } else { + config.connection = Object.assign({}, config.connection, replicas.write.connection) + } + + /** + * Add pool to the config when pool config defined on main connection + * or the write replica + */ + if (config.pool || replicas.write.pool) { + config.pool = Object.assign({}, config.pool, replicas.write.pool) + } + + return config as knex.Config + } + + /** + * Returns the config for read replicas. + */ + private _getReadConfig (): knex.Config { + if (!this.config.replicas) { + return this.config + } + + const { replicas, ...config } = this.config + + /** + * Reading replicas and storing them as a reference, so that we + * can pick a config from replicas as round robin. + */ + this._readReplicas = (replicas.read.connection as Array).map((one) => { + if (typeof (one) === 'string' || typeof (config.connection) === 'string') { + return one + } else { + return Object.assign({}, config.connection, one) + } + }) + + /** + * Add database property on the main connection, since knexjs needs it + * internally + */ + config.connection = { + database: this._readReplicas[0].database, + } + + /** + * Add pool to the config when pool config defined on main connection + * or the read replica + */ + if (config.pool || replicas.read.pool) { + config.pool = Object.assign({}, config.pool, replicas.read.pool) + } + + return config as knex.Config + } + + /** + * Resolves connection config for the writer connection + */ + private _writeConfigResolver (originalConfig: ConnectionConfigContract) { + return originalConfig.connection + } + + /** + * Resolves connection config for the reader connection + */ + private _readConfigResolver (originalConfig: ConnectionConfigContract) { + if (!this._readReplicas.length) { + return originalConfig.connection + } + + const index = this._roundRobinCounter++ % this._readReplicas.length + this._logger.trace({ connection: this.name }, `round robin using host at ${index} index`) + return this._readReplicas[index] + } + + /** + * Creates the write connection + */ + private _setupWriteConnection () { + this._client = knex(this._getWriteConfig()) + patchKnex(this._client, this._writeConfigResolver.bind(this)) + } + + /** + * Creates the read connection. If there aren't any replicas in use, then + * it will use reference the write client + */ + private _setupReadConnection () { + if (!this._hasReadWriteReplicas()) { + this._readClient = this._client + return + } + + this._logger.trace({ connection: this.name }, 'setting up read/write replicas') + this._readClient = knex(this._getReadConfig()) + patchKnex(this._readClient, this._readConfigResolver.bind(this)) } /** * Returns the pool instance for the given connection */ public get pool (): null | Pool { - return this.client ? this.client['_context'].client.pool : null + return this._client ? this._client.client.pool : null + } + + /** + * Returns the pool instance for the read connection. When replicas are + * not in use, then read/write pools are same. + */ + public get readPool (): null | Pool { + return this._readClient ? this._readClient.client.pool : null } /** @@ -68,7 +293,8 @@ export class Connection extends EventEmitter implements ConnectionContract { */ public connect () { try { - this.client = knex(this.config) + this._setupWriteConnection() + this._setupReadConnection() this._monitorPoolResources() this.emit('connect', this) } catch (error) { @@ -85,12 +311,115 @@ export class Connection extends EventEmitter implements ConnectionContract { * by the `close` event. */ public async disconnect (): Promise { - if (this.client) { + this._logger.trace({ connection: this.name }, 'destroying connection') + + /** + * Disconnect write client + */ + if (this._client) { try { - await this.client!.destroy() + await this._client.destroy() } catch (error) { this.emit('disconnect:error', error, this) } } + + /** + * Disconnect read client when it exists and both clients + * aren't same + */ + if (this._readClient && this._readClient !== this._client) { + try { + await this._readClient.destroy() + } catch (error) { + this.emit('disconnect:error', error, this) + } + } + } + + /** + * Returns the read client + */ + public getReadClient () { + this._ensureClients() + return this._readClient! + } + + /** + * Returns the write client + */ + public getWriteClient () { + this._ensureClients() + return this._client! + } + + /** + * Truncate table + */ + public async truncate (table: string): Promise { + this._ensureClients() + await this._client!.select(table).truncate() + } + + /** + * Get information for a table columns + */ + public async columnsInfo (table: string, column?: string): Promise { + this._ensureClients() + const query = this._client!.select(table) + const result = await (column ? query.columnInfo(column) : query.columnInfo()) + return result + } + + /** + * Returns an instance of a transaction. Each transaction will + * query and hold a single connection for all queries. + */ + public async transaction (): Promise { + this._ensureClients() + const trx = await this._client!.transaction() + return new Transaction(trx, this.dialect) + } + + /** + * Returns instance of a query builder for selecting, updating + * or deleting rows + */ + public query (): DatabaseQueryBuilderContract { + this._ensureClients() + return new DatabaseQueryBuilder(this._client!.queryBuilder(), this) + } + + /** + * Returns instance of a query builder for inserting rows + */ + public insertQuery (): InsertQueryBuilderContract { + this._ensureClients() + return new InsertQueryBuilder(this._client!.queryBuilder(), this) + } + + /** + * Returns instance of raw query builder + */ + public raw (sql: any, bindings?: any): RawContract { + this._ensureClients() + return new RawQueryBuilder(this._client!.raw(sql, bindings)) + } + + /** + * Returns instance of a query builder and selects the table + */ + public from (table: any): DatabaseQueryBuilderContract { + this._ensureClients() + return this.query().from(table) + } + + /** + * Returns instance of a query builder and selects the table + * for an insert query + */ + public table (table: any): InsertQueryBuilderContract { + this._ensureClients() + return this.insertQuery().table(table) } } diff --git a/src/Database/index.ts b/src/Database/index.ts deleted file mode 100644 index b4692b8f..00000000 --- a/src/Database/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * @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 { DatabaseQueryBuilderContract, QueryCallback } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' -import { BaseQueryBuilder } from '../BaseQueryBuilder' - -/** - * Wrapping the user function for a query callback and give them - * a new instance of the `DatabaseQueryBuilder` and not - * knex.QueryBuilder - */ -function queryCallback (userFn: QueryCallback) { - return (builder: knex.QueryBuilder) => { - // @ts-ignore - userFn(new DatabaseQueryBuilder(builder)) - } -} - -export class DatabaseQueryBuilder extends BaseQueryBuilder implements DatabaseQueryBuilderContract { - constructor (client: knex.QueryBuilder) { - super(client, queryCallback) - } - - private _normalizeAggregateColumns (columns: any, alias?: any): any { - if (columns.constructor === Object) { - return Object.keys(columns).reduce((result, key) => { - result[key] = this.$transformValue(columns[key]) - return result - }, {}) - } - - if (!alias) { - throw new Error('Aggregate function needs an alias as 2nd argument') - } - - return { [alias]: this.$transformValue(columns) } - } - - // @ts-ignore - public select (): this { - this.$knexBuilder.select(...arguments) - return this - } - - public count (columns: any, alias?: any): any { - this.$knexBuilder.count(this._normalizeAggregateColumns(columns, alias)) - return this - } - - public countDistinct (columns: any, alias?: any): any { - this.$knexBuilder.countDistinct(this._normalizeAggregateColumns(columns, alias)) - return this - } - - public min (columns: any, alias?: any): any { - this.$knexBuilder.min(this._normalizeAggregateColumns(columns, alias)) - return this - } - - public max (columns: any, alias?: any): any { - this.$knexBuilder.max(this._normalizeAggregateColumns(columns, alias)) - return this - } - - public avg (columns: any, alias?: any): any { - this.$knexBuilder.avg(this._normalizeAggregateColumns(columns, alias)) - return this - } - - public avgDistinct (columns: any, alias?: any): any { - this.$knexBuilder.avgDistinct(this._normalizeAggregateColumns(columns, alias)) - return this - } - - public sum (columns: any, alias?: any): any { - this.$knexBuilder.sum(this._normalizeAggregateColumns(columns, alias)) - return this - } -} diff --git a/src/InsertQueryBuilder/index.ts b/src/InsertQueryBuilder/index.ts deleted file mode 100644 index 513dfb06..00000000 --- a/src/InsertQueryBuilder/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * @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 { InsertQueryBuilderContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' - -/** - * Exposes the API for performing SQL inserts - */ -export class InsertQueryBuilder implements InsertQueryBuilderContract { - constructor (protected $knexBuilder: knex.QueryBuilder) { - } - - /** - * Define table for performing the insert query - */ - public table (table: any): this { - this.$knexBuilder.table(table) - return this - } - - /** - * Define returning columns for the insert query - */ - public returning (column: any): any { - this.$knexBuilder.returning(column) - return this - } - - /** - * Perform insert query - */ - public insert (columns: any, defer = false): Promise | any { - this.$knexBuilder.insert(columns) - - if (!defer) { - return this.exec() - } - - return this - } - - /** - * Insert multiple rows in a single query - */ - public multiInsert (columns: any, defer = false): Promise | any { - return this.insert(columns, defer) - } - - /** - * Executes the insert query - */ - public async exec (): Promise { - const returnValue = await this.$knexBuilder - return returnValue - } - - /** - * Get SQL representation of the constructed query - */ - public toSQL () { - return this.$knexBuilder.toSQL() - } - - /** - * Returns string representation of the query - */ - public toString () { - return this.$knexBuilder.toString() - } -} diff --git a/src/BaseQueryBuilder/index.ts b/src/QueryBuilder/Chainable.ts similarity index 88% rename from src/BaseQueryBuilder/index.ts rename to src/QueryBuilder/Chainable.ts index f5aa69b0..c85c85d8 100644 --- a/src/BaseQueryBuilder/index.ts +++ b/src/QueryBuilder/Chainable.ts @@ -11,7 +11,8 @@ import * as knex from 'knex' import { ChainableContract, QueryCallback } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' -import { RawQueryBuilder } from '../RawQueryBuilder' + +import { RawQueryBuilder } from './Raw' /** * Function to transform the query callbacks and passing them the right @@ -20,14 +21,30 @@ import { RawQueryBuilder } from '../RawQueryBuilder' type DBQueryCallback = (userFn: QueryCallback) => ((builder: knex.QueryBuilder) => void) /** - * Base query builder exposes the API for constructing SQL queries. + * The chainable query builder to consturct SQL queries for selecting, updating and + * deleting records. + * + * The API internally uses the knex query builder. However, many of methods may have + * different API. */ -export class BaseQueryBuilder implements ChainableContract { +export abstract class Chainable implements ChainableContract { constructor ( protected $knexBuilder: knex.QueryBuilder, private _queryCallback: DBQueryCallback, ) {} + /** + * Returns the value pair for the `whereBetween` clause + */ + private _getBetweenPair (value: any[]): any { + const [lhs, rhs] = value + if (!lhs || !rhs) { + throw new Error('Invalid array for whereBetween value') + } + + return [this.$transformValue(lhs), this.$transformValue(rhs)] + } + /** * Transforms the value to something that knex can internally understand and * handle. It includes. @@ -38,17 +55,29 @@ export class BaseQueryBuilder implements ChainableContract { * builder and not knex query builder. */ protected $transformValue (value: any) { - if (value instanceof BaseQueryBuilder) { + if (value instanceof Chainable) { return value.$knexBuilder } if (typeof (value) === 'function') { - return this._queryCallback(value) + return this.$transformCallback(value) } return this.$transformRaw(value) } + /** + * Transforms the user callback to something that knex + * can internally process + */ + protected $transformCallback (value: any) { + if (typeof (value) === 'function') { + return this._queryCallback(value) + } + + return value + } + /** * Returns the underlying knex raw query builder for Lucid raw * query builder @@ -66,7 +95,7 @@ export class BaseQueryBuilder implements ChainableContract { * use the last selected table */ public from (table: any): this { - this.$knexBuilder.from(table) + this.$knexBuilder.from(this.$transformCallback(table)) return this } @@ -79,7 +108,11 @@ export class BaseQueryBuilder implements ChainableContract { } else if (operator) { this.$knexBuilder.where(key, this.$transformValue(operator)) } else { - this.$knexBuilder.where(this.$transformValue(key)) + /** + * Only callback is allowed as a standalone param. One must use `whereRaw` + * for raw/sub queries. This is our limitation to have consistent API + */ + this.$knexBuilder.where(this.$transformCallback(key)) } return this @@ -94,7 +127,7 @@ export class BaseQueryBuilder implements ChainableContract { } else if (operator) { this.$knexBuilder.orWhere(key, this.$transformValue(operator)) } else { - this.$knexBuilder.orWhere(this.$transformValue(key)) + this.$knexBuilder.orWhere(this.$transformCallback(key)) } return this @@ -116,7 +149,7 @@ export class BaseQueryBuilder implements ChainableContract { } else if (operator) { this.$knexBuilder.whereNot(key, this.$transformValue(operator)) } else { - this.$knexBuilder.whereNot(this.$transformValue(key)) + this.$knexBuilder.whereNot(this.$transformCallback(key)) } return this @@ -131,7 +164,7 @@ export class BaseQueryBuilder implements ChainableContract { } else if (operator) { this.$knexBuilder.orWhereNot(key, this.$transformValue(operator)) } else { - this.$knexBuilder.orWhereNot(this.$transformValue(key)) + this.$knexBuilder.orWhereNot(this.$transformCallback(key)) } return this @@ -301,8 +334,8 @@ export class BaseQueryBuilder implements ChainableContract { /** * Add where between clause */ - public whereBetween (key: any, value: any): this { - this.$knexBuilder.whereBetween(key, value.map((one) => this.$transformValue(one))) + public whereBetween (key: any, value: [any, any]): this { + this.$knexBuilder.whereBetween(key, this._getBetweenPair(value)) return this } @@ -310,7 +343,7 @@ export class BaseQueryBuilder implements ChainableContract { * Add where between clause */ public orWhereBetween (key: any, value: any): this { - this.$knexBuilder.orWhereBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.orWhereBetween(key, this._getBetweenPair(value)) return this } @@ -325,7 +358,7 @@ export class BaseQueryBuilder implements ChainableContract { * Add where between clause */ public whereNotBetween (key: any, value: any): this { - this.$knexBuilder.whereNotBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.whereNotBetween(key, this._getBetweenPair(value)) return this } @@ -333,7 +366,7 @@ export class BaseQueryBuilder implements ChainableContract { * Add where between clause */ public orWhereNotBetween (key: any, value: any): this { - this.$knexBuilder.orWhereNotBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.orWhereNotBetween(key, this._getBetweenPair(value)) return this } @@ -519,16 +552,9 @@ export class BaseQueryBuilder implements ChainableContract { if (value) { this.$knexBuilder.having(key, operator, this.$transformValue(value)) } else if (operator) { - /** - * @todo: The having method in Knex is badly implemented. They only accept - * an instance of raw query and not `sql` and `bindings`, however everywhere - * else they accept `sql`, `bindings` and instance of raw query together. - * - * So we need to transform the `sql` and `bindings` to a raw query instance. - */ this.$knexBuilder.having(key, this.$transformValue(operator)) } else { - this.$knexBuilder.having(this.$transformValue(key)) + this.$knexBuilder.having(this.$transformCallback(key)) } return this @@ -544,16 +570,9 @@ export class BaseQueryBuilder implements ChainableContract { if (value) { this.$knexBuilder.orHaving(key, operator, this.$transformValue(value)) } else if (operator) { - /** - * @todo: The having method in Knex is badly implemented. They only accept - * an instance of raw query and not `sql` and `bindings`, however everywhere - * else they accept `sql`, `bindings` and instance of raw query together. - * - * So we need to transform the `sql` and `bindings` to a raw query instance. - */ this.$knexBuilder.orHaving(key, this.$transformValue(operator)) } else { - this.$knexBuilder.orHaving(this.$transformValue(key)) + this.$knexBuilder.orHaving(this.$transformCallback(key)) } return this @@ -724,7 +743,7 @@ export class BaseQueryBuilder implements ChainableContract { * Adding `having between` clause */ public havingBetween (key: any, value: any): this { - this.$knexBuilder.havingBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.havingBetween(key, this._getBetweenPair(value)) return this } @@ -732,7 +751,7 @@ export class BaseQueryBuilder implements ChainableContract { * Adding `or having between` clause */ public orHavingBetween (key: any, value: any): this { - this.$knexBuilder.orHavingBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.orHavingBetween(key, this._getBetweenPair(value)) return this } @@ -747,7 +766,7 @@ export class BaseQueryBuilder implements ChainableContract { * Adding `having not between` clause */ public havingNotBetween (key: any, value: any): this { - this.$knexBuilder.havingNotBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.havingNotBetween(key, this._getBetweenPair(value)) return this } @@ -755,7 +774,7 @@ export class BaseQueryBuilder implements ChainableContract { * Adding `or having not between` clause */ public orHavingNotBetween (key: any, value: any): this { - this.$knexBuilder.orHavingNotBetween(key, value.map((one) => this.$transformValue(one))) + this.$knexBuilder.orHavingNotBetween(key, this._getBetweenPair(value)) return this } @@ -901,21 +920,33 @@ export class BaseQueryBuilder implements ChainableContract { return this } + /** + * Clear select columns + */ public clearSelect (): this { this.$knexBuilder.clearSelect() return this } + /** + * Clear where clauses + */ public clearWhere (): this { this.$knexBuilder.clearWhere() return this } + /** + * Clear order by + */ public clearOrder (): this { this.$knexBuilder.clearOrder() return this } + /** + * Clear having + */ public clearHaving (): this { this.$knexBuilder.clearHaving() return this @@ -958,16 +989,34 @@ export class BaseQueryBuilder implements ChainableContract { } /** - * Get SQL representation of the constructed query + * Define `with` CTE + */ + public with (alias: any, query: any): this { + this.$knexBuilder.with(alias, query) + return this + } + + /** + * Define `with` CTE with recursive keyword */ - public toSQL () { - return this.$knexBuilder.toSQL() + public withRecursive (alias: any, query: any): this { + this.$knexBuilder.withRecursive(alias, query) + return this } /** - * Returns string representation of the query + * Define schema for the table */ - public toString () { - return this.$knexBuilder.toString() + public withSchema (schema: any): this { + this.$knexBuilder.withSchema(schema) + return this + } + + /** + * Define table alias + */ + public as (alias: any): this { + this.$knexBuilder.as(alias) + return this } } diff --git a/src/QueryBuilder/Database.ts b/src/QueryBuilder/Database.ts new file mode 100644 index 00000000..5266a477 --- /dev/null +++ b/src/QueryBuilder/Database.ts @@ -0,0 +1,277 @@ +/* + * @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 { + DatabaseQueryBuilderContract, + QueryCallback, + TransactionClientContract, + QueryClientContract, + } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' + +import { Chainable } from './Chainable' +import { executeQuery } from '../utils' + +/** + * Wrapping the user function for a query callback and give them + * a new instance of the `DatabaseQueryBuilder` and not + * knex.QueryBuilder + */ +function queryCallback (userFn: QueryCallback) { + return (builder: knex.QueryBuilder) => { + userFn(new DatabaseQueryBuilder(builder)) + } +} + +/** + * Database query builder exposes the API to construct and run queries for selecting, + * updating and deleting records. + */ +export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuilderContract { + constructor (builder: knex.QueryBuilder, private _client?: QueryClientContract) { + super(builder, queryCallback) + } + + /** + * 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 () { + if (!this._client || this._client.dialect === 'sqlite3') { + 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 + } + + /** + * Normalizes the columns aggregates functions to something + * knex can process. + */ + private _normalizeAggregateColumns (columns: any, alias?: any): any { + if (columns.constructor === Object) { + return Object.keys(columns).reduce((result, key) => { + result[key] = this.$transformValue(columns[key]) + return result + }, {}) + } + + if (!alias) { + throw new Error('Aggregate function needs an alias as 2nd argument') + } + + return { [alias]: this.$transformValue(columns) } + } + + /** + * Define columns for selection + */ + public select (): this { + this.$knexBuilder.select(...arguments) + return this + } + + /** + * Count rows for the current query + */ + public count (columns: any, alias?: any): this { + this.$knexBuilder.count(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Count distinct rows for the current query + */ + public countDistinct (columns: any, alias?: any): this { + this.$knexBuilder.countDistinct(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Make use of `min` aggregate function + */ + public min (columns: any, alias?: any): this { + this.$knexBuilder.min(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Make use of `max` aggregate function + */ + public max (columns: any, alias?: any): this { + this.$knexBuilder.max(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Make use of `avg` aggregate function + */ + public avg (columns: any, alias?: any): this { + this.$knexBuilder.avg(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Make use of distinct `avg` aggregate function + */ + public avgDistinct (columns: any, alias?: any): this { + this.$knexBuilder.avgDistinct(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Make use of `sum` aggregate function + */ + public sum (columns: any, alias?: any): this { + this.$knexBuilder.sum(this._normalizeAggregateColumns(columns, alias)) + return this + } + + /** + * Perform update by incrementing value for a given column. Increments + * can be clubbed with `update` as well + */ + public increment (column: any, counter?: any): this { + this.$knexBuilder.increment(column, counter) + return this + } + + /** + * Perform update by decrementing value for a given column. Decrements + * can be clubbed with `update` as well + */ + public decrement (column: any, counter?: any): this { + this.$knexBuilder.decrement(column, counter) + return this + } + + /** + * Delete rows under the current query + */ + public del (): this { + this.$knexBuilder.del() + return this + } + + /** + * Clone the current query builder + */ + public clone (): DatabaseQueryBuilder { + return new DatabaseQueryBuilder(this.$knexBuilder.clone(), this._client) + } + + /** + * Define returning columns + */ + public returning (columns: any): this { + this.$knexBuilder.returning(columns) + return this + } + + /** + * Perform update + */ + public update (columns: any): this { + this.$knexBuilder.update(columns) + return this + } + + /** + * Fetch and return first results from the results set. This method + * will implicitly set a `limit` on the query + */ + public async first (): Promise { + 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 { + const result = await executeQuery(this.$knexBuilder, this._getQueryClient()) + 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/QueryBuilder/Insert.ts b/src/QueryBuilder/Insert.ts new file mode 100644 index 00000000..6ec234c1 --- /dev/null +++ b/src/QueryBuilder/Insert.ts @@ -0,0 +1,149 @@ +/* + * @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 { + InsertQueryBuilderContract, + TransactionClientContract, + QueryClientContract, +} from '@ioc:Adonis/Addons/DatabaseQueryBuilder' + +import { executeQuery } from '../utils' + +/** + * Exposes the API for performing SQL inserts + */ +export class InsertQueryBuilder implements InsertQueryBuilderContract { + constructor (protected $knexBuilder: knex.QueryBuilder, private _client?: QueryClientContract) { + } + + /** + * Returns the client to be used for the query. Even though the insert query + * is always using the `write` client, we still go through the process of + * self defining the connection, so that we can discover any bugs during + * this process. + */ + private _getQueryClient () { + if (!this._client || this._client.dialect === 'sqlite3') { + return + } + + /** + * Always use write client for write queries + */ + return this._client.getWriteClient().client + } + + /** + * Define table for performing the insert query + */ + public table (table: any): this { + this.$knexBuilder.table(table) + return this + } + + /** + * Define returning columns for the insert query + */ + public returning (column: any): any { + this.$knexBuilder.returning(column) + return this + } + + /** + * Perform insert query + */ + public insert (columns: any): this { + this.$knexBuilder.insert(columns) + return this + } + + /** + * Insert multiple rows in a single query + */ + 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 { + const result = await executeQuery(this.$knexBuilder, this._getQueryClient()) + 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/QueryBuilder/Raw.ts b/src/QueryBuilder/Raw.ts new file mode 100644 index 00000000..126df869 --- /dev/null +++ b/src/QueryBuilder/Raw.ts @@ -0,0 +1,103 @@ +/* + * @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 { RawContract, TransactionClientContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' + +/** + * Exposes the API to execute raw queries + */ +export class RawQueryBuilder implements RawContract { + constructor (protected $knexBuilder: knex.Raw) { + } + + /** + * Wrap the query with before/after strings. + */ + public wrap (before: string, after: string): this { + 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 { + const result = await this.$knexBuilder + 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/RawQueryBuilder/index.ts b/src/RawQueryBuilder/index.ts deleted file mode 100644 index af5514d2..00000000 --- a/src/RawQueryBuilder/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * @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 { RawContract } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' - -export class RawQueryBuilder implements RawContract { - constructor (protected $knexBuilder: knex.Raw) { - } - - public wrap (before: string, after: string): this { - this.$knexBuilder.wrap(before, after) - return this - } - - public toQuery (): string { - return this.$knexBuilder.toQuery() - } - - public toSQL (): knex.Sql { - return this.$knexBuilder.toSQL() - } -} diff --git a/src/Transaction/index.ts b/src/Transaction/index.ts new file mode 100644 index 00000000..d65f0944 --- /dev/null +++ b/src/Transaction/index.ts @@ -0,0 +1,131 @@ +/* + * @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 { 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' +import { DatabaseQueryBuilder } from '../QueryBuilder/Database' + +/** + * Transaction uses a dedicated connection from the connection pool + * and executes queries inside a given transaction. + */ +export class Transaction implements TransactionClientContract { + public isTransaction: true = true + + constructor (public knexClient: knex.Transaction, public dialect: string) { + } + + /** + * Whether or not transaction has been completed + */ + public get isCompleted () { + return this.knexClient.isCompleted() + } + + /** + * Returns the read client. Which is just a single client in case + * of transactions + */ + public getReadClient () { + return this.knexClient + } + + /** + * Returns the write client. Which is just a single client in case + * of transactions + */ + public getWriteClient () { + return this.knexClient + } + + /** + * Truncate tables inside a transaction + */ + public async truncate (table: string): Promise { + await this.knexClient.select(table).truncate() + } + + /** + * Get columns info inside a transaction. You won't need it here, however + * added for API compatibility with the [[Connection]] class + */ + public async columnsInfo (table: string, column?: string): Promise { + const query = this.knexClient.select(table) + const result = await (column ? query.columnInfo(column) : query.columnInfo()) + return result + } + + /** + * Get a new query builder instance + */ + public query (): DatabaseQueryBuilderContract { + return new DatabaseQueryBuilder(this.knexClient.queryBuilder()) + } + + /** + * Get a new insert query builder instance + */ + public insertQuery (): InsertQueryBuilderContract { + return new InsertQueryBuilder(this.knexClient.queryBuilder()) + } + + /** + * Returns another instance of transaction with save point + */ + public async transaction (): Promise { + const trx = await this.knexClient.transaction() + return new Transaction(trx, this.dialect) + } + + /** + * Execute raw query on transaction + */ + public raw (sql: any, bindings?: any): RawContract { + return new RawQueryBuilder(this.knexClient.raw(sql, bindings)) + } + + /** + * Same as [[Transaction.query]] but also selects the table + */ + public from (table: any): DatabaseQueryBuilderContract { + return this.query().from(table) + } + + /** + * Same as [[Transaction.insertTable]] but also selects the table + */ + public table (table: any): InsertQueryBuilderContract { + return this.insertQuery().table(table) + } + + /** + * Commit the transaction + */ + public async commit () { + await this.knexClient.commit() + } + + /** + * Rollback the transaction + */ + public async rollback () { + await this.knexClient.rollback() + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 00000000..534f8626 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,58 @@ +/* +* @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' + +/** + * Executes the knex query with an option to manually pull connection from + * a dedicated knex client. + */ +export async function executeQuery (builder: knex.QueryBuilder, client?: any) { + if (!client) { + return builder + } + + /** + * Acquire connection from the client and set it as the + * connection to be used for executing the query + */ + const connection = await client.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 + } catch (error) { + queryError = error + } + + /** + * Releasing the connection back to pool + */ + client.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 93bd74fd..28b7fc50 100644 --- a/test-helpers/index.ts +++ b/test-helpers/index.ts @@ -10,18 +10,21 @@ /// import { join } from 'path' +import * as knex from 'knex' import * as dotenv from 'dotenv' +import { FakeLogger } from '@poppinss/logger' import { Filesystem } from '@poppinss/dev-utils' + import { ConnectionConfigContract, ConnectionContract } from '@ioc:Adonis/Addons/Database' import { - DatabaseQueryBuilderContract, RawContract, InsertQueryBuilderContract, + DatabaseQueryBuilderContract, } from '@ioc:Adonis/Addons/DatabaseQueryBuilder' -import { DatabaseQueryBuilder } from '../src/Database' -import { InsertQueryBuilder } from '../src/InsertQueryBuilder' -import { RawQueryBuilder } from '../src/RawQueryBuilder' +import { RawQueryBuilder } from '../src/QueryBuilder/Raw' +import { InsertQueryBuilder } from '../src/QueryBuilder/Insert' +import { DatabaseQueryBuilder } from '../src/QueryBuilder/Database' export const fs = new Filesystem(join(__dirname, 'tmp')) dotenv.config() @@ -75,6 +78,19 @@ export async function setup () { if (process.env.DB === 'sqlite') { await fs.ensureRoot() } + + const db = knex(getConfig()) + + const hasTable = await db.schema.hasTable('users') + if (!hasTable) { + await db.schema.createTable('users', (table) => { + table.increments() + table.string('username') + table.timestamps() + }) + } + + await db.destroy() } /** @@ -83,7 +99,20 @@ export async function setup () { export async function cleanup () { if (process.env.DB === 'sqlite') { await fs.cleanup() + return } + + const db = knex(getConfig()) + await db.schema.dropTableIfExists('users') + await db.destroy() +} + +/** + * Reset database tables + */ +export async function resetTables () { + const db = knex(getConfig()) + await db.table('users').truncate() } /** @@ -91,7 +120,8 @@ export async function cleanup () { */ export function getQueryBuilder (connection: ConnectionContract) { return new DatabaseQueryBuilder( - connection.client!.queryBuilder(), + connection.getWriteClient().queryBuilder(), + connection, ) as unknown as DatabaseQueryBuilderContract } @@ -100,7 +130,7 @@ export function getQueryBuilder (connection: ConnectionContract) { */ export function getRawQueryBuilder (connection: ConnectionContract, sql: string, bindings?: any[]) { return new RawQueryBuilder( - bindings ? connection.client!.raw(sql, bindings) : connection.client!.raw(sql), + bindings ? connection.getWriteClient().raw(sql, bindings) : connection.getWriteClient().raw(sql), ) as unknown as RawContract } @@ -109,6 +139,17 @@ export function getRawQueryBuilder (connection: ConnectionContract, sql: string, */ export function getInsertBuilder (connection: ConnectionContract) { return new InsertQueryBuilder( - connection.client!.queryBuilder(), + connection.getWriteClient().queryBuilder(), ) as unknown as InsertQueryBuilderContract } + +/** + * Returns fake logger instance + */ +export function getLogger () { + return new FakeLogger({ + enabled: true, + name: 'lucid', + level: 'info', + }) +} diff --git a/test/connection-manager.spec.ts b/test/connection-manager.spec.ts index 24bd03e2..2b73ff13 100644 --- a/test/connection-manager.spec.ts +++ b/test/connection-manager.spec.ts @@ -11,8 +11,8 @@ import * as test from 'japa' -import { getConfig, setup, cleanup } from '../test-helpers' -import { ConnectionManager } from '../src/ConnectionManager' +import { ConnectionManager } from '../src/Connection/Manager' +import { getConfig, setup, cleanup, getLogger } from '../test-helpers' test.group('ConnectionManager', (group) => { group.before(async () => { @@ -24,7 +24,7 @@ test.group('ConnectionManager', (group) => { }) test('do not connect until connect is called', (assert) => { - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) assert.isTrue(manager.has('primary')) @@ -32,7 +32,7 @@ test.group('ConnectionManager', (group) => { }) test('connect and set its state to open', async (assert) => { - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) manager.connect('primary') @@ -41,7 +41,7 @@ test.group('ConnectionManager', (group) => { }) test('on disconnect set state to closed', async (assert) => { - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) manager.connect('primary') @@ -51,7 +51,7 @@ test.group('ConnectionManager', (group) => { }) test('raise exception when attempt to add a duplication connection', async (assert) => { - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) manager.connect('primary') @@ -60,7 +60,7 @@ test.group('ConnectionManager', (group) => { }) test('patch config when connection is not in open state', async (assert) => { - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) manager.connect('primary') @@ -71,7 +71,7 @@ test.group('ConnectionManager', (group) => { }) test('ignore multiple calls to `connect` on a single connection', async () => { - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) manager.connect('primary') @@ -85,7 +85,7 @@ test.group('ConnectionManager', (group) => { test('releasing a connection must close it first', async (assert) => { assert.plan(2) - const manager = new ConnectionManager() + const manager = new ConnectionManager(getLogger()) manager.add('primary', getConfig()) manager.connect('primary') diff --git a/test/connection.spec.ts b/test/connection.spec.ts index a3059219..232ab3e5 100644 --- a/test/connection.spec.ts +++ b/test/connection.spec.ts @@ -12,10 +12,66 @@ import * as test from 'japa' import { MysqlConfigContract } from '@ioc:Adonis/Addons/Database' -import { getConfig, setup, cleanup } from '../test-helpers' import { Connection } from '../src/Connection' +import { getConfig, setup, cleanup, resetTables, getLogger } from '../test-helpers' -test.group('Connection', (group) => { +if (process.env.DB !== 'sqlite') { + test.group('Connection | config', (group) => { + group.before(async () => { + await setup() + }) + + group.after(async () => { + await cleanup() + }) + + test('get write config by merging values from connection', (assert) => { + const config = getConfig() + config.replicas! = { + write: { + connection: { + host: '10.0.0.1', + }, + }, + read: { + connection: [{ + host: '10.0.0.1', + }], + }, + } + + const connection = new Connection('primary', config, getLogger()) + const writeConfig = connection['_getWriteConfig']() + + assert.equal(writeConfig.client, config.client) + assert.equal(writeConfig.connection!['host'], '10.0.0.1') + }) + + test('get read config by merging values from connection', (assert) => { + const config = getConfig() + config.replicas! = { + write: { + connection: { + host: '10.0.0.1', + }, + }, + read: { + connection: [{ + host: '10.0.0.1', + }], + }, + } + + const connection = new Connection('primary', config, getLogger()) + const readConfig = connection['_getReadConfig']() + + assert.equal(readConfig.client, config.client) + assert.deepEqual(readConfig.connection, { database: 'lucid' }) + }) + }) +} + +test.group('Connection | setup', (group) => { group.before(async () => { await setup() }) @@ -24,15 +80,19 @@ test.group('Connection', (group) => { await cleanup() }) + group.afterEach(async () => { + await resetTables() + }) + test('do not instantiate knex unless connect is called', (assert) => { - const connection = new Connection('primary', getConfig()) - assert.isUndefined(connection.client) + const connection = new Connection('primary', getConfig(), getLogger()) + assert.isUndefined(connection['_client']) }) test('instantiate knex when connect is invoked', async (assert, done) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.on('connect', () => { - assert.isDefined(connection.client) + assert.isDefined(connection.getWriteClient()) assert.equal(connection.pool!.numUsed(), 0) done() }) @@ -41,35 +101,20 @@ test.group('Connection', (group) => { }) test('on disconnect destroy knex', async (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() await connection.disconnect() - assert.isUndefined(connection.client) - }) - - test('destroy connection when pool min resources are zero and connection is idle', async (assert, done) => { - const connection = new Connection('primary', Object.assign(getConfig(), { - pool: { - min: 0, - idleTimeoutMillis: 10, - }, - })) - connection.connect() - await connection.client!.raw('select 1+1 as result') - - connection.on('disconnect', () => { - assert.isUndefined(connection.client) - done() - }) + assert.isUndefined(connection['_client']) + assert.isUndefined(connection['_readClient']) }) test('on disconnect emit disconnect event', async (assert, done) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() connection.on('disconnect', () => { - assert.isUndefined(connection.client) + assert.isUndefined(connection['_client']) done() }) @@ -77,7 +122,11 @@ test.group('Connection', (group) => { }) test('raise error when unable to make connection', (assert) => { - const connection = new Connection('primary', Object.assign({}, getConfig(), { client: null })) + const connection = new Connection( + 'primary', + Object.assign({}, getConfig(), { client: null }), + getLogger(), + ) const fn = () => connection.connect() assert.throw(fn, /knex: Required configuration option/) @@ -85,18 +134,84 @@ test.group('Connection', (group) => { }) if (process.env.DB === 'mysql') { - test.group('Connection | mysql', () => { + test.group('Connection | setup mysql', () => { test('pass user config to mysql driver', async (assert) => { const config = getConfig() as MysqlConfigContract - config.connection.charset = 'utf-8' - config.connection.typeCast = false + config.connection!.charset = 'utf-8' + config.connection!.typeCast = false - const connection = new Connection('primary', config) + const connection = new Connection('primary', config, getLogger()) connection.connect() - assert.equal(connection.client!['_context'].client.constructor.name, 'Client_MySQL') - assert.equal(connection.client!['_context'].client.config.connection.charset, 'utf-8') - assert.equal(connection.client!['_context'].client.config.connection.typeCast, false) + assert.equal(connection.getWriteClient()['_context'].client.constructor.name, 'Client_MySQL') + assert.equal(connection.getWriteClient()['_context'].client.config.connection.charset, 'utf-8') + assert.equal(connection.getWriteClient()['_context'].client.config.connection.typeCast, false) }) }) } + +test.group('Connection | query', (group) => { + group.before(async () => { + await setup() + }) + + group.after(async () => { + await cleanup() + }) + + test('get query builder instance to perform select queries', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const results = await connection.query().from('users') + assert.isArray(results) + assert.lengthOf(results, 0) + + await connection.disconnect() + }) + + test('get insert query builder instance', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + await connection.insertQuery().table('users').insert({ username: 'virk' }) + + const results = await connection.query().from('users') + assert.isArray(results) + assert.lengthOf(results, 1) + assert.equal(results[0].username, 'virk') + + await connection.disconnect() + }) + + test('perform raw queries', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const command = process.env.DB === 'sqlite' ? `DELETE FROM users;` : 'TRUNCATE users;' + + await connection.insertQuery().table('users').insert({ username: 'virk' }) + await connection.raw(command).exec() + const results = await connection.query().from('users') + assert.isArray(results) + assert.lengthOf(results, 0) + + await connection.disconnect() + }) + + test('perform queries inside a transaction', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const trx = await connection.transaction() + await trx.insertQuery().table('users').insert({ username: 'virk' }) + await trx.rollback() + + const results = await connection.query().from('users') + + assert.isArray(results) + assert.lengthOf(results, 0) + + await connection.disconnect() + }) +}) diff --git a/test/insert-query-builder.spec.ts b/test/insert-query-builder.spec.ts index 34e6c3c2..1f97fe4d 100644 --- a/test/insert-query-builder.spec.ts +++ b/test/insert-query-builder.spec.ts @@ -12,7 +12,7 @@ import * as test from 'japa' import { Connection } from '../src/Connection' -import { getConfig, setup, cleanup, getInsertBuilder } from '../test-helpers' +import { getConfig, setup, cleanup, getInsertBuilder, getLogger } from '../test-helpers' test.group('Query Builder | from', (group) => { group.before(async () => { @@ -24,13 +24,13 @@ test.group('Query Builder | from', (group) => { }) test('perform insert', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getInsertBuilder(connection) - const { sql, bindings } = db.table('users').insert({ username: 'virk' }, true).toSQL() + const { sql, bindings } = db.table('users').insert({ username: 'virk' }).toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .insert({ username: 'virk' }) .toSQL() @@ -40,16 +40,16 @@ test.group('Query Builder | from', (group) => { }) test('perform multi insert', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getInsertBuilder(connection) const { sql, bindings } = db .table('users') - .multiInsert([{ username: 'virk' }, { username: 'nikk' }], true) + .multiInsert([{ username: 'virk' }, { username: 'nikk' }]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .insert([{ username: 'virk' }, { username: 'nikk' }]) .toSQL() @@ -59,17 +59,17 @@ test.group('Query Builder | from', (group) => { }) test('define returning columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getInsertBuilder(connection) const { sql, bindings } = db .table('users') .returning(['id', 'username']) - .multiInsert([{ username: 'virk' }, { username: 'nikk' }], true) + .multiInsert([{ username: 'virk' }, { username: 'nikk' }]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .returning(['id', 'username']) .insert([{ username: 'virk' }, { username: 'nikk' }]) diff --git a/test/query-builder.spec.ts b/test/query-builder.spec.ts index 9287f50d..27b13c96 100644 --- a/test/query-builder.spec.ts +++ b/test/query-builder.spec.ts @@ -10,10 +10,66 @@ /// import * as test from 'japa' - import { Connection } from '../src/Connection' -import { DatabaseQueryBuilder } from '../src/Database' -import { getConfig, setup, cleanup, getQueryBuilder, getRawQueryBuilder } from '../test-helpers' +import { DatabaseQueryBuilder } from '../src/QueryBuilder/Database' +import { getConfig, setup, cleanup, getQueryBuilder, getRawQueryBuilder, getLogger } from '../test-helpers' + +if (process.env.DB !== 'sqlite') { + test.group('Query Builder | client', (group) => { + group.before(async () => { + await setup() + }) + + group.after(async () => { + await cleanup() + }) + + test('use read client when making select query', (assert) => { + assert.plan(1) + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + connection.getReadClient = function getReadClient () { + assert.isTrue(true) + return this._client + } + + const db = getQueryBuilder(connection) + db.select('*').from('users') + db['_getQueryClient']() + }) + + test('use write client for update', (assert) => { + assert.plan(1) + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const db = getQueryBuilder(connection) + connection.getWriteClient = function getWriteClient () { + assert.isTrue(true) + return this._client + } + + db.from('users').update('username', 'virk') + db['_getQueryClient']() + }) + + test('use write client for delete', (assert) => { + assert.plan(1) + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + const db = getQueryBuilder(connection) + + connection.getWriteClient = function getWriteClient () { + assert.isTrue(true) + return this._client + } + + db.from('users').del() + db['_getQueryClient']() + }) + }) +} test.group('Query Builder | from', (group) => { group.before(async () => { @@ -25,24 +81,24 @@ test.group('Query Builder | from', (group) => { }) test('define query table', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) const { sql, bindings } = db.from('users').toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client!.from('users').toSQL() + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient().from('users').toSQL() assert.equal(sql, knexSql) assert.deepEqual(bindings, knexBindings) }) test('define table alias', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) const { sql, bindings } = db.from({ u: 'users' }).toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client!.from({ u: 'users' }).toSQL() + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient().from({ u: 'users' }).toSQL() assert.equal(sql, knexSql) assert.deepEqual(bindings, knexBindings) @@ -59,7 +115,7 @@ test.group('Query Builder | where', (group) => { }) test('add where clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -68,7 +124,7 @@ test.group('Query Builder | where', (group) => { .where('username', 'virk') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where('username', 'virk') .toSQL() @@ -78,7 +134,7 @@ test.group('Query Builder | where', (group) => { }) test('add where clause as an object', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -87,7 +143,7 @@ test.group('Query Builder | where', (group) => { .where({ username: 'virk', age: 22 }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where({ username: 'virk', age: 22 }) .toSQL() @@ -97,7 +153,7 @@ test.group('Query Builder | where', (group) => { }) test('add where wrapped clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -106,7 +162,7 @@ test.group('Query Builder | where', (group) => { .where((builder) => builder.where('username', 'virk')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where((builder) => builder.where('username', 'virk')) .toSQL() @@ -116,7 +172,7 @@ test.group('Query Builder | where', (group) => { }) test('add where clause with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -125,7 +181,7 @@ test.group('Query Builder | where', (group) => { .where('age', '>', 22) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where('age', '>', 22) .toSQL() @@ -135,7 +191,7 @@ test.group('Query Builder | where', (group) => { }) test('add where clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -144,9 +200,9 @@ test.group('Query Builder | where', (group) => { .where('age', '>', getRawQueryBuilder(connection, 'select min_age from ages limit 1;')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .where('age', '>', connection.client!.raw('select min_age from ages limit 1;')) + .where('age', '>', connection.getWriteClient().raw('select min_age from ages limit 1;')) .toSQL() assert.equal(sql, knexSql) @@ -154,7 +210,7 @@ test.group('Query Builder | where', (group) => { }) test('add orWhere clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -164,7 +220,7 @@ test.group('Query Builder | where', (group) => { .orWhere('age', 18) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where('age', '>', 22) .orWhere('age', 18) @@ -175,7 +231,7 @@ test.group('Query Builder | where', (group) => { }) test('add orWhere wrapped clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -188,7 +244,7 @@ test.group('Query Builder | where', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where('age', '>', 22) .orWhere((builder) => { @@ -211,7 +267,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add where no clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -220,7 +276,7 @@ test.group('Query Builder | whereNot', (group) => { .whereNot('username', 'virk') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNot('username', 'virk') .toSQL() @@ -230,7 +286,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add where not clause as an object', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -239,7 +295,7 @@ test.group('Query Builder | whereNot', (group) => { .whereNot({ username: 'virk', age: 22 }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNot({ username: 'virk', age: 22 }) .toSQL() @@ -249,7 +305,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add where not wrapped clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -258,7 +314,7 @@ test.group('Query Builder | whereNot', (group) => { .whereNot((builder) => builder.where('username', 'virk')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNot((builder) => builder.where('username', 'virk')) .toSQL() @@ -268,7 +324,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add where not clause with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -277,7 +333,7 @@ test.group('Query Builder | whereNot', (group) => { .whereNot('age', '>', 22) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNot('age', '>', 22) .toSQL() @@ -287,7 +343,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add where not clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -296,9 +352,9 @@ test.group('Query Builder | whereNot', (group) => { .whereNot('age', '>', getRawQueryBuilder(connection, 'select min_age from ages limit 1;')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereNot('age', '>', connection.client!.raw('select min_age from ages limit 1;')) + .whereNot('age', '>', connection.getWriteClient().raw('select min_age from ages limit 1;')) .toSQL() assert.equal(sql, knexSql) @@ -306,7 +362,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add orWhereNot clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -316,7 +372,7 @@ test.group('Query Builder | whereNot', (group) => { .orWhereNot('age', 18) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNot('age', '>', 22) .orWhereNot('age', 18) @@ -327,7 +383,7 @@ test.group('Query Builder | whereNot', (group) => { }) test('add orWhereNot wrapped clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -340,7 +396,7 @@ test.group('Query Builder | whereNot', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where('age', '>', 22) .orWhereNot((builder) => { @@ -363,7 +419,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add whereIn clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -372,7 +428,7 @@ test.group('Query Builder | whereIn', (group) => { .whereIn('username', ['virk', 'nikk']) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereIn('username', ['virk', 'nikk']) .toSQL() @@ -382,7 +438,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add whereIn as a query callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -393,7 +449,7 @@ test.group('Query Builder | whereIn', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereIn('username', (builder) => { builder.from('accounts') @@ -405,7 +461,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add whereIn as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -414,9 +470,9 @@ test.group('Query Builder | whereIn', (group) => { .whereIn('username', getQueryBuilder(connection).select('id').from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereIn('username', connection.client!.select('id').from('accounts')) + .whereIn('username', connection.getWriteClient().select('id').from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -424,10 +480,10 @@ test.group('Query Builder | whereIn', (group) => { }) test('add whereIn as a rawquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() - const ref = connection.client!.ref.bind(connection.client) + const ref = connection.getWriteClient().ref.bind(connection.getWriteClient()) const db = getQueryBuilder(connection) const { sql, bindings } = db @@ -437,10 +493,10 @@ test.group('Query Builder | whereIn', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereIn('username', [ - connection.client!.raw(`select ${ref('id')} from ${ref('accounts')}`), + connection.getWriteClient().raw(`select ${ref('id')} from ${ref('accounts')}`), ]) .toSQL() @@ -449,7 +505,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add whereIn as a subquery with array of keys', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -461,9 +517,9 @@ test.group('Query Builder | whereIn', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereIn(['username', 'email'], connection.client!.select('username', 'email').from('accounts')) + .whereIn(['username', 'email'], connection.getWriteClient().select('username', 'email').from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -471,7 +527,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add whereIn as a 2d array', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -480,7 +536,7 @@ test.group('Query Builder | whereIn', (group) => { .whereIn(['username', 'email'], [['foo', 'bar']]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereIn(['username', 'email'], [['foo', 'bar']]) .toSQL() @@ -490,7 +546,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add orWhereIn clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -500,7 +556,7 @@ test.group('Query Builder | whereIn', (group) => { .orWhereIn('username', ['foo']) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereIn('username', ['virk', 'nikk']) .orWhereIn('username', ['foo']) @@ -511,7 +567,7 @@ test.group('Query Builder | whereIn', (group) => { }) test('add orWhereIn as a query callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -525,7 +581,7 @@ test.group('Query Builder | whereIn', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereIn('username', (builder) => { builder.from('accounts') @@ -550,7 +606,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) test('add whereNotIn clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -559,7 +615,7 @@ test.group('Query Builder | whereNotIn', (group) => { .whereNotIn('username', ['virk', 'nikk']) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotIn('username', ['virk', 'nikk']) .toSQL() @@ -569,7 +625,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) test('add whereNotIn as a query callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -580,7 +636,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotIn('username', (builder) => { builder.from('accounts') @@ -592,7 +648,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) test('add whereNotIn as a sub query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -601,9 +657,9 @@ test.group('Query Builder | whereNotIn', (group) => { .whereNotIn('username', getQueryBuilder(connection).select('username').from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereNotIn('username', connection.client!.select('username').from('accounts')) + .whereNotIn('username', connection.getWriteClient().select('username').from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -611,7 +667,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) test('add whereNotIn as a 2d array', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -620,7 +676,7 @@ test.group('Query Builder | whereNotIn', (group) => { .whereNotIn(['username', 'email'], [['foo', 'bar']]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotIn(['username', 'email'], [['foo', 'bar']]) .toSQL() @@ -630,7 +686,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) test('add orWhereNotIn clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -640,7 +696,7 @@ test.group('Query Builder | whereNotIn', (group) => { .orWhereNotIn('username', ['foo']) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotIn('username', ['virk', 'nikk']) .orWhereNotIn('username', ['foo']) @@ -651,7 +707,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) test('add orWhereNotIn as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -665,7 +721,7 @@ test.group('Query Builder | whereNotIn', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotIn('username', (builder) => { builder.from('accounts') @@ -690,7 +746,7 @@ test.group('Query Builder | whereNull', (group) => { }) test('add where null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -699,7 +755,7 @@ test.group('Query Builder | whereNull', (group) => { .whereNull('deleted_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNull('deleted_at') .toSQL() @@ -709,7 +765,7 @@ test.group('Query Builder | whereNull', (group) => { }) test('add or where null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -719,7 +775,7 @@ test.group('Query Builder | whereNull', (group) => { .orWhereNull('updated_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNull('deleted_at') .orWhereNull('updated_at') @@ -740,7 +796,7 @@ test.group('Query Builder | whereNotNull', (group) => { }) test('add where not null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -749,7 +805,7 @@ test.group('Query Builder | whereNotNull', (group) => { .whereNotNull('deleted_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotNull('deleted_at') .toSQL() @@ -759,7 +815,7 @@ test.group('Query Builder | whereNotNull', (group) => { }) test('add or where not null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -769,7 +825,7 @@ test.group('Query Builder | whereNotNull', (group) => { .orWhereNotNull('updated_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotNull('deleted_at') .orWhereNotNull('updated_at') @@ -790,7 +846,7 @@ test.group('Query Builder | whereExists', (group) => { }) test('add where exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -801,7 +857,7 @@ test.group('Query Builder | whereExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereExists((builder) => { builder.from('accounts') @@ -813,7 +869,7 @@ test.group('Query Builder | whereExists', (group) => { }) test('add where exists clause as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -822,9 +878,9 @@ test.group('Query Builder | whereExists', (group) => { .whereExists(getQueryBuilder(connection).from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereExists(connection.client!.from('accounts')) + .whereExists(connection.getWriteClient().from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -832,7 +888,7 @@ test.group('Query Builder | whereExists', (group) => { }) test('add or where exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -843,7 +899,7 @@ test.group('Query Builder | whereExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orWhereExists((builder) => { builder.from('accounts') @@ -855,7 +911,7 @@ test.group('Query Builder | whereExists', (group) => { }) test('add or where exists clause as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -864,9 +920,9 @@ test.group('Query Builder | whereExists', (group) => { .orWhereExists(getQueryBuilder(connection).from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .orWhereExists(connection.client!.from('accounts')) + .orWhereExists(connection.getWriteClient().from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -884,7 +940,7 @@ test.group('Query Builder | whereNotExists', (group) => { }) test('add where exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -895,7 +951,7 @@ test.group('Query Builder | whereNotExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotExists((builder) => { builder.from('accounts') @@ -907,7 +963,7 @@ test.group('Query Builder | whereNotExists', (group) => { }) test('add where exists clause as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -916,9 +972,9 @@ test.group('Query Builder | whereNotExists', (group) => { .whereNotExists(getQueryBuilder(connection).from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereNotExists(connection.client!.from('accounts')) + .whereNotExists(connection.getWriteClient().from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -926,7 +982,7 @@ test.group('Query Builder | whereNotExists', (group) => { }) test('add or where exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -937,7 +993,7 @@ test.group('Query Builder | whereNotExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orWhereNotExists((builder) => { builder.from('accounts') @@ -949,7 +1005,7 @@ test.group('Query Builder | whereNotExists', (group) => { }) test('add or where exists clause as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -958,9 +1014,9 @@ test.group('Query Builder | whereNotExists', (group) => { .orWhereNotExists(getQueryBuilder(connection).from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .orWhereNotExists(connection.client!.from('accounts')) + .orWhereNotExists(connection.getWriteClient().from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -978,7 +1034,7 @@ test.group('Query Builder | whereBetween', (group) => { }) test('add where between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -987,7 +1043,7 @@ test.group('Query Builder | whereBetween', (group) => { .whereBetween('age', [18, 20]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereBetween('age', [18, 20]) .toSQL() @@ -997,7 +1053,7 @@ test.group('Query Builder | whereBetween', (group) => { }) test('add where between clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1009,11 +1065,11 @@ test.group('Query Builder | whereBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereBetween('age', [ - connection.client!.raw('select min_age from ages;'), - connection.client!.raw('select max_age from ages;'), + connection.getWriteClient().raw('select min_age from ages;'), + connection.getWriteClient().raw('select max_age from ages;'), ]) .toSQL() @@ -1022,7 +1078,7 @@ test.group('Query Builder | whereBetween', (group) => { }) test('add or where between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1031,7 +1087,7 @@ test.group('Query Builder | whereBetween', (group) => { .orWhereBetween('age', [18, 20]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orWhereBetween('age', [18, 20]) .toSQL() @@ -1041,7 +1097,7 @@ test.group('Query Builder | whereBetween', (group) => { }) test('add or where between clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1053,11 +1109,11 @@ test.group('Query Builder | whereBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orWhereBetween('age', [ - connection.client!.raw('select min_age from ages;'), - connection.client!.raw('select max_age from ages;'), + connection.getWriteClient().raw('select min_age from ages;'), + connection.getWriteClient().raw('select max_age from ages;'), ]) .toSQL() @@ -1076,7 +1132,7 @@ test.group('Query Builder | whereNotBetween', (group) => { }) test('add where not between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1085,7 +1141,7 @@ test.group('Query Builder | whereNotBetween', (group) => { .whereNotBetween('age', [18, 20]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotBetween('age', [18, 20]) .toSQL() @@ -1095,7 +1151,7 @@ test.group('Query Builder | whereNotBetween', (group) => { }) test('add where not between clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1107,11 +1163,11 @@ test.group('Query Builder | whereNotBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereNotBetween('age', [ - connection.client!.raw('select min_age from ages;'), - connection.client!.raw('select max_age from ages;'), + connection.getWriteClient().raw('select min_age from ages;'), + connection.getWriteClient().raw('select max_age from ages;'), ]) .toSQL() @@ -1120,7 +1176,7 @@ test.group('Query Builder | whereNotBetween', (group) => { }) test('add or where not between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1129,7 +1185,7 @@ test.group('Query Builder | whereNotBetween', (group) => { .orWhereNotBetween('age', [18, 20]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orWhereNotBetween('age', [18, 20]) .toSQL() @@ -1139,7 +1195,7 @@ test.group('Query Builder | whereNotBetween', (group) => { }) test('add or where not between clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1151,11 +1207,11 @@ test.group('Query Builder | whereNotBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orWhereNotBetween('age', [ - connection.client!.raw('select min_age from ages;'), - connection.client!.raw('select max_age from ages;'), + connection.getWriteClient().raw('select min_age from ages;'), + connection.getWriteClient().raw('select max_age from ages;'), ]) .toSQL() @@ -1174,7 +1230,7 @@ test.group('Query Builder | whereRaw', (group) => { }) test('add where raw clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1183,7 +1239,7 @@ test.group('Query Builder | whereRaw', (group) => { .whereRaw('id = ?', [1]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereRaw('id = ?', [1]) .toSQL() @@ -1193,7 +1249,7 @@ test.group('Query Builder | whereRaw', (group) => { }) test('add where raw clause without bindings', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1202,7 +1258,7 @@ test.group('Query Builder | whereRaw', (group) => { .whereRaw('id = 1') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereRaw('id = 1') .toSQL() @@ -1212,7 +1268,7 @@ test.group('Query Builder | whereRaw', (group) => { }) test('add where raw clause with object of bindings', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1221,7 +1277,7 @@ test.group('Query Builder | whereRaw', (group) => { .whereRaw('id = :id', { id: 1 }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereRaw('id = :id', { id: 1 }) .toSQL() @@ -1231,7 +1287,7 @@ test.group('Query Builder | whereRaw', (group) => { }) test('add where raw clause from a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1240,9 +1296,9 @@ test.group('Query Builder | whereRaw', (group) => { .whereRaw(getRawQueryBuilder(connection, 'select id from accounts;')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .whereRaw(connection.client!.raw('select id from accounts;')) + .whereRaw(connection.getWriteClient().raw('select id from accounts;')) .toSQL() assert.equal(sql, knexSql) @@ -1250,7 +1306,7 @@ test.group('Query Builder | whereRaw', (group) => { }) test('add or where raw clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1260,7 +1316,7 @@ test.group('Query Builder | whereRaw', (group) => { .orWhereRaw('id = ?', [2]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .whereRaw('id = ?', [1]) .orWhereRaw('id = ?', [2]) @@ -1281,7 +1337,7 @@ test.group('Query Builder | join', (group) => { }) test('add query join', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1290,7 +1346,7 @@ test.group('Query Builder | join', (group) => { .join('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .join('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1300,7 +1356,7 @@ test.group('Query Builder | join', (group) => { }) test('add query join with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1309,7 +1365,7 @@ test.group('Query Builder | join', (group) => { .join('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .join('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1319,7 +1375,7 @@ test.group('Query Builder | join', (group) => { }) test('add query join using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1330,7 +1386,7 @@ test.group('Query Builder | join', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .join('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1342,7 +1398,7 @@ test.group('Query Builder | join', (group) => { }) test('add query join as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1351,9 +1407,9 @@ test.group('Query Builder | join', (group) => { .join('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .join('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .join('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1371,7 +1427,7 @@ test.group('Query Builder | innerJoin', (group) => { }) test('add query innerJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1380,7 +1436,7 @@ test.group('Query Builder | innerJoin', (group) => { .innerJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .innerJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1390,7 +1446,7 @@ test.group('Query Builder | innerJoin', (group) => { }) test('add query innerJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1399,7 +1455,7 @@ test.group('Query Builder | innerJoin', (group) => { .innerJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .innerJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1409,7 +1465,7 @@ test.group('Query Builder | innerJoin', (group) => { }) test('add query innerJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1420,7 +1476,7 @@ test.group('Query Builder | innerJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .innerJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1432,7 +1488,7 @@ test.group('Query Builder | innerJoin', (group) => { }) test('add query innerJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1441,9 +1497,9 @@ test.group('Query Builder | innerJoin', (group) => { .innerJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .innerJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .innerJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1461,7 +1517,7 @@ test.group('Query Builder | leftJoin', (group) => { }) test('add query leftJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1470,7 +1526,7 @@ test.group('Query Builder | leftJoin', (group) => { .leftJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .leftJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1480,7 +1536,7 @@ test.group('Query Builder | leftJoin', (group) => { }) test('add query leftJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1489,7 +1545,7 @@ test.group('Query Builder | leftJoin', (group) => { .leftJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .leftJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1499,7 +1555,7 @@ test.group('Query Builder | leftJoin', (group) => { }) test('add query leftJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1510,7 +1566,7 @@ test.group('Query Builder | leftJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .leftJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1522,7 +1578,7 @@ test.group('Query Builder | leftJoin', (group) => { }) test('add query leftJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1531,9 +1587,9 @@ test.group('Query Builder | leftJoin', (group) => { .leftJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .leftJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .leftJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1551,7 +1607,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { }) test('add query leftOuterJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1560,7 +1616,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { .leftOuterJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .leftOuterJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1570,7 +1626,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { }) test('add query leftOuterJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1579,7 +1635,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { .leftOuterJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .leftOuterJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1589,7 +1645,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { }) test('add query leftOuterJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1600,7 +1656,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .leftOuterJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1612,7 +1668,7 @@ test.group('Query Builder | leftOuterJoin', (group) => { }) test('add query leftOuterJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1621,9 +1677,9 @@ test.group('Query Builder | leftOuterJoin', (group) => { .leftOuterJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .leftOuterJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .leftOuterJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1641,7 +1697,7 @@ test.group('Query Builder | rightJoin', (group) => { }) test('add query rightJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1650,7 +1706,7 @@ test.group('Query Builder | rightJoin', (group) => { .rightJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .rightJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1660,7 +1716,7 @@ test.group('Query Builder | rightJoin', (group) => { }) test('add query rightJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1669,7 +1725,7 @@ test.group('Query Builder | rightJoin', (group) => { .rightJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .rightJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1679,7 +1735,7 @@ test.group('Query Builder | rightJoin', (group) => { }) test('add query rightJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1690,7 +1746,7 @@ test.group('Query Builder | rightJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .rightJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1702,7 +1758,7 @@ test.group('Query Builder | rightJoin', (group) => { }) test('add query rightJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1711,9 +1767,9 @@ test.group('Query Builder | rightJoin', (group) => { .rightJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .rightJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .rightJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1731,7 +1787,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { }) test('add query rightOuterJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1740,7 +1796,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { .rightOuterJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .rightOuterJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1750,7 +1806,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { }) test('add query rightOuterJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1759,7 +1815,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { .rightOuterJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .rightOuterJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1769,7 +1825,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { }) test('add query rightOuterJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1780,7 +1836,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .rightOuterJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1792,7 +1848,7 @@ test.group('Query Builder | rightOuterJoin', (group) => { }) test('add query rightOuterJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1801,9 +1857,9 @@ test.group('Query Builder | rightOuterJoin', (group) => { .rightOuterJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .rightOuterJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .rightOuterJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1821,7 +1877,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { }) test('add query fullOuterJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1830,7 +1886,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { .fullOuterJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .fullOuterJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1840,7 +1896,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { }) test('add query fullOuterJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1849,7 +1905,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { .fullOuterJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .fullOuterJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1859,7 +1915,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { }) test('add query fullOuterJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1870,7 +1926,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .fullOuterJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1882,7 +1938,7 @@ test.group('Query Builder | fullOuterJoin', (group) => { }) test('add query fullOuterJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1891,9 +1947,9 @@ test.group('Query Builder | fullOuterJoin', (group) => { .fullOuterJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .fullOuterJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .fullOuterJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -1911,7 +1967,7 @@ test.group('Query Builder | crossJoin', (group) => { }) test('add query crossJoin', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1920,7 +1976,7 @@ test.group('Query Builder | crossJoin', (group) => { .crossJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .crossJoin('profiles', 'users.id', 'profiles.user_id') .toSQL() @@ -1930,7 +1986,7 @@ test.group('Query Builder | crossJoin', (group) => { }) test('add query crossJoin with operator', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1939,7 +1995,7 @@ test.group('Query Builder | crossJoin', (group) => { .crossJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .crossJoin('profiles', 'users.id', '!=', 'profiles.user_id') .toSQL() @@ -1949,7 +2005,7 @@ test.group('Query Builder | crossJoin', (group) => { }) test('add query crossJoin using join callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1960,7 +2016,7 @@ test.group('Query Builder | crossJoin', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .crossJoin('profiles', (builder) => { builder.on('users.id', 'profiles.user_id') @@ -1972,7 +2028,7 @@ test.group('Query Builder | crossJoin', (group) => { }) test('add query crossJoin as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -1981,9 +2037,9 @@ test.group('Query Builder | crossJoin', (group) => { .crossJoin('profiles', 'profiles.type', getRawQueryBuilder(connection, '?', ['social'])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .crossJoin('profiles', 'profiles.type', connection.client!.raw('?', ['social'])) + .crossJoin('profiles', 'profiles.type', connection.getWriteClient().raw('?', ['social'])) .toSQL() assert.equal(sql, knexSql) @@ -2001,7 +2057,7 @@ test.group('Query Builder | joinRaw', (group) => { }) test('add join as a raw join', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2010,7 +2066,7 @@ test.group('Query Builder | joinRaw', (group) => { .joinRaw('natural full join table1') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .joinRaw('natural full join table1') .toSQL() @@ -2020,7 +2076,7 @@ test.group('Query Builder | joinRaw', (group) => { }) test('add join as a raw join by passing the raw query output', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2029,7 +2085,7 @@ test.group('Query Builder | joinRaw', (group) => { .joinRaw(getRawQueryBuilder(connection, 'natural full join table1')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .joinRaw('natural full join table1') .toSQL() @@ -2049,7 +2105,7 @@ test.group('Query Builder | distinct', (group) => { }) test('define distinct columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2058,7 +2114,7 @@ test.group('Query Builder | distinct', (group) => { .distinct('name', 'age') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .distinct('name', 'age') .toSQL() @@ -2078,7 +2134,7 @@ test.group('Query Builder | groupBy', (group) => { }) test('define group by columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2087,7 +2143,7 @@ test.group('Query Builder | groupBy', (group) => { .groupBy('name', 'age') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .groupBy('name', 'age') .toSQL() @@ -2107,7 +2163,7 @@ test.group('Query Builder | groupByRaw', (group) => { }) test('define group by columns as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2116,7 +2172,7 @@ test.group('Query Builder | groupByRaw', (group) => { .groupByRaw('select (age) from user_profiles') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .groupByRaw('select (age) from user_profiles') .toSQL() @@ -2136,7 +2192,7 @@ test.group('Query Builder | orderBy', (group) => { }) test('define order by columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2145,7 +2201,7 @@ test.group('Query Builder | orderBy', (group) => { .orderBy('name') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orderBy('name') .toSQL() @@ -2155,7 +2211,7 @@ test.group('Query Builder | orderBy', (group) => { }) test('define order by columns with explicit direction', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2164,7 +2220,7 @@ test.group('Query Builder | orderBy', (group) => { .orderBy('name', 'desc') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orderBy('name', 'desc') .toSQL() @@ -2174,7 +2230,7 @@ test.group('Query Builder | orderBy', (group) => { }) test('define order by columns as an array of objects', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2183,7 +2239,7 @@ test.group('Query Builder | orderBy', (group) => { .orderBy([{ column: 'name', order: 'desc' }, { column: 'age', order: 'desc' }]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orderBy([{ column: 'name', order: 'desc' }, { column: 'age', order: 'desc' }]) .toSQL() @@ -2203,7 +2259,7 @@ test.group('Query Builder | orderByRaw', (group) => { }) test('define order by columns as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2212,7 +2268,7 @@ test.group('Query Builder | orderByRaw', (group) => { .orderByRaw('col DESC NULLS LAST') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orderByRaw('col DESC NULLS LAST') .toSQL() @@ -2232,7 +2288,7 @@ test.group('Query Builder | offset', (group) => { }) test('define select offset', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2241,7 +2297,7 @@ test.group('Query Builder | offset', (group) => { .offset(10) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .offset(10) .toSQL() @@ -2261,7 +2317,7 @@ test.group('Query Builder | limit', (group) => { }) test('define results limit', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2270,7 +2326,7 @@ test.group('Query Builder | limit', (group) => { .limit(10) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .limit(10) .toSQL() @@ -2290,7 +2346,7 @@ test.group('Query Builder | union', (group) => { }) test('define union query as a callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2301,7 +2357,7 @@ test.group('Query Builder | union', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .union((builder) => { builder.select('*').from('users').whereNull('first_name') @@ -2313,7 +2369,7 @@ test.group('Query Builder | union', (group) => { }) test('define union query as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2322,9 +2378,9 @@ test.group('Query Builder | union', (group) => { .union(getQueryBuilder(connection).from('users').whereNull('first_name')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .union(connection.client!.from('users').whereNull('first_name')) + .union(connection.getWriteClient().from('users').whereNull('first_name')) .toSQL() assert.equal(sql, knexSql) @@ -2332,7 +2388,7 @@ test.group('Query Builder | union', (group) => { }) test('define union query as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2341,9 +2397,9 @@ test.group('Query Builder | union', (group) => { .union(getRawQueryBuilder(connection, 'select * from users where first_name is null')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .union(connection.client!.raw('select * from users where first_name is null')) + .union(connection.getWriteClient().raw('select * from users where first_name is null')) .toSQL() assert.equal(sql, knexSql) @@ -2351,7 +2407,7 @@ test.group('Query Builder | union', (group) => { }) test('define union query as an array of callbacks', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2362,7 +2418,7 @@ test.group('Query Builder | union', (group) => { }]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .union([(builder) => { builder.select('*').from('users').whereNull('first_name') @@ -2374,7 +2430,7 @@ test.group('Query Builder | union', (group) => { }) test('define union query as an array of subqueries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2383,9 +2439,9 @@ test.group('Query Builder | union', (group) => { .union([getQueryBuilder(connection).from('users').whereNull('first_name')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .union([connection.client!.from('users').whereNull('first_name')]) + .union([connection.getWriteClient().from('users').whereNull('first_name')]) .toSQL() assert.equal(sql, knexSql) @@ -2393,7 +2449,7 @@ test.group('Query Builder | union', (group) => { }) test('define union query as an array of raw queries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2402,9 +2458,9 @@ test.group('Query Builder | union', (group) => { .union([getRawQueryBuilder(connection, 'select * from users where first_name is null')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .union([connection.client!.raw('select * from users where first_name is null')]) + .union([connection.getWriteClient().raw('select * from users where first_name is null')]) .toSQL() assert.equal(sql, knexSql) @@ -2422,7 +2478,7 @@ test.group('Query Builder | unionAll', (group) => { }) test('define unionAll query as a callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2433,7 +2489,7 @@ test.group('Query Builder | unionAll', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .unionAll((builder) => { builder.select('*').from('users').whereNull('first_name') @@ -2445,7 +2501,7 @@ test.group('Query Builder | unionAll', (group) => { }) test('define unionAll query as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2454,9 +2510,9 @@ test.group('Query Builder | unionAll', (group) => { .unionAll(getQueryBuilder(connection).from('users').whereNull('first_name')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .unionAll(connection.client!.from('users').whereNull('first_name')) + .unionAll(connection.getWriteClient().from('users').whereNull('first_name')) .toSQL() assert.equal(sql, knexSql) @@ -2464,7 +2520,7 @@ test.group('Query Builder | unionAll', (group) => { }) test('define unionAll query as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2473,9 +2529,9 @@ test.group('Query Builder | unionAll', (group) => { .unionAll(getRawQueryBuilder(connection, 'select * from users where first_name is null')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .unionAll(connection.client!.raw('select * from users where first_name is null')) + .unionAll(connection.getWriteClient().raw('select * from users where first_name is null')) .toSQL() assert.equal(sql, knexSql) @@ -2483,7 +2539,7 @@ test.group('Query Builder | unionAll', (group) => { }) test('define unionAll query as an array of callbacks', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2494,7 +2550,7 @@ test.group('Query Builder | unionAll', (group) => { }]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .unionAll([(builder) => { builder.select('*').from('users').whereNull('first_name') @@ -2506,7 +2562,7 @@ test.group('Query Builder | unionAll', (group) => { }) test('define unionAll query as an array of subqueries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2515,9 +2571,9 @@ test.group('Query Builder | unionAll', (group) => { .unionAll([getQueryBuilder(connection).from('users').whereNull('first_name')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .unionAll([connection.client!.from('users').whereNull('first_name')]) + .unionAll([connection.getWriteClient().from('users').whereNull('first_name')]) .toSQL() assert.equal(sql, knexSql) @@ -2525,7 +2581,7 @@ test.group('Query Builder | unionAll', (group) => { }) test('define unionAll query as an array of raw queries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2534,9 +2590,9 @@ test.group('Query Builder | unionAll', (group) => { .unionAll([getRawQueryBuilder(connection, 'select * from users where first_name is null')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .unionAll([connection.client!.raw('select * from users where first_name is null')]) + .unionAll([connection.getWriteClient().raw('select * from users where first_name is null')]) .toSQL() assert.equal(sql, knexSql) @@ -2554,7 +2610,7 @@ test.group('Query Builder | forUpdate', (group) => { }) test('define FOR UPDATE lock', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2563,7 +2619,7 @@ test.group('Query Builder | forUpdate', (group) => { .forUpdate() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .forUpdate() .toSQL() @@ -2573,7 +2629,7 @@ test.group('Query Builder | forUpdate', (group) => { }) test('define FOR UPDATE lock with additional tables (pg only)', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2582,7 +2638,7 @@ test.group('Query Builder | forUpdate', (group) => { .forUpdate('profiles') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .forUpdate('profiles') .toSQL() @@ -2602,7 +2658,7 @@ test.group('Query Builder | forShare', (group) => { }) test('define FOR SHARE lock', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2611,7 +2667,7 @@ test.group('Query Builder | forShare', (group) => { .forShare() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .forShare() .toSQL() @@ -2621,7 +2677,7 @@ test.group('Query Builder | forShare', (group) => { }) test('define FOR SHARE lock with additional tables (pg only)', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2630,7 +2686,7 @@ test.group('Query Builder | forShare', (group) => { .forShare('profiles') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .forShare('profiles') .toSQL() @@ -2651,7 +2707,7 @@ if (['pg', 'mysql'].includes(process.env.DB!)) { }) test('add no wait instruction to the query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2661,7 +2717,7 @@ if (['pg', 'mysql'].includes(process.env.DB!)) { .noWait() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .forShare() .noWait() @@ -2682,7 +2738,7 @@ if (['pg', 'mysql'].includes(process.env.DB!)) { }) test('add skip locked instruction to the query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2692,7 +2748,7 @@ if (['pg', 'mysql'].includes(process.env.DB!)) { .skipLocked() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .forShare() .skipLocked() @@ -2714,7 +2770,7 @@ test.group('Query Builder | having', (group) => { }) test('add having clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2723,7 +2779,7 @@ test.group('Query Builder | having', (group) => { .having('count', '>', 10) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .having('count', '>', 10) .toSQL() @@ -2733,7 +2789,7 @@ test.group('Query Builder | having', (group) => { }) test('add having clause as a callback', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2744,7 +2800,7 @@ test.group('Query Builder | having', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .having((builder) => { builder.where('id', '>', 10) @@ -2756,9 +2812,9 @@ test.group('Query Builder | having', (group) => { }) test('add having clause value being a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() - const ref = connection.client!.ref.bind(connection.client) + const ref = connection.getWriteClient().ref.bind(connection.getWriteClient()) const db = getQueryBuilder(connection) const { sql, bindings } = db @@ -2770,12 +2826,12 @@ test.group('Query Builder | having', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .having( 'user_id', '=', - connection.client!.raw(`(select ${ref('user_id')} from ${ref('accounts')})`), + connection.getWriteClient().raw(`(select ${ref('user_id')} from ${ref('accounts')})`), ) .toSQL() @@ -2784,7 +2840,7 @@ test.group('Query Builder | having', (group) => { }) test('add having clause value being a sub query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2797,12 +2853,12 @@ test.group('Query Builder | having', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .having( 'user_id', '=', - connection.client!.select('id').from('accounts'), + connection.getWriteClient().select('id').from('accounts'), ) .toSQL() @@ -2811,18 +2867,18 @@ test.group('Query Builder | having', (group) => { }) test('add having clause as a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) const { sql, bindings } = db .from('users') - .having(getRawQueryBuilder(connection, 'sum(likes) > ?', [200])) + .havingRaw(getRawQueryBuilder(connection, 'sum(likes) > ?', [200])) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .having(connection.client!.raw('sum(likes) > ?', [200])) + .having(connection.getWriteClient().raw('sum(likes) > ?', [200])) .toSQL() assert.equal(sql, knexSql) @@ -2830,7 +2886,7 @@ test.group('Query Builder | having', (group) => { }) test('add or having clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2840,7 +2896,7 @@ test.group('Query Builder | having', (group) => { .orHaving('total', '>', 10) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .having('count', '>', 10) .orHaving('total', '>', 10) @@ -2861,7 +2917,7 @@ test.group('Query Builder | havingIn', (group) => { }) test('add having in clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2870,7 +2926,7 @@ test.group('Query Builder | havingIn', (group) => { .havingIn('id', [10, 20]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingIn('id', [10, 20]) .toSQL() @@ -2880,7 +2936,7 @@ test.group('Query Builder | havingIn', (group) => { }) test('add having in clause values as subqueries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2889,9 +2945,9 @@ test.group('Query Builder | havingIn', (group) => { .havingIn('id', [getQueryBuilder(connection).select('id').from('accounts')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .havingIn('id', [connection.client!.select('id').from('accounts') as any]) + .havingIn('id', [connection.getWriteClient().select('id').from('accounts') as any]) .toSQL() assert.equal(sql, knexSql) @@ -2899,7 +2955,7 @@ test.group('Query Builder | havingIn', (group) => { }) test('add having in clause values as raw queries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2908,9 +2964,9 @@ test.group('Query Builder | havingIn', (group) => { .havingIn('id', [getRawQueryBuilder(connection, 'select id from accounts')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .havingIn('id', [connection.client!.raw('select id from accounts')]) + .havingIn('id', [connection.getWriteClient().raw('select id from accounts')]) .toSQL() assert.equal(sql, knexSql) @@ -2918,7 +2974,7 @@ test.group('Query Builder | havingIn', (group) => { }) test('add having in clause values as query callbacks', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const fn = (builder) => { @@ -2931,7 +2987,7 @@ test.group('Query Builder | havingIn', (group) => { .havingIn('id', fn) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingIn('id', fn as any) .toSQL() @@ -2941,7 +2997,7 @@ test.group('Query Builder | havingIn', (group) => { }) test('add or having in clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2951,7 +3007,7 @@ test.group('Query Builder | havingIn', (group) => { .orHavingIn('id', [10, 30]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingIn('id', [10, 20]) ['orHavingIn']('id', [10, 30]) @@ -2972,7 +3028,7 @@ test.group('Query Builder | havingNotIn', (group) => { }) test('add not having in clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -2981,7 +3037,7 @@ test.group('Query Builder | havingNotIn', (group) => { .havingNotIn('id', [10, 20]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotIn']('id', [10, 20]) .toSQL() @@ -2991,7 +3047,7 @@ test.group('Query Builder | havingNotIn', (group) => { }) test('add having in clause values as subqueries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3000,9 +3056,9 @@ test.group('Query Builder | havingNotIn', (group) => { .havingNotIn('id', [getQueryBuilder(connection).select('id').from('accounts')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - ['havingNotIn']('id', [connection.client!.select('id').from('accounts') as any]) + ['havingNotIn']('id', [connection.getWriteClient().select('id').from('accounts') as any]) .toSQL() assert.equal(sql, knexSql) @@ -3010,7 +3066,7 @@ test.group('Query Builder | havingNotIn', (group) => { }) test('add having in clause values as raw queries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3019,9 +3075,9 @@ test.group('Query Builder | havingNotIn', (group) => { .havingNotIn('id', [getRawQueryBuilder(connection, 'select id from accounts')]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - ['havingNotIn']('id', [connection.client!.raw('select id from accounts')]) + ['havingNotIn']('id', [connection.getWriteClient().raw('select id from accounts')]) .toSQL() assert.equal(sql, knexSql) @@ -3029,7 +3085,7 @@ test.group('Query Builder | havingNotIn', (group) => { }) test('add having in clause values as query callbacks', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const fn = (builder) => { @@ -3042,7 +3098,7 @@ test.group('Query Builder | havingNotIn', (group) => { .havingNotIn('id', fn) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotIn']('id', fn as any) .toSQL() @@ -3052,7 +3108,7 @@ test.group('Query Builder | havingNotIn', (group) => { }) test('add or having in clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3062,7 +3118,7 @@ test.group('Query Builder | havingNotIn', (group) => { .orHavingNotIn('id', [10, 30]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotIn']('id', [10, 20]) ['orHavingNotIn']('id', [10, 30]) @@ -3083,7 +3139,7 @@ test.group('Query Builder | havingNull', (group) => { }) test('add having null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3092,7 +3148,7 @@ test.group('Query Builder | havingNull', (group) => { .havingNull('deleted_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNull']('deleted_at') .toSQL() @@ -3102,7 +3158,7 @@ test.group('Query Builder | havingNull', (group) => { }) test('add or having null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3112,7 +3168,7 @@ test.group('Query Builder | havingNull', (group) => { .orHavingNull('updated_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNull']('deleted_at') .orHavingNull('updated_at') @@ -3133,7 +3189,7 @@ test.group('Query Builder | havingNotNull', (group) => { }) test('add having null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3142,7 +3198,7 @@ test.group('Query Builder | havingNotNull', (group) => { .havingNotNull('deleted_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotNull']('deleted_at') .toSQL() @@ -3152,7 +3208,7 @@ test.group('Query Builder | havingNotNull', (group) => { }) test('add or having not null clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3162,7 +3218,7 @@ test.group('Query Builder | havingNotNull', (group) => { .orHavingNotNull('updated_at') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotNull']('deleted_at') .orHavingNotNull('updated_at') @@ -3183,7 +3239,7 @@ test.group('Query Builder | havingExists', (group) => { }) test('add having exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3194,7 +3250,7 @@ test.group('Query Builder | havingExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingExists']((builder) => { builder.select('*').from('accounts').whereRaw('users.account_id = accounts.id') @@ -3206,7 +3262,7 @@ test.group('Query Builder | havingExists', (group) => { }) test('add having exists clause as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3215,9 +3271,9 @@ test.group('Query Builder | havingExists', (group) => { .havingExists(getQueryBuilder(connection).select('*').from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - ['havingExists'](connection.client!.select('*').from('accounts')) + ['havingExists'](connection.getWriteClient().select('*').from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -3225,7 +3281,7 @@ test.group('Query Builder | havingExists', (group) => { }) test('add or having exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3239,7 +3295,7 @@ test.group('Query Builder | havingExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingExists']((builder) => { builder.select('*').from('accounts') @@ -3264,7 +3320,7 @@ test.group('Query Builder | havingNotExists', (group) => { }) test('add having not exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3275,7 +3331,7 @@ test.group('Query Builder | havingNotExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotExists']((builder) => { builder.select('*').from('accounts').whereRaw('users.account_id = accounts.id') @@ -3287,7 +3343,7 @@ test.group('Query Builder | havingNotExists', (group) => { }) test('add having not exists clause as a subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3296,9 +3352,9 @@ test.group('Query Builder | havingNotExists', (group) => { .havingNotExists(getQueryBuilder(connection).select('*').from('accounts')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - ['havingNotExists'](connection.client!.select('*').from('accounts')) + ['havingNotExists'](connection.getWriteClient().select('*').from('accounts')) .toSQL() assert.equal(sql, knexSql) @@ -3306,7 +3362,7 @@ test.group('Query Builder | havingNotExists', (group) => { }) test('add or having not exists clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3320,7 +3376,7 @@ test.group('Query Builder | havingNotExists', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') ['havingNotExists']((builder) => { builder.select('*').from('accounts') @@ -3345,7 +3401,7 @@ test.group('Query Builder | havingBetween', (group) => { }) test('add having between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3354,7 +3410,7 @@ test.group('Query Builder | havingBetween', (group) => { .havingBetween('id', [5, 10]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingBetween('id', [5, 10]) .toSQL() @@ -3364,7 +3420,7 @@ test.group('Query Builder | havingBetween', (group) => { }) test('add having between clause with raw values', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3376,11 +3432,11 @@ test.group('Query Builder | havingBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingBetween('id', [ - connection.client!.raw('select min(id) from users;'), - connection.client!.raw('select max(id) from users;'), + connection.getWriteClient().raw('select min(id) from users;'), + connection.getWriteClient().raw('select max(id) from users;'), ]) .toSQL() @@ -3389,7 +3445,7 @@ test.group('Query Builder | havingBetween', (group) => { }) test('add having between clause with subqueries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3401,11 +3457,11 @@ test.group('Query Builder | havingBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingBetween('id', [ - connection.client!.select('id') as any, - connection.client!.select('id') as any, + connection.getWriteClient().select('id') as any, + connection.getWriteClient().select('id') as any, ]) .toSQL() @@ -3414,7 +3470,7 @@ test.group('Query Builder | havingBetween', (group) => { }) test('add or having between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3424,7 +3480,7 @@ test.group('Query Builder | havingBetween', (group) => { .orHavingBetween('id', [18, 23]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingBetween('id', [5, 10]) .orHavingBetween('id', [18, 23]) @@ -3445,7 +3501,7 @@ test.group('Query Builder | havingNotBetween', (group) => { }) test('add having not between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3454,7 +3510,7 @@ test.group('Query Builder | havingNotBetween', (group) => { .havingNotBetween('id', [5, 10]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingNotBetween('id', [5, 10]) .toSQL() @@ -3464,7 +3520,7 @@ test.group('Query Builder | havingNotBetween', (group) => { }) test('add having not between clause with raw values', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3476,11 +3532,11 @@ test.group('Query Builder | havingNotBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingNotBetween('id', [ - connection.client!.raw('select min(id) from users;'), - connection.client!.raw('select max(id) from users;'), + connection.getWriteClient().raw('select min(id) from users;'), + connection.getWriteClient().raw('select max(id) from users;'), ]) .toSQL() @@ -3489,7 +3545,7 @@ test.group('Query Builder | havingNotBetween', (group) => { }) test('add having not between clause with subqueries', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3501,11 +3557,11 @@ test.group('Query Builder | havingNotBetween', (group) => { ]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingNotBetween('id', [ - connection.client!.select('id') as any, - connection.client!.select('id') as any, + connection.getWriteClient().select('id') as any, + connection.getWriteClient().select('id') as any, ]) .toSQL() @@ -3514,7 +3570,7 @@ test.group('Query Builder | havingNotBetween', (group) => { }) test('add or having not between clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3524,7 +3580,7 @@ test.group('Query Builder | havingNotBetween', (group) => { .orHavingNotBetween('id', [18, 23]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingNotBetween('id', [5, 10]) .orHavingNotBetween('id', [18, 23]) @@ -3545,7 +3601,7 @@ test.group('Query Builder | havingRaw', (group) => { }) test('add having raw clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3554,7 +3610,7 @@ test.group('Query Builder | havingRaw', (group) => { .havingRaw('id = ?', [1]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingRaw('id = ?', [1]) .toSQL() @@ -3564,7 +3620,7 @@ test.group('Query Builder | havingRaw', (group) => { }) test('add having raw clause without bindings', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3573,7 +3629,7 @@ test.group('Query Builder | havingRaw', (group) => { .havingRaw('id = 1') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingRaw('id = 1') .toSQL() @@ -3583,7 +3639,7 @@ test.group('Query Builder | havingRaw', (group) => { }) test('add having raw clause with object of bindings', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3592,7 +3648,7 @@ test.group('Query Builder | havingRaw', (group) => { .havingRaw('id = :id', { id: 1 }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingRaw('id = :id', { id: 1 }) .toSQL() @@ -3602,7 +3658,7 @@ test.group('Query Builder | havingRaw', (group) => { }) test('add having raw clause from a raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3611,9 +3667,9 @@ test.group('Query Builder | havingRaw', (group) => { .havingRaw(getRawQueryBuilder(connection, 'select id from accounts;')) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') - .havingRaw(connection.client!.raw('select id from accounts;')) + .havingRaw(connection.getWriteClient().raw('select id from accounts;')) .toSQL() assert.equal(sql, knexSql) @@ -3621,7 +3677,7 @@ test.group('Query Builder | havingRaw', (group) => { }) test('add or having raw clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3631,7 +3687,7 @@ test.group('Query Builder | havingRaw', (group) => { .orHavingRaw('id = ?', [2]) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .havingRaw('id = ?', [1]) .orHavingRaw('id = ?', [2]) @@ -3652,7 +3708,7 @@ test.group('Query Builder | clearSelect', (group) => { }) test('clear selected columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3662,7 +3718,7 @@ test.group('Query Builder | clearSelect', (group) => { .clearSelect() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .select('id', 'username') .clearSelect() @@ -3683,7 +3739,7 @@ test.group('Query Builder | clearWhere', (group) => { }) test('clear where clauses', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3693,7 +3749,7 @@ test.group('Query Builder | clearWhere', (group) => { .clearWhere() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .where('username', 'virk') .clearWhere() @@ -3714,7 +3770,7 @@ test.group('Query Builder | clearOrder', (group) => { }) test('clear order by columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3724,7 +3780,7 @@ test.group('Query Builder | clearOrder', (group) => { .clearOrder() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .orderBy('id', 'desc') .clearOrder() @@ -3745,7 +3801,7 @@ test.group('Query Builder | clearHaving', (group) => { }) test('clear having clause', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3755,7 +3811,7 @@ test.group('Query Builder | clearHaving', (group) => { .clearHaving() .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .having('id', '>', 10) .clearHaving() @@ -3776,7 +3832,7 @@ test.group('Query Builder | count', (group) => { }) test('count all rows', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3785,7 +3841,7 @@ test.group('Query Builder | count', (group) => { .count('*', 'total') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .count('*', { as: 'total' }) .toSQL() @@ -3795,7 +3851,7 @@ test.group('Query Builder | count', (group) => { }) test('count multiple rows', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3804,7 +3860,7 @@ test.group('Query Builder | count', (group) => { .count({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .count({ u: 'username', e: 'email' }) .toSQL() @@ -3814,7 +3870,7 @@ test.group('Query Builder | count', (group) => { }) test('count by raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3823,10 +3879,10 @@ test.group('Query Builder | count', (group) => { .count(getRawQueryBuilder(connection, 'select * from profiles where is_verified = ?', [true]), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .count({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -3835,7 +3891,7 @@ test.group('Query Builder | count', (group) => { }) test('count by subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3844,10 +3900,10 @@ test.group('Query Builder | count', (group) => { .count(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .count({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -3856,7 +3912,7 @@ test.group('Query Builder | count', (group) => { }) test('count by raw query on multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3868,10 +3924,10 @@ test.group('Query Builder | count', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .count({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -3881,7 +3937,7 @@ test.group('Query Builder | count', (group) => { }) test('count by subquery on multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3893,10 +3949,10 @@ test.group('Query Builder | count', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .count({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() @@ -3916,7 +3972,7 @@ test.group('Query Builder | countDistinct', (group) => { }) test('count all rows', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3925,7 +3981,7 @@ test.group('Query Builder | countDistinct', (group) => { .countDistinct('*', 'total') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .countDistinct('*', { as: 'total' }) .toSQL() @@ -3935,7 +3991,7 @@ test.group('Query Builder | countDistinct', (group) => { }) test('count multiple rows', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3944,7 +4000,7 @@ test.group('Query Builder | countDistinct', (group) => { .countDistinct({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .countDistinct({ u: 'username', e: 'email' }) .toSQL() @@ -3954,7 +4010,7 @@ test.group('Query Builder | countDistinct', (group) => { }) test('count by raw query', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3966,10 +4022,10 @@ test.group('Query Builder | countDistinct', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .countDistinct({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -3978,7 +4034,7 @@ test.group('Query Builder | countDistinct', (group) => { }) test('count by subquery', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -3987,10 +4043,10 @@ test.group('Query Builder | countDistinct', (group) => { .countDistinct(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .countDistinct({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -3999,7 +4055,7 @@ test.group('Query Builder | countDistinct', (group) => { }) test('count by raw query on multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4011,10 +4067,10 @@ test.group('Query Builder | countDistinct', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .countDistinct({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -4024,7 +4080,7 @@ test.group('Query Builder | countDistinct', (group) => { }) test('count by subquery on multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4036,10 +4092,10 @@ test.group('Query Builder | countDistinct', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .countDistinct({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() @@ -4059,7 +4115,7 @@ test.group('Query Builder | min', (group) => { }) test('use min function', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4068,7 +4124,7 @@ test.group('Query Builder | min', (group) => { .min('*', 'smallest') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .min('*', { as: 'smallest' }) .toSQL() @@ -4078,7 +4134,7 @@ test.group('Query Builder | min', (group) => { }) test('use min function for multiple times', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4087,7 +4143,7 @@ test.group('Query Builder | min', (group) => { .min({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .min({ u: 'username', e: 'email' }) .toSQL() @@ -4097,7 +4153,7 @@ test.group('Query Builder | min', (group) => { }) test('use raw queries to compute min', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4109,10 +4165,10 @@ test.group('Query Builder | min', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .min({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -4121,7 +4177,7 @@ test.group('Query Builder | min', (group) => { }) test('use subqueries to compute min', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4130,10 +4186,10 @@ test.group('Query Builder | min', (group) => { .min(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .min({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -4142,7 +4198,7 @@ test.group('Query Builder | min', (group) => { }) test('use raw query to compute min with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4154,10 +4210,10 @@ test.group('Query Builder | min', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .min({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -4167,7 +4223,7 @@ test.group('Query Builder | min', (group) => { }) test('use subquery to compute min with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4179,10 +4235,10 @@ test.group('Query Builder | min', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .min({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() @@ -4202,7 +4258,7 @@ test.group('Query Builder | max', (group) => { }) test('use max function', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4211,7 +4267,7 @@ test.group('Query Builder | max', (group) => { .max('*', 'biggest') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .max('*', { as: 'biggest' }) .toSQL() @@ -4221,7 +4277,7 @@ test.group('Query Builder | max', (group) => { }) test('use max function for multiple times', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4230,7 +4286,7 @@ test.group('Query Builder | max', (group) => { .max({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .max({ u: 'username', e: 'email' }) .toSQL() @@ -4240,7 +4296,7 @@ test.group('Query Builder | max', (group) => { }) test('use raw queries to compute max', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4252,10 +4308,10 @@ test.group('Query Builder | max', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .max({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -4264,7 +4320,7 @@ test.group('Query Builder | max', (group) => { }) test('use subqueries to compute max', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4273,10 +4329,10 @@ test.group('Query Builder | max', (group) => { .max(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .max({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -4285,7 +4341,7 @@ test.group('Query Builder | max', (group) => { }) test('use raw query to compute max with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4297,10 +4353,10 @@ test.group('Query Builder | max', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .max({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -4310,7 +4366,7 @@ test.group('Query Builder | max', (group) => { }) test('use subquery to compute max with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4322,10 +4378,10 @@ test.group('Query Builder | max', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .max({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() @@ -4345,7 +4401,7 @@ test.group('Query Builder | sum', (group) => { }) test('use sum function', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4354,7 +4410,7 @@ test.group('Query Builder | sum', (group) => { .sum('*', 'total') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .sum('*', { as: 'total' }) .toSQL() @@ -4364,7 +4420,7 @@ test.group('Query Builder | sum', (group) => { }) test('use sum function for multiple times', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4373,7 +4429,7 @@ test.group('Query Builder | sum', (group) => { .sum({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .sum({ u: 'username', e: 'email' }) .toSQL() @@ -4383,7 +4439,7 @@ test.group('Query Builder | sum', (group) => { }) test('use raw queries to compute sum', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4395,10 +4451,10 @@ test.group('Query Builder | sum', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .sum({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -4407,7 +4463,7 @@ test.group('Query Builder | sum', (group) => { }) test('use subqueries to compute sum', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4416,10 +4472,10 @@ test.group('Query Builder | sum', (group) => { .sum(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .sum({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -4428,7 +4484,7 @@ test.group('Query Builder | sum', (group) => { }) test('use raw query to compute sum with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4440,10 +4496,10 @@ test.group('Query Builder | sum', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .sum({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -4453,7 +4509,7 @@ test.group('Query Builder | sum', (group) => { }) test('use subquery to compute sum with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4465,10 +4521,10 @@ test.group('Query Builder | sum', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .sum({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() @@ -4488,7 +4544,7 @@ test.group('Query Builder | avg', (group) => { }) test('use avg function', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4497,7 +4553,7 @@ test.group('Query Builder | avg', (group) => { .avg('*', 'avg') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avg('*', { as: 'avg' }) .toSQL() @@ -4507,7 +4563,7 @@ test.group('Query Builder | avg', (group) => { }) test('use avg function for multiple times', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4516,7 +4572,7 @@ test.group('Query Builder | avg', (group) => { .avg({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avg({ u: 'username', e: 'email' }) .toSQL() @@ -4526,7 +4582,7 @@ test.group('Query Builder | avg', (group) => { }) test('use raw queries to compute avg', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4538,10 +4594,10 @@ test.group('Query Builder | avg', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avg({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -4550,7 +4606,7 @@ test.group('Query Builder | avg', (group) => { }) test('use subqueries to compute avg', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4559,10 +4615,10 @@ test.group('Query Builder | avg', (group) => { .avg(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avg({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -4571,7 +4627,7 @@ test.group('Query Builder | avg', (group) => { }) test('use raw query to compute avg with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4583,10 +4639,10 @@ test.group('Query Builder | avg', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avg({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -4596,7 +4652,7 @@ test.group('Query Builder | avg', (group) => { }) test('use subquery to compute avg with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4608,10 +4664,10 @@ test.group('Query Builder | avg', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avg({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() @@ -4631,7 +4687,7 @@ test.group('Query Builder | avgDistinct', (group) => { }) test('use avgDistinct function', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4640,7 +4696,7 @@ test.group('Query Builder | avgDistinct', (group) => { .avgDistinct('*', 'avgDistinct') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avgDistinct('*', { as: 'avgDistinct' }) .toSQL() @@ -4650,7 +4706,7 @@ test.group('Query Builder | avgDistinct', (group) => { }) test('use avgDistinct function for multiple times', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4659,7 +4715,7 @@ test.group('Query Builder | avgDistinct', (group) => { .avgDistinct({ u: 'username', e: 'email' }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avgDistinct({ u: 'username', e: 'email' }) .toSQL() @@ -4669,7 +4725,7 @@ test.group('Query Builder | avgDistinct', (group) => { }) test('use raw queries to compute avgDistinct', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4681,10 +4737,10 @@ test.group('Query Builder | avgDistinct', (group) => { ) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avgDistinct({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), }) .toSQL() @@ -4693,7 +4749,7 @@ test.group('Query Builder | avgDistinct', (group) => { }) test('use subqueries to compute avgDistinct', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4702,10 +4758,10 @@ test.group('Query Builder | avgDistinct', (group) => { .avgDistinct(getQueryBuilder(connection).where('is_verified', true).from('profiles'), 'u') .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avgDistinct({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), }) .toSQL() @@ -4714,7 +4770,7 @@ test.group('Query Builder | avgDistinct', (group) => { }) test('use raw query to compute avgDistinct with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4726,10 +4782,10 @@ test.group('Query Builder | avgDistinct', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avgDistinct({ - u: connection.client!.raw('select * from profiles where is_verified = ?', [true]), + u: connection.getWriteClient().raw('select * from profiles where is_verified = ?', [true]), e: 'email', }) .toSQL() @@ -4739,7 +4795,7 @@ test.group('Query Builder | avgDistinct', (group) => { }) test('use subquery to compute avgDistinct with multiple columns', (assert) => { - const connection = new Connection('primary', getConfig()) + const connection = new Connection('primary', getConfig(), getLogger()) connection.connect() const db = getQueryBuilder(connection) @@ -4751,10 +4807,10 @@ test.group('Query Builder | avgDistinct', (group) => { }) .toSQL() - const { sql: knexSql, bindings: knexBindings } = connection.client! + const { sql: knexSql, bindings: knexBindings } = connection.getWriteClient() .from('users') .avgDistinct({ - u: connection.client!.where('is_verified', true).from('profiles'), + u: connection.getWriteClient().where('is_verified', true).from('profiles'), e: 'email', }) .toSQL() diff --git a/test/transactions.spec.ts b/test/transactions.spec.ts new file mode 100644 index 00000000..3841a381 --- /dev/null +++ b/test/transactions.spec.ts @@ -0,0 +1,100 @@ +/* +* @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 test from 'japa' + +import { Connection } from '../src/Connection' +import { getConfig, setup, cleanup, resetTables, getLogger } from '../test-helpers' + +test.group('Transaction | query', (group) => { + group.before(async () => { + await setup() + }) + + group.after(async () => { + await cleanup() + }) + + group.afterEach(async () => { + await resetTables() + }) + + test('perform select query under a transaction', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const db = await connection.transaction() + const results = await db.query().from('users') + await db.commit() + + assert.isArray(results) + assert.lengthOf(results, 0) + }) + + test('commit insert', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const db = await connection.transaction() + await db.insertQuery().table('users').insert({ username: 'virk' }) + await db.commit() + + const results = await connection.query().from('users') + assert.isArray(results) + assert.lengthOf(results, 1) + assert.equal(results[0].username, 'virk') + }) + + test('rollback insert', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + const db = await connection.transaction() + await db.insertQuery().table('users').insert({ username: 'virk' }) + await db.rollback() + + const results = await connection.query().from('users') + assert.isArray(results) + assert.lengthOf(results, 0) + }) + + test('perform nested transactions with save points', async (assert) => { + const connection = new Connection('primary', getConfig(), getLogger()) + connection.connect() + + /** + * Transaction 1 + */ + const db = await connection.transaction() + await db.insertQuery().table('users').insert({ username: 'virk' }) + + /** + * Transaction 2: Save point + */ + const db1 = await db.transaction() + await db1.insertQuery().table('users').insert({ username: 'nikk' }) + + /** + * Rollback 2 + */ + await db1.rollback() + + /** + * Commit first + */ + await db.commit() + + const results = await connection.query().from('users') + assert.isArray(results) + assert.lengthOf(results, 1) + assert.equal(results[0].username, 'virk') + }) +})