You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.2 KiB
190 lines
5.2 KiB
/**
|
|
* @module flitter-orm/src/filter/Filter
|
|
*/
|
|
|
|
const Focus = require('./Focus')
|
|
const FilterProxy = require('../proxy/model/FilterProxy')
|
|
const { ObjectId } = require('mongodb')
|
|
|
|
/**
|
|
* An accumulating MongoDB filter object.
|
|
* @class
|
|
*/
|
|
class Filter {
|
|
/**
|
|
* The root query object.
|
|
* @type {object}
|
|
* @private
|
|
*/
|
|
_root = {$and: []}
|
|
|
|
constructor(model) {
|
|
/**
|
|
* The model in question.
|
|
* @type: {module:flitter-orm/src/model/Model}
|
|
*/
|
|
this._model = model
|
|
}
|
|
|
|
/**
|
|
* Clone this filter into a new filter instance.
|
|
* Ensures that modifications to the cloned filter do
|
|
* no affect this existing filter.
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
clone() {
|
|
const filter = new this.constructor(this._model)
|
|
filter.absorb(this._root)
|
|
return filter
|
|
}
|
|
|
|
/**
|
|
* Focus on a particular field.
|
|
* @param {string} field
|
|
* @returns {module:flitter-orm/src/filter/Focus~Focus}
|
|
*/
|
|
field(field) {
|
|
return new Focus(this, field)
|
|
}
|
|
|
|
/**
|
|
* End the filter and apply it to the model's proxy.
|
|
* @returns {module:flitter-orm/src/proxy/model/FilterProxy~FilterProxy}
|
|
*/
|
|
end() {
|
|
return new FilterProxy(this._model, this)
|
|
}
|
|
|
|
/**
|
|
* Asserts that a field must equal the value.
|
|
* @param {string} field
|
|
* @param {*} value
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
equal(field, value) {
|
|
return this.field(field).equal(value).end()
|
|
}
|
|
|
|
/**
|
|
* Asserts that a field must be less than the value.
|
|
* @param {string} field
|
|
* @param {*} value
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
less_than(field, value) {
|
|
return this.field(field).less_than(value).end()
|
|
}
|
|
|
|
/**
|
|
* Asserts that a field must be greater than the value.
|
|
* @param {string} field
|
|
* @param {*} value
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
greater_than(field, value) {
|
|
return this.field(field).greater_than(value).end()
|
|
}
|
|
|
|
/**
|
|
* Asserts that a field must be less than or equal to the value.
|
|
* @param {string} field
|
|
* @param {*} value
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
less_than_equal(field, value) {
|
|
return this.field(field).less_than_equal(value).end()
|
|
}
|
|
|
|
/**
|
|
* Asserts that a field must be greater than or equal to the value.
|
|
* @param {string} field
|
|
* @param {*} value
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
greater_than_equal(field, value) {
|
|
return this.field(field).greater_than_equal(value).end()
|
|
}
|
|
|
|
/**
|
|
* Asserts that a field must be in the array of options for the value.
|
|
* @param {string} field
|
|
* @param {*} value
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
in(field, value) {
|
|
return this.field(field).in(value).end()
|
|
}
|
|
|
|
/**
|
|
* Write the accumulated filter to a MongoDB compatible filter object.
|
|
* @returns {object}
|
|
*/
|
|
write() {
|
|
if ( this._root.$and.length < 1 ) return {}
|
|
return this.__exec_resolve(this._root)
|
|
}
|
|
|
|
/**
|
|
* Resolve the filter object from structures to primitives.
|
|
* @param {object} object
|
|
* @returns {object}
|
|
* @private
|
|
*/
|
|
__exec_resolve(object) {
|
|
if ( Array.isArray(object) ) {
|
|
const return_arr = []
|
|
for ( const elem of object ) {
|
|
const val = typeof elem === 'function' ? elem() : elem
|
|
return_arr.push(this.__exec_resolve(val))
|
|
}
|
|
return return_arr
|
|
} else if ( typeof object === 'object' && !(object instanceof Date) && !(object instanceof ObjectId) ) {
|
|
const return_obj = {}
|
|
for ( const prop in object ) {
|
|
const elem = object[prop]
|
|
const val = typeof elem === 'function' ? elem() : elem
|
|
return_obj[prop] = this.__exec_resolve(val)
|
|
}
|
|
return return_obj
|
|
} else if ( typeof object === 'function' ) {
|
|
return this.__exec_resolve(object())
|
|
} else {
|
|
return object
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merge this filter with another.
|
|
* @param {module:flitter-orm/src/filter/Filter~Filter} other
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
*/
|
|
absorb(other) {
|
|
if ( other._root ) {
|
|
this._root.$and = this._root.$and.concat(other._root.$and)
|
|
} else {
|
|
for ( const key in other ) {
|
|
if ( key === '$and' ) {
|
|
this._root.$and = this._root.$and.concat(other.$and)
|
|
} else {
|
|
this._root.$and.push({ [key]: other[key] })
|
|
}
|
|
}
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Callback to break a field's focus and merge the filters for that field into this filter.
|
|
* @param {module:flitter-orm/src/filter/Focus~Focus} focus
|
|
* @returns {module:flitter-orm/src/filter/Filter~Filter}
|
|
* @private
|
|
*/
|
|
_unfocus(focus) {
|
|
this._root.$and.push({ [focus._field]: focus._root })
|
|
return this
|
|
}
|
|
}
|
|
|
|
module.exports = exports = Filter
|