blob: 5f8382bb0f6ae305b8be14615754855ee100c487 [file] [log] [blame]
// depot.js v0.1.6
// (c) 2013 Michal Kuklis
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
(function (name, root, factory) {
if (typeof exports == 'object') {
module.exports = factory();
} else if (typeof define == 'function' && define.amd) {
define(factory);
} else {
root[name] = factory();
}
}("depot", this, function () {
"use strict";
// depot api
var api = {
save: function (record) {
var id, ids;
this.refresh();
if (!record[this.idAttribute]) {
record[this.idAttribute] = guid();
}
id = record[this.idAttribute] + '';
if (this.ids.indexOf(id) < 0) {
this.ids.push(id);
ids = this.ids.join(",");
this.storageAdaptor.setItem(this.name, ids);
this.store = ids;
}
this.storageAdaptor.setItem(getKey(this.name, id), JSON.stringify(record));
return record;
},
update: function (id, data) {
if (typeof data == 'undefined') {
data = id;
id = data[this.idAttribute];
}
var record = this.get(id);
if (record) {
record = extend(record, data);
this.save(record);
}
return record;
},
updateAll: function (data) {
var records = this.all();
records.forEach(function (record) {
record = extend(record, data);
this.save(record);
}, this);
return records;
},
find: function (criteria) {
var key, match, record;
var name = this.name;
var self = this;
if (!criteria) return this.all();
this.refresh();
return this.ids.reduce(function (memo, id) {
record = jsonData(self.storageAdaptor.getItem(getKey(name, id)));
match = findMatch(criteria, record);
if (match) {
memo.push(record);
}
return memo;
}, []);
},
get: function (id) {
return jsonData(this.storageAdaptor.getItem(getKey(this.name, id)));
},
all: function () {
var record, self = this, name = this.name;
this.refresh();
return this.ids.reduce(function (memo, id) {
record = self.storageAdaptor.getItem(getKey(name, id));
if (record) {
memo.push(jsonData(record));
}
return memo;
}, []);
},
destroy: function (record) {
var index;
var id = (record[this.idAttribute]) ? record[this.idAttribute] : record;
var key = getKey(this.name, id);
record = jsonData(this.storageAdaptor.getItem(key));
this.storageAdaptor.removeItem(key);
index = this.ids.indexOf(id);
if (index != -1) this.ids.splice(index, 1);
this.storageAdaptor.setItem(this.name, this.ids.join(","));
return record;
},
destroyAll: function (criteria) {
var attr, id, match, record, key;
this.refresh();
for (var i = this.ids.length - 1; i >= 0; i--) {
id = this.ids[i];
key = getKey(this.name, id);
if (criteria) {
record = jsonData(this.storageAdaptor.getItem(key));
match = findMatch(criteria, record);
if (match) {
this.storageAdaptor.removeItem(key);
this.ids.splice(i, 1);
}
}
else {
this.storageAdaptor.removeItem(key);
}
}
if (criteria) {
this.storageAdaptor.setItem(this.name, this.ids.join(","));
}
else {
this.storageAdaptor.removeItem(this.name);
this.ids = [];
}
},
size: function () {
this.refresh();
return this.ids.length;
},
refresh: function () {
var store = this.storageAdaptor.getItem(this.name);
if (this.store && this.store === store) {
return;
}
this.ids = (store && store.split(",")) || [];
this.store = store;
}
};
// helpers
function jsonData(data) {
return data && JSON.parse(data);
}
function getKey(name, id) {
return name + "-" + id;
}
function findMatch(criteria, record) {
var match, attr;
if (typeof criteria == 'function') {
match = criteria(record);
}
else {
match = true;
for (attr in criteria) {
match &= (criteria[attr] === record[attr]);
}
}
return match;
}
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16).substring(1);
}
function guid() {
return s4() + s4() + '-' + s4() + '-' + s4() +
'-' +s4() + '-' + s4() + s4() + s4();
}
function extend(dest, source) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
dest[key] = source[key];
}
}
return dest;
}
function depot(name, options) {
var instance;
options = extend({
idAttribute: '_id',
storageAdaptor: localStorage
}, options);
if (!options.storageAdaptor) throw new Error("No storage adaptor was found");
instance = Object.create(api, {
name: { value: name },
idAttribute: { value: options.idAttribute },
storageAdaptor: { value: options.storageAdaptor }
});
instance.refresh();
return instance;
}
return depot;
}));