angular-cached-resource
Version:
An AngularJS module to interact with RESTful resources, even when browser is offline
146 lines (114 loc) • 5.3 kB
text/coffeescript
DEFAULT_ACTIONS =
get: { method: 'GET', }
query: { method: 'GET', isArray: yes }
save: { method: 'POST', }
remove: { method: 'DELETE', }
delete: { method: 'DELETE', }
readArrayCache = require './read_array_cache'
readCache = require './read_cache'
writeCache = require './write_cache'
module.exports = buildCachedResourceClass = ($resource, $timeout, $q, providerParams, args) ->
{$log} = providerParams
ResourceCacheEntry = require('./resource_cache_entry')(providerParams)
ResourceCacheArrayEntry = require('./resource_cache_array_entry')(providerParams)
ResourceWriteQueue = require('./resource_write_queue')(providerParams, $q)
Cache = require('./cache')(providerParams)
$key = args.shift()
url = args.shift()
while args.length
arg = args.pop()
if angular.isObject(arg[Object.keys(arg)[0]])
actions = arg
else
paramDefaults = arg
actions = angular.extend({}, DEFAULT_ACTIONS, actions)
paramDefaults ?= {}
boundParams = {}
for param, paramDefault of paramDefaults when paramDefault[0] is '@'
boundParams[paramDefault.substr(1)] = param
Resource = $resource.call(null, url, paramDefaults, actions)
isPermissibleBoundValue = (value) ->
angular.isDate(value) or angular.isNumber(value) or angular.isString(value)
class CachedResource
$cache: true # right now this is just a flag, eventually it could be useful for cache introspection (see https://github.com/goodeggs/angular-cached-resource/issues/8)
constructor: (attrs) ->
angular.extend @, attrs
toJSON: ->
data = angular.extend {}, @
delete data.$promise
delete data.$httpPromise
data
$params: ->
params = {}
for attribute, param of boundParams when isPermissibleBoundValue @[attribute]
params[param] = @[attribute]
params
$$addToCache: (dirty = false) ->
entry = new ResourceCacheEntry($key, @$params())
entry.set @, dirty
@
@$clearCache: ({where, exceptFor, clearPendingWrites, isArray, clearChildren} = {}) ->
where ?= null
exceptFor ?= null
clearPendingWrites ?= false
isArray ?= false
clearChildren ?= false
return $log.error "Using where and exceptFor arguments at once in $clearCache() method is forbidden!" if where && exceptFor
cacheKeys = []
translateParamsArrayToEntries = (entries) ->
entries ||= []
# Translate where and exceptFor objects to array of objects.
# f.e. `{where: {id: 2}}` to `{where: [{id: 2}]}`
entries = [entries] unless angular.isArray(entries)
entries.map (entry) ->
new CachedResource(entry).$params()
translateEntriesToCacheKeys = (params_objects) ->
params_objects.map (params) ->
new ResourceCacheEntry($key, params).fullCacheKey()
translateParamsArrayToCacheKeys = (entries) ->
translateEntriesToCacheKeys translateParamsArrayToEntries entries
if exceptFor || where
if isArray
cacheArrayEntry = new ResourceCacheArrayEntry($key, exceptFor || where).load()
cacheKeys.push cacheArrayEntry.fullCacheKey()
if cacheArrayEntry.value && ((exceptFor && !clearChildren) || (where && clearChildren))
entries = (params for params in cacheArrayEntry.value)
cacheKeys = cacheKeys.concat(translateEntriesToCacheKeys(entries)) if entries
else
cacheKeys = translateParamsArrayToCacheKeys(where || exceptFor)
if !clearPendingWrites && !where
{queue, key} = CachedResource.$writes
cacheKeys.push key
entries = queue.map (resource) -> resource.resourceParams
cacheKeys = cacheKeys.concat translateEntriesToCacheKeys(entries)
else if clearPendingWrites && where
$log.debug "TODO if clearPendingWrites && where"
# TODO clear only those writes, which match :where parameter
if where
Cache.clear {key: $key, where: cacheKeys}
else
Cache.clear {key: $key, exceptFor: cacheKeys}
@$addToCache: (attrs, dirty) ->
new CachedResource(attrs).$$addToCache(dirty)
@$addArrayToCache: (attrs, instances, dirty = false) ->
instances = instances.map (instance) ->
new CachedResource(instance)
new ResourceCacheArrayEntry($key, attrs).addInstances instances, dirty
@$resource: Resource
@$key: $key
CachedResource.$writes = new ResourceWriteQueue(CachedResource, $timeout)
for actionName, actionConfig of actions
method = actionConfig.method.toUpperCase()
unless actionConfig.cache is false
handler = if method is 'GET' and actionConfig.isArray
readArrayCache($q, providerParams, actionName, CachedResource, actionConfig)
else if method is 'GET'
readCache($q, providerParams, actionName, CachedResource, actionConfig)
else if method in ['POST', 'PUT', 'DELETE', 'PATCH']
writeCache($q, providerParams, actionName, CachedResource, actionConfig)
CachedResource[actionName] = handler
CachedResource::["$#{actionName}"] = handler unless method is 'GET'
else
CachedResource[actionName] = Resource[actionName]
CachedResource::["$#{actionName}"] = Resource::["$#{actionName}"]
CachedResource