angular-data-localforage
Advanced tools
Comparing version 0.1.0 to 1.0.0
@@ -5,7 +5,6 @@ { | ||
"description": "localForage adapter for angular-data.", | ||
"version": "0.1.0", | ||
"homepage": "https://github.com/jmdobry/angular-data-localForage/", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/jmdobry/angular-data-localForage.git" | ||
"url": "https://github.com/jmdobry/angular-data-localForage.git" | ||
}, | ||
@@ -32,6 +31,8 @@ "main": "./dist/angular-data-localForage.min.js", | ||
"angular-mocks": "~1.2.16", | ||
"angular-data": "~0.8.1", | ||
"angular-cache": "~3.0.0-beta.4", | ||
"localforage": "~0.8.1" | ||
"localforage": "~0.9.x" | ||
}, | ||
"dependencies": { | ||
"angular": "~1.x.x", | ||
"angular-data": "~1.x.x" | ||
} | ||
} |
@@ -0,3 +1,8 @@ | ||
##### 1.0.0 - 14 December 2014 | ||
- Updated dependencies | ||
- Added support for collections | ||
##### 0.1.0 - 17 May 2014 | ||
Initial Release |
@@ -0,5 +1,188 @@ | ||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.DSLocalForageAdapter=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
var isKind = require('./isKind'); | ||
/** | ||
*/ | ||
var isArray = Array.isArray || function (val) { | ||
return isKind(val, 'Array'); | ||
}; | ||
module.exports = isArray; | ||
},{"./isKind":2}],2:[function(require,module,exports){ | ||
var kindOf = require('./kindOf'); | ||
/** | ||
* Check if value is from a specific "kind". | ||
*/ | ||
function isKind(val, kind){ | ||
return kindOf(val) === kind; | ||
} | ||
module.exports = isKind; | ||
},{"./kindOf":3}],3:[function(require,module,exports){ | ||
var _rKind = /^\[object (.*)\]$/, | ||
_toString = Object.prototype.toString, | ||
UNDEF; | ||
/** | ||
* Gets the "kind" of value. (e.g. "String", "Number", etc) | ||
*/ | ||
function kindOf(val) { | ||
if (val === null) { | ||
return 'Null'; | ||
} else if (val === UNDEF) { | ||
return 'Undefined'; | ||
} else { | ||
return _rKind.exec( _toString.call(val) )[1]; | ||
} | ||
} | ||
module.exports = kindOf; | ||
},{}],4:[function(require,module,exports){ | ||
/** | ||
* @constant Maximum 32-bit signed integer value. (2^31 - 1) | ||
*/ | ||
module.exports = 2147483647; | ||
},{}],5:[function(require,module,exports){ | ||
/** | ||
* @constant Minimum 32-bit signed integer value (-2^31). | ||
*/ | ||
module.exports = -2147483648; | ||
},{}],6:[function(require,module,exports){ | ||
var randInt = require('./randInt'); | ||
var isArray = require('../lang/isArray'); | ||
/** | ||
* Returns a random element from the supplied arguments | ||
* or from the array (if single argument is an array). | ||
*/ | ||
function choice(items) { | ||
var target = (arguments.length === 1 && isArray(items))? items : arguments; | ||
return target[ randInt(0, target.length - 1) ]; | ||
} | ||
module.exports = choice; | ||
},{"../lang/isArray":1,"./randInt":10}],7:[function(require,module,exports){ | ||
var randHex = require('./randHex'); | ||
var choice = require('./choice'); | ||
/** | ||
* Returns pseudo-random guid (UUID v4) | ||
* IMPORTANT: it's not totally "safe" since randHex/choice uses Math.random | ||
* by default and sequences can be predicted in some cases. See the | ||
* "random/random" documentation for more info about it and how to replace | ||
* the default PRNG. | ||
*/ | ||
function guid() { | ||
return ( | ||
randHex(8)+'-'+ | ||
randHex(4)+'-'+ | ||
// v4 UUID always contain "4" at this position to specify it was | ||
// randomly generated | ||
'4' + randHex(3) +'-'+ | ||
// v4 UUID always contain chars [a,b,8,9] at this position | ||
choice(8, 9, 'a', 'b') + randHex(3)+'-'+ | ||
randHex(12) | ||
); | ||
} | ||
module.exports = guid; | ||
},{"./choice":6,"./randHex":9}],8:[function(require,module,exports){ | ||
var random = require('./random'); | ||
var MIN_INT = require('../number/MIN_INT'); | ||
var MAX_INT = require('../number/MAX_INT'); | ||
/** | ||
* Returns random number inside range | ||
*/ | ||
function rand(min, max){ | ||
min = min == null? MIN_INT : min; | ||
max = max == null? MAX_INT : max; | ||
return min + (max - min) * random(); | ||
} | ||
module.exports = rand; | ||
},{"../number/MAX_INT":4,"../number/MIN_INT":5,"./random":11}],9:[function(require,module,exports){ | ||
var choice = require('./choice'); | ||
var _chars = '0123456789abcdef'.split(''); | ||
/** | ||
* Returns a random hexadecimal string | ||
*/ | ||
function randHex(size){ | ||
size = size && size > 0? size : 6; | ||
var str = ''; | ||
while (size--) { | ||
str += choice(_chars); | ||
} | ||
return str; | ||
} | ||
module.exports = randHex; | ||
},{"./choice":6}],10:[function(require,module,exports){ | ||
var MIN_INT = require('../number/MIN_INT'); | ||
var MAX_INT = require('../number/MAX_INT'); | ||
var rand = require('./rand'); | ||
/** | ||
* Gets random integer inside range or snap to min/max values. | ||
*/ | ||
function randInt(min, max){ | ||
min = min == null? MIN_INT : ~~min; | ||
max = max == null? MAX_INT : ~~max; | ||
// can't be max + 0.5 otherwise it will round up if `rand` | ||
// returns `max` causing it to overflow range. | ||
// -0.5 and + 0.49 are required to avoid bias caused by rounding | ||
return Math.round( rand(min - 0.5, max + 0.499999999999) ); | ||
} | ||
module.exports = randInt; | ||
},{"../number/MAX_INT":4,"../number/MIN_INT":5,"./rand":8}],11:[function(require,module,exports){ | ||
/** | ||
* Just a wrapper to Math.random. No methods inside mout/random should call | ||
* Math.random() directly so we can inject the pseudo-random number | ||
* generator if needed (ie. in case we need a seeded random or a better | ||
* algorithm than the native one) | ||
*/ | ||
function random(){ | ||
return random.get(); | ||
} | ||
// we expose the method so it can be swapped if needed | ||
random.get = Math.random; | ||
module.exports = random; | ||
},{}],12:[function(require,module,exports){ | ||
var guid = require('mout/random/guid'); | ||
/** | ||
* @author Jason Dobry <jason.dobry@gmail.com> | ||
* @file angular-data-localforage.js | ||
* @version 0.1.0 - Homepage <https://github.com/jmdobry/angular-data-localForage/> | ||
* @version 1.0.0 - Homepage <https://github.com/jmdobry/angular-data-localForage/> | ||
* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/> | ||
@@ -11,165 +194,311 @@ * @license MIT <https://github.com/jmdobry/angular-data-localForage/blob/master/LICENSE> | ||
(function (window, angular, localforage, undefined) { | ||
'use strict'; | ||
'use strict'; | ||
localforage.config({ | ||
name: 'DS' | ||
}); | ||
localforage.config({ | ||
name: 'DS' | ||
}); | ||
/** | ||
* @doc function | ||
* @id DSLocalForageAdapterProvider | ||
* @name DSLocalForageAdapterProvider | ||
*/ | ||
function DSLocalForageAdapterProvider() { | ||
/** | ||
* @doc function | ||
* @id DSLocalForageAdapterProvider | ||
* @name DSLocalForageAdapterProvider | ||
*/ | ||
function DSLocalForageAdapterProvider() { | ||
this.$get = ['DSUtils', function (DSUtils) { | ||
this.$get = ['DSUtils', '$q', 'DS', '$rootScope', function (DSUtils, $q, DS, $rootScope) { | ||
/** | ||
* @doc interface | ||
* @id DSLocalForageAdapter | ||
* @name DSLocalForageAdapter | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: find, | ||
function resolve(deferred, v) { | ||
if (!$rootScope.$$phase) { | ||
return $rootScope.$apply(function () { | ||
return deferred.resolve(v); | ||
}); | ||
} else { | ||
return deferred.resolve(v); | ||
} | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
findAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
function reject(deferred, e) { | ||
if (!$rootScope.$$phase) { | ||
return $rootScope.$apply(function () { | ||
return deferred.reject(e); | ||
}); | ||
} else { | ||
return deferred.reject(e); | ||
} | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:create | ||
* @name create | ||
* @description | ||
* Not supported. | ||
*/ | ||
create: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc interface | ||
* @id DSLocalForageAdapter | ||
* @name DSLocalForageAdapter | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
getPath: function (resourceConfig, options) { | ||
return DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.name); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: update, | ||
getIdPath: function (resourceConfig, options, id) { | ||
return DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.getEndpoint(id, options), id); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
updateAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
getIds: function (resourceConfig, options) { | ||
var idsPath = this.getPath(resourceConfig, options); | ||
var deferred = $q.defer(); | ||
localforage.getItem(idsPath, function (err, ids) { | ||
if (err) { | ||
return reject(deferred, err); | ||
} else if (ids) { | ||
return resolve(deferred, ids); | ||
} else { | ||
return localforage.setItem(idsPath, {}, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroy | ||
* @name destroy | ||
* @description | ||
* Remove an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: destroy, | ||
saveKeys: function (ids, resourceConfig, options) { | ||
var keysPath = this.getPath(resourceConfig, options); | ||
var deferred = $q.defer(); | ||
localforage.setItem(keysPath, ids, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
destroyAll: function () { | ||
throw new Error('Not supported!'); | ||
} | ||
}; | ||
ensureId: function (id, resourceConfig, options) { | ||
var _this = this; | ||
return _this.getIds(resourceConfig, options).then(function (ids) { | ||
ids[id] = 1; | ||
return _this.saveKeys(ids, resourceConfig, options); | ||
}); | ||
}, | ||
function GET(key, successCallback) { | ||
return localforage.getItem(key, successCallback); | ||
} | ||
removeId: function (id, resourceConfig, options) { | ||
var _this = this; | ||
return _this.getIds(resourceConfig, options).then(function (ids) { | ||
delete ids[id]; | ||
return _this.saveKeys(ids, resourceConfig, options); | ||
}); | ||
}, | ||
function PUT(key, value, successCallback) { | ||
return localforage.getItem(key) | ||
.then(function (item) { | ||
if (item) { | ||
DSUtils.deepMixIn(item, value); | ||
return localforage.setItem(key, item, successCallback); | ||
} else { | ||
return localforage.setItem(key, value, successCallback); | ||
} | ||
}); | ||
} | ||
GET: function (key) { | ||
var deferred = $q.defer(); | ||
localforage.getItem(key, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
function DEL(key, successCallback) { | ||
return localforage.removeItem(key, successCallback); | ||
} | ||
PUT: function (key, value) { | ||
var deferred = $q.defer(); | ||
localforage.setItem(key, value, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
function find(resourceConfig, id, options) { | ||
options = options || {}; | ||
return GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id) | ||
); | ||
} | ||
DEL: function (key) { | ||
var deferred = $q.defer(); | ||
localforage.removeItem(key, function (err, v) { | ||
if (err) { | ||
return reject(deferred, err); | ||
} else { | ||
return resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
function update(resourceConfig, id, attrs, options) { | ||
options = options || {}; | ||
return PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
attrs | ||
).then(function () { | ||
return GET(DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id)); | ||
}); | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: function (resourceConfig, id, options) { | ||
options = options || {}; | ||
return this.GET(this.getIdPath(resourceConfig, options, id)).then(function (item) { | ||
if (!item) { | ||
return $q.reject(new Error('Not Found!')); | ||
} else { | ||
return item; | ||
} | ||
}); | ||
}, | ||
function destroy(resourceConfig, id, options) { | ||
options = options || {}; | ||
return DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id) | ||
); | ||
} | ||
}]; | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Retrieve a collection of entities from localforage. | ||
*/ | ||
findAll: function (resourceConfig, params, options) { | ||
var _this = this; | ||
options = options || {}; | ||
return _this.getIds(resourceConfig, options).then(function (ids) { | ||
var idsArray = DSUtils.keys(ids); | ||
if (!('allowSimpleWhere' in options)) { | ||
options.allowSimpleWhere = true; | ||
} | ||
var tasks = []; | ||
DSUtils.forEach(idsArray, function (id) { | ||
tasks.push(_this.GET(_this.getIdPath(resourceConfig, options, id))); | ||
}); | ||
return $q.all(tasks); | ||
}).then(function (items) { | ||
return DS.defaults.defaultFilter.call(DS, items, resourceConfig.name, params, options); | ||
}); | ||
}, | ||
angular.module('angular-data.DS').provider('DSLocalForageAdapter', DSLocalForageAdapterProvider); | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:create | ||
* @name create | ||
* @description | ||
*/ | ||
create: function (resourceConfig, attrs, options) { | ||
var _this = this; | ||
var i; | ||
attrs[resourceConfig.idAttribute] = attrs[resourceConfig.idAttribute] || guid(); | ||
options = options || {}; | ||
return _this.PUT( | ||
DSUtils.makePath(this.getIdPath(resourceConfig, options, attrs[resourceConfig.idAttribute])), | ||
attrs | ||
).then(function (item) { | ||
i = item; | ||
return _this.ensureId(item[resourceConfig.idAttribute], resourceConfig, options); | ||
}).then(function () { | ||
return i; | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: function (resourceConfig, id, attrs, options) { | ||
var _this = this; | ||
var i, item; | ||
options = options || {}; | ||
var path = _this.getIdPath(resourceConfig, options, id); | ||
return _this.GET(path).then(function (it) { | ||
if (it) { | ||
item = it; | ||
DSUtils.deepMixIn(item, attrs); | ||
} | ||
return _this.PUT(path, item || attrs); | ||
}).then(function () { | ||
i = item; | ||
return _this.ensureId(item[resourceConfig.idAttribute], resourceConfig, options); | ||
}).then(function () { | ||
return i; | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Update a collection of entities in localforage. | ||
*/ | ||
updateAll: function (resourceConfig, attrs, params, options) { | ||
var _this = this; | ||
return _this.findAll(resourceConfig, params, options).then(function (items) { | ||
var tasks = []; | ||
DSUtils.forEach(items, function (item) { | ||
tasks.push(_this.update(resourceConfig, item[resourceConfig.idAttribute], attrs, options)); | ||
}); | ||
return $q.all(tasks); | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroy | ||
* @name destroy | ||
* @description | ||
* Remove an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: function (resourceConfig, id, options) { | ||
var _this = this; | ||
options = options || {}; | ||
return _this.DEL(_this.getIdPath(resourceConfig, options, id)).then(function () { | ||
return _this.removeId(id, resourceConfig, options); | ||
}).then(function () { | ||
return null; | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
destroyAll: function (resourceConfig, params, options) { | ||
var _this = this; | ||
return _this.findAll(resourceConfig, params, options).then(function (items) { | ||
var tasks = []; | ||
DSUtils.forEach(items, function (item) { | ||
tasks.push(_this.destroy(resourceConfig, item[resourceConfig.idAttribute], options)); | ||
}); | ||
return $q.all(tasks); | ||
}); | ||
} | ||
}; | ||
}]; | ||
} | ||
angular.module('angular-data.DS').provider('DSLocalForageAdapter', DSLocalForageAdapterProvider); | ||
})(window, window.angular, window.localforage); | ||
},{"mout/random/guid":7}]},{},[12])(12) | ||
}); |
/** | ||
* @author Jason Dobry <jason.dobry@gmail.com> | ||
* @file angular-data-localForage.min.js | ||
* @version 0.1.0 - Homepage <https://github.com/jmdobry/angular-data-localForage/> | ||
* @version 1.0.0 - Homepage <https://github.com/jmdobry/angular-data-localForage/> | ||
* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/> | ||
@@ -10,2 +10,2 @@ * @license MIT <https://github.com/jmdobry/angular-data-localForage/blob/master/LICENSE> | ||
*/ | ||
!function(a,b,c){"use strict";function d(){this.$get=["DSUtils",function(a){function b(a,b){return c.getItem(a,b)}function d(b,d,e){return c.getItem(b).then(function(f){return f?(a.deepMixIn(f,d),c.setItem(b,f,e)):c.setItem(b,d,e)})}function e(a,b){return c.removeItem(a,b)}function f(c,d,e){return e=e||{},b(a.makePath(e.baseUrl||c.baseUrl,c.endpoint,d))}function g(c,e,f,g){return g=g||{},d(a.makePath(g.baseUrl||c.baseUrl,c.endpoint,e),f).then(function(){return b(a.makePath(g.baseUrl||c.baseUrl,c.endpoint,e))})}function h(b,c,d){return d=d||{},e(a.makePath(d.baseUrl||b.baseUrl,b.endpoint,c))}return{find:f,findAll:function(){throw new Error("Not supported!")},create:function(){throw new Error("Not supported!")},update:g,updateAll:function(){throw new Error("Not supported!")},destroy:h,destroyAll:function(){throw new Error("Not supported!")}}}]}c.config({name:"DS"}),b.module("angular-data.DS").provider("DSLocalForageAdapter",d)}(window,window.angular,window.localforage); | ||
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.DSLocalForageAdapter=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){var c=a("./isKind"),d=Array.isArray||function(a){return c(a,"Array")};b.exports=d},{"./isKind":2}],2:[function(a,b){function c(a,b){return d(a)===b}var d=a("./kindOf");b.exports=c},{"./kindOf":3}],3:[function(a,b){function c(a){return null===a?"Null":a===d?"Undefined":e.exec(f.call(a))[1]}var d,e=/^\[object (.*)\]$/,f=Object.prototype.toString;b.exports=c},{}],4:[function(a,b){b.exports=2147483647},{}],5:[function(a,b){b.exports=-2147483648},{}],6:[function(a,b){function c(a){var b=1===arguments.length&&e(a)?a:arguments;return b[d(0,b.length-1)]}var d=a("./randInt"),e=a("../lang/isArray");b.exports=c},{"../lang/isArray":1,"./randInt":10}],7:[function(a,b){function c(){return d(8)+"-"+d(4)+"-4"+d(3)+"-"+e(8,9,"a","b")+d(3)+"-"+d(12)}var d=a("./randHex"),e=a("./choice");b.exports=c},{"./choice":6,"./randHex":9}],8:[function(a,b){function c(a,b){return a=null==a?e:a,b=null==b?f:b,a+(b-a)*d()}var d=a("./random"),e=a("../number/MIN_INT"),f=a("../number/MAX_INT");b.exports=c},{"../number/MAX_INT":4,"../number/MIN_INT":5,"./random":11}],9:[function(a,b){function c(a){a=a&&a>0?a:6;for(var b="";a--;)b+=d(e);return b}var d=a("./choice"),e="0123456789abcdef".split("");b.exports=c},{"./choice":6}],10:[function(a,b){function c(a,b){return a=null==a?d:~~a,b=null==b?e:~~b,Math.round(f(a-.5,b+.499999999999))}var d=a("../number/MIN_INT"),e=a("../number/MAX_INT"),f=a("./rand");b.exports=c},{"../number/MAX_INT":4,"../number/MIN_INT":5,"./rand":8}],11:[function(a,b){function c(){return c.get()}c.get=Math.random,b.exports=c},{}],12:[function(a){var b=a("mout/random/guid");!function(a,c,d){"use strict";function e(){this.$get=["DSUtils","$q","DS","$rootScope",function(a,c,e,f){function g(a,b){return f.$$phase?a.resolve(b):f.$apply(function(){return a.resolve(b)})}function h(a,b){return f.$$phase?a.reject(b):f.$apply(function(){return a.reject(b)})}return{getPath:function(b,c){return a.makePath(c.baseUrl||b.baseUrl,b.name)},getIdPath:function(b,c,d){return a.makePath(c.baseUrl||b.baseUrl,b.getEndpoint(d,c),d)},getIds:function(a,b){var e=this.getPath(a,b),f=c.defer();return d.getItem(e,function(a,b){return a?h(f,a):b?g(f,b):d.setItem(e,{},function(a,b){a?h(f,a):g(f,b)})}),f.promise},saveKeys:function(a,b,e){var f=this.getPath(b,e),i=c.defer();return d.setItem(f,a,function(a,b){a?h(i,a):g(i,b)}),i.promise},ensureId:function(a,b,c){var d=this;return d.getIds(b,c).then(function(e){return e[a]=1,d.saveKeys(e,b,c)})},removeId:function(a,b,c){var d=this;return d.getIds(b,c).then(function(e){return delete e[a],d.saveKeys(e,b,c)})},GET:function(a){var b=c.defer();return d.getItem(a,function(a,c){a?h(b,a):g(b,c)}),b.promise},PUT:function(a,b){var e=c.defer();return d.setItem(a,b,function(a,b){a?h(e,a):g(e,b)}),e.promise},DEL:function(a){var b=c.defer();return d.removeItem(a,function(a,c){return a?h(b,a):g(b,c)}),b.promise},find:function(a,b,d){return d=d||{},this.GET(this.getIdPath(a,d,b)).then(function(a){return a?a:c.reject(new Error("Not Found!"))})},findAll:function(b,d,f){var g=this;return f=f||{},g.getIds(b,f).then(function(d){var e=a.keys(d);"allowSimpleWhere"in f||(f.allowSimpleWhere=!0);var h=[];return a.forEach(e,function(a){h.push(g.GET(g.getIdPath(b,f,a)))}),c.all(h)}).then(function(a){return e.defaults.defaultFilter.call(e,a,b.name,d,f)})},create:function(c,d,e){var f,g=this;return d[c.idAttribute]=d[c.idAttribute]||b(),e=e||{},g.PUT(a.makePath(this.getIdPath(c,e,d[c.idAttribute])),d).then(function(a){return f=a,g.ensureId(a[c.idAttribute],c,e)}).then(function(){return f})},update:function(b,c,d,e){var f,g,h=this;e=e||{};var i=h.getIdPath(b,e,c);return h.GET(i).then(function(b){return b&&(g=b,a.deepMixIn(g,d)),h.PUT(i,g||d)}).then(function(){return f=g,h.ensureId(g[b.idAttribute],b,e)}).then(function(){return f})},updateAll:function(b,d,e,f){var g=this;return g.findAll(b,e,f).then(function(e){var h=[];return a.forEach(e,function(a){h.push(g.update(b,a[b.idAttribute],d,f))}),c.all(h)})},destroy:function(a,b,c){var d=this;return c=c||{},d.DEL(d.getIdPath(a,c,b)).then(function(){return d.removeId(b,a,c)}).then(function(){return null})},destroyAll:function(b,d,e){var f=this;return f.findAll(b,d,e).then(function(d){var g=[];return a.forEach(d,function(a){g.push(f.destroy(b,a[b.idAttribute],e))}),c.all(g)})}}}]}d.config({name:"DS"}),c.module("angular-data.DS").provider("DSLocalForageAdapter",e)}(window,window.angular,window.localforage)},{"mout/random/guid":7}]},{},[12])(12)}); |
206
Gruntfile.js
@@ -9,105 +9,121 @@ /* | ||
module.exports = function (grunt) { | ||
'use strict'; | ||
'use strict'; | ||
require('load-grunt-tasks')(grunt); | ||
require('time-grunt')(grunt); | ||
require('jit-grunt')(grunt, { | ||
coveralls: 'grunt-karma-coveralls' | ||
}); | ||
require('time-grunt')(grunt); | ||
var pkg = grunt.file.readJSON('package.json'); | ||
var pkg = grunt.file.readJSON('package.json'); | ||
// Project configuration. | ||
grunt.initConfig({ | ||
pkg: pkg, | ||
clean: { | ||
coverage: ['coverage/'], | ||
dist: ['dist/'] | ||
}, | ||
jshint: { | ||
all: ['Gruntfile.js', 'src/**/*.js', 'test/*.js'], | ||
jshintrc: '.jshintrc' | ||
}, | ||
watch: { | ||
files: ['src/**/*.js'], | ||
tasks: ['build'] | ||
}, | ||
uglify: { | ||
main: { | ||
options: { | ||
banner: '/**\n' + | ||
'* @author Jason Dobry <jason.dobry@gmail.com>\n' + | ||
'* @file angular-data-localForage.min.js\n' + | ||
'* @version <%= pkg.version %> - Homepage <https://github.com/jmdobry/angular-data-localForage/>\n' + | ||
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' + | ||
'* @license MIT <https://github.com/jmdobry/angular-data-localForage/blob/master/LICENSE>\n' + | ||
'*\n' + | ||
'* @overview localForage adapter for angular-data.\n' + | ||
'*/\n' | ||
}, | ||
files: { | ||
'dist/angular-data-localForage.min.js': ['dist/angular-data-localForage.js'] | ||
} | ||
} | ||
}, | ||
copy: { | ||
dist: { | ||
files: { | ||
'dist/angular-data-localForage.js': ['src/angular-data-localForage.js'] | ||
} | ||
} | ||
}, | ||
karma: { | ||
options: { | ||
configFile: './karma.conf.js' | ||
}, | ||
dev: { | ||
browsers: ['Chrome'], | ||
autoWatch: true, | ||
singleRun: false | ||
}, | ||
min: { | ||
browsers: ['Chrome'], | ||
autoWatch: false, | ||
singleRun: true, | ||
options: { | ||
files: [ | ||
'bower_components/angular/angular.js', | ||
'bower_components/angular-mocks/angular-mocks.js', | ||
'bower_components/angular-data/dist/angular-data.js', | ||
'bower_components/angular-cache/dist/angular-cache.js', | ||
'dist/angular-data-localForage.min.js', | ||
'test/integration/**/*.js', | ||
'karma.start.js' | ||
] | ||
} | ||
}, | ||
ci: { | ||
browsers: ['Firefox', 'PhantomJS'] | ||
} | ||
}, | ||
coveralls: { | ||
options: { | ||
coverage_dir: 'coverage' | ||
} | ||
} | ||
}); | ||
// Project configuration. | ||
grunt.initConfig({ | ||
pkg: pkg, | ||
clean: { | ||
coverage: ['coverage/'], | ||
dist: ['dist/'] | ||
}, | ||
jshint: { | ||
all: ['Gruntfile.js', 'src/**/*.js', 'test/*.js'], | ||
jshintrc: '.jshintrc' | ||
}, | ||
watch: { | ||
files: ['src/**/*.js'], | ||
tasks: ['build'] | ||
}, | ||
uglify: { | ||
main: { | ||
options: { | ||
banner: '/**\n' + | ||
'* @author Jason Dobry <jason.dobry@gmail.com>\n' + | ||
'* @file angular-data-localForage.min.js\n' + | ||
'* @version <%= pkg.version %> - Homepage <https://github.com/jmdobry/angular-data-localForage/>\n' + | ||
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' + | ||
'* @license MIT <https://github.com/jmdobry/angular-data-localForage/blob/master/LICENSE>\n' + | ||
'*\n' + | ||
'* @overview localForage adapter for angular-data.\n' + | ||
'*/\n' | ||
}, | ||
files: { | ||
'dist/angular-data-localForage.min.js': ['dist/angular-data-localForage.js'] | ||
} | ||
} | ||
}, | ||
copy: { | ||
dist: { | ||
files: { | ||
'dist/angular-data-localForage.js': ['src/angular-data-localForage.js'] | ||
} | ||
} | ||
}, | ||
karma: { | ||
options: { | ||
configFile: './karma.conf.js' | ||
}, | ||
dev: { | ||
browsers: ['Chrome'], | ||
autoWatch: true, | ||
singleRun: false | ||
}, | ||
min: { | ||
browsers: ['Chrome'], | ||
autoWatch: false, | ||
singleRun: true, | ||
options: { | ||
files: [ | ||
'bower_components/angular/angular.js', | ||
'bower_components/angular-mocks/angular-mocks.js', | ||
'bower_components/angular-data/dist/angular-data.js', | ||
'bower_components/localforage/dist/localforage.js', | ||
'dist/angular-data-localForage.min.js', | ||
'test/**/*.js', | ||
'karma.start.js' | ||
] | ||
} | ||
}, | ||
ci: { | ||
browsers: ['Firefox', 'PhantomJS'] | ||
} | ||
}, | ||
browserify: { | ||
options: { | ||
browserifyOptions: { | ||
standalone: 'DSLocalForageAdapter' | ||
} | ||
}, | ||
dist: { | ||
files: { | ||
'dist/angular-data-localForage.js': ['src/angular-data-localForage.js'] | ||
} | ||
} | ||
}, | ||
coveralls: { | ||
options: { | ||
coverage_dir: 'coverage' | ||
} | ||
} | ||
}); | ||
grunt.registerTask('version', function (filePath) { | ||
var file = grunt.file.read(filePath); | ||
grunt.registerTask('version', function (filePath) { | ||
var file = grunt.file.read(filePath); | ||
file = file.replace(/<%= pkg\.version %>/gi, pkg.version); | ||
file = file.replace(/<%= pkg\.version %>/gi, pkg.version); | ||
grunt.file.write(filePath, file); | ||
}); | ||
grunt.file.write(filePath, file); | ||
}); | ||
grunt.registerTask('test', ['clean:coverage', 'karma:dev']); | ||
grunt.registerTask('build', [ | ||
'clean', | ||
'jshint', | ||
'copy', | ||
'version:dist/angular-data-localForage.js', | ||
'uglify:main' | ||
]); | ||
grunt.registerTask('default', ['build']); | ||
grunt.registerTask('test', ['build', 'clean:coverage', 'karma:min', 'karma:ci']); | ||
grunt.registerTask('build', [ | ||
'clean', | ||
'jshint', | ||
'browserify', | ||
'version:dist/angular-data-localForage.js', | ||
'uglify:main' | ||
]); | ||
grunt.registerTask('default', ['build']); | ||
// Used by TravisCI | ||
grunt.registerTask('ci', ['build', 'karma:ci', 'coveralls']); | ||
grunt.registerTask('go', ['build', 'watch']); | ||
// Used by TravisCI | ||
grunt.registerTask('ci', ['build', 'karma:ci', 'coveralls']); | ||
}; |
@@ -25,5 +25,4 @@ // an example karma.conf.js | ||
'bower_components/angular-data/dist/angular-data.js', | ||
'bower_components/angular-cache/dist/angular-cache.js', | ||
'bower_components/localforage/dist/localforage.js', | ||
'src/angular-data-localForage.js', | ||
'dist/angular-data-localForage.js', | ||
'test/**/*.js', | ||
@@ -30,0 +29,0 @@ 'karma.start.js' |
// Setup global test variables | ||
var $rootScope, $q, $log, DSProvider, DS, DSUtils, DSLocalForageAdapter, p1, p2, p3, p4, p5; | ||
var $rootScope, $q, $log, DSProvider, DS, DSUtils, DSLocalForageAdapter, p1, p2, p3, p4, p5, Post, User; | ||
@@ -42,6 +42,7 @@ // Helper globals | ||
DSUtils = _DSUtils_; | ||
DS.defineResource({ | ||
Post = DS.defineResource({ | ||
name: 'post', | ||
endpoint: '/posts' | ||
}); | ||
User = DS.defineResource('user'); | ||
$log = _$log_; | ||
@@ -48,0 +49,0 @@ }); |
{ | ||
"name": "angular-data-localforage", | ||
"description": "localForage adapter for angular-data.", | ||
"version": "0.1.0", | ||
"version": "1.0.0", | ||
"homepage": "https://github.com/jmdobry/angular-data-localForage", | ||
@@ -21,28 +21,31 @@ "repository": { | ||
], | ||
"dependencies": { | ||
"mout": "^0.11.0" | ||
}, | ||
"devDependencies": { | ||
"grunt": "0.4.4", | ||
"grunt-cli": "0.1.13", | ||
"grunt-contrib-clean": "0.5.0", | ||
"load-grunt-tasks": "0.4.0", | ||
"grunt-contrib-uglify": "0.4.0", | ||
"grunt": "0.4.5", | ||
"grunt-browserify": "^3.2.1", | ||
"grunt-contrib-clean": "0.6.0", | ||
"grunt-contrib-copy": "0.7.0", | ||
"grunt-contrib-jshint": "0.10.0", | ||
"karma-script-launcher": "~0.1.0", | ||
"karma-chrome-launcher": "~0.1.3", | ||
"karma-firefox-launcher": "~0.1.3", | ||
"karma-phantomjs-launcher": "~0.1.4", | ||
"karma": "~0.12.16", | ||
"grunt-karma": "~0.8.3", | ||
"grunt-contrib-uglify": "0.6.0", | ||
"grunt-contrib-watch": "0.6.1", | ||
"grunt-karma": "0.9.0", | ||
"grunt-karma-coveralls": "2.5.3", | ||
"jit-grunt": "0.9.0", | ||
"karma": "0.12.28", | ||
"karma-chai": "0.1.0", | ||
"mocha": "~1.18.2", | ||
"karma-coverage": "~0.2.1", | ||
"grunt-contrib-watch": "~0.6.1", | ||
"grunt-karma-coveralls": "~2.5.0", | ||
"karma-mocha": "~0.1.3", | ||
"karma-sinon": "~1.0.3", | ||
"time-grunt": "~0.3.1", | ||
"grunt-contrib-copy": "^0.5.0" | ||
"karma-chrome-launcher": "0.1.7", | ||
"karma-coverage": "0.2.7", | ||
"karma-firefox-launcher": "0.1.3", | ||
"karma-mocha": "0.1.10", | ||
"karma-phantomjs-launcher": "0.1.4", | ||
"karma-script-launcher": "0.1.0", | ||
"karma-sinon": "1.0.4", | ||
"mocha": "2.0.1", | ||
"time-grunt": "1.0.0" | ||
}, | ||
"scripts": { | ||
"test": "node node_modules/grunt-cli/bin/grunt test" | ||
"test": "grunt test" | ||
} | ||
} |
@@ -5,8 +5,8 @@ ## angular-data-localForage | ||
__Current version:__ 0.1.0 | ||
__Current version:__ 1.0.0 | ||
Adapter usage documentation can be found [here](http://angular-data.codetrain.io). | ||
Adapter usage documentation can be found [here](http://angular-data.pseudobry.com). | ||
## Issues | ||
[issues](https://github.com/jmdobry/angular-data-localForage/issues?milestone=7&page=1&state=open) for what's in development | ||
[issues](https://github.com/jmdobry/angular-data-localForage/issues) for what's in development | ||
@@ -13,0 +13,0 @@ ## Changelog |
@@ -0,1 +1,3 @@ | ||
var guid = require('mout/random/guid'); | ||
/** | ||
@@ -11,165 +13,308 @@ * @author Jason Dobry <jason.dobry@gmail.com> | ||
(function (window, angular, localforage, undefined) { | ||
'use strict'; | ||
'use strict'; | ||
localforage.config({ | ||
name: 'DS' | ||
}); | ||
localforage.config({ | ||
name: 'DS' | ||
}); | ||
/** | ||
* @doc function | ||
* @id DSLocalForageAdapterProvider | ||
* @name DSLocalForageAdapterProvider | ||
*/ | ||
function DSLocalForageAdapterProvider() { | ||
/** | ||
* @doc function | ||
* @id DSLocalForageAdapterProvider | ||
* @name DSLocalForageAdapterProvider | ||
*/ | ||
function DSLocalForageAdapterProvider() { | ||
this.$get = ['DSUtils', function (DSUtils) { | ||
this.$get = ['DSUtils', '$q', 'DS', '$rootScope', function (DSUtils, $q, DS, $rootScope) { | ||
/** | ||
* @doc interface | ||
* @id DSLocalForageAdapter | ||
* @name DSLocalForageAdapter | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: find, | ||
function resolve(deferred, v) { | ||
if (!$rootScope.$$phase) { | ||
return $rootScope.$apply(function () { | ||
return deferred.resolve(v); | ||
}); | ||
} else { | ||
return deferred.resolve(v); | ||
} | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
findAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
function reject(deferred, e) { | ||
if (!$rootScope.$$phase) { | ||
return $rootScope.$apply(function () { | ||
return deferred.reject(e); | ||
}); | ||
} else { | ||
return deferred.reject(e); | ||
} | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:create | ||
* @name create | ||
* @description | ||
* Not supported. | ||
*/ | ||
create: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
/** | ||
* @doc interface | ||
* @id DSLocalForageAdapter | ||
* @name DSLocalForageAdapter | ||
* @description | ||
* Default adapter used by angular-data. This adapter uses AJAX and JSON to send/retrieve data to/from a server. | ||
* Developers may provide custom adapters that implement the adapter interface. | ||
*/ | ||
return { | ||
getPath: function (resourceConfig, options) { | ||
return DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.name); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: update, | ||
getIdPath: function (resourceConfig, options, id) { | ||
return DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.getEndpoint(id, options), id); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
updateAll: function () { | ||
throw new Error('Not supported!'); | ||
}, | ||
getIds: function (resourceConfig, options) { | ||
var idsPath = this.getPath(resourceConfig, options); | ||
var deferred = $q.defer(); | ||
localforage.getItem(idsPath, function (err, ids) { | ||
if (err) { | ||
return reject(deferred, err); | ||
} else if (ids) { | ||
return resolve(deferred, ids); | ||
} else { | ||
return localforage.setItem(idsPath, {}, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroy | ||
* @name destroy | ||
* @description | ||
* Remove an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: destroy, | ||
saveKeys: function (ids, resourceConfig, options) { | ||
var keysPath = this.getPath(resourceConfig, options); | ||
var deferred = $q.defer(); | ||
localforage.setItem(keysPath, ids, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
destroyAll: function () { | ||
throw new Error('Not supported!'); | ||
} | ||
}; | ||
ensureId: function (id, resourceConfig, options) { | ||
var _this = this; | ||
return _this.getIds(resourceConfig, options).then(function (ids) { | ||
ids[id] = 1; | ||
return _this.saveKeys(ids, resourceConfig, options); | ||
}); | ||
}, | ||
function GET(key, successCallback) { | ||
return localforage.getItem(key, successCallback); | ||
} | ||
removeId: function (id, resourceConfig, options) { | ||
var _this = this; | ||
return _this.getIds(resourceConfig, options).then(function (ids) { | ||
delete ids[id]; | ||
return _this.saveKeys(ids, resourceConfig, options); | ||
}); | ||
}, | ||
function PUT(key, value, successCallback) { | ||
return localforage.getItem(key) | ||
.then(function (item) { | ||
if (item) { | ||
DSUtils.deepMixIn(item, value); | ||
return localforage.setItem(key, item, successCallback); | ||
} else { | ||
return localforage.setItem(key, value, successCallback); | ||
} | ||
}); | ||
} | ||
GET: function (key) { | ||
var deferred = $q.defer(); | ||
localforage.getItem(key, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
function DEL(key, successCallback) { | ||
return localforage.removeItem(key, successCallback); | ||
} | ||
PUT: function (key, value) { | ||
var deferred = $q.defer(); | ||
localforage.setItem(key, value, function (err, v) { | ||
if (err) { | ||
reject(deferred, err); | ||
} else { | ||
resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
function find(resourceConfig, id, options) { | ||
options = options || {}; | ||
return GET( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id) | ||
); | ||
} | ||
DEL: function (key) { | ||
var deferred = $q.defer(); | ||
localforage.removeItem(key, function (err, v) { | ||
if (err) { | ||
return reject(deferred, err); | ||
} else { | ||
return resolve(deferred, v); | ||
} | ||
}); | ||
return deferred.promise; | ||
}, | ||
function update(resourceConfig, id, attrs, options) { | ||
options = options || {}; | ||
return PUT( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id), | ||
attrs | ||
).then(function () { | ||
return GET(DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id)); | ||
}); | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:find | ||
* @name find | ||
* @description | ||
* Retrieve a single entity from localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to retrieve. | ||
* @returns {Promise} Promise. | ||
*/ | ||
find: function (resourceConfig, id, options) { | ||
options = options || {}; | ||
return this.GET(this.getIdPath(resourceConfig, options, id)).then(function (item) { | ||
if (!item) { | ||
return $q.reject(new Error('Not Found!')); | ||
} else { | ||
return item; | ||
} | ||
}); | ||
}, | ||
function destroy(resourceConfig, id, options) { | ||
options = options || {}; | ||
return DEL( | ||
DSUtils.makePath(options.baseUrl || resourceConfig.baseUrl, resourceConfig.endpoint, id) | ||
); | ||
} | ||
}]; | ||
} | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:findAll | ||
* @name findAll | ||
* @description | ||
* Retrieve a collection of entities from localforage. | ||
*/ | ||
findAll: function (resourceConfig, params, options) { | ||
var _this = this; | ||
options = options || {}; | ||
return _this.getIds(resourceConfig, options).then(function (ids) { | ||
var idsArray = DSUtils.keys(ids); | ||
if (!('allowSimpleWhere' in options)) { | ||
options.allowSimpleWhere = true; | ||
} | ||
var tasks = []; | ||
DSUtils.forEach(idsArray, function (id) { | ||
tasks.push(_this.GET(_this.getIdPath(resourceConfig, options, id))); | ||
}); | ||
return $q.all(tasks); | ||
}).then(function (items) { | ||
return DS.defaults.defaultFilter.call(DS, items, resourceConfig.name, params, options); | ||
}); | ||
}, | ||
angular.module('angular-data.DS').provider('DSLocalForageAdapter', DSLocalForageAdapterProvider); | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:create | ||
* @name create | ||
* @description | ||
*/ | ||
create: function (resourceConfig, attrs, options) { | ||
var _this = this; | ||
var i; | ||
attrs[resourceConfig.idAttribute] = attrs[resourceConfig.idAttribute] || guid(); | ||
options = options || {}; | ||
return _this.PUT( | ||
DSUtils.makePath(this.getIdPath(resourceConfig, options, attrs[resourceConfig.idAttribute])), | ||
attrs | ||
).then(function (item) { | ||
i = item; | ||
return _this.ensureId(item[resourceConfig.idAttribute], resourceConfig, options); | ||
}).then(function () { | ||
return i; | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:update | ||
* @name update | ||
* @description | ||
* Update an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to update. | ||
* @param {object} attrs The attributes with which to update the entity. | ||
* @returns {Promise} Promise. | ||
*/ | ||
update: function (resourceConfig, id, attrs, options) { | ||
var _this = this; | ||
var i, item; | ||
options = options || {}; | ||
var path = _this.getIdPath(resourceConfig, options, id); | ||
return _this.GET(path).then(function (it) { | ||
if (it) { | ||
item = it; | ||
DSUtils.deepMixIn(item, attrs); | ||
} | ||
return _this.PUT(path, item || attrs); | ||
}).then(function () { | ||
i = item; | ||
return _this.ensureId(item[resourceConfig.idAttribute], resourceConfig, options); | ||
}).then(function () { | ||
return i; | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:updateAll | ||
* @name updateAll | ||
* @description | ||
* Update a collection of entities in localforage. | ||
*/ | ||
updateAll: function (resourceConfig, attrs, params, options) { | ||
var _this = this; | ||
return _this.findAll(resourceConfig, params, options).then(function (items) { | ||
var tasks = []; | ||
DSUtils.forEach(items, function (item) { | ||
tasks.push(_this.update(resourceConfig, item[resourceConfig.idAttribute], attrs, options)); | ||
}); | ||
return $q.all(tasks); | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroy | ||
* @name destroy | ||
* @description | ||
* Remove an entity in localforage. | ||
* | ||
* @param {object} resourceConfig Properties: | ||
* - `{string}` - `baseUrl` - Base url. | ||
* - `{string=}` - `namespace` - Namespace path for the resource. | ||
* @param {string|number} id The primary key of the entity to destroy. | ||
* @returns {Promise} Promise. | ||
*/ | ||
destroy: function (resourceConfig, id, options) { | ||
var _this = this; | ||
options = options || {}; | ||
return _this.DEL(_this.getIdPath(resourceConfig, options, id)).then(function () { | ||
return _this.removeId(id, resourceConfig, options); | ||
}).then(function () { | ||
return null; | ||
}); | ||
}, | ||
/** | ||
* @doc method | ||
* @id DSLocalForageAdapter.methods:destroyAll | ||
* @name destroyAll | ||
* @description | ||
* Not supported. | ||
*/ | ||
destroyAll: function (resourceConfig, params, options) { | ||
var _this = this; | ||
return _this.findAll(resourceConfig, params, options).then(function (items) { | ||
var tasks = []; | ||
DSUtils.forEach(items, function (item) { | ||
tasks.push(_this.destroy(resourceConfig, item[resourceConfig.idAttribute], options)); | ||
}); | ||
return $q.all(tasks); | ||
}); | ||
} | ||
}; | ||
}]; | ||
} | ||
angular.module('angular-data.DS').provider('DSLocalForageAdapter', DSLocalForageAdapterProvider); | ||
})(window, window.angular, window.localforage); |
@@ -1,53 +0,21 @@ | ||
describe('DSLocalForageAdapter.destroy(resourceConfig, id, options)', function () { | ||
it('should destroy an item from localStorage', function (done) { | ||
var path = DSUtils.makePath('api', 'posts', 1); | ||
localforage.setItem(path, p1) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p1, 'p1 should be in localforage'); | ||
$rootScope.$apply(); | ||
return DSLocalForageAdapter.destroy({ | ||
baseUrl: 'api', | ||
endpoint: 'posts' | ||
}, 1); | ||
}) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.isNull(item, 'the item should be gone from localStorage'); | ||
path = DSUtils.makePath('api2', 'posts', 1); | ||
return localforage.setItem(path, p2); | ||
}) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p2, 'p2 should be in localforage'); | ||
$rootScope.$apply(); | ||
return DSLocalForageAdapter.destroy({ | ||
baseUrl: 'api', | ||
endpoint: 'posts' | ||
}, 1, { baseUrl: 'api2' }); | ||
}) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.isNull(item, 'the item should be gone from localStorage'); | ||
done(); | ||
}) | ||
.catch(function (err) { | ||
console.error(err.stack); | ||
fail('should not have rejected'); | ||
}); | ||
$rootScope.$apply(); | ||
}); | ||
describe('DSLocalForageAdapter.destroy', function () { | ||
it('should destroy a user from localForage', function (done) { | ||
var id; | ||
DSLocalForageAdapter.create(User, { name: 'John' }) | ||
.then(function (user) { | ||
id = user.id; | ||
return DSLocalForageAdapter.destroy(User, user.id); | ||
}) | ||
.then(function (user) { | ||
assert.isFalse(!!user); | ||
return DSLocalForageAdapter.find(User, id); | ||
}) | ||
.then(function () { | ||
done('Should not have reached here!'); | ||
}) | ||
.catch(function (err) { | ||
assert.equal(err.message, 'Not Found!'); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -1,47 +0,29 @@ | ||
describe('DSLocalForageAdapter.find(resourceConfig, id, options)', function () { | ||
it('should find an item in localforage', function (done) { | ||
var path = DSUtils.makePath('api', 'posts', 1); | ||
localforage.setItem(path, p1) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p1, 'p1 should be in localforage'); | ||
$rootScope.$apply(); | ||
return DSLocalForageAdapter.find({ | ||
baseUrl: 'api', | ||
endpoint: 'posts' | ||
}, 1); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p1, 'the item should have been found'); | ||
path = DSUtils.makePath('api2', 'posts', 1); | ||
return localforage.setItem(path, p2); | ||
}) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p2, 'p2 should be in localforage'); | ||
$rootScope.$apply(); | ||
return DSLocalForageAdapter.find({ | ||
baseUrl: 'api', | ||
endpoint: 'posts' | ||
}, 1, { baseUrl: 'api2' }); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p2, 'the item should have been found'); | ||
done(); | ||
}) | ||
.catch(function (err) { | ||
console.error(err.stack); | ||
fail('should not have rejected'); | ||
}); | ||
$rootScope.$apply(); | ||
}); | ||
describe('DSLocalForageAdapter.find', function () { | ||
it('should find a user in localForage', function (done) { | ||
var id; | ||
DSLocalForageAdapter.create(User, { name: 'John' }) | ||
.then(function (user) { | ||
id = user.id; | ||
assert.equal(user.name, 'John'); | ||
assert.isString(user.id); | ||
return DSLocalForageAdapter.find(User, user.id); | ||
}) | ||
.then(function (user) { | ||
assert.equal(user.name, 'John'); | ||
assert.isString(user.id); | ||
assert.deepEqual(user, { id: id, name: 'John' }); | ||
return DSLocalForageAdapter.destroy(User, id); | ||
}) | ||
.then(function (user) { | ||
assert.isFalse(!!user); | ||
return DSLocalForageAdapter.find(User, id); | ||
}) | ||
.then(function () { | ||
done('Should not have reached here!'); | ||
}) | ||
.catch(function (err) { | ||
assert.equal(err.message, 'Not Found!'); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -1,55 +0,41 @@ | ||
describe('DSLocalForageAdapter.update(resourceConfig, id, options)', function () { | ||
it('should update an item in localforage', function (done) { | ||
var path = DSUtils.makePath('api', 'posts', 1); | ||
localforage.setItem(path, p1) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p1, 'p1 should be in localforage'); | ||
$rootScope.$apply(); | ||
return DSLocalForageAdapter.update({ | ||
baseUrl: 'api', | ||
endpoint: 'posts' | ||
}, 1, { age: 99 }); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, { author: 'John', id: 5, age: 99 }, 'the item should have been updated'); | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, { author: 'John', id: 5, age: 99 }, 'the item should have been updated'); | ||
path = DSUtils.makePath('api2', 'posts', 1); | ||
return localforage.setItem(path, p2); | ||
}) | ||
.then(function () { | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, p2, 'p2 should be in localforage'); | ||
$rootScope.$apply(); | ||
return DSLocalForageAdapter.update({ | ||
baseUrl: 'api', | ||
endpoint: 'posts' | ||
}, 1, { author: 'Beth' }, { baseUrl: 'api2' }); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, { author: 'Beth', id: 6, age: 31 }, 'the item should have been updated'); | ||
return localforage.getItem(path); | ||
}) | ||
.then(function (item) { | ||
assert.deepEqual(item, { author: 'Beth', id: 6, age: 31 }, 'the item should have been updated'); | ||
done(); | ||
}) | ||
.catch(function (err) { | ||
console.error(err.stack); | ||
fail('should not have rejected'); | ||
}); | ||
$rootScope.$apply(); | ||
}); | ||
describe('DSLocalForageAdapter.update', function () { | ||
it('should update a user in localForage', function (done) { | ||
var id; | ||
DSLocalForageAdapter.create(User, { name: 'John' }) | ||
.then(function (user) { | ||
id = user.id; | ||
assert.equal(user.name, 'John'); | ||
assert.isString(user.id); | ||
return DSLocalForageAdapter.find(User, user.id); | ||
}) | ||
.then(function (foundUser) { | ||
assert.equal(foundUser.name, 'John'); | ||
assert.isString(foundUser.id); | ||
assert.deepEqual(foundUser, { id: id, name: 'John' }); | ||
return DSLocalForageAdapter.update(User, foundUser.id, { name: 'Johnny' }); | ||
}) | ||
.then(function (updatedUser) { | ||
assert.equal(updatedUser.name, 'Johnny'); | ||
assert.isString(updatedUser.id); | ||
assert.deepEqual(updatedUser, { id: id, name: 'Johnny' }); | ||
return DSLocalForageAdapter.find(User, updatedUser.id); | ||
}) | ||
.then(function (foundUser) { | ||
assert.equal(foundUser.name, 'Johnny'); | ||
assert.isString(foundUser.id); | ||
assert.deepEqual(foundUser, { id: id, name: 'Johnny' }); | ||
return DSLocalForageAdapter.destroy(User, foundUser.id); | ||
}) | ||
.then(function (user) { | ||
assert.isFalse(!!user); | ||
return DSLocalForageAdapter.find(User, id); | ||
}) | ||
.then(function () { | ||
done('Should not have reached here!'); | ||
}) | ||
.catch(function (err) { | ||
assert.equal(err.message, 'Not Found!'); | ||
done(); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
54064
21
1208
1
4
1
+ Addedmout@^0.11.0
+ Addedmout@0.11.1(transitive)