knex 1.0.2 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # Master (Unreleased)
2
2
 
3
+ # 1.0.5 - 05 March, 2022
4
+
5
+ ### New features:
6
+
7
+ - Override knexfile options with CLI options #4047
8
+
9
+ ### Bug fixes:
10
+
11
+ - Stringify json value in update #5063
12
+ - Fix isModuleType() for yarn #4447
13
+ - Wrapped Unions Fixes #5072
14
+ - SQLite: Fix @vscode-sqlite3 error message #5081
15
+ - CLI: Fix completed migration listing #5060
16
+
17
+ ### Typings:
18
+
19
+ - Make default generic parameters of `Knex` match the generic parameter types of `knex` #5021
20
+ - Update knex types for TS 4.7 #5095
21
+
22
+ # 1.0.4 - 13 March, 2022
23
+
24
+ ### New features:
25
+
26
+ - Add whereLike functions #5044
27
+
28
+ ### Bug fixes:
29
+
30
+ - Fix orWhereJsonPath clause #5022
31
+ - Subquery in on clause missing parenthesis #5049
32
+ - Rework Union Wrapping #5030
33
+ - Oracle: Fix batch inserts with DEFAULT values with OracleDB #2592 #5037
34
+
35
+ ### Typings:
36
+
37
+ - Fix types for "returning" methods #5031
38
+ - createTableLike callback should be optional #5055
39
+
40
+ ### Documentation:
41
+
42
+ - Website URL changed to https://knex.github.io/documentation/
43
+
44
+ # 1.0.3 - 11 February, 2022
45
+
46
+ ### Bug fixes:
47
+
48
+ - Fix error message for missing migration files #4937
49
+ - Add withMaterialized and withNotMaterialized to method-constants #5009
50
+ - PostgreSQL: Fix whereJsonPath queries #5011
51
+ - PostgreSQL: Fix delete joins #5016
52
+ - CockroachDB: Fix whereJsonPath queries #5011
53
+ - MySQL: Create primary keys in same statement #5017
54
+
55
+ ### Typings:
56
+
57
+ - Fix type definition for getMigration in MigrationSource #4998
58
+ - Fix argument type of alter method #4996
59
+
60
+ ### Improvements:
61
+
62
+ - Use async / await syntax in seeds as default #5005
63
+
64
+ ### Documentation:
65
+
66
+ - Add Firebird dialect to ECOSYSTEM.md #5003
67
+
3
68
  # 1.0.2 - 02 February, 2022
4
69
 
