(#3946 #3758) - add buffer.type, test types
diff --git a/lib/adapters/leveldb/index.js b/lib/adapters/leveldb/index.js
index b95757c..33bcce4 100644
--- a/lib/adapters/leveldb/index.js
+++ b/lib/adapters/leveldb/index.js
@@ -28,6 +28,7 @@
var readAsBinaryString = require('../../deps/binary/readAsBinaryString');
var binStringToBluffer =
require('../../deps/binary/binaryStringToBlobOrBuffer');
+var typedBuffer = require('../../deps/binary/typedBuffer');
var LevelTransaction = require('./transaction');
@@ -79,6 +80,7 @@
} else if (isBrowser) { // browser, it's a binary string
data = binStringToBluffer(buffer, type);
} else { // node, it's already a buffer
+ buffer.type = type; // non-standard, but used for consistency
data = buffer;
}
}
@@ -367,6 +369,7 @@
// method...
api._getAttachment = function (attachment, opts, callback) {
var digest = attachment.digest;
+ var type = attachment.content_type;
stores.binaryStore.get(digest, function (err, attach) {
var data;
@@ -374,8 +377,8 @@
if (err && err.name === 'NotFoundError') {
// Empty attachment
data = !opts.binary ? '' : isBrowser ?
- utils.createBlob([''], {type: attachment.content_type}) :
- new Buffer('');
+ utils.createBlob([''], {type: type}) :
+ typedBuffer('', 'binary', type);
return callback(null, data);
}
@@ -385,11 +388,13 @@
if (isBrowser) {
if (opts.binary) {
- data = binStringToBluffer(attach, attachment.content_type);
+ data = binStringToBluffer(attach, type);
} else {
data = utils.btoa(attach);
}
} else {
+ // non-standard, but used for consistency with the browser
+ attach.type = type;
data = opts.binary ? attach : utils.btoa(attach);
}
callback(null, data);
diff --git a/lib/deps/ajax.js b/lib/deps/ajax.js
index 704b14c..17ea6f1 100644
--- a/lib/deps/ajax.js
+++ b/lib/deps/ajax.js
@@ -2,9 +2,10 @@
var request = require('request');
-var buffer = require('./buffer');
+var buffer = require('./binary/buffer');
var errors = require('./errors');
var utils = require('../utils');
+var isBrowser = typeof process === 'undefined' || process.browser;
function ajax(options, adapterCallback) {
@@ -57,6 +58,10 @@
}
});
}
+ if (!isBrowser && options.binary) {
+ // non-standard buffer.type for consistency with the browser
+ obj.type = resp.headers['content-type'];
+ }
cb(null, obj, resp);
}
diff --git a/lib/deps/binary/base64.js b/lib/deps/binary/base64.js
index 572e301..9550d09 100644
--- a/lib/deps/binary/base64.js
+++ b/lib/deps/binary/base64.js
@@ -1,6 +1,6 @@
'use strict';
-var buffer = require('./../buffer');
+var buffer = require('./buffer');
if (typeof atob === 'function') {
exports.atob = function (str) {
diff --git a/lib/deps/binary/base64StringToBlobOrBuffer.js b/lib/deps/binary/base64StringToBlobOrBuffer.js
index d0e835d..375ab22 100644
--- a/lib/deps/binary/base64StringToBlobOrBuffer.js
+++ b/lib/deps/binary/base64StringToBlobOrBuffer.js
@@ -3,14 +3,14 @@
var isBrowser = typeof process === 'undefined' || process.browser;
var atob = require('./base64').atob;
var binaryStringToBlobOrBuffer = require('./binaryStringToBlobOrBuffer');
-var buffer = require('../buffer');
+var typedBuffer = require('./typedBuffer');
if (isBrowser) {
module.exports = function (b64, type) {
return binaryStringToBlobOrBuffer(atob(b64), type);
};
} else {
- module.exports = function (b64) {
- return new buffer(b64, 'base64');
+ module.exports = function (b64, type) {
+ return typedBuffer(b64, 'base64', type);
};
}
\ No newline at end of file
diff --git a/lib/deps/binary/binaryStringToBlobOrBuffer.js b/lib/deps/binary/binaryStringToBlobOrBuffer.js
index c0e539a..4cf4962 100644
--- a/lib/deps/binary/binaryStringToBlobOrBuffer.js
+++ b/lib/deps/binary/binaryStringToBlobOrBuffer.js
@@ -1,7 +1,7 @@
'use strict';
var isBrowser = typeof process === 'undefined' || process.browser;
-var buffer = require('../buffer');
+var typedBuffer = require('./typedBuffer');
var createBlob = require('./blob');
var binaryStringToArrayBuffer = require('./binaryStringToArrayBuffer');
@@ -11,7 +11,7 @@
return createBlob([binaryStringToArrayBuffer(binString)], {type: type});
};
} else {
- module.exports = function (binString) {
- return new buffer(binString, 'binary');
+ module.exports = function (binString, type) {
+ return typedBuffer(binString, 'binary', type);
};
}
\ No newline at end of file
diff --git a/lib/deps/buffer-browser.js b/lib/deps/binary/buffer-browser.js
similarity index 100%
rename from lib/deps/buffer-browser.js
rename to lib/deps/binary/buffer-browser.js
diff --git a/lib/deps/buffer.js b/lib/deps/binary/buffer.js
similarity index 100%
rename from lib/deps/buffer.js
rename to lib/deps/binary/buffer.js
diff --git a/lib/deps/binary/typedBuffer.js b/lib/deps/binary/typedBuffer.js
new file mode 100644
index 0000000..9939bd5
--- /dev/null
+++ b/lib/deps/binary/typedBuffer.js
@@ -0,0 +1,12 @@
+'use strict';
+
+var buffer = require('./buffer');
+
+function typedBuffer(binString, buffType, type) {
+ // buffType is either 'binary' or 'base64'
+ var buff = new buffer(binString, buffType);
+ buff.type = type; // non-standard, but used for consistency with the browser
+ return buff;
+}
+
+module.exports = typedBuffer;
\ No newline at end of file
diff --git a/lib/deps/multipart.js b/lib/deps/multipart.js
index 8adc0a2..a2de8a0 100644
--- a/lib/deps/multipart.js
+++ b/lib/deps/multipart.js
@@ -14,7 +14,7 @@
var utils = require('../utils');
var clone = utils.clone;
var isBrowser = typeof process === 'undefined' || process.browser;
-var buffer = require('./buffer');
+var buffer = require('./binary/buffer');
function createBlobOrBuffer(parts, type) {
if (isBrowser) {
diff --git a/package.json b/package.json
index 2f6387d..db2e870 100644
--- a/package.json
+++ b/package.json
@@ -111,7 +111,7 @@
"./adapters/levelalt": false,
"./lib/version.js": "./lib/version-browser.js",
"./lib/adapters/preferredAdapters.js": "./lib/adapters/preferredAdapters-browser.js",
- "./lib/deps/buffer.js": "./lib/deps/buffer-browser.js",
+ "./lib/deps/binary/buffer.js": "./lib/deps/binary/buffer-browser.js",
"./lib/deps/migrate.js": "./lib/deps/migrate-browser.js",
"bluebird": "lie",
"fs": false,
diff --git a/tests/integration/test.attachments.js b/tests/integration/test.attachments.js
index f615612..e54825b 100644
--- a/tests/integration/test.attachments.js
+++ b/tests/integration/test.attachments.js
@@ -187,9 +187,10 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
+ att.data.type.should.equal(expected.content_type);
return testUtils.readBlobPromise(att.data);
- }).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ }).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
});
@@ -220,8 +221,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
});
}));
@@ -256,8 +258,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
});
@@ -297,8 +300,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
});
@@ -365,8 +369,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
});
@@ -441,8 +446,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
}));
@@ -536,8 +542,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
}));
@@ -579,8 +586,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
});
@@ -655,8 +663,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
}));
@@ -746,8 +755,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
}));
@@ -841,8 +851,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
}));
}));
@@ -899,8 +910,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
doneWithDoc();
});
}).catch(reject);
@@ -1010,8 +1022,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
});
})).then(doneWithDoc);
}).catch(reject);
@@ -1069,8 +1082,9 @@
should.exist(att.digest);
att.content_type.should.equal(expected.content_type);
att.data.should.not.be.a('string');
- return testUtils.readBlobPromise(att.data).then(function (b64) {
- testUtils.btoa(b64).should.equal(expected.data);
+ att.data.type.should.equal(expected.content_type);
+ return testUtils.readBlobPromise(att.data).then(function (bin) {
+ testUtils.btoa(bin).should.equal(expected.data);
doneWithDoc();
});
}).catch(reject);
@@ -1839,11 +1853,14 @@
doc._attachments['foo.txt'].content_type.should.equal('text/plain');
db.getAttachment('bin_doc', 'foo.txt', function (err, res) {
should.not.exist(err, 'fetched attachment');
+ res.type.should.equal('text/plain');
testUtils.readBlob(res, function (data) {
data.should.equal('This is a base64 encoded text');
db.put(binAttDoc2, function (err, rev) {
db.getAttachment('bin_doc2', 'foo.txt',
- function (err, res, xhr) {
+ function (err, res) {
+ should.not.exist(err);
+ res.type.should.equal('text/plain');
testUtils.readBlob(res, function (data) {
data.should.equal('', 'Correct data returned');
moreTests(rev.rev);
@@ -1861,10 +1878,13 @@
function (err, info) {
info.ok.should.equal(true);
db.getAttachment('bin_doc2', 'foo2.txt', function (err, res, xhr) {
+ should.not.exist(err);
+ res.type.should.equal('text/plain');
testUtils.readBlob(res, function (data) {
should.exist(data);
db.get('bin_doc2', { attachments: true },
function (err, res, xhr) {
+ should.not.exist(err);
should.exist(res._attachments, 'Result has attachments field');
should.not
.exist(res._attachments['foo2.txt'].stub, 'stub is false');
@@ -1884,10 +1904,12 @@
it('Test getAttachment', function (done) {
var db = new PouchDB(dbs.name);
db.put(binAttDoc, function (err, res) {
+ should.not.exist(err);
db.getAttachment('bin_doc', 'foo.txt', function (err, res) {
if (err) {
return done(err);
}
+ res.type.should.equal('text/plain');
testUtils.readBlob(res, function (data) {
data.should.equal('This is a base64 encoded text', 'correct data');
done();
@@ -1896,6 +1918,74 @@
});
});
+ it('Test getAttachment with stubs', function () {
+ var db = new PouchDB(dbs.name);
+ return db.put({
+ _id: 'doc',
+ _attachments: {
+ '1': {
+ content_type: 'application/octet-stream',
+ data: testUtils.btoa('1\u00002\u00013\u0002')
+ }
+ }
+ }).then(function (res) {
+ return db.get('doc');
+ }).then(function (doc) {
+ doc._attachments['2'] = {
+ content_type: 'application/octet-stream',
+ data: testUtils.btoa('3\u00002\u00011\u0002')
+ };
+ return db.put(doc);
+ }).then(function () {
+ return db.getAttachment('doc', '1');
+ }).then(function (att) {
+ att.type.should.equal('application/octet-stream');
+ return testUtils.readBlobPromise(att);
+ }).then(function (bin) {
+ bin.should.equal('1\u00002\u00013\u0002');
+ return db.getAttachment('doc', '2');
+ }).then(function (att) {
+ att.type.should.equal('application/octet-stream');
+ return testUtils.readBlobPromise(att);
+ }).then(function (bin) {
+ bin.should.equal('3\u00002\u00011\u0002');
+ });
+ });
+
+ it('Test get() with binary:true and stubs', function () {
+ var db = new PouchDB(dbs.name);
+ return db.put({
+ _id: 'doc',
+ _attachments: {
+ '1': {
+ content_type: 'application/octet-stream',
+ data: testUtils.btoa('1\u00002\u00013\u0002')
+ }
+ }
+ }).then(function (res) {
+ return db.get('doc');
+ }).then(function (doc) {
+ doc._attachments['2'] = {
+ content_type: 'application/octet-stream',
+ data: testUtils.btoa('3\u00002\u00011\u0002')
+ };
+ return db.put(doc);
+ }).then(function () {
+ return db.get('doc', {attachments: true, binary: true});
+ }).then(function (doc) {
+ var att1 = doc._attachments['1'].data;
+ var att2 = doc._attachments['2'].data;
+ att1.type.should.equal('application/octet-stream');
+ att2.type.should.equal('application/octet-stream');
+ return testUtils.readBlobPromise(att1).then(function (bin) {
+ bin.should.equal('1\u00002\u00013\u0002');
+ return testUtils.readBlobPromise(att2);
+ }).then(function (bin) {
+ bin.should.equal('3\u00002\u00011\u0002');
+ });
+ });
+ });
+
it('Test attachments in allDocs/changes', function (done) {
var db = new PouchDB(dbs.name);
var docs = [
@@ -2264,6 +2354,8 @@
should.exist(res._attachments['my/text?@']);
db.getAttachment('mydoc', 'my/text?@', function (err, attachment) {
+ should.not.exist(err);
+ attachment.type.should.equal('text/plain');
testUtils.readBlob(attachment, function (data) {
data.should.eql('Mytext');
@@ -2371,6 +2463,8 @@
doc._attachments['foo.json'].content_type.should
.equal('application/json', 'doc has correct content type');
db.getAttachment(results.id, 'foo.json', function (err, attachment) {
+ should.not.exist(err);
+ attachment.type.should.equal('application/json');
testUtils.readBlob(attachment, function (data) {
jsonDoc._attachments['foo.json'].data.should
.equal('eyJIZWxsbyI6IndvcmxkIn0=', 'correct data');
@@ -2632,7 +2726,10 @@
return PouchDB.utils.Promise.all(testCases.map(function (testCase) {
var promise = testCase[0];
var expected = testCase[1];
- return promise.then(testUtils.readBlobPromise).then(function (bin) {
+ return promise.then(function (blob) {
+ blob.type.should.equal('text/plain');
+ return testUtils.readBlobPromise(blob);
+ }).then(function (bin) {
bin.should.equal(expected, 'didn\'t get blob we expected for rev');
});
}));
@@ -2672,6 +2769,7 @@
should.not.exist(err, 'attachment inserted');
db.getAttachment('foo', 'foo.txt', function (err, blob) {
should.not.exist(err, 'attachment gotten');
+ blob.type.should.equal('text/plain');
testUtils.readBlob(blob, function (returnedData) {
testUtils.btoa(returnedData).should.equal(data);
db.get('foo', function (err, doc) {
@@ -2718,6 +2816,7 @@
should.not.exist(err, 'attachment inserted');
db.getAttachment('foo', 'foo.png', function (err, blob) {
should.not.exist(err, 'attachment gotten');
+ blob.type.should.equal('image/png');
testUtils.readBlob(blob, function (returnedData) {
testUtils.btoa(returnedData).should.equal(data);
db.get('foo', function (err, doc) {
@@ -2909,9 +3008,8 @@
return db.putAttachment('foo', 'foo.bin', base64, 'image/png').then(function () {
return db.getAttachment('foo', 'foo.bin');
}).then(function (blob) {
- return new PouchDB.utils.Promise(function (resolve) {
- testUtils.readBlob(blob, resolve);
- });
+ blob.type.should.equal('image/png');
+ return testUtils.readBlobPromise(blob);
}).then(function (bin) {
testUtils.btoa(bin).should.equal(base64);
});
@@ -2954,6 +3052,7 @@
should.not.exist(err, 'attachment inserted');
db.getAttachment('foo', 'foo.png', function (err, blob) {
should.not.exist(err, 'attachment gotten');
+ blob.type.should.equal('image/png');
testUtils.readBlob(blob, function (returnedData) {
testUtils.btoa(returnedData).should.equal(data);
db.get('foo', function (err, doc) {
@@ -3167,6 +3266,41 @@
});
});
+ it('Attachment types replicate', function () {
+ var binAttDoc = {
+ _id: 'bin_doc',
+ _attachments: {
+ 'foo.txt': {
+ content_type: 'text/plain',
+ data: 'VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ='
+ }
+ }
+ };
+ var docs1 = [
+ binAttDoc,
+ {_id: '0', integer: 0},
+ {_id: '1', integer: 1},
+ {_id: '2', integer: 2},
+ {_id: '3', integer: 3}
+ ];
+
+ var db = new PouchDB(dbs.name);
+ var remote = new PouchDB(dbs.remote);
+
+ return remote.bulkDocs({ docs: docs1 }).then(function(info) {
+ return db.replicate.from(remote);
+ }).then(function () {
+ return db.get('bin_doc', {attachments: true, binary: true});
+ }).then(function (doc) {
+ var blob = doc._attachments['foo.txt'].data;
+ blob.type.should.equal('text/plain');
+ return testUtils.readBlobPromise(blob);
+ }).then(function (bin) {
+ bin.should.equal(testUtils.atob(
+ 'VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ='));
+ });
+ });
+
it('Many many attachments replicate', function () {
var doc = {_id: 'foo'};
@@ -3323,7 +3457,7 @@
}
});
}
- return remote.bulkDocs(docs).then(function (info) {
+ return remote.bulkDocs(docs).then(function () {
return remote.replicate.to(db);
}).then(function () {
return db.allDocs();
diff --git a/tests/integration/utils.js b/tests/integration/utils.js
index 1f88e58..7d76ee0 100644
--- a/tests/integration/utils.js
+++ b/tests/integration/utils.js
@@ -55,7 +55,9 @@
if (typeof module !== 'undefined' && module.exports) {
return new Buffer(data, 'binary');
} else {
- return PouchDB.utils.createBlob([data], { type: type });
+ return PouchDB.utils.createBlob([data], {
+ type: (type || 'text/plain')
+ });
}
};