hydrate-mongodb
Version:
An Object Document Mapper (ODM) for MongoDB.
287 lines (286 loc) • 11.7 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var mappingBase_1 = require("./mappingBase");
var mappingModel_1 = require("./mappingModel");
var persistenceError_1 = require("../persistenceError");
var ObjectMapping = (function (_super) {
__extends(ObjectMapping, _super);
function ObjectMapping() {
var _this = _super.call(this, 64 | 2048) || this;
_this.properties = [];
_this._propertiesByName = new Map();
_this._propertiesByField = new Map();
return _this;
}
ObjectMapping.prototype.addProperty = function (property) {
if (!property) {
throw new persistenceError_1.PersistenceError("Missing required argument 'property'.");
}
var error = this.validateProperty(property);
if (error) {
throw new persistenceError_1.PersistenceError(error);
}
this._propertiesByName.set(property.name, property);
if (property.field) {
this._propertiesByField.set(property.field, property);
}
this.properties.push(property);
return property;
};
ObjectMapping.prototype.validateProperty = function (property) {
if (!property.name) {
return "Property is missing 'name'.";
}
if (!property.field && !property.hasFlags(1)) {
return "Property must define a 'field' mapping if the property is not ignored.";
}
if (this._propertiesByName.has(property.name)) {
return "There is already a mapped property with the name '" + property.name + "'.";
}
if (this._propertiesByField.has(property.field)) {
return "There is already a mapped property for field '" + property.field + "'.";
}
};
ObjectMapping.prototype.getProperty = function (name) {
if (!name) {
throw new persistenceError_1.PersistenceError("Missing required argument 'name'.");
}
return this._propertiesByName.get(name);
};
ObjectMapping.prototype.getPropertyForField = function (field) {
return this._propertiesByField.get(field);
};
ObjectMapping.prototype.getProperties = function (flags) {
if (!flags) {
return this.properties;
}
var ret = [];
var properties = this.properties;
for (var i = 0, l = properties.length; i < l; i++) {
var property = properties[i];
if ((property.flags & flags) !== 0) {
ret.push(property);
}
}
return ret;
};
ObjectMapping.prototype.read = function (context, value) {
return this.readObject(context, {}, value, false);
};
ObjectMapping.prototype.readObject = function (context, obj, value, checkRemoved) {
if (value == null) {
return null;
}
if (typeof value !== "object") {
context.addError("Expected value to be an object.");
return;
}
var base = context.path ? context.path + "." : "", properties = this.properties;
var objectParent = context.parent;
context.parent = obj;
for (var i = 0, l = properties.length; i < l; i++) {
var property = properties[i];
if ((property.flags & 4096) != 0) {
property.setPropertyValue(obj, objectParent);
continue;
}
if ((property.flags & (1 | 64
| 512)) != 0) {
continue;
}
var fieldValue = property.getFieldValue(value), propertyValue = undefined;
if (fieldValue !== undefined) {
if (fieldValue === null) {
if (property.nullable) {
propertyValue = null;
}
}
else {
var savedPath = context.path;
context.path = base + property.name;
if ((property.flags & 1024) != 0) {
context.addFetch(context.path);
}
propertyValue = property.mapping.read(context, fieldValue);
context.path = savedPath;
}
}
if (propertyValue !== undefined) {
property.setPropertyValue(obj, propertyValue);
}
else {
if (checkRemoved && property.getPropertyValue(obj) !== undefined) {
property.setPropertyValue(obj, undefined);
}
}
}
context.parent = objectParent;
if (context.observer && (this.flags & 131072) == 0) {
context.observer.watch(obj);
}
return obj;
};
ObjectMapping.prototype.write = function (context, value) {
return this.writeObject(context, {}, value);
};
ObjectMapping.prototype.writeObject = function (context, document, value) {
if (value == null)
return null;
var base = context.path ? context.path + "." : "", properties = this.properties, fieldValue;
if (this.flags & 2048) {
if (context.visited.indexOf(value) !== -1) {
context.addError("Recursive reference of embedded object is not allowed.");
return;
}
context.visited.push(value);
}
for (var i = 0, l = properties.length; i < l; i++) {
var property = properties[i], flags = property.flags;
if ((flags & (1 | 64)) != 0) {
continue;
}
var propertyValue = property.getPropertyValue(value);
if (propertyValue === undefined) {
continue;
}
if (propertyValue === null) {
if (!property.nullable) {
continue;
}
fieldValue = null;
}
else {
var savedPath = context.path;
context.path = base + property.name;
fieldValue = property.mapping.write(context, propertyValue);
context.path = savedPath;
}
property.setFieldValue(document, fieldValue);
}
context.visited.pop();
return document;
};
ObjectMapping.prototype.watch = function (value, observer, visited) {
if (!value || typeof value != "object")
return;
if (this.flags & 2048) {
if (visited.indexOf(value) !== -1)
return;
visited.push(value);
}
observer.watch(value);
for (var i = 0, l = this.properties.length; i < l; i++) {
var property = this.properties[i];
if ((property.flags & 1) == 0) {
property.mapping.watch(property.getPropertyValue(value), observer, visited);
}
}
};
ObjectMapping.prototype.areEqual = function (documentValue1, documentValue2) {
if (documentValue1 === documentValue2)
return true;
if (documentValue1 == null || documentValue2 == null)
return false;
if (typeof documentValue1 !== "object" || typeof documentValue2 !== "object") {
return false;
}
var properties = this.properties;
for (var i = 0, l = properties.length; i < l; i++) {
var property = properties[i];
if ((property.flags & (1 | 64)) != 0) {
continue;
}
var fieldValue1 = property.getFieldValue(documentValue1);
var fieldValue2 = property.getFieldValue(documentValue2);
if (fieldValue1 !== fieldValue2 && !property.mapping.areEqual(fieldValue1, fieldValue2)) {
return false;
}
}
return true;
};
ObjectMapping.prototype.walk = function (session, value, flags, entities, embedded, references) {
if (!value || typeof value !== "object")
return;
if (this.flags & 2048) {
if (embedded.indexOf(value) !== -1)
return;
embedded.push(value);
}
var properties = this.properties;
for (var i = 0, l = properties.length; i < l; i++) {
var property = properties[i];
if ((property.flags & 1) == 0
&& ((property.flags & flags) != 0 || ((flags & 8063) == 0))) {
property.mapping.walk(session, property.getPropertyValue(value), flags, entities, embedded, references);
}
}
};
ObjectMapping.prototype.fetch = function (session, parentEntity, value, path, depth, callback) {
if (!value || typeof value !== "object" || depth == path.length) {
process.nextTick(function () { return callback(null, value); });
return;
}
var property = this.getProperty(path[depth]);
if (property === undefined) {
return callback(new persistenceError_1.PersistenceError("Undefined property '" + path[depth] + "' in path '" + path.join(".") + "'."));
}
var propertyValue = property.getPropertyValue(value);
if ((property.flags & 64) != 0 && propertyValue === undefined) {
property.mapping.fetchInverse(session, parentEntity, property.inverseOf, path, depth + 1, handleCallback);
}
else if ((property.flags & 2048) != 0 && propertyValue === undefined) {
this.fetchPropertyValue(session, value, property, handleCallback);
}
else {
property.mapping.fetch(session, parentEntity, propertyValue, path, depth + 1, handleCallback);
}
function handleCallback(err, result) {
if (err)
return callback(err);
if (propertyValue !== result) {
property.setPropertyValue(value, result);
}
callback(null, value);
}
};
ObjectMapping.prototype.fetchPropertyValue = function (session, value, property, callback) {
process.nextTick(function () { return callback(null, property.getPropertyValue(value)); });
};
ObjectMapping.prototype.resolveCore = function (context) {
var property = this.getProperty(context.currentProperty);
if (property === undefined) {
if ((this.flags & 4) != 0) {
context.setError("Undefined property for class '" + this.name + "'.");
}
else {
context.setError("Undefined property.");
}
return;
}
if ((property.flags & 4096) != 0) {
context.setError("Cannot resolve parent reference.");
}
else if ((property.flags & 64) != 0) {
context.setError("Cannot resolve inverse side of relationship.");
}
else if ((property.flags & 1) != 0) {
context.setError("Cannot resolve ignored property.");
}
if (context.resolveProperty(property.mapping, property.field)) {
return;
}
property.mapping.resolve(context);
};
return ObjectMapping;
}(mappingBase_1.MappingBase));
exports.ObjectMapping = ObjectMapping;