UNPKG

@n8n/typeorm

Version:

Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports PostgreSQL and SQLite databases.

159 lines (157 loc) 6.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqliteLibrary = void 0; const tslib_1 = require("tslib"); const mkdirp_1 = require("mkdirp"); const path_1 = tslib_1.__importDefault(require("path")); const DriverPackageNotInstalledError_1 = require("../../error/DriverPackageNotInstalledError"); const QueryResult_1 = require("../../query-runner/QueryResult"); const QueryFailedError_1 = require("../../error/QueryFailedError"); /** * An adapter to the underlying SQLite library. */ class SqliteLibrary { constructor(options) { this.options = options; /** * Any attached databases (excepting default 'main') */ this.attachedDatabases = new Map(); } /** * If driver dependency is not given explicitly, then try to load it via "require". */ loadLibrary() { try { const sqlite = this.options.driver || require("sqlite3"); this.sqlite = sqlite.verbose(); } catch (e) { throw new DriverPackageNotInstalledError_1.DriverPackageNotInstalledError("SQLite", "sqlite3"); } } /** * Creates connection with the database. * * @param {number} flags Flags, such as SQLITE_OPEN_READONLY, to pass to the sqlite3 database connection */ async createDatabaseConnection(flags) { if (this.options.flags === undefined || !(this.options.flags & this.sqlite.OPEN_URI)) { await this.createDatabaseDirectory(this.options.database); } const databaseConnection = await new Promise((ok, fail) => { if (this.options.flags === undefined && flags === undefined) { const connection = new this.sqlite.Database(this.options.database, (err) => { if (err) return fail(err); ok(connection); }); } else { const connectionFlags = (this.options.flags ?? 0) | (flags ?? 0); const connection = new this.sqlite.Database(this.options.database, connectionFlags, (err) => { if (err) return fail(err); ok(connection); }); } }); // Internal function to run a command on the connection and fail if an error occured. function run(line) { return new Promise((ok, fail) => { databaseConnection.run(line, (err) => { if (err) return fail(err); ok(); }); }); } // in the options, if encryption key for SQLCipher is setted. // Must invoke key pragma before trying to do any other interaction with the database. if (this.options.key) { await run(`PRAGMA key = ${JSON.stringify(this.options.key)}`); } if (this.options.enableWAL) { await run(`PRAGMA journal_mode = WAL`); } if (this.options.busyTimeout && typeof this.options.busyTimeout === "number" && this.options.busyTimeout > 0) { await run(`PRAGMA busy_timeout = ${this.options.busyTimeout}`); } // we need to enable foreign keys in sqlite to make sure all foreign key related features // working properly. this also makes onDelete to work with sqlite. await run(`PRAGMA foreign_keys = ON`); await this.attachDatabases(databaseConnection); return databaseConnection; } async destroyDatabaseConnection(dbConnection) { return new Promise((resolve, reject) => { dbConnection.close((err) => err ? reject(err) : resolve()); }); } async runQuery(databaseConnection, query, parameters, useStructuredResult = false) { return await new Promise((resolve, reject) => { try { const isInsertQuery = query.startsWith("INSERT "); const isDeleteQuery = query.startsWith("DELETE "); const isUpdateQuery = query.startsWith("UPDATE "); const handler = function (err, rows) { if (err) { return reject(new QueryFailedError_1.QueryFailedError(query, parameters, err)); } else { const result = new QueryResult_1.QueryResult(); if (isInsertQuery) { result.raw = this["lastID"]; } else { result.raw = rows; } if (Array.isArray(rows)) { result.records = rows; } result.affected = this["changes"]; if (useStructuredResult) { resolve(result); } else { resolve(result.raw); } } }; if (isInsertQuery || isDeleteQuery || isUpdateQuery) { databaseConnection.run(query, parameters, handler); } else { databaseConnection.all(query, parameters, handler); } } catch (err) { reject(err); } }); } /** * Performs the attaching of the database files. The attachedDatabase should have been populated during calls to #buildTableName * during EntityMetadata production (see EntityMetadata#buildTablePath) * * https://sqlite.org/lang_attach.html */ async attachDatabases(connection) { // @todo - possibly check number of databases (but unqueriable at runtime sadly) - https://www.sqlite.org/limits.html#max_attached for (const { attachHandle, attachFilepathAbsolute, } of this.attachedDatabases.values()) { await this.createDatabaseDirectory(attachFilepathAbsolute); await this.runQuery(connection, `ATTACH "${attachFilepathAbsolute}" AS "${attachHandle}"`); } } /** * Auto creates database directory if it does not exist. */ async createDatabaseDirectory(fullPath) { await (0, mkdirp_1.mkdirp)(path_1.default.dirname(fullPath)); } } exports.SqliteLibrary = SqliteLibrary; //# sourceMappingURL=SqliteLibrary.js.map