UNPKG

@harishreddym/baqend

Version:

Baqend JavaScript SDK

307 lines (275 loc) 7.71 kB
'use strict'; const error = require('../error'); const Acl = require('../Acl'); const Lockable = require('./Lockable'); const deprecated = require('./deprecated'); /** * The Metadata instance tracks the state of an object and checks if the object state was changed since last * load/update. The metadata keeps therefore the state of: * - in which state the object currently is * - which db managed the instance * - the metadata of the object (id, version, bucket) * - which is the owning object (root object) of an embedded object * * {@link util.Metadata#get(object)} can be used on any managed object to retrieve the metadata of the root object * * @alias util.Metadata * @extends util.Lockable */ class Metadata extends Lockable { /** * Creates a metadata instance for the given type and object instance * * @param {metamodel.ManagedType} type The type of the object * @param {*} object The object instance of the type * @return {*} The created metadata for the object */ static create(type, object) { let meta; if (type.isEntity) { meta = new Metadata(object, type); } else if (type.isEmbeddable) { meta = { type, readAccess() { const metadata = this.root && this.root._metadata; if (metadata) { metadata.readAccess(); } }, writeAccess() { const metadata = this.root && this.root._metadata; if (metadata) { metadata.writeAccess(); } }, }; } else { throw new Error('Illegal type ' + type); } return meta; } /** * Returns the metadata of the managed object * @param {binding.Managed} managed * @return {util.Metadata} */ static get(managed) { return managed._metadata; } /** * @type EntityManager */ get db() { if (this.entityManager) { return this.entityManager; } this.entityManager = require('../baqend'); // eslint-disable-line global-require return this.entityManager; } /** * @param db {EntityManager} */ set db(db) { if (!this.entityManager) { this.entityManager = db; } else { throw new Error('DB has already been set.'); } } /** * @type string * @readonly */ get bucket() { return this.type.name; } /** * @type string * @readonly */ get key() { if (!this.decodedKey && this.id) { const index = this.id.lastIndexOf('/'); this.decodedKey = decodeURIComponent(this.id.substring(index + 1)); } return this.decodedKey; } /** * @param {string} value */ set key(value) { const val = value + ''; if (this.id) { throw new Error('The id can\'t be set twice.'); } this.id = '/db/' + this.bucket + '/' + encodeURIComponent(val); this.decodedKey = val; } /** * Indicates if this object already belongs to an db * <code>true</code> if this object belongs already to an db otherwise <code>false</code> * @type boolean * @readonly */ get isAttached() { return !!this.entityManager; } /** * Indicates if this object is represents a db object, but was not loaded up to now * @type boolean * @readonly */ get isAvailable() { return this.state > Metadata.Type.UNAVAILABLE; } /** * Indicates if this object represents the state of the db and was not modified in any manner * @type boolean * @readonly */ get isPersistent() { return this.state === Metadata.Type.PERSISTENT; } /** * Indicates that this object was modified and the object was not written back to the db * @type boolean * @readonly */ get isDirty() { return this.state === Metadata.Type.DIRTY; } /** * @param {binding.Entity} entity * @param {metamodel.ManagedType} type */ constructor(entity, type) { super(); /** * @type binding.Entity * @private */ this.root = entity; this.state = Metadata.Type.DIRTY; this.enabled = true; /** @type string */ this.id = null; /** @type number */ this.version = null; /** @type metamodel.ManagedType */ this.type = type; /** @type Acl */ this.acl = new Acl(this); } /** * Enable/Disable state change tracking of this object * @param {boolean} newStateTrackingState The new change tracking state * @return {void} */ enable(newStateTrackingState) { this.enabled = newStateTrackingState; } /** * Signals that the object will be accessed by a read * * Ensures that the object was loaded already. * * @return {void} */ readAccess() { if (this.enabled) { if (!this.isAvailable) { throw new error.PersistentError('This object ' + this.id + ' is not available.'); } } } /** * Signals that the object will be accessed by a write * * Ensures that the object was loaded already and marks the object as dirty. * * @return {void} */ writeAccess() { if (this.enabled) { if (!this.isAvailable) { throw new error.PersistentError('This object ' + this.id + ' is not available.'); } this.setDirty(); } } /** * Indicates that the associated object isn't available * @return {void} */ setUnavailable() { this.state = Metadata.Type.UNAVAILABLE; } /** * Indicates that the associated object is not stale * * An object is stale if it correlates the database state and is not modified by the user. * * @return {void} */ setPersistent() { this.state = Metadata.Type.PERSISTENT; } /** * Indicates the the object is modified by the user * @return {void} */ setDirty() { this.state = Metadata.Type.DIRTY; } /** * Indicates the the object is removed * @return {void} */ setRemoved() { // mark the object only as dirty if it was already available if (this.isAvailable) { this.setDirty(); this.version = null; } } /** * Converts the object to an JSON-Object * @param {Object|boolean} [options=false] to json options by default excludes the metadata * @param {boolean} [options.excludeMetadata=false] Excludes the metadata form the serialized json * @param {number} [options.depth=0] Includes up to depth referenced objects into the serialized json * @param {boolean} [options.persisting=false] indicates if the current state will be persisted. * Used to update the internal change tracking state of collections and mark the object persistent if its true * @return {json} JSON-Object * @deprecated */ getJson(options) { return this.type.toJsonValue(this, this.root, options); } /** * Sets the object content from json * @param {json} json The updated json content * @param {Object=} options The options used to apply the json * @param {boolean} [options.persisting=false] indicates if the current state will be persisted. * Used to update the internal change tracking state of collections and mark the object persistent or dirty afterwards * @param {boolean} [options.onlyMetadata=false} Indicates if only the metadata should be updated * @param {boolean} {options.updateMetadataOnly=false} Indicates if only the metadata should be updated * @return {void} * @deprecated */ setJson(json, options) { this.type.fromJsonValue(this, json, this.root, options); } } /** * @enum {number} */ Metadata.Type = { UNAVAILABLE: -1, PERSISTENT: 0, DIRTY: 1, }; deprecated(Metadata.prototype, '_root', 'root'); deprecated(Metadata.prototype, '_state', 'state'); deprecated(Metadata.prototype, '_enabled', 'enabled'); module.exports = Metadata;