Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

(#589) fix phonegap/cordova adapter api not filling bug #653

Closed
wants to merge 10 commits into from

5 participants

Howon Lee Dale  Harvey Ben Tomasz Kołodziejski Nick Thompson
Howon Lee

Note that usage should be something like:

var database;
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady(){
    Pouch('listoutfitter', {phonegap: true}, function (err, db) {
        if (err) {
            console.log("Error while creating database: " + err)
            for( var e in err) {
                console.log("Error element: " + e + " -> "  + err[e]);
            }
            return;
        }
        console.log("Successfully made new database");
        database = db;
        db.post({_id: 'doc1', title: 'Cony Island Baby' }, {}, function (err, response) {
            console.log("created doc: " + response.ok);
            console.log("doc id:  " + response.id)
            console.log("rev: " + response.rev)
        })
    });
};

First, note that we must create and use the db inside an onDeviceReady() function, because we use websql which only becomes available to us after the deviceready event.
Second, note that we pass the phonegap: true option.

Howon Lee

I don't have any idea of how to test this

Dale  Harvey
Owner

So I would like to hide a lot of this from end users, we already have a taskqueue so we can delay setup, and seems like we should be able to feature detect being inside phonegap.

Why does the setup function need delayed until after the pouch.adapter is constructed?

And by test do you mean to set up a single test to very its all working or automated? yeh I dont think the automated tests are going to be easy but will ask around

Howon Lee howonlee closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
4 src/adapters/pouch.http.js
View
@@ -646,6 +646,10 @@ var HttpPouch = function(opts, callback) {
params.push('conflicts=true');
}
+ if (opts.limit || opts.limit === 0) {
+ params.push('limit=' + opts.limit);
+ }
+
// If opts.descending exists, add the descending value to the query string.
// if descending=true then the change results are returned in
// descending order (most recent change first).
22 src/adapters/pouch.idb.js
View
@@ -715,11 +715,23 @@ var IdbPouch = function(opts, callback) {
function fetchChanges() {
txn = idb.transaction([DOC_STORE, BY_SEQ_STORE]);
txn.oncomplete = onTxnComplete;
- var req = descending ?
- txn.objectStore(BY_SEQ_STORE)
- .openCursor(IDBKeyRange.lowerBound(opts.since, true), descending) :
- txn.objectStore(BY_SEQ_STORE)
- .openCursor(IDBKeyRange.lowerBound(opts.since, true));
+
+ var req;
+
+ if (opts.limit && descending) {
+ req = txn.objectStore(BY_SEQ_STORE)
+ .openCursor(IDBKeyRange.bound(opts.since, opts.since + opts.limit, true), descending);
+ } else if (opts.limit && !descending) {
+ req = txn.objectStore(BY_SEQ_STORE)
+ .openCursor(IDBKeyRange.bound(opts.since, opts.since + opts.limit, true));
+ } else if (descending) {
+ req = txn.objectStore(BY_SEQ_STORE)
+ .openCursor(IDBKeyRange.lowerBound(opts.since, true), descending);
+ } else {
+ req = txn.objectStore(BY_SEQ_STORE)
+ .openCursor(IDBKeyRange.lowerBound(opts.since, true));
+ }
+
req.onsuccess = onsuccess;
req.onerror = onerror;
}
6 src/adapters/pouch.leveldb.js
View
@@ -157,7 +157,7 @@ var LevelPouch = function(opts, callback) {
api._info = function(callback) {
return call(callback, null, {
- name: opts.name,
+ db_name: opts.name,
doc_count: doc_count,
update_seq: update_seq
});
@@ -606,6 +606,10 @@ var LevelPouch = function(opts, callback) {
streamOpts.start = opts.since ? opts.since + 1 : 0;
}
+ if (opts.limit) {
+ streamOpts.limit = opts.limit;
+ }
+
var changeStream = stores[BY_SEQ_STORE].readStream(streamOpts);
changeStream
.on('data', function(data) {
86 src/adapters/pouch.websql.js
View
@@ -1,5 +1,6 @@
/*globals call: false, extend: false, parseDoc: false, Crypto: false */
/*globals isLocalId: false, isDeleted: false, Changes: false, filterChange: false */
+/*global isCordova*/
'use strict';
@@ -46,42 +47,51 @@ var webSqlPouch = function(opts, callback) {
callback(null, api);
}
- db.transaction(function (tx) {
- var meta = 'CREATE TABLE IF NOT EXISTS ' + META_STORE +
- ' (update_seq, dbid)';
- var attach = 'CREATE TABLE IF NOT EXISTS ' + ATTACH_STORE +
- ' (digest, json, body BLOB)';
- var doc = 'CREATE TABLE IF NOT EXISTS ' + DOC_STORE +
- ' (id unique, seq, json, winningseq)';
- var seq = 'CREATE TABLE IF NOT EXISTS ' + BY_SEQ_STORE +
- ' (seq INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, doc_id_rev UNIQUE, json)';
-
- tx.executeSql(attach);
- tx.executeSql(doc);
- tx.executeSql(seq);
- tx.executeSql(meta);
-
- var updateseq = 'SELECT update_seq FROM ' + META_STORE;
- tx.executeSql(updateseq, [], function(tx, result) {
- if (!result.rows.length) {
- var initSeq = 'INSERT INTO ' + META_STORE + ' (update_seq) VALUES (?)';
- var newId = Math.uuid();
- tx.executeSql(initSeq, [0]);
- return;
- }
- update_seq = result.rows.item(0).update_seq;
- });
- var dbid = 'SELECT dbid FROM ' + META_STORE;
- tx.executeSql(dbid, [], function(tx, result) {
- if (!result.rows.length) {
- var initDb = 'INSERT INTO ' + META_STORE + ' (dbid) VALUES (?)';
- var newId = Math.uuid();
- tx.executeSql(initDb, [newId]);
- return;
- }
- instanceId = result.rows.item(0).dbid;
- });
- }, unknownError(callback), dbCreated);
+ function setup(){
+ db.transaction(function (tx) {
+ var meta = 'CREATE TABLE IF NOT EXISTS ' + META_STORE +
+ ' (update_seq, dbid)';
+ var attach = 'CREATE TABLE IF NOT EXISTS ' + ATTACH_STORE +
+ ' (digest, json, body BLOB)';
+ var doc = 'CREATE TABLE IF NOT EXISTS ' + DOC_STORE +
+ ' (id unique, seq, json, winningseq)';
+ var seq = 'CREATE TABLE IF NOT EXISTS ' + BY_SEQ_STORE +
+ ' (seq INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, doc_id_rev UNIQUE, json)';
+
+ tx.executeSql(attach);
+ tx.executeSql(doc);
+ tx.executeSql(seq);
+ tx.executeSql(meta);
+
+ var updateseq = 'SELECT update_seq FROM ' + META_STORE;
+ tx.executeSql(updateseq, [], function(tx, result) {
+ if (!result.rows.length) {
+ var initSeq = 'INSERT INTO ' + META_STORE + ' (update_seq) VALUES (?)';
+ var newId = Math.uuid();
+ tx.executeSql(initSeq, [0]);
+ return;
+ }
+ update_seq = result.rows.item(0).update_seq;
+ });
+ var dbid = 'SELECT dbid FROM ' + META_STORE;
+ tx.executeSql(dbid, [], function(tx, result) {
+ if (!result.rows.length) {
+ var initDb = 'INSERT INTO ' + META_STORE + ' (dbid) VALUES (?)';
+ var newId = Math.uuid();
+ tx.executeSql(initDb, [newId]);
+ return;
+ }
+ instanceId = result.rows.item(0).dbid;
+ });
+ }, unknownError(callback), dbCreated);
+ }
+ if (isCordova()){
+ //to wait until custom api is made in pouch.adapters before doing setup
+ window.addEventListener(name + "_pouch", setup, false);
+ } else {
+ setup();
+ }
+
api.type = function() {
return 'websql';
@@ -575,6 +585,10 @@ var webSqlPouch = function(opts, callback) {
DOC_STORE + '.winningseq WHERE ' + DOC_STORE + '.seq > ' + opts.since +
' ORDER BY ' + DOC_STORE + '.seq ' + (descending ? 'DESC' : 'ASC');
+ if (opts.limit) {
+ sql += ' LIMIT ' + opts.limit;
+ }
+
db.transaction(function(tx) {
tx.executeSql(sql, [], function(tx, result) {
for (var i = 0, l = result.rows.length; i < l; i++ ) {
16 src/plugins/pouchdb.mapreduce.js
View
@@ -25,9 +25,6 @@ var MapReduce = function(db) {
options.reduce = false;
}
- // Including conflicts
- options.conflicts = true;
-
function sum(values) {
return values.reduce(function(a, b) { return a + b; }, 0);
}
@@ -75,10 +72,6 @@ var MapReduce = function(db) {
eval('fun.reduce = ' + fun.reduce.toString() + ';');
}
- // exclude _conflicts key by default
- // or to use options.conflicts if it's set when called by db.query
- var conflicts = ('conflicts' in options ? options.conflicts : false);
-
//only proceed once all documents are mapped and joined
var checkComplete= function(){
if (completed && results.length == num_started){
@@ -89,7 +82,10 @@ var MapReduce = function(db) {
results.reverse();
}
if (options.reduce === false) {
- return options.complete(null, {rows: results});
+ return options.complete(null, {
+ rows: results,
+ total_rows: results.length
+ });
}
var groups = [];
@@ -106,12 +102,12 @@ var MapReduce = function(db) {
e.value = fun.reduce(e.key, e.value) || null;
e.key = e.key[0][0];
});
- options.complete(null, {rows: groups});
+ options.complete(null, {rows: groups, total_rows: groups.length});
}
}
db.changes({
- conflicts: conflicts,
+ conflicts: true,
include_docs: true,
onChange: function(doc) {
if (!('deleted' in doc)) {
8 src/pouch.adapter.js
View
@@ -1,5 +1,6 @@
/*globals Pouch: true, yankError: false, extend: false, call: false, parseDocId: false, traverseRevTree: false */
/*globals arrayFirst: false, rootToLeaf: false, computeHeight: false */
+/*globals cordova, isCordova */
"use strict";
@@ -419,6 +420,9 @@ var PouchAdapter = function(opts, callback) {
return;
}
opts = extend(true, {}, opts);
+
+ // 0 and 1 should return 1 document
+ opts.limit = opts.limit === 0 ? 1 : opts.limit;
return customApi._changes(opts);
};
@@ -534,6 +538,10 @@ var PouchAdapter = function(opts, callback) {
api.taskqueue.execute(api);
}
+ if (isCordova()){
+ //to inform websql adapter that we can use api
+ cordova.fireWindowEvent(opts.name + "_pouch", {});
+ }
return customApi;
};
9 src/pouch.utils.js
View
@@ -127,7 +127,7 @@ var parseDoc = function(doc, newEdits) {
newRevId = revInfo[2];
doc._rev_tree = [{
pos: parseInt(revInfo[1], 10),
- ids: [revInfo[2], {}, []]
+ ids: [revInfo[2], opts, []]
}];
}
}
@@ -265,6 +265,10 @@ var isChromeApp = function(){
return (typeof chrome !== "undefined" && typeof chrome.storage !== "undefined" && typeof chrome.storage.local !== "undefined");
};
+var isCordova = function(){
+ return (typeof cordova !== "undefined" || typeof PhoneGap !== "undefined" || typeof phonegap !== "undefined");
+};
+
if (typeof module !== 'undefined' && module.exports) {
// use node.js's crypto library instead of the Crypto object created by deps/uuid.js
var crypto = require('crypto');
@@ -302,7 +306,8 @@ if (typeof module !== 'undefined' && module.exports) {
extend: extend,
ajax: ajax,
rootToLeaf: rootToLeaf,
- isChromeApp: isChromeApp
+ isChromeApp: isChromeApp,
+ isCordova: isCordova
};
}
11 tests/test.bulk_docs.js
View
@@ -183,4 +183,15 @@ adapters.map(function(adapter) {
});
});
});
+
+ asyncTest('656 regression in handling deleted docs', function() {
+ initTestDB(this.name, function(err, db) {
+ db.bulkDocs({docs: [{_id: "foo", _rev: "1-a", _deleted: true}]}, {new_edits: false}, function(err, res){
+ db.get("foo", function(err, res){
+ ok(err, "deleted");
+ start();
+ });
+ });
+ });
+ });
});
41 tests/test.changes.js
View
@@ -66,6 +66,47 @@ adapters.map(function(adapter) {
});
});
+ asyncTest("Changes Since and limit", function () {
+ var docs = [
+ {_id: "0", integer: 0},
+ {_id: "1", integer: 1},
+ {_id: "2", integer: 2},
+ {_id: "3", integer: 3}
+ ];
+ initTestDB(this.name, function(err, db) {
+ db.bulkDocs({docs: docs}, function(err, info) {
+ db.changes({
+ since: 2,
+ limit: 1,
+ complete: function(err, results) {
+ equal(results.results.length, 1, 'Partial results');
+ start();
+ }
+ });
+ });
+ });
+ });
+
+ asyncTest("Changes limit = 0", function () {
+ var docs = [
+ {_id: "0", integer: 0},
+ {_id: "1", integer: 1},
+ {_id: "2", integer: 2},
+ {_id: "3", integer: 3}
+ ];
+ initTestDB(this.name, function(err, db) {
+ db.bulkDocs({docs: docs}, function(err, info) {
+ db.changes({
+ limit: 0,
+ complete: function(err, results) {
+ equal(results.results.length, 1, 'Partial results');
+ start();
+ }
+ });
+ });
+ });
+ });
+
// Note for the following test that CouchDB's implementation of /_changes
// with `descending=true` ignores any `since` parameter.
asyncTest("Descending changes", function () {
21 tests/test.views.js
View
@@ -42,6 +42,7 @@ adapters.map(function(adapter) {
db.remove(doc, function(_, resp) {
db.query(queryFun, {include_docs: true, reduce: false}, function(_, res) {
equal(res.rows.length, 1, 'Dont include deleted documents');
+ equal(res.total_rows, 1, 'Include total_rows property.');
res.rows.forEach(function(x, i) {
ok(x.id, 'emitted row has id');
ok(x.key, 'emitted row has key');
@@ -242,32 +243,20 @@ adapters.map(function(adapter) {
});
- asyncTest('Views should include _conflict by default', function() {
+ asyncTest('Views should include _conflicts', function() {
var self = this;
var doc1 = {_id: '1', foo: 'bar'};
var doc2 = {_id: '1', foo: 'baz'};
- var queryFun = function(doc) { emit(doc._conflicts); };
+ var queryFun = function(doc) { emit(doc._id, !!doc._conflicts); };
initDBPair(this.name, this.remote, function(db, remote) {
db.post(doc1, function(err, res) {
remote.post(doc2, function(err, res) {
db.replicate.from(remote, function(err, res) {
db.get(doc1._id, {conflicts: true}, function(err, res) {
ok(res._conflicts,'Conflict exists in db');
-
- // Default behaviour
db.query(queryFun, function(err, res) {
- equal(res.rows[0].key.length, 1, 'Conflicts included');
-
- // conflicts: true
- db.query(queryFun, {conflicts: true}, function(err, res) {
- equal(res.rows[0].key.length, 1, 'Conflicts included');
-
- // conflicts: false
- db.query(queryFun, {conflicts: false}, function(err, res) {
- equal(res.rows[0].key.length, 1,'Conflicts excluded');
- start();
- });
- });
+ ok(res.rows[0].value, 'Conflicts included.');
+ start();
});
});
});
Something went wrong with that request. Please try again.