hydrate-mongodb
Version:
An Object Document Mapper (ODM) for MongoDB.
193 lines (192 loc) • 8.61 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var RegExpUtil = require("../core/regExpUtil");
var mappingModel_1 = require("../mapping/mappingModel");
var writeContext_1 = require("../mapping/writeContext");
var persistenceError_1 = require("../persistenceError");
var CriteriaBuilder = (function () {
function CriteriaBuilder(mapping) {
this.mapping = mapping;
}
CriteriaBuilder.prototype.build = function (criteria) {
this.error = undefined;
var preparedCriteria = this.prepareQueryDocument(criteria, this.mapping);
if (!preparedCriteria) {
return null;
}
this.mapping.setQueryDocumentDiscriminator(preparedCriteria);
return preparedCriteria;
};
CriteriaBuilder.prototype.prepareQueryDocument = function (query, mapping, withinField) {
if (!query)
return {};
var result = {};
for (var key in query) {
if (query.hasOwnProperty(key)) {
var value = query[key], preparedKey = key, preparedValue = value;
if (key[0] == "$") {
if (key == "$and" || key == "$or" || key == "$nor") {
if (!Array.isArray(value)) {
this.error = new persistenceError_1.PersistenceError("Value of '" + key + "' operator should be an array.");
return null;
}
var arr = new Array(value.length);
for (var i = 0, l = value.length; i < l; i++) {
arr[i] = this.prepareQueryDocument(value[i], mapping);
}
preparedValue = arr;
}
else if (key == "$where" || key == "$text") {
if (withinField) {
this.error = new persistenceError_1.PersistenceError("Operator '" + key + "' is not allowed in $elemMatch.");
return null;
}
preparedValue = value;
}
else if (withinField) {
return this._prepareQueryExpression(key, query, mapping);
}
else {
this.error = new persistenceError_1.PersistenceError("Unknown top-level operator '" + key + "'.");
return null;
}
}
else {
if (key == "_id") {
if (typeof value === "string") {
preparedValue = this.mapping.inheritanceRoot.identity.fromString(value);
}
if (value == null || preparedValue == null) {
this.error = new persistenceError_1.PersistenceError("Missing or invalid identifier for '_id'.");
return null;
}
}
else {
var context = mapping.resolve(key);
if (context.error) {
this.error = context.error;
return null;
}
var resolvedMapping = context.resolvedMapping;
if (this.isQueryExpression(value)) {
if (resolvedMapping.flags & 1) {
resolvedMapping = resolvedMapping.elementMapping;
}
preparedValue = this._prepareQueryExpression(key, value, resolvedMapping);
}
else {
if (resolvedMapping.flags & 1) {
var arrayMapping = resolvedMapping;
if (!Array.isArray(value) || (arrayMapping.nestedDepth > 1 && arrayMapping.nestedDepth > this._findArrayDepth(value))) {
resolvedMapping = arrayMapping.elementMapping;
}
}
preparedValue = this.prepareQueryValue(context.resolvedPath, value, resolvedMapping);
}
preparedKey = context.resolvedPath;
}
}
(result || (result = {}))[preparedKey] = preparedValue;
}
}
return result;
};
CriteriaBuilder.prototype._prepareQueryExpression = function (operator, query, mapping) {
if (!query) {
this.error = new persistenceError_1.PersistenceError("Missing value for operator '" + operator + "'.");
return null;
}
var result = {};
for (var key in query) {
if (query.hasOwnProperty(key)) {
if (key[0] != "$") {
this.error = new persistenceError_1.PersistenceError("Unexpected value '" + key + "' in query expression.");
return null;
}
var value = query[key], preparedValue;
switch (key) {
case '$gt':
case '$gte':
case '$lt':
case '$lte':
case '$ne':
preparedValue = this.prepareQueryValue(key, value, mapping);
break;
case '$in':
case '$nin':
case '$all':
preparedValue = this.prepareArrayOfValues(key, value, mapping);
break;
case '$not':
preparedValue = this._prepareQueryExpression(key, value, mapping);
break;
case '$elemMatch':
preparedValue = this.prepareQueryDocument(value, mapping, true);
break;
case '$exists':
case '$type':
case '$mod':
case '$regex':
case '$options':
case '$geoIntersects':
case '$geoWithin':
case '$nearSphere':
case '$near':
case '$size':
case '$comment':
preparedValue = value;
break;
default:
this.error = new persistenceError_1.PersistenceError("Unknown query operator '" + key + "'.");
return null;
}
result[key] = preparedValue;
}
}
return result;
};
CriteriaBuilder.prototype.prepareArrayOfValues = function (operator, value, mapping) {
if (!Array.isArray(value)) {
this.error = new persistenceError_1.PersistenceError("Expected array for '" + operator + "' operator.");
return null;
}
var result = new Array(value.length);
for (var i = 0, l = value.length; i < l; i++) {
result[i] = this.prepareQueryValue(operator, value[i], mapping);
}
return result;
};
CriteriaBuilder.prototype.prepareQueryValue = function (path, value, mapping) {
if ((mapping.flags & 256) && (value instanceof RegExp)) {
return RegExpUtil.clone(value);
}
var context = new writeContext_1.WriteContext(path);
var preparedValue = mapping.write(context, value);
if (context.hasErrors) {
this.error = new persistenceError_1.PersistenceError("Bad value: " + context.getErrorMessage());
return null;
}
return preparedValue;
};
CriteriaBuilder.prototype._findArrayDepth = function (value, depth) {
if (depth === void 0) { depth = 0; }
if (value && Array.isArray(value)) {
for (var i = 0, l = value.length; i < l; i++) {
depth = Math.max(depth, this._findArrayDepth(value[i], depth + 1));
}
}
return depth;
};
CriteriaBuilder.prototype.isQueryExpression = function (value) {
if (typeof value === "object") {
for (var key in value) {
if (value.hasOwnProperty(key)) {
return key[0] == "$";
}
}
}
return false;
};
return CriteriaBuilder;
}());
exports.CriteriaBuilder = CriteriaBuilder;