type-r
Version:
Serializable, validated, and observable data layer for modern JS applications
69 lines (54 loc) • 2.37 kB
text/typescript
import { AnyType, ChainableAttributeSpec, Record } from '../record';
import { CollectionReference, parseReference } from './commons';
/********
* Reference to model by id.
*
* Untyped attribute. Holds model id, when unresolved. When resolved, is substituted
* with a real model.
*
* No model changes are detected and counted as owner's change. That's intentional.
*/
/** @private */
type RecordRefValue = Record | string;
/** @private */
class RecordRefType extends AnyType {
// It is always serialized as an id, whenever it's resolved or not.
toJSON( value : RecordRefValue ){
return value && typeof value === 'object' ? value.id : value;
}
// Wne
clone( value : RecordRefValue ){
return value && typeof value === 'object' ? value.id : value;
}
// Model refs by id are equal when their ids are equal.
isChanged( a : RecordRefValue, b : RecordRefValue){
var aId = a && ( (<Record>a).id == null ? a : (<Record>a).id ),
bId = b && ( (<Record>b).id == null ? b : (<Record>b).id );
return aId !== bId;
}
// Refs are always valid.
validate( model, value, name ){}
}
export function memberOf<R extends typeof Record>( this : void, masterCollection : CollectionReference, T? : R ) : ChainableAttributeSpec<R> {
const getMasterCollection = parseReference( masterCollection );
const typeSpec = new ChainableAttributeSpec<R>({
value : null,
_metatype : RecordRefType
});
return typeSpec
.get( function( objOrId : RecordRefValue, name : string ) : Record {
if( typeof objOrId === 'object' ) return objOrId;
// So, we're dealing with an id reference. Resolve it.
const collection = getMasterCollection( this );
let record : Record = null;
// If master collection exists and is not empty...
if( collection && collection.length ){
// Silently update attribute with record from this collection.
record = collection.get( objOrId ) || null;
this.attributes[ name ] = record;
// Subscribe for events manually. delegateEvents won't be invoked.
record && this._attributes[ name ].handleChange( record, null, this, {} );
}
return record;
});
}