Skip to content

Instantly share code, notes, and snippets.

@samstr
Last active August 24, 2021 15:00
Show Gist options
  • Save samstr/fc7fd916023f5ea39d531c80aff5e9e6 to your computer and use it in GitHub Desktop.
Save samstr/fc7fd916023f5ea39d531c80aff5e9e6 to your computer and use it in GitHub Desktop.
/* utils/aws/rds.ts */
import { Client } from 'pg';
import type { QueryResult } from 'pg';
interface AnyObject {
[key: string]: any;
}
export enum RdsSource {
Reader,
Writer,
}
export interface RdsConfig {
database: string;
debugQuery?: boolean;
password: string;
port: number;
readerHost: string;
user: string;
writerHost: string;
}
export type QueryValues = (string | number | boolean)[];
class Rds {
client?: Client;
database: string;
debugQuery?: boolean;
password: string;
port: number;
readerHost: string;
source?: RdsSource;
user: string;
writerHost: string;
constructor(config: RdsConfig) {
const {
database,
debugQuery = false,
password,
port,
readerHost,
user,
writerHost,
} = config;
if (database) {
this.database = database;
}
if (debugQuery) {
this.debugQuery = debugQuery;
}
if (password) {
this.password = password;
}
if (port) {
this.port = port;
}
if (readerHost) {
this.readerHost = readerHost;
}
if (user) {
this.user = user;
}
if (writerHost) {
this.writerHost = writerHost;
}
}
connect(source: RdsSource): void {
if (!this.client) {
this.source = source;
console.log(`Connecting to ${this.source}`);
this.client = new Client({
user: this.user,
host:
this.source === RdsSource.Writer ? this.writerHost : this.readerHost,
database: this.database,
password: this.password,
port: this.port,
});
this.client.connect();
} else {
console.log(`Client already exists (connected to ${this.source}`);
}
}
disconnect(): void {
if (this.client) {
console.log(`Disconnecting from ${this.source}: Done`);
this.client.end();
this.client = null;
} else {
console.log(`No need to disconnect (no client connected)`);
}
}
async query(query: string, values: QueryValues = []): Promise<QueryResult> {
if (this.debugQuery) {
console.log(
`Query on (${this.source}):`,
query.replace('\n', '').replace(/\s+/g, ' '),
values || []
);
}
const result = await this.client.query(query, values);
return result;
}
async transaction(fn: () => AnyObject): Promise<AnyObject> {
try {
if (this.debugQuery) {
console.log('Transaction: BEGIN');
}
await this.client.query('BEGIN');
const data = await fn();
if (this.debugQuery) {
console.log('Transaction: COMMIT');
}
await this.client.query('COMMIT');
return data;
} catch (err) {
console.error('Error during transaction', err);
if (this.debugQuery) {
console.log('Transaction: ROLLBACK');
}
await this.client.query('ROLLBACK');
throw err;
}
}
}
export default Rds;
// Usage
import Rds, { RdsSource } from 'utils/aws/rds';
const db = new Rds({
writerHost: PG_WRITER_HOST, // Vercel ENV Vars
readerHost: PG_READER_HOST,
port: PG_PORT,
user: PG_USER,
password: PG_PASSWORD,
database: PG_DATABASE,
debugQuery: PG_DEBUG_QUERY,
});
db.connect(RdsSource.Reader);
const result = await db.query('SELECT * FROM table WHERE id = $1', [123]);
db.disconnect();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment