From 6742d7d624a4c22cebc4b8c7cf140239beae075f Mon Sep 17 00:00:00 2001
From: Will Hunt <will@half-shot.uk>
Date: Tue, 23 Oct 2018 03:33:24 +0100
Subject: [PATCH] Add support for postgres!

---
 config/config.schema.yaml |  4 +++-
 src/config.ts             |  3 ++-
 src/db/dbdataevent.ts     |  2 +-
 src/db/sqlite3.ts         |  3 ++-
 src/discordas.ts          |  3 ++-
 src/store.ts              | 41 +++++++++++++++++++++++++++------------
 6 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/config/config.schema.yaml b/config/config.schema.yaml
index 40b50ca..96cc1ab 100644
--- a/config/config.schema.yaml
+++ b/config/config.schema.yaml
@@ -68,8 +68,10 @@ properties:
                     type: "string"
     database:
         type: "object"
-        required: ["filename"]
+        required: []
         properties:
+          connString:
+            type: "string"
           filename:
             type: "string"
           userStorePath:
diff --git a/src/config.ts b/src/config.ts
index f8be3e4..cfa5727 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -37,7 +37,8 @@ class DiscordBridgeConfigBridge {
   public disableHereMention: boolean = false;
 }
 
-class DiscordBridgeConfigDatabase {
+export class DiscordBridgeConfigDatabase {
+  public connString: string;
   public filename: string;
   public userStorePath: string;
   public roomStorePath: string;
diff --git a/src/db/dbdataevent.ts b/src/db/dbdataevent.ts
index d4af4bb..8756b9e 100644
--- a/src/db/dbdataevent.ts
+++ b/src/db/dbdataevent.ts
@@ -81,7 +81,7 @@ export class DbEvent implements IDbDataMany {
                 FROM discord_msg_store
                 WHERE msg_id = $id`, {
                     id: this.DiscordId,
-        }) !== undefined;
+        }) != null;
         if (msgExists) {
             return;
         }
diff --git a/src/db/sqlite3.ts b/src/db/sqlite3.ts
index 61c4f80..57ac657 100644
--- a/src/db/sqlite3.ts
+++ b/src/db/sqlite3.ts
@@ -1,8 +1,9 @@
 import * as Database from "better-sqlite3";
 import { Log } from "../log";
+import { DatabaseConnector } from "./connector";
 const log = new Log("SQLite3");
 
-export class SQLite3 {
+export class SQLite3 implements DatabaseConnector {
     private db: Database;
     constructor (private filename: string) {
 
diff --git a/src/discordas.ts b/src/discordas.ts
index 4aa4597..33b70b2 100644
--- a/src/discordas.ts
+++ b/src/discordas.ts
@@ -57,7 +57,8 @@ function run (port: number, fileConfig: DiscordBridgeConfig) {
     url: config.bridge.homeserverUrl,
   });
   const provisioner = new Provisioner();
-  const discordstore = new DiscordStore(config.database ? config.database.filename : "discord.db");
+  // Warn and deprecate old config options.
+  const discordstore = new DiscordStore(config.database);
   const discordbot = new DiscordBot(config, discordstore, provisioner);
   const roomhandler = new MatrixRoomHandler(discordbot, config, botUserId, provisioner);
 
diff --git a/src/store.ts b/src/store.ts
index dec11df..ad6b48f 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -5,6 +5,9 @@ import { SQLite3 } from "./db/sqlite3";
 export const CURRENT_SCHEMA = 7;
 
 import { Log } from "./log";
+import { DiscordBridgeConfigDatabase } from "./config";
+import { Postgres } from "./db/postgres";
+import { DatabaseConnector } from "./db/connector";
 const log = new Log("DiscordStore");
 /**
  * Stores data for specific users and data not specific to rooms.
@@ -13,20 +16,29 @@ export class DiscordStore {
   /**
    * @param  {string} filepath Location of the SQLite database file.
    */
-  public db: SQLite3;
+  public db: DatabaseConnector;
   private version: number;
-  private filepath: string;
-  constructor (filepath: string) {
+  private config: DiscordBridgeConfigDatabase;
+  constructor (private configOrFile: DiscordBridgeConfigDatabase|string) {
+    if (typeof(configOrFile) === "string"){
+        this.config = new DiscordBridgeConfigDatabase();
+        this.config.filename = configOrFile;
+    } else {
+        this.config = configOrFile;
+    }
     this.version = null;
-    this.filepath = filepath;
   }
 
   public backup_database(): Promise<void|{}> {
-    if (this.filepath === ":memory:") {
+    if (this.config.filename == null) {
+        log.warn("Backups not supported on non-sqlite connector");
+        return;
+    }
+    if (this.config.filename === ":memory:") {
       log.info("Can't backup a :memory: database.");
       return Promise.resolve();
     }
-    const BACKUP_NAME = this.filepath + ".backup";
+    const BACKUP_NAME = this.config.filename + ".backup";
 
     return new Promise((resolve, reject) => {
       // Check to see if a backup file already exists.
@@ -39,7 +51,7 @@ export class DiscordStore {
           log.warn("NOT backing up database while a file already exists");
           resolve(true);
         }
-        const rd = fs.createReadStream(this.filepath);
+        const rd = fs.createReadStream(this.config.filename);
         rd.on("error", reject);
         const wr = fs.createWriteStream(BACKUP_NAME);
         wr.on("error", reject);
@@ -146,7 +158,7 @@ export class DiscordStore {
         userId,
       },
     ).then( (rows) => {
-      if (rows !== undefined) {
+      if (rows != null) {
         return rows.map((row) => row.discord_id);
       } else {
         return [];
@@ -168,7 +180,7 @@ export class DiscordStore {
         discordId,
       },
     ).then( (row) => {
-      return row !== undefined ? row.token : null;
+      return row != null ? row.token : null;
     }).catch( (err) => {
       log.error("Error getting discord ids ", err.Error);
       throw err;
@@ -188,7 +200,7 @@ export class DiscordStore {
       discordId,
       discordChannel,
     }).then( (row) => {
-      return row !== undefined ? row.room_id : null;
+      return row != null ? row.room_id : null;
     }).catch( (err) => {
       log.error("Error getting room_id ", err.Error);
       throw err;
@@ -276,8 +288,13 @@ export class DiscordStore {
   }
 
   private async open_database(): Promise<void|Error> {
-    log.info("Opening database ", this.filepath);
-    this.db = new SQLite3(this.filepath);
+    if (this.config.filename) {
+        log.info("Filename present in config, using sqlite");
+        this.db = new SQLite3(this.config.filename);
+    } else if (this.config.connString) {
+        log.info("connString present in config, using postgres");
+        this.db = new Postgres(this.config.connString);
+    }
     try {
         await this.db.Open();
     } catch (ex) {
-- 
GitLab