All files / owid-grapher/db DatabaseConnection.ts

47.9% Statements 57/119
100% Branches 0/0
0% Functions 0/10
47.9% Lines 57/119

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 931x 1x 1x 1x 1x     1x 1x               1x 1x               1x 1x 1x 1x 1x 1x 1x 1x     1x 1x       1x 1x                     1x 1x                                   1x 1x                     1x 1x     1x 1x     1x 1x
import * as mysql from "mysql"
 
class TransactionContext {
    conn: mysql.PoolConnection
    constructor(conn: mysql.PoolConnection) {
        this.conn = conn
    }
 
    execute(queryStr: string, params?: any[]): Promise<any> {
        return new Promise((resolve, reject) => {
            this.conn.query(queryStr, params, (err, rows) => {
                if (err) return reject(err)
                resolve(rows)
            })
        })
    }
 
    query(queryStr: string, params?: any[]): Promise<any> {
        return new Promise((resolve, reject) => {
            this.conn.query(queryStr, params, (err, rows) => {
                if (err) return reject(err)
                resolve(rows)
            })
        })
    }
}
 
// Promise wrapper for node-mysql with transaction support and some shorthands
export class DatabaseConnection {
    config: mysql.PoolConfig
    pool!: mysql.Pool
 
    constructor(config: mysql.PoolConfig) {
        this.config = config
    }
 
    async connect(): Promise<void> {
        this.pool = mysql.createPool(this.config)
        await this.getConnection()
    }
 
    getConnection(): Promise<mysql.PoolConnection> {
        return new Promise((resolve, reject) => {
            this.pool.getConnection((poolerr, conn) => {
                if (poolerr) {
                    reject(poolerr)
                } else {
                    resolve(conn)
                }
            })
        })
    }
 
    async transaction<T>(
        callback: (t: TransactionContext) => Promise<T>
    ): Promise<T> {
        const conn = await this.getConnection()
        const transactionContext = new TransactionContext(conn)

        try {
            await transactionContext.execute("START TRANSACTION")
            const result = await callback(transactionContext)
            await transactionContext.execute("COMMIT")
            return result
        } catch (err) {
            await transactionContext.execute("ROLLBACK")
            throw err
        } finally {
            transactionContext.conn.release()
        }
    }
 
    query(queryStr: string, params?: any[]): Promise<any> {
        return new Promise((resolve, reject) => {
            this.pool.query(queryStr, params, (err, rows) => {
                if (err) {
                    console.log(`ERROR with query::\n${queryStr}\n::ERROR`)
                    return reject(err)
                }
                resolve(rows)
            })
        })
    }
 
    async get(queryStr: string, params?: any[]): Promise<any> {
        return (await this.query(queryStr, params))[0]
    }
 
    end(): void {
        this.pool.end()
    }
}