knex 2.0.0 → 2.3.0

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/CONTRIBUTING.md +10 -0
  3. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -0
  4. package/lib/dialects/cockroachdb/index.js +5 -0
  5. package/lib/dialects/index.js +34 -0
  6. package/lib/dialects/mssql/index.js +20 -14
  7. package/lib/dialects/mssql/schema/mssql-compiler.js +9 -2
  8. package/lib/dialects/mysql/query/mysql-querycompiler.js +1 -1
  9. package/lib/dialects/mysql/schema/mysql-compiler.js +2 -2
  10. package/lib/dialects/oracledb/index.js +2 -1
  11. package/lib/dialects/postgres/schema/pg-columncompiler.js +8 -1
  12. package/lib/dialects/postgres/schema/pg-compiler.js +2 -2
  13. package/lib/dialects/postgres/schema/pg-tablecompiler.js +33 -6
  14. package/lib/dialects/sqlite3/index.js +20 -7
  15. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +18 -1
  16. package/lib/execution/runner.js +2 -9
  17. package/lib/formatter/wrappingFormatter.js +1 -2
  18. package/lib/knex-builder/Knex.js +28 -0
  19. package/lib/knex-builder/internal/config-resolver.js +2 -3
  20. package/lib/knex-builder/internal/parse-connection.js +4 -2
  21. package/lib/migrations/migrate/MigrationGenerator.js +1 -1
  22. package/lib/migrations/migrate/stub/js-schema.stub +22 -0
  23. package/lib/migrations/migrate/stub/ts-schema.stub +21 -0
  24. package/lib/schema/builder.js +12 -0
  25. package/lib/schema/columnbuilder.js +12 -0
  26. package/lib/schema/columncompiler.js +4 -2
  27. package/lib/schema/tablebuilder.js +12 -0
  28. package/lib/schema/viewbuilder.js +12 -0
  29. package/package.json +33 -23
  30. package/scripts/clean.js +29 -0
  31. package/scripts/update_gitignore_for_tsc_output.js +85 -0
  32. package/types/index.d.ts +849 -396
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # Master (Unreleased)
2
2
 
3
+ # 2.3.0 - 31 August, 2022
4
+
5
+ ### New features:
6
+
7
+ - PostgreSQL: Explicit jsonb support for custom pg clients #5201
8
+ - SQLite: Support returning with sqlite3 and better-sqlite3 #5285
9
+ - MSSQL: Implement mapBinding mssql dialect option #5292
10
+
11
+ ### Typings:
12
+
13
+ - Update types for TS 4.8 #5279
14
+ - Fix typo #5267
15
+ - Fix WhereJsonObject withCompositeTableType #5306
16
+ - Fix AnalyticFunction type #5304
17
+ - Infer specific column value type in aggregations #5297
18
+
19
+ # 2.2.0 - 19 July, 2022
20
+
21
+ ### New features:
22
+
23
+ - Inline primary key creation for postgres flavours #5233
24
+ - SQLite: Add warning for undefined connection file #5223
25
+ - MSSQL: Add JSON parameter support for connection #5200
26
+
27
+ ### Bug fixes:
28
+
29
+ - PostgreSQL: add primaryKey option for uuid #5212
30
+
31
+ ### Typings:
32
+
33
+ - Add promisable and better types #5222
34
+ - Update raw query bind parameter type #5208
35
+
36
+ # 2.1.0 - 26 May, 2022
37
+
38
+ ### New features:
39
+
40
+ - Improve bundling experience to safely import dialects while using static paths #5142
41
+ - Implement extendable builders #5041
42
+ - PostgreSQL: Refresh materialized view concurrently #5166
43
+
44
+ ### Bug fixes:
45
+
46
+ - Use correct paths in package.json browser field #5174
47
+ - MariaDB: Fix 'NULL' returned instead of NULL on MariaDB 10.2.6+ #5181
48
+ - MySQL: fix hasColumn Error (hasColumn ('a_id') is true, but hasColumn('a_Id') is false) #5148
49
+ - MSSQL: Fix .hasTable result when using .withSchema #5176
50
+ - Oracle: correctly INSERTS Buffer #4869
51
+
52
+ ### Typings:
53
+
54
+ - Update type definitions for pg connection #5139
55
+
3
56
  # 2.0.0 - 21 April, 2022
