true If public access is allowed
+ */
+
+
+ Acl.prototype.isPublicReadAllowed = function isPublicReadAllowed() {
+ return this.read.isPublicAllowed();
+ };
+
+ /**
+ * Sets whenever all users and roles should have the permission to read the object.
+ * Note: All other allow read rules will be removed.
+ */
+
+
+ Acl.prototype.setPublicReadAllowed = function setPublicReadAllowed() {
+ return this.read.setPublicAllowed();
+ };
+
+ /**
+ * Checks whenever the user or role is explicit allowed to read the object.
+ *
+ * @param {model.User|model.Role|string} userOrRole The user or role to check for
+ * @return {boolean} true
if read access is explicitly allowed for the given user or role
+ */
+
+
+ Acl.prototype.isReadAllowed = function isReadAllowed(userOrRole) {
+ return this.read.isAllowed(userOrRole);
+ };
+
+ /**
+ * Checks whenever the user or role is explicit denied to read the object
+ *
+ * @param {model.User|model.Role|string} userOrRole The user or role to check for
+ * @return {boolean} true
if read access is explicitly denied for the given user or role
+ */
+
+
+ Acl.prototype.isReadDenied = function isReadDenied(userOrRole) {
+ return this.read.isDenied(userOrRole);
+ };
+
+ /**
+ * Allows the given user or rule to read the object
+ * @param {...(model.User|model.Role|string)} userOrRole The user or role to allow
+ * @return {Acl} this acl object
+ */
+
+
+ Acl.prototype.allowReadAccess = function allowReadAccess(userOrRole) {
+ Permission.prototype.allowAccess.apply(this.read, arguments);
+ return this;
+ };
+
+ /**
+ * Denies the given user or rule to read the object
+ * @param {...(model.User|model.Role|string)} userOrRole The user or role to deny
+ * @return {Acl} this acl object
+ */
+
+
+ Acl.prototype.denyReadAccess = function denyReadAccess(userOrRole) {
+ Permission.prototype.denyAccess.apply(this.read, arguments);
+ return this;
+ };
+
+ /**
+ * Deletes any read allow/deny rule for the given user or role
+ * @param {...(model.User|model.Role|string)} userOrRole The user or role
+ * @return {Acl} this acl object
+ */
+
+
+ Acl.prototype.deleteReadAccess = function deleteReadAccess(userOrRole) {
+ Permission.prototype.deleteAccess.apply(this.read, arguments);
+ return this;
+ };
+
+ /**
+ * Gets whenever all users and roles have the permission to write the object
+ * @return {boolean} true
If public access is allowed
+ */
+
+
+ Acl.prototype.isPublicWriteAllowed = function isPublicWriteAllowed() {
+ return this.write.isPublicAllowed();
+ };
+
+ /**
+ * Sets whenever all users and roles should have the permission to write the object.
+ * Note: All other allow write rules will be removed.
+ */
+
+
+ Acl.prototype.setPublicWriteAllowed = function setPublicWriteAllowed() {
+ return this.write.setPublicAllowed();
+ };
+
+ /**
+ * Checks whenever the user or role is explicit allowed to write the object.
+ *
+ * @param {model.User|model.Role|string} userOrRole The user or role to check for
+ * @return {boolean} true
if write access is explicitly allowed for the given user or role
+ */
+
+
+ Acl.prototype.isWriteAllowed = function isWriteAllowed(userOrRole) {
+ return this.write.isAllowed(userOrRole);
+ };
+
+ /**
+ * Checks whenever the user or role is explicit denied to write the object
+ *
+ * @param {model.User|model.Role|string} userOrRole The user or role to check for
+ * @return {boolean} true
if write access is explicitly denied for the given user or role
+ */
+
+
+ Acl.prototype.isWriteDenied = function isWriteDenied(userOrRole) {
+ return this.write.isDenied(userOrRole);
+ };
+
+ /**
+ * Allows the given user or rule to write the object
+ * @param {...(model.User|model.Role|string)} userOrRole The user or role to allow
+ * @return {Acl} this acl object
+ */
+
+
+ Acl.prototype.allowWriteAccess = function allowWriteAccess(userOrRole) {
+ Permission.prototype.allowAccess.apply(this.write, arguments);
+ return this;
+ };
+
+ /**
+ * Denies the given user or rule to write the object
+ * @param {...(model.User|model.Role|string)} userOrRole The user or role to deny
+ * @return {Acl} this acl object
+ */
+
+
+ Acl.prototype.denyWriteAccess = function denyWriteAccess(userOrRole) {
+ Permission.prototype.denyAccess.apply(this.write, arguments);
+ return this;
+ };
+
+ /**
+ * Deletes any write allow/deny rule for the given user or role
+ * @param {...(model.User|model.Role|string)} userOrRole The user or role
+ * @return {Acl} this acl object
+ */
+
+
+ Acl.prototype.deleteWriteAccess = function deleteWriteAccess(userOrRole) {
+ Permission.prototype.deleteAccess.apply(this.write, arguments);
+ return this;
+ };
+
+ /**
+ * A Json representation of the set of rules
+ * @return {json}
+ */
+
+
+ Acl.prototype.toJSON = function toJSON() {
+ return {
+ read: this.read,
+ write: this.write
+ };
+ };
+
+ /**
+ * Sets the acl rules form json
+ * @param {json} json The json encoded acls
+ */
+
+
+ Acl.prototype.fromJSON = function fromJSON(json) {
+ this.read.fromJSON(json.read || {});
+ this.write.fromJSON(json.write || {});
+ };
+
+ return Acl;
+}();
+
+module.exports = Acl;
+
+},{"65":65}],2:[function(_dereq_,module,exports){
+"use strict";
+
+var message = _dereq_(36);
+var error = _dereq_(34);
+var binding = _dereq_(20);
+var util = _dereq_(70);
+var query = _dereq_(59);
+
+var UserFactory = _dereq_(19);
+var EntityTransaction = _dereq_(4);
+var Metadata = _dereq_(63);
+var Message = _dereq_(25);
+var BloomFilter = _dereq_(21);
+var StatusCode = Message.StatusCode;
+
+/**
+ * @alias EntityManager
+ * @extends util.Lockable
+ */
+
+var EntityManager = function (_util$Lockable) {
+ babelHelpers.inherits(EntityManager, _util$Lockable);
+ babelHelpers.createClass(EntityManager, [{
+ key: 'isOpen',
+
+
+ /**
+ * Determine whether the entity manager is open.
+ * true until the entity manager has been closed
+ * @type boolean
+ */
+ get: function get() {
+ return !!this._connector;
+ }
+
+ /**
+ * The authentication token if the user is logged in currently
+ * @type String
+ */
+
+ }, {
+ key: 'token',
+ get: function get() {
+ return this.tokenStorage.token;
+ },
+
+
+ /**
+ * The authentication token if the user is logged in currently
+ * @param {String} value
+ */
+ set: function set(value) {
+ this.tokenStorage.update(value);
+ }
+
+ /**
+ * @param {EntityManagerFactory} entityManagerFactory The factory which of this entityManager instance
+ */
+
+ }, {
+ key: 'isCachingDisabled',
+ get: function get() {
+ return !this.bloomFilter;
+ }
+ }]);
+
+ function EntityManager(entityManagerFactory) {
+ babelHelpers.classCallCheck(this, EntityManager);
+
+ /**
+ * Log messages can created by calling log directly as function, with a specific log level or with the helper
+ * methods, which a members of the log method.
+ *
+ * Logs will be filtered by the client logger and the before they persisted. The default log level is
+ * 'info' therefore all log messages below the given message aren't persisted.
+ *
+ * Examples:
+ *
+ // default log level ist info
+ db.log('test message %s', 'my string');
+ // info: test message my string
+ // pass a explicit log level as the first argument, one of ('trace', 'debug', 'info', 'warn', 'error')
+ db.log('warn', 'test message %d', 123);
+ // warn: test message 123
+ // debug log level will not be persisted by default, since the default logging level is info
+ db.log('debug', 'test message %j', {number: 123}, {});
+ // debug: test message {"number":123}
+ // data = {}
+ // One additional json object can be provided, which will be persisted together with the log entry
+ db.log('info', 'test message %s, %s', 'first', 'second', {number: 123});
+ // info: test message first, second
+ // data = {number: 123}
+ //use the log level helper
+ db.log.info('test message', 'first', 'second', {number: 123});
+ // info: test message first second
+ // data = {number: 123}
+ //change the default log level to trace, i.e. all log levels will be persisted, note that the log level can be
+ //additionally configured in the baqend
+ db.log.level = 'trace';
+ //trace will be persisted now
+ db.log.trace('test message', 'first', 'second', {number: 123});
+ // info: test message first second
+ // data = {number: 123}
+ *
+ *
+ * @type util.Logger
+ */
+ var _this = babelHelpers.possibleConstructorReturn(this, _util$Lockable.call(this));
+
+ _this.log = util.Logger.create(_this);
+
+ /**
+ * The connector used for requests
+ * @type connector.Connector
+ * @private
+ */
+ _this._connector = null;
+
+ /**
+ * All managed and cached entity instances
+ * @type Map
+ */
+ _this._entities = null;
+
+ /** @type EntityManagerFactory */
+ _this.entityManagerFactory = entityManagerFactory;
+
+ /** @type metamodel.Metamodel */
+ _this.metamodel = entityManagerFactory.metamodel;
+
+ /** @type util.Code */
+ _this.code = entityManagerFactory.code;
+
+ /** @type util.Modules */
+ _this.modules = null;
+
+ /**
+ * The current logged in user object
+ * @type model.User
+ */
+ _this.me = null;
+
+ /**
+ * Returns true if the device token is already registered, otherwise false.
+ * @type boolean
+ */
+ _this.isDeviceRegistered = false;
+
+ /**
+ * Returns the tokenStorage which will be used to authorize all requests.
+ * @type {util.TokenStorage}
+ */
+ _this.tokenStorage = null;
+
+ /**
+ * @type {caching.BloomFilter}
+ */
+ _this.bloomFilter = null;
+
+ /**
+ * Set of object ids that were revalidated after the Bloom filter was loaded.
+ */
+ _this.cacheWhiteList = null;
+
+ /**
+ * Set of object ids that were updated but are not yet included in the bloom filter.
+ * This set essentially implements revalidation by side effect which does not work in Chrome.
+ */
+ _this.cacheBlackList = null;
+
+ /**
+ * Bloom filter refresh interval in seconds.
+ *
+ * @type {number}
+ */
+ _this.bloomFilterRefresh = 60;
+
+ /**
+ * Bloom filter refresh Promise
+ *
+ */
+ _this._bloomFilterLock = new util.Lockable();
+ return _this;
+ }
+
+ /**
+ * Connects this entityManager, used for synchronous and asynchronous initialization
+ * @param {connector.Connector} connector
+ * @param {Object} connectData
+ * @param {util.TokenStorage} tokenStorage The used tokenStorage for token persistence
+ */
+
+
+ EntityManager.prototype.connected = function connected(connector, connectData, tokenStorage) {
+ this._connector = connector;
+ this.tokenStorage = tokenStorage;
+ this.bloomFilterRefresh = this.entityManagerFactory.staleness;
+ this._entities = {};
+
+ this.File = binding.FileFactory.create(this);
+ this._createObjectFactory(this.metamodel.embeddables);
+ this._createObjectFactory(this.metamodel.entities);
+
+ this.transaction = new EntityTransaction(this);
+ this.modules = new util.Modules(this, connector);
+
+ if (connectData) {
+ this.isDeviceRegistered = !!connectData.device;
+ if (connectData.user && connectData.token == tokenStorage.token) this._updateUser(connectData.user, true);
+
+ if (this.bloomFilterRefresh > 0 && connectData.bloomFilter && util.atob && !util.isNode) {
+ this.updateBloomFilter(connectData.bloomFilter);
+ }
+ }
+ };
+
+ /**
+ * @param {metamodel.ManagedType[]} types
+ * @return {binding.ManagedFactory}
+ * @private
+ */
+
+
+ EntityManager.prototype._createObjectFactory = function _createObjectFactory(types) {
+ Object.keys(types).forEach(function (ref) {
+ var type = this.metamodel.managedType(ref);
+ var name = type.name;
+
+ if (this[name]) {
+ type.typeConstructor = this[name];
+ Object.defineProperty(this, name, {
+ value: type.createObjectFactory(this)
+ });
+ } else {
+ Object.defineProperty(this, name, {
+ get: function get() {
+ Object.defineProperty(this, name, {
+ value: type.createObjectFactory(this)
+ });
+
+ return this[name];
+ },
+ set: function set(typeConstructor) {
+ type.typeConstructor = typeConstructor;
+ },
+
+ configurable: true
+ });
+ }
+ }, this);
+ };
+
+ EntityManager.prototype.send = function send(message) {
+ var _this2 = this;
+
+ message.tokenStorage = this.tokenStorage;
+ return this._connector.send(message).catch(function (e) {
+ if (e.status == StatusCode.BAD_CREDENTIALS) {
+ _this2._logout();
+ }
+ throw e;
+ });
+ };
+
+ /**
+ * Get an instance, whose state may be lazily fetched. If the requested instance does not exist
+ * in the database, the EntityNotFoundError is thrown when the instance state is first accessed.
+ * The application should not expect that the instance state will be available upon detachment,
+ * unless it was accessed by the application while the entity manager was open.
+ *
+ * @param {(Class|string)} entityClass
+ * @param {string=} key
+ */
+
+
+ EntityManager.prototype.getReference = function getReference(entityClass, key) {
+ var id, type;
+ if (key) {
+ type = this.metamodel.entity(entityClass);
+ if (key.indexOf('/db/') == 0) {
+ id = key;
+ } else {
+ id = type.ref + '/' + encodeURIComponent(key);
+ }
+ } else {
+ id = entityClass;
+ type = this.metamodel.entity(id.substring(0, id.indexOf('/', 4))); //skip /db/
+ }
+
+ var entity = this._entities[id];
+ if (!entity) {
+ entity = type.create();
+ var metadata = Metadata.get(entity);
+ metadata.id = id;
+ metadata.setUnavailable();
+
+ this._attach(entity);
+ }
+
+ return entity;
+ };
+
+ /**
+ * Creates an instance of Query.Builder for query creation and execution. The Query results are instances of the
+ * resultClass argument.
+ * @param {Class<*>=} resultClass - the type of the query result
+ * @return {query.Builder<*>} A query builder to create one ore more queries for the specified class
+ */
+
+
+ EntityManager.prototype.createQueryBuilder = function createQueryBuilder(resultClass) {
+ return new query.Builder(this, resultClass);
+ };
+
+ /**
+ * Clear the persistence context, causing all managed entities to become detached.
+ * Changes made to entities that have not been flushed to the database will not be persisted.
+ */
+
+
+ EntityManager.prototype.clear = function clear() {
+ this._entities = {};
+ };
+
+ /**
+ * Close an application-managed entity manager. After the close method has been invoked,
+ * all methods on the EntityManager instance and any Query and TypedQuery objects obtained from it
+ * will throw the IllegalStateError except for transaction, and isOpen (which will return false).
+ * If this method is called when the entity manager is associated with an active transaction,
+ * the persistence context remains managed until the transaction completes.
+ */
+
+
+ EntityManager.prototype.close = function close() {
+ this._connector = null;
+
+ return this.clear();
+ };
+
+ /**
+ * Check if the instance is a managed entity instance belonging to the current persistence context.
+ * @param {binding.Entity} entity - entity instance
+ * @returns {boolean} boolean indicating if entity is in persistence context
+ */
+
+
+ EntityManager.prototype.contains = function contains(entity) {
+ return !!entity && this._entities[entity.id] === entity;
+ };
+
+ /**
+ * Check if an object with the id from the given entity is already attached.
+ * @param {binding.Entity} entity - entity instance
+ * @returns {boolean} boolean indicating if entity with same id is attached
+ */
+
+
+ EntityManager.prototype.containsById = function containsById(entity) {
+ return !!(entity && this._entities[entity.id]);
+ };
+
+ /**
+ * Remove the given entity from the persistence context, causing a managed entity to become detached.
+ * Unflushed changes made to the entity if any (including removal of the entity),
+ * will not be synchronized to the database. Entities which previously referenced the detached entity will continue to reference it.
+ * @param {binding.Entity} entity - entity instance
+ */
+
+
+ EntityManager.prototype.detach = function detach(entity) {
+ var _this3 = this;
+
+ var state = Metadata.get(entity);
+ return state.withLock(function () {
+ _this3.removeReference(entity);
+ return Promise.resolve(entity);
+ });
+ };
+
+ /**
+ * Resolve the depth by loading the referenced objects of the given entity.
+ *
+ * @param {binding.Entity} entity - entity instance
+ * @param {Object} [options] The load options
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype.resolveDepth = function resolveDepth(entity, options) {
+ var _this4 = this;
+
+ if (!options || !options.depth) return Promise.resolve(entity);
+
+ options.resolved = options.resolved || [];
+ var promises = [];
+ var subOptions = Object.assign({}, options, {
+ depth: options.depth === true ? true : options.depth - 1
+ });
+ this.getSubEntities(entity, 1).forEach(function (subEntity) {
+ if (subEntity != null && !~options.resolved.indexOf(subEntity)) {
+ options.resolved.push(subEntity);
+ promises.push(_this4.load(subEntity.id, null, subOptions));
+ }
+ });
+
+ return Promise.all(promises).then(function () {
+ return entity;
+ });
+ };
+
+ /**
+ * Search for an entity of the specified oid.
+ * If the entity instance is contained in the persistence context, it is returned from there.
+ * @param {(Class|string)} entityClass - entity class
+ * @param {String} oid - Object ID
+ * @param {Object} [options] The load options.
+ * @return {Promise} the loaded entity or null
+ */
+
+
+ EntityManager.prototype.load = function load(entityClass, oid, options) {
+ var _this5 = this;
+
+ options = options || {};
+ var entity = this.getReference(entityClass, oid);
+ var state = Metadata.get(entity);
+
+ if (!options.refresh && options.local && state.isAvailable) {
+ return this.resolveDepth(entity, options);
+ }
+
+ var msg = new message.GetObject(state.bucket, state.key);
+
+ this.ensureCacheHeader(entity.id, msg, options.refresh);
+
+ return this.send(msg).then(function (response) {
+ // refresh object if loaded older version from cache
+ // chrome doesn't using cache when ifNoneMatch is set
+ if (entity.version > response.entity.version) {
+ options.refresh = true;
+ return _this5.load(entityClass, oid, options);
+ }
+
+ _this5.addToWhiteList(response.entity.id);
+
+ if (response.status != StatusCode.NOT_MODIFIED) {
+ state.setJson(response.entity, true);
+ }
+
+ return _this5.resolveDepth(entity, options);
+ }, function (e) {
+ if (e.status == StatusCode.OBJECT_NOT_FOUND) {
+ _this5.removeReference(entity);
+ state.setRemoved();
+ return null;
+ } else {
+ throw e;
+ }
+ });
+ };
+
+ /**
+ * @param {binding.Entity} entity
+ * @param {Object} options
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype.insert = function insert(entity, options) {
+ var _this6 = this;
+
+ options = options || {};
+ var isNew;
+
+ return this._save(entity, options, function (state, json) {
+ if (state.version) throw new error.PersistentError('Existing objects can\'t be inserted.');
+
+ isNew = !state.id;
+
+ return new message.CreateObject(state.bucket, json);
+ }).then(function (val) {
+ if (isNew) _this6._attach(entity);
+
+ return val;
+ });
+ };
+
+ /**
+ * @param {binding.Entity} entity
+ * @param {Object} options
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype.update = function update(entity, options) {
+ options = options || {};
+
+ return this._save(entity, options, function (state, json) {
+ if (!state.version) throw new error.PersistentError("New objects can't be inserted.");
+
+ if (options.force) {
+ delete json.version;
+ return new message.ReplaceObject(state.bucket, state.key, json).ifMatch('*');
+ } else {
+ return new message.ReplaceObject(state.bucket, state.key, json).ifMatch(state.version);
+ }
+ });
+ };
+
+ /**
+ * @param {binding.Entity} entity
+ * @param {Object} options The save options
+ * @param {boolean=} withoutLock Set true to save the entity without locking
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype.save = function save(entity, options, withoutLock) {
+ options = options || {};
+
+ var msgFactory = function msgFactory(state, json) {
+ if (options.force) {
+ if (!state.id) throw new error.PersistentError("New special objects can't be forcedly saved.");
+
+ delete json.version;
+ return new message.ReplaceObject(state.bucket, state.key, json);
+ } else if (state.version) {
+ return new message.ReplaceObject(state.bucket, state.key, json).ifMatch(state.version);
+ } else {
+ return new message.CreateObject(state.bucket, json);
+ }
+ };
+
+ return withoutLock ? this._locklessSave(entity, options, msgFactory) : this._save(entity, options, msgFactory);
+ };
+
+ /**
+ * @param {binding.Entity} entity
+ * @param {Function} cb pre-safe callback
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype.optimisticSave = function optimisticSave(entity, cb) {
+ var _this7 = this;
+
+ return Metadata.get(entity).withLock(function () {
+ return _this7._optimisticSave(entity, cb);
+ });
+ };
+
+ /**
+ * @param {binding.Entity} entity
+ * @param {Function} cb pre-safe callback
+ * @return {Promise}
+ * @private
+ */
+
+
+ EntityManager.prototype._optimisticSave = function _optimisticSave(entity, cb) {
+ var _this8 = this;
+
+ var abort = false;
+ var abortFn = function abortFn() {
+ abort = true;
+ };
+ var promise = Promise.resolve(cb(entity, abortFn));
+
+ if (abort) return Promise.resolve(entity);
+
+ return promise.then(function () {
+ return _this8.save(entity, {}, true).catch(function (e) {
+ if (e.status == 412) {
+ return _this8.refresh(entity, {}).then(function () {
+ return _this8._optimisticSave(entity, cb);
+ });
+ } else {
+ throw e;
+ }
+ });
+ });
+ };
+
+ /**
+ * Save the object state without locking
+ * @param {binding.Entity} entity
+ * @param {Object} options
+ * @param {Function} msgFactory
+ * @return {Promise.}
+ * @private
+ */
+
+
+ EntityManager.prototype._locklessSave = function _locklessSave(entity, options, msgFactory) {
+ var _this9 = this;
+
+ this.attach(entity);
+ var state = Metadata.get(entity);
+ var refPromises;
+
+ var json;
+ if (state.isAvailable) {
+ //getting json will check all collections changes, therefore we must do it before proofing the dirty state
+ json = state.getJson(false, true);
+ }
+
+ if (state.isDirty) {
+ if (!options.refresh) {
+ state.setPersistent();
+ }
+
+ var sendPromise = this.send(msgFactory(state, json)).then(function (response) {
+ if (options.refresh) {
+ state.setJson(response.entity, true);
+ } else {
+ state.setJsonMetadata(response.entity);
+ }
+ return entity;
+ }, function (e) {
+ if (e.status == StatusCode.OBJECT_NOT_FOUND) {
+ _this9.removeReference(entity);
+ state.setRemoved();
+ return null;
+ } else {
+ state.setDirty();
+ throw e;
+ }
+ });
+
+ refPromises = [sendPromise];
+ } else {
+ refPromises = [Promise.resolve(entity)];
+ }
+
+ var subOptions = Object.assign({}, options);
+ subOptions.depth = 0;
+ this.getSubEntities(entity, options.depth).forEach(function (sub) {
+ refPromises.push(_this9._save(sub, subOptions, msgFactory));
+ });
+
+ return Promise.all(refPromises).then(function () {
+ return entity;
+ });
+ };
+
+ /**
+ * Save and lock the object state
+ * @param {binding.Entity} entity
+ * @param {Object} options
+ * @param {Function} msgFactory
+ * @return {Promise.}
+ * @private
+ */
+
+
+ EntityManager.prototype._save = function _save(entity, options, msgFactory) {
+ var _this10 = this;
+
+ this.ensureBloomFilterFreshness();
+
+ var state = Metadata.get(entity);
+ if (state.version) {
+ this.addToBlackList(entity.id);
+ }
+
+ return state.withLock(function () {
+ return _this10._locklessSave(entity, options, msgFactory);
+ });
+ };
+
+ /**
+ * Returns all referenced sub entities for the given depth and root entity
+ * @param {binding.Entity} entity
+ * @param {boolean|number} depth
+ * @param {binding.Entity[]} [resolved]
+ * @param {binding.Entity=} initialEntity
+ * @returns {binding.Entity[]}
+ */
+
+
+ EntityManager.prototype.getSubEntities = function getSubEntities(entity, depth, resolved, initialEntity) {
+ var _this11 = this;
+
+ resolved = resolved || [];
+ if (!depth) {
+ return resolved;
+ }
+ initialEntity = initialEntity || entity;
+
+ var state = Metadata.get(entity);
+ for (var _iterator = state.type.references(), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
+ var _ref;
+
+ if (_isArray) {
+ if (_i >= _iterator.length) break;
+ _ref = _iterator[_i++];
+ } else {
+ _i = _iterator.next();
+ if (_i.done) break;
+ _ref = _i.value;
+ }
+
+ var value = _ref;
+
+ this.getSubEntitiesByPath(entity, value.path).forEach(function (subEntity) {
+ if (!~resolved.indexOf(subEntity) && subEntity != initialEntity) {
+ resolved.push(subEntity);
+ resolved = _this11.getSubEntities(subEntity, depth === true ? depth : depth - 1, resolved, initialEntity);
+ }
+ });
+ }
+
+ return resolved;
+ };
+
+ /**
+ * Returns all referenced one level sub entities for the given path
+ * @param {binding.Entity} entity
+ * @param {Array} path
+ * @returns {binding.Entity[]}
+ */
+
+
+ EntityManager.prototype.getSubEntitiesByPath = function getSubEntitiesByPath(entity, path) {
+ var _this12 = this;
+
+ var subEntities = [entity];
+
+ path.forEach(function (attributeName) {
+
+ var tmpSubEntities = [];
+ subEntities.forEach(function (subEntity) {
+ var curEntity = subEntity[attributeName];
+ if (!curEntity) return;
+
+ var attribute = _this12.metamodel.managedType(subEntity.constructor).getAttribute(attributeName);
+ if (attribute.isCollection) {
+ for (var _iterator2 = curEntity.entries(), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
+ var _ref2;
+
+ if (_isArray2) {
+ if (_i2 >= _iterator2.length) break;
+ _ref2 = _iterator2[_i2++];
+ } else {
+ _i2 = _iterator2.next();
+ if (_i2.done) break;
+ _ref2 = _i2.value;
+ }
+
+ var entry = _ref2;
+
+ tmpSubEntities.push(entry[1]);
+ attribute.keyType && attribute.keyType.isEntity && tmpSubEntities.push(entry[0]);
+ }
+ } else {
+ tmpSubEntities.push(curEntity);
+ }
+ });
+ subEntities = tmpSubEntities;
+ });
+
+ return subEntities;
+ };
+
+ /**
+ * Delete the entity instance.
+ * @param {binding.Entity} entity
+ * @param {Object} options The delete options
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype['delete'] = function _delete(entity, options) {
+ var _this13 = this;
+
+ options = options || {};
+
+ this.attach(entity);
+ var state = Metadata.get(entity);
+
+ return state.withLock(function () {
+ if (!state.version && !options.force) throw new error.IllegalEntityError(entity);
+
+ var msg = new message.DeleteObject(state.bucket, state.key);
+
+ _this13.addToBlackList(entity.id);
+
+ if (!options.force) msg.ifMatch(state.version);
+
+ var refPromises = [_this13.send(msg).then(function () {
+ _this13.removeReference(entity);
+ state.setRemoved();
+ return entity;
+ })];
+
+ var subOptions = Object.assign({}, options);
+ subOptions.depth = 0;
+ _this13.getSubEntities(entity, options.depth).forEach(function (sub) {
+ refPromises.push(_this13.delete(sub, subOptions));
+ });
+
+ return Promise.all(refPromises).then(function () {
+ return entity;
+ });
+ });
+ };
+
+ /**
+ * Synchronize the persistence context to the underlying database.
+ *
+ * @returns {Promise<*>}
+ */
+
+
+ EntityManager.prototype.flush = function flush(doneCallback, failCallback) {}
+ // TODO: implement this
+
+
+ /**
+ * Make an instance managed and persistent.
+ * @param {binding.Entity} entity - entity instance
+ */
+ ;
+
+ EntityManager.prototype.persist = function persist(entity) {
+ this.attach(entity);
+ };
+
+ /**
+ * Refresh the state of the instance from the database, overwriting changes made to the entity, if any.
+ * @param {binding.Entity} entity - entity instance
+ * @param {Object} options The refresh options
+ * @return {Promise}
+ */
+
+
+ EntityManager.prototype.refresh = function refresh(entity, options) {
+ options = options || {};
+ options.refresh = true;
+
+ return this.load(entity.id, null, options);
+ };
+
+ /**
+ * Attach the instance to this database context, if it is not already attached
+ * @param {binding.Entity} entity The entity to attach
+ */
+
+
+ EntityManager.prototype.attach = function attach(entity) {
+ if (!this.contains(entity)) {
+ var type = this.metamodel.entity(entity.constructor);
+ if (!type) throw new error.IllegalEntityError(entity);
+
+ if (this.containsById(entity)) throw new error.EntityExistsError(entity);
+
+ this._attach(entity);
+ }
+ };
+
+ EntityManager.prototype._attach = function _attach(entity) {
+ var metadata = Metadata.get(entity);
+ if (metadata.isAttached) {
+ if (metadata.db != this) {
+ throw new error.EntityExistsError(entity);
+ }
+ } else {
+ metadata.db = this;
+ }
+
+ if (!metadata.id) {
+ if (metadata.type.name != 'User' && metadata.type.name != 'Role' && metadata.type.name != 'logs.AppLog') {
+ metadata.id = '/db/' + metadata.type.name + '/' + util.uuid();
+ }
+ }
+
+ if (metadata.id) {
+ this._entities[metadata.id] = entity;
+ }
+ };
+
+ EntityManager.prototype.removeReference = function removeReference(entity) {
+ var state = Metadata.get(entity);
+ if (!state) throw new error.IllegalEntityError(entity);
+
+ delete this._entities[state.id];
+ };
+
+ EntityManager.prototype.register = function register(user, password, loginOption) {
+ var _this14 = this;
+
+ var login = loginOption > UserFactory.LoginOption.NO_LOGIN;
+ if (this.me && login) {
+ throw new error.PersistentError('User is already logged in.');
+ }
+
+ return this.withLock(function () {
+ var msg = new message.Register({
+ user: user,
+ password: password,
+ login: login
+ });
+ return _this14._userRequest(msg, loginOption);
+ });
+ };
+
+ EntityManager.prototype.login = function login(username, password, loginOption) {
+ var _this15 = this;
+
+ if (this.me) throw new error.PersistentError('User is already logged in.');
+
+ return this.withLock(function () {
+ var msg = new message.Login({
+ username: username,
+ password: password
+ });
+
+ return _this15._userRequest(msg, loginOption);
+ });
+ };
+
+ EntityManager.prototype.logout = function logout() {
+ var _this16 = this;
+
+ return this.withLock(function () {
+ return _this16.send(new message.Logout()).then(_this16._logout.bind(_this16));
+ });
+ };
+
+ EntityManager.prototype.loginWithOAuth = function loginWithOAuth(provider, clientID, options) {
+ if (this.me) throw new error.PersistentError('User is already logged in.');
+
+ options = Object.assign({
+ title: "Login with " + provider,
+ timeout: 5 * 60 * 1000,
+ state: {},
+ loginOption: true
+ }, options);
+
+ var msg;
+ if (Message[provider + 'OAuth']) {
+ msg = new Message[provider + 'OAuth'](clientID, options.scope, JSON.stringify(options.state));
+ } else {
+ throw new Error('OAuth provider ' + provider + ' not supported.');
+ }
+
+ var req = this._userRequest(msg, options.loginOption);
+ var w = open(msg.request.path, options.title, 'width=' + options.width + ',height=' + options.height);
+
+ return new Promise(function (resolve, reject) {
+ var timeout = setTimeout(function () {
+ reject(new error.PersistentError('OAuth login timeout.'));
+ }, options.timeout);
+
+ req.then(resolve, reject).then(function () {
+ clearTimeout(timeout);
+ });
+ });
+ };
+
+ EntityManager.prototype.renew = function renew() {
+ var _this17 = this;
+
+ return this.withLock(function () {
+ var msg = new message.Me();
+ return _this17._userRequest(msg, true);
+ });
+ };
+
+ EntityManager.prototype.newPassword = function newPassword(username, password, _newPassword) {
+ var _this18 = this;
+
+ return this.withLock(function () {
+ var msg = new message.NewPassword({
+ username: username,
+ password: password,
+ newPassword: _newPassword
+ });
+
+ return _this18.send(msg).then(function (response) {
+ return _this18._updateUser(response.entity);
+ });
+ });
+ };
+
+ EntityManager.prototype._updateUser = function _updateUser(obj, updateMe) {
+ var user = this.getReference(obj.id);
+ var metadata = Metadata.get(user);
+ metadata.setJson(obj, true);
+
+ if (updateMe) this.me = user;
+
+ return user;
+ };
+
+ EntityManager.prototype._logout = function _logout() {
+ this.me = null;
+ this.token = null;
+ };
+
+ EntityManager.prototype._userRequest = function _userRequest(msg, loginOption) {
+ var _this19 = this;
+
+ var login = loginOption > UserFactory.LoginOption.NO_LOGIN;
+ if (login) {
+ this.tokenStorage.temporary = loginOption < UserFactory.LoginOption.PERSIST_LOGIN;
+ }
+
+ return this.send(msg).then(function (response) {
+ if (response.entity) {
+ return _this19._updateUser(response.entity, login);
+ }
+ }, function (e) {
+ if (e.status == StatusCode.OBJECT_NOT_FOUND) {
+ if (login) _this19._logout();
+ return null;
+ } else {
+ throw e;
+ }
+ });
+ };
+
+ EntityManager.prototype.registerDevice = function registerDevice(os, token, device) {
+ var msg = new message.DeviceRegister({
+ token: token,
+ devicetype: os,
+ device: device
+ });
+
+ msg.withCredentials = true;
+ return this.send(msg);
+ };
+
+ EntityManager.prototype.checkDeviceRegistration = function checkDeviceRegistration() {
+ var _this20 = this;
+
+ return this.send(new message.DeviceRegistered()).then(function () {
+ return _this20.isDeviceRegistered = true;
+ }, function (e) {
+ if (e.status == StatusCode.OBJECT_NOT_FOUND) {
+ return _this20.isDeviceRegistered = false;
+ } else {
+ throw e;
+ }
+ });
+ };
+
+ EntityManager.prototype.pushDevice = function pushDevice(pushMessage) {
+ return this.send(new message.DevicePush(pushMessage));
+ };
+
+ /**
+ * The given entity will be checked by the validation code of the entity type.
+ *
+ * @param {binding.Entity} entity
+ * @returns {util.ValidationResult} result
+ */
+
+
+ EntityManager.prototype.validate = function validate(entity) {
+ var type = Metadata.get(entity).type;
+
+ var result = new util.ValidationResult();
+ for (var iter = type.attributes(), item; !(item = iter.next()).done;) {
+ var validate = new util.Validator(item.value.name, entity);
+ result.fields[validate.key] = validate;
+ }
+
+ var validationCode = type.validationCode;
+ if (validationCode) {
+ validationCode(result.fields);
+ }
+
+ return result;
+ };
+
+ /**
+ * Adds the given object id to the cacheWhiteList if needed.
+ * @param {string} objectId The id to add.
+ */
+
+
+ EntityManager.prototype.addToWhiteList = function addToWhiteList(objectId) {
+ if (!this.isCachingDisabled) {
+ if (this.bloomFilter.contains(objectId)) {
+ this.cacheWhiteList.add(objectId);
+ }
+ this.cacheBlackList.delete(objectId);
+ }
+ };
+
+ /**
+ * Adds the given object id to the cacheBlackList if needed.
+ * @param {string} objectId The id to add.
+ */
+
+
+ EntityManager.prototype.addToBlackList = function addToBlackList(objectId) {
+ if (!this.isCachingDisabled) {
+ if (!this.bloomFilter.contains(objectId)) {
+ this.cacheBlackList.add(objectId);
+ }
+ this.cacheWhiteList.delete(objectId);
+ }
+ };
+
+ EntityManager.prototype.refreshBloomFilter = function refreshBloomFilter() {
+ var _this21 = this;
+
+ if (this.isCachingDisabled) return Promise.resolve();
+
+ var msg = new message.GetBloomFilter();
+ return this.send(msg).then(function (response) {
+ _this21.updateBloomFilter(response.entity);
+ return _this21.bloomFilter;
+ });
+ };
+
+ EntityManager.prototype.updateBloomFilter = function updateBloomFilter(bloomFilter) {
+ this.bloomFilter = new BloomFilter(bloomFilter);
+ this.cacheWhiteList = new Set();
+ this.cacheBlackList = new Set();
+ };
+
+ /**
+ * Checks the freshness of the bloom filter and does a reload if necessary
+ */
+
+
+ EntityManager.prototype.ensureBloomFilterFreshness = function ensureBloomFilterFreshness() {
+ var _this22 = this;
+
+ if (this.isCachingDisabled) return;
+
+ var now = new Date().getTime();
+ var refreshRate = this.bloomFilterRefresh * 1000;
+
+ if (this._bloomFilterLock.isReady && now - this.bloomFilter.creation > refreshRate) {
+ this._bloomFilterLock.withLock(function () {
+ return _this22.refreshBloomFilter();
+ });
+ }
+ };
+
+ /**
+ * Checks for a given id, if revalidation is required, the resource is stale or caching was disabled
+ * @param {string} id The object id to check
+ * @returns {boolean} Indicates if the resource must be revalidated
+ */
+
+
+ EntityManager.prototype.mustRevalidate = function mustRevalidate(id) {
+ if (util.isNode) return false;
+
+ this.ensureBloomFilterFreshness();
+
+ var refresh = this.isCachingDisabled || !this._bloomFilterLock.isReady;
+ refresh = refresh || !this.cacheWhiteList.has(id) && (this.cacheBlackList.has(id) || this.bloomFilter.contains(id));
+ return refresh;
+ };
+
+ /**
+ *
+ * @param {string} id To check the bloom filter
+ * @param {connector.Message} message To attach the headers
+ * @param {boolean} refresh To force the reload headers
+ */
+
+
+ EntityManager.prototype.ensureCacheHeader = function ensureCacheHeader(id, message, refresh) {
+ refresh = refresh || this.mustRevalidate(id);
+
+ if (refresh) {
+ message.noCache();
+ }
+ };
+
+ /**
+ * Creates a absolute url for the given relative one
+ * @param {string} relativePath the relative url
+ * @param {boolean=} authorize indicates if authorization credentials should be generated and be attached to the url
+ * @return {string} a absolute url wich is optionaly signed with a resource token which authenticates the currently
+ * logged in user
+ */
+
+
+ EntityManager.prototype.createURL = function createURL(relativePath, authorize) {
+ var path = this._connector.basePath + relativePath;
+
+ var append = false;
+ if (authorize && this.me) {
+ path = this.tokenStorage.signPath(path);
+ append = true;
+ } else {
+ path = path.split('/').map(encodeURIComponent).join('/');
+ }
+
+ if (this.mustRevalidate(relativePath)) {
+ path = path + (append ? '&' : '?') + 'BCB';
+ }
+
+ return this._connector.origin + path;
+ };
+
+ return EntityManager;
+}(util.Lockable);
+
+/**
+ * Constructor for a new List collection
+ * @function
+ * @param {...*} args Same arguments can be passed as the Array constructor takes
+ * @return {void} The new created List
+ */
+
+
+EntityManager.prototype.List = Array;
+
+/**
+ * Constructor for a new Set collection
+ * @function
+ * @param {Iterable<*>=} collection The initial array or collection to initialize the new Set
+ * @return {void} The new created Set
+ */
+EntityManager.prototype.Set = Set;
+
+/**
+ * Constructor for a new Map collection
+ * @function
+ * @param {Iterable<*>=} collection The initial array or collection to initialize the new Map
+ * @return {void} The new created Map
+ */
+EntityManager.prototype.Map = Map;
+
+/**
+ * Constructor for a new GeoPoint
+ * @function
+ * @param {string|number|Object|Array} [latitude] A coordinate pair (latitude first), a GeoPoint like object or the GeoPoint's latitude
+ * @param {number=} longitude The GeoPoint's longitude
+ * @return {void} The new created GeoPoint
+ */
+EntityManager.prototype.GeoPoint = _dereq_(5);
+
+/**
+ * An User factory for user objects.
+ * The User factory can be called to create new instances of users or can be used to register/login/logout users.
+ * The created instances implements the {@link model.User} interface
+ * @name User
+ * @type binding.UserFactory
+ * @memberOf EntityManager.prototype
+ */
+
+/**
+ * An Role factory for role objects.
+ * The Role factory can be called to create new instances of roles, later on users can be attached to roles to manage the
+ * access permissions through this role
+ * The created instances implements the {@link model.Role} interface
+ * @name Role
+ * @memberOf EntityManager.prototype
+ * @type binding.EntityFactory
+ */
+
+/**
+ * An Device factory for user objects.
+ * The Device factory can be called to create new instances of devices or can be used to register, push to and
+ * check registration status of devices.
+ * @name Device
+ * @memberOf EntityManager.prototype
+ * @type binding.DeviceFactory
+ */
+
+/**
+ * An Object factory for entity or embedded objects,
+ * that can be accessed by the type name of the entity type.
+ * An object factory can be called to create new instances of the type.
+ * The created instances implements the {@link binding.Entity} or the {@link binding.Managed} interface
+ * whenever the class is an entity or embedded object
+ * @name [YourEntityClass: string]
+ * @memberOf EntityManager.prototype
+ * @type {*}
+ */
+
+/**
+ * A File factory for file objects.
+ * The file factory can be called to create new instances for files.
+ * The created instances implements the {@link binding.File} interface
+ * @name File
+ * @memberOf EntityManager.prototype
+ * @type binding.FileFactory
+ */
+
+module.exports = EntityManager;
+
+},{"19":19,"20":20,"21":21,"25":25,"34":34,"36":36,"4":4,"5":5,"59":59,"63":63,"70":70}],3:[function(_dereq_,module,exports){
+"use strict";
+
+var message = _dereq_(36);
+var metamodel = _dereq_(52);
+
+var util = _dereq_(70);
+var caching = _dereq_(22);
+var Connector = _dereq_(23);
+var EntityManager = _dereq_(2);
+
+/**
+ * @alias EntityManagerFactory
+ * @extends util.Lockable
+ */
+
+var EntityManagerFactory = function (_util$Lockable) {
+ babelHelpers.inherits(EntityManagerFactory, _util$Lockable);
+
+ EntityManagerFactory.prototype._connected = function _connected() {};
+
+ /**
+ * Creates a new EntityManagerFactory connected to the given destination
+ * @param {string|Object} [options] The destination to connect with, or an options object
+ * @param {string} [options.host] The destination to connect with
+ * @param {number} [options.port=80|443] The optional destination port to connect with
+ * @param {boolean} [options.secure=false] true
To use a secure ssl encrypted connection
+ * @param {string} [options.basePath="/v1"] The base path of the api
+ * @param {Object} [options.schema=null] The serialized schema as json used to initialize the metamodel
+ * @param {util.TokenStorage} [options.tokenStorage] The tokenStorage which should be used by this emf
+ * @param {util.TokenStorageFactory} [options.tokenStorageFactory] The tokenStorage factory implementation which should
+ * be used for token storage
+ * @param {number} [options.staleness=60] The maximum staleness of objects that are acceptable while reading cached data
+ */
+
+
+ function EntityManagerFactory(options) {
+ babelHelpers.classCallCheck(this, EntityManagerFactory);
+
+ var _this = babelHelpers.possibleConstructorReturn(this, _util$Lockable.call(this));
+
+ options = Object(options) instanceof String ? { host: options } : options || {};
+
+ /** @type connector.Connector */
+ _this._connector = null;
+ /** @type metamodel.Metamodel */
+ _this.metamodel = _this.createMetamodel();
+ /** @type util.Code */
+ _this.code = new util.Code(_this.metamodel, _this);
+ /** @type util.TokenStorageFactory */
+ _this.tokenStorageFactory = util.TokenStorage.WEB_STORAGE || util.TokenStorage.GLOBAL;
+
+ _this.configure(options);
+
+ var isReady = true;
+ var ready = new Promise(function (success) {
+ _this._connected = success;
+ });
+
+ if (options.host) {
+ _this.connect(options.host, options.port, options.secure, options.basePath);
+ } else {
+ isReady = false;
+ }
+
+ if (!_this.tokenStorage) {
+ isReady = false;
+ ready = ready.then(function () {
+ return _this.tokenStorageFactory.create(_this._connector.origin);
+ }).then(function (tokenStorage) {
+ _this.tokenStorage = tokenStorage;
+ });
+ }
+
+ if (options.schema) {
+ _this._connectData = options;
+ _this.metamodel.init(options.schema);
+ } else {
+ isReady = false;
+ ready = ready.then(function () {
+ var msg = new message.Connect();
+ msg.withCredentials = true; //used for registered devices
+
+ if (_this.staleness === 0) msg.noCache();
+
+ return _this.send(msg);
+ }).then(function (response) {
+ _this._connectData = response.entity;
+
+ if (_this.staleness === undefined) {
+ _this.staleness = _this._connectData.bloomFilterRefresh || 60;
+ }
+
+ if (!_this.metamodel.isInitialized) _this.metamodel.init(_this._connectData.schema);
+
+ _this.tokenStorage.update(_this._connectData.token);
+ });
+ }
+
+ if (!isReady) {
+ _this.withLock(function () {
+ return ready;
+ }, true);
+ }
+ return _this;
+ }
+
+ /**
+ * Apply additional configurations to this EntityManagerFactory
+ * @param {Object} options The additional configuration options
+ * @param {util.TokenStorage} [options.tokenStorage] The tokenStorage which should be used by this emf
+ * @param {util.TokenStorageFactory} [options.tokenStorageFactory] The tokenStorage factory implementation which should
+ * be used for token storage
+ * @param {number} [options.staleness=60] The maximum staleness of objects that are acceptable while reading cached data,
+ * 0
to always bypass the browser cache
+ */
+
+
+ EntityManagerFactory.prototype.configure = function configure(options) {
+ if (this._connector) throw new Error('The EntityManagerFactory can only be configured before is is connected.');
+
+ if (options.tokenStorage) {
+ /** @type util.TokenStorage */
+ this.tokenStorage = options.tokenStorage;
+ }
+
+ if (options.tokenStorageFactory) {
+ this.tokenStorageFactory = options.tokenStorageFactory;
+ }
+
+ if (options.staleness !== undefined) {
+ /** @type number */
+ this.staleness = options.staleness;
+ }
+ };
+
+ /**
+ * Connects this EntityManager to the given destination
+ * @param {string} hostOrApp The host or the app name to connect with
+ * @param {number} [port=80|443] The port to connect to
+ * @param {boolean} [secure=false] true
To use a secure connection
+ * @param {string} [basePath="/v1"] The base path of the api
+ */
+
+
+ EntityManagerFactory.prototype.connect = function connect(hostOrApp, port, secure, basePath) {
+ if (this._connector) throw new Error('The EntityManagerFactory is already connected.');
+
+ if (Object(port) instanceof Boolean) {
+ secure = port;
+ port = 0;
+ }
+
+ this._connector = Connector.create(hostOrApp, port, secure, basePath);
+
+ this._connected();
+ return this.ready();
+ };
+
+ /**
+ * Connects this EntityManager to the given destination
+ * @param {string} hostOrApp The host or the app name to connect with
+ * @param {boolean} [secure=false] true
To use a secure connection
+ * @name connect
+ * @memberOf EntityManagerFactory.prototype
+ * @method
+ */
+
+ /**
+ * Creates a new Metamodel instance, which is not connected
+ * @return {metamodel.Metamodel} A new Metamodel instance
+ */
+
+
+ EntityManagerFactory.prototype.createMetamodel = function createMetamodel() {
+ return new metamodel.Metamodel(this);
+ };
+
+ /**
+ * Create a new application-managed EntityManager.
+ *
+ * @param {boolean=} useSharedTokenStorage The token storage to persist the authorization token, or
+ * true
To use the shared token storage of the emf.
+ * false
To use a instance based storage.
+ *
+ * @returns {EntityManager} a new entityManager
+ */
+
+
+ EntityManagerFactory.prototype.createEntityManager = function createEntityManager(useSharedTokenStorage) {
+ var _this2 = this;
+
+ var em = new EntityManager(this);
+
+ if (this.isReady) {
+ em.connected(this._connector, this._connectData, useSharedTokenStorage ? this.tokenStorage : new util.TokenStorage(this._connector.origin));
+ } else {
+ em.withLock(function () {
+ return _this2.ready().then(function () {
+ em.connected(_this2._connector, _this2._connectData, useSharedTokenStorage ? _this2.tokenStorage : new util.TokenStorage(_this2._connector.origin));
+ });
+ }, true);
+ }
+
+ return em;
+ };
+
+ EntityManagerFactory.prototype.send = function send(message) {
+ if (!message.tokenStorage) message.tokenStorage = this.tokenStorage;
+ return this._connector.send(message);
+ };
+
+ return EntityManagerFactory;
+}(util.Lockable);
+
+module.exports = EntityManagerFactory;
+
+},{"2":2,"22":22,"23":23,"36":36,"52":52,"70":70}],4:[function(_dereq_,module,exports){
+"use strict";
+
+var message = _dereq_(36);
+var error = _dereq_(34);
+
+/**
+ * @alias EntityTransaction
+ */
+
+var EntityTransaction = function () {
+ babelHelpers.createClass(EntityTransaction, [{
+ key: 'isActive',
+
+
+ /**
+ * Indicate whether a resource transaction is in progress.
+ * @returns {boolean} indicating whether transaction is in progress
+ */
+ get: function get() {
+ return Boolean(this.tid);
+ }
+
+ /**
+ * @param {EntityManager} entityManager
+ */
+
+ }]);
+
+ function EntityTransaction(entityManager) {
+ babelHelpers.classCallCheck(this, EntityTransaction);
+
+ this._connector = entityManager.connector;
+ this.entityManager = entityManager;
+
+ this.tid = null;
+ this.rollbackOnly = false;
+
+ this.readSet = null;
+ this.changeSet = null;
+ }
+
+ /**
+ * Start a resource transaction.
+ */
+
+
+ EntityTransaction.prototype.begin = function begin(doneCallback, failCallback) {
+ return this.yield().then(function () {
+ var result = this.send(new message.PostTransaction()).done(function (msg) {
+ this.tid = msg.tid;
+
+ this.rollbackOnly = false;
+ this.readSet = {};
+ this.changeSet = {};
+ });
+
+ return this.wait(result);
+ }).then(doneCallback, failCallback);
+ };
+
+ /**
+ * Commit the current resource transaction, writing any unflushed changes to the database.
+ */
+
+
+ EntityTransaction.prototype.commit = function commit(doneCallback, failCallback) {
+ return this.yield().then(function () {
+ if (this.getRollbackOnly()) {
+ return this.rollback().then(function () {
+ throw new error.RollbackError();
+ });
+ } else {
+ return this.wait(this.entityManager.flush()).then(function () {
+ var readSet = [];
+ for (var ref in this.readSet) {
+ readSet.push({
+ "oid": ref,
+ "version": this.readSet[ref]
+ });
+ }
+
+ var result = this.send(new message.PutTransactionCommitted(this.tid, readSet));
+
+ return this.wait(result).then(function (msg) {
+ this.tid = null;
+ this.readSet = null;
+ this.changeSet = null;
+
+ var oids = msg.oids;
+ for (var oid in oids) {
+ var version = oids[oid];
+ var entity = this.entityManager.entities[oid];
+
+ if (entity) {
+ var state = util.Metadata.get(entity);
+ if (version == 'DELETED' || state.isDeleted) {
+ this.entityManager.removeReference(entity);
+ } else {
+ state.setJsonValue(state.type.version, version);
+ }
+ }
+ }
+ });
+ });
+ }
+ }).then(doneCallback, failCallback);
+ };
+
+ /**
+ * Determine whether the current resource transaction has been marked for rollback.
+ * @returns {boolean} indicating whether the transaction has been marked for rollback
+ */
+
+
+ EntityTransaction.prototype.getRollbackOnly = function getRollbackOnly() {
+ return this.rollbackOnly;
+ };
+
+ /**
+ * Roll back the current resource transaction.
+ */
+
+
+ EntityTransaction.prototype.rollback = function rollback(doneCallback, failCallback) {
+ return this.yield().then(function () {
+ var result = this.send(new message.PutTransactionAborted(this.tid));
+
+ this.wait(result).then(function () {
+ this.tid = null;
+ this.readSet = null;
+ this.changeSet = null;
+ return this.entityManager.clear();
+ }, function () {
+ return this.entityManager.clear();
+ });
+ }).then(doneCallback, failCallback);
+ };
+
+ /**
+ * Mark the current resource transaction so that the only possible outcome of the transaction is for the transaction to be rolled back.
+ */
+
+
+ EntityTransaction.prototype.setRollbackOnly = function setRollbackOnly(context, onSuccess) {
+ return this.yield().done(function () {
+ this.rollbackOnly = true;
+ });
+ };
+
+ EntityTransaction.prototype.isRead = function isRead(identifier) {
+ return this.isActive && identifier in this.readSet;
+ };
+
+ EntityTransaction.prototype.setRead = function setRead(identifier, version) {
+ if (this.isActive && !this.isChanged(identifier)) {
+ this.readSet[identifier] = version;
+ }
+ };
+
+ EntityTransaction.prototype.isChanged = function isChanged(identifier) {
+ return this.isActive && identifier in this.changeSet;
+ };
+
+ EntityTransaction.prototype.setChanged = function setChanged(identifier) {
+ if (this.isActive) {
+ delete this.readSet[identifier];
+ this.changeSet[identifier] = true;
+ }
+ };
+
+ return EntityTransaction;
+}();
+
+module.exports = EntityTransaction;
+
+},{"34":34,"36":36}],5:[function(_dereq_,module,exports){
+"use strict";
+
+/**
+ * Creates a new GeoPoint instance
+ * From latitude and longitude
+ * From a json object
+ * Or an tuple of latitude and longitude
+ *
+ * @alias GeoPoint
+ */
+
+var GeoPoint = function () {
+
+ /**
+ * Creates a GeoPoint with the user's current location, if available.
+ * @return {Promise} A promise that will be resolved with a GeoPoint
+ */
+ GeoPoint.current = function current() {
+ return new Promise(function (resolve, reject) {
+ navigator.geolocation.getCurrentPosition(function (location) {
+ resolve(new GeoPoint(location.coords.latitude, location.coords.longitude));
+ }, function (error) {
+ reject(error);
+ });
+ });
+ };
+
+ /**
+ * @param {string|number|Object|Array} [latitude] A coordinate pair (latitude first), a GeoPoint like object or the GeoPoint's latitude
+ * @param {number=} longitude The GeoPoint's longitude
+ */
+
+
+ function GeoPoint(latitude, longitude) {
+ babelHelpers.classCallCheck(this, GeoPoint);
+
+ var lat = void 0,
+ lng = void 0;
+ if (Object(latitude) instanceof String) {
+ var index = latitude.indexOf(';');
+ lat = latitude.substring(0, index);
+ lng = latitude.substring(index + 1);
+ } else if (Object(latitude) instanceof Number) {
+ lat = latitude;
+ lng = longitude;
+ } else if (Object(latitude) instanceof Array) {
+ lat = latitude[0];
+ lng = latitude[1];
+ } else if (latitude instanceof Object) {
+ lat = latitude.latitude;
+ lng = latitude.longitude;
+ } else {
+ lat = 0;
+ lng = 0;
+ }
+
+ /**
+ * Longitude of the given point
+ * @type {number}
+ */
+ this.longitude = lng;
+
+ /**
+ * Latitude of the given point
+ * @type {number}
+ */
+ this.latitude = lat;
+
+ if (this.latitude < -90 || this.latitude > 90) {
+ throw new Error("Latitude " + this.latitude + " is not in bound of -90 <= latitude <= 90");
+ }
+
+ if (this.longitude < -180 || this.longitude > 180) {
+ throw new Error("Longitude " + this.longitude + " is not in bound of -180 <= longitude <= 180");
+ }
+ }
+
+ /**
+ * Returns the distance from this GeoPoint to another in kilometers.
+ * @param {GeoPoint} point another GeoPoint
+ * @return {number} The distance in kilometers
+ *
+ * @see GeoPoint#radiansTo
+ */
+
+
+ GeoPoint.prototype.kilometersTo = function kilometersTo(point) {
+ return Number((GeoPoint.EARTH_RADIUS_IN_KILOMETERS * this.radiansTo(point)).toFixed(3));
+ };
+
+ /**
+ * Returns the distance from this GeoPoint to another in miles.
+ * @param {GeoPoint} point another GeoPoint
+ * @return {number} The distance in miles
+ *
+ * @see GeoPoint#radiansTo
+ */
+
+
+ GeoPoint.prototype.milesTo = function milesTo(point) {
+ return Number((GeoPoint.EARTH_RADIUS_IN_MILES * this.radiansTo(point)).toFixed(3));
+ };
+
+ /**
+ * Computes the arc, in radian, between two WGS-84 positions.
+ *
+ * The haversine formula implementation is taken from:
+ * {@link http://www.movable-type.co.uk/scripts/latlong.html}
+ *
+ * Returns the distance from this GeoPoint to another in radians.
+ * @param {GeoPoint} point another GeoPoint
+ * @return {number} the arc, in radian, between two WGS-84 positions
+ *
+ * @see http://en.wikipedia.org/wiki/Haversine_formula
+ */
+
+
+ GeoPoint.prototype.radiansTo = function radiansTo(point) {
+ var from = this,
+ to = point;
+ var rad1 = from.latitude * GeoPoint.DEG_TO_RAD,
+ rad2 = to.latitude * GeoPoint.DEG_TO_RAD,
+ dLng = (to.longitude - from.longitude) * GeoPoint.DEG_TO_RAD;
+
+ return Math.acos(Math.sin(rad1) * Math.sin(rad2) + Math.cos(rad1) * Math.cos(rad2) * Math.cos(dLng));
+ };
+
+ /**
+ * A String representation in latitude, longitude format
+ * @return {string} The string representation of this class
+ */
+
+
+ GeoPoint.prototype.toString = function toString() {
+ return this.latitude + ';' + this.longitude;
+ };
+
+ /**
+ * Returns a JSON representation of the GeoPoint
+ * @return {json} A GeoJson object of this GeoPoint
+ */
+
+
+ GeoPoint.prototype.toJSON = function toJSON() {
+ return { latitude: this.latitude, longitude: this.longitude };
+ };
+
+ return GeoPoint;
+}();
+
+GeoPoint.DEG_TO_RAD = Math.PI / 180;
+
+/**
+ * The Earth radius in kilometers used by {@link GeoPoint#kilometersTo}
+ * @type {number}
+ */
+GeoPoint.EARTH_RADIUS_IN_KILOMETERS = 6371;
+
+/**
+ * The Earth radius in miles used by {@link GeoPoint#milesTo}
+ * @type {number}
+ */
+GeoPoint.EARTH_RADIUS_IN_MILES = 3956;
+
+module.exports = GeoPoint;
+
+},{}],6:[function(_dereq_,module,exports){
+'use strict';
+
+/**
+ * @interface baqend
+ * @extends EntityManager
+ */
+var EntityManagerFactory = _dereq_(3);
+var EntityManager = _dereq_(2);
+
+EntityManager.prototype.binding = _dereq_(20);
+EntityManager.prototype.connector = _dereq_(28);
+EntityManager.prototype.error = _dereq_(34);
+EntityManager.prototype.message = _dereq_(36);
+EntityManager.prototype.metamodel = _dereq_(52);
+EntityManager.prototype.util = _dereq_(70);
+EntityManager.prototype.caching = _dereq_(22);
+EntityManager.prototype.query = _dereq_(59);
+
+EntityManager.prototype.EntityManager = _dereq_(2);
+EntityManager.prototype.EntityManagerFactory = _dereq_(3);
+EntityManager.prototype.EntityTransaction = _dereq_(4);
+EntityManager.prototype.Acl = _dereq_(1);
+
+var emf = new EntityManagerFactory();
+var db = emf.createEntityManager(true);
+
+/**
+ * Configures the DB with additional config options
+ * @param {Object} options The additional configuration options
+ * @param {util.TokenStorage} [options.tokenStorage] The tokenStorage which should be used by this emf
+ * @param {util.TokenStorageFactory} [options.tokenStorageFactory] The tokenStorage factory implementation which should
+ * be used for token storage
+ * @param {number} [options.staleness=60] The maximum staleness of objects that are acceptable while reading cached data,
+ * 0
to always bypass the browser cache
+ * @function
+ * @return {baqend}
+ * @alias baqend#configure
+ */
+db.configure = function (options) {
+ emf.configure(options);
+ return this;
+};
+
+/**
+ * Connects the DB with the server and calls the callback on success
+ * @param {string} hostOrApp The host or the app name to connect with
+ * @param {boolean} [secure=false] true
To use a secure connection
+ * @param {util.Lockable~callback=} doneCallback The callback, called when a connection is established and the
+ * SDK is ready to use
+ * @param {util.Lockable~callback=} failCallback When an error occurred while initializing the SDK
+ * @function
+ * @return {Promise}
+ * @alias baqend#connect
+ */
+db.connect = function (hostOrApp, secure, doneCallback, failCallback) {
+ if (secure instanceof Function) {
+ failCallback = doneCallback;
+ doneCallback = secure;
+ secure = undefined;
+ }
+
+ emf.connect(hostOrApp, secure);
+ return this.ready(doneCallback, failCallback);
+};
+
+exports = module.exports = db;
+//import {db} from 'baqend';
+exports.db = db;
+//import db from 'baqend';
+exports.default = db;
+
+},{"1":1,"2":2,"20":20,"22":22,"28":28,"3":3,"34":34,"36":36,"4":4,"52":52,"59":59,"70":70}],7:[function(_dereq_,module,exports){
+"use strict";
+
+/**
+ * @alias binding.Accessor
+ */
+
+var Accessor = function () {
+ function Accessor() {
+ babelHelpers.classCallCheck(this, Accessor);
+ }
+
+ /**
+ * @param {Object} object
+ * @param {metamodel.Attribute} attribute
+ * @returns {*}
+ */
+ Accessor.prototype.getValue = function getValue(object, attribute) {
+ return object[attribute.name];
+ };
+
+ /**
+ * @param {Object} object
+ * @param {metamodel.Attribute} attribute
+ * @param {*} value
+ */
+
+
+ Accessor.prototype.setValue = function setValue(object, attribute, value) {
+ object[attribute.name] = value;
+ };
+
+ return Accessor;
+}();
+
+module.exports = Accessor;
+
+},{}],8:[function(_dereq_,module,exports){
+"use strict";
+
+var EntityFactory = _dereq_(11);
+
+/**
+ * @class binding.DeviceFactory
+ * @extends binding.EntityFactory
+ *
+ * @param {Object=} properties initial properties to set on the instance
+ * @param {...*} arguments Additional constructor params passed through the type constructor
+ * @return {model.Device} The new managed instance
+ */
+var DeviceFactory = EntityFactory.extend( /** @lends binding.DeviceFactory.prototype */{
+
+ /**
+ * Returns true if the devices is already registered, otherwise false.
+ * @returns {boolean} Status of the device registration
+ */
+ get isRegistered() {
+ return this._db.isDeviceRegistered;
+ },
+
+ /**
+ * Register a new device with the given device token and OS.
+ * @param {string} os The OS of the device (IOS/Android)
+ * @param {string} token The GCM or APNS device token
+ * @param {model.Device=} device A optional device entity to set custom field values
+ * @param {binding.Entity~doneCallback=} doneCallback Called when the operation succeed.
+ * @param {binding.Entity~failCallback=} failCallback Called when the operation failed.
+ * @return {Promise}
+ */
+ register: function register(os, token, device, doneCallback, failCallback) {
+ if (device instanceof Function) {
+ failCallback = doneCallback;
+ doneCallback = device;
+ device = null;
+ }
+
+ return this._db.registerDevice(os, token, device).then(doneCallback, failCallback);
+ },
+
+
+ /**
+ * Uses the info from the given {util.PushMessage} message to send an push notification.
+ * @param {util.PushMessage} pushMessage to send an push notification.
+ * @param {binding.Entity~doneCallback=} doneCallback Called when the operation succeed.
+ * @param {binding.Entity~failCallback=} failCallback Called when the operation failed.
+ * @return {Promise}
+ */
+ push: function push(pushMessage, doneCallback, failCallback) {
+ return this._db.pushDevice(pushMessage).then(doneCallback, failCallback);
+ }
+});
+
+DeviceFactory.PushMessage = _dereq_(66);
+
+module.exports = DeviceFactory;
+
+},{"11":11,"66":66}],9:[function(_dereq_,module,exports){
+"use strict";
+
+var Metadata = _dereq_(63);
+var Lockable = _dereq_(61);
+
+/**
+ * @alias binding.Enhancer
+ */
+
+var Enhancer = function () {
+ function Enhancer() {
+ babelHelpers.classCallCheck(this, Enhancer);
+ }
+
+ /**
+ * @param {Class<*>} superClass
+ * @returns {Class<*>} typeConstructor
+ */
+ Enhancer.prototype.createProxy = function createProxy(superClass) {
+ return function (_superClass) {
+ babelHelpers.inherits(Proxy, _superClass);
+
+ function Proxy() {
+ babelHelpers.classCallCheck(this, Proxy);
+ return babelHelpers.possibleConstructorReturn(this, _superClass.apply(this, arguments));
+ }
+
+ return Proxy;
+ }(superClass);
+ };
+
+ /**
+ * @param {Class<*>} typeConstructor
+ * @returns {string}
+ */
+
+
+ Enhancer.prototype.getIdentifier = function getIdentifier(typeConstructor) {
+ return typeConstructor.__d__;
+ };
+
+ /**
+ * @param {Class<*>} typeConstructor
+ * @param {string} identifier
+ */
+
+
+ Enhancer.prototype.setIdentifier = function setIdentifier(typeConstructor, identifier) {
+ Object.defineProperty(typeConstructor, '__d__', {
+ value: identifier
+ });
+ };
+
+ /**
+ * @param {metamodel.ManagedType} type
+ * @param {Class<*>} typeConstructor
+ */
+
+
+ Enhancer.prototype.enhance = function enhance(type, typeConstructor) {
+ if (typeConstructor.__ype__ == type) return;
+
+ if (typeConstructor.hasOwnProperty('__ype__')) throw new Error('Type is already used by a different manager');
+
+ Object.defineProperty(typeConstructor, '__ype__', {
+ value: type
+ });
+
+ this.setIdentifier(typeConstructor, type.ref);
+ this.enhancePrototype(typeConstructor.prototype, type);
+ };
+
+ /**
+ * Enhance the prototype of the type
+ * @param {Object} proto
+ * @param {metamodel.ManagedType} type
+ */
+
+
+ Enhancer.prototype.enhancePrototype = function enhancePrototype(proto, type) {
+ if (proto.toString === Object.prototype.toString) {
+ // implements a better convenience toString method
+ Object.defineProperty(proto, 'toString', {
+ value: function toString() {
+ return this._metadata.id || this._metadata.bucket;
+ },
+ enumerable: false
+ });
+ }
+
+ // enhance all persistent object properties
+ if (type.superType && type.superType.name == 'Object') {
+ for (var _iterator = type.superType.declaredAttributes, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
+ var _ref;
+
+ if (_isArray) {
+ if (_i >= _iterator.length) break;
+ _ref = _iterator[_i++];
+ } else {
+ _i = _iterator.next();
+ if (_i.done) break;
+ _ref = _i.value;
+ }
+
+ var attr = _ref;
+
+ if (!attr.isMetadata) this.enhanceProperty(proto, attr);
+ }
+ }
+
+ // enhance all persistent properties
+ for (var _iterator2 = type.declaredAttributes, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
+ var _ref2;
+
+ if (_isArray2) {
+ if (_i2 >= _iterator2.length) break;
+ _ref2 = _iterator2[_i2++];
+ } else {
+ _i2 = _iterator2.next();
+ if (_i2.done) break;
+ _ref2 = _i2.value;
+ }
+
+ var _attr = _ref2;
+
+ this.enhanceProperty(proto, _attr);
+ }
+ };
+
+ /**
+ * @param {Object} proto
+ * @param {metamodel.Attribute} attribute
+ */
+
+
+ Enhancer.prototype.enhanceProperty = function enhanceProperty(proto, attribute) {
+ var name = '$' + attribute.name;
+ Object.defineProperty(proto, attribute.name, {
+ get: function get() {
+ var metadata = this._metadata;
+ metadata.readAccess();
+ return metadata[name];
+ },
+ set: function set(value) {
+ var metadata = this._metadata;
+ metadata.writeAccess();
+ metadata[name] = value;
+ },
+
+ configurable: true,
+ enumerable: true
+ });
+ };
+
+ return Enhancer;
+}();
+
+module.exports = Enhancer;
+
+},{"61":61,"63":63}],10:[function(_dereq_,module,exports){
+"use strict";
+
+var Managed = _dereq_(15);
+
+/**
+ * @alias binding.Entity
+ * @extends binding.Managed
+ */
+
+var Entity = function (_Managed) {
+ babelHelpers.inherits(Entity, _Managed);
+
+ /**
+ * The default constructor, copy all given properties to this object
+ * @param {Object=} properties - The optional properties to copy
+ */
+ function Entity(properties) {
+ babelHelpers.classCallCheck(this, Entity);
+ return babelHelpers.possibleConstructorReturn(this, _Managed.call(this, properties));
+ }
+
+ return Entity;
+}(Managed);
+
+Object.defineProperties(Entity.prototype, /** @lends binding.Entity.prototype */{
+ /**
+ * The unique id of this object
+ *
+ * Sets the unique id of this object, if the id is not formatted as an valid id,
+ * it will be used as the key component of the id has the same affect as setting the key
+ *
+ * @type string
+ */
+ id: {
+ get: function get() {
+ return this._metadata.id;
+ },
+ set: function set(value) {
+ if (this._metadata.id) throw new Error('The id can\'t be set twice: ' + value);
+
+ value += '';
+ if (value.indexOf('/db/' + this._metadata.bucket + '/') == 0) {
+ this._metadata.id = value;
+ } else {
+ this.key = value;
+ }
+ },
+
+ enumerable: true
+ },
+
+ /**
+ * The unique key part of the id
+ * When the key of the unique id is set an error will be thrown if an id is already set.
+ * @type string
+ */
+ key: {
+ get: function get() {
+ return this._metadata.key;
+ },
+ set: function set(value) {
+ this._metadata.key = value;
+ }
+ },
+
+ /**
+ * The version of this object
+ * @type number
+ */
+ version: {
+ get: function get() {
+ return this._metadata.version;
+ },
+
+ enumerable: true
+ },
+
+ /**
+ * The object read/write permissions
+ * @type Acl
+ */
+ acl: {
+ get: function get() {
+ return this._metadata.acl;
+ },
+
+ enumerable: true
+ },
+
+ /**
+ * Waits on the previously requested operation and calls the doneCallback if the operation is fulfilled
+ * @param {util.Lockable~callback=} doneCallback The callback which will be invoked when the previously
+ * operations on this object is completed.
+ * @return {Promise} A promise which completes successfully, when the previously requested
+ * operation completes
+ * @method
+ */
+ ready: {
+ value: function ready(doneCallback) {
+ return this._metadata.ready(doneCallback);
+ }
+ },
+
+ /**
+ * Attach this object to the given db
+ * @param {EntityManager} db The db which will be used for future crud operations
+ * @method
+ */
+ attach: {
+ value: function attach(db) {
+ db.attach(this);
+ }
+ },
+
+ /**
+ * Saves the object. Inserts the object if it doesn't exists and updates the object if the object exist.
+ * @param {Object} [options] The save options
+ * @param {boolean} [options.force=false] Force the save operation, the version will not be validated.
+ * @param {number|boolean} [options.depth=0] The object depth which will be saved. Depth 0 save this object only,
+ *