Add mbcheck.
This commit is contained in:
Executable
+162
@@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
var options = argv = require('optimist').argv,
|
||||||
|
_ = require('underscore'),
|
||||||
|
Step = require('step'),
|
||||||
|
utils = require('..').utils,
|
||||||
|
MBTiles = require('..').MBTiles,
|
||||||
|
mbtiles,
|
||||||
|
tables = [],
|
||||||
|
zooms = [],
|
||||||
|
tiles = [];
|
||||||
|
|
||||||
|
// Show help.
|
||||||
|
if (argv.help || argv._.length === 0) {
|
||||||
|
console.warn('Usage: mbcheck [OPTIONS] [FILE]');
|
||||||
|
utils.table([
|
||||||
|
['--help', 'Show help.']
|
||||||
|
]);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wishlist:
|
||||||
|
// ---------
|
||||||
|
// - check that tiles exist for specified bounds
|
||||||
|
|
||||||
|
Step(
|
||||||
|
function() { mbtiles = new MBTiles(argv._[0], this); },
|
||||||
|
function() { mbtiles.integrity(this); },
|
||||||
|
function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
mbtiles.exists('tiles', function(err, exists) {
|
||||||
|
if (!exists) throw new Error('`tiles` table does not exist.');
|
||||||
|
this();
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
mbtiles.exists('metadata', function(err, exists) {
|
||||||
|
if (!exists) throw new Error('`metadata` table does not exist.');
|
||||||
|
this();
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
mbtiles.metadata('name', this.parallel());
|
||||||
|
mbtiles.metadata('type', this.parallel());
|
||||||
|
mbtiles.metadata('desciption', this.parallel());
|
||||||
|
mbtiles.metadata('version', this.parallel());
|
||||||
|
mbtiles.metadata('format', this.parallel());
|
||||||
|
mbtiles.metadata('bounds', this.parallel());
|
||||||
|
},
|
||||||
|
function(err, name, type, description, version, format, bounds) {
|
||||||
|
console.warn('');
|
||||||
|
console.warn(' Metadata');
|
||||||
|
utils.table([
|
||||||
|
['name', name],
|
||||||
|
['type', type],
|
||||||
|
['description', description],
|
||||||
|
['vesion', version],
|
||||||
|
['format', format],
|
||||||
|
['bounds', bounds]
|
||||||
|
]);
|
||||||
|
this();
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
Step(
|
||||||
|
function() {
|
||||||
|
var group = this.group(),
|
||||||
|
query = mbtiles.db.prepare(
|
||||||
|
'SELECT zoom_level AS zoom, ' +
|
||||||
|
'COUNT(zoom_level) AS count ' +
|
||||||
|
'FROM tiles ' +
|
||||||
|
'WHERE zoom_level = ?'
|
||||||
|
);
|
||||||
|
for (var i = 0; i < 30; i++) {
|
||||||
|
query.get(i, group());
|
||||||
|
}
|
||||||
|
query.finalize();
|
||||||
|
},
|
||||||
|
function(err, rows) {
|
||||||
|
if (err) throw err;
|
||||||
|
zooms = rows;
|
||||||
|
do {
|
||||||
|
var last = zooms.pop();
|
||||||
|
if (last.count) zooms.push(last);
|
||||||
|
} while(!last.count);
|
||||||
|
do {
|
||||||
|
var first = zooms.shift();
|
||||||
|
if (first.count) zooms.unshift(first);
|
||||||
|
} while(!first.count);
|
||||||
|
this();
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
Step(
|
||||||
|
function() {
|
||||||
|
var group = this.group(),
|
||||||
|
query = mbtiles.db.prepare(
|
||||||
|
'SELECT MAX(tile_column) AS maxx, ' +
|
||||||
|
'MIN(tile_column) AS minx, ' +
|
||||||
|
'MAX(tile_row) AS maxy, ' +
|
||||||
|
'MIN(tile_row) AS miny, ' +
|
||||||
|
'zoom_level AS zoom ' +
|
||||||
|
'FROM tiles ' +
|
||||||
|
'WHERE zoom_level = ?'
|
||||||
|
);
|
||||||
|
for (var i = 0; i < zooms.length; i++) {
|
||||||
|
query.get(zooms[i].zoom, group());
|
||||||
|
}
|
||||||
|
query.finalize();
|
||||||
|
},
|
||||||
|
function(err, rows) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
var group = this.group(),
|
||||||
|
query = mbtiles.db.prepare(
|
||||||
|
'SELECT zoom_level AS zoom, ' +
|
||||||
|
'COUNT(zoom_level) AS count, ' +
|
||||||
|
'? AS expected ' +
|
||||||
|
'FROM tiles ' +
|
||||||
|
'WHERE zoom_level = ? AND ' +
|
||||||
|
'tile_column >= ? AND ' +
|
||||||
|
'tile_column <= ? AND ' +
|
||||||
|
'tile_row >= ? AND ' +
|
||||||
|
'tile_row <= ?'
|
||||||
|
);
|
||||||
|
for (var i = 0; i < rows.length; i++) {
|
||||||
|
var expected = (rows[i].maxx - rows[i].minx + 1) * (rows[i].maxy - rows[i].miny + 1);
|
||||||
|
query.get(
|
||||||
|
expected,
|
||||||
|
rows[i].zoom,
|
||||||
|
rows[i].minx,
|
||||||
|
rows[i].maxx,
|
||||||
|
rows[i].miny,
|
||||||
|
rows[i].maxy,
|
||||||
|
group()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
query.finalize();
|
||||||
|
},
|
||||||
|
function(err, rows) {
|
||||||
|
if (err) throw err;
|
||||||
|
console.warn('');
|
||||||
|
var output = [];
|
||||||
|
output.push(['Z', 'Tiles', 'Missing']);
|
||||||
|
_(rows).each(function(row, index) {
|
||||||
|
output.push([
|
||||||
|
row.zoom,
|
||||||
|
zooms[index].count,
|
||||||
|
row.expected - row.count
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
utils.table(output);
|
||||||
|
this();
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
var MBTiles = require('./lib/mbtiles'),
|
var MBTiles = require('./lib/mbtiles'),
|
||||||
|
utils = require('./lib/utils'),
|
||||||
Step = require('step');
|
Step = require('step');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
MBTiles: MBTiles,
|
MBTiles: MBTiles,
|
||||||
|
utils: utils,
|
||||||
pool: function(datasource) {
|
pool: function(datasource) {
|
||||||
return {
|
return {
|
||||||
create: function(callback) {
|
create: function(callback) {
|
||||||
|
|||||||
@@ -34,6 +34,17 @@ MBTiles.prototype.exists = function(table, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DB integrity check.
|
||||||
|
MBTiles.prototype.integrity = function(callback) {
|
||||||
|
this.db.get('PRAGMA quick_check(1)', function(err, row) {
|
||||||
|
if (!(row && row.integrity_check && row.integrity_check === 'ok')) {
|
||||||
|
callback(new Error('Corrupted database.'));
|
||||||
|
} else {
|
||||||
|
callback(null, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Setup schema, indices, views for a new mbtiles database.
|
// Setup schema, indices, views for a new mbtiles database.
|
||||||
// Sets the synchronous flag to OFF for (much) faster inserts.
|
// Sets the synchronous flag to OFF for (much) faster inserts.
|
||||||
// See http://www.sqlite3.org/pragma.html#pragma_synchronous
|
// See http://www.sqlite3.org/pragma.html#pragma_synchronous
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
var utils = {};
|
||||||
|
|
||||||
|
utils.table = function(fields) {
|
||||||
|
if (!fields[0]) return;
|
||||||
|
var lengths = fields[0].map(function(val, i) {
|
||||||
|
return Math.max.apply(Math, fields.map(function(field) {
|
||||||
|
if (field[i] === undefined) field[i] = '';
|
||||||
|
return field[i].toString().length;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
fields.forEach(function(field) {
|
||||||
|
console.warn(
|
||||||
|
' ' + field.map(function(val, i) {
|
||||||
|
if (i >= lengths.length - 1) return val;
|
||||||
|
return val + Array(lengths[i] - val.toString().length + 1).join(' ');
|
||||||
|
}).join(' ')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = utils;
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
"Young Hahn <yhahn>"
|
"Young Hahn <yhahn>"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"optimist": "0.2.x",
|
||||||
"sqlite3": "2.0.x",
|
"sqlite3": "2.0.x",
|
||||||
"step": "0.0.x",
|
"step": "0.0.x",
|
||||||
"underscore": "1.1.x",
|
"underscore": "1.1.x",
|
||||||
|
|||||||
Reference in New Issue
Block a user