diff --git a/lib/zxystream.js b/lib/zxystream.js index 4d1d44f..4da0cda 100644 --- a/lib/zxystream.js +++ b/lib/zxystream.js @@ -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) { diff --git a/test/zxystream.js b/test/zxystream.js index 92008fc..eafdd7a 100644 --- a/test/zxystream.js +++ b/test/zxystream.js @@ -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();