4
57
 
5
58
  ### Breaking changes
package/CONTRIBUTING.md CHANGED
@@ -169,6 +169,16 @@ Once this is done, check it works by attempting to login:
169
169
  psql -h localhost -U postgres -d knex_test
170
170
  ```
171
171
 
172
+ ## Typescript source files
173
+
174
+ > TL;DR: Starting with release 2.0.0 Knex is adding support for Typescript source files. Thus to develop in this repo you will need to run `npm run build` each time you edit `.ts` files to generate the resulting `.js` files. This is automatically run whenever you run `npm install` or checkout a new Git branch so when developing in Javascript you don't have to worry about it. It is encouraged that new functionality and sources be written in Typescript but this is not required.
175
+
176
+ Starting with release 2.0.0, Knex is support source additions in Typescript! This allows for better safety in the code added. However, pre-2.0.0 Knex was always written in pure Javascript and thus a "hybrid" approach is being used for 2.0.0 to allow for the new `.ts` files to exist along `.js` files that make up the majority of this repository.
177
+
178
+ To develop in this repository use the `npm run build` and `npm run clean` commands to compile and delete the `.js` and related files from `.ts` files. If you wish to have the `tsc` compiled watch and recompile on changes then run `npm run build:ts -- --watch`. Note that for easy integration with Javascript the outputted files are done in a "side-by-side" manner meaning that `lib/foo/bar.ts` will result in `lib/foo/bar.js`. This is done automatically via the npm script command `"prepare"` whenever you run `npm install` and Git hook for `post-checkout` (added by Husky) which executes when you run commands like `git checkout` , thus making it easier to not have to worry about this if you're working in pure Javascript.
179
+
180
+ The script file `./scripts/update_gitignore_for_tsc_output.js` file is called as part of the `npm run build` command which will update the `lib/.gitignore` file which is used to ensure generated `.js` and related files from `tsc` compilation are not checked into the git repo.
181
+
172
182
  ## Want to be Collaborator?
173
183
 
174
184
  There is always room for more collaborators. Be active on resolving github issues / sending pull requests / reviewing code and we will ask you to join.
@@ -0,0 +1,14 @@
1
+ const ColumnCompiler_PG = require('../postgres/schema/pg-columncompiler.js');
2
+
3
+ class ColumnCompiler_CRDB extends ColumnCompiler_PG {
4
+ uuid(options = { primaryKey: false }) {
5
+ return (
6
+ 'uuid' +
7
+ (this.tableCompiler._canBeAddPrimaryKey(options)
8
+ ? ' primary key default gen_random_uuid()'
9
+ : '')
10
+ );
11
+ }
12
+ }
13
+
14
+ module.exports = ColumnCompiler_CRDB;
@@ -3,6 +3,7 @@
3
3
  const Client_PostgreSQL = require('../postgres');
4
4
  const Transaction = require('../postgres/execution/pg-transaction');
5
5
  const QueryCompiler = require('./crdb-querycompiler');
6
+ const ColumnCompiler = require('./crdb-columncompiler');
6
7
  const TableCompiler = require('./crdb-tablecompiler');
7
8
  const ViewCompiler = require('./crdb-viewcompiler');
8
9
  const QueryBuilder = require('./crdb-querybuilder');
@@ -19,6 +20,10 @@ class Client_CockroachDB extends Client_PostgreSQL {
19
20
  return new QueryCompiler(this, builder, formatter);
20
21
  }
21
22
 
23
+ columnCompiler() {
24
+ return new ColumnCompiler(this, ...arguments);
25
+ }
26
+
22
27
  tableCompiler() {
23
28
  return new TableCompiler(this, ...arguments);
24
29
  }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDialectByNameOrAlias = void 0;
4
+ const { resolveClientNameWithAliases } = require('../util/helpers');
5
+ const dbNameToDialectLoader = Object.freeze({
6
+ 'better-sqlite3': () => require('./better-sqlite3'),
7
+ cockroachdb: () => require('./cockroachdb'),
8
+ mssql: () => require('./mssql'),
9
+ mysql: () => require('./mysql'),
10
+ mysql2: () => require('./mysql2'),
11
+ oracle: () => require('./oracle'),
12
+ oracledb: () => require('./oracledb'),
13
+ pgnative: () => require('./pgnative'),
14
+ postgres: () => require('./postgres'),
15
+ redshift: () => require('./redshift'),
16
+ sqlite3: () => require('./sqlite3'),
17
+ });
18
+ /**
19
+ * Gets the Dialect object with the given client name or throw an
20
+ * error if not found.
21
+ *
22
+ * NOTE: This is a replacement for prior practice of doing dynamic
23
+ * string construction for imports of Dialect objects.
24
+ */
25
+ function getDialectByNameOrAlias(clientName) {
26
+ const resolvedClientName = resolveClientNameWithAliases(clientName);
27
+ const dialectLoader = dbNameToDialectLoader[resolvedClientName];
28
+ if (!dialectLoader) {
29
+ throw new Error(`Invalid clientName given: ${clientName}`);
30
+ }
31
+ return dialectLoader();
32
+ }
33
+ exports.getDialectByNameOrAlias = getDialectByNameOrAlias;
34
+ //# sourceMappingURL=index.js.map
@@ -333,14 +333,24 @@ class Client_MSSQL extends Client {
333
333
  _typeForBinding(binding) {
334
334
  const Driver = this._driver();
335
335
 
336
+ if (
337
+ this.connectionSettings.options &&
338
+ this.connectionSettings.options.mapBinding
339
+ ) {
340
+ const result = this.connectionSettings.options.mapBinding(binding);
341
+ if (result) {
342
+ return [result.value, result.type];
343
+ }
344
+ }
345
+
336
346
  switch (typeof binding) {
337
347
  case 'string':
338
- return Driver.TYPES.NVarChar;
348
+ return [binding, Driver.TYPES.NVarChar];
339
349
  case 'boolean':
340
- return Driver.TYPES.Bit;
350
+ return [binding, Driver.TYPES.Bit];
341
351
  case 'number': {
342
352
  if (binding % 1 !== 0) {
343
- return Driver.TYPES.Float;
353
+ return [binding, Driver.TYPES.Float];
344
354
  }
345
355
 
346
356
  if (binding < SQL_INT4.MIN || binding > SQL_INT4.MAX) {
@@ -350,25 +360,21 @@ class Client_MSSQL extends Client {
350
360
  );
351
361
  }
352
362
 
353
- return Driver.TYPES.BigInt;
363
+ return [binding, Driver.TYPES.BigInt];
354
364
  }
355
365
 
356
- return Driver.TYPES.Int;
366
+ return [binding, Driver.TYPES.Int];
357
367
  }
358
368
  default: {
359
- // if (binding === null || typeof binding === 'undefined') {
360
- // return tedious.TYPES.Null;
361
- // }
362
-
363
369
  if (binding instanceof Date) {
364
- return Driver.TYPES.DateTime;
370
+ return [binding, Driver.TYPES.DateTime];
365
371
  }
366
372
 
367
373
  if (binding instanceof Buffer) {
368
- return Driver.TYPES.VarBinary;
374
+ return [binding, Driver.TYPES.VarBinary];
369
375
  }
370
376
 
371
- return Driver.TYPES.NVarChar;
377
+ return [binding, Driver.TYPES.NVarChar];
372
378
  }
373
379
  }
374
380
  }
@@ -401,8 +407,8 @@ class Client_MSSQL extends Client {
401
407
  }
402
408
 
403
409
  // sets a request input parameter. Detects bigints and decimals and sets type appropriately.
404
- _setReqInput(req, i, binding) {
405
- const tediousType = this._typeForBinding(binding);
410
+ _setReqInput(req, i, inputBinding) {
411
+ const [binding, tediousType] = this._typeForBinding(inputBinding);
406
412
  const bindingName = 'p'.concat(i);
407
413
  let options;
408
414
 
@@ -49,10 +49,17 @@ class SchemaCompiler_MSSQL extends SchemaCompiler {
49
49
  this.builder,
50
50
  this.bindingsHolder
51
51
  );
52
- const sql =
52
+ const bindings = [tableName];
53
+ let sql =
53
54
  `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ` +
54
55
  `WHERE TABLE_NAME = ${formattedTable}`;
55
- this.pushQuery({ sql, output: (resp) => resp.length > 0 });
56
+
57
+ if (this.schema) {
58
+ sql += ' AND TABLE_SCHEMA = ?';
59
+ bindings.push(this.schema);
60
+ }
61
+
62
+ this.pushQuery({ sql, bindings, output: (resp) => resp.length > 0 });
56
63
  }
57
64
 
58
65
  // Check whether a column exists on the schema.
@@ -131,7 +131,7 @@ class QueryCompiler_MySQL extends QueryCompiler {
131
131
  output(resp) {
132
132
  const out = resp.reduce(function (columns, val) {
133
133
  columns[val.COLUMN_NAME] = {
134
- defaultValue: val.COLUMN_DEFAULT,
134
+ defaultValue: val.COLUMN_DEFAULT === 'NULL' ? null : val.COLUMN_DEFAULT,
135
135
  type: val.DATA_TYPE,
136
136
  maxLength: val.CHARACTER_MAXIMUM_LENGTH,
137
137
  nullable: val.IS_NULLABLE === 'YES',
@@ -48,8 +48,8 @@ class SchemaCompiler_MySQL extends SchemaCompiler {
48
48
  output(resp) {
49
49
  return resp.some((row) => {
50
50
  return (
51
- this.client.wrapIdentifier(row.Field) ===
52
- this.client.wrapIdentifier(column)
51
+ this.client.wrapIdentifier(row.Field.toLowerCase()) ===
52
+ this.client.wrapIdentifier(column.toLowerCase())
53
53
  );
54
54
  });
55
55
  },
@@ -111,7 +111,8 @@ class Client_Oracledb extends Client_Oracle {
111
111
  this
112
112
  );
113
113
  } else if (value instanceof BlobHelper) {
114
- return 'EMPTY_BLOB()';
114
+ formatter.bindings.push(value.value);
115
+ return '?';
115
116
  }
116
117
  return unwrapRaw(value, true, builder, this, formatter) || '?';
117
118
  }
@@ -124,6 +124,13 @@ class ColumnCompiler_PG extends ColumnCompiler {
124
124
  (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
125
125
  );
126
126
  }
127
+
128
+ uuid(options = { primaryKey: false }) {
129
+ return (
130
+ 'uuid' +
131
+ (this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
132
+ );
133
+ }
127
134
  }
128
135
 
129
136
  ColumnCompiler_PG.prototype.bigint = 'bigint';
@@ -133,12 +140,12 @@ ColumnCompiler_PG.prototype.double = 'double precision';
133
140
  ColumnCompiler_PG.prototype.floating = 'real';
134
141
  ColumnCompiler_PG.prototype.smallint = 'smallint';
135
142
  ColumnCompiler_PG.prototype.tinyint = 'smallint';
136
- ColumnCompiler_PG.prototype.uuid = 'uuid';
137
143
 
138
144
  function jsonColumn(client, jsonb) {
139
145
  if (
140
146
  !client.version ||
141
147
  client.config.client === 'cockroachdb' ||
148
+ client.config.jsonbSupport === true ||
142
149
  parseFloat(client.version) >= 9.2
143
150
  ) {
144
151
  return jsonb ? 'jsonb' : 'json';
@@ -118,9 +118,9 @@ class SchemaCompiler_PG extends SchemaCompiler {
118
118
  );
119
119
  }
120
120
 
121
- refreshMaterializedView(viewName) {
121
+ refreshMaterializedView(viewName, concurrently = false) {
122
122
  this.pushQuery({
123
- sql: `refresh materialized view ${this.formatter.wrap(viewName)}`,
123
+ sql: `refresh materialized view${concurrently ? " concurrently" : ""} ${this.formatter.wrap(viewName)}`,
124
124
  });
125
125
  }
126
126
 
@@ -44,7 +44,10 @@ class TableCompiler_PG extends TableCompiler {
44
44
  const createStatement = ifNot
45
45
  ? 'create table if not exists '
46
46
  : 'create table ';
47
- const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
47
+ const columnsSql = ` (${columns.sql.join(', ')}${
48
+ this.primaryKeys() || ''
49
+ }${this._addChecks()})`;
50
+
48
51
  let sql =
49
52
  createStatement +
50
53
  this.tableName() +
@@ -65,6 +68,28 @@ class TableCompiler_PG extends TableCompiler {
65
68
  if (hasComment) this.comment(this.single.comment);
66
69
  }
67
70
 
71
+ primaryKeys() {
72
+ const pks = (this.grouped.alterTable || []).filter(
73
+ (k) => k.method === 'primary'
74
+ );
75
+ if (pks.length > 0 && pks[0].args.length > 0) {
76
+ const columns = pks[0].args[0];
77
+ let constraintName = pks[0].args[1] || '';
78
+ let deferrable;
79
+ if (isObject(constraintName)) {
80
+ ({ constraintName, deferrable } = constraintName);
81
+ }
82
+ deferrable = deferrable ? ` deferrable initially ${deferrable}` : '';
83
+ constraintName = constraintName
84
+ ? this.formatter.wrap(constraintName)
85
+ : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
86
+
87
+ return `, constraint ${constraintName} primary key (${this.formatter.columnize(
88
+ columns
89
+ )})${deferrable}`;
90
+ }
91
+ }
92
+
68
93
  addColumns(columns, prefix, colCompilers) {
69
94
  if (prefix === this.alterColumnsPrefix) {
70
95
  // alter columns
@@ -153,11 +178,13 @@ class TableCompiler_PG extends TableCompiler {
153
178
  constraintName = constraintName
154
179
  ? this.formatter.wrap(constraintName)
155
180
  : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
156
- this.pushQuery(
157
- `alter table ${this.tableName()} add constraint ${constraintName} primary key (${this.formatter.columnize(
158
- columns
159
- )})${deferrable}`
160
- );
181
+ if (this.method !== 'create' && this.method !== 'createIfNot') {
182
+ this.pushQuery(
183
+ `alter table ${this.tableName()} add constraint ${constraintName} primary key (${this.formatter.columnize(
184
+ columns
185
+ )})${deferrable}`
186
+ );
187
+ }
161
188
  }
162
189
 
163
190
  unique(columns, indexName) {
@@ -20,11 +20,20 @@ const QueryBuilder = require('./query/sqlite-querybuilder');
20
20
  class Client_SQLite3 extends Client {
21
21
  constructor(config) {
22
22
  super(config);
23
+
24
+ if (config.connection && config.connection.filename === undefined) {
25
+ this.logger.warn(
26
+ 'Could not find `connection.filename` in config. Please specify ' +
27
+ 'the database path and name to avoid errors. ' +
28
+ '(see docs https://knexjs.org/guide/#configuration-options)'
29
+ );
30
+ }
31
+
23
32
  if (config.useNullAsDefault === undefined) {
24
33
  this.logger.warn(
25
34
  'sqlite does not support inserting default values. Set the ' +
26
35
  '`useNullAsDefault` flag to hide this warning. ' +
27
- '(see docs http://knexjs.org/#Builder-insert).'
36
+ '(see docs https://knexjs.org/guide/query-builder.html#insert).'
28
37
  );
29
38
  }
30
39
  }
@@ -117,6 +126,8 @@ class Client_SQLite3 extends Client {
117
126
  switch (method) {
118
127
  case 'insert':
119
128
  case 'update':
129
+ callMethod = obj.returning ? 'all' : 'run';
130
+ break;
120
131
  case 'counter':
121
132
  case 'del':
122
133
  callMethod = 'run';
@@ -181,16 +192,18 @@ class Client_SQLite3 extends Client {
181
192
  if (response) {
182
193
  return response;
183
194
  }
184
-
185
- // ToDo Implement after https://github.com/microsoft/vscode-node-sqlite3/issues/15 is resolved
186
- this.logger.warn(
187
- 'node-sqlite3 does not currently support RETURNING clause'
188
- );
189
195
  }
190
196
  return [ctx.lastID];
191
197
  }
198
+ case 'update': {
199
+ if (returning) {
200
+ if (response) {
201
+ return response;
202
+ }
203
+ }
204
+ return ctx.changes;
205
+ }
192
206
  case 'del':
193
- case 'update':
194
207
  case 'counter':
195
208
  return ctx.changes;
196
209
  default: {
@@ -76,7 +76,7 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
76
76
  throw new TypeError(
77
77
  '`sqlite` does not support inserting default values. Specify ' +
78
78
  'values explicitly or use the `useNullAsDefault` config flag. ' +
79
- '(see docs http://knexjs.org/#Builder-insert).'
79
+ '(see docs https://knexjs.org/guide/query-builder.html#insert).'
80
80
  );
81
81
  });
82
82
  });
@@ -149,6 +149,23 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
149
149
  };
150
150
  }
151
151
 
152
+ // Compiles an `update` query, allowing for a return value.
153
+ update() {
154
+ const withSQL = this.with();
155
+ const updateData = this._prepUpdate(this.single.update);
156
+ const wheres = this.where();
157
+ const { returning } = this.single;
158
+ return {
159
+ sql:
160
+ withSQL +
161
+ `update ${this.single.only ? 'only ' : ''}${this.tableName} ` +
162
+ `set ${updateData.join(', ')}` +
163
+ (wheres ? ` ${wheres}` : '') +
164
+ this._returning(returning),
165
+ returning,
166
+ };
167
+ }
168
+
152
169
  _ignore(columns) {
153
170
  if (columns === true) {
154
171
  return ' on conflict do nothing';
@@ -61,22 +61,15 @@ class Runner {
61
61
  Transform = Transform || require('stream').Transform;
62
62
 
63
63
  const queryContext = this.builder.queryContext();
64
- let queryStream;
65
64
 
66
65
  const stream = new Transform({
67
66
  objectMode: true,
68
67
  transform: (chunk, _, callback) => {
69
68
  callback(null, this.client.postProcessResponse(chunk, queryContext));
70
69
  },
71
- destroy() {
72
- // For some reason destroy is not available for mssql on Node 14. Might be a problem with tedious: https://github.com/tediousjs/tedious/issues/1139
73
- if (queryStream && queryStream.destroy) {
74
- queryStream.destroy(new Error('stream destroyed'));
75
- }
76
- },
77
70
  });
78
- stream.on('pipe', (qs) => {
79
- queryStream = qs;
71
+ stream.on('close', () => {
72
+ this.client.releaseConnection(this.connection);
80
73
  });
81
74
 
82
75
  const connectionAcquirePromise = this.ensureConnection(
@@ -225,8 +225,7 @@ function rawOrFn(value, method, builder, client, bindingHolder) {
225
225
  compileCallback(value, method, client, bindingHolder),
226
226
  undefined,
227
227
  builder,
228
- client,
229
- bindingHolder
228
+ client
230
229
  );
231
230
  }
232
231
  return unwrapRaw(value, undefined, builder, client, bindingHolder) || '';
@@ -5,6 +5,10 @@ const QueryInterface = require('../query/method-constants');
5
5
  const makeKnex = require('./make-knex');
6
6
  const { KnexTimeoutError } = require('../util/timeout');
7
7
  const { resolveConfig } = require('./internal/config-resolver');
8
+ const SchemaBuilder = require('../schema/builder');
9
+ const ViewBuilder = require('../schema/viewbuilder');
10
+ const ColumnBuilder = require('../schema/columnbuilder');
11
+ const TableBuilder = require('../schema/tablebuilder');
8
12
 
9
13
  function knex(config) {
10
14
  const { resolvedConfig, Dialect } = resolveConfig(...arguments);
@@ -28,4 +32,28 @@ knex.QueryBuilder = {
28
32
  },
29
33
  };
30
34
 
35
+ knex.SchemaBuilder = {
36
+ extend: function (methodName, fn) {
37
+ SchemaBuilder.extend(methodName, fn);
38
+ },
39
+ };
40
+
41
+ knex.ViewBuilder = {
42
+ extend: function (methodName, fn) {
43
+ ViewBuilder.extend(methodName, fn);
44
+ },
45
+ };
46
+
47
+ knex.ColumnBuilder = {
48
+ extend: function (methodName, fn) {
49
+ ColumnBuilder.extend(methodName, fn);
50
+ },
51
+ };
52
+
53
+ knex.TableBuilder = {
54
+ extend: function (methodName, fn) {
55
+ TableBuilder.extend(methodName, fn);
56
+ },
57
+ };
58
+
31
59
  module.exports = knex;
@@ -2,7 +2,7 @@ const Client = require('../../client');
2
2
  const { SUPPORTED_CLIENTS } = require('../../constants');
3
3
 
4
4
  const parseConnection = require('./parse-connection');
5
- const { resolveClientNameWithAliases } = require('../../util/helpers');
5
+ const { getDialectByNameOrAlias } = require('../../dialects');
6
6
 
7
7
  function resolveConfig(config) {
8
8
  let Dialect;
@@ -34,8 +34,7 @@ function resolveConfig(config) {
34
34
  );
35
35
  }
36
36
 
37
- const resolvedClientName = resolveClientNameWithAliases(clientName);
38
- Dialect = require(`../../dialects/${resolvedClientName}/index.js`);
37
+ Dialect = getDialectByNameOrAlias(clientName);
39
38
  }
40
39
 
41
40
  // If config connection parameter is passed as string, try to parse it
@@ -69,8 +69,10 @@ function connectionObject(parsed) {
69
69
  }
70
70
  if (parsed.searchParams) {
71
71
  for (const [key, value] of parsed.searchParams.entries()) {
72
- const isMySQLLike = ['mysql:', 'mariadb:'].includes(parsed.protocol);
73
- if (isMySQLLike) {
72
+ const isNestedConfigSupported = ['mysql:', 'mariadb:', 'mssql:'].includes(
73
+ parsed.protocol
74
+ );
75
+ if (isNestedConfigSupported) {
74
76
  try {
75
77
  connection[key] = JSON.parse(value);
76
78
  } catch (err) {
@@ -41,7 +41,7 @@ class MigrationGenerator {
41
41
 
42
42
  _getNewMigrationName(name) {
43
43
  if (name[0] === '-') name = name.slice(1);
44
- return yyyymmddhhmmss() + '_' + name + '.' + this.config.extension;
44
+ return yyyymmddhhmmss() + '_' + name + '.' + this.config.extension.split('-')[0];
45
45
  }
46
46
 
47
47
  _getNewMigrationPath(name) {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @param { import("knex").Knex } knex
3
+ * @returns { Promise<void> }
4
+ */
5
+ exports.up = function({schema}) {
6
+ <% if (d.tableName) { %>
7
+ return schema.createTable("<%= d.tableName %>", function(t) {
8
+ t.increments();
9
+ t.timestamp();
10
+ });
11
+ <% } %>
12
+ };
13
+
14
+ /**
15
+ * @param { import("knex").Knex } knex
16
+ * @returns { Promise<void> }
17
+ */
18
+ exports.down = function({schema}) {
19
+ <% if (d.tableName) { %>
20
+ return schema.dropTable("<%= d.tableName %>");
21
+ <% } %>
22
+ };
@@ -0,0 +1,21 @@
1
+ import { Knex } from "knex";
2
+
3
+ <% if (d.tableName) { %>
4
+ export async function up({schema}: Knex): Promise<Knex.SchemaBuilder> {
5
+ return schema.createTable("<%= d.tableName %>", (t) => {
6
+ t.increments();
7
+ t.timestamps();
8
+ });
9
+ }
10
+ <% } else { %>
11
+ export async function up({schema}: Knex): Promise<void> {
12
+ }
13
+ <% } %>
14
+ <% if (d.tableName) { %>
15
+ export async function down({schema}: Knex): Promise<Knex.SchemaBuilder> {
16
+ return schema.dropTable("<%= d.tableName %>");
17
+ }
18
+ <% } else { %>
19
+ export async function down({schema}: Knex): Promise<void> {
20
+ }
21
+ <% } %>
@@ -1,5 +1,6 @@
1
1
  const { EventEmitter } = require('events');
2
2
  const toArray = require('lodash/toArray');
3
+ const assign = require('lodash/assign');
3
4
  const { addQueryContext } = require('../util/helpers');
4
5
  const saveAsyncStack = require('../util/save-async-stack');
5
6
  const {
@@ -96,6 +97,17 @@ class SchemaBuilder extends EventEmitter {
96
97
  };
97
98
  });
98
99
 
100
+
101
+ SchemaBuilder.extend = (methodName, fn) => {
102
+ if (Object.prototype.hasOwnProperty.call(SchemaBuilder.prototype, methodName)) {
103
+ throw new Error(
104
+ `Can't extend SchemaBuilder with existing method ('${methodName}').`
105
+ );
106
+ }
107
+
108
+ assign(SchemaBuilder.prototype, { [methodName]: fn });
109
+ };
110
+
99
111
  augmentWithBuilderInterface(SchemaBuilder);
100
112
  addQueryContext(SchemaBuilder);
101
113