@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
JavaScript
;
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;