added delete, getAllEdits + unit tests

This commit is contained in:
Andy Gup 2015-02-18 18:01:58 -07:00
parent 702387f7a3
commit 7c3baa2753
2 changed files with 228 additions and 42 deletions

View File

@ -34,37 +34,64 @@ O.esri.Edit.EditStore = function()
*/
this.pushEdit = function(operation,layer,graphic, callback)
{
try
{
var edit = {
id: graphic.attributes.objectid,
operation: operation,
layer: layer,
graphic: graphic.toJson()
};
var transaction = this._db.transaction([objectStoreName],"readwrite");
transaction.oncomplete = function(event){
callback(true);
var edit = {
id: layer + "/" + graphic.attributes.objectid,
operation: operation,
layer: layer,
graphic: graphic.toJson()
};
transaction.onerror = function(event){
callback(false,event.target.error.message);
var transaction = this._db.transaction([objectStoreName],"readwrite");
transaction.oncomplete = function(event){
callback(true);
};
transaction.onerror = function(event){
callback(false,event.target.error.message);
};
var objectStore = transaction.objectStore(objectStoreName);
var request = objectStore.put(edit);
request.onsuccess = function(event){
//console.log("item added to db " + event.target.result);
};
};
/**
* Returns all the edits recursively via the callback
* @param callback {value, message}
*/
this.getAllEdits = function(callback){
console.assert(this._db !== null, "indexeddb not initialized");
if(this._db !== null){
var transaction = this._db.transaction([objectStoreName])
.objectStore(objectStoreName)
.openCursor();
transaction.onsuccess = function(event)
{
var cursor = event.target.result;
if(cursor){
callback(cursor.value,null);
cursor.continue();
}
else
{
callback(null, "end");
}
}.bind(this);
transaction.onerror = function(err)
{
callback(null, err);
};
var objectStore = transaction.objectStore(objectStoreName);
var request = objectStore.put(edit);
request.onsuccess = function(event){
//console.log("item added to db " + event.target.result);
};
}
catch(err)
else
{
console.log("AttachmentsStore: " + err.stack);
callback(false,err.stack);
callback(null, "no db");
}
};
@ -90,7 +117,7 @@ O.esri.Edit.EditStore = function()
//Create a new update object
var update = {
id: graphic.attributes.objectid,
id: layer + "/" + graphic.attributes.objectid,
operation: operation,
layer: layer,
graphic: graphic.toJson()
@ -109,6 +136,83 @@ O.esri.Edit.EditStore = function()
}
};
/**
* Delete a pending edit's record from the database.
* IMPORTANT: Be aware of false negatives. See Step 4 in this function.
*
* @param layerUrl
* @param graphic Graphic
* @param callback {boolean}
*/
this.delete = function(layerUrl, graphic, callback){
// NOTE: the implementation of the IndexedDB spec has a major failure with respect to
// handling deletes. The result of the operation is specified as undefined.
// What this means is that there is no way to tell if an operation was successful or not.
//
// In order to get around this we have to verify if after the attempted deletion operation
// if the record is or is not in the database. Kinda dumb, but that's how IndexedDB works.
//http://stackoverflow.com/questions/17137879/is-there-a-way-to-get-information-on-deleted-record-when-calling-indexeddbs-obj
var db = this._db;
var deferred = null;
var self = this;
var edit = {
id: layerUrl + "/" + graphic.attributes.objectid,
operation: null,
layer: layerUrl,
graphic: graphic.toJson()
};
require(["dojo/Deferred"], function(Deferred){
deferred = new Deferred();
// Step 1 - lets see if record exits. If it does then return callback.
self.editExists(edit).then(function(result){
if(result.success){
// Step 4 - Then we check to see if the record actually exists or not.
deferred.then(function(edit){
self.editExists(edit).then(function(results){
results.success == false ? callback(true) : callback(false);
},
function(){
callback(true); //because we want this test to throw an error. That means item deleted.
})
},
// There was a problem with the delete operation on the database
function(err){
callback(err);
});
var objectStore = db.transaction([objectStoreName],"readwrite").objectStore(objectStoreName);
// Step 2 - go ahead and delete graphic
var objectStoreDeleteRequest = objectStore.delete(edit.id);
// Step 3 - We know that the onsuccess will always fire unless something serious goes wrong.
// So we go ahead and resolve the deferred here.
objectStoreDeleteRequest.onsuccess = function() {
deferred.resolve(edit);
};
objectStoreDeleteRequest.onerror = function(msg){
deferred.reject({success:false,error:msg});
}
}
},
// If there is an error in editExists()
function(){
callback(false);
});
});
//We return a deferred object so that when calling this function you can chain it with a then() statement.
//return deferred;
};
this.resetEditsQueue = function(callback)
{
console.assert(this._db !== null, "indexeddb not initialized");
@ -163,11 +267,11 @@ O.esri.Edit.EditStore = function()
var objectStore = db.transaction([objectStoreName],"readwrite").objectStore(objectStoreName);
//Get the entry associated with the graphic
var objectStoreGraphicRequest = objectStore.get(newEdit.graphic.attributes.objectid);
var objectStoreGraphicRequest = objectStore.get(newEdit.id);
objectStoreGraphicRequest.onsuccess = function() {
var graphic = objectStoreGraphicRequest.result;
if(graphic.layer == newEdit.layer){
if(graphic && (graphic.layer == newEdit.layer)){
deferred.resolve({success:true,error:null});
}
else{
@ -184,11 +288,15 @@ O.esri.Edit.EditStore = function()
return deferred;
};
/**
* Returns the approximate size of the database in bytes
* @param callback {usage, error} Whereas, the usage Object is {sizeBytes: number, editCount: number}
*/
this.getUsage = function(callback)
{
console.assert(this._db !== null, "indexeddb not initialized");
var usage = { sizeBytes: 0, attachmentCount: 0 };
var usage = { sizeBytes: 0, editCount: 0 };
var transaction = this._db.transaction([objectStoreName])
.objectStore(objectStoreName)
@ -201,18 +309,17 @@ O.esri.Edit.EditStore = function()
var cursor = event.target.result;
if(cursor)
{
console.log(cursor.value.id, cursor.value.featureId, cursor.value.objectId);
var storedObject = cursor.value;
var json = JSON.stringify(storedObject);
usage.sizeBytes += json.length;
usage.attachmentCount += 1;
usage.editCount += 1;
cursor.continue();
}
else
{
callback(usage,null);
}
}.bind(this);
};
transaction.onerror = function(err)
{
callback(null,err);
@ -292,14 +399,14 @@ O.esri.Edit.EditStore = function()
*/
this.hasPendingEdits = function()
{
// DEPRECATED at v2.5!
return "DEPRECATED at v2.5!";
};
/**
* Deprecated @ v2.5. Use public function editExists() instead.
*/
this._isEditDuplicated = function(newEdit,edits){
// DEPRECATED at v2.5!
return "DEPRECATED at v2.5!";
};
};

View File

@ -277,23 +277,92 @@ describe("Public Interface", function()
});
});
async.it("does edit already exist", function(done)
async.it("check yes edit already exists", function(done)
{
var edit = {
id: g_test.lineFeature.attributes.objectid,
operation: g_editsStore.DELETE,
layer: 2,
graphic: g_test.lineFeature.toJson()
id: 6 + "/" + g_test.pointFeature.attributes.objectid,
operation: g_editsStore.ADD,
layer: 6,
graphic: g_test.pointFeature.toJson()
};
g_editsStore.editExists(edit).then(function(result){
console.log("RESULT " + JSON.stringify(result));
console.log("RESULT does edit exist " + JSON.stringify(result));
expect(result.success).toBe(true);
done();
},function(err){
expect(err.success).toBe(true);
done();
})
});
async.it("check no edit does not exist", function(done)
{
var edit = {
id: 62 + "/" + g_test.pointFeature.attributes.objectid,
operation: g_editsStore.ADD,
layer: 62,
graphic: g_test.pointFeature.toJson()
};
g_editsStore.editExists(edit).then(function(result){
console.log("RESULT does edit exist " + JSON.stringify(result));
expect(result.success).toBe(false);
done();
},function(err){
expect(err.success).toBe(false);
done();
})
});
async.it("get all edits recursively", function(done)
{
g_editsStore.getAllEdits(function(value,message){
if(message ==="end")
{
expect(value).toBe(null);
done();
}
else{
console.log("VALUE: " + JSON.stringify(value));
}
})
});
async.it("delete an non-existing record from the database", function(done){
//Then let's delete that new entry
g_editsStore.delete(21,g_test.pointFeature,function(result){
expect(result).toBe(false); console.log("LKJ:LKJ " + result)
g_editsStore.pendingEditsCount(function(counts){
expect(counts).toBe(3);
done();
});
})
});
async.it("delete an existing record from the database", function(done){
//First we add a new entry
g_editsStore.pushEdit(g_editsStore.ADD, 22, g_test.pointFeature, function(result){
expect(result).toEqual(true);
//Then let's delete that new entry
g_editsStore.delete(22,g_test.pointFeature,function(result){
expect(result).toBe(true);
g_editsStore.pendingEditsCount(function(counts){
expect(counts).toBe(3);
done();
});
})
});
});
// it("pending edits", function()
// {
// expect(g_editsStore.hasPendingEdits()).toBeTruthy();
@ -343,8 +412,18 @@ describe("Public Interface", function()
//
});
//
// describe("Local Storage size", function()
// {
describe("Database storage size", function()
{
async.it("get size", function(done){
g_editsStore.getUsage(function(result,error){
console.log("RESULT IS " + result.sizeBytes);
expect(result).toEqual(jasmine.any(Object));
expect(result.sizeBytes).toEqual(1142);
expect(result.editCount).toEqual(3);
done();
})
})
});
// var usedBytes, totalBytes;
//
// it("reset edits queue", function()