5
70
  ### New features:
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [knex.js](http://knexjs.org)
1
+ # [knex.js](https://knex.github.io/documentation/)
2
2
 
3
3
  [![npm version](http://img.shields.io/npm/v/knex.svg)](https://npmjs.org/package/knex)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/knex.svg)](https://npmjs.org/package/knex)
@@ -13,15 +13,15 @@
13
13
  A batteries-included, multi-dialect (PostgreSQL, MySQL, CockroachDB, MSSQL, SQLite3, Oracle (including Oracle Wallet Authentication)) query builder for
14
14
  Node.js, featuring:
15
15
 
16
- - [transactions](https://knexjs.org/#Transactions)
17
- - [connection pooling](https://knexjs.org/#Installation-pooling)
18
- - [streaming queries](https://knexjs.org/#Interfaces-Streams)
19
- - both a [promise](https://knexjs.org/#Interfaces-Promises) and [callback](https://knexjs.org/#Interfaces-Callbacks) API
16
+ - [transactions](https://knex.github.io/documentation/#Transactions)
17
+ - [connection pooling](https://knex.github.io/documentation/#Installation-pooling)
18
+ - [streaming queries](https://knex.github.io/documentation/#Interfaces-Streams)
19
+ - both a [promise](https://knex.github.io/documentation/#Interfaces-Promises) and [callback](https://knex.github.io/documentation/#Interfaces-Callbacks) API
20
20
  - a [thorough test suite](https://github.com/knex/knex/actions)
21
21
 
22
22
  Node.js versions 12+ are supported.
23
23
 
24
- * Take a look at the [full documentation](https://knexjs.org) to get started!
24
+ * Take a look at the [full documentation](https://knex.github.io/documentation) to get started!
25
25
  * Browse the [list of plugins and tools](https://github.com/knex/knex/blob/master/ECOSYSTEM.md) built for knex
26
26
  * Check out our [recipes wiki](https://github.com/knex/knex/wiki/Recipes) to search for solutions to some specific problems
27
27
  * In case of upgrading from an older version, see [migration guide](https://github.com/knex/knex/blob/master/UPGRADING.md)
package/bin/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const rechoir = require('rechoir');
3
+ const merge = require('lodash/merge');
3
4
  const interpret = require('interpret');
4
5
  const resolveFrom = require('resolve-from');
5
6
  const path = require('path');
@@ -9,6 +10,7 @@ const color = require('colorette');
9
10
  const argv = require('getopts')(process.argv.slice(2));
10
11
  const cliPkg = require('../package');
11
12
  const {
13
+ parseConfigObj,
12
14
  mkConfigObj,
13
15
  resolveEnvironmentConfig,
14
16
  exit,
@@ -59,8 +61,17 @@ async function initKnex(env, opts) {
59
61
  env.configuration,
60
62
  env.configPath
61
63
  );
64
+
65
+ const optionsConfig = parseConfigObj(opts);
66
+ const config = merge(resolvedConfig, optionsConfig);
67
+
68
+ // Migrations directory gets defaulted if it is undefined.
69
+ if (!env.configPath && !config.migrations.directory) {
70
+ config.migrations.directory = null;
71
+ }
72
+
62
73
  const knex = require(env.modulePath);
63
- return knex(resolvedConfig);
74
+ return knex(config);
64
75
  }
65
76
 
66
77
  function invoke() {
@@ -138,16 +149,10 @@ function invoke() {
138
149
  .option('--knexfile [path]', 'Specify the knexfile path.')
139
150
  .option('--knexpath [path]', 'Specify the path to knex instance.')
140
151
  .option('--cwd [path]', 'Specify the working directory.')
141
- .option('--client [name]', 'Set DB client without a knexfile.')
142
- .option('--connection [address]', 'Set DB connection without a knexfile.')
143
- .option(
144
- '--migrations-directory [path]',
145
- 'Set migrations directory without a knexfile.'
146
- )
147
- .option(
148
- '--migrations-table-name [path]',
149
- 'Set migrations table name without a knexfile.'
150
- )
152
+ .option('--client [name]', 'Set DB client.')
153
+ .option('--connection [address]', 'Set DB connection.')
154
+ .option('--migrations-directory [path]', 'Set migrations directory.')
155
+ .option('--migrations-table-name [path]', 'Set migrations table name.')
151
156
  .option(
152
157
  '--env [name]',
153
158
  'environment, default: process.env.NODE_ENV || development'
@@ -1,12 +1,39 @@
1
1
  const { DEFAULT_EXT, DEFAULT_TABLE_NAME } = require('./constants');
2
2
  const { resolveClientNameWithAliases } = require('../../lib/util/helpers');
3
- const fs = require('fs');
4
3
  const path = require('path');
5
4
  const escalade = require('escalade/sync');
6
5
  const tildify = require('tildify');
7
6
  const color = require('colorette');
8
7
  const argv = require('getopts')(process.argv.slice(2));
9
8
 
9
+ function findCaseInsensitiveProperty(propertyName, object) {
10
+ return Object.keys(object).find(
11
+ (key) => key.toLowerCase() === propertyName.toLowerCase()
12
+ );
13
+ }
14
+
15
+ function parseConfigObj(opts) {
16
+ const config = { migrations: {} };
17
+
18
+ if (opts.client) {
19
+ config.client = opts.client;
20
+ }
21
+
22
+ if (opts.connection) {
23
+ config.connection = opts.connection;
24
+ }
25
+
26
+ if (opts.migrationsDirectory) {
27
+ config.migrations.directory = opts.migrationsDirectory;
28
+ }
29
+
30
+ if (opts.migrationsTableName) {
31
+ config.migrations.tableName = opts.migrationsTableName;
32
+ }
33
+
34
+ return config;
35
+ }
36
+
10
37
  function mkConfigObj(opts) {
11
38
  if (!opts.client) {
12
39
  throw new Error(
@@ -17,16 +44,14 @@ function mkConfigObj(opts) {
17
44
  const envName = opts.env || process.env.NODE_ENV || 'development';
18
45
  const resolvedClientName = resolveClientNameWithAliases(opts.client);
19
46
  const useNullAsDefault = resolvedClientName === 'sqlite3';
47
+ const parsedConfig = parseConfigObj(opts);
48
+
20
49
  return {
21
50
  ext: DEFAULT_EXT,
22
51
  [envName]: {
52
+ ...parsedConfig,
23
53
  useNullAsDefault,
24
- client: opts.client,
25
- connection: opts.connection,
26
- migrations: {
27
- directory: opts.migrationsDirectory,
28
- tableName: opts.migrationsTableName || DEFAULT_TABLE_NAME,
29
- },
54
+ tableName: parsedConfig.tableName || DEFAULT_TABLE_NAME,
30
55
  },
31
56
  };
32
57
  }
@@ -174,6 +199,7 @@ function findUpConfig(cwd, name, extensions) {
174
199
  }
175
200
 
176
201
  module.exports = {
202
+ parseConfigObj,
177
203
  mkConfigObj,
178
204
  resolveEnvironmentConfig,
179
205
  exit,
@@ -6,7 +6,7 @@ function listMigrations(completed, newMigrations) {
6
6
  let message = '';
7
7
 
8
8
  if (completed.length === 0) {
9
- message += color.red('No Completed Migration files Found. \n');
9
+ message += color.red('No Completed Migration files Found.\n');
10
10
  } else {
11
11
  message = color.green(
12
12
  `Found ${completed.length} Completed Migration file/files.\n`
@@ -14,7 +14,7 @@ function listMigrations(completed, newMigrations) {
14
14
 
15
15
  for (let i = 0; i < completed.length; i++) {
16
16
  const file = completed[i];
17
- message += color.cyan(`${file} \n`);
17
+ message += color.cyan(`${file.name}\n`);
18
18
  }
19
19
  }
20
20
 
@@ -27,7 +27,7 @@ function listMigrations(completed, newMigrations) {
27
27
 
28
28
  for (let i = 0; i < newMigrations.length; i++) {
29
29
  const file = newMigrations[i];
30
- message += color.cyan(`${file.file} \n`);
30
+ message += color.cyan(`${file.file}\n`);
31
31
  }
32
32
  }
33
33
 
package/lib/client.js CHANGED
@@ -189,7 +189,10 @@ class Client extends EventEmitter {
189
189
  try {
190
190
  this.driver = this._driver();
191
191
  } catch (e) {
192
- const message = `Knex: run\n$ npm install ${this.driverName} --save`;
192
+ const driverName = this.aliasDriverName
193
+ ? this.aliasDriverName
194
+ : this.driverName;
195
+ const message = `Knex: run\n$ npm install ${driverName} --save`;
193
196
  this.logger.error(`${message}\n${e.message}\n${e.stack}`);
194
197
  throw new Error(`${message}\n${e.message}`);
195
198
  }
@@ -35,9 +35,9 @@ class QueryCompiler_CRDB extends QueryCompiler_PG {
35
35
 
36
36
  whereJsonPath(statement) {
37
37
  let castValue = '';
38
- if (parseInt(statement.value)) {
38
+ if (!isNaN(statement.value) && parseInt(statement.value)) {
39
39
  castValue = '::int';
40
- } else if (parseFloat(statement.value)) {
40
+ } else if (!isNaN(statement.value) && parseFloat(statement.value)) {
41
41
  castValue = '::float';
42
42
  } else {
43
43
  castValue = " #>> '{}'";
@@ -19,7 +19,12 @@ class TableCompiler_MySQL extends TableCompiler {
19
19
  : 'create table ';
20
20
  const { client } = this;
21
21
  let conn = {};
22
- const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
22
+ let columnsSql = ' (' + columns.sql.join(', ');
23
+
24
+ columnsSql += this.primaryKeys() || '';
25
+ columnsSql += this._addChecks();
26
+ columnsSql += ')';
27
+
23
28
  let sql =
24
29
  createStatement +
25
30
  this.tableName() +
@@ -135,6 +140,34 @@ class TableCompiler_MySQL extends TableCompiler {
135
140
  });
136
141
  }
137
142
 
143
+ primaryKeys() {
144
+ const pks = (this.grouped.alterTable || []).filter(
145
+ (k) => k.method === 'primary'
146
+ );
147
+ if (pks.length > 0 && pks[0].args.length > 0) {
148
+ const columns = pks[0].args[0];
149
+ let constraintName = pks[0].args[1] || '';
150
+ if (constraintName) {
151
+ constraintName = ' constraint ' + this.formatter.wrap(constraintName);
152
+ }
153
+
154
+ if (this.grouped.columns) {
155
+ const incrementsCols = this._getIncrementsColumnNames();
156
+ if (incrementsCols.length) {
157
+ incrementsCols.forEach((c) => {
158
+ if (!columns.includes(c)) {
159
+ columns.unshift(c);
160
+ }
161
+ });
162
+ }
163
+ }
164
+
165
+ return `,${constraintName} primary key (${this.formatter.columnize(
166
+ columns
167
+ )})`;
168
+ }
169
+ }
170
+
138
171
  getFKRefs(runner) {
139
172
  const bindingsHolder = {
140
173
  bindings: [],
@@ -269,11 +302,13 @@ class TableCompiler_MySQL extends TableCompiler {
269
302
  });
270
303
  }
271
304
  }
272
- this.pushQuery(
273
- `alter table ${this.tableName()} add primary key ${constraintName}(${this.formatter.columnize(
274
- primaryCols
275
- )})`
276
- );
305
+ if (this.method !== 'create' && this.method !== 'createIfNot') {
306
+ this.pushQuery(
307
+ `alter table ${this.tableName()} add primary key ${constraintName}(${this.formatter.columnize(
308
+ primaryCols
309
+ )})`
310
+ );
311
+ }
277
312
  if (incrementsCols.length) {
278
313
  this.pushQuery(
279
314
  `alter table ${this.tableName()} modify column ${this.formatter.columnize(
@@ -156,8 +156,8 @@ class Oracledb_Compiler extends Oracle_Compiler {
156
156
  // later position binding will only convert the ? params
157
157
  subSql = self.formatter.client.positionBindings(subSql);
158
158
  const parameterizedValuesWithoutDefaultAndBlob = parameterizedValues
159
- .replace('DEFAULT, ', '')
160
- .replace(', DEFAULT', '')
159
+ .replace(/DEFAULT, /g, '')
160
+ .replace(/, DEFAULT/g, '')
161
161
  .replace('EMPTY_BLOB(), ', '')
162
162
  .replace(', EMPTY_BLOB()', '');
163
163
  return (
@@ -112,7 +112,7 @@ class QueryCompiler_PG extends QueryCompiler {
112
112
  );
113
113
  }
114
114
  if (joinWheres.length > 0) {
115
- wheres += (wheres ? ' and ' : '') + joinWheres.join(' ');
115
+ wheres += (wheres ? ' and ' : 'where ') + joinWheres.join(' and ');
116
116
  }
117
117
  }
118
118
  if (tableJoins.length > 0) {
@@ -341,9 +341,9 @@ class QueryCompiler_PG extends QueryCompiler {
341
341
 
342
342
  whereJsonPath(statement) {
343
343
  let castValue = '';
344
- if (parseInt(statement.value)) {
344
+ if (!isNaN(statement.value) && parseInt(statement.value)) {
345
345
  castValue = '::int';
346
- } else if (parseFloat(statement.value)) {
346
+ } else if (!isNaN(statement.value) && parseFloat(statement.value)) {
347
347
  castValue = '::float';
348
348
  } else {
349
349
  castValue = " #>> '{}'";
@@ -232,6 +232,8 @@ Object.assign(Client_SQLite3.prototype, {
232
232
  dialect: 'sqlite3',
233
233
 
234
234
  driverName: 'sqlite3',
235
+ // SqlLite3 driver package name is different from driver name.
236
+ aliasDriverName: '@vscode/sqlite3',
235
237
  });
236
238
 
237
239
  module.exports = Client_SQLite3;
@@ -2,15 +2,12 @@
2
2
  * @param { import("knex").Knex } knex
3
3
  * @returns { Promise<void> }
4
4
  */
5
- exports.seed = function(knex) {
5
+ exports.seed = async function(knex) {
6
6
  // Deletes ALL existing entries
7
- return knex('table_name').del()
8
- .then(function () {
9
- // Inserts seed entries
10
- return knex('table_name').insert([
11
- {id: 1, colName: 'rowValue1'},
12
- {id: 2, colName: 'rowValue2'},
13
- {id: 3, colName: 'rowValue3'}
14
- ]);
15
- });
7
+ await knex('table_name').del()
8
+ await knex('table_name').insert([
9
+ {id: 1, colName: 'rowValue1'},
10
+ {id: 2, colName: 'rowValue2'},
11
+ {id: 3, colName: 'rowValue3'}
12
+ ]);
16
13
  };
@@ -1,14 +1,9 @@
1
- const { readFile } = require('./fs');
1
+ const getPackageType = require('get-package-type');
2
2
 
3
3
  module.exports = async function isModuleType(filepath) {
4
- if (process.env.npm_package_json) {
5
- // npm >= 7.0.0
6
- const packageJson = JSON.parse(
7
- await readFile(process.env.npm_package_json, 'utf-8')
8
- );
9
- if (packageJson.type === 'module') {
10
- return true;
11
- }
12
- }
13
- return process.env.npm_package_type === 'module' || filepath.endsWith('.mjs');
4
+ return (
5
+ filepath.endsWith('.mjs') ||
6
+ (!filepath.endsWith('.cjs') &&
7
+ (await getPackageType(filepath)) === 'module')
8
+ );
14
9
  };
@@ -3,6 +3,8 @@
3
3
  module.exports = [
4
4
  'with',
5
5
  'withRecursive',
6
+ 'withMaterialized',
7
+ 'withNotMaterialized',
6
8
  'select',
7
9
  'as',
8
10
  'columns',
@@ -25,12 +27,16 @@ module.exports = [
25
27
  'fullOuterJoin',
26
28
  'crossJoin',
27
29
  'where',
28
- 'whereLike',
29
- 'whereILike',
30
30
  'andWhere',
31
31
  'orWhere',
32
32
  'whereNot',
33
33
  'orWhereNot',
34
+ 'whereLike',
35
+ 'andWhereLike',
36
+ 'orWhereLike',
37
+ 'whereILike',
38
+ 'andWhereILike',
39
+ 'orWhereILike',
34
40
  'whereRaw',
35
41
  'whereWrapped',
36
42
  'havingWrapped',
@@ -691,11 +691,21 @@ class Builder extends EventEmitter {
691
691
  return this._whereLike('whereLike', column, value);
692
692
  }
693
693
 
694
+ // Adds a `or where like` clause to the query.
695
+ orWhereLike(column, value) {
696
+ return this._bool('or')._whereLike('whereLike', column, value);
697
+ }
698
+
694
699
  // Adds a `where ilike` clause to the query.
695
700
  whereILike(column, value) {
696
701
  return this._whereLike('whereILike', column, value);
697
702
  }
698
703
 
704
+ // Adds a `or where ilike` clause to the query.
705
+ orWhereILike(column, value) {
706
+ return this._bool('or')._whereLike('whereILike', column, value);
707
+ }
708
+
699
709
  // Adds a `group by` clause to the query.
700
710
  groupBy(item) {
701
711
  if (item && item.isRawInstance) {
@@ -1226,7 +1236,11 @@ class Builder extends EventEmitter {
1226
1236
  const obj = this._single.update || {};
1227
1237
  this._method = 'update';
1228
1238
  if (isString(values)) {
1229
- obj[values] = returning;
1239
+ if (isPlainObject(returning)) {
1240
+ obj[values] = JSON.stringify(returning);
1241
+ } else {
1242
+ obj[values] = returning;
1243
+ }
1230
1244
  if (arguments.length > 2) {
1231
1245
  ret = arguments[2];
1232
1246
  }
@@ -1505,8 +1519,8 @@ class Builder extends EventEmitter {
1505
1519
  return this;
1506
1520
  }
1507
1521
 
1508
- orWhereJsonPath(column, operator, value) {
1509
- return this._bool('or').whereJsonPath(column, operator, value);
1522
+ orWhereJsonPath(column, path, operator, value) {
1523
+ return this._bool('or').whereJsonPath(column, path, operator, value);
1510
1524
  }
1511
1525
 
1512
1526
  // Json superset wheres
@@ -1725,6 +1739,8 @@ Builder.prototype.andWhereNotBetween = Builder.prototype.whereNotBetween;
1725
1739
  Builder.prototype.andWhereJsonObject = Builder.prototype.whereJsonObject;
1726
1740
  Builder.prototype.andWhereNotJsonObject = Builder.prototype.whereJsonObject;
1727
1741
  Builder.prototype.andWhereJsonPath = Builder.prototype.whereJsonPath;
1742
+ Builder.prototype.andWhereLike = Builder.prototype.whereLike;
1743
+ Builder.prototype.andWhereILike = Builder.prototype.whereILike;
1728
1744
  Builder.prototype.andHaving = Builder.prototype.having;
1729
1745
  Builder.prototype.andHavingIn = Builder.prototype.havingIn;
1730
1746
  Builder.prototype.andHavingNotIn = Builder.prototype.havingNotIn;
@@ -124,8 +124,54 @@ class QueryCompiler {
124
124
  select() {
125
125
  let sql = this.with();
126
126
 
127
- const statements = components.map((component) => this[component](this));
128
- sql += compact(statements).join(' ');
127
+ let unionStatement = '';
128
+
129
+ const firstStatements = [];
130
+ const endStatements = [];
131
+
132
+ components.forEach((component) => {
133
+ const statement = this[component](this);
134
+ // We store the 'union' statement to append it at the end.
135
+ // We still need to call the component sequentially because of
136
+ // order of bindings.
137
+ switch (component) {
138
+ case 'union':
139
+ unionStatement = statement;
140
+ break;
141
+ case 'columns':
142
+ case 'join':
143
+ case 'where':
144
+ firstStatements.push(statement);
145
+ break;
146
+ default:
147
+ endStatements.push(statement);
148
+ break;
149
+ }
150
+ });
151
+
152
+ // Check if we need to wrap the main query.
153
+ // We need to wrap main query if one of union have wrap options to true
154
+ // to avoid error syntax (in PostgreSQL for example).
155
+ const wrapMainQuery =
156
+ this.grouped.union &&
157
+ this.grouped.union.map((u) => u.wrap).some((u) => u);
158
+
159
+ if (this.onlyUnions()) {
160
+ const statements = compact(firstStatements.concat(endStatements)).join(
161
+ ' '
162
+ );
163
+ sql += unionStatement + (statements ? ' ' + statements : '');
164
+ } else {
165
+ const allStatements =
166
+ (wrapMainQuery ? '(' : '') +
167
+ compact(firstStatements).join(' ') +
168
+ (wrapMainQuery ? ')' : '');
169
+ const endStat = compact(endStatements).join(' ');
170
+ sql +=
171
+ allStatements +
172
+ (unionStatement ? ' ' + unionStatement : '') +
173
+ (endStat ? ' ' + endStat : endStat);
174
+ }
129
175
  return sql;
130
176
  }
131
177
 
@@ -706,9 +752,10 @@ class QueryCompiler {
706
752
  this.bindingsHolder
707
753
  );
708
754
  if (statement) {
709
- if (union.wrap) sql += '(';
755
+ const wrap = union.wrap;
756
+ if (wrap) sql += '(';
710
757
  sql += statement;
711
- if (union.wrap) sql += ')';
758
+ if (wrap) sql += ')';
712
759
  }
713
760
  }
714
761
  return sql;
@@ -842,6 +889,7 @@ class QueryCompiler {
842
889
  }
843
890
 
844
891
  onBasic(clause) {
892
+ const toWrap = clause.value instanceof QueryBuilder;
845
893
  return (
846
894
  wrap_(
847
895
  clause.column,
@@ -858,13 +906,15 @@ class QueryCompiler {
858
906
  this.bindingsHolder
859
907
  ) +
860
908
  ' ' +
909
+ (toWrap ? '(' : '') +
861
910
  wrap_(
862
911
  clause.value,
863
912
  undefined,
864
913
  this.builder,
865
914
  this.client,
866
915
  this.bindingsHolder
867
- )
916
+ ) +
917
+ (toWrap ? ')' : '')
868
918
  );
869
919
  }
870
920