refactoring costco to support bulk deletions and better functional transform error handling

This commit is contained in:
Max Ogden
2011-07-21 18:52:52 -07:00
parent dc85be81d5
commit 30d320f8d9
4 changed files with 103 additions and 41 deletions

View File

@@ -69,6 +69,7 @@
<script type='text/mustache' class="columnActionsTemplate"> <script type='text/mustache' class="columnActionsTemplate">
<li><a data-action="bulkEdit" class="menuAction" href="JavaScript:void(0);">Transform...</a></li> <li><a data-action="bulkEdit" class="menuAction" href="JavaScript:void(0);">Transform...</a></li>
<li><a data-action="deleteColumn" class="menuAction" href="JavaScript:void(0);">Delete this column</a></li>
</script> </script>
<script type='text/mustache' class="titleTemplate"><span id="project-name-button" class="app-path-section">{{db_name}}</span></script> <script type='text/mustache' class="titleTemplate"><span id="project-name-button" class="app-path-section">{{db_name}}</span></script>

View File

@@ -3,60 +3,117 @@
var costco = function() { var costco = function() {
function handleEditorChange(e) { function handleEditorChange(e) {
mapDocs(app.cache, e.target.value, true); var editFunc = evalFunction(e.target.value);
} var errors = $('.expression-preview-parsing-status');
if (_.isFunction(editFunc)) {
function mapDocs(docs, funcString, preview) { errors.text('No syntax error.');
if(preview) var errors = $('.expression-preview-parsing-status'); } else {
try { errors.text(editFunc);
eval("var editFunc = " + funcString);
if(preview) errors.text('No syntax error.');
} catch(e) {
if(preview) errors.text(e+"");
return; return;
} }
previewTransform(app.cache, editFunc);
}
var toUpdate = [] function evalFunction(funcString) {
, deleted = 0 try {
, edited = 0 eval("var editFunc = " + funcString);
, failed = 0 return editFunc;
} catch(e) {
return e+"";
}
}
function previewTransform(docs, editFunc) {
var preview = [];
var updated = mapDocs(docs, editFunc);
for (var i = 0; i < updated.docs.length; i++) {
var before = docs[i]
, after = updated.docs[i]
;
if (!after) after = {};
preview.push({before: JSON.stringify(before[app.currentColumn]), after: JSON.stringify(after[app.currentColumn])});
}
util.render('editPreview', 'expression-preview-container', {rows: preview});
}
function mapDocs(docs, editFunc) {
var edited = []
, deleted = []
, failed = []
; ;
if(preview) var preview = []; var updatedDocs = _.map(docs, function(doc) {
_.each(docs, function(doc) {
try { try {
var updated = editFunc(_.clone(doc)); var updated = editFunc(_.clone(doc));
} catch(e) { } catch(e) {
failed++; // ignore if it throws on this doc failed.push(doc);
return; return;
} }
if(updated === null) { if(updated === null) {
doc._deleted = true; updated = {_deleted: true};
toUpdate.push(doc); edited.push(updated);
deleted++; deleted.push(doc);
} }
else if(updated && !_.isEqual(updated, doc)) { else if(updated && !_.isEqual(updated, doc)) {
toUpdate.push(updated); edited.push(updated);
edited++;
} }
return updated;
if(preview) preview.push({before: JSON.stringify(doc[app.currentColumn]), after: JSON.stringify(updated[app.currentColumn])});
}); });
if(preview) util.render('editPreview', 'expression-preview-container', {rows: preview}); return {
return toUpdate; edited: edited,
docs: updatedDocs,
deleted: deleted,
failed: failed
};
} }
function updateDocs(docs, callback) { function updateDocs(editFunc) {
if(!docs.length) var dfd = $.Deferred();
return callback("Failed to update"); util.notify("Updating documents...", {persist: true, loader: true});
couch.request({url: app.baseURL + "api/_bulk_docs", type: "POST", data: JSON.stringify({docs: docs})}).then(callback); couch.request({url: app.baseURL + "api/json"}).then(function(docs) {
var toUpdate = costco.mapDocs(docs.docs, editFunc).edited;
costco.uploadDocs(toUpdate).then(
function(updatedDocs) {
util.notify(updatedDocs.length + " documents updated successfully");
recline.fetchRows(false, app.offset);
dfd.resolve(updatedDocs);
},
function(err) {
util.notify("Errorz! " + err);
dfd.reject(err);
}
);
});
return dfd.promise();
}
function uploadDocs(docs) {
var dfd = $.Deferred();
if(!docs.length) dfd.resolve("Failed to update");
couch.request({url: app.baseURL + "api/_bulk_docs", type: "POST", data: JSON.stringify({docs: docs})})
.then(
dfd.resolve,
function(err) { dfd.reject(err.responseText) }
);
return dfd.promise();
}
function deleteColumn(name) {
var deleteFunc = function(doc) {
delete doc[name];
return doc;
}
return updateDocs(deleteFunc);
} }
return { return {
handleEditorChange: handleEditorChange, handleEditorChange: handleEditorChange,
evalFunction: evalFunction,
previewTransform: previewTransform,
mapDocs: mapDocs, mapDocs: mapDocs,
updateDocs: updateDocs updateDocs: updateDocs,
uploadDocs: uploadDocs,
deleteColumn: deleteColumn
}; };
}(); }();

View File

@@ -23,7 +23,12 @@ var recline = function() {
json: function() { window.location.href = "_rewrite/api/json" }, json: function() { window.location.href = "_rewrite/api/json" },
urlImport: function() { showDialog('urlImport') }, urlImport: function() { showDialog('urlImport') },
pasteImport: function() { showDialog('pasteImport') }, pasteImport: function() { showDialog('pasteImport') },
uploadImport: function() { showDialog('uploadImport') } uploadImport: function() { showDialog('uploadImport') },
deleteColumn: function() {
var msg = "Are you sure? This will delete '" + app.currentColumn + "' from all documents.";
if (confirm(msg)) costco.deleteColumn(app.currentColumn);
util.hide('menu');
}
} }
actions[$(e.target).attr('data-action')](); actions[$(e.target).attr('data-action')]();

View File

@@ -113,15 +113,13 @@ app.after = {
$('.dialog-content .okButton').click(function(e) { $('.dialog-content .okButton').click(function(e) {
var funcText = $('.expression-preview-code').val(); var funcText = $('.expression-preview-code').val();
var editFunc = costco.evalFunction(funcText);
if (!_.isFunction(editFunc)) {
util.notify("Error with function! " + editFunc);
return;
}
util.hide('dialog'); util.hide('dialog');
util.notify("Updating documents...", {persist: true, loader: true}); costco.updateDocs(editFunc);
couch.request({url: app.baseURL + "api/json"}).then(function(docs) {
var toUpdate = costco.mapDocs(docs.docs, funcText);
costco.updateDocs(toUpdate, function(msg) {
util.notify(msg.length + " documents updated successfully");
recline.fetchRows(false, app.offset);
});
});
}) })
var editor = $('.expression-preview-code'); var editor = $('.expression-preview-code');
@@ -160,5 +158,6 @@ app.sammy = $.sammy(function () {
}); });
$(function() { $(function() {
util.traverse = require('traverse');
app.sammy.run(); app.sammy.run();
}) })