Repository: knex/knex
Pull request #5070 (2022-03-18 09:14:15)

Bump debug from 4.3.3 to 4.3.4
Bumps [debug](https://github.com/debug-js/debug) from 4.3.3 to 4.3.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/debug-js/debug/releases">debug's releases</a>.</em></p>
<blockquote>
<h2>4.3.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Add section about configuring JS console to show debug messages by <a href="https://github.com/gitname"><code>@​gitname</code></a> in <a href="https://github-redirect.dependabot.com/debug-js/debug/pull/866">debug-js/debug#866</a></li>
<li>Replace deprecated String.prototype.substr() by <a href="https://github.com/CommanderRoot"><code>@​CommanderRoot</code></a> in <a href="https://github-redirect.dependabot.com/debug-js/debug/pull/876">debug-js/debug#876</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/gitname"><code>@​gitname</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/debug-js/debug/pull/866">debug-js/debug#866</a></li>
<li><a href="https://github.com/CommanderRoot"><code>@​CommanderRoot</code></a> made their first contribution in <a href="https://github-redirect.dependabot.com/debug-js/debug/pull/876">debug-js/debug#876</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/debug-js/debug/compare/4.3.3...4.3.4">https://github.com/debug-js/debug/compare/4.3.3...4.3.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/debug-js/debug/commit/da66c86c5fd71ef570f36b5b1edfa4472149f1bc"><code>da66c86</code></a> 4.3.4</li>
<li><a href="https://github.com/debug-js/debug/commit/9b334123f1331a252bc27c99c33b5c4f199d200f"><code>9b33412</code></a> replace deprecated String.prototype.substr() (<a href="https://github-redirect.dependabot.com/debug-js/debug/issues/876">#876</a>)</li>
<li><a href="https://github.com/debug-js/debug/commit/c0805cc4d3b2c7c987567e99ecaec78840516d7b"><code>c0805cc</code></a> add section about configuring JS console to show debug messages (<a href="https://github-redirect.dependabot.com/debug-js/debug/issues/866">#866</a>)</li>
<li>See full diff in <a href="https://github.com/debug-js/debug/compare/4.3.3...4.3.4">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=debug&package-manager=npm_and_yarn&previous-version=4.3.3&new-version=4.3.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index ffddd909..c04820d7 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -20,7 +20,7 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@v2.4.0
+      uses: actions/checkout@v3
 
     - name: Initialize CodeQL
       uses: github/codeql-action/init@v1
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 3df58f04..d6621cd4 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -19,7 +19,7 @@ jobs:
 
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v2.4.0
+        uses: actions/checkout@v3
         with:
           fetch-depth: 1
 
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index 9a8432e2..71c1cfc5 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -21,7 +21,7 @@ jobs:
 
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v2.4.0
+        uses: actions/checkout@v3
         with:
           fetch-depth: 1
 
diff --git a/lib/query/querycompiler.js b/lib/query/querycompiler.js
index a7a4997a..a4a09d27 100644
--- a/lib/query/querycompiler.js
+++ b/lib/query/querycompiler.js
@@ -125,16 +125,27 @@ class QueryCompiler {
     let sql = this.with();
 
     let unionStatement = '';
-    // Compute all statements to main query
-    const statements = components.map((component) => {
+
+    const firstStatements = [];
+    const endStatements = [];
+
+    components.forEach((component) => {
       const statement = this[component](this);
       // We store the 'union' statement to append it at the end.
       // We still need to call the component sequentially because of
       // order of bindings.
-      if (component === 'union') {
-        unionStatement = statement;
-      } else {
-        return statement;
+      switch (component) {
+        case 'union':
+          unionStatement = statement;
+          break;
+        case 'columns':
+        case 'join':
+        case 'where':
+          firstStatements.push(statement);
+          break;
+        default:
+          endStatements.push(statement);
+          break;
       }
     });
 
@@ -144,15 +155,22 @@ class QueryCompiler {
     const wrapMainQuery =
       this.grouped.union &&
       this.grouped.union.map((u) => u.wrap).some((u) => u);
-    const allStatements =
-      (wrapMainQuery ? '(' : '') +
-      compact(statements).join(' ') +
-      (wrapMainQuery ? ')' : '');
 
     if (this.onlyUnions()) {
-      sql += unionStatement + ' ' + allStatements;
+      const statements = compact(firstStatements.concat(endStatements)).join(
+        ' '
+      );
+      sql += unionStatement + (statements ? ' ' + statements : '');
     } else {
-      sql += allStatements + (unionStatement ? ' ' + unionStatement : '');
+      const allStatements =
+        (wrapMainQuery ? '(' : '') +
+        compact(firstStatements).join(' ') +
+        (wrapMainQuery ? ')' : '');
+      const endStat = compact(endStatements).join(' ');
+      sql +=
+        allStatements +
+        (unionStatement ? ' ' + unionStatement : '') +
+        (endStat ? ' ' + endStat : endStat);
     }
     return sql;
   }
diff --git a/package.json b/package.json
index 2417471e..d49cc8e3 100644
--- a/package.json
+++ b/package.json
@@ -56,7 +56,7 @@
   "dependencies": {
     "colorette": "2.0.16",
     "commander": "^8.3.0",
-    "debug": "4.3.3",
+    "debug": "4.3.4",
     "escalade": "^3.1.1",
     "esm": "^3.2.25",
     "get-package-type": "^0.1.0",
@@ -124,14 +124,14 @@
     "oracledb": "^5.3.0",
     "pg": "^8.7.1",
     "pg-query-stream": "^4.2.1",
-    "prettier": "2.5.1",
+    "prettier": "2.6.0",
     "rimraf": "^3.0.2",
     "sinon": "^13.0.1",
     "sinon-chai": "^3.7.0",
     "source-map-support": "^0.5.21",
     "tap-spec": "^5.0.0",
     "tape": "^5.5.0",
-    "tedious": "^12.3.0",
+    "tedious": "^14.3.0",
     "toxiproxy-node-client": "^2.0.6",
     "ts-node": "^10.4.0",
     "tsd": "^0.19.1",
diff --git a/types/index.d.ts b/types/index.d.ts
index 358a2f71..fe2f1ab0 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -307,7 +307,7 @@ interface DMLOptions {
   includeTriggerModifications?: boolean;
 }
 
-export interface Knex<TRecord extends {} = any, TResult = Record<string, any>[]>
+export interface Knex<TRecord extends {} = any, TResult = any[]>
   extends Knex.QueryInterface<TRecord, TResult>, events.EventEmitter {
   <TTable extends Knex.TableNames>(
     tableName: TTable,


Test patch:
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index f9506b3f..2ede409f 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -23,7 +23,7 @@ jobs:
 
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v2.4.0
+        uses: actions/checkout@v3
         with:
           fetch-depth: 1
 
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index b069edd0..3a59eedc 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -21,7 +21,7 @@ jobs:
 
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v2.4.0
+        uses: actions/checkout@v3
         with:
           fetch-depth: 1
 
diff --git a/test-tsd/types.test-d.ts b/test-tsd/types.test-d.ts
index 05478f34..471f2fff 100644
--- a/test-tsd/types.test-d.ts
+++ b/test-tsd/types.test-d.ts
@@ -19,6 +19,18 @@ expectType<Knex<any, unknown[]>>(knexCjsImport.knex({}));
 expectType<KnexTimeoutError>(new knex.KnexTimeoutError());
 expectType<KnexTimeoutError>(new knex.KnexTimeoutError());
 
+// Knex instances need to be assigned first so their generic types aren't inferred
+const k1 = knex({});
+expectAssignable<Knex>(k1);
+const k2 = knexStar.default({});
+expectAssignable<Knex>(k2);
+const k3 = knexStar.knex({});
+expectAssignable<Knex>(k3);
+const k4 = knexCjsImport.default({});
+expectAssignable<Knex>(k4);
+const k5 = knexCjsImport.knex({});
+expectAssignable<Knex>(k5);
+
 // eslint-disable-next-line
 expectType<any>(knexCjs({}));
 // eslint-disable-next-line
diff --git a/test/cli/esm-interop.spec.js b/test/cli/esm-interop.spec.js
index 6fda578d..f3b24800 100644
--- a/test/cli/esm-interop.spec.js
+++ b/test/cli/esm-interop.spec.js
@@ -660,7 +660,7 @@ const fixture = [
   },
 ].filter(Boolean);
 
-describe.only('esm interop and mjs support', () => {
+describe('esm interop and mjs support', () => {
   before(() => {
     process.env.KNEX_PATH = '../knex.js';
   });
diff --git a/test/integration2/query/select/selects.spec.js b/test/integration2/query/select/selects.spec.js
index 335658a1..ee4212be 100644
--- a/test/integration2/query/select/selects.spec.js
+++ b/test/integration2/query/select/selects.spec.js
@@ -68,12 +68,12 @@ describe('Selects', function () {
         // await dropTables(knex);
       });
 
-      it('runs with no conditions', function () {
-        return knex('accounts').select();
+      it('runs with no conditions', async () => {
+        await knex('accounts').select();
       });
 
       it('returns an array of a single column with `pluck`', async () => {
-        return knex
+        await knex
           .pluck('id')
           .orderBy('id')
           .from('accounts')
@@ -123,8 +123,8 @@ describe('Selects', function () {
           });
       });
 
-      it('can pluck a qualified column name, #1619', function () {
-        return knex
+      it('can pluck a qualified column name, #1619', async () => {
+        await knex
           .pluck('accounts.id')
           .from('accounts')
           .orderBy('accounts.id')
@@ -174,8 +174,8 @@ describe('Selects', function () {
           });
       });
 
-      it('starts selecting at offset', function () {
-        return knex
+      it('starts selecting at offset', async () => {
+        await knex
           .pluck('id')
           .orderBy('id')
           .from('accounts')
@@ -273,7 +273,7 @@ describe('Selects', function () {
       });
 
       it('#4199 - ignores invalid hint comments', async function () {
-        return knex
+        await knex
           .select('id')
           .orderBy('id')
           .from('accounts')
@@ -387,8 +387,8 @@ describe('Selects', function () {
           });
       });
 
-      it('returns a single entry with first', function () {
-        return knex
+      it('returns a single entry with first', async () => {
+        await knex
           .first('id', 'first_name')
           .orderBy('id')
           .from('accounts')
@@ -438,20 +438,17 @@ describe('Selects', function () {
           });
       });
 
-      it('allows you to stream', function () {
+      it('allows you to stream', async function () {
         if (isPgNative(knex)) {
           return this.skip();
         }
         let count = 0;
-        return knex('accounts')
-          .stream(function (rowStream) {
-            rowStream.on('data', function () {
-              count++;
-            });
-          })
-          .then(function () {
-            assert(count === 8, 'Eight rows should have been streamed');
+        await knex('accounts').stream(function (rowStream) {
+          rowStream.on('data', function () {
+            count++;
           });
+        });
+        assert(count === 8, 'Eight rows should have been streamed');
       });
 
       it('returns a stream if not passed a function', function (done) {
@@ -467,12 +464,12 @@ describe('Selects', function () {
         });
       });
 
-      it('allows you to stream with mysql dialect options', function () {
+      it('allows you to stream with mysql dialect options', async function () {
         if (!isMysql(knex)) {
           return this.skip();
         }
         const rows = [];
-        return knex('accounts')
+        await knex('accounts')
           .options({
             typeCast(field, next) {
               let val;
@@ -487,15 +484,13 @@ describe('Selects', function () {
             rowStream.on('data', function (row) {
               rows.push(row);
             });
-          })
-          .then(function () {
-            expect(rows).to.have.lengthOf(8);
-            rows.forEach((row) => {
-              ['first_name', 'last_name', 'email'].forEach((field) =>
-                expect(row[field]).to.equal(row[field].toUpperCase())
-              );
-            });
           });
+        expect(rows).to.have.lengthOf(8);
+        rows.forEach((row) => {
+          ['first_name', 'last_name', 'email'].forEach((field) =>
+            expect(row[field]).to.equal(row[field].toUpperCase())
+          );
+        });
       });
 
       it('emits error on the stream, if not passed a function, and connecting fails', function () {
@@ -582,8 +577,8 @@ describe('Selects', function () {
           });
       });
 
-      it('uses "orderBy"', function () {
-        return knex('accounts')
+      it('uses "orderBy"', async function () {
+        await knex('accounts')
           .pluck('id')
           .orderBy('id', 'desc')
           .testSql(function (tester) {
@@ -735,8 +730,8 @@ describe('Selects', function () {
         await knex.schema.dropTable('OrderByNullTest');
       });
 
-      it('#1276 - Dates NULL should be returned as NULL, not as new Date(null)', function () {
-        return knex.schema
+      it('#1276 - Dates NULL should be returned as NULL, not as new Date(null)', async function () {
+        await knex.schema
           .dropTableIfExists('DatesTest')
           .createTable('DatesTest', function (table) {
             table.increments('id').primary();
@@ -744,37 +739,29 @@ describe('Selects', function () {
             table.timestamp('timeStampCol').nullable().defaultTo(null); // MySQL defaults TIMESTAMP columns to current timestamp
             table.date('dateCol');
             table.time('timeCol');
-          })
-          .then(function () {
-            return knex('DatesTest').insert([
-              {
-                dateTimeCol: null,
-                timeStampCol: null,
-                dateCol: null,
-                timeCol: null,
-              },
-            ]);
-          })
-          .then(function () {
-            return knex('DatesTest').select();
-          })
-          .then(function (rows) {
-            expect(rows[0].dateTimeCol).to.equal(null);
-            expect(rows[0].timeStampCol).to.equal(null);
-            expect(rows[0].dateCol).to.equal(null);
-            expect(rows[0].timeCol).to.equal(null);
           });
+        await knex('DatesTest').insert([
+          {
+            dateTimeCol: null,
+            timeStampCol: null,
+            dateCol: null,
+            timeCol: null,
+          },
+        ]);
+        const rows = await knex('DatesTest').select();
+        expect(rows[0].dateTimeCol).to.equal(null);
+        expect(rows[0].timeStampCol).to.equal(null);
+        expect(rows[0].dateCol).to.equal(null);
+        expect(rows[0].timeCol).to.equal(null);
       });
 
-      it('has a "distinct" clause', function () {
-        return Promise.all([
-          knex('accounts')
-            .select()
-            .distinct('email')
-            .where('logins', 2)
-            .orderBy('email'),
-          knex('accounts').distinct('email').select().orderBy('email'),
-        ]);
+      it('has a "distinct" clause', async function () {
+        await knex('accounts')
+          .select()
+          .distinct('email')
+          .where('logins', 2)
+          .orderBy('email');
+        await knex('accounts').distinct('email').select().orderBy('email');
       });
 
       it('supports "distinct on"', async function () {
@@ -924,11 +911,10 @@ describe('Selects', function () {
         });
       });
 
-      it('always returns the response object from raw', function () {
+      it('always returns the response object from raw', async function () {
         if (isPostgreSQL(knex)) {
-          return knex.raw('select id from accounts').then(function (resp) {
-            assert(Array.isArray(resp.rows) === true);
-          });
+          const resp = await knex.raw('select id from accounts');
+          assert(Array.isArray(resp.rows) === true);
         }
       });
 
@@ -954,82 +940,72 @@ describe('Selects', function () {
         return knex('accounts').where('id', 1).forUpdate().first();
       });
 
-      it('select for update locks selected row', function () {
+      it('select for update locks selected row', async function () {
         if (isSQLite(knex)) {
           return this.skip();
         }
 
-        return knex('test_default_table')
-          .insert({ string: 'making sure there is a row to lock' })
-          .then(() => {
-            return knex
-              .transaction((trx) => {
-                // select all from test table and lock
-                return trx('test_default_table')
-                  .forUpdate()
-                  .then((res) => {
-                    // try to select stuff from table in other connection should just hang...
-                    return knex('test_default_table').forUpdate().timeout(100);
-                  });
-              })
+        await knex('test_default_table').insert({
+          string: 'making sure there is a row to lock',
+        });
+        try {
+          await knex.transaction((trx) => {
+            // select all from test table and lock
+            return trx('test_default_table')
+              .forUpdate()
               .then((res) => {
-                expect('Second query should have timed out').to.be.false;
-              })
-              .catch((err) => {
-                expect(err.message).to.be.contain(
-                  'Defined query timeout of 100ms exceeded when running query'
-                );
+                // try to select stuff from table in other connection should just hang...
+                return knex('test_default_table').forUpdate().timeout(100);
               });
           });
+        } catch (err) {
+          expect(err.message).to.be.contain(
+            'Defined query timeout of 100ms exceeded when running query'
+          );
+          return;
+        }
+        expect('Second query should have timed out').to.be.false;
       });
 
-      it('select for update locks only some tables, #2834', function () {
+      it('select for update locks only some tables, #2834', async function () {
         if (!isPostgreSQL(knex)) {
           return this.skip();
         }
 
-        return knex('test_default_table')
-          .insert({ string: 'making sure there is a row to lock', tinyint: 1 })
-          .then(() => {
-            return knex('test_default_table2')
-              .insert({
-                string: 'making sure there is a row to lock',
-                tinyint: 1,
+        await knex('test_default_table').insert({
+          string: 'making sure there is a row to lock',
+          tinyint: 1,
+        });
+        await knex('test_default_table2').insert({
+          string: 'making sure there is a row to lock',
+          tinyint: 1,
+        });
+        try {
+          await knex.transaction((trx) => {
+            // select all from two test tables and lock only one table
+            return trx('test_default_table')
+              .innerJoin(
+                'test_default_table2',
+                'test_default_table.tinyint',
+                'test_default_table2.tinyint'
+              )
+              .forUpdate('test_default_table')
+              .then((res) => {
+                // try to select stuff from unlocked table should not hang...
+                return knex('test_default_table2').forUpdate().timeout(150);
               })
-              .then(() => {
-                return knex
-                  .transaction((trx) => {
-                    // select all from two test tables and lock only one table
-                    return trx('test_default_table')
-                      .innerJoin(
-                        'test_default_table2',
-                        'test_default_table.tinyint',
-                        'test_default_table2.tinyint'
-                      )
-                      .forUpdate('test_default_table')
-                      .then((res) => {
-                        // try to select stuff from unlocked table should not hang...
-                        return knex('test_default_table2')
-                          .forUpdate()
-                          .timeout(150);
-                      })
-                      .then((res) => {
-                        // try to select stuff from table in other connection should just hang...
-                        return knex('test_default_table')
-                          .forUpdate()
-                          .timeout(100);
-                      });
-                  })
-                  .then((res) => {
-                    expect('Second query should have timed out').to.be.false;
-                  })
-                  .catch((err) => {
-                    expect(err.message).to.be.contain(
-                      'Defined query timeout of 100ms exceeded when running query'
-                    );
-                  });
+              .then((res) => {
+                // try to select stuff from table in other connection should just hang...
+                return knex('test_default_table').forUpdate().timeout(100);
               });
           });
+        } catch (err) {
+          expect(err.message).to.be.contain(
+            'Defined query timeout of 100ms exceeded when running query'
+          );
+          return;
+        }
+        expect('Second query should have timed out').to.be.false;
       });
 
       it('select for no key update doesnt stop other transactions from inserting into tables that have a foreign key relationship', async function () {
@@ -1038,34 +1014,27 @@ describe('Selects', function () {
         }
 
         await createParentAndChildTables(knex);
-
-        return knex('parent')
-          .insert({
-            id: 1,
-          })
-          .then(() => {
-            return knex('child')
-              .insert({
-                id: 1,
-                parent_id: 1,
-              })
-              .then(() => {
-                return knex.transaction((trx) => {
-                  // select all from the parent table in the for no key update mode
-                  return trx('parent')
-                    .forNoKeyUpdate()
-                    .then((res) => {
-                      // Insert should into the child table not hang
-                      return knex('child')
-                        .insert({
-                          id: 2,
-                          parent_id: 1,
-                        })
-                        .timeout(150);
-                    });
-                });
-              });
-          });
+        await knex('parent').insert({
+          id: 1,
+        });
+        await knex('child').insert({
+          id: 1,
+          parent_id: 1,
+        });
+        await knex.transaction((trx) => {
+          // select all from the parent table in the for no key update mode
+          return trx('parent')
+            .forNoKeyUpdate()
+            .then((res) => {
+              // Insert should into the child table not hang
+              return knex('child')
+                .insert({
+                  id: 2,
+                  parent_id: 1,
+                })
+                .timeout(150);
+            });
+        });
       });
 
       it('select for key share blocks select for update but not select for no key update', async function () {
@@ -1073,76 +1042,69 @@ describe('Selects', function () {
           return this.skip();
         }
 
-        return knex('test_default_table')
-          .insert({ string: 'making sure there is a row to lock' })
-          .then(() => {
-            return knex
-              .transaction((trx) => {
-                // select all from test table and lock
-                return trx('test_default_table')
-                  .forKeyShare()
-                  .then((res) => {
-                    // trying to select stuff from table in other connection should succeed with for no key update
-                    return knex('test_default_table')
-                      .forNoKeyUpdate()
-                      .timeout(200);
-                  })
-                  .then((res) => {
-                    // trying to select stuff from table in other connection should hang with for update
-                    return knex('test_default_table').forUpdate().timeout(100);
-                  });
-              })
+        await knex('test_default_table').insert({
+          string: 'making sure there is a row to lock',
+        });
+        try {
+          await knex.transaction((trx) => {
+            // select all from test table and lock
+            return trx('test_default_table')
+              .forKeyShare()
               .then((res) => {
-                expect('Second query should have timed out').to.be.false;
+                // trying to select stuff from table in other connection should succeed with for no key update
+                return knex('test_default_table').forNoKeyUpdate().timeout(200);
               })
-              .catch((err) => {
-                expect(err.message).to.be.contain(
-                  'Defined query timeout of 100ms exceeded when running query'
-                );
+              .then((res) => {
+                // trying to select stuff from table in other connection should hang with for update
+                return knex('test_default_table').forUpdate().timeout(100);
               });
           });
+        } catch (err) {
+          expect(err.message).to.be.contain(
+            'Defined query timeout of 100ms exceeded when running query'
+          );
+          return;
+        }
+        expect('Second query should have timed out').to.be.false;
       });
 
-      it('select for share prevents updating in other transaction', function () {
+      it('select for share prevents updating in other transaction', async function () {
         // Query cancellation is not yet implemented for CockroachDB
         if (isSQLite(knex) || isOracle(knex) || isCockroachDB(knex)) {
           return this.skip();
         }
-
-        return knex('test_default_table')
-          .insert({ string: 'making sure there is a row to lock' })
-          .then(() => {
-            return knex
-              .transaction((trx) => {
-                // select all from test table and lock
-                return trx('test_default_table')
-                  .forShare()
-                  .then((res) => {
-                    // try to update row that was selected for share should just hang...
-                    return knex.transaction((trx2) => {
-                      return trx2('test_default_table')
-                        .update({ string: 'foo' })
-                        .timeout(100);
-                    });
-                  });
-              })
+        await knex('test_default_table').insert({
+          string: 'making sure there is a row to lock',
+        });
+        try {
+          await knex.transaction((trx) => {
+            // select all from test table and lock
+            return trx('test_default_table')
+              .forShare()
               .then((res) => {
-                expect('Second query should have timed out').to.be.false;
-              })
-              .catch((err) => {
-                // mssql fails because it tries to rollback at the same time when update query is running
-                // hopefully for share really works though...
-                if (isMssql(knex)) {
-                  expect(err.message).to.be.contain(
-                    "Can't rollback transaction. There is a request in progress"
-                  );
-                } else {
-                  expect(err.message).to.be.contain(
-                    'Defined query timeout of 100ms exceeded when running query'
-                  );
-                }
+                // try to update row that was selected for share should just hang...
+                return knex.transaction((trx2) => {
+                  return trx2('test_default_table')
+                    .update({ string: 'foo' })
+                    .timeout(100);
+                });
               });
           });
+        } catch (err) {
+          // mssql fails because it tries to rollback at the same time when update query is running
+          // hopefully for share really works though...
+          if (isMssql(knex)) {
+            expect(err.message).to.be.contain(
+              "Can't rollback transaction. There is a request in progress"
+            );
+          } else {
+            expect(err.message).to.be.contain(
+              'Defined query timeout of 100ms exceeded when running query'
+            );
+          }
+          return;
+        }
+        expect('Second query should have timed out').to.be.false;
       });
 
       it('forUpdate().skipLocked() with order by should return the first non-locked row', async function () {
@@ -1268,43 +1230,39 @@ describe('Selects', function () {
         const subquery = knex
           .from('accounts')
           .whereBetween('id', [result[0].id, result[2].id]);
-        return knex
-          .pluck('id')
-          .orderBy('id')
-          .from(subquery)
-          .then(
-            (rows) => {
-              expect(knex.client.driverName).to.oneOf([
-                'sqlite3',
-                'oracledb',
-                'cockroachdb',
-                'better-sqlite3',
-              ]);
-
-              if (knex.client.driverName !== 'cockroachdb') {
-                assertNumberArrayStrict(knex, rows, [
-                  result[0].id,
-                  result[1].id,
-                  result[2].id,
-                ]);
-              } else {
-                expect(rows.length).to.equal(3);
-              }
-            },
-            (e) => {
-              if (isMysql(knex)) {
-                expect(e.errno).to.equal(1248);
-              } else if (isPostgreSQL(knex)) {
-                expect(e.message).to.contain('must have an alias');
-              } else if (isMssql(knex)) {
-                expect(e.message).to.contain(
-                  "Incorrect syntax near the keyword 'order'"
-                );
-              } else {
-                throw e;
-              }
-            }
-          );
+
+        try {
+          const rows = await knex.pluck('id').orderBy('id').from(subquery);
+
+          expect(knex.client.driverName).to.oneOf([
+            'sqlite3',
+            'oracledb',
+            'cockroachdb',
+            'better-sqlite3',
+          ]);
+
+          if (knex.client.driverName !== 'cockroachdb') {
+            assertNumberArrayStrict(knex, rows, [
+              result[0].id,
+              result[1].id,
+              result[2].id,
+            ]);
+          } else {
+            expect(rows.length).to.equal(3);
+          }
+        } catch (err) {
+          if (isMysql(knex)) {
+            expect(err.errno).to.equal(1248);
+          } else if (isPostgreSQL(knex)) {
+            expect(err.message).to.contain('must have an alias');
+          } else if (isMssql(knex)) {
+            expect(err.message).to.contain(
+              "Incorrect syntax near the keyword 'order'"
+            );
+          } else {
+            throw err;
+          }
+        }
       });
 
       describe('"with" tests', () => {
diff --git a/test/integration2/query/select/unions.spec.js b/test/integration2/query/select/unions.spec.js
index 8a01a688..429c1cd3 100644
--- a/test/integration2/query/select/unions.spec.js
+++ b/test/integration2/query/select/unions.spec.js
@@ -7,6 +7,7 @@ const {
   isPgBased,
   isSQLite,
   isPostgreSQL,
+  isMysql,
 } = require('../../../util/db-helpers');
 const { assertNumberArray } = require('../../../util/assertHelper');
 const {
@@ -22,6 +23,7 @@ const {
   getAllDbs,
   getKnexForDb,
 } = require('../../util/knex-instance-provider');
+const logger = require('../../../integration/logger');
 
 describe('unions', function () {
   getAllDbs().forEach((db) => {
@@ -30,7 +32,7 @@ describe('unions', function () {
       const unionCols = ['last_name', 'phone'];
 
       before(async () => {
-        knex = getKnexForDb(db);
+        knex = logger(getKnexForDb(db));
 
         await dropTables(knex);
         await createUsers(knex);
@@ -163,28 +165,344 @@ describe('unions', function () {
           );
       });
 
-      it('handles nested unions with group by and limit', async function () {
+      it('handles nested unions with limit', async function () {
         if (!isPostgreSQL(knex)) {
           return this.skip();
         }
         const results = await knex('accounts')
-          .count('logins')
           .select('last_name')
-          .limit(1)
-          .groupBy('last_name')
           .unionAll(function () {
-            this.count('logins')
-              .select('last_name')
-              .from('accounts')
-              .limit(1)
-              .groupBy('last_name')
-              .orderBy('last_name')
-              .where('logins', '>', '1');
-          }, true);
-        expect(results).to.eql([
-          { count: '2', last_name: 'User2' },
-          { count: '4', last_name: 'User' },
-        ]);
+            this.select('last_name').from('accounts');
+          })
+          .first();
+        expect(results).to.eql({
+          last_name: 'User',
+        });
+      });
+
+      describe('unions with wrapped queries', () => {
+        it('nested unions with group by in subqueries and limit and orderby', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex
+            .select('last_name')
+            .unionAll(
+              [
+                knex.select('last_name').from('accounts').groupBy('last_name'),
+                knex.select('last_name').from('accounts').groupBy('last_name'),
+              ],
+              true
+            )
+            .limit(5)
+            .orderBy('last_name')
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select "last_name" from "accounts" group by "last_name") union all (select "last_name" from "accounts" group by "last_name") order by "last_name" asc limit ?',
+                [5],
+                [
+                  { last_name: 'User' },
+                  { last_name: 'User' },
+                  { last_name: 'User2' },
+                  { last_name: 'User2' },
+                ]
+              );
+              tester(
+                'mysql',
+                '(select `last_name` from `accounts` group by `last_name`) union all (select `last_name` from `accounts` group by `last_name`) order by `last_name` asc limit ?',
+                [5],
+                [
+                  { last_name: 'User' },
+                  { last_name: 'User' },
+                  { last_name: 'User2' },
+                  { last_name: 'User2' },
+                ]
+              );
+              tester(
+                'mysql2',
+                '(select `last_name` from `accounts` group by `last_name`) union all (select `last_name` from `accounts` group by `last_name`) order by `last_name` asc limit ?',
+                [5],
+                [
+                  { last_name: 'User' },
+                  { last_name: 'User' },
+                  { last_name: 'User2' },
+                  { last_name: 'User2' },
+                ]
+              );
+            });
+        });
+
+        it('nested unions with first', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex
+            .unionAll(
+              function () {
+                this.select('last_name').from('accounts');
+              },
+              function () {
+                this.select('last_name').from('accounts');
+              },
+              true
+            )
+            .first()
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select "last_name" from "accounts") union all (select "last_name" from "accounts") limit ?',
+                [1],
+                {
+                  last_name: 'User',
+                }
+              );
+              tester(
+                'mysql',
+                '(select `last_name` from `accounts`) union all (select `last_name` from `accounts`) limit ?',
+                [1],
+                {
+                  last_name: 'User',
+                }
+              );
+              tester(
+                'mysql2',
+                '(select `last_name` from `accounts`) union all (select `last_name` from `accounts`) limit ?',
+                [1],
+                {
+                  last_name: 'User',
+                }
+              );
+            });
+        });
+
+        it('nested unions with order by and limit', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex
+            .unionAll(
+              function () {
+                this.select('last_name').from('accounts');
+              },
+              function () {
+                this.select('last_name').from('accounts');
+              },
+              true
+            )
+            .orderBy('last_name')
+            .limit(2)
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select "last_name" from "accounts") union all (select "last_name" from "accounts") order by "last_name" asc limit ?',
+                [2],
+                [
+                  {
+                    last_name: 'User',
+                  },
+                  {
+                    last_name: 'User',
+                  },
+                ]
+              );
+              tester(
+                'mysql',
+                '(select `last_name` from `accounts`) union all (select `last_name` from `accounts`) order by `last_name` asc limit ?',
+                [2],
+                [
+                  {
+                    last_name: 'User',
+                  },
+                  {
+                    last_name: 'User',
+                  },
+                ]
+              );
+              tester(
+                'mysql2',
+                '(select `last_name` from `accounts`) union all (select `last_name` from `accounts`) order by `last_name` asc limit ?',
+                [2],
+                [
+                  {
+                    last_name: 'User',
+                  },
+                  {
+                    last_name: 'User',
+                  },
+                ]
+              );
+            });
+        });
+
+        it('nested unions with having and groupby in subqueries', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex
+            .unionAll(
+              function () {
+                this.select('last_name')
+                  .from('accounts')
+                  .having('last_name', '!=', 'User')
+                  .groupBy('last_name');
+              },
+              function () {
+                this.select('last_name')
+                  .from('accounts')
+                  .having('last_name', '!=', 'User')
+                  .groupBy('last_name');
+              },
+              true
+            )
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select "last_name" from "accounts" group by "last_name" having "last_name" != ?) union all (select "last_name" from "accounts" group by "last_name" having "last_name" != ?)',
+                ['User', 'User'],
+                [{ last_name: 'User2' }, { last_name: 'User2' }]
+              );
+              tester(
+                'mysql',
+                '(select `last_name` from `accounts` group by `last_name` having `last_name` != ?) union all (select `last_name` from `accounts` group by `last_name` having `last_name` != ?)',
+                ['User', 'User'],
+                [{ last_name: 'User2' }, { last_name: 'User2' }]
+              );
+              tester(
+                'mysql2',
+                '(select `last_name` from `accounts` group by `last_name` having `last_name` != ?) union all (select `last_name` from `accounts` group by `last_name` having `last_name` != ?)',
+                ['User', 'User'],
+                [{ last_name: 'User2' }, { last_name: 'User2' }]
+              );
+            });
+        });
+
+        it('nested unions all with order by in subqueries and limit', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex
+            .unionAll(
+              function () {
+                this.select('last_name').from('accounts').orderBy('last_name');
+              },
+              function () {
+                this.select('last_name').from('accounts').orderBy('last_name');
+              },
+              true
+            )
+            .limit(2)
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select "last_name" from "accounts" order by "last_name" asc) union all (select "last_name" from "accounts" order by "last_name" asc) limit ?',
+                [2],
+                [{ last_name: 'User' }, { last_name: 'User' }]
+              );
+              tester(
+                'mysql',
+                '(select `last_name` from `accounts` order by `last_name` asc) union all (select `last_name` from `accounts` order by `last_name` asc) limit ?',
+                [2],
+                [{ last_name: 'User' }, { last_name: 'User' }]
+              );
+              tester(
+                'mysql2',
+                '(select `last_name` from `accounts` order by `last_name` asc) union all (select `last_name` from `accounts` order by `last_name` asc) limit ?',
+                [2],
+                [{ last_name: 'User' }, { last_name: 'User' }]
+              );
+            });
+        });
+
+        it('nested unions all with limit in each subqueries', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex
+            .unionAll(
+              [
+                knex.select('last_name').from('accounts').limit(1),
+                knex.select('last_name').from('accounts').limit(1),
+              ],
+              true
+            )
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select "last_name" from "accounts" limit ?) union all (select "last_name" from "accounts" limit ?)',
+                [1, 1],
+                [
+                  {
+                    last_name: 'User',
+                  },
+                  {
+                    last_name: 'User',
+                  },
+                ]
+              );
+              tester(
+                'mysql',
+                '(select `last_name` from `accounts` limit ?) union all (select `last_name` from `accounts` limit ?)',
+                [1, 1],
+                [
+                  {
+                    last_name: 'User',
+                  },
+                  {
+                    last_name: 'User',
+                  },
+                ]
+              );
+              tester(
+                'mysql2',
+                '(select `last_name` from `accounts` limit ?) union all (select `last_name` from `accounts` limit ?)',
+                [1, 1],
+                [
+                  {
+                    last_name: 'User',
+                  },
+                  {
+                    last_name: 'User',
+                  },
+                ]
+              );
+            });
+        });
+
+        it('nested unions with group by and where in subqueries and limit', async function () {
+          if (!isPostgreSQL(knex) && !isMysql(knex)) {
+            return this.skip();
+          }
+          await knex('accounts')
+            .count('logins')
+            .limit(1)
+            .unionAll(function () {
+              this.count('logins')
+                .from('accounts')
+                .groupBy('last_name')
+                .where('logins', '>', '1');
+            }, true)
+            .testSql(function (tester) {
+              tester(
+                'pg',
+                '(select count("logins") from "accounts") union all (select count("logins") from "accounts" where "logins" > ? group by "last_name") limit ?',
+                ['1', 1],
+                [{ count: '8' }]
+              );
+              tester(
+                'mysql',
+                '(select count(`logins`) from `accounts`) union all (select count(`logins`) from `accounts` where `logins` > ? group by `last_name`) limit ?',
+                ['1', 1],
+                [{ 'count(`logins`)': 8 }]
+              );
+              tester(
+                'mysql2',
+                '(select count(`logins`) from `accounts`) union all (select count(`logins`) from `accounts` where `logins` > ? group by `last_name`) limit ?',
+                ['1', 1],
+                [{ 'count(`logins`)': 8 }]
+              );
+            });
+        });
       });
 
       describe('intersects', function () {
diff --git a/test/unit/query/builder.js b/test/unit/query/builder.js
index 2986d6b9..c4a63848 100644
--- a/test/unit/query/builder.js
+++ b/test/unit/query/builder.js
@@ -2296,7 +2296,7 @@ describe('QueryBuilder', () => {
         .first();
       testsql(firstUnionAll, {
         mysql: {
-          sql: '(select * from `users` where `id` = ? group by `id` limit ?) union all (select * from `users` where `id` = ?)',
+          sql: '(select * from `users` where `id` = ?) union all (select * from `users` where `id` = ?) group by `id` limit ?',
           bindings: [1, 2, 1],
         },
         mssql: {
@@ -2304,11 +2304,11 @@ describe('QueryBuilder', () => {
           bindings: [1, 1, 2],
         },
         pg: {
-          sql: '(select * from "users" where "id" = ? group by "id" limit ?) union all (select * from "users" where "id" = ?)',
+          sql: '(select * from "users" where "id" = ?) union all (select * from "users" where "id" = ?) group by "id" limit ?',
           bindings: [1, 2, 1],
         },
         'pg-redshift': {
-          sql: '(select * from "users" where "id" = ? group by "id" limit ?) union all (select * from "users" where "id" = ?)',
+          sql: '(select * from "users" where "id" = ?) union all (select * from "users" where "id" = ?) group by "id" limit ?',
           bindings: [1, 2, 1],
         },
       });
diff --git a/types/test.ts b/types/test.ts
index 038fe6dc..5a25ce76 100644
--- a/types/test.ts
+++ b/types/test.ts
@@ -82,6 +82,9 @@ type _T8 = ExtendsWitness<Knex.QueryBuilder<User, number[]>, Knex.QueryBuilder>;
 type _T9 = ExtendsWitness<Knex.QueryBuilder<any, any[]>, Knex.QueryBuilder>;
 type _T10 = ExtendsWitness<Knex.QueryBuilder<User, number>, Knex.QueryBuilder>;
 
+// Ensure the return type of knex() is compatible with Knex with default parameters
+type _T2_1 = ExtendsWitness<typeof knexInstance, Knex>;
+
 declare module './tables' {
   interface Tables {
     users_inferred: User;