diff --git a/index.js b/index.js index 0fb0894..29a7751 100644 --- a/index.js +++ b/index.js @@ -9,28 +9,39 @@ let SqlString = require('sqlstring'); class PagiHelp { constructor(options) { if(options) { - let { columnNameConverter } = options; + let { columnNameConverter, dialect } = options; if (columnNameConverter) this.columnNameConverter = columnNameConverter; + this.dialect = dialect || "mysql"; + } else { + this.dialect = "mysql"; } } columnNameConverter = (x) => x; + dialect = "mysql"; + + escapeIdentifier = (identifier) => { + if (this.dialect === "postgresql") { + return `"${identifier.replace(/"/g, '""')}"`; + } + return `\`${identifier.replace(/`/g, '``')}\``; + }; columNames = (arr) => arr.map((a) => { if (a.prefix) { if (a.alias) return ( - a.prefix + "." + this.columnNameConverter(a.name) + " AS " + a.alias + this.escapeIdentifier(a.prefix) + "." + this.escapeIdentifier(this.columnNameConverter(a.name)) + " AS " + this.escapeIdentifier(a.alias) ); - return a.prefix + "." + this.columnNameConverter(a.name); + return this.escapeIdentifier(a.prefix) + "." + this.escapeIdentifier(this.columnNameConverter(a.name)); } if (a.statement) { - if (a.alias) return a.statement + " AS " + a.alias; + if (a.alias) return a.statement + " AS " + this.escapeIdentifier(a.alias); return a.statement; } - if (a.alias) return this.columnNameConverter(a.name) + " AS " + a.alias; - return this.columnNameConverter(a.name); + if (a.alias) return this.escapeIdentifier(this.columnNameConverter(a.name)) + " AS " + this.escapeIdentifier(a.alias); + return this.escapeIdentifier(this.columnNameConverter(a.name)); }); tupleCreator = (tuple, replacements, asItIs = false) => { @@ -40,6 +51,9 @@ class PagiHelp { } let field = tuple[0]; if (operator === "JSON_CONTAINS" || operator === "JSON_OVERLAPS") { + if (this.dialect === "postgresql") { + throw `${operator} is not supported in PostgreSQL.`; + } let query = `${operator}(${field}, ?)`; if (tuple[2] && typeof tuple[2] === "object") { replacements.push(JSON.stringify(tuple[2])); @@ -49,6 +63,9 @@ class PagiHelp { return query; } if (operator === "FIND_IN_SET") { + if (this.dialect === "postgresql") { + throw "FIND_IN_SET is not supported in PostgreSQL."; + } let query = `FIND_IN_SET(?, ${field})`; replacements.push(tuple[2]); return query; @@ -147,9 +164,9 @@ class PagiHelp { if (column.statement) { fieldName = column.statement; } else if (column.prefix) { - fieldName = `${column.prefix}.${column.name}`; + fieldName = `${this.escapeIdentifier(column.prefix)}.${this.escapeIdentifier(column.name)}`; } else { - fieldName = column.name; + fieldName = this.escapeIdentifier(column.name); } return [[fieldName, operator, value]]; @@ -171,24 +188,21 @@ class PagiHelp { let query = "SELECT " + columnList.join(",") + - " FROM `" + - tableName + - "`" + + " FROM " + + this.escapeIdentifier(tableName) + joinQuery; let countQuery = "SELECT " + columnList.join(",") + - " FROM `" + - tableName + - "`" + + " FROM " + + this.escapeIdentifier(tableName) + joinQuery; let totalCountQuery = - "SELECT COUNT(*) AS countValue " + - " FROM `" + - tableName + - "`" + + "SELECT COUNT(*) AS " + this.escapeIdentifier("countValue") + " " + + " FROM " + + this.escapeIdentifier(tableName) + joinQuery; let replacements = []; @@ -297,9 +311,9 @@ class PagiHelp { countQuery = countQuery.replace(/(UNION ALL\s*)$/i, ""); if (totalCountQueries.length > 1) { - totalCountQuery = `SELECT SUM(countValue) AS countValue FROM ( ${totalCountQueries.join( + totalCountQuery = `SELECT SUM(${this.escapeIdentifier("countValue")}) AS ${this.escapeIdentifier("countValue")} FROM ( ${totalCountQueries.join( " UNION ALL " - )} ) AS totalCounts`; + )} ) AS ${this.escapeIdentifier("totalCounts")}`; } else { totalCountQuery = totalCountQueries[0]; } @@ -312,11 +326,21 @@ class PagiHelp { sort.sorts[i] = sort.sorts[i].toUpperCase() } for (let i = 0; i < sort.attributes.length; i++) { + const sortAttr = sort.attributes[i]; + + let orderByPart; + if (sortAttr.includes(".")) { + const [prefix, colName] = sortAttr.split("."); + orderByPart = `${this.escapeIdentifier(prefix)}.${this.escapeIdentifier(this.columnNameConverter(colName))}`; + } else { + orderByPart = this.escapeIdentifier(this.columnNameConverter(sortAttr)); + } + orderByQuery = orderByQuery + "" + - this.columnNameConverter(SqlString.escapeId(sort.attributes[i])) + - "" + + orderByPart + + " " + sort.sorts[i] + ","; } @@ -328,11 +352,21 @@ class PagiHelp { let offset = (paginationObject.pageNo - 1) * paginationObject.itemsPerPage; - query = query + " LIMIT ?,?"; - replacements.push(offset, paginationObject.itemsPerPage); + if (this.dialect === "postgresql") { + query = query + " LIMIT ? OFFSET ?"; + replacements.push(paginationObject.itemsPerPage, offset); + } else { + query = query + " LIMIT ?,?"; + replacements.push(offset, paginationObject.itemsPerPage); + } } else if(paginationObject.offset && paginationObject.limit ) { - query = query + " LIMIT ?,?"; - replacements.push(paginationObject.offset,paginationObject.limit) + if (this.dialect === "postgresql") { + query = query + " LIMIT ? OFFSET ?"; + replacements.push(paginationObject.limit, paginationObject.offset); + } else { + query = query + " LIMIT ?,?"; + replacements.push(paginationObject.offset, paginationObject.limit); + } } return {