Commit 7d25b5ce authored by Bryan Kaperick's avatar Bryan Kaperick

allDocs method is updated to allow an options.revision_limit parameter which...

allDocs method is updated to allow an options.revision_limit parameter which allows queries on older revisions of documents.
parent 038c7a51
......@@ -26,119 +26,22 @@
type: "query",
sub_storage: spec.sub_storage
});
this._lastseen = undefined;
this.param = true;
}
BryanStorage.prototype.get = function (id_in, revision) {
BryanStorage.prototype.get = function (id_in, steps) {
// Default behavior, get() returns the most recent revision
if (revision === undefined) {
revision = {
steps: 0,
path: "absolute"
};
}
// Default type of traversal is absolute:
// "absolute" -- step backward in chronological order of changes to document
// "consistent" -- step backward in chronological order of only edits the
// most recent version is based on. Other branches of edits are ignored
if (revision.path === undefined) {
revision.path = "absolute";
}
if (revision.steps === undefined) {
revision.steps = 0;
}
if (revision.steps === 0) {
revision.path = "absolute";
if (steps === undefined) {
steps = 0;
}
// Query to get the last edit made to this document
var storage = this,
substorage = this._sub_storage,
var substorage = this._sub_storage,
options = {
query: "doc_id: " + id_in,
sort_on: [["timestamp", "descending"]]
sort_on: [["timestamp", "descending"]],
limit: [steps, 1]
};
if (revision.path === "leaves") {
return substorage.allDocs({
query: "leaf: true",
sort_on: [["timestamp", "descending"]]
})
.push(function (results) {
var promises = results.data.rows.map(function (res) {
return substorage.get(res.id);
});
return RSVP.all(promises);
})
.push(function (documents) {
var not_leaves = {},
leaves = [],
ind,
doc_data,
fix_leaves = [];
function update_leaf_state(data) {
var new_data = data;
new_data.leaf = false;
return substorage.put(data.timestamp, new_data);
}
// Loop through documents and push only leaf versions to leaves array
for (ind = 0; ind < documents.length; ind += 1) {
doc_data = documents[ind];
not_leaves[doc_data.lastseen] = true;
if (not_leaves[doc_data.timestamp] === true) {
fix_leaves.push(update_leaf_state);
} else {
if (doc_data.op === "put") {
// XXX: For cheaper evaluation, break out of the loop once
// leaves.length == revision.steps, and only fix the leaves in
// fix_leaves at that point.
// However, since we already spent time to retrieve all leaves,
// it may be better to go ahead and clean up all mislabelled
// leaves right now, so the next call to get.leaves is cheaper
leaves.push(doc_data.doc);
// revision.steps is guaranteed to be >= 1 in this branch
//
if (leaves.length - 1 === revision.steps) {
storage._lastseen = doc_data.timestamp;
}
}
}
}
// Fix all mislabelled leaves and then return the array of leaves
return RSVP.all(fix_leaves)
//XXX: Not sure why I can't use a .push here instead of .then
.then(function () {
if (leaves.length - 1 >= revision.steps) {
return leaves[revision.steps];
}
throw new jIO.util.jIOError(
"bryanstorage: there are fewer than " +
revision.steps + " leaf revisions for '" + id_in + "'",
404
);
});
});
}
// In "absolute" path, .get returns the revision.steps-most-recent revision
if (revision.path === "absolute") {
options.limit = [revision.steps, 1];
// In "consistent path, .get returns the most recent revision and looks
// deeper into history with the result's .lastseen attribute
} else if (revision.path === "consistent") {
options.limit = [0, 1];
}
return substorage.allDocs(options)
.push(function (results) {
if (results.data.rows.length > 0) {
......@@ -151,62 +54,13 @@
})
.push(function (result) {
// Function used to chain together substorage.get's for "consistent"
// traversal
function recurse_get(result) {
if (result.lastseen === undefined) {
throw new jIO.util.jIOError(
"bryanstorage: cannot find object '" +
id_in +
"' (end of history)",
404
);
}
return substorage.get(result.lastseen);
}
// If last edit was a remove, throw a 'not found' error
if (result.op === "remove" && revision.path === "absolute") {
throw new jIO.util.jIOError(
"bryanstorage: cannot find object '" + id_in + "' (removed)",
404
);
}
if (result.op === "put") {
// The query for "absolute" traversal returns exactly the document
// requested
if (revision.path === "absolute" || revision.steps === 0) {
storage._lastseen = result.timestamp;
return result.doc;
}
if (revision.path === "consistent") {
// Chain together promises to access history of document
var promise = substorage.get(result.lastseen);
while (revision.steps > 1) {
promise = promise.push(recurse_get);
revision.steps -= 1;
}
// Once at desired depth, update storage._lastseen and return doc
return promise.push(function (result) {
storage._lastseen = result.timestamp;
if (result.op === "remove") {
throw new jIO.util.jIOError(
"bryanstorage: cannot find object '" +
result.doc_id +
"' (removed)",
404
);
}
return result.doc;
});
}
return result.doc;
}
throw new jIO.util.jIOError(
"bryanstorage: cannot find object '" + id_in + "' (removed)",
404
);
});
};
......@@ -221,12 +75,9 @@
timestamp: timestamp,
doc_id: id,
doc: data,
op: "put",
lastseen: this._lastseen,
leaf: true
op: "put"
};
this._lastseen = timestamp;
//console.log(metadata.doc.k, timestamp, metadata.lastseen);
return this._sub_storage.put(timestamp, metadata);
};
......@@ -236,12 +87,8 @@
// XXX: remove this attribute once query can sort_on id
timestamp: timestamp,
doc_id: id,
op: "remove",
lastseen: this._lastseen,
leaf: true
op: "remove"
};
this._lastseen = timestamp;
//console.log("removed", timestamp, metadata.lastseen);
return this._sub_storage.put(timestamp, metadata);
};
......@@ -297,7 +144,6 @@
});
};
// Not implemented for IndexedDB
BryanStorage.prototype.repair = function () {
return this._sub_storage.repair.apply(this._sub_storage, arguments);
};
......@@ -306,13 +152,22 @@
};
BryanStorage.prototype.buildQuery = function (options) {
if (options === undefined) {
options = {};
}
if (options.sort_on === undefined) {
options.sort_on = [];
}
options.sort_on.push(["timestamp", "descending"]);
if (options.limit === undefined) {
options.limit = [0, -1];
}
options.sort_on.push(["timestamp", "descending"]);
// Default behavior is to return only the latest revision of each document
if (options.revision_limit === undefined) {
options.revision_limit = [0, 1];
}
var meta_options = {
// XXX: I don't believe it's currently possible to query on sub-attributes
// so for now, we just use the inputted query, which obviously will fail
......@@ -327,36 +182,52 @@
first_doc = options.limit[0];
return this._sub_storage.allDocs(meta_options)
// Get all documents found in query
.push(function (results) {
var promises = results.data.rows.map(function (data) {
return substorage.get(data.id);
});
return RSVP.all(promises);
})
.push(function (results_array) {
var clean_data = [],
ind,
seen_docs = [],
seen_docs = {},
current_doc,
counter = 0;
// Default behavior is to not limit the number of documents returned
if (max_num_docs === -1) {
max_num_docs = results_array.length;
}
for (ind = 0; ind < results_array.length; ind += 1) {
current_doc = results_array[ind];
// Initialize count of revisions
if (!seen_docs.hasOwnProperty(current_doc.doc_id)) {
seen_docs[current_doc.doc_id] = 0;
}
// If the latest version of this document has not yet been
// included in query result
if (seen_docs[current_doc.doc_id] !== true) {
if (options.revision_limit[0] <= seen_docs[current_doc.doc_id] &&
seen_docs[current_doc.doc_id] < options.revision_limit[0] +
options.revision_limit[1]) {
// If the latest edit was a put operation, add it to query
// If the latest edit was a put operation, add it to query
// results
if (current_doc.op === "put") {
if (counter >= first_doc) {
// Note the rev attribute added to the output data.
// This guarantees that `this.get(id, rev) === doc`
clean_data.push({
doc: {},
doc: current_doc.doc,
value: {},
id: current_doc.doc_id
id: current_doc.doc_id,
rev: seen_docs[current_doc.doc_id]
});
if (clean_data.length === max_num_docs) {
return clean_data;
......@@ -364,9 +235,9 @@
}
counter += 1;
}
// Mark document as read so no older edits are considered
seen_docs[current_doc.doc_id] = true;
}
// Keep track of how many times this doc_id has been seen
seen_docs[current_doc.doc_id] += 1;
}
// In passing results back to allDocs, formatting of query is handled
return clean_data;
......
......@@ -83,9 +83,7 @@
title: "foo0"
},
timestamp: results.timestamp,
op: "put",
lastseen: undefined,
leaf: true
op: "put"
}, "The first item in the log is pushing bar's title to 'foo0'");
return jio.remove("bar");
})
......@@ -119,9 +117,7 @@
deepEqual(result, {
doc_id: "bar",
timestamp: result.timestamp,
op: "remove",
lastseen: result.lastseen,
leaf: true
op: "remove"
});
})
.fail(function (error) {
......@@ -291,7 +287,7 @@
test("Testing proper retrieval of older revisions of documents",
function () {
stop();
expect(8);
expect(12);
// create storage of type "bryan" with memory as substorage
var jio = jIO.createJIO({
......@@ -303,13 +299,47 @@
}
}
});
jio.put("doc", {
"k0": "v0"
})
jio.get("doc")
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"Document does not exist yet.");
})
.push(function () {
return jio.put("doc", {
"k0": "v0"
});
})
.push(function () {
return jio.get("doc", 0);
})
.push(function (result) {
deepEqual(result, {
"k0": "v0"
});
})
.push(function () {
return jio.put("doc", {"k1": "v1"});
})
.push(function () {
return jio.get("doc", 0);
})
.push(function (result) {
deepEqual(result, {
"k1": "v1"
});
})
.push(function () {
return jio.get("doc", 1);
})
.push(function (result) {
deepEqual(result, {
"k0": "v0"
});
})
.push(function () {
return jio.put("doc", {"k2": "v2"});
})
......@@ -329,19 +359,19 @@
deepEqual(result,
{"k4": "v4"},
"By default, .get returns latest revision");
return jio.get("doc", {steps: 0});
return jio.get("doc", 0);
})
.push(function (result) {
deepEqual(result,
{"k4": "v4"},
".get returns latest revision with second input = 0");
return jio.get("doc", {steps: 1});
return jio.get("doc", 1);
})
.push(function (result) {
deepEqual(result,
{"k3": "v3"},
"Walk back one revision with second input = 1");
return jio.get("doc", {steps: 2});
return jio.get("doc", 2);
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
......@@ -350,25 +380,25 @@
deepEqual(error.status_code,
404,
"Current state of document is 'removed'.");
return jio.get("doc", {steps: 3});
return jio.get("doc", 3);
})
.push(function (result) {
deepEqual(result,
{"k2": "v2"},
"Walk back three revisions with second input = 3");
return jio.get("doc", {steps: 4});
return jio.get("doc", 4);
})
.push(function (result) {
deepEqual(result,
{"k1": "v1"},
"Walk back four revisions with second input = 4");
return jio.get("doc", {steps: 5});
return jio.get("doc", 5);
})
.push(function (result) {
deepEqual(result,
{"k0": "v0"},
"Walk back five revisions with second input = 5");
return jio.get("doc", {steps: 6});
return jio.get("doc", 6);
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
......@@ -386,38 +416,18 @@
});
/////////////////////////////////////////////////////////////////
// Accessing older revisions with multiple users
// Accessing older revisions with two users
/////////////////////////////////////////////////////////////////
module("bryanStorage.accessing_older_revisions_multiple_users");
test("Testing retrieval of older revisions of documents with multiple users",
module("bryanStorage.querying_old_revisions");
test("Testing retrieval of older revisions via allDocs calls",
function () {
stop();
expect(51);
expect(47);
// create storage of type "bryan" with memory as substorage
var dbname = "multi_user_db" + Date.now(),
jio1 = jIO.createJIO({
type: "bryan",
sub_storage: {
type: "uuid",
sub_storage: {
type: "indexeddb",
database: dbname
}
}
}),
jio2 = jIO.createJIO({
type: "bryan",
sub_storage: {
type: "uuid",
sub_storage: {
type: "indexeddb",
database: dbname
}
}
}),
jio3 = jIO.createJIO({
var dbname = "db-" + Date.now(),
jio = jIO.createJIO({
type: "bryan",
sub_storage: {
type: "uuid",
......@@ -427,696 +437,239 @@
}
}
});
jio1.put("doc", {
"k": "v0.1"
jio.put("doc", {
"k": "v0"
})
.push(function () {
return jio2.get("doc");
})
.push(function () {
return jio3.get("doc");
})
.push(function () {
return jio2.put("doc", {
"k": "v0.1.2"
return jio.put("doc", {
"k": "v1"
});
})
.push(function () {
return jio3.put("doc", {
"k": "v0.1.3"
});
})
/**
.push(function () {
return jio2.put("doc", {
"k": "v0.1.2.2"
});
})
**/
.push(function () {
return jio2.remove("doc");
})
.push(function () {
return jio3.put("doc", {
"k": "v0.1.3.3"
});
})
.push(function () {
return jio1.get("doc");
})
.push(function () {
return jio1.put("doc", {
"k": "v0.1.3.3.1"
return jio.put("doc", {
"k": "v2"
});
})
.push(function () {
return jio2.put("doc", {
"k": "v0.1.2.2.2"
return jio.put("doc", {
"k": "v3"
});
})
.push(function () {
return jio3.put("doc", {
"k": "v0.1.3.3.3"
});
})
.push(function () {
return jio1.get("doc");
})
// jio2 has a different version than 1 & 3 as its latest revision
/**
.push(function () {
return jio2.get("doc");
})
**/
.push(function () {
return jio3.get("doc");
})
// Test all lastseens are the same
.push(function () {
// These are all undefined outside the storage definition, so these
// tests are meaningless
//equal(jio1._lastseen, jio2._lastseen, "All users see same version");
//equal(jio1._lastseen, jio3._lastseen, "All users see same version");
//
// Test consistent history of user 1
//
return jio1.get("doc", {
path: "consistent",
steps: 0
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
}, "Get of depth 0 returns latest version"
);
return jio1.get("doc", {
path: "consistent",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3"
}, "Get of consistent depth 1 returns correct version"
);
return jio1.get("doc", {
path: "consistent",
steps: 2
return jio.allDocs({
query: "",
revision_limit: [0, 1]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3"
}, "Get of consistent depth 2 returns correct version"
);
return jio1.get("doc", {
path: "consistent",
steps: 3
});
.push(function (results) {
deepEqual(results.data.rows.length,
1,
"Only one query returned with options.revision_limit == [0,1]");
return jio.get(results.data.rows[0].id);
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
}, "Get of consistent depth 3 returns correct version"
);
return jio1.get("doc", {
path: "consistent",
steps: 4
"k": "v3"
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only 3 previous states of this document: " + error);
})
.push(function () {
//
// Test consistent history of user 2 (Is the same as 1 & 3 even though
// User 2 has not explicitly called .get since the latest changes
// were made)
//
return jio2.get("doc", {
path: "consistent",
steps: 0
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
}, "Get of depth 0 returns latest version"
);
return jio2.get("doc", {
path: "consistent",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3"
}, "Get of depth 0 returns latest version"
);
return jio2.get("doc", {
path: "consistent",
steps: 2
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3"
}, "Get of consistent depth 2 returns correct version"
);
return jio2.get("doc", {
path: "consistent",
steps: 3
return jio.allDocs({
query: "",
revision_limit: [1, 1]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
}, "Get of consistent depth 3 returns correct version"
);
return jio2.get("doc", {
path: "consistent",
steps: 4
.push(function (results) {
deepEqual(results.data.rows.length,
1,
"Only one query returned with options.revision_limit == [1,1]");
deepEqual(results.data.rows[0].doc, {
"k": "v2"
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only 3 previous states of this document: " + error);
})
.push(function () {
//
// Test consistent history of user 3 (Should be same as user 1)
//
return jio3.get("doc", {
path: "consistent",
steps: 0
return jio.allDocs({
query: "",
revision_limit: [2, 1]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
}, "User 2 consistent history is same as user 1"
);
return jio3.get("doc", {
path: "consistent",
steps: 1
.push(function (results) {
deepEqual(results.data.rows.length,
1,
"Only one query returned with options.revision_limit == [2,1]");
deepEqual(results.data.rows[0].doc, {
"k": "v1"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3"
}, "User 2 consistent history is same as user 1"
);
return jio3.get("doc", {
path: "consistent",
steps: 2
return jio.allDocs({
query: "",
revision_limit: [3, 1]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3"
}, "User 2 consistent history is same as user 1"
);
return jio3.get("doc", {
path: "consistent",
steps: 3
.push(function (results) {
deepEqual(results.data.rows.length,
1,
"Only one query returned with options.revision_limit == [3,1]");
deepEqual(results.data.rows[0].doc, {
"k": "v0"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
}, "User 2 consistent history is same as user 1"
);
return jio3.get("doc", {
path: "consistent",
steps: 4
return jio.allDocs({
query: "",
revision_limit: [4, 1]
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only 3 previous states of this document");
})
// Reset jio3._lastseen to be at v0.1.3.3.3
.push(function () {
return jio3.get("doc");
.push(function (results) {
equal(results.data.rows.length, 0, "Past all previous revisions");
})
//
// Test absolute history of user 1
//
.push(function () {
return jio1.get("doc", {
path: "absolute",
steps: 0
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
}, "Get of absolute depth 0 returns latest version"
);
return jio1.get("doc", {
path: "absolute",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2"
}, "Get of absolute depth 1 returns correct version"
);
return jio1.get("doc", {
path: "absolute",
steps: 2
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.1"
}, "Get of absolute depth 2 returns correct version"
);
return jio1.get("doc", {
path: "absolute",
steps: 3
return jio.allDocs({
revision_limit: [0, 2]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3"
}, "Get of absolute depth 3 returns correct version"
);
return jio1.get("doc", {
path: "absolute",
steps: 4
.push(function (results) {
equal(results.data.rows.length, 2);
deepEqual(results.data.rows[0].doc, {
"k": "v3"
}, "Only retrieve two most recent revions");
deepEqual(results.data.rows[1].doc, {
"k": "v2"
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"Document has been removed at this point");
return jio1.get("doc", {
path: "absolute",
steps: 5
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3"
}, "Get of absolute depth 5 returns correct version"
);
return jio1.get("doc", {
path: "absolute",
steps: 6
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2"
}, "Get of absolute depth 6 returns correct version"
);
return jio1.get("doc", {
path: "absolute",
steps: 7
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
});
return jio1.get("doc", {
path: "absolute",
steps: 8
});
return jio.remove("doc");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only 3 previous states of this document");
})
//
// Test absolute history of user 2
//
.push(function () {
return jio2.get("doc", {
path: "absolute",
steps: 0
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
});
return jio2.get("doc", {
path: "absolute",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2"
});
return jio2.get("doc", {
path: "absolute",
steps: 2
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.1"
});
return jio2.get("doc", {
path: "absolute",
steps: 3
return jio.allDocs({
query: "",
revision_limit: [0, 1]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3"
});
return jio2.get("doc", {
path: "absolute",
steps: 4
});
.push(function (results) {
equal(results.data.rows.length, 0,
"Query does not return removed doc");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"Document has been removed at this point");
return jio2.get("doc", {
path: "absolute",
steps: 5
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3"
});
return jio2.get("doc", {
path: "absolute",
steps: 6
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2"
});
return jio2.get("doc", {
path: "absolute",
steps: 7
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
});
return jio2.get("doc", {
path: "absolute",
steps: 8
return jio.allDocs({
query: "",
revision_limit: [1, 3]
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only 3 previous states of this document");
})
//
// Tests on checking out an older revision and making a new edit branch
//
.push(function () {
return jio1.get("doc", {
path: "absolute",
steps: 1
});
.push(function (results) {
equal(results.data.rows.length, 3);
deepEqual(results.data.rows[0].doc, {
"k": "v3"
}, "1st, 2nd, and 3rd versions removed from current are retrieved");
deepEqual(results.data.rows[1].doc, {
"k": "v2"
}, "1st, 2nd, and 3rd versions removed from current are retrieved");
deepEqual(results.data.rows[2].doc, {
"k": "v1"
}, "1st, 2nd, and 3rd versions removed from current are retrieved");
})
.push(function () {
return jio1.put("doc", {
"k": "v0.1.2.2.2.1"
return jio.put("doc2", {
"k2": "w0"
});
})
.push(function () {
return jio1.get("doc", {
path: "consistent",
steps: 1
return jio.allDocs({
revision_limit: [1, 3]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2"
}, "The new document is added to the correct edit branch"
);
return jio1.get("doc", {
path: "consistent",
steps: 2
});
.push(function (results) {
equal(results.data.rows.length, 3);
deepEqual(results.data.rows[0].doc, {
"k": "v3"
}, "Does not retrieve new document outside queried revision range");
deepEqual(results.data.rows[1].doc, {
"k": "v2"
}, "Does not retrieve new document outside queried revision range");
deepEqual(results.data.rows[2].doc, {
"k": "v1"
}, "Does not retrieve new document outside queried revision range");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"This document was removed at this time");
return jio1.get("doc", {
path: "consistent",
steps: 3
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2"
}, "The new document is added to the correct edit branch"
);
return jio1.get("doc", {
path: "consistent",
steps: 4
return jio.allDocs({
revision_limit: [0, 2]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
}, "This edit branch also leads back to the original version"
);
return jio1.get("doc", {
path: "consistent",
steps: 5
});
.push(function (results) {
equal(results.data.rows.length, 2);
deepEqual(results.data.rows[0].doc, {
"k2": "w0"
}, "Retrieves all documents with versions in queried revision range");
deepEqual(results.data.rows[1].doc, {
"k": "v3"
}, "Retrieves all documents with versions in queried revision range");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are no revisions before the original document");
})
.push(function () {
return jio3.put("doc", {
"k": "v0.1.3.3.3.3"
return jio.put("doc2", {
"k2": "w1"
});
})
// All three users have the same latest revision
.push(function () {
return jio1.get("doc");
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "User one accesses latest revision correctly"
);
return jio2.get("doc");
return jio.allDocs();
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "User two accesses latest revision correctly"
);
return jio3.get("doc");
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "User three accesses latest revision correctly"
);
return jio2.get("doc", {
path: "consistent",
steps: 1
.push(function (results) {
equal(results.data.rows.length, 1,
"There is only one non-removed doc");
equal(results.data.rows[0].rev, 0);
deepEqual(results.data.rows[0].doc, {
"k2": "w1"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
}, "User 2 accesses the 1st edit in consistent traversal."
);
})
//
// Testing .getting on leaf nodes
//
.push(function () {
return jio1.get("doc", {
path: "leaves"
});
return jio.remove("doc2");
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "First result is the most-recently-added leaf"
);
return jio2.get("doc", {
path: "leaves",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2.1"
}, "Second result is the 2nd most-recently-added leaf"
);
return jio3.get("doc", {
path: "leaves",
steps: 2,
db: "jio3"
.push(function () {
return jio.allDocs({
revision_limit: [0, 4]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.1"
}, "Third result is the 3rd most-recently-added leaf"
);
//
// Editing document revisions stemming from the latest leaf nodes seen
//
return jio1.put("doc", {
"k": "v0.1.3.3.3.3.1"
.push(function (results) {
equal(results.data.rows.length, 5);
equal(results.data.rows[0].rev, 1, "Rev parameter is correct");
equal(results.data.rows[1].rev, 2, "Rev parameter is correct");
equal(results.data.rows[2].rev, 1, "Rev parameter is correct");
equal(results.data.rows[3].rev, 2, "Rev parameter is correct");
equal(results.data.rows[4].rev, 3, "Rev parameter is correct");
deepEqual(results.data.rows[0].doc, {
"k2": "w1"
});
})
.push(function () {
return jio3.remove("doc"); // removing v0.1.3.3.1
})
// Check that jio1 sees latest non-removed revision
.push(function () {
return jio1.get("doc");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"The most recent edit was a remove, so throw error");
})
.push(function () {
// jio2 lastseen should point to "v0.1.2.2.2.1"
return jio2.put("doc", {
"k": "v0.1.2.2.2.1.2"
deepEqual(results.data.rows[1].doc, {
"k2": "w0"
});
})
.push(function () {
return jio1.get("doc", {
path: "leaves",
steps: 0
deepEqual(results.data.rows[2].doc, {
"k": "v3"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2.1.2"
}, "Accessing the first leaf node at this time"
);
return jio1.get("doc", {
path: "leaves",
steps: 1
deepEqual(results.data.rows[3].doc, {
"k": "v2"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3.1"
}, "Accessing the second leaf node at this time"
);
return jio1.get("doc", {
path: "leaves",
steps: 2
deepEqual(results.data.rows[4].doc, {
"k": "v1"
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only two non-removed leaves");
// jio1 should still have lastseen at v0.1.3.3.3.3.1
return jio1.put("doc", {
"k": "v0.1.3.3.3.3.1.1"
});
})
.push(function () {
return jio1.get("doc", {
path: "consistent",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3.1"
}, "If a .get fails, that should not reset ._lastseen parameter"
);
return jio1.get("doc", {
path: "consistent",
steps: 2
return jio.allDocs({
limit: [1, 4],
revision_limit: [0, 4]
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "History of 0.1.2.2.2 has been constructed correctly.");
.push(function (results) {
equal(results.data.rows.length, 4,
"Correct number of results with options.limit set");
equal(results.data.rows[0].rev, 2, "Rev parameter is correct");
equal(results.data.rows[1].rev, 1, "Rev parameter is correct");
equal(results.data.rows[2].rev, 2, "Rev parameter is correct");
equal(results.data.rows[3].rev, 3, "Rev parameter is correct");
deepEqual(results.data.rows[0].doc, {
"k2": "w0"
}, "Correct results with options.limit set");
deepEqual(results.data.rows[1].doc, {
"k": "v3"
}, "Correct results with options.limit set");
deepEqual(results.data.rows[2].doc, {
"k": "v2"
}, "Correct results with options.limit set");
deepEqual(results.data.rows[3].doc, {
"k": "v1"
}, "Correct results with options.limit set");
})
.fail(function (error) {
//console.log(error);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment