@ngageoint/geopackage
Version:
GeoPackage JavaScript Library
351 lines • 15.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqliteAdapter = void 0;
var fs_1 = __importDefault(require("fs"));
var path_1 = __importDefault(require("path"));
var http_1 = __importDefault(require("http"));
var os_1 = __importDefault(require("os"));
/**
* This adapter uses better-sqlite3 to execute queries against the GeoPackage database
* @see {@link https://github.com/JoshuaWise/better-sqlite3|better-sqlite3}
*/
var SqliteAdapter = /** @class */ (function () {
// /**
// * Creates an adapter from an already established better-sqlite3 database connection
// * @param {*} db better-sqlite3 database connection
// * @return {module:db/sqliteAdapter~Adapter}
// */
// static createAdapterFromDb(db) {
// return new SqliteAdapter(db);
// };
function SqliteAdapter(filePath) {
this.filePath = filePath;
}
/**
* Returns a Promise which, when resolved, returns a DBAdapter which has connected to the GeoPackage database file
*/
SqliteAdapter.prototype.initialize = function () {
return __awaiter(this, void 0, void 0, function () {
var Database_1, url_1, byteArray_1, tmpPath_1;
var _this = this;
return __generator(this, function (_a) {
// @ts-ignore
try {
Database_1 = require('better-sqlite3');
if (this.filePath && typeof this.filePath === 'string') {
if (this.filePath.indexOf('http') === 0) {
url_1 = this.filePath;
return [2 /*return*/, new Promise(function (resolve, reject) {
http_1.default
.get(url_1, function (response) {
if (response.statusCode !== 200) {
reject(new Error('Unable to reach url: ' + _this.filePath));
}
var tmpPath = path_1.default.join(os_1.default.tmpdir(), Date.now() + Math.floor(Math.random() * 100) + '.gpkg');
var writeStream = fs_1.default.createWriteStream(tmpPath);
response.pipe(writeStream);
writeStream.on('close', function () {
try {
_this.db = new Database_1(tmpPath);
// verify that this is an actual database
_this.db.pragma('journal_mode = WAL');
_this.filePath = tmpPath;
resolve(_this);
}
catch (err) {
console.log('error', err);
reject(err);
}
});
})
.on('error', function (e) {
reject(e);
});
})];
}
else {
this.db = new Database_1(this.filePath);
return [2 /*return*/, this];
}
}
else if (this.filePath) {
byteArray_1 = this.filePath;
tmpPath_1 = path_1.default.join(os_1.default.tmpdir(), Date.now() + '.gpkg');
return [2 /*return*/, new Promise(function (resolve, reject) {
fs_1.default.writeFile(tmpPath_1, byteArray_1, function () {
_this.db = new Database_1(tmpPath_1);
// verify that this is an actual database
try {
_this.db.pragma('journal_mode = WAL');
}
catch (err) {
console.log('error', err);
reject(err);
}
_this.filePath = tmpPath_1;
resolve(_this);
});
})];
}
else {
console.log('create in memory');
this.db = new Database_1(':memory:');
return [2 /*return*/, this];
}
}
catch (err) {
console.log('Error opening database', err);
throw err;
}
return [2 /*return*/];
});
});
};
/**
* Closes the connection to the GeoPackage
*/
SqliteAdapter.prototype.close = function () {
this.db.pragma('wal_autocheckpoint=0');
this.db.pragma('wal_checkpoint(RESTART)');
this.db.close();
};
/**
* Get the connection to the database file
* @return {*}
*/
SqliteAdapter.prototype.getDBConnection = function () {
return this.db;
};
SqliteAdapter.prototype.getFunctionList = function () {
return this.db.pragma('function_list');
};
/**
* Returns a Buffer containing the contents of the database as a file
*/
SqliteAdapter.prototype.export = function () {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve) {
return fs_1.default.readFile(_this.filePath, function (err, data) {
resolve(data);
});
})];
});
});
};
/**
* Registers the given function so that it can be used by SQL statements
* @see {@link https://github.com/JoshuaWise/better-sqlite3/wiki/API#registeroptions-function---this|better-sqlite3 register}
* @param {string} name name of function to register
* @param {Function} functionDefinition function to register
* @return {module:db/sqliteAdapter~Adapter} this
*/
SqliteAdapter.prototype.registerFunction = function (name, functionDefinition) {
this.db.function(name, functionDefinition);
return this;
};
/**
* Gets one row of results from the statement
* @see {@link https://github.com/JoshuaWise/better-sqlite3/wiki/API#getbindparameters---row|better-sqlite3 get}
* @param {string} sql statement to run
* @param {Array|Object} [params] bind parameters
* @return {Object}
*/
SqliteAdapter.prototype.get = function (sql, params) {
var statement = this.db.prepare(sql);
if (params) {
return statement.get(params);
}
else {
return statement.get();
}
};
/**
* Determines if a tableName exists in the database
* @param {String} tableName
* @returns {Boolean}
*/
SqliteAdapter.prototype.isTableExists = function (tableName) {
var statement = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=:name");
var result = statement.get({ name: tableName });
return !!result;
};
/**
* Gets all results from the statement in an array
* @see {@link https://github.com/JoshuaWise/better-sqlite3/wiki/API#allbindparameters---array-of-rows|better-sqlite3 all}
* @param {String} sql statement to run
* @param {Array|Object} [params] bind parameters
* @return {Object[]}
*/
SqliteAdapter.prototype.all = function (sql, params) {
var statement = this.db.prepare(sql);
if (params) {
return statement.all(params);
}
else {
return statement.all();
}
};
/**
* Returns an `Iterable` with results from the query
* @see {@link https://github.com/JoshuaWise/better-sqlite3/wiki/API#iteratebindparameters---iterator|better-sqlite3 iterate}
* @param {String} sql statement to run
* @param {Object|Array} [params] bind parameters
* @return {Iterable.<Object>}
*/
SqliteAdapter.prototype.each = function (sql, params) {
var statement = this.db.prepare(sql);
if (params) {
return statement.iterate(params);
}
else {
return statement.iterate();
}
};
/**
* Run the given statement, returning information about what changed.
*
* @see {@link https://github.com/JoshuaWise/better-sqlite3/wiki/API#runbindparameters---object|better-sqlite3}
* @param {String} sql statement to run
* @param {Object|Array} [params] bind parameters
* @return {{changes: number, lastInsertROWID: number}} object: `{ "changes": number, "lastInsertROWID": number }`
* * `changes`: number of rows the statement changed
* * `lastInsertROWID`: ID of the last inserted row
*/
SqliteAdapter.prototype.run = function (sql, params) {
var statement = this.db.prepare(sql);
if (params) {
return statement.run(params);
}
else {
return statement.run();
}
};
/**
* Runs the specified insert statement and returns the last inserted id or undefined if no insert happened
* @param {String} sql statement to run
* @param {Object|Array} [params] bind parameters
* @return {Number} last inserted row id
*/
SqliteAdapter.prototype.insert = function (sql, params) {
var statement = this.db.prepare(sql);
return statement.run(params).lastInsertRowid;
};
/**
* Prepares a SQL statement
* @param sql
*/
SqliteAdapter.prototype.prepareStatement = function (sql) {
return this.db.prepare(sql);
};
/**
* Runs an insert statement with the parameters provided
* @param {any} statement statement to run
* @param {Object|Array} [params] bind parameters
* @return {Number} last inserted row id
*/
SqliteAdapter.prototype.bindAndInsert = function (statement, params) {
return statement.run(params).lastInsertRowid;
};
/**
* Closes a prepared statement
* @param statement
*/
SqliteAdapter.prototype.closeStatement = function (statement) {
statement = null;
};
/**
* Runs the specified delete statement and returns the number of deleted rows
* @param {String} sql statement to run
* @param {Object|Array} params bind parameters
* @return {Number} deleted rows
*/
SqliteAdapter.prototype.delete = function (sql, params) {
var statement = this.db.prepare(sql);
return statement.run(params).changes;
};
/**
* Drops the table
* @param {String} table table name
* @return {Boolean} indicates if the table was dropped
*/
SqliteAdapter.prototype.dropTable = function (table) {
try {
var statement = this.db.prepare('DROP TABLE IF EXISTS "' + table + '"');
var result = statement.run();
var vacuum = this.db.prepare('VACUUM');
vacuum.run();
return result.changes === 0;
}
catch (e) {
console.log('Drop Table Error', e);
return false;
}
};
/**
* Counts rows that match the query
* @param {string} tableName table name from which to count
* @param {string} [where] where clause
* @param {Object|Array} [whereArgs] where args
* @return {Number} count
*/
SqliteAdapter.prototype.count = function (tableName, where, whereArgs) {
var sql = 'SELECT COUNT(*) as count FROM "' + tableName + '"';
if (where) {
sql += ' where ' + where;
}
var statement = this.db.prepare(sql);
if (whereArgs) {
return statement.get(whereArgs).count;
}
else {
return statement.get().count;
}
};
SqliteAdapter.prototype.transaction = function (func) {
this.db.transaction(func)();
};
return SqliteAdapter;
}());
exports.SqliteAdapter = SqliteAdapter;
//# sourceMappingURL=sqliteAdapter.js.map