UNPKG

@ckpack/pg-helper

Version:

A small helper of node-postgres can help you build queries more easily and safely

243 lines (242 loc) 7.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.literalSql = exports.returningSql = exports.insertSql = exports.updateSql = exports.includeSql = exports.limitOffsetSql = exports.whereSql = exports.orderSql = exports.objHump2underline = exports.rowsUnderline2hump = exports.fieldsSql = exports.sqlTemplate = void 0; const symbolLiteral = Symbol('literal'); /** * sqlTemp to pg query params * ``` * sqlTemp: `select * from ${USERS} where username = {username}` * sqlParams: {username: 'xiaohong'} * to * sql: `select * from ${USERS} where username = $1` * values: ['xiaohong'] * ``` * @param sqlTemp sql * @param sqlParams value */ function sqlTemplate(sqlTemp, sqlParams) { sqlParams = sqlParams || {}; const sqlArr = sqlTemp.split(/[{}]/); let sql = ''; const sqlArrLen = sqlArr.length; const values = []; for (let index = 0; index < sqlArrLen; index += 1) { const item = sqlArr[index]; if (!item) continue; if (index % 2 !== 0) { sql += `$${(index + 1) / 2}`; if (item in sqlParams) { values.push(sqlParams[item]); } else { throw new Error(`${item} not in params`); } } else { sql += item; } } return { sql, values }; } exports.sqlTemplate = sqlTemplate; /** * build fields Sql */ function fieldsSql(params) { return ` "${params.join('", "')}" `; } exports.fieldsSql = fieldsSql; function underline2hump(str) { return str.replace(/_([a-z])/g, (match, p1) => p1.toUpperCase()); } function hump2underline(str) { return str.replace(/([A-Z])/g, (match, p1) => `_${p1.toLowerCase()}`); } function objHump2underline(obj) { const formatObj = {}; Object.keys(obj).forEach((key) => { formatObj[hump2underline(key)] = obj[key]; }); return formatObj; } exports.objHump2underline = objHump2underline; function rowsUnderline2hump(rows) { if (!Array.isArray(rows) || rows.length === 0) return []; return rows.map((obj) => { const res = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { res[underline2hump(key)] = obj[key]; } } return res; }); } exports.rowsUnderline2hump = rowsUnderline2hump; /** * build order sql */ function orderSql(orders = []) { const orderSql = orders.map((order) => { if (Array.isArray(order)) { const [field, type] = order; return ` "${field}" ${type || ''} `; } return ` "${order}" `; }).join(', '); return orderSql ? ` ORDER BY ${orderSql} ` : ' '; } exports.orderSql = orderSql; function getWhereSql(where, options) { if (!where || Object.keys(where).length === 0) return ''; options = options || {}; const type = options.type || 'and'; const fields = Object.keys(where).filter((field) => ['and', 'or'].indexOf(field) === -1); let sql = ' ( '; if (fields.length > 0) { const firstField = fields[0]; sql += ` "${firstField}" ${where[firstField]} `; fields.shift(); fields.forEach((field) => { sql += ` ${type} "${field}" ${where[field]} `; }); } if ('and' in where) { sql += ` AND ${getWhereSql(where.and, { type: 'and' })} `; } if ('or' in where) { sql += ` OR ${getWhereSql(where.or, { type: 'or' })} `; } sql += ' ) '; return sql; } /** * build where sql */ function whereSql(where) { if (!where) return ''; let sql = getWhereSql(where); if (sql) { sql = ` WHERE ${sql} `; } return sql; } exports.whereSql = whereSql; /** * build limit offset sql */ function limitOffsetSql(params) { params = params || {}; const { limit, offset, page } = params; if (!limit || !Number.isInteger(limit)) { return ''; } if (offset && Number.isInteger(offset)) { return ` LIMIT ${limit} OFFSET ${offset} `; } if (page && Number.isInteger(page)) { return ` LIMIT ${limit} OFFSET ${(page - 1) * limit} `; } return ` LIMIT ${limit} `; } exports.limitOffsetSql = limitOffsetSql; /** * build include Sql */ function includeSql(params) { if (!params || !Array.isArray(params)) { return ' * '; } return params.map((param) => { if (Array.isArray(param)) { const [field, aliax, type] = param; return ` "${field}" ${type ? ` :: ${type} ` : ''} ${aliax ? ` as "${aliax}" ` : ''}`; } return ` "${param}" `; }).join(', '); } exports.includeSql = includeSql; /** * build update sql */ function updateSql(params = {}) { if (Array.isArray(params)) { return params.map((field) => { if (typeof field === 'object' && field.value) { const fieldValue = typeof field.value === 'string' ? field.value : field.value[symbolLiteral]; return ` "${field.field}" = ${fieldValue} `; } return ` "${field}" = {${field}} `; }).join(', '); } const fields = Object.keys(params); return fields.filter((field) => params[field] !== undefined) .map((field) => { if (typeof params[field] === 'object' && symbolLiteral in params[field]) { return ` "${field}" = ${params[field][symbolLiteral]} `; } return ` "${field}" = {${field}} `; }).join(', '); } exports.updateSql = updateSql; /** * build insert sql */ function insertSql(params) { let fieldSql = ' ( '; let valuesSql = ' VALUES '; const data = []; if (!Array.isArray(params)) { params = [params]; } const fields = Object.keys(params[0]); fieldSql += fieldsSql(fields); fieldSql += ' ) '; const fieldCount = fields.length; let ignoreCount = 0; valuesSql += params.map((param, index) => { let valueSql = ' ( '; const paramFields = Object.keys(param); valueSql += paramFields.map((value, valueIndex) => { if (param[value] && typeof param[value] === 'object' && param[value][symbolLiteral]) { ignoreCount += 1; return param[value][symbolLiteral]; } data.push(param[value]); return `$${index * fieldCount + valueIndex + 1 - ignoreCount}`; }).join(', '); valueSql += ' ) '; return valueSql; }).join(', '); return { sql: fieldSql + valuesSql, data }; } exports.insertSql = insertSql; /** * build returning sql */ function returningSql(returning) { if (!Array.isArray(returning)) { return returning ? ' RETURNING * ' : ''; } return ` RETURNING ${fieldsSql(returning)} `; } exports.returningSql = returningSql; /** * Functions used internally to build sql, It is useful to construct some special SQL, the returned sql will not be used as a template for the key */ function literalSql(sql) { return { [symbolLiteral]: sql }; } exports.literalSql = literalSql;