2014-12-14 17:00:02 +00:00

247 lines
6.3 KiB
JavaScript

/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
(function(global) {
function Set() {
this.set_ = new global.Set;
this.keys_ = [];
}
Set.prototype = {
add: function(key) {
if (!this.set_.has(key))
this.keys_.push(key);
return this.set_.add(key);
},
has: function(key) {
return this.set_.has(key);
},
delete: function(key) {
this.keys_.splice(this.keys_.indexOf(key), 1);
this.set_.delete(key);
},
keys: function() {
return this.keys_.slice();
}
}
var dbName = 'PersistObserved';
var version;
var db;
var storeNames = {};
function constructorName(objOrFunction) {
if (typeof objOrFunction == 'function')
return objOrFunction.name;
else
return Object.getPrototypeOf(objOrFunction).constructor.name;
}
function getKeyPath(constructor) {
return constructor.keyPath || 'id';
}
function onerror(e) {
console.log('Error: ' + e);
};
var postOpen = [];
function openDB() {
var request = webkitIndexedDB.open(dbName);
request.onerror = onerror;
request.onsuccess = function(e) {
db = e.target.result;
version = db.version || 0;
for (var i = 0; i < db.objectStoreNames.length; i++)
storeNames[db.objectStoreNames.item(i)] = true;
postOpen.forEach(function(action) {
action();
});
};
}
function handleChanged(changeRecords) {
changeRecords.forEach(function(change) {
persist(change.object);
});
}
var observer = new ChangeSummary(function(summaries) {
storeChanges = {};
function getChange(obj) {
var change = storeChanges[constructorName(obj)];
if (change)
return change;
change = {
keyPath: getKeyPath(obj),
needsAdd: new Set,
needsSave: new Set,
needsDelete: new Set
};
storeChanges[storeName] = change;
return change;
}
summaries.forEach(function(summary) {
if (!Array.isArray(summary.object)) {
getChange(summary.object).needsSave.add(summary.object);
return;
}
summary.arraySplices.forEach(function(splice) {
for (var i = 0; i < splice.removed.length; i++) {
var obj = splice.removed[i];
var change = getChange(obj);
if (change.needsAdd.has(obj))
change.needsAdd.delete(obj);
else
change.needsDelete.add(obj);
}
for (var i = splice.index; i < splice.index + splice.addedCount; i++) {
var obj = summary.object[i];
var change = getChange(obj);
if (change.needsDelete.has(obj))
change.needsDelete.delete(obj);
else
change.needsAdd.add(obj);
}
});
});
var storeNames = Object.keys(storeChanges);
console.log('Persisting: ' + JSON.stringify(storeNames));
var trans = db.transaction(storeNames, "readwrite");
trans.onerror = onerror;
trans.oncomplete = function() {
console.log('...complete');
}
storeNames.forEach(function(storeName) {
var change = storeChanges[storeName];
var store = trans.objectStore(storeName);
change.needsDelete.keys().forEach(function(obj) {
var request = store.delete(obj[change.keyPath]);
request.onerror = onerror;
request.onsuccess = function(e) {
console.log(' deleted: ' + JSON.stringify(obj));
delete obj[keyPath];
observer.unobserve(obj);
if (change.needsSave.has(obj))
change.needsSave.delete(obj);
};
});
change.needsSave.keys().forEach(function(obj) {
var request = store.put(obj);
request.onerror = onerror;
request.onsuccess = function(e) {
console.log(' saved: ' + JSON.stringify(obj));
};
});
change.needsAdd.keys().forEach(function(obj) {
obj[keyPath] = ++maxIds[storeName];
var request = store.put(obj);
request.onerror = onerror;
request.onsuccess = function(e) {
console.log(' created: ' + JSON.stringify(obj));
observer.observe(obj);
};
});
});
});
var maxIds = {};
global.persistDB = {};
global.persistDB.retrieve = function(constructor) {
var results = [];
var instance = new constructor();
keyPath = constructor.keyPath || 'id';
storeName = constructor.name;
maxIds[storeName] = maxIds[storeName] || 0;
function doRetrieve() {
console.log("Retrieving: " + storeName);
var trans = db.transaction([storeName]);
var store = trans.objectStore(storeName);
var keyRange = webkitIDBKeyRange.lowerBound(0);
var request = store.openCursor(keyRange);
request.onerror = onerror;
request.onsuccess = function(e) {
var result = e.target.result;
if (!!result == false) {
observer.observePropertySet(results);
console.log('...complete');
return;
}
var object = result.value;
maxIds[storeName] = Math.max(maxIds[storeName], object[keyPath]);
object.__proto__ = instance;
constructor.apply(object);
results.push(object);
observer.observe(object);
console.log(' => ' + JSON.stringify(object));
result.continue();
};
}
function createStore() {
console.log('Creating store: ' + storeName);
version++;
var request = db.setVersion(version);
request.onerror = onerror;
request.onsuccess = function(e) {
var store = db.createObjectStore(storeName, { keyPath: keyPath });
storeNames[storeName] = true;
e.target.transaction.oncomplete = doRetrieve;
};
}
var action = function() {
if (storeName in storeNames)
doRetrieve()
else
createStore();
}
if (db)
action();
else
postOpen.push(action);
return results;
};
openDB();
})(this);