UNPKG

postgres-pdo

Version:
372 lines (325 loc) 10.4 kB
class Pdo { constructor(client, options = {}) { this.client = client; this.escape = options.escapeCb ?? encodeURI; this.unescape = options.unescapeCb ?? unescape; this.clean(); this._catch = console.error; this._getLogDuration = options.getLogDuration; } catch(fn) { this._catch = fn; return this; } setEscape(escape) { this.escape = escape ?? encodeURI; return this; } clean() { this._type = null; this._table = null; this._where = null; this._columns = null; this._values = null; this._groupBy = null; this._select = null; this._join = []; this._orderBy = null; this._orderDirection = null; this._limit = null; this._offset = null; this._returning = null; this._conflict = null; this._having = null; this._subQueries = []; } select(select = ['*']) { this.clean(); this._type = 'select' this._select = select; return this; } from(table) { this._table = table; return this; } update(pairs = null) { this.clean(); this._type = 'update'; if (pairs) { this.set(pairs); } return this; } set(pairs) { this._columns = []; this._values = []; Object.keys(pairs).forEach(key => { this._columns.push(key); this._values.push(pairs[key]); }); return this; } table(table) { this._table = table; return this; } insert(columns = null) { this.clean(); this._type = 'insert'; if (columns) { if (Array.isArray(columns)) { this.columns(columns); } else { this.columns(Object.keys(columns)); this.values(Object.values(columns)); } } else { this.columns(columns); } return this; } returning(id) { this._returning = id; return this; } columns(columns) { this._columns = columns; return this; } values(values) { this._values = values; return this; } into(table) { this._table = table; return this; } delete(table) { this.clean(); this._type = 'delete'; this._table = table; return this; } leftJoin(joinTable, field1, cond, field2, clause, condWhere, value) { this._join.push(`LEFT JOIN ${joinTable} ON ${field1} ${cond} ${field2}${clause ? ` AND ${clause} ${condWhere} ${this.escapeData(value)}` : ''}`); return this; } where(clause, cond, value, skipEscape = false) { this._where = `${clause} ${cond} ${skipEscape ? value : this.escapeData(value)}`; return this; } whereIsNull(clause) { this._where = `${clause} IS NULL`; return this; } whereIsNotNull(clause) { this._where = `${clause} IS NOT NULL`; return this; } orWhereIsNull(clause) { this._where = `${this._where} OR ${clause} IS NULL`; return this; } orWhereIsNotNull(clause) { this._where = `${this._where} OR ${clause} IS NOT NULL`; return this; } andWhereIsNull(clause) { this._where = `${this._where} AND ${clause} IS NULL`; return this; } andWhereIsNotNull(clause) { this._where = `${this._where} AND ${clause} IS NOT NULL`; return this; } andWhere(clause, cond, value) { this._where = `${this._where} AND ${clause} ${cond} ${this.escapeData(value)}`; return this; } orWhere(clause, cond, value) { this._where = `${this._where} OR ${clause} ${cond} ${this.escapeData(value)}`; return this; } whereIn(clause, arr) { this._where = `${clause} IN (${arr.map(item => this.escapeData(item)).join(',')})`; return this; } andWhereIn(clause, arr) { this._where = `${this._where} AND ${clause} IN (${arr.map(item => this.escapeData(item)).join(',')})`; return this; } andWhereNotIn(clause, arr) { this._where = `${this._where} AND ${clause} NOT IN (${arr.map(item => this.escapeData(item)).join(',')})`; return this; } andWithBrace() { this._where = `${this._where} AND (1 = 1`; return this; } orWithBrace() { this._where = `${this._where} OR (1 = 1`; return this; } closeBrace() { this._where = `${this._where})`; return this; } conflictDoNothing() { this._conflict = `DO NOTHING`; return this; } conflictDoUpdate(clause, pairs) { this._conflict = `(${clause}) DO UPDATE SET ${Object.keys(pairs).map(column => (`${column} = ${this.escapeData(pairs[column])}`)).join(',')}`; return this; } groupBy(groupBy) { this._groupBy = groupBy; return this; } orderBy(column, direction = 'ASC') { this._orderBy = column; this._orderDirection = direction; return this; } having(clause, cond, value, skipEscape = false) { this._having = `${clause} ${cond} ${skipEscape ? value : this.escapeData(value)}`; return this; } andHaving(clause, cond, value) { this._having = `${this._having} AND ${clause} ${cond} ${this.escapeData(value)}`; return this; } orHaving(clause, cond, value) { this._having = `${this._having} OR ${clause} ${cond} ${this.escapeData(value)}`; return this; } limit(limit, offset = 0) { this._limit = limit; this._offset = offset; return this; } with(subQueries) { if (Array.isArray(subQueries)) this._subQueries = [...subQueries]; if (typeof subQueries === 'string') this._subQueries = [subQueries]; return this; } escapeData(value) { try { if (value === null || !this.escape) { return value; } else if (typeof value === "boolean") { return value; } else if (typeof value === "string") { return `'${this.escape(value)}'`; } else if (typeof value === "number") { return parseFloat(value); } else { return `'${this.escape(value)}'`; } } catch (e) { return `'${value}'`; } } join(arr) { return arr.reduce((acc, cur) => acc + (acc !== undefined ? ',' : '') + cur); } getQuery() { let query; switch (this._type) { case 'select': query = `SELECT ${this.join(this._select)} FROM ${this._table}`; if (this._join.length) { this._join.map(str => { query += ` ${str}`; }); } if (this._where) { query += ` WHERE ${this._where}`; } if (this._groupBy) { query += ` GROUP BY ${this._groupBy}`; } if (this._having) { query += ` HAVING ${this._having}`; } if (this._orderBy) { query += ` ORDER BY ${this._orderBy} ${this._orderDirection}`; } if (this._limit) { query += ` LIMIT ${this._limit}`; } if (this._offset) { query += ` OFFSET ${this._offset}`; } if (this._subQueries.length) { query = `WITH ${this._subQueries.join(',')} ${query}`; } break; case 'insert': query = `INSERT INTO ${this._table} (${this._columns?.join(',')}) VALUES (${this.join(this._values?.map((v) => this.escapeData(v)))})`; if (this._conflict) { query += ` ON CONFLICT ${this._conflict}`; } if (this._returning) { query += ` RETURNING ${this._returning}`; } if (this._subQueries.length) { query = `WITH ${this._subQueries.join(',')} ${query}`; } break; case 'update': query = `UPDATE ${this._table} SET ${this._values?.map((value, i) => { return `${this._columns[i]} = ${this.escapeData(value)}`; }).join(',')}`; if (this._conflict) { query += ` ON CONFLICT ${this._conflict}`; } if (this._where) { query += ` WHERE ${this._where}`; } if (this._returning) { query += ` RETURNING ${this._returning}`; } if (this._subQueries.length) { query = `WITH ${this._subQueries.join(',')} ${query}`; } break; case 'delete': query = `DELETE FROM ${this._table}`; if (this._where) { query += ` WHERE ${this._where}`; } if (this._returning) { query += ` RETURNING ${this._returning}`; } if (this._subQueries.length) { query = `WITH ${this._subQueries.join(',')} ${query}`; } break; } return query; } async execute() { const startTime = new Date().getTime(); const query = this.getQuery(); try { const result = await this.client.unsafe(query); if (this._getLogDuration) { this._getLogDuration(query.replace(/\n/g, ' ').replace(/\s+/g, ' '), new Date().getTime() - startTime); } return result; } catch (e) { this._catch(e); } } } module.exports = Pdo;