Home Reference Source Repository

src/TransientProperty.js

import { assert } from "akutils";

import ObjectProperty from "./ObjectProperty";
import PrimitiveProperty from "./PrimitiveProperty";
import Shadow from "./Shadow";
import StateType from "./StateType";

import appDebug, { TransientKey as DebugKey } from "./debug";
const debug = appDebug(DebugKey);


const _data = "data";
const _desc = Symbol('desc');
const _id = "id";
const _lockId = Symbol('lockId');
const _locks = Symbol('locks');
const _subscribers = Symbol('subscribers');
const _trans = Symbol('trans');
const _transId = Symbol('id');
//const PrimaryLockName = "__primary__";

var nextLockId = 1;


export class TransientLock {
	constructor(id, desc, trans) {
		this[_lockId] = id;
		this[_desc] = desc;
		this[_trans] = trans;
	}

	desc() {
		return this[_desc];
	}

	id() {
		return this[_lockId];
	}

	is(desc) {
		return this[_desc] === desc;
	}

	release() {
		this[_trans]._removeLock(this);
	}

	trans() {
		return this[_trans];
	}
}


export class TransientShadow extends Shadow {
	delete() {
		const transRoot = this.$$().parent()._();

		transRoot.delete(this.id);
	}

	isLocked() {
		return this.$$().isLocked();
	}

	lock(desc) {
		return this.$$().lock(desc);
	}
}

/*

*/
export default class TransientProperty extends ObjectProperty {
	constructor(id, property) {
		super();

		this._keyed.addProperty(_data, property);
		this._keyed.set(_id,  id);

		this.setShadowClass(TransientShadow);
		this[_transId] = id;
		this[_locks] = [];

		debug( d => d(`TransientProperty created: id=${ id }`) );
	}

	propertyWillUnshadow() {
		delete this[_locks];

		debug( d => d(`propertyWillUnshadow(): id=${ this[_transId] }`) );
	}

	get id() {
		return this[_transId];
	}

	data() {
		const transObj = this._();

		return transObj && transObj.data;
	}

	isLocked() {
		return this[_locks] && this[_locks].length > 0;
	}

	lock(desc=`lock:${nextLockId}`) {
		return this._addLock(new TransientLock(nextLockId++, desc, this));
	}

	_removeLock(lock) {
		if (!this[_locks]) { return }

		this[_locks] = this[_locks].filter( l => l !== lock );
		debug( d => d(`_removeLock(): id=${ this[_transId] }, locked=${ this.isLocked() }, desc=${ lock.desc() }`) );
	}

	_addLock(lock) {
		assert( a => a.is(lock.trans() === this, "Lock transient object mismatch") );

		if (!this[_locks]) { return null }

		this[_locks].push(lock);
		debug( d => d(`_addLock(): id=${ this[_transId] }, desc=${ lock.desc() }`) );

		return lock;
	}
}


StateType.defineType(TransientProperty, spec => {
	spec.initialState({})
		.properties({
				[_id]: PrimitiveProperty.type,
			})
		.autoshadowOff
		.readonly
		.typeName("TransientProperty");
});