remove old db stuff master
authorJustin Wind <justin.wind+git@gmail.com>
Tue, 15 Jul 2025 22:02:37 +0000 (15:02 -0700)
committerJustin Wind <justin.wind+git@gmail.com>
Tue, 15 Jul 2025 22:02:37 +0000 (15:02 -0700)
24 files changed:
server.js
src/db/base.js [deleted file]
src/db/index-old.js [deleted file]
src/db/postgres-old/index.js [deleted file]
src/db/postgres-old/sql/auth-get-by-id.sql [deleted file]
src/db/postgres-old/sql/auth-upsert.sql [deleted file]
src/db/postgres-old/sql/link-access.sql [deleted file]
src/db/postgres-old/sql/link-expire.sql [deleted file]
src/db/postgres-old/sql/link-get-all.sql [deleted file]
src/db/postgres-old/sql/link-get-by-id.sql [deleted file]
src/db/postgres-old/sql/link-get-by-url.sql [deleted file]
src/db/postgres-old/sql/link-update.sql [deleted file]
src/db/postgres-old/sql/link-upsert.sql [deleted file]
src/db/postgres-old/sql/schema/1.0.0/apply.sql [deleted file]
src/db/postgres-old/sql/schema/1.0.0/revert.sql [deleted file]
src/db/postgres-old/sql/schema/1.0.1/apply.sql [deleted file]
src/db/postgres-old/sql/schema/1.0.1/revert.sql [deleted file]
src/db/postgres-old/sql/schema/init.sql [deleted file]
src/db/sqlite-old/index.js [deleted file]
src/errors.js
test/src/db/base.js [deleted file]
test/src/db/postgres/index.js [deleted file]
test/src/db/sqlite/index.js [deleted file]
test/src/manager.js

index 1770dd9adb599c68561c3dddd884f9ce0208d919..24a04b263574839a786a1990943cbcbc5f61c424 100644 (file)
--- a/server.js
+++ b/server.js
@@ -49,18 +49,6 @@ async function main() {
   server.on('error', (...args) => logger.error(_scope, 'server error', { args }));
   server.on('listening', (...args) => logger.info(_scope, 'server listening', { ...args, PORT, ADDR, version }));
   server.listen(PORT, ADDR);
-
-  // http.createServer((req, res) => {
-  //   asyncLocalStorage.run({}, async () => {
-  //     await service.dispatch(req, res);
-  //   });
-  // }).listen(PORT, ADDR, (err) => {
-  //   if (err) {
-  //     logger.error(_scope, 'error starting server:', err);
-  //     throw err;
-  //   }
-  //   logger.info(_scope, 'server started', { version, listenAddress: ADDR, listenPort: PORT });
-  // });
 }
 
 main().catch(console.error);
