Used prepared statement rather than batch/offset for zxystream.
This commit is contained in:
@@ -6,22 +6,13 @@ util.inherits(ZXYStream, stream.Readable);
|
||||
|
||||
// Readable stream of line-delimited z/x/y coordinates
|
||||
// contained within the MBTiles `tiles` table/view.
|
||||
//
|
||||
// The `batch` option exists to allow tests to check that
|
||||
// multiple calls to `_read` are handled properly. IRL the
|
||||
// default offset of 1000 should be reasonably efficient
|
||||
// and not worth messing with.
|
||||
function ZXYStream(source, options) {
|
||||
if (!source) throw new TypeError('MBTiles source required');
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (options.batch !== undefined && typeof options.batch !== 'number')
|
||||
throw new TypeError('options.batch must be a positive integer');
|
||||
|
||||
this.source = source;
|
||||
this.batch = options.batch || 1000;
|
||||
this.offset = 0;
|
||||
this._afterGet = this._afterGet.bind(this);
|
||||
|
||||
stream.Readable.call(this);
|
||||
}
|
||||
@@ -38,15 +29,23 @@ ZXYStream.prototype._read = function() {
|
||||
});
|
||||
}
|
||||
|
||||
this.source._db.all('SELECT zoom_level AS z, tile_column AS x, tile_row AS y FROM ' + this.table + ' LIMIT ' + this.batch + ' OFFSET ' + this.offset, function(err, rows) {
|
||||
if (err && err.code === 'SQLITE_ERROR' && /no such table/.test(err.message)) return stream.push(null);
|
||||
if (err) return stream.emit('error', err);
|
||||
if (!rows.length) return stream.push(null);
|
||||
stream.offset += stream.batch;
|
||||
var chunk = '';
|
||||
for (var i = 0; i < rows.length; i++) chunk += toLine(rows[i]);
|
||||
stream.push(chunk);
|
||||
});
|
||||
// Prepare sql statement
|
||||
if (!stream.statement) {
|
||||
stream.statement = this.source._db.prepare('SELECT zoom_level AS z, tile_column AS x, tile_row AS y FROM ' + this.table, function(err) {
|
||||
if (err && err.code === 'SQLITE_ERROR' && /no such table/.test(err.message)) return stream.push(null);
|
||||
return stream._read();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
stream.statement.get(stream._afterGet);
|
||||
};
|
||||
|
||||
ZXYStream.prototype._afterGet = function(err, row) {
|
||||
if (err && err.code === 'SQLITE_ERROR' && /no such table/.test(err.message)) return this.push(null);
|
||||
if (err) return this.emit('error', err);
|
||||
if (!row) return this.push(null);
|
||||
this.push(toLine(row));
|
||||
};
|
||||
|
||||
function toLine(row) {
|
||||
|
||||
@@ -10,14 +10,12 @@ tape('zxystream setup', function(assert) {
|
||||
});
|
||||
});
|
||||
|
||||
tape('zxystream default batch', function(assert) {
|
||||
tape('zxystream default', function(assert) {
|
||||
var stream = source.createZXYStream();
|
||||
var output = '';
|
||||
var called = 0;
|
||||
|
||||
assert.deepEqual(stream.source, source, 'sets stream.source');
|
||||
assert.deepEqual(stream.batch, 1000, 'sets stream.batch = 1000');
|
||||
assert.deepEqual(stream.offset, 0, 'sets stream.offset = 0');
|
||||
|
||||
stream.on('data', function(lines) {
|
||||
assert.equal(stream.table, 'map');
|
||||
@@ -27,7 +25,7 @@ tape('zxystream default batch', function(assert) {
|
||||
stream.on('end', function() {
|
||||
var queue = output.toString().split('\n');
|
||||
assert.equal(queue.length, 270);
|
||||
assert.equal(called, 1, 'emitted data x1 times');
|
||||
assert.equal(called, 269, 'emitted data' + called + ' times');
|
||||
checkTile(queue);
|
||||
function checkTile(queue) {
|
||||
if (!queue.length) return assert.end();
|
||||
@@ -43,38 +41,6 @@ tape('zxystream default batch', function(assert) {
|
||||
});
|
||||
|
||||
|
||||
tape('zxystream batch = 10', function(assert) {
|
||||
var stream = source.createZXYStream({batch:10});
|
||||
var output = '';
|
||||
var called = 0;
|
||||
|
||||
assert.deepEqual(stream.source, source, 'sets stream.source');
|
||||
assert.deepEqual(stream.batch, 10, 'sets stream.batch = 10');
|
||||
assert.deepEqual(stream.offset, 0, 'sets stream.offset = 0');
|
||||
|
||||
stream.on('data', function(lines) {
|
||||
assert.equal(stream.table, 'map');
|
||||
output += lines;
|
||||
called++;
|
||||
});
|
||||
stream.on('end', function() {
|
||||
var queue = output.toString().split('\n');
|
||||
assert.equal(queue.length, 270);
|
||||
assert.equal(called, 27, 'emitted data x27 times');
|
||||
checkTile(queue);
|
||||
function checkTile(queue) {
|
||||
if (!queue.length) return assert.end();
|
||||
var zxy = queue.shift();
|
||||
if (!zxy) return checkTile(queue);
|
||||
zxy = zxy.split('/');
|
||||
source.getTile(zxy[0], zxy[1], zxy[2], function(err, buffer, headers) {
|
||||
assert.equal(!err && (buffer instanceof Buffer), true, zxy.join('/') + ' exists');
|
||||
checkTile(queue);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
tape('zxystream unindexed', function(assert) {
|
||||
new MBTiles(__dirname + '/fixtures/unindexed.mbtiles', function(err, s) {
|
||||
assert.ifError(err);
|
||||
@@ -89,8 +55,6 @@ tape('zxystream unindexed zxystream', function(assert) {
|
||||
var called = 0;
|
||||
|
||||
assert.deepEqual(stream.source, source, 'sets stream.source');
|
||||
assert.deepEqual(stream.batch, 1000, 'sets stream.batch = 1000');
|
||||
assert.deepEqual(stream.offset, 0, 'sets stream.offset = 0');
|
||||
|
||||
stream.on('data', function(lines) {
|
||||
assert.equal(stream.table, 'tiles');
|
||||
@@ -100,7 +64,7 @@ tape('zxystream unindexed zxystream', function(assert) {
|
||||
stream.on('end', function() {
|
||||
var queue = output.toString().split('\n');
|
||||
assert.equal(queue.length, 286);
|
||||
assert.equal(called, 1, 'emitted data x27 times');
|
||||
assert.equal(called, 285, 'emitted data x285 times');
|
||||
checkTile(queue);
|
||||
function checkTile(queue) {
|
||||
if (!queue.length) return assert.end();
|
||||
|
||||
Reference in New Issue
Block a user