0.1.0Updated 7 months ago
import { Client, ConnectionString } from "https://deno.land/x/postgres@v0.19.3/mod.ts";
import { Sluggify } from "../../utils/slug.ts";

export class PostgresClient {
  client: Client
  readonly connection_string: string
  readonly database: string

  private SETUP_FINISHED = false;

  constructor(connection_string: ConnectionString) {
    const [ _, extracted_connection_string, database ] = connection_string.match(/((?:postgresql|postgres):\/\/(?:[^:@\s]*(?::[^@\s]*)?@)?(?:[^\/\?\s]+))\b(?:\/(.+))?/) ?? [];

    if(!extracted_connection_string) throw new Error('PostgresClient > Invalid connection_string provided')

    this.connection_string = extracted_connection_string;
    this.database = Sluggify(database);

    this.client = new Client(`${this.connection_string}/postgres`);
  }

  async CreateTable<T = Record<string, string>>(name: string, fields: { [P in keyof Required<T>]: string }, { onCreate }: CreateTableOptions = {}) {
    const fields_array: string[] = Object.entries(fields).map(([ name, type ]) => `${name} ${type}`);

    const query = `CREATE TABLE IF NOT EXISTS "${name}" (${fields_array.join(',')})`;

    const response = await this.query(query);

    if(response.warnings.length === 0) {
      onCreate?.();
    }

    return response;
  }

  async Setup() {
    if(this.SETUP_FINISHED) return this;

    await this.EnsureDatabaseExists(this.database);
    await this.EnsureDatabaseExists('postgres');

    this.SETUP_FINISHED = true;

    await this.client.end();
    this.client = new Client(`${this.connection_string}/${this.database}`);
    await this.client.connect();

    return this;
  }

  private async EnsureDatabaseExists(name: string) {
    if(this.SETUP_FINISHED) return;

    const { rowCount = 0 } = await this.query(`SELECT datname FROM pg_catalog.pg_database where datname=$1`, [name]);

    if(rowCount === 0) {
      await this.query(`CREATE DATABASE "${name}"`);
    }
  }

  async query<T = any>(query: string, args?: any[]) {
    return this.client.queryObject<T>(query, args);
  }

  get end() { return this.client.end.bind(this.client); }
}

interface CreateTableOptions {
  onCreate?: () => Promise<void>
}