Skip to content

Commit

Permalink
feat(database): add aggregation helpers
Browse files Browse the repository at this point in the history
* rowsCount

* Aggregates - static model count

* spacing fix

* Finalize aggregates

* rename to get

* typo

* Move to Database layer

* formatting fix

* formatting fix

* Knex refactor

* Standard styling

* Fix QueryBuilder proxy chaining

* add distinct aggregates

* Add distinct tests and fix typos

* refactor(database): refactor code style

* refactor(lucid): add aggregates to model query builder

* Revert "Fix QueryBuilder proxy chaining"

This reverts commit b5ea8a7.

* Added distinct helpers to QueryBuilder

* Revert "Added distinct helpers to QueryBuilder"

This reverts commit dd164aa.

* Revert "Revert "Fix QueryBuilder proxy chaining""

This reverts commit 4a30f68.

* Added database test to clarify the need for query wrapping

* fix(querybuilder): use new query instance over clone

* fix: Added aggregate helper support to BelongsToMany and fixed aggregate query column selection bug

re #225 re #205

* fix(Removed _prepareAggregate (unneeded)):

re #205 re #226

* style(Spelling fix):

* Testing fix

* Remove old comment
  • Loading branch information
benallfree authored and thetutlage committed Nov 22, 2017
1 parent 01a6fa7 commit 10023f7
Show file tree
Hide file tree
Showing 8 changed files with 630 additions and 87 deletions.
134 changes: 134 additions & 0 deletions src/Database/MonkeyPatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,140 @@ KnexQueryBuilder.prototype.paginate = async function (page = 2, perPage = 20) {
}
}

/**
* Generates an aggregate function, that returns the aggregated result
* as a number.
*
* @method generateAggregate
*
* @param {String} aggregateOp
* @param {String} defaultColumnName
*
* @return {Number}
*
* @example
* ```js
* generateAggregate('count')
* ```
*/
function generateAggregate (aggregateOp, defaultColumnName = undefined) {
let funcName = `get${_.upperFirst(aggregateOp)}`

/**
* Do not re-add the method if exists
*/
if (KnexQueryBuilder.prototype[funcName]) {
return
}

KnexQueryBuilder.prototype[funcName] = async function (columnName = defaultColumnName) {
if (!columnName) {
throw new Error(`'${funcName}' requires a column name.`)
}

const wrapper = new this.constructor(this.client)
const query = wrapper.from(this.as('__lucid'))[aggregateOp](`${columnName} as __lucid_aggregate`)
const results = await query
return results[0].__lucid_aggregate
}
}

/**
* Fetch and return a row count
*
* @method getCount
* @async
*
* @param {String} columnName = '*'
*
* @return {Number} The count of of rows in this query
*/
generateAggregate('count', '*')

/**
* Fetch and return a distinct row count
*
* @method getCountDistinct
* @async
*
* @param {String} columnName
*
* @return {Number} The distinct count of rows in this query
*/
generateAggregate('countDistinct')

/**
* Fetch and return the sum of all values in columnName
*
* @method getSum
* @async
*
* @param {String} columnName
*
* @return {Number} The sum of columnName
*/
generateAggregate('sum')

/**
* Fetch and return the sum of all distinct values in columnName
*
* @method getSumDistinct
* @async
*
* @param {String} columnName
*
* @return {Number} The sum of distinct values in columnName
*/
generateAggregate('sumDistinct')

/**
* Fetch and return the minimum of all values in columnName
*
* @method getMin
* @async
*
* @param {String} columnName
*
* @return {Number} The minimunm value of columnName
*/
generateAggregate('min')

/**
* Fetch and return the maximum of all values in columnName
*
* @method getMax
* @async
*
* @param {String} columnName
*
* @return {Number} The maximunm value of columnName
*/
generateAggregate('max')

/**
* Fetch and return the average of all values in columnName
*
* @method getAvg
* @async
*
* @param {String} columnName
*
* @return {Number} The average value of columnName
*/
generateAggregate('avg')

/**
* Fetch and return the average of all distinct values in columnName
*
* @method getAvgDistinct
* @async
*
* @param {String} columnName
*
* @return {Number} The average of distinct values of columnName
*/
generateAggregate('avgDistinct')

