{"version":3,"sources":["../ts/modules/caching.ts"],"names":["isPromiseLike","foo","then","isStorage","Object","getPrototypeOf","setItem","DeferredPromise","constructor","this","promise","Promise","resolve","reject","wrap","promiselike","retval","value","err","exports","LookupCache","fn","backingCache","SimpleCache","get","key","containsKey","set","keys","clear","unset","LookupCacheAsyncImpl","pendingCache","getMissingValue","let","pending","undefined","realizeValue","pendingValue","backingKeys","pendingKeys","concat","pendingKey","deferredPromise","LookupCacheAsync","super","BatchedLookupCacheAsync","batch","Array","from","param","deferCount","deferreds","defer","getBatch","fetch","setTimeout","deferredPromises","length","push","results","arr","process","forEach","result","StorageCache","storage","namespace","keySerializationStrategy","serialization_1","JsonSerializationStrategy","valueSerializationStrategy","IdentitySerializationStrategy","cacheKey","getCacheKey","removeItem","serializedValue","serialize","deserialize","getItem","allKeys","prefix","prefixLength","filter","startsWith","map","substring","s","suffix","LocalStorageCache","localStorage","SessionStorageCache","sessionStorage","Lazy","getter","getterParams","_hasValue","_getter","_getterParams","_value","apply","hasValue"],"mappings":"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","file":"caching.js","sourcesContent":["import { ISerializationStrategy, IdentitySerializationStrategy, JsonSerializationStrategy } from 'serialization';\r\n\r\nfunction isPromiseLike( foo: any ): foo is PromiseLike {\r\n\treturn foo && typeof foo.then === 'function';\r\n}\r\n\r\nfunction isStorage( foo: any ): foo is Storage {\r\n\tconst proto = Object.getPrototypeOf( foo );\r\n\treturn typeof proto.setItem !== 'undefined';\r\n}\r\n\r\nexport type CacheStore = IDictionary|Storage;\r\n\r\nexport interface ICacheSet {\r\n\tset( key: CacheKey, value: T );\r\n\tunset( key: CacheKey );\r\n\tclear();\r\n}\r\n\r\nexport interface ICacheGet {\r\n\tget( key: CacheKey ): T;\r\n\tcontainsKey( key: CacheKey ): boolean;\r\n\tkeys?: Array;\r\n}\r\n\r\nexport interface ICache extends ICacheGet, ICacheSet {}\r\nexport interface ICacheSetAsync extends ICacheSet> {}\r\nexport interface ICacheGetAsync extends ICacheGet> {}\r\nexport interface ICacheAsync extends ICacheGetAsync, ICacheSetAsync {}\r\nexport interface IBatchedCacheAsync extends ICacheAsync {\r\n\tgetBatch( keys: ArrayLike ): Array>;\r\n\tdefer(): void;\r\n\tfetch(): void;\r\n}\r\n\r\n// TODO: move someplace more accessible\r\nclass DeferredPromise {\r\n\tconstructor() {\r\n\t\tthis.promise = new Promise( ( resolve, reject ) => {\r\n\t\t\tthis.resolve = resolve;\r\n\t\t\tthis.reject = reject;\r\n\t\t} );\r\n\t}\r\n\r\n\tpublic promise: Promise;\r\n\tpublic resolve: ( value?: T|PromiseLike ) => void;\r\n\tpublic reject: ( err?: T ) => void;\r\n\r\n\tpublic static wrap( promiselike: T|PromiseLike ) {\r\n\t\tconst retval = new DeferredPromise();\r\n\t\tPromise.resolve( promiselike ).then( value => { retval.resolve( value ); }, err => { retval.reject( err ); } );\r\n\t\treturn retval;\r\n\t}\r\n}\r\n\r\nexport class LookupCache implements ICache {\r\n\tconstructor( fn: ( param: CacheKey ) => T, backingCache: ICache = new SimpleCache() ) {\r\n\t\tthis.fn = fn;\r\n\t\tthis.backingCache = backingCache;\r\n\t}\r\n\r\n\tpublic get( key: CacheKey ): T {\r\n\t\tif( !this.backingCache.containsKey( key ) ) {\r\n\t\t\tthis.backingCache.set( key, this.fn( key ) );\r\n\t\t}\r\n\t\treturn this.backingCache.get( key );\r\n\t}\r\n\r\n\tpublic get keys() {\r\n\t\treturn this.backingCache.keys;\r\n\t}\r\n\r\n\tpublic containsKey( key: CacheKey ) {\r\n\t\treturn this.backingCache.containsKey( key );\r\n\t}\r\n\r\n\tpublic clear() {\r\n\t\tthis.backingCache.clear();\r\n\t}\r\n\r\n\tpublic set( key: CacheKey, value: T ) {\r\n\t\tthis.backingCache.set( key, value );\r\n\t}\r\n\r\n\tpublic unset( key: CacheKey ) {\r\n\t\tthis.backingCache.unset( key );\r\n\t}\r\n\r\n\tprivate fn: ( param: CacheKey ) => T;\r\n\tprotected backingCache: ICache;\r\n}\r\n\r\nexport abstract class LookupCacheAsyncImpl implements ICacheAsync {\r\n\tconstructor( backingCache: ICache = new SimpleCache() ) {\r\n\t\tthis.backingCache = backingCache;\r\n\t}\r\n\r\n\tpublic get( key: CacheKey ): Promise {\r\n\t\tif( this.backingCache.containsKey( key ) ) {\r\n\t\t\treturn Promise.resolve( this.backingCache.get( key ) );\r\n\t\t}\r\n\t\tconst getMissingValue = () => Promise.resolve( this.getMissingValue( key ) );\r\n\t\tlet pending = this.pendingCache.get( key ),\r\n\t\t\tpromiselike: PromiseLike;\r\n\t\tif( pending ) {\r\n\t\t\tpromiselike = Promise.resolve( pending.promise.then( undefined, getMissingValue ) );\r\n\t\t} else {\r\n\t\t\tpromiselike = getMissingValue();\r\n\t\t}\r\n\t\tpromiselike = Promise.resolve( promiselike.then( value => this.realizeValue( key, value ) ) );\r\n\t\treturn this.pendingValue( key, promiselike );\r\n\t}\r\n\r\n\tpublic containsKey( key: CacheKey ) {\r\n\t\treturn this.backingCache.containsKey( key ) || this.pendingCache.containsKey( key );\r\n\t}\r\n\r\n\tpublic get keys() {\r\n\t\tconst backingKeys = this.backingCache.keys,\r\n\t\t\tpendingKeys = this.pendingCache.keys;\r\n\t\tif( !backingKeys && !pendingKeys ) return undefined;\r\n\t\treturn ([]).concat( backingKeys || [] ).concat( pendingKeys || [] );\r\n\t}\r\n\r\n\tpublic clear() {\r\n\t\tconst pendingKeys = this.pendingCache.keys;\r\n\t\tif( pendingKeys ) for( let pendingKey of pendingKeys ) {\r\n\t\t\tthis.unset( pendingKey );\r\n\t\t}\r\n\t\tthis.pendingCache.clear();\r\n\t\tthis.backingCache.clear();\r\n\t}\r\n\r\n\tprotected abstract getMissingValue( key: CacheKey ): PromiseLike;\r\n\r\n\tprotected pendingValue( key: CacheKey, value: PromiseLike ) {\r\n\t\tthis.backingCache.unset( key );\r\n\t\tconst deferredPromise = DeferredPromise.wrap( value );\r\n\t\t\r\n\t\tconst pending = this.pendingCache.get( key );\r\n\t\tif( pending ) {\r\n\t\t\tpending.resolve( deferredPromise.promise );\r\n\t\t} else {\r\n\t\t\tdeferredPromise.promise.then( value => this.realizeValue( key, value ) );\r\n\t\t}\r\n\t\tthis.pendingCache.set( key, deferredPromise );\r\n\r\n\t\treturn deferredPromise.promise;\r\n\t}\r\n\r\n\tprotected realizeValue( key: CacheKey, value: T ) {\r\n\t\tconst deferredPromise = this.pendingCache.get( key );\r\n\t\tif( deferredPromise ) {\r\n\t\t\tdeferredPromise.resolve( value );\r\n\t\t\tthis.pendingCache.unset( key );\r\n\t\t}\r\n\t\tthis.backingCache.set( key, value );\r\n\t\treturn value;\r\n\t}\r\n\r\n\tpublic set( key: CacheKey, value: T|PromiseLike ) {\r\n\t\tif( isPromiseLike( value ) ) {\r\n\t\t\tthis.pendingValue( key, value );\r\n\t\t} else {\r\n\t\t\tthis.realizeValue( key, value );\r\n\t\t}\r\n\t}\r\n\r\n\tpublic unset( key: CacheKey ) {\r\n\t\tconst pending = this.pendingCache.get( key );\r\n\t\tif( pending ) pending.reject();\r\n\t\tthis.pendingCache.unset( key );\r\n\t\tthis.backingCache.unset( key );\r\n\t}\r\n\r\n\tprivate backingCache: ICache;\r\n\tprivate pendingCache = new SimpleCache>();\r\n}\r\n\r\nexport class LookupCacheAsync extends LookupCacheAsyncImpl implements ICacheAsync {\r\n\tconstructor( fn: ( param: CacheKey ) => T|PromiseLike, backingCache?: ICache ) {\r\n\t\tsuper( backingCache );\r\n\t\tthis.fn = fn;\r\n\t}\r\n\r\n\tprotected getMissingValue( key: CacheKey ) {\r\n\t\treturn Promise.resolve( this.fn( key ) );\r\n\t}\r\n\r\n\tprivate fn: ( param: CacheKey ) => T|PromiseLike;\r\n}\r\n\r\nexport class BatchedLookupCacheAsync extends LookupCacheAsyncImpl implements IBatchedCacheAsync {\r\n\tconstructor( private batch: ( param: Array ) => ArrayLike>|PromiseLike> = ( param ) => Array.from( param, () => Promise.reject( null ) ), backingCache?: ICache ) {\r\n\t\tsuper( backingCache );\r\n\t}\r\n\r\n\tprotected getMissingValue( key: CacheKey ) {\r\n\t\tlet deferredPromise = this.deferreds.get( key );\r\n\t\tif( !deferredPromise ) {\r\n\t\t\tdeferredPromise = new DeferredPromise();\r\n\t\t\tthis.deferreds.set( key, deferredPromise );\r\n\t\t}\r\n\t\tif( this.deferCount <= 0 ) {\r\n\t\t\tthis.resolve();\r\n\t\t}\r\n\t\treturn deferredPromise.promise;\r\n\t}\r\n\r\n\tprivate deferCount = 0;\r\n\tpublic defer() {\r\n\t\t++this.deferCount;\r\n\t}\r\n\r\n\tpublic getBatch( keys: ArrayLike ): Array> {\r\n\t\tthis.defer();\r\n\t\tconst retval = Array.from( keys, key => this.get( key ) );\r\n\t\tthis.fetch();\r\n\t\treturn retval;\r\n\t}\r\n\r\n\tpublic fetch() {\r\n\t\tif( this.deferCount > 0 ) {\r\n\t\t\tif( --this.deferCount > 0 ) return;\r\n\t\t}\r\n\t\tthis.deferCount = 0;\r\n\t\tthis.resolve();\r\n\t}\r\n\r\n\tpublic set( key: CacheKey, value: T|PromiseLike ) {\r\n\t\tconst { deferreds } = this,\r\n\t\t\tdeferredPromise = deferreds.get( key );\r\n\t\tif( deferredPromise ) {\r\n\t\t\tdeferredPromise.resolve( value );\r\n\t\t\tdeferreds.unset( key );\r\n\t\t}\r\n\t\tsuper.set( key, value );\r\n\t}\r\n\r\n\tpublic unset( key: CacheKey ) {\r\n\t\tconst { deferreds } = this,\r\n\t\t\tdeferredPromise = deferreds.get( key );\r\n\t\tif( deferredPromise ) {\r\n\t\t\tdeferredPromise.reject();\r\n\t\t\tdeferreds.unset( key );\r\n\t\t}\r\n\t\tsuper.unset( key );\r\n\t}\r\n\r\n\tpublic clear() {\r\n\t\tconst { deferreds } = this,\r\n\t\t\t{ keys } = deferreds;\r\n\t\tfor( let key of keys ) {\r\n\t\t\tdeferreds.get( key ).reject();\r\n\t\t\tdeferreds.unset( key );\r\n\t\t}\r\n\t\tsuper.clear();\r\n\t}\r\n\r\n\tprivate resolve() {\r\n\t\tsetTimeout( () => {\r\n\t\t\tconst { deferreds } = this,\r\n\t\t\t\t{ keys } = deferreds,\r\n\t\t\t\tdeferredPromises = [];\r\n\t\t\tif( keys.length <= 0 ) return;\r\n\r\n\t\t\tfunction process( results: ArrayLike> ) {\r\n\t\t\t\tArray.from( results ).forEach( ( result, key ) => {\r\n\t\t\t\t\tconst deferredPromise = deferredPromises[ key ];\r\n\t\t\t\t\tdeferredPromise.resolve( result );\r\n\t\t\t\t} );\r\n\t\t\t}\r\n\r\n\t\t\tfor( let key of keys ) {\r\n\t\t\t\tdeferredPromises.push( deferreds.get( key ) );\r\n\t\t\t\tdeferreds.unset( key );\r\n\t\t\t}\r\n\t\t\tconst results = this.batch( Array.from( keys ) );\r\n\t\t\tif( isPromiseLike>( results ) ) {\r\n\t\t\t\tresults.then( arr => process( arr ) );\r\n\t\t\t} else {\r\n\t\t\t\tprocess( results );\r\n\t\t\t}\r\n\t\t}, 0 );\r\n\t}\r\n\r\n\tprivate deferreds = new SimpleCache>();\r\n}\r\n\r\nexport class StorageCache implements ICache {\r\n\tconstructor( storage: IDictionary|Storage, namespace?: string ) {\r\n\t\tthis.namespace = namespace || '';\r\n\t\tthis.storage = storage;\r\n\t}\r\n\r\n\tpublic unset( key: CacheKey ) {\r\n\t\tconst cacheKey = this.getCacheKey( key ),\r\n\t\t\tstorage = this.storage;\r\n\t\tif( isStorage( storage ) ) {\r\n\t\t\tstorage.removeItem( cacheKey );\r\n\t\t} else {\r\n\t\t\treturn delete this.storage[ cacheKey ];\r\n\t\t}\r\n\t}\r\n\r\n\tpublic set( key: CacheKey, value: T ) {\r\n\t\tconst cacheKey = this.getCacheKey( key ),\r\n\t\t\tserializedValue = this.valueSerializationStrategy.serialize( value ),\r\n\t\t\tstorage = this.storage;\r\n\t\tif( isStorage( storage ) ) {\r\n\t\t\tstorage.setItem( cacheKey, serializedValue );\r\n\t\t} else {\r\n\t\t\tthis.storage[ cacheKey ] = serializedValue;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get( key: CacheKey ): T {\r\n\t\tconst cacheKey = this.getCacheKey( key ),\r\n\t\t\tstorage = this.storage;\r\n\t\tif( isStorage( storage ) ) {\r\n\t\t\treturn this.valueSerializationStrategy.deserialize( storage.getItem( cacheKey ) );\r\n\t\t} else {\r\n\t\t\treturn this.valueSerializationStrategy.deserialize( this.storage[ cacheKey ] );\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get keys() {\r\n\t\tconst namespace = this.namespace;\r\n\t\tlet allKeys = Object.keys( this.storage );\r\n\t\t\t\r\n\t\tif( namespace ) {\r\n\t\t\tconst prefix = `${namespace}$`,\r\n\t\t\t\tprefixLength = prefix.length;\r\n\t\t\tallKeys = allKeys.filter( key => key.startsWith( prefix ) ).map( key => key.substring( prefixLength ) );\r\n\t\t}\r\n\r\n\t\treturn allKeys.map( s => this.keySerializationStrategy.deserialize( s ) );\r\n\t}\r\n\r\n\tpublic containsKey( key: CacheKey ) {\r\n\t\treturn this.getCacheKey( key ) in this.storage;\r\n\t}\r\n\r\n\tpublic clear() {\r\n\t\tfor( let key of Array.from( this.keys ) ) {\r\n\t\t\tthis.unset( key );\r\n\t\t}\r\n\t}\r\n\r\n\tprotected getCacheKey( key: CacheKey ) {\r\n\t\tconst { namespace } = this,\r\n\t\t\tsuffix = this.keySerializationStrategy.serialize( key );\r\n\t\tif( namespace ) {\r\n\t\t\treturn `${namespace}$${suffix}`;\r\n\t\t} else {\r\n\t\t\treturn suffix;\r\n\t\t}\r\n\t}\r\n\r\n\tprotected keySerializationStrategy: ISerializationStrategy = new JsonSerializationStrategy();\r\n\tprotected valueSerializationStrategy: ISerializationStrategy = new IdentitySerializationStrategy();\r\n\tprotected namespace: string;\r\n\tprotected storage: CacheStore;\r\n}\r\n\r\nexport class SimpleCache extends StorageCache {\r\n\tconstructor() {\r\n\t\tsuper( {} );\r\n\t}\r\n}\r\n\r\nexport class LocalStorageCache extends StorageCache {\r\n\tconstructor( namespace?: string ) {\r\n\t\tsuper( localStorage || {}, namespace );\r\n\t}\r\n\r\n\tprotected valueSerializationStrategy: ISerializationStrategy = new JsonSerializationStrategy();\r\n}\r\n\r\nexport class SessionStorageCache extends StorageCache {\r\n\tconstructor( namespace?: string ) {\r\n\t\tsuper( sessionStorage || {}, namespace );\r\n\t}\r\n\r\n\tprotected valueSerializationStrategy: ISerializationStrategy = new JsonSerializationStrategy();\r\n}\r\n\r\nexport class Lazy {\r\n\tconstructor( getter: ( ...args: Array ) => T, ...getterParams: Array ) {\r\n\t\tthis._getter = getter;\r\n\t\tthis._getterParams = getterParams;\r\n\t}\r\n\r\n\tpublic get value() {\r\n\t\tif( !this._hasValue ) {\r\n\t\t\tthis._value = this._getter.apply( this, this._getterParams );\r\n\t\t\tdelete this._getterParams;\r\n\t\t\tthis._hasValue = true;\r\n\t\t}\r\n\t\treturn this._value;\r\n\t}\r\n\r\n\tpublic get hasValue() {\r\n\t\treturn this._hasValue;\r\n\t}\r\n\r\n\tprivate _getter: () => T;\r\n\tprivate _getterParams: Array;\r\n\tprivate _value: T;\r\n\tprivate _hasValue = false;\r\n}\r\n"]}