Skip to content

Commit

Permalink
fix(database): pagination counts query must use the subQuery of exten…
Browse files Browse the repository at this point in the history
…ded query builder

Closes #378
  • Loading branch information
thetutlage committed Oct 1, 2018
1 parent 1da1fa1 commit b613b64
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/Database/MonkeyPatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ KnexQueryBuilder.prototype.forPage = function (page = 1, perPage = 20) {
KnexQueryBuilder.prototype.paginate = async function (page = 1, perPage = 20) {
const countByQuery = this.clone()

/**
* Copy the subQuery fn to the clone query. This will make sure
* that build uses the extended query builder methods on the
* cloned query too
*/
countByQuery.subQuery = this.subQuery

/**
* Force cast page and perPage to numbers
*/
Expand Down
24 changes: 24 additions & 0 deletions src/Lucid/QueryBuilder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ const queryMethods = [
class QueryBuilder {
constructor (Model, connection) {
this.Model = Model
this.connectionString = connection

const table = this.Model.prefix ? `${this.Model.prefix}${this.Model.table}` : this.Model.table

/**
Expand Down Expand Up @@ -925,6 +927,28 @@ class QueryBuilder {
this._hiddenFields = fields
return this
}

/**
* Create a clone of Query builder
*
* @method clone
*
* @return {QueryBuilde}
*/
clone () {
const clonedQuery = new QueryBuilder(this.Model, this.connectionString)
clonedQuery.query = this.query.clone()
clonedQuery.query.subQuery = this.query.subQuery

clonedQuery._eagerLoads = this._eagerLoads
clonedQuery._sideLoaded = this._sideLoaded
clonedQuery._visibleFields = this._visibleFields
clonedQuery._hiddenFields = this._hiddenFields
clonedQuery._withCountCounter = this._withCountCounter
clonedQuery.scopesIterator = this.scopesIterator

return clonedQuery
}
}

aggregates.concat(queryMethods).forEach((method) => {
Expand Down
70 changes: 70 additions & 0 deletions test/unit/lucid.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const { Config, setupResolver } = require('@adonisjs/sink')

const helpers = require('./helpers')
const Model = require('../../src/Lucid/Model')
const QueryBuilder = require('../../src/Lucid/QueryBuilder')
const DatabaseManager = require('../../src/Database/Manager')
const VanillaSerializer = require('../../src/Lucid/Serializers/Vanilla')

Expand Down Expand Up @@ -1958,4 +1959,73 @@ test.group('Model', (group) => {
assert.equal(query.sql, helpers.formatQuery('select * from "users" where ("age" > ?)'))
assert.deepEqual(query.bindings, helpers.formatBindings([18]))
})

test('clone query builder', async (assert) => {
class User extends Model {
static scopeAdult (builder) {
builder.where('age', '>', 18)
}
}

User._bootIfNotBooted()
assert.instanceOf(User.query().clone(), QueryBuilder)
})

test('clone query builder must have same constraints', async (assert) => {
class User extends Model {
}

User._bootIfNotBooted()
const query = User.query().where('username', 'virk')
const query1 = query.clone()

assert.instanceOf(query1, QueryBuilder)
assert.equal(query1.toSQL().sql, helpers.formatQuery('select * from "users" where "username" = ?'))
})

test('run whereHas inside cloned query', async (assert) => {
class Profile extends Model {
}

class User extends Model {
profile () {
return this.hasOne(Profile)
}
}

User._bootIfNotBooted()
Profile._bootIfNotBooted()

const query = User.query().clone().where(function () {
this.whereHas('profile')
})

assert.equal(query.toSQL().sql, helpers.formatQuery('select * from "users" where (exists (select * from "profiles" where "users"."id" = "profiles"."user_id"))'))
})

test('run whereHas with paginate', async (assert) => {
class Profile extends Model {
}

class User extends Model {
profile () {
return this.hasOne(Profile)
}
}

User._bootIfNotBooted()
Profile._bootIfNotBooted()

const user = await User.create({ username: 'virk' })
await user.profile().create({ profile_name: 'virk' })

let userQuery = null
User.onQuery((query) => (userQuery = query))

await User.query().where(function () {
this.whereHas('profile')
}).paginate()

assert.equal(userQuery.sql, helpers.formatQuery('select * from "users" where (exists (select * from "profiles" where "users"."id" = "profiles"."user_id")) limit ?'))
})
})

0 comments on commit b613b64

Please sign in to comment.