/**
* Returns the latest row from the database.
*
Expand Down
105 changes: 104 additions & 1 deletion src/Lucid/Model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,109 @@ class Model extends BaseModel {
this.newUp(newInstance.$attributes)
}
}
}

/**
* Return a count of all model records.
*
* @method getCount
*
* @param {String} columnName = '*'
*
* @return {Number}
*/
static async getCount (columnName = '*') {
return this.query().getCount(columnName)
}

/**
* Return a distinct count of all model records.
*
* @method getCountDistinct
*
* @param {String} columnName
*
* @return {Number}
*/
static async getCountDistinct (columnName) {
return this.query().getCountDistinct(columnName)
}

/**
* Return the average of all values of columnName.
*
* @method getAvg
*
* @param {String} columnName
*
* @return {Number}
*/
static async getAvg (columnName) {
return this.query().getAvg(columnName)
}

/**
* Return the average of all distinct values of columnName.
*
* @method getAvgDistinct
*
* @param {String} columnName
*
* @return {Number}
*/
static async getAvgDistinct (columnName) {
return this.query().getAvgDistinct(columnName)
}

/**
* Return the minimum of all values of columnName.
*
* @method getMin
*
* @param {String} columnName
*
* @return {Number}
*/
static async getMin (columnName) {
return this.query().getMin(columnName)
}

/**
* Return the maximum of all values of columnName.
*
* @method getMax
*
* @param {String} columnName
*
* @return {Number}
*/
static async getMax (columnName) {
return this.query().getMax(columnName)
}

/**
* Return the sum of all values of columnName.
*
* @method getSum
*
* @param {String} columnName
*
* @return {Number}
*/
static async getSum (columnName) {
return this.query().getSum(columnName)
}

/**
* Return the sum of all distinct values of columnName.
*
* @method getSumDistinct
*
* @param {String} columnName
*
* @return {Number}
*/
static async getSumDistinct (columnName) {
return this.query().getSumDistinct(columnName)
}
}
module.exports = Model
104 changes: 104 additions & 0 deletions src/Lucid/QueryBuilder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,110 @@ class QueryBuilder {
return new this.Model.Serializer(modelInstances, pages)
}

/**
* Return a count of all model records.
*
* @method getCount
*
* @param {String} columnName = '*'
*
* @return {Number}
*/
getCount (columnName = '*') {
return this.query.getCount(columnName)
}

/**
* Return a distinct count of all model records.
*
* @method getCountDistinct
*
* @param {String} columnName
*
* @return {Number}
*/
getCountDistinct (columnName) {
return this.query.getCountDistinct(columnName)
}

/**
* Return the average of all values of columnName.
*
* @method getAvg
*
* @param {String} columnName
*
* @return {Number}
*/
getAvg (columnName) {
return this.query.getAvg(columnName)
}

/**
* Return the average of all distinct values of columnName.
*
* @method getAvgDistinct
*
* @param {String} columnName
*
* @return {Number}
*/
getAvgDistinct (columnName) {
return this.query.getAvgDistinct(columnName)
}

/**
* Return the minimum of all values of columnName.
*
* @method getMin
*
* @param {String} columnName
*
* @return {Number}
*/
getMin (columnName) {
return this.query.getMin(columnName)
}

/**
* Return the maximum of all values of columnName.
*
* @method getMax
*
* @param {String} columnName
*
* @return {Number}
*/
getMax (columnName) {
return this.query.getMax(columnName)
}

/**
* Return the sum of all values of columnName.
*
* @method getSum
*
* @param {String} columnName
*
* @return {Number}
*/
getSum (columnName) {
return this.query.getSum(columnName)
}

/**
* Return the sum of all distinct values of columnName.
*
* @method getSumDistinct
*
* @param {String} columnName
*
* @return {Number}
*/
getSumDistinct (columnName) {
return this.query.getSumDistinct(columnName)
}

/**
* Bulk update data from query builder. This method will also
* format all dates and set `updated_at` column
Expand Down
12 changes: 12 additions & 0 deletions src/Lucid/Relations/BaseRelation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,22 @@ const proxyGet = require('../../../lib/proxyGet')
const methodsList = [
'increment',
'decrement',
'sum',
'sumDistinct',
'avg',
'avgDistinct',
'min',
'max',
'count',
'countDistinct',
'getSum',
'getSumDistinct',
'getAvg',
'getAvgDistinct',
'getMin',
'getMax',
'getCount',
'getCountDistinct',
'truncate',
'ids',
'paginate',
Expand Down
Loading

0 comments on commit 10023f7

Please sign in to comment.