Skip to content

Commit

Permalink
(#2477) - use a Map and Set instead of an object when we have user su…
Browse files Browse the repository at this point in the history
…pplied values
  • Loading branch information
calvinmetcalf committed Jul 17, 2014
1 parent 6e8a572 commit 63bfe3a
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 27 deletions.
8 changes: 4 additions & 4 deletions lib/adapters/idb.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ function init(api, opts, callback) {
}

var results = [];
var fetchedDocs = {};
var fetchedDocs = new utils.Map();
var updateSeq = 0;
var currentDocId = -1;

Expand Down Expand Up @@ -240,9 +240,9 @@ function init(api, opts, callback) {

var id = currentDoc.metadata.id;

if (id in fetchedDocs) {
if (fetchedDocs.has(id)) {
// if newEdits=false, can re-use the same id from this batch
return updateDoc(fetchedDocs[id], currentDoc);
return updateDoc(fetchedDocs.get(id), currentDoc);
}

var req = txn.objectStore(DOC_STORE).get(id);
Expand Down Expand Up @@ -413,7 +413,7 @@ function init(api, opts, callback) {
delete metadata.deletedOrLocal;
delete metadata.winningRev;
results.push(docInfo);
fetchedDocs[docInfo.metadata.id] = docInfo.metadata;
fetchedDocs.set(docInfo.metadata.id, docInfo.metadata);
utils.call(callback);
};
}
Expand Down
46 changes: 28 additions & 18 deletions lib/adapters/leveldb.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var META_STORE = 'meta-store';

// leveldb barks if we try to open a db multiple times
// so we cache opened connections here for initstore()
var dbStores = {};
var dbStores = new utils.Map();

// store the value of update_seq in the by-sequence store the key name will
// never conflict, since the keys in the by-sequence store are integers
Expand All @@ -42,19 +42,24 @@ function LevelPouch(opts, callback) {
if (typeof leveldown.destroy !== 'function') {
leveldown.destroy = function (name, cb) { cb(); };
}

var dbStore = dbStores[leveldown.name] = dbStores[leveldown.name] || {};
if (dbStore[name]) {
db = dbStore[name];
var dbStore;
if (dbStores.has(leveldown.name)) {
dbStore = dbStores.get(leveldown.name);
} else {
dbStore = new utils.Map();
dbStores.set(leveldown.name, dbStore);
}
if (dbStore.has(name)) {
db = dbStore.get(name);
afterDBCreated();
} else {
dbStore[name] = sublevel(levelup(name, opts, function (err) {
dbStore.set(name, sublevel(levelup(name, opts, function (err) {
if (err) {
delete dbStore[name];
dbStore.delete(name);
return callback(err);
}
db = dbStore[name];
db._locks = db._locks || {};
db = dbStore.get(name);
db._locks = db._locks || new utils.Set();
db._docCountQueue = {
queue : [],
running : false,
Expand All @@ -65,7 +70,7 @@ function LevelPouch(opts, callback) {
} else {
migrate.toSublevel(name, db, afterDBCreated);
}
}));
})));
}

function afterDBCreated() {
Expand Down Expand Up @@ -296,16 +301,16 @@ function LevelPouch(opts, callback) {
};

api.lock = function (id) {
if (id in db._locks) {
if (db._locks.has(id)) {
return false;
} else {
db._locks[id] = true;
db._locks.add(id);
return true;
}
};

api.unlock = function (id) {
delete db._locks[id];
db._locks.delete(id);
return true;
};

Expand Down Expand Up @@ -856,7 +861,7 @@ function LevelPouch(opts, callback) {
if (err) {
callback(err);
} else {
delete dbStore[name];
dbStore.delete(name);
callback();
}
});
Expand Down Expand Up @@ -967,14 +972,19 @@ LevelPouch.destroy = utils.toPromise(function (name, opts, callback) {
leveldown.destroy = function (name, cb) { cb(); };
}

var dbStore = dbStores[leveldown.name] || {};
var dbStore;
if (dbStores.has(leveldown.name)) {
dbStore = dbStores.get(leveldown.name);
} else {
dbStore = new utils.Map();
}

if (dbStore[name]) {
if (dbStore.has(name)) {

LevelPouch.Changes.removeAllListeners(name);

dbStore[name].close(function () {
delete dbStore[name];
dbStore.get(name).close(function () {
dbStore.delete(name);
leveldown.destroy(name, callback);
});
} else {
Expand Down
8 changes: 4 additions & 4 deletions lib/adapters/websql.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ function WebSqlPouch(opts, callback) {
var tx;
var results = [];
var updateSeq = 0;
var fetchedDocs = {};
var fetchedDocs = new utils.Map();
var currentDocId = -1;

function complete() {
Expand Down Expand Up @@ -579,7 +579,7 @@ function WebSqlPouch(opts, callback) {
[docInfo.metadata.id, seq, metadataStr];
tx.executeSql(sql, params, function () {
results.push(docInfo);
fetchedDocs[docInfo.metadata.id] = docInfo.metadata;
fetchedDocs.set(docInfo.metadata.id, docInfo.metadata);
callback();
});
}
Expand Down Expand Up @@ -637,9 +637,9 @@ function WebSqlPouch(opts, callback) {

var id = currentDoc.metadata.id;

if (id in fetchedDocs) {
if (fetchedDocs.has(id)) {
// if newEdits=false, can re-use the same id from this batch
return updateDoc(fetchedDocs[id], currentDoc);
return updateDoc(fetchedDocs.get(id), currentDoc);
}

tx.executeSql('SELECT json FROM ' + DOC_STORE +
Expand Down
50 changes: 50 additions & 0 deletions lib/deps/collections.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict';
exports.Map = global.Map || LazyMap;
exports.Set = global.Set || LazySet;
// based on https://github.com/montagejs/collections
function LazyMap() {
this.store = {};
}
LazyMap.prototype.mangle = function (key) {
if (typeof key !== "string") {
throw new TypeError("key must be a string but Got " + key);
}
return '$' + key;
};
LazyMap.prototype.get = function (key) {
var mangled = this.mangle(key);
if (mangled in this.store) {
return this.store[mangled];
} else {
return void 0;
}
};
LazyMap.prototype.set = function (key, value) {
var mangled = this.mangle(key);
this.store[mangled] = value;
return true;
};
LazyMap.prototype.has = function (key) {
var mangled = this.mangle(key);
return mangled in this.store;
};
LazyMap.prototype.delete = function (key) {
var mangled = this.mangle(key);
if (mangled in this.store) {
delete this.store[mangled];
return true;
}
return false;
};
function LazySet() {
this.store = new LazyMap();
}
LazySet.prototype.add = function (key) {
return this.store.set(key, true);
};
LazySet.prototype.has = function (key) {
return this.store.has(key);
};
LazySet.prototype.delete = function (key) {
return this.store.delete(key);
};
5 changes: 4 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ exports.getArguments = require('argsarray');
var buffer = require('./deps/buffer');
var errors = require('./deps/errors');
var EventEmitter = require('events').EventEmitter;
var collections = require('./deps/collections');
exports.Map = collections.Map;
exports.Set = collections.Set;

if (typeof global.Promise === 'function') {
exports.Promise = global.Promise;
Expand Down Expand Up @@ -543,4 +546,4 @@ exports.MD5 = exports.Crypto.MD5 = function (string) {
} else {
return md5(string);
}
};
};
1 change: 1 addition & 0 deletions tests/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<script src='browser.migration.js'></script>
<script src='test.uuids.js'></script>
<script src='test.slash_id.js'></script>
<script src='test.reserved.js'></script>
<script src='browser.worker.js'></script>
<script type="text/javascript" src="./webrunner.js"></script>
</body>
Expand Down
67 changes: 67 additions & 0 deletions tests/test.reserved.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

var adapters = [
['local', 'http'],
['http', 'http'],
['http', 'local'],
['local', 'local']
];

adapters.forEach(function (adapters) {
describe('test.reserved.js-' + adapters[0] + '-' + adapters[1], function () {

var dbs = {};

beforeEach(function (done) {
dbs.name = testUtils.adapterUrl(adapters[0], 'test_repl');
dbs.remote = testUtils.adapterUrl(adapters[1], 'test_repl_remote');
testUtils.cleanup([dbs.name, dbs.remote], done);
});

after(function (done) {
testUtils.cleanup([dbs.name, dbs.remote], done);
});

it('test docs with reserved javascript ids', function () {
this.timeout(5000);
var db = new PouchDB(dbs.name);
var remote = new PouchDB(dbs.remote);
return db.bulkDocs([
{_id: 'constructor'},
{_id: 'toString'},
{_id: 'valueOf'}
]).then(function () {
return db.allDocs({key: 'constructor'});
}).then(function (res) {
res.rows.should.have.length(1, 'allDocs with key');
return db.allDocs({keys: ['constructor']});
}).then(function (res) {
res.rows.should.have.length(1, 'allDocs with keys');
return db.allDocs();
}).then(function (res) {
res.rows.should.have.length(3, 'allDocs empty opts');
return db.query(function (doc) {
emit(doc._id);
}, {key: 'constructor'});
}).then(function (res) {
res.rows.should.have.length(1, 'query with key');
return db.query(function (doc) {
emit(doc._id);
}, {keys: ['constructor']});
}).then(function (res) {
res.rows.should.have.length(1, 'query with keys');
return new PouchDB.utils.Promise(function (resolve, reject) {
db.replicate.to(remote).on('complete', resolve).on('error', reject);
});
});
});

it('can create db with reserved name', function () {
return new PouchDB('constructor').then(function (db) {
return db.info().then(function () {
return db.destroy();
});
});
});
});
});

0 comments on commit 63bfe3a

Please sign in to comment.