'use strict';
const { UnsupportedEngine } = require('./errors');
+const path = require('node:path');
/**
* Instantiate a database engine based on the configured connection string.
* @param {Object} options
* @param {Object} options.db
* @param {String} options.db.connectionString
- * @param {...any} engineArguments
+ * @param {...any} engineArguments
* @returns {Database}
*/
- constructor(Abstract, logger, options, ...engineArguments) {
+ constructor(enginePathPrefix, logger, options, ...engineArguments) {
const connectionString = options.db.connectionString || '';
const protocol = connectionString.slice(0, connectionString.indexOf('://')).toLowerCase();
-
- const EngineCreator = DatabaseFactory.requireEngineCreator(protocol);
- const Engine = EngineCreator(Abstract);
+ const enginePath = this.enginePath(enginePathPrefix, protocol);
+ const Engine = this.localRequire(enginePath);
return new Engine(logger, options, ...engineArguments);
}
/**
- * Return the required db class as specified by `protocol`.
- * @param {String} protocol
- * @returns {Object}
+ * N.B. Re-implement this so require runs from expected location!
+ * @param {String} enginePath
*/
- static requireEngineCreator(protocol) {
- const Engines = DatabaseFactory.Engines;
- switch (protocol) {
- case Engines.PostgreSQL:
- return require('./postgres-creator');
-
- case Engines.SQLite:
- return require('./sqlite-creator');
+ localRequire(enginePath) { // eslint-disable-line class-methods-use-this
+ return require(enginePath); // eslint-disable-line security/detect-non-literal-require
+ }
- default:
- throw new UnsupportedEngine(protocol);
- }
+ get supportedProtocols() { // eslint-disable-line class-methods-use-this
+ return [
+ 'postgresql',
+ 'sqlite',
+ ];
}
- /**
- * Mapping of protocol types.
- */
- static get Engines() {
- return {
- PostgreSQL: 'postgresql',
- SQLite: 'sqlite',
- };
+ enginePath(enginePathPrefix, protocol) {
+ if (!this.supportedProtocols.includes(protocol)) {
+ throw new UnsupportedEngine(protocol);
+ }
+ return [enginePathPrefix, protocol].join(path.sep);
}
}
// Suppress QueryFile warnings when running tests
this.noWarnings = options.db.noWarnings;
+
+ // Use a schema if provided
+ this.pgSchema = options.db.pgSchema;
}
'use strict';
-const Abstract = require('../lib/abstract');
+const { Abstract } = require('../');
class AbstractIntegration extends Abstract {
constructor(...args) {
--- /dev/null
+'use strict';
+
+const { Factory: BaseFactory } = require('../');
+
+class Factory extends BaseFactory {
+ constructor(...args) {
+ super('.', ...args);
+ }
+ localRequire(enginePath) {
+ return require(enginePath);
+ }
+}
+
+module.exports = Factory;
if (process.env.POSTGRES_TEST_PATH) {
implementations.push({
name: 'PostgreSQL',
- module: '../test-integration/postgres',
+ module: '../test-integration/',
config: {
db: {
connectionString: `postgresql://${process.env.POSTGRES_TEST_PATH}`,
if (process.env.SQLITE_TEST_PATH) {
implementations.push({
name: 'SQLite',
- module: '../test-integration/sqlite',
+ module: '../test-integration/',
config: {
db: {
connectionString: `sqlite://${process.env.SQLITE_TEST_PATH}`,
const assert = require('node:assert');
const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
const Factory = require('../../lib/factory');
-const Abstract = require('../../lib/abstract');
const { UnsupportedEngine } = require('../../lib/errors');
const pgp = require('pg-promise');
const nop = () => unknown;
describe('Factory', function () {
- let logger, options;
+ let logger, options, enginePathPrefix;
beforeEach(function () {
logger = process.env['VERBOSE_TESTS'] ? console : { log: nop, debug: nop };
connectionString: '',
},
};
+ enginePathPrefix = '../test-integration';
});
it('covers postgres', function () {
sinon.stub(pgp.utils, 'enumSql').returns({});
options.db.connectionString = 'postgresql://example';
- const factory = new Factory(Abstract, logger, options);
+ const factory = new Factory(enginePathPrefix, logger, options);
assert(factory);
});
it('covers sqlite', function () {
options.db.connectionString = 'sqlite://:memory:';
- const factory = new Factory(Abstract, logger, options);
+ const factory = new Factory(enginePathPrefix, logger, options);
assert(factory);
});
it('covers unknown', function () {
options.db.connectionString = 'redis://example';
- assert.throws(() => new Factory(Abstract, logger, options), UnsupportedEngine);
+ assert.throws(() => new Factory(enginePathPrefix, logger, options), UnsupportedEngine);
});
it('covers empty', function () {
delete options.db.connectionString;
- assert.throws(() => new Factory(Abstract, logger, options), UnsupportedEngine);
+ assert.throws(() => new Factory(enginePathPrefix, logger, options), UnsupportedEngine);
});
}); // Factory