Created
April 2, 2020 21:17
-
-
Save FrenchMajesty/ca9348d62accd7f7d29219ddb1675a07 to your computer and use it in GitHub Desktop.
AdonisJS URI Query Builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
class QueryBuilder { | |
constructor(params) { | |
this.query = null; | |
this.params = this.formatParams(params); | |
this.hasPagination = false; | |
this.hasLazyLoad = false; | |
} | |
/** | |
* Format the request URL params to be easy to use and apply | |
* | |
* @param {Object} params | |
* @returns {Object} | |
*/ | |
formatParams(params) { | |
params.include = params.include || ''; | |
params.filters = params.filters || {}; | |
params.pagination = params.pagination || {}; | |
params.lazyload = params.lazyload || {}; | |
const include = params.include.split(','); | |
const filters = {}; | |
Object.keys(params.filters).forEach((type) => { | |
const filter = params.filters[type]; | |
filters[type] = filter.split(','); | |
}); | |
return { | |
include, | |
filters, | |
pagination: params.pagination, | |
lazyload: params.lazyload, | |
}; | |
} | |
for(query) { | |
this.query = query; | |
return this; | |
} | |
fetch() { | |
if(this.hasPagination) { | |
return this.fetchWithPagination(); //TODO: What happens if we need the data in JSON? | |
} | |
if(this.hasLazyLoad) { | |
return this.fetchWithLazyLoad(); | |
} | |
return this.query.fetch(); | |
} | |
first() { | |
return this.query.first(); | |
} | |
firstOrFail() { | |
return this.query.firstOrFail(); | |
} | |
/** | |
* Fetch the query and format the result for use in a lazy loaded list setting | |
* | |
* @async | |
* @returns {Object} | |
*/ | |
async fetchWithLazyLoad() { | |
const total = await this.query.getCount(); | |
let data = null; | |
if(this.hasLazyLoad) { | |
const { length } = this.params.lazyload; | |
data = await this.query.limit(length).fetch(); | |
}else { | |
data = await this.query.fetch(); | |
} | |
return { | |
current: data.toJSON().length, | |
total, | |
data, | |
}; | |
} | |
/** | |
* Fetch the query and format the result for pagination | |
* | |
* @async | |
* @returns {Object} | |
*/ | |
async fetchWithPagination() { | |
const { page, limit } = this.params.pagination; | |
const total = await this.query.getCount(); | |
const data = await this.applyPagination(); | |
return { | |
perPage: limit, | |
lastPage: Math.ceil(total / limit), | |
page, | |
total, | |
data, | |
}; | |
} | |
/** | |
* Apply the pagination params provided to the query | |
* | |
* @returns {QueryBuilder} | |
*/ | |
allowPagination() { | |
let { page } = this.params.pagination; | |
this.params.pagination.page = page ? Number(page) : 1; | |
this.params.pagination.limit = this.params.pagination.limit || 20; | |
if(page && Number(page)) { | |
this.hasPagination = true; | |
} | |
return this; | |
} | |
/** | |
* Apply query limiting params provided to the query | |
* | |
* @returns {Void} | |
*/ | |
allowLazyLoad() { | |
let { length } = this.params.lazyload; | |
if(length) { | |
this.hasLazyLoad = true; | |
} | |
return this; | |
} | |
/** | |
* Apply the pagination to the query | |
* | |
* @returns {Array} | |
*/ | |
applyPagination() { | |
const { page, limit } = this.params.pagination; | |
this.query.offset((page-1) * limit).limit(limit); | |
return this.query.fetch(); | |
} | |
/** | |
* Apply the allowed filters provided with the request | |
* | |
* @param {Array} filters | |
* @returns {QueryBuilder} | |
*/ | |
allowedFilters(filters) { | |
Object.keys(this.params.filters).forEach((key) => { | |
const value = this.params.filters[key]; | |
const isAllowed = filters.find((filter) => filter == key); | |
if(!key.match('custom.') && isAllowed) { | |
this.query.where(key, 'like', `%${value}%`); | |
} | |
}); | |
const {custom} = this.params.filters; | |
if(custom) { | |
custom.forEach((customQuery) => { | |
const isAllowed = filters.find((filter) => filter == `custom.${customQuery}`); | |
if(isAllowed) this.query[customQuery](); | |
}); | |
} | |
return this; | |
} | |
/** | |
* Eager load the allowed relations that were provided in the request | |
* | |
* @param {Array} relations The name of the relations allowed to eager load | |
* @returns {QueryBuilder} | |
*/ | |
allowedIncludes(relations) { | |
const toLoad = this.params.include.filter((value) => { | |
return relations.find((relation) => relation == value); | |
}); | |
toLoad.forEach((relation) => this.query.with(relation)); | |
return this; | |
} | |
} | |
module.exports = QueryBuilder; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment