UNPKG

angular-cached-resource

Version:

An AngularJS module to interact with RESTful resources, even when browser is offline

134 lines (112 loc) 5.29 kB
CACHE_RETRY_TIMEOUT = 60000 # one minute module.exports = (providerParams, $q) -> {$log} = providerParams ResourceCacheEntry = require('./resource_cache_entry')(providerParams) Cache = require('./cache')(providerParams) # this could be a lot nicer with ES6 WeakMaps # (http://www.nczonline.net/blog/2014/01/21/private-instance-members-with-weakmaps-in-javascript/) # but till then this is to maintain private instance members flushQueueDeferreds = {} resetDeferred = (queue) -> deferred = $q.defer() flushQueueDeferreds[queue.key] = deferred queue.promise = deferred.promise deferred resolveDeferred = (queue) -> flushQueueDeferreds[queue.key].resolve() class ResourceWriteQueue logStatusOfRequest: (status, action, params, data) -> $log.debug("#{action} for #{@key} #{angular.toJson(params)} #{status} (queue length: #{@queue.length})", data) constructor: (@CachedResource, @$timeout) -> @key = "#{@CachedResource.$key}/write" @queue = Cache.getItem(@key, []) write.busy = false for write in @queue resetDeferred(@) if @queue.length is 0 resolveDeferred(@) # initialize the queue with a resolved promise enqueue: (params, resourceData, action, deferred) -> resetDeferred(@) if @queue.length is 0 resourceParams = if angular.isArray(resourceData) resourceData.map((resource) -> resource.$params()) else resourceData.$params() write = @findWrite {params, action} if not write? @queue.push {params, resourceParams, action, deferred} @_update() else write.deferred?.promise.then (response) -> deferred.resolve response write.deferred?.promise.catch (error) -> deferred.reject error @logStatusOfRequest('enqueued', action, params, resourceData) findWrite: ({action, params}) -> for write in @queue return write if action is write.action and angular.equals(params, write.params) removeWrite: ({action, params}) -> newQueue = [] for entry in @queue newQueue.push entry unless action is entry.action and angular.equals(params, entry.params) @queue = newQueue if @queue.length is 0 and @timeoutPromise @$timeout.cancel @timeoutPromise delete @timeoutPromise @_update() resolveDeferred @ if @queue.length is 0 flush: (done) -> @promise.then done if angular.isFunction(done) @_setFlushTimeout() @_processWrite(write) for write in @queue processResource: (params, done) -> notDone = true for write in @_writesForResource(params) @_processWrite write, => if notDone and @_writesForResource(params).length is 0 notDone = false done() _writesForResource: (params) -> # TODO FIX FIX FIXME this should compare against individual write.resourceParams, which could be a nested array write for write in @queue when angular.equals(params, write.params) _processWrite: (write, done) -> return if write.busy write.busy = true if angular.isArray(write.resourceParams) cacheEntries = write.resourceParams.map (resourceParams) => new ResourceCacheEntry(@CachedResource.$key, resourceParams).load() writeData = cacheEntries.map (cacheEntry) -> cacheEntry.value else cacheEntries = [new ResourceCacheEntry(@CachedResource.$key, write.resourceParams).load()] writeData = cacheEntries[0].value onSuccess = (value) => @removeWrite write write.deferred?.resolve value @logStatusOfRequest('succeeded', write.action, write.resourceParams, writeData) done() if angular.isFunction(done) onFailure = (error) => if error and error.status >= 400 and error.status < 500 @removeWrite write $log.error "#{write.action} to #{@CachedResource.$key} failed with error #{error.status}", { method: error.config.method, url: error.config.url, writeData } else write.busy = false @logStatusOfRequest("failed with error #{angular.toJson error}; still in queue", write.action, write.resourceParams, writeData) write.deferred?.reject error @CachedResource.$resource[write.action](write.params, writeData, onSuccess, onFailure).$promise.then (savedResources) => savedResources = if angular.isArray(savedResources) then savedResources else [savedResources] for resource in savedResources resourceInstance = new @CachedResource(resource) cacheEntry = new ResourceCacheEntry(@CachedResource.$key, resourceInstance.$params()).load() cacheEntry.set(resource, false) @logStatusOfRequest('processed', write.action, write.resourceParams, writeData) _setFlushTimeout: -> if @queue.length > 0 and not @timeoutPromise @timeoutPromise = @$timeout angular.bind(@, @flush), CACHE_RETRY_TIMEOUT @timeoutPromise.then => delete @timeoutPromise @_setFlushTimeout() _update: -> savableQueue = @queue.map (write) -> params: write.params resourceParams: write.resourceParams action: write.action Cache.setItem @key, savableQueue