Validate features for adds and updates

This commit is contained in:
Andy Gup 2015-03-23 15:49:07 -06:00
parent 727a82686e
commit c75bd479cd
2 changed files with 250 additions and 102 deletions

View File

@ -283,45 +283,29 @@ define([
adds.forEach(function (addEdit) {
var deferred = new Deferred();
//self._validateFeature(addEdit).then(function(result){
// console.log("HELLLLOOOO")
//});
var objectId = this._getNextTempId();
addEdit.attributes[this.objectIdField] = objectId;
var thisLayer = this;
self._editStore.pushEdit(self._editStore.ADD, this.url, addEdit, function (result, error) {
if(result == true){
results.addResults.push({success: true, error: null, objectId: objectId});
// We need to run some validation tests against each feature being added.
// If graphic doesn't exist return false and we will add a phantom graphic
// If graphic DOES exist then return true and we do not need to add a phantom graphic
this._validateFeature(addEdit,this.url,self._editStore.ADD).then(function(result){
console.log("EDIT ADD IS BACK!!! " );
var phantomAdd = new Graphic(
addEdit.geometry,
self._getPhantomSymbol(addEdit.geometry, self._editStore.ADD),
{
objectId: objectId
});
// Add phantom graphic to the layer
thisLayer._phantomLayer.add(phantomAdd);
// Add phantom graphic to the database
self._editStore.pushPhantomGraphic(phantomAdd, function (result) {
if (!result)console.log("There was a problem adding phantom graphic id: " + objectId);
console.log("Phantom graphic " + objectId + " added to database as an add.");
});
domAttr.set(phantomAdd.getNode(), "stroke-dasharray", "10,4");
domStyle.set(phantomAdd.getNode(), "pointer-events", "none");
deferred.resolve(result);
if(result.success){
thisLayer._pushValidatedAddFeatureToDB(thisLayer,addEdit,result.operation,results,objectId,deferred);
}
else{
// If we can't push edit to database then we don't create a phantom graphic
results.addResults.push({success: false, error: error, objectId: objectId});
deferred.reject(error);
// If we get here then we deleted an edit that was added offline.
// We also have deleted the phantom graphic.
deferred.resolve(true);
}
},function(error){
console.log("_validateFeature: Unable to validate!");
deferred.reject(error);
});
promises.push(deferred);
@ -336,35 +320,24 @@ define([
var thisLayer = this;
self._editStore.pushEdit(self._editStore.UPDATE, this.url, updateEdit, function (result, error) {
// We need to run some validation tests against each feature being added.
// If graphic doesn't exist return false and we will add a phantom graphic
// If graphic DOES exist then return true and we do not need to add a phantom graphic
this._validateFeature(updateEdit,this.url,self._editStore.UPDATE).then(function(result){
console.log("EDIT UPDATE IS BACK!!! " );
if(result == true){
results.updateResults.push({success: true, error: null, objectId: objectId});
var phantomUpdate = new Graphic(
updateEdit.geometry,
self._getPhantomSymbol(updateEdit.geometry, self._editStore.UPDATE),
{
objectId: objectId
});
thisLayer._phantomLayer.add(phantomUpdate);
// Add phantom graphic to the database
self._editStore.pushPhantomGraphic(phantomUpdate, function (result) {
if (!result)console.log("There was a problem adding phantom graphic id: " + objectId);
console.log("Phantom graphic " + objectId + " added to database as an update.");
});
domAttr.set(phantomUpdate.getNode(), "stroke-dasharray", "5,2");
domStyle.set(phantomUpdate.getNode(), "pointer-events", "none");
deferred.resolve(result);
if(result.success){
thisLayer._pushValidatedUpdateFeatureToDB(thisLayer,updateEdit,result.operation,results,objectId,deferred);
}
else{
// If we can't push edit to database then we don't create a phantom graphic
results.addResults.push({success: false, error: error, objectId: objectId});
deferred.reject(error);
// If we get here then we deleted an edit that was added offline.
// We also have deleted the phantom graphic.
deferred.resolve(true);
}
},function(error){
console.log("_validateFeature: Unable to validate!");
deferred.reject(error);
});
promises.push(deferred);
@ -642,6 +615,154 @@ define([
/* internal methods */
/**
* Pushes an UPDATE request to the database after it's been validated
* @param layer
* @param updateEdit
* @param operation
* @param resultsArray
* @param objectId
* @param deferred
* @private
*/
layer._pushValidatedUpdateFeatureToDB = function(layer,updateEdit,operation,resultsArray,objectId,deferred){
self._editStore.pushEdit(operation, layer.url, updateEdit, function (result, error) {
if(result == true){
resultsArray.updateResults.push({success: true, error: null, objectId: objectId});
var phantomUpdate = new Graphic(
updateEdit.geometry,
self._getPhantomSymbol(updateEdit.geometry, self._editStore.UPDATE),
{
objectId: objectId
});
layer._phantomLayer.add(phantomUpdate);
// Add phantom graphic to the database
self._editStore.pushPhantomGraphic(phantomUpdate, function (result) {
if (!result)console.log("There was a problem adding phantom graphic id: " + objectId);
console.log("Phantom graphic " + objectId + " added to database as an update.");
});
domAttr.set(phantomUpdate.getNode(), "stroke-dasharray", "5,2");
domStyle.set(phantomUpdate.getNode(), "pointer-events", "none");
deferred.resolve(result);
}
else{
// If we can't push edit to database then we don't create a phantom graphic
resultsArray.addResults.push({success: false, error: error, objectId: objectId});
deferred.reject(error);
}
});
};
/**
* Pushes an ADD request to the database after it's been validated
* @param layer
* @param addEdit
* @param operation
* @param resultsArray
* @param objectId
* @param deferred
* @private
*/
layer._pushValidatedAddFeatureToDB = function(layer,addEdit,operation,resultsArray,objectId,deferred){
self._editStore.pushEdit(operation, layer.url, addEdit, function (result, error) {
if(result == true){
resultsArray.addResults.push({success: true, error: null, objectId: objectId});
var phantomAdd = new Graphic(
addEdit.geometry,
self._getPhantomSymbol(addEdit.geometry, self._editStore.ADD),
{
objectId: objectId
});
// Add phantom graphic to the layer
layer._phantomLayer.add(phantomAdd);
// Add phantom graphic to the database
self._editStore.pushPhantomGraphic(phantomAdd, function (result) {
if (!result)console.log("There was a problem adding phantom graphic id: " + objectId);
console.log("Phantom graphic " + objectId + " added to database as an add.");
});
domAttr.set(phantomAdd.getNode(), "stroke-dasharray", "10,4");
domStyle.set(phantomAdd.getNode(), "pointer-events", "none");
deferred.resolve(result);
}
else{
// If we can't push edit to database then we don't create a phantom graphic
resultsArray.addResults.push({success: false, error: error, objectId: objectId});
deferred.reject(error);
}
});
};
/**
* Validates duplicate entries. Last edit on same feature can overwite any previous values.
* Note: if an edit was already added offline and you delete it then we return success == false
* @param graphic esri.Graphic.
* @param layerUrl the URL of the feature service
* @param operation add, update or delete action on an edit
* @returns deferred {success:boolean,graphic:graphic,operation:add|update|delete}
* @private
*/
layer._validateFeature = function (graphic,layerUrl,operation) {
var deferred = new Deferred();
var id = layerUrl + "/" + graphic.attributes.objectid;
self._editStore.getEdit(id,function(success,result){
if (success) {
switch( operation )
{
case self._editStore.ADD:
// Not good - however we'll allow the new ADD to replace/overwrite existing edit
// and pass it through unmodified. Last ADD wins.
deferred.resolve({"success":true,"graphic":graphic,"operation":operation});
break;
case self._editStore.UPDATE:
// If we are doing an update on a feature that has not been added to
// the server yet, then we need to maintain its operation as an ADD
// and not an UPDATE. This avoids the potential for an error if we submit
// an update operation on a feature that has not been added to the
// database yet.
if(result.operation = self._editStore.ADD){
graphic.operation = self._editStore.ADD;
operation = self._editStore.ADD;
}
deferred.resolve({"success":true,"graphic":graphic,"operation":operation});
break;
case self._editStore.DELETE:
if(result.operation = this._editStore.ADD){
// If we are deleting a new feature that has not been added to the
// server yet we need to delete it and its phantom graphic.
deferred.resolve({"success":false,"graphic":graphic,"operation":operation});
}
deferred.resolve({"success":true,"graphic":graphic,"operation":operation});
break;
}
}
else if(result == "Id not found"){
// Let's simply pass the graphic back as good-to-go.
// No modifications needed because the graphic does not
// already exist in the database.
deferred.resolve({"success":true,"graphic":graphic,"operation":operation});
}
else{
deferred.reject(graphic);
}
});
return deferred;
};
layer._getFilesFromForm = function (formNode) {
var files = [];
var inputNodes = array.filter(formNode.elements, function (node) {
@ -1316,52 +1437,6 @@ define([
return dfd.promise;
},
/**
* Validates duplicate entries. Last edit on same feature can overwite any previous values.
* @param edit valid internal editsStore edit object.
* @returns deferred
* @private
*/
_validateFeature: function (edit) {
var deferred = new Deferred();
this._editStore.getEdit(edit.id,function(success,result){
if (success) {
switch( edit.operation )
{
case this._editStore.ADD:
// Not good - however we'll allow the new ADD to replace existing edit
// and pass it through unmodified. Last ADD wins.
deferred.resolve(edit);
break;
case this._editStore.UPDATE:
// If we are doing an update on a feature that has not been added to
// the server yet, then we need to maintain its operation as an ADD
// and not an update. This avoids the potential for an error if we submit
// an update operation on a feature that has not been added to the
// database yet.
if(result.operation = this._editStore.ADD){
edit.operation = this._editStore.ADD;
}
deferred.resolve(edit);
break;
case this._editStore.DELETE:
if(result.operation = this._editStore.ADD){
// If we are deleting a new feature that has not been added to the
// server yet we need to delete it and its phantom graphic.
}
deferred.resolve(edit);
break;
}
}
else{
deferred.resolve(edit);
}
});
return deferred;
},
/**
* Deprecated @ v2.5. Internal-use only
* @returns {string}

View File

@ -409,9 +409,82 @@ describe("Offline Editing", function()
});
});
async.it("Update new feature offline - point", function(done){
// Let's make a change to g6 attributes
g6.attributes.additionalinformation = "TEST123";
var updates = [g6];
g_featureLayers[0].applyEdits(null,updates,null,function(addResults,updateResults,deleteResults)
{
expect(updateResults.length).toBe(1);
g_editsStore.pendingEditsCount(function(result){
// Should be the exact same as previous test
// An update to a new feature should be a single entry in the database.
// We simply update the existing entry with the new information.
expect(result).toBe(9);
done();
});
},
function(error)
{
expect(true).toBeFalsy();
});
});
async.it("validate non-existent feature - ADD", function(done){
var testGraphic = new g_modules.Graphic({"geometry":{"x":-109100,"y":5137000,"spatialReference":{"wkid":102100}},"attributes":{"symbolname":"Reference Point DLRP","z":null,"additionalinformation":null,"eny":null,"datetimevalid":null,"datetimeexpired":null,"distance":null,"azimuth":null,"uniquedesignation":null,"x":null,"y":null}} );
g_featureLayers[0]._validateFeature(testGraphic,g_featureLayers[0].url,"add")
.then(function(result){
expect(result.success).toBe(true);
expect(testGraphic).toEqual(result.graphic);
expect(result.operation).toEqual("add");
done();
},function(error){
console.log("Validate feature error: " + error);
});
});
async.it("validate existing feature - ADD", function(done){
var id = getObjectIds([g6]).toString();
expect(id).toEqual("-3");
g_featureLayers[0]._validateFeature(g6,g_featureLayers[0].url,"add")
.then(function(result){
expect(result.success).toBe(true);
expect(g6).toEqual(result.graphic);
expect(JSON.stringify(g6.toJson()) === JSON.stringify(result.graphic.toJson())).toBeTruthy();
expect(result.operation).toEqual("add");
done();
},function(error){
console.log("Validate feature error: " + error);
});
});
async.it("validate existing feature - UPDATE", function(done){
var id = getObjectIds([g6]).toString();
expect(id).toEqual("-3");
g_featureLayers[0]._validateFeature(g6,g_featureLayers[0].url,"update")
.then(function(result){
expect(result.success).toBe(true);
expect(g6).toEqual(result.graphic);
// we swap the operation type when updating an edit that hasn't
// been submitted to the server yet.
expect(result.operation).toBe("add");
expect(JSON.stringify(g6.toJson()) === JSON.stringify(result.graphic.toJson())).toBeTruthy();
expect(result.operation).toEqual("add");
done();
},function(error){
console.log("Validate feature error: " + error);
});
});
async.it("check db size", function(done){
g_featureLayers[0].getUsage(function(usage,error){
expect(usage.sizeBytes).toBe(7978);
expect(usage.sizeBytes).toBe(7982);
expect(usage.editCount).toBe(9);
expect(error).toBe(null);
done();