UNPKG

@type-r/models

Version:

The serializable type system for JS and TypeScript

115 lines (90 loc) 3.5 kB
export interface IONode { /** @internal */ _endpoint : IOEndpoint /** @internal */ _ioPromise : IOPromise< this > } export interface IOPromise<T> extends Promise<T> { abort? : () => void } export interface IOEndpoint { list( options : IOOptions, collection? ) : IOPromise<any> create( json : any, options : IOOptions, record? ) : IOPromise<any> update( id : string | number, json :any, options : IOOptions, record? ) : IOPromise<any> read( id : string | number, options : IOOptions, record? ) : IOPromise<any> destroy( id : string | number, options : IOOptions, record? ) : IOPromise<any> subscribe( events : IOEvents, collection? ) : IOPromise<any> unsubscribe( events : IOEvents, collection? ) : void } export interface IOOptions { ioMethod? : 'save' | 'fetch' } export interface IOEvents { updated? : ( json : any ) => void removed? : ( json : any ) => void } export function getOwnerEndpoint( self ) : IOEndpoint { // Check if we are the member of the collection... const { collection } = self; if( collection ){ return getOwnerEndpoint( collection ); } // Now, if we're the member of the model... if( self._owner ){ const { _endpoints } = self._owner; return _endpoints && _endpoints[ self._ownerKey ]; } } /** * Create abortable promise. * Adds `promise.abort()` function which rejects the promise by default * initialize() function takes third optional argument `abort : ( resolve, reject ) => void`, * which can be used to add custom abort handling. */ declare var Promise: PromiseConstructorLike; export function createIOPromise( initialize : InitIOPromise ) : IOPromise<any>{ let resolve, reject, onAbort; function abort( fn ){ onAbort = fn; } const promise : IOPromise<any> = new Promise( ( a_resolve, a_reject ) =>{ reject = a_reject; resolve = a_resolve; initialize( resolve, reject, abort ); }) as IOPromise<any>; promise.abort = () => { onAbort ? onAbort( resolve, reject ) : reject( new Error( "I/O Aborted" ) ); } return promise; } export type InitIOPromise = ( resolve : ( x? : any ) => void, reject : ( x? : any ) => void, abort? : ( fn : Function ) => void ) => void; export function startIO( self : IONode, promise : IOPromise<any>, options : IOOptions, thenDo : ( json : any ) => any ) : IOPromise<any> { // Stop pending I/O first... abortIO( self ); self._ioPromise = promise .then( resp => { self._ioPromise = null; const result = thenDo ? thenDo( resp ) : resp; triggerAndBubble( self, 'sync', self, resp, options ); return result; } ) .catch( err => { self._ioPromise = null; // Overlaps with a new `error` event. triggerAndBubble( self, 'error', self, err, options ); throw err; } ) as IOPromise<any>; self._ioPromise.abort = promise.abort; return self._ioPromise; } export function abortIO( self : IONode ){ if( self._ioPromise && self._ioPromise.abort ){ self._ioPromise.abort(); self._ioPromise = null; } } export function triggerAndBubble( eventSource, ...args ){ eventSource.trigger.apply( eventSource, args ); const { collection } = eventSource; collection && collection.trigger.apply( collection, args ); }