UNPKG

@n8n/typeorm

Version:

Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.

155 lines (153 loc) 6.32 kB
import { mkdirp } from "mkdirp"; import path from "path"; import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"; import { PlatformTools } from "../../platform/PlatformTools"; import { QueryResult } from "../../query-runner/QueryResult"; import { QueryFailedError } from "../../error/QueryFailedError"; /** * An adapter to the underlying SQLite library. */ export 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 || PlatformTools.load("sqlite3"); this.sqlite = sqlite.verbose(); } catch (e) { throw new 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(query, parameters, err)); } else { const result = new 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 mkdirp(path.dirname(fullPath)); } } //# sourceMappingURL=SqliteLibrary.js.map