diff --git a/src/db/base.js b/src/db/base.js
deleted file mode 100644 (file)
index db20422..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-'use strict';
-
-const common = require('../common');
-const DBErrors = require('./errors');
-
-const _fileScope = common.fileScope(__filename);
-
-class BaseDatabase {
-  constructor(logger) {
-    this.logger = logger;
-  }
-
-  static _camelfy(snakeCase, delim = '_') {
-    if (!snakeCase || typeof snakeCase.split !== 'function') {
-      return undefined;
-    }
-    const words = snakeCase.split(delim);
-    return [
-      words.shift(),
-      ...words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)),
-    ].join('');
-  }
-
-  _notImplemented(method, args) {
-    const _scope = _fileScope(method);
-    this.logger.error(_scope, 'abstract method called', Array.from(args));
-    throw new DBErrors.NotImplemented();
-  }
-
-  async context(fn) {
-    this._notImplemented('context', { fn });
-  }
-
-  async transaction(dbCtx, fn) {
-    this._notImplemented('transaction', { dbCtx, fn });
-  }
-
-  async getAuthById(dbCtx, id) {
-    this._notImplemented('getAuthById', { dbCtx, id });
-  }
-
-  async upsertAuth(dbCtx, id, secert, credential) {
-    this._notImplemented('upsertAuthCredential', { dbCtx, id, credential });
-  }
-
-  async upsertLink(dbCtx, id, url, authToken) {
-    this._notImplemented('upsertLink', { dbCtx, id, url, authToken });
-  }
-
-  async getLinkById(dbCtx, id) {
-    this._notImplemented('getLinkById', { dbCtx, id });
-  }
-
-  async getLinkByUrl(dbCtx, url) {
-    this._notImplemented('getLinkByUrl', { dbCtx, url });
-  }
-
-  async accessLink(dbCtx, id) {
-    this._notImplemented('accessLink', { dbCtx, id });
-  }
-
-  async expireLink(dbCtx, id, expires) {
-    this._notImplemented('expireLink', { dbCtx, id, expires });
-  }
-
-  async getAllLinks(dbCtx) {
-    this._notImplemented('getAllLinks', { dbCtx });
-  }
-
-}
-
-module.exports = BaseDatabase;
diff --git a/src/db/index-old.js b/src/db/index-old.js
deleted file mode 100644 (file)
index b7c9549..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-'use strict';
-
-const common = require('../common');
-const DBErrors = require('./errors');
-
-const _fileScope = common.fileScope(__filename);
-
-const defaultOptions = {
-  connectionString: '',
-};
-
-class DatabaseFactory {
-  constructor(logger, options, ...rest) {
-    const _scope = _fileScope + ':constructor';
-    options = { ...defaultOptions, ...options };
-    const protocol = options.connectionString.slice(0, options.connectionString.indexOf('://')).toLowerCase();
-    switch (protocol) {
-      case DatabaseFactory.Engines.PostgreSQL: {
-        const Postgres = require('./postgres-old');
-        return new Postgres(logger, options, ...rest);
-      }
-
-      case DatabaseFactory.Engines.SQLite: {
-        const SQLite = require('./sqlite-old');
-        return new SQLite(logger, options, ...rest);
-      }
-
-      default:
-        logger.error(_scope, 'unsupported connectionString', { options });
-        throw new DBErrors.UnsupportedEngine(protocol);
-    }
-  }
-
-  static get Engines() {
-    return {
-      PostgreSQL: 'postgresql',
-      SQLite: 'sqlite',
-    };
-  }
-
-}
-
-module.exports = DatabaseFactory;
diff --git a/src/db/postgres-old/index.js b/src/db/postgres-old/index.js
deleted file mode 100644 (file)
index 775a0a6..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-'use strict';
-
-const pgpInitOptions = {
-  capSQL: true,
-};
-
-const path = require('node:path');
-const pgp = require('pg-promise')(pgpInitOptions);
-const BaseDatabase = require('../base');
-const common = require('../../common');
-
-const _fileScope = common.fileScope(__filename);
-
-const defaultOptions = {
-  connectionString: undefined,
-  queryLogLevel: undefined,
-  listenerPingDelayMs: 2000,
-  listenerRetryDelayMs: 5000,
-  listenerRetryTimes: 10,
-  listenerChannel: 'cache_invalidation',
-  listenerCallback: () => {},
-  listenerLostCallback: () => {},
-};
-
-class PostgresDatabase extends BaseDatabase {
-  constructor(logger, options, _pgp = pgp) {
-    const _scope = _fileScope('constructor');
-
-    super(logger);
-    common.setOptions(this, defaultOptions, options);
-
-    this.logger.debug(_scope, 'connecting', { connectionString: this.connectionString });
-
-    this.db = _pgp(this.connectionString);
-
-    if (this.queryLogLevel) {
-      pgpInitOptions.query = (e) => {
-        this.logger[this.queryLogLevel](_fileScope('pgp:query'), e.query, { params: e.params });
-      };
-    }
-
-    pgpInitOptions.error = (err, event) => {
-      this.logger.error(_fileScope('pgp:error'), '', { err, event });
-    };
-
-    pgpInitOptions.receive = ({ data, result, ctx: event }) => {
-      const exemplaryRow = data[0];
-      for (const prop in exemplaryRow) {
-        const camel = BaseDatabase._camelfy(prop);
-        if (!(camel in exemplaryRow)) {
-          for (const d of data) {
-            // eslint-disable-next-line security/detect-object-injection
-            d[camel] = d[prop];
-            // eslint-disable-next-line security/detect-object-injection
-            delete d[prop];
-          }
-        }
-      }
-
-      if (this.queryLogLevel) {
-        this.logger[this.queryLogLevel](_fileScope('pgp:result'), { query: event.query, ...PostgresDatabase._resultLog(result) });
-      }
-    };
-    this._initStatements(_pgp);
-  }
-
-  static _resultLog(result) {
-    return {
-      command: result?.commaand,
-      rowCount: result?.rowCount,
-      duration: result?.duration,
-    };
-  }
-
-  _initStatements(_pgp) {
-    const _scope = _fileScope('_initStatements');
-
-    const qfOptions = {
-      minify: true,
-    };
-    this.statement = _pgp.utils.enumSql(path.join(__dirname, 'sql'), {}, (file) => {
-      const qf = new _pgp.QueryFile(file, qfOptions);
-      this.logger.debug(_scope, file, { file: qf.file, options: qf.options, query: qf.query });
-      if (qf.error) {
-        this.logger.error(_scope, file, { error: qf.error });
-        throw qf.error;
-      }
-      return qf;
-    });
-
-    this.logger.debug(_scope, 'complete', { statementCount: Object.keys(this.statement).length });
-  }
-
-  // WIP not used yet
-  async _initListener() {
-    await this._reconnectListener(0, 1);
-    this._sendListenerNotifications();
-  }
-  _sendListenerNotifications() {
-    const _scope = _fileScope('_sendListenerNotifications');
-    setTimeout(async () => {
-      if (this.listenerConnection) {
-        try {
-          await this.listenerConnection.none('NOTIFY $1~, $2', [this.listenerChannel, 'ping']);
-        } catch (e) {
-          this.logger.error(_scope, 'failed', e);
-        } finally {
-          this._sendListenerNotifications();
-        }
-      }
-    }, this.listenerPingDelayMs);
-  }
-  async _onListenerConnectionLost(err, ev) {
-    const _scope = _fileScope('_onConnectionLost');
-    const eventName = 'notification';
-    this.listenerConnection = null;
-    this.logger.error(_scope, 'listener connection lost', { err, ev });
-    ev.client.removeListener(eventName, this._onListenerNotificationBound);
-    await this.listenerLostCallback();
-    await this._reconnectListener(this.listenerRetryDelayMs, this.listenerRetryTimes);
-    this.logger.debug(_scope, 'listener reconnected');
-  }
-  async _onListenerNotification(data) {
-    return await this.listenerCallback(data.payload);
-  }
-  async _reconnectListener(delay, retriesRemaining) {
-    const _scope = _fileScope('_reconnectListener');
-    const eventName = 'notification';
-    if (this.listenerConnection) {
-      this.listenerConnection.done();
-      this.listenerConnection = null;
-    }
-    if (this.listenerReconnectPending) {
-      clearTimeout(this.listenerReconnectPending);
-      delete this.listenerReconnectPending;
-    }
-    return new Promise((resolve, reject) => {
-      this.listenerReconnectPending = setTimeout(async () => {
-        try {
-          this.listenerConnection = await this.db.connect({
-            direct: true,
-            onLost: this._onListenerConnectionLost.bind(this),
-          });
-          if (!this._onListenerNotificationBound) {
-            this._onListenerNotificationBound = this._onListenerNotification.bind(this);
-          }
-          this.listenerConnection.client.on(eventName, this._onListenerNotificationBound);
-          await this.listenerConnection.none('LISTEN $1~', this.listenerChannel);
-          delete this.listenerReconnectPending;
-          this.logger.debug(_scope, 'listener connection established');
-          resolve();
-        } catch (e) {
-          if (retriesRemaining > 0) {
-            try {
-              await this._reconnectListener(delay, retriesRemaining - 1);
-              resolve();
-            } catch (e2) {
-              reject(e2);
-            }
-          } else {
-            reject(e);
-          }
-        }
-      }, delay);
-    });
-  }
-
-
-  // eslint-disable-next-line class-methods-use-this
-  _postgresInfo(result) {
-    return {
-      changes: result.rowCount,
-      lastInsertRowid: result.rows.length ? result.rows[0].id : undefined,
-      duration: result.duration,
-    };
-  }
-
-  async context(fn) {
-    return await this.db.task(async (t) => await fn(t));
-  }
-
-
-  async transaction(dbCtx, fn) {
-    dbCtx = dbCtx || this.db;
-    return await dbCtx.txIf(async (t) => await fn(t));
-  }
-
-
-  async getAuthById(dbCtx, id) {
-    const _scope = _fileScope('getAuthById');
-    this.logger.debug(_scope, 'called', { id });
-  
-    dbCtx = dbCtx || this.db;
-
-    const auth = await dbCtx.oneOrNone(this.statement.authGetById, { id });
-    this.logger.debug(_scope, 'get', { auth });
-    return auth;
-  }
-
-
-  async upsertAuth(dbCtx, id, secret, credential) {
-    const _scope = _fileScope('upsertAuth');
-    this.logger.debug(_scope, 'called', { id });
-    dbCtx = dbCtx || this.db;
-
-    const result = await dbCtx.result(this.statement.authUpsert, { id, secret, credential });
-    this.logger.debug(_scope, 'result', PostgresDatabase._resultLog(result) );
-  }
-
-
-  static _epochFix(epoch) {
-    switch (epoch) {
-      case Infinity:
-        return Number.MAX_SAFE_INTEGER;
-      
-      case -Infinity:
-        return 0;
-
-      default:
-        return epoch;
-    }
-  }
-
-
-  static _linkToNative(link) {
-    return link && {
-      ...link,
-      created: PostgresDatabase._epochFix(link.created),
-      lastAccess: PostgresDatabase._epochFix(link.lastAccess),
-      expires: PostgresDatabase._epochFix(link.expires),
-    };
-  }
-
-  async upsertLink(dbCtx, id, url, authToken) {
-    const _scope = _fileScope('upsertLink');
-    this.logger.debug(_scope, 'called', { id, url, authToken });
-  
-    dbCtx = dbCtx || this.db;
-
-    const result = await dbCtx.result(this.statement.linkUpsert, { id, url, authToken });
-    this.logger.debug(_scope, 'result', PostgresDatabase._resultLog(result) );
-    return this._postgresInfo(result);
-  }
-
-
-  async getLinkById(dbCtx, id) {
-    const _scope = _fileScope('getLinkById');
-    this.logger.debug(_scope, 'called', { id });
-  
-    dbCtx = dbCtx || this.db;
-
-    const link = await dbCtx.oneOrNone(this.statement.linkGetById, { id });
-    this.logger.debug(_scope, 'get', { link });
-    return PostgresDatabase._linkToNative(link);
-  }
-
-
-  async getLinkByUrl(dbCtx, url) {
-    const _scope = _fileScope('getLinkByUrl');
-    this.logger.debug(_scope, 'called', { url });
-  
-    dbCtx = dbCtx || this.db;
-
-    const link = await dbCtx.oneOrNone(this.statement.linkGetByUrl, { url });
-    this.logger.debug(_scope, 'get', { link });
-    return PostgresDatabase._linkToNative(link);
-  }
-
-
-  async accessLink(dbCtx, id) {
-    const _scope = _fileScope('accessLink');
-    this.logger.debug(_scope, 'called', { id });
-  
-    dbCtx = dbCtx || this.db;
-
-    const link = await dbCtx.oneOrNone(this.statement.linkAccess, { id });
-    this.logger.debug(_scope, 'get', { link });
-    return PostgresDatabase._linkToNative(link);
-  }
-
-
-  async expireLink(dbCtx, id, expires) {
-    const _scope = _fileScope('expireLink');
-    this.logger.debug(_scope, 'called', { id, expires });
-  
-    dbCtx = dbCtx || this.db;
-
-    const result = await dbCtx.result(this.statement.linkExpire, { expires, id });
-    this.logger.debug(_scope, 'result', PostgresDatabase._resultLog(result) );
-    return this._postgresInfo(result);
-  }
-
-
-  async getAllLinks(dbCtx) {
-    const _scope = _fileScope('getAllLinks');
-    this.logger.debug(_scope, 'called', { });
-  
-    dbCtx = dbCtx || this.db;
-
-    const links = await dbCtx.manyOrNone(this.statement.linkGetAll, { });
-    this.logger.debug(_scope, 'get', { links });
-    return links.map((l) => PostgresDatabase._linkToNative(l));
-  }
-
-
-}
-
-module.exports = PostgresDatabase;
diff --git a/src/db/postgres-old/sql/auth-get-by-id.sql b/src/db/postgres-old/sql/auth-get-by-id.sql
deleted file mode 100644 (file)
index 98f0434..0000000
+++ /dev/null
@@ -1 +0,0 @@
-SELECT * FROM auth WHERE id = $(id)
\ No newline at end of file
diff --git a/src/db/postgres-old/sql/auth-upsert.sql b/src/db/postgres-old/sql/auth-upsert.sql
deleted file mode 100644 (file)
index f90be73..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
---
-INSERT INTO auth (id, secret, password) VALUES ($(id), $(secret), $(credential))
-ON CONFLICT (id) DO
-UPDATE SET password = $(credential), secret = $(secret)
diff --git a/src/db/postgres-old/sql/link-access.sql b/src/db/postgres-old/sql/link-access.sql
deleted file mode 100644 (file)
index 5f4c128..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-UPDATE link SET accesses = accesses + 1, last_access = now() WHERE id = $(id)
-RETURNING *,
-       extract(epoch from created) AS created,
-       extract(epoch from last_access) AS last_access,
-       extract(epoch from expires) AS expires
diff --git a/src/db/postgres-old/sql/link-expire.sql b/src/db/postgres-old/sql/link-expire.sql
deleted file mode 100644 (file)
index a799b8a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-UPDATE link SET expires = to_timestamp($(expires)) WHERE id = $(id)
\ No newline at end of file
diff --git a/src/db/postgres-old/sql/link-get-all.sql b/src/db/postgres-old/sql/link-get-all.sql
deleted file mode 100644 (file)
index 40a935f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-SELECT *,
-       extract(epoch from created) AS created,
-       extract(epoch from last_access) AS last_access,
-       extract(epoch from expires) AS expires
-FROM link
-ORDER BY id
\ No newline at end of file
diff --git a/src/db/postgres-old/sql/link-get-by-id.sql b/src/db/postgres-old/sql/link-get-by-id.sql
deleted file mode 100644 (file)
index 8eeb27d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-SELECT *,
-       extract(epoch from created) AS created,
-       extract(epoch from last_access) AS last_access,
-       extract(epoch from expires) AS expires
-FROM link WHERE id = $(id)
\ No newline at end of file
diff --git a/src/db/postgres-old/sql/link-get-by-url.sql b/src/db/postgres-old/sql/link-get-by-url.sql
deleted file mode 100644 (file)
index 113837a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-SELECT *,
-       extract(epoch from created) AS created,
-       extract(epoch from last_access) AS last_access,
-       extract(epoch from expires) AS expires
-FROM link WHERE url = $(url)
\ No newline at end of file
diff --git a/src/db/postgres-old/sql/link-update.sql b/src/db/postgres-old/sql/link-update.sql
deleted file mode 100644 (file)
index fb04ea4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-UPDATE link SET url = $(url) WHERE id = $(id)
\ No newline at end of file
diff --git a/src/db/postgres-old/sql/link-upsert.sql b/src/db/postgres-old/sql/link-upsert.sql
deleted file mode 100644 (file)
index 9a8e024..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-INSERT INTO link (id, url, auth_token)
-       VALUES
-               ($(id), $(url), $(authToken))
-       ON CONFLICT (id) DO UPDATE
-       SET
-               url = $(url)
-RETURNING *,
-       extract(epoch from created) AS created,
-       extract(epoch from last_access) AS last_access,
-       extract(epoch from expires) AS expires
diff --git a/src/db/postgres-old/sql/schema/1.0.0/apply.sql b/src/db/postgres-old/sql/schema/1.0.0/apply.sql
deleted file mode 100644 (file)
index c05abc9..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-BEGIN;
-
-       -- core data
-       CREATE TABLE link (
-               id TEXT NOT NULL PRIMARY KEY,
-               url TEXT NOT NULL UNIQUE,
-               created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
-               last_access TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT '-infinity'::timestamptz,
-               accesses INTEGER NOT NULL DEFAULT 0,
-               expires TIMESTAMP WITH TIME ZONE,
-               auth_token TEXT
-       );
-
-       -- send notices to invalidate cacheable link data
-       CREATE OR REPLACE FUNCTION cache_invalidation_link()
-               RETURNS TRIGGER
-               LANGUAGE plpgsql
-               AS $$
-               DECLARE
-                       payload varchar;
-               BEGIN
-                       IF NEW.url != OLD.url OR NEW.expires != OLD.expires
-                       THEN
-                               payload = 'link|' || CAST(NEW.id AS text);
-                               PERFORM pg_notify('cache_invalidation', payload);
-                       END IF;
-                       RETURN NEW;
-               END;
-               $$
-       ;
-       CREATE TRIGGER cache_invalidation_link
-               AFTER UPDATE
-               ON link
-               FOR EACH ROW
-                       EXECUTE PROCEDURE cache_invalidation();
-
-       -- better auth TBD
-       CREATE TABLE auth (
-               id TEXT NOT NULL PRIMARY KEY,
-               secret TEXT NOT NULL,
-               password TEXT
-       );
-
-       -- system entries
-       INSERT INTO link (id, url) VALUES
-               ('static', '/static/index.html'),
-               ('favicon.ico', '/static/favicon.ico'),
-               ('robots.txt', '/static/robots.txt')
-       ;
-
-       -- migration complete
-       INSERT INTO _meta_schema_version (major, minor, patch) VALUES (1, 0, 0);
-COMMIT;
diff --git a/src/db/postgres-old/sql/schema/1.0.0/revert.sql b/src/db/postgres-old/sql/schema/1.0.0/revert.sql
deleted file mode 100644 (file)
index 38ed34d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-BEGIN;
-       DROP TRIGGER cache_invalidation_link ON link;
-       DROP FUNCTION cache_invalidation_link();
-       DROP TABLE auth;
-       DROP TABLE link;
-       DELETE FROM _meta_schema_version WHERE major = 1 AND minor = 0 AND patch = 0;
-COMMIT;
diff --git a/src/db/postgres-old/sql/schema/1.0.1/apply.sql b/src/db/postgres-old/sql/schema/1.0.1/apply.sql
deleted file mode 100644 (file)
index 94374ff..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-BEGIN;
-
-       ALTER TABLE link
-               ADD COLUMN is_special BOOLEAN NOT NULL DEFAULT false
-       ;
-
-       UPDATE link
-               SET is_special = true
-       WHERE
-               url = ANY('/static/robots.txt', '/static/index.html',  '/static/favicon.ico');
-
-       INSERT INTO _meta_schema_version (major, minor, patch) VALUES (1, 0, 1);
-
-COMMIT;
diff --git a/src/db/postgres-old/sql/schema/1.0.1/revert.sql b/src/db/postgres-old/sql/schema/1.0.1/revert.sql
deleted file mode 100644 (file)
index 08fa1c4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-BEGIN;
-
-       ALTER TABLE link
-               DROP COLUMN is_special
-       ;
-
-       DELETE FROM _meta_schema_version WHERE major = 1 AND minor = 0 AND patch = 1;
-
-COMMIT;
diff --git a/src/db/postgres-old/sql/schema/init.sql b/src/db/postgres-old/sql/schema/init.sql
deleted file mode 100644 (file)
index 27fdae3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-BEGIN;
-       CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-
-       CREATE TABLE IF NOT EXISTS _meta_schema_version (
-               major BIGINT NOT NULL,
-               minor BIGINT NOT NULL,
-               patch BIGINT NOT NULL,
-               applied TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
-               PRIMARY KEY (major, minor, patch)
-       );
-       INSERT INTO _meta_schema_version (major, minor, patch) VALUES (0, 0, 0);
-COMMIT;
diff --git a/src/db/sqlite-old/index.js b/src/db/sqlite-old/index.js
deleted file mode 100644 (file)
index 610a3d3..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-'use strict';
-
-const SQLite = require('better-sqlite3');
-const BaseDatabase = require('../base');
-const common = require('../../common');
-const DBErrors = require('../errors');
-
-const _fileScope = common.fileScope(__filename);
-
-const defaultOptions = {
-  connectionString: '',
-  optimizeAfterChanges: 1000,
-  queryLogLevel: 'debug',
-};
-
-const EPOCH_NOW = '(strftime(\'%s\', \'now\'))';
-
-class SQLiteDatabase extends BaseDatabase {
-  constructor(logger, options) {
-    const _scope = _fileScope('constructor');
-
-    super(logger);
-    common.setOptions(this, defaultOptions, options);
-
-    this.dbFilename = this.connectionString.slice('sqlite://'.length) || ':memory:';
-
-    this.logger.debug(_scope, 'connecting', { dbFilename: this.dbFilename });
-
-    this.db = new SQLite(this.dbFilename, {
-      verbose: (query) => this.queryLogLevel && this.logger[this.queryLogLevel](_fileScope('statement'), 'executing', { query }),
-    });
-
-    this.changesSinceLastOptimize = BigInt(0);
-
-    this.db.pragma('foreign_keys = on');
-    this.db.pragma('journal_mode = WAL');
-    this.db.defaultSafeIntegers(true);
-
-    this._initTables();
-    this._initStatements();
-  }
-
-  async initialize() {
-    this._x = true;
-  }
-
-  healthCheck() {
-    const _scope = _fileScope('healthCheck');
-    this.logger.debug(_scope, 'called', {});
-    if (!this.db.open) {
-      throw new DBErrors.UnexpectedResult('database is not open');
-    }
-    return { open: this.db.open };
-  }
-
-  _closeConnection() {
-    this.db.close();
-  }
-
-  _purgeTables(really) {
-    if (really) {
-      const extantTableNames = ['auth', 'link'];
-      extantTableNames.forEach((table) => {
-        const result = this.db.prepare(`DELETE FROM ${table}`).run();
-        this.logger.debug(_fileScope('_purgeTables'), 'success', { table, result });
-      });
-    }
-  }
-
-  _initTables() {
-    const _scope = _fileScope('_initTables');
-    const tableExists = this.db.prepare('SELECT name FROM sqlite_master WHERE type=\'table\' AND name=:tableName').pluck(true);
-
-    const tables = [
-      {
-        name: 'auth',
-        statements: [
-          `CREATE TABLE IF NOT EXISTS auth (
-            id TEXT NOT NULL PRIMARY KEY CHECK (typeof(id) = 'text'),
-            secret TEXT NOT NULL CHECK (typeof(secret) = 'text'),
-            password TEXT CHECK (typeof(password) IN ('text', 'null'))
-          )`,
-          `INSERT INTO auth (id, secret, password)
-            VALUES
-            ('foo', 'secret', 'quux')`,
-        ],
-      },
-      {
-        name: 'link',
-        statements: [
-          `CREATE TABLE IF NOT EXISTS link (
-            id TEXT NOT NULL PRIMARY KEY CHECK (typeof(id) = 'text'),
-            url TEXT NOT NULL UNIQUE CHECK (typeof(url) = 'text'),
-            created INTEGER NOT NULL DEFAULT ${EPOCH_NOW} CHECK (typeof(created) = 'integer'),
-            last_access INTEGER NOT NULL DEFAULT 0 CHECK (typeof(last_access) = 'integer'),
-            accesses INTEGER NOT NULL DEFAULT 0 CHECK (typeof(accesses) = 'integer'),
-            expires INTEGER CHECK (typeof(expires) IN ('integer', 'null')),
-            auth_token TEXT CHECK (typeof(auth_token) IN ('text', 'null')),
-            is_special INTEGER NOT NULL DEFAULT 0 CHECK (is_special IN (0, 1))
-          )`,
-          'CREATE INDEX IF NOT EXISTS link_url_idx ON link(url)',
-        ],
-      },
-    ];
-
-    tables.forEach((t) => {
-      const table = tableExists.get({ tableName: t.name });
-      if (table === undefined) {
-        t.statements.forEach((s) => {
-          this.logger.info(_scope, 'creating table', { tableName: t.name });
-          this.db.prepare(s).run();
-        });
-      }
-    });
-  }
-
-  _initStatements() {
-    this.statement = {
-      _beginImmediate: this.db.prepare('BEGIN IMMEDIATE'),
-      _commit: this.db.prepare('COMMIT'),
-      _rollback: this.db.prepare('ROLLBACK'),
-      getAuthById: this.db.prepare('SELECT * FROM auth WHERE id = :id'),
-      insertAuth: this.db.prepare('INSERT INTO auth (id, secret, password) VALUES (:id, :secret, :credential)'),
-      updateAuth: this.db.prepare('UPDATE auth SET password = :credential, secret = :secret WHERE id = :id'),
-      getLinkById: this.db.prepare('SELECT * FROM link WHERE id = :id'),
-      getLinkByUrl: this.db.prepare('SELECT * FROM link WHERE url = :url'),
-      upsertLink: this.db.prepare('INSERT INTO link (id, url, auth_token) VALUES (:id, :url, :authToken)'),
-      updateLink: this.db.prepare('UPDATE link SET url = :url WHERE id = :id'),
-      incrementLinkAccess: this.db.prepare(`UPDATE link SET accesses = accesses + 1, last_access = ${EPOCH_NOW} WHERE id = :id`),
-      expireLink: this.db.prepare('UPDATE link SET expires = :expires WHERE id = :id'),
-      linkGetAll: this.db.prepare('SELECT * FROM link'),
-    };
-  }
-
-  _optimize() {
-    const _scope = _fileScope('_optimize');
-    this.logger.debug(_scope, 'called', {});
-    const optimizations = this.db.prepare('SELECT * FROM pragma_optimize(0x03)').all();
-    this.logger.debug(_scope, 'pragma preview', { optimizations });
-    this.db.pragma('optimize');
-    this.changesSinceLastOptimize = BigInt(0);
-  }
-
-  _maybeOptimize() {
-    if (this.changesSinceLastOptimize >= this.optimizeAfterChanges) {
-      this._optimize();
-    }
-  }
-
-  _sqliteInfo(info) {
-    if (info.changes) {
-      this.changesSinceLastOptimize += BigInt(info.changes);
-      this._maybeOptimize();
-    }
-    return {
-      changes: Number(info.changes),
-      lastInsertRowid: Number(info.lastInsertRowid),
-    };
-  }
-
-  static _deOphidiate(row) {
-    return row && Object.keys(row).reduce((snakelessRow, k) => Object.assign(snakelessRow, {
-      // eslint-disable-next-line security/detect-object-injection
-      [BaseDatabase._camelfy(k)]: row[k],
-    }), {});
-  }
-
-
-  async context(fn) {
-    const dbCtx = this.db;
-    return await fn(dbCtx);
-  }
-
-  async transaction(dbCtx, fn, ...rest) {
-    dbCtx = dbCtx || this.db;
-    try {
-      this.statement._beginImmediate.run();
-      const result = await fn(dbCtx, ...rest);
-      this.statement._commit.run();
-      return result;
-    } finally {
-      if (this.db.inTransaction) {
-        this.statement._rollback.run();
-      }
-    }
-  }
-
-  async getAuthById(dbCtx, id) {
-    const _scope = _fileScope('getAuthById');
-    this.logger.debug(_scope, 'called', { id });
-  
-    let auth;
-    auth = this.statement.getAuthById.get({ id });
-    auth = SQLiteDatabase._deOphidiate(auth);
-
-    this.logger.debug(_scope, 'get', { auth });
-    return auth;
-  }
-
-  async upsertAuth(dbCtx, id, secret, credential) {
-    const _scope = _fileScope('upsertAuthCredential');
-    this.logger.debug(_scope, 'called', { id });
-
-    let info;
-    try {
-      info = this.statement.insertAuth.run({ id, secret, credential });
-    } catch (e) {
-      switch (e.code) {
-        case 'SQLITE_CONSTRAINT_UNIQUE':
-        case 'SQLITE_CONSTRAINT_PRIMARYKEY': {
-          this.logger.debug(_scope, 'updating existing auth', { id });
-          info = this.statement.updateAuth.run({ id, secret, credential });
-          break;
-        }
-
-        default: {
-          this.logger.error(_scope, 'failed to upsert auth credential', { error: e, id });
-          throw e;
-        }
-      }
-    }
-    this.logger.debug(_scope, 'run', { info });
-    if (info.changes != 1) {
-      this.logger.error(_scope, 'failed to upsert auth credential', { id, info });
-      throw new DBErrors.UnexpectedResult();
-    }
-
-    return this._sqliteInfo(info);
-  }
-
-  async upsertLink(dbCtx, id, url, authToken) {
-    const _scope = _fileScope('upsertLink');
-    this.logger.debug(_scope, 'called', { id, url });
-
-    let info;
-    try {
-      info = this.statement.upsertLink.run({ id, url, authToken });
-    } catch (e) {
-      switch (e.code) {
-        case 'SQLITE_CONSTRAINT_UNIQUE':
-        case 'SQLITE_CONSTRAINT_PRIMARYKEY': {
-          this.logger.debug(_scope, 'updating existing id', { id, url });
-          info = this.statement.updateLink.run({ id, url });
-          break;
-        }
-
-        default: {
-          this.logger.error(_scope, 'failed to insert link', { error: e, id, url });
-          throw e;
-        }
-      }
-    }
-    this.logger.debug(_scope, 'run', { info });
-    if (info.changes != 1) {
-      this.logger.error(_scope, 'failed to insert link', { id, url, info });
-      throw new DBErrors.UnexpectedResult();
-    }
-
-    return this._sqliteInfo(info);
-  }
-
-  static _linkToNative(link) {
-    return link && {
-      id: link.id,
-      url: link.url,
-      created: Number(link.created),
-      lastAccess: Number(link.lastAccess),
-      accesses: Number(link.accesses),
-      expires: ('expires' in link) ? Number(link.expires) : undefined,
-      authToken: link.authToken,
-      isSpecial: !! link.isSpecial,
-    };
-  }
-
-  async getLinkById(dbCtx, id) {
-    const _scope = _fileScope('getLinkById');
-    this.logger.debug(_scope, 'called', { id });
-
-    let link = this.statement.getLinkById.get({ id });
-    link = SQLiteDatabase._deOphidiate(link);
-
-    this.logger.debug(_scope, 'get', { link });
-    return SQLiteDatabase._linkToNative(link);
-  }
-
-  async getLinkByUrl(dbCtx, url) {
-    const _scope = _fileScope('getLinkByUrl');
-    this.logger.debug(_scope, 'called', { url });
-
-    let link = this.statement.getLinkByUrl.get({ url });
-    link = SQLiteDatabase._deOphidiate(link);
-
-    this.logger.debug(_scope, 'get', { link });
-    return SQLiteDatabase._linkToNative(link);
-  }
-
-  async accessLink(dbCtx, id) {
-    const _scope = _fileScope('accessLink');
-    this.logger.debug(_scope, 'called', { id });
-
-    let link = this.statement.getLinkById.get({ id });
-    link = SQLiteDatabase._deOphidiate(link);
-
-    this.logger.debug(_scope, 'get', { id, link });
-
-    if (link) {
-      const info = this.statement.incrementLinkAccess.run({ id });
-      this.logger.debug(_scope, 'increment', { id, info });
-      if (info.changes != 1) {
-        this.logger.error(_scope, 'failed to increment link access', { id, link, info });
-        throw new DBErrors.UnexpectedResult();
-      }
-    }
-    return SQLiteDatabase._linkToNative(link);
-  }
-
-  async expireLink(dbCtx, id, expires) {
-    const _scope = _fileScope('expireLink');
-    this.logger.debug(_scope, 'called', { id });
-
-    const info = this.statement.expireLink.run({ id, expires });
-    if (info.changes != 1) {
-      throw new DBErrors.UnexpectedResult();
-    }
-    return this._sqliteInfo(info);
-  }
-
-  // eslint-disable-next-line no-unused-vars
-  async getAllLinks(dbCtx) {
-    const _scope = _fileScope('getAllLinks');
-    this.logger.debug(_scope, 'called', { });
-  
-    let links;
-    links = this.statement.linkGetAll.all({});
-    links = links.map((l) => SQLiteDatabase._deOphidiate(l));
-    this.logger.debug(_scope, 'get', { links });
-    links = links.map((l) => SQLiteDatabase._linkToNative(l));
-    return links;
-  }
-
-}
-
-module.exports = SQLiteDatabase;
index 1259fea2f59bdb19d12bac833242dc179802bc08..ca28841bbc4a6c29226a080fb3b917591bf1ae1b 100644 (file)
@@ -2,13 +2,6 @@
 
 const { Errors } = require('@squeep/api-dingus');
 
-class DatabaseError extends Errors.DingusError {
-  constructor(...args) {
-    super(...args);
-    Error.captureStackTrace(DatabaseError);
-  }
-}
-
 class ServeStaticFile extends Errors.DingusError {
   constructor(file, ...args) {
     super(...args);
@@ -21,7 +14,6 @@ class SlugGeneratorExhausted extends Errors.DingusError {}
 
 module.exports = {
   ...Errors,
-  DatabaseError,
   ServeStaticFile,
   SlugGeneratorExhausted,
 };
\ No newline at end of file
diff --git a/test/src/db/base.js b/test/src/db/base.js
deleted file mode 100644 (file)
index fab28fb..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-'use strict';
-
-const assert = require('node:assert');
-const sinon = require('sinon');
-const BaseDatabase = require('../../../src/db/base');
-const DBErrors = require('../../../src/db/errors');
-
-const noExpectedException = 'did not get expected exception';
-
-describe('BaseDatabase', function () {
-  let logger, db;
-
-  beforeEach(function () {
-    logger = { error: () => {} };
-    db = new BaseDatabase(logger);
-  });
-
-  afterEach(function () {
-    sinon.restore();
-  });
-
-  describe('_camelfy', function () {
-    it('empty arg', function () {
-      const result = BaseDatabase._camelfy();
-      assert.strictEqual(result, undefined);
-    });
-    it('no change', function () {
-      const str = 'camelCase';
-      const result = BaseDatabase._camelfy(str);
-      assert.strictEqual(result, str);
-    });
-    it('does expected', function () {
-      const str = 'snake_case_thing';
-      const result = BaseDatabase._camelfy(str);
-      assert.strictEqual(result, 'snakeCaseThing');
-    });
-  }); // _camelfy
-
-  describe('interface', function () {
-    it('covers methods', async function () {
-      const methods = [
-        'context',
-        'transaction',
-        'getAuthById',
-        'upsertAuth',
-        'upsertLink',
-        'getLinkById',
-        'getLinkByUrl',
-        'accessLink',
-        'expireLink',
-        'getAllLinks',
-      ];
-      const invokedMethods = methods.map(async (m) => {
-        try {
-          // eslint-disable-next-line security/detect-object-injection
-          await db[m]();
-          assert.fail(noExpectedException);
-        } catch (e) {
-          assert(e instanceof DBErrors.NotImplemented);
-        }
-      });
-      await Promise.all(invokedMethods);
-    });
-  }); // interface
-
-});
\ No newline at end of file
diff --git a/test/src/db/postgres/index.js b/test/src/db/postgres/index.js
deleted file mode 100644 (file)
index 6f6cf04..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-'use strict';
-
-const assert = require('node:assert');
-const sinon = require('sinon');
-
-const noExpectedException = 'did not get expected exception';
-
-describe('PostgresDatabase', function () {
-  const PostgresDatabase = require('../../../../src/db/postgres-old');
-  let pgpStub, db, logger, options, dbCtx;
-
-  beforeEach(function () {
-
-    pgpStub = () => {
-      const stub = {
-        result: sinon.stub(),
-        all: sinon.stub(),
-        get: sinon.stub(),
-        run: sinon.stub(),
-        one: sinon.stub(),
-        manyOrNone: sinon.stub(),
-        oneOrNone: sinon.stub(),
-        query: sinon.stub(),
-        batch: sinon.stub(),
-      };
-      stub.tx = async (fn) => await fn(stub);
-      stub.txIf = async (fn) => await fn(stub);
-      stub.task = async (fn) => await fn(stub);
-      return stub;
-    };
-    pgpStub.utils = {
-      enumSql: () => ({}),
-    };
-    pgpStub.QueryFile = class {};
-    pgpStub.end = () => {},
-
-    logger = {
-      debug: sinon.stub(),
-      error: sinon.stub(),
-    };
-    options = {};
-    db = new PostgresDatabase(logger, options, pgpStub);
-    db.statement = {};
-    dbCtx = undefined;
-  });
-
-  it('covers constructor options', function () {
-    options = {
-      queryLogLevel: 'debug',
-    };
-    db = new PostgresDatabase(logger, options, pgpStub);
-  });
-
-  describe('context', function () {
-    it('covers', async function () {
-      const fn = sinon.stub();
-      await db.context(fn);
-      assert(fn.called);
-    });
-  }); // context
-
-  describe('transaction', function () {
-    it('covers', async function () {
-      const fn = sinon.stub();
-      await db.transaction(undefined, fn);
-      assert(fn.called);
-    });
-  }); // transaction
-
-  describe('getAuthById', function () {
-    let id;
-    it('stubbed success', async function () {
-      const expected = {
-        id: 'id',
-        secret: 'secret',
-        password: 'password',
-      };
-      id = 'id';
-      db.db.oneOrNone.resolves(expected);
-      const result = await db.getAuthById(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.db.oneOrNone.rejects(expectedExeption);
-      try {
-        await db.getAuthById(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getAuthById
-
-  describe('upsertAuth', function () {
-    let id, secret, credential;
-    beforeEach(function () {
-      id = 'id';
-      secret = 'secret';
-      credential = 'credential';
-    });
-    it('stubbed success', async function () {
-      await db.upsertAuth(dbCtx, id, secret, credential);
-    });
-  }); // upsertAuth
-
-  describe('_epochFix', function () {
-    it('clamps infinity', function () {
-      const epoch = Infinity;
-      const expected = Number.MAX_SAFE_INTEGER;
-      const result = PostgresDatabase._epochFix(epoch);
-      assert.strictEqual(result, expected);
-    });
-    it('clamps negative infinity', function () {
-      const epoch = -Infinity;
-      const expected = 0;
-      const result = PostgresDatabase._epochFix(epoch);
-      assert.strictEqual(result, expected);
-    });
-    it('returns number', function () {
-      const epoch = 123;
-      const expected = 123;
-      const result = PostgresDatabase._epochFix(epoch);
-      assert.strictEqual(result, expected);
-    });
-  }); // _epochFix
-
-  describe('_linkToNative', function () {
-    it('handles missing link', function () {
-      const link = undefined;
-      const expected = undefined;
-      const result = PostgresDatabase._linkToNative(link);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('converts epochs', function () {
-      const link = {
-        id: 'id',
-        url: 'url',
-        expires: null,
-        lastAccess: -Infinity,
-        created: 123,
-      };
-      const expected = {
-        id: 'id',
-        url: 'url',
-        expires: null,
-        lastAccess: 0,
-        created: 123,
-      };
-      const result = PostgresDatabase._linkToNative(link);
-      assert.deepStrictEqual(result, expected);
-    });
-  }); // _linkToNative
-
-  describe('upsertLink', function () {
-    let id, url, authToken;
-    it('stubbed success', async function () {
-      const returns = {
-        rowCount: 0,
-        rows: [],
-        duration: 0,
-      };
-      id = 'id';
-      db.db.result.resolves(returns);
-      const expected = {
-        changes: 0,
-        duration: 0,
-        lastInsertRowid: undefined,
-      };
-      const result = await db.upsertLink(dbCtx, id, url, authToken);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.db.result.rejects(expectedExeption);
-      try {
-        await db.upsertLink(dbCtx, id, url, authToken);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // upsertLink
-
-  describe('getLinkById', function () {
-    let id;
-    it('stubbed success', async function () {
-      const expected = {
-        id: 'id',
-        url: 'url',
-        created: 0,
-        expires: 0,
-        lastAccess: 0,
-      };
-      id = 'id';
-      db.db.oneOrNone.resolves(expected);
-      const result = await db.getLinkById(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.db.oneOrNone.rejects(expectedExeption);
-      try {
-        await db.getLinkById(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getLinkById
-
-  describe('getLinkByUrl', function () {
-    let url;
-    it('stubbed success', async function () {
-      const expected = {
-        id: 'id',
-        url: 'url',
-        created: 0,
-        expires: 0,
-        lastAccess: 0,
-      };
-      url = 'url';
-      db.db.oneOrNone.resolves(expected);
-      const result = await db.getLinkByUrl(dbCtx, url);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      url = 'url';
-      db.db.oneOrNone.rejects(expectedExeption);
-      try {
-        await db.getLinkByUrl(dbCtx, url);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getLinkByUrl
-
-  describe('accessLink', function () {
-    let id;
-    it('stubbed success', async function () {
-      const expected = {
-        id: 'id',
-        url: 'url',
-        created: 0,
-        expires: 0,
-        lastAccess: 0,
-      };
-      id = 'id';
-      db.db.oneOrNone.resolves(expected);
-      const result = await db.accessLink(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.db.oneOrNone.rejects(expectedExeption);
-      try {
-        await db.accessLink(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // accessLink
-
-  describe('expireLink', function () {
-    let id, expires;
-    it('stubbed success', async function () {
-      const returns = {
-        rowCount: 1,
-        rows: [ { id: 1 } ],
-        duration: 10,
-      };
-      const expected = {
-        changes: 1,
-        duration: 10,
-        lastInsertRowid: 1,
-      };
-      id = 'id';
-      expires = null;
-      db.db.result.resolves(returns);
-      const result = await db.expireLink(dbCtx, id, expires);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      expires = null;
-      db.db.result.rejects(expectedExeption);
-      try {
-        await db.expireLink(dbCtx, id, expires);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // expireLink
-
-  describe('getAllLinks', function () {
-    it('stubbed success', async function () {
-      const expected = [
-        {
-          id: 'id',
-          url: 'url',
-          created: 0,
-          expires: 0,
-          lastAccess: 0,
-        },
-      ];
-      db.db.manyOrNone.resolves(expected);
-      const result = await db.getAllLinks(dbCtx);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      db.db.manyOrNone.rejects(expectedExeption);
-      try {
-        await db.getAllLinks(dbCtx);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getAllLinks
-
-});
\ No newline at end of file
diff --git a/test/src/db/sqlite/index.js b/test/src/db/sqlite/index.js
deleted file mode 100644 (file)
index 8bd7ccd..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-'use strict';
-
-const assert = require('node:assert');
-const sinon = require('sinon');
-const DBErrors = require('../../../../src/db/errors');
-
-const noExpectedException = 'did not get expected exception';
-
-describe('SQLiteDatabase', function () {
-  const SQLiteDatabase = require('../../../../src/db/sqlite-old');
-  let db, logger, options, dbCtx;
-
-  beforeEach(function () {
-    logger = {
-      debug: sinon.stub(),
-      info: sinon.stub(),
-      error: sinon.stub(),
-    };
-    options = {};
-    db = new SQLiteDatabase(logger, options);
-    dbCtx = undefined;
-  });
-
-  describe('context', function () {
-    it('covers', async function () {
-      const fn = sinon.stub();
-      await db.context(fn);
-      assert(fn.called);
-    });
-  }); // context
-
-  describe('transaction', function () {
-    it('covers', async function () {
-      const fn = sinon.stub();
-      await db.transaction(dbCtx, fn);
-      assert(fn.called);
-    });
-    it('covers rollback', async function () {
-      const fn = sinon.stub();
-      fn.throws(new Error('rollback'));
-      try {
-        await db.transaction(dbCtx, fn);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.strictEqual(e.message, 'rollback', noExpectedException);
-      }
-    });
-  }); // transaction
-
-  describe('getAuthById', function () {
-    let id;
-    beforeEach(function () {
-      sinon.stub(db.statement.getAuthById, 'get');
-    });
-
-    it('stubbed success', async function () {
-      const expected = {
-        id: 'id',
-        secret: 'secret',
-        password: 'password',
-      };
-      id = 'id';
-      db.statement.getAuthById.get.returns(expected);
-      const result = await db.getAuthById(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.statement.getAuthById.get.throws(expectedExeption);
-      try {
-        await db.getAuthById(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getAuthById
-
-  describe('upsertAuth', function () {
-    let id, secret, credential;
-    beforeEach(function () {
-      sinon.stub(db.statement.insertAuth, 'run').returns({ changes: 1n, lastInsertRowid: 123n });
-      sinon.stub(db.statement.updateAuth, 'run').returns({ changes: 1n, lastInsertRowid: 123n });
-    });
-    it('stubbed insert success', async function () {
-      await db.upsertAuth(dbCtx, id, secret, credential);
-    });
-    it('stubbed update success', async function () {
-      db.statement.insertAuth.run.throws({ code: 'SQLITE_CONSTRAINT_UNIQUE' });
-      await db.upsertAuth(dbCtx, id, secret, credential);
-    });
-    it('covers error', async function () {
-      const expectedException = new Error('blah');
-      db.statement.insertAuth.run.throws(expectedException);
-      try {
-        await db.upsertAuth(dbCtx, id, secret, credential);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedException, noExpectedException);
-      }
-    });
-    it('covers unexpected error', async function () {
-      const expectedException = DBErrors.UnexpectedResult;
-      const returns = {
-        changes: 0n,
-        lastInsertRowid: undefined,
-      };
-      db.statement.insertAuth.run.returns(returns);
-      try {
-        await db.upsertAuth(dbCtx, id, secret, credential);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof expectedException, noExpectedException);
-      }
-    });
-  }); // upsertAuth
-
-  describe('upsertLink', function () {
-    let id, url, authToken;
-    beforeEach(function () {
-      sinon.stub(db.statement.upsertLink, 'run');
-      sinon.stub(db.statement.updateLink, 'run');
-    });
-
-    it('stubbed insert success', async function () {
-      const info = {
-        changes: BigInt(1),
-        lastInsertRowid: BigInt(123),
-      };
-      id = 'id';
-      db.statement.upsertLink.run.returns(info);
-      const expected = {
-        changes: 1,
-        lastInsertRowid: 123,
-      };
-      const result = await db.upsertLink(dbCtx, id, url, authToken);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed update success', async function () {
-      const info = {
-        changes: BigInt(1),
-        lastInsertRowid: BigInt(123),
-      };
-      id = 'id';
-      db.statement.upsertLink.run.throws({ code: 'SQLITE_CONSTRAINT_UNIQUE' });
-      db.statement.updateLink.run.returns(info);
-      const expected = {
-        changes: 1,
-        lastInsertRowid: 123,
-      };
-      const result = await db.upsertLink(dbCtx, id, url, authToken);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.statement.upsertLink.run.throws(expectedExeption);
-      try {
-        await db.upsertLink(dbCtx, id, url, authToken);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-    it('stubbed unexpected failure', async function () {
-      const expectedException = DBErrors.UnexpectedResult;
-      const returns = {
-        changes: 0,
-        lastInsertRowid: undefined,
-      };
-      id = 'id';
-      db.statement.upsertLink.run.returns(returns);
-      try {
-        await db.upsertLink(dbCtx, id, url, authToken);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof expectedException);
-      }
-    });
-  }); // upsertLink
-
-  describe('getLinkById', function () {
-    let id;
-
-    beforeEach(function () {
-      sinon.stub(db.statement.getLinkById, 'get');
-    });
-
-    it('stubbed success', async function () {
-      const returns = {
-        id: 'id',
-        isSpecial: false,
-        url: 'url',
-        created: 0,
-        expires: 0,
-        'auth_token': 'abc',
-        'last_access': 0,
-        accesses: 0,
-      };
-      const expected = {
-        id: 'id',
-        isSpecial: false,
-        url: 'url',
-        created: 0,
-        expires: 0,
-        authToken: 'abc',
-        lastAccess: 0,
-        accesses: 0,
-      };
-      id = 'id';
-      db.statement.getLinkById.get.returns(returns);
-      const result = await db.getLinkById(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.statement.getLinkById.get.throws(expectedExeption);
-      try {
-        await db.getLinkById(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getLinkById
-
-  describe('getLinkByUrl', function () {
-    let url;
-
-    beforeEach(function () {
-      sinon.stub(db.statement.getLinkByUrl, 'get');
-    });
-
-    it('stubbed success', async function () {
-      const returns = {
-        id: 'id',
-        isSpecial: false,
-        url: 'url',
-        created: 0,
-        expires: 123,
-        'auth_token': 'abc',
-        'last_access': 0,
-        accesses: 0,
-      };
-      const expected = {
-        id: 'id',
-        isSpecial: false,
-        url: 'url',
-        created: 0,
-        expires: 123,
-        authToken: 'abc',
-        lastAccess: 0,
-        accesses: 0,
-      };
-      url = 'url';
-      db.statement.getLinkByUrl.get.returns(returns);
-      const result = await db.getLinkByUrl(dbCtx, url);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      url = 'url';
-      db.statement.getLinkByUrl.get.throws(expectedExeption);
-      try {
-        await db.getLinkByUrl(dbCtx, url);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getLinkByUrl
-
-  describe('accessLink', function () {
-    let id;
-
-    beforeEach(function () {
-      sinon.stub(db.statement.getLinkById, 'get');
-      sinon.stub(db.statement.incrementLinkAccess, 'run');
-    });
-
-    it('stubbed exists success', async function () {
-      const returns = {
-        id: 'id',
-        isSpecial: false,
-        url: 'url',
-        created: 0,
-        expires: 0,
-        'auth_token': 'abc',
-        'last_access': 0,
-        accesses: 0,
-      };
-      const expected = {
-        id: 'id',
-        isSpecial: false,
-        url: 'url',
-        created: 0,
-        expires: 0,
-        authToken: 'abc',
-        lastAccess: 0,
-        accesses: 0,
-      };
-      id = 'id';
-      db.statement.getLinkById.get.returns(returns);
-      db.statement.incrementLinkAccess.run.returns({ changes: 1 });
-      const result = await db.accessLink(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed missing success', async function () {
-      const returns = undefined;
-      const expected = undefined;
-      id = 'id';
-      db.statement.getLinkById.get.returns(returns);
-      db.statement.incrementLinkAccess.run.returns({ changes: 0 });
-      const result = await db.accessLink(dbCtx, id);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed increment failure', async function () {
-      const expectedExeption = DBErrors.UnexpectedResult;
-      const returns = {
-        id: 'id',
-        url: 'url',
-        created: 0,
-        expires: 0,
-        'auth_token': 'abc',
-        'last_access': 0,
-        accesses: 0,
-      };
-      id = 'id';
-      db.statement.getLinkById.get.returns(returns);
-      db.statement.incrementLinkAccess.run.returns({ changes: 0 });
-      try {
-        await db.accessLink(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof expectedExeption, noExpectedException);
-      }
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      db.statement.getLinkById.get.throws(expectedExeption);
-      try {
-        await db.accessLink(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // accessLink
-
-  describe('expireLink', function () {
-    let id, expires;
-
-    beforeEach(function () {
-      sinon.stub(db.statement.expireLink, 'run');
-    });
-
-    it('stubbed success', async function () {
-      const returns = {
-        changes: 1,
-        lastInsertRowid: 123,
-      };
-      const expected = {
-        changes: 1,
-        lastInsertRowid: 123,
-      };
-      id = 'id';
-      expires = null;
-      db.statement.expireLink.run.returns(returns);
-      const result = await db.expireLink(dbCtx, id, expires);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed change failure', async function () {
-      const expectedExeption = DBErrors.UnexpectedResult;
-      const returns = {
-        changes: 0,
-        lastInsertRowid: undefined,
-      };
-      id = 'id';
-      db.statement.expireLink.run.returns(returns);
-      try {
-        await db.expireLink(dbCtx, id);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof expectedExeption, noExpectedException);
-      }
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      id = 'id';
-      expires = null;
-      db.statement.expireLink.run.throws(expectedExeption);
-      try {
-        await db.expireLink(dbCtx, id, expires);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // expireLink
-
-  describe('getAllLinks', function () {
-    beforeEach(function () {
-      sinon.stub(db.statement.linkGetAll, 'all');
-    });
-
-    it('stubbed success', async function () {
-      const returns = [
-        {
-          id: 'id',
-          isSpecial: false,
-          url: 'url',
-          created: 0,
-          expires: 0,
-          'auth_token': 'abc',
-          'last_access': 0,
-          accesses: 0,
-        },
-      ];
-      const expected = [
-        {
-          id: 'id',
-          isSpecial: false,
-          url: 'url',
-          created: 0,
-          expires: 0,
-          authToken: 'abc',
-          lastAccess: 0,
-          accesses: 0,
-        },
-      ];
-      db.statement.linkGetAll.all.returns(returns);
-      const result = await db.getAllLinks(dbCtx);
-      assert.deepStrictEqual(result, expected);
-    });
-    it('stubbed failure', async function () {
-      const expectedExeption = new Error('blah');
-      db.statement.linkGetAll.all.throws(expectedExeption);
-      try {
-        await db.getAllLinks(dbCtx);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expectedExeption, noExpectedException);
-      }
-    });
-  }); // getAllLinks
-
-  describe('_optimize', function () {
-    let cslo, oac;
-    beforeEach(function () {
-      cslo = db.changesSinceLastOptimize;
-      oac = db.optimizeAfterChanges;
-      sinon.stub(db.db, 'prepare').returns({
-        all: sinon.stub(),
-      });
-      sinon.stub(db.db, 'pragma');
-    });
-    afterEach(function () {
-      db.changesSinceLastOptimize = cslo;
-      db.optimizeAfterChanges = oac;
-    });
-    it('covers', function () {
-      db._optimize();
-      assert(db.db.pragma.called);
-    });
-    it('_maybeOptimize', function () {
-      db.changesSinceLastOptimize = BigInt(1000);
-      db.optimizeAfterChanges = BigInt(10);
-      sinon.stub(db, '_optimize');
-      db._maybeOptimize();
-      assert(db._optimize.called);
-    });
-  });
-
-});
\ No newline at end of file
index e22673ba5654f36aa1b1b02bdc593ba0636dd4f4..ecb1f936864d53817c6eb43514f8ca88fc55e697 100644 (file)
@@ -7,26 +7,18 @@ const sinon = require('sinon');
 const Manager = require('../../src/manager');
 const common = require('../../src/common');
 const Enum = require('../../src/enum');
+const StubDB = require('../stub-db');
 const { ServeStaticFile, SlugGeneratorExhausted } = require('../../src/errors');
 
 const noExpectedException = 'did not get expected exception';
 
 describe('Manager', function () {
-  let manager, logger, options;
+  let manager, logger, db, options;
   let res, ctx;
 
   beforeEach(function () {
     logger = new StubLogger(sinon);
-    const stubDb = {
-      context: async (fn) => await fn({}),
-      transaction: async (_dbCtx, fn) => await fn({}),
-      getLinkById: sinon.stub(),
-      accessLink: sinon.stub(),
-      getLinkByUrl: sinon.stub(),
-      expireLink: sinon.stub(),
-      upsertLink: sinon.stub(),
-      getAllLinks: sinon.stub(),
-    };
+    db = new StubDB(logger);
     options = {};
     res = {
       end: sinon.stub(),
@@ -35,7 +27,7 @@ describe('Manager', function () {
     ctx = {
       params: {},
     };
-    manager = new Manager(logger, stubDb, options);
+    manager = new Manager(logger, db, options);
 
   });
   afterEach(function () {