diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js index 18a3c8ebc2dd9f7dcb8560fed5f0e10b6b94ffe0..cfb5a109638a20414127ffd5e066d2356ccd774e 100644 --- a/process/Sql_lib/process.js +++ b/process/Sql_lib/process.js @@ -587,6 +587,250 @@ SqlCondition.equalsNot = function(pField, pValue, pAlternativeCond, pAlias) { return SqlCondition.begin(pAlias).andPrepare(pField, pValue, "# <> ?").build(pAlternativeCond); } + +/** + * Object for building sqls. The main purpose of this is to make it + * possible to use SqlCondition objects inside join conditions or sub sqls. + * This can also be useful to build complex sqls where parts should be added + * dynamically while keeping the code clear. + * + * @class + */ +function SqlBuilder () +{ + this._query = []; +} + +/** + * Alternative way of creating a new SqlBuilder object that allows to use + * methods on it directly without having to put brackets around it + * + * @return {SqlBuilder} a new SqlBuilder object + */ +SqlBuilder.begin = function () +{ + return new SqlBuilder(); +} + +/** + * Builds the sql and uses db.translateStatement to make a string out of it. + * @return {String} the sql as string + */ +SqlBuilder.prototype.toString = function () +{ + return db.translateStatement(this.build()); +} + +/** + * Adds a select clause to the sql. + * @param {String|String[]} pFields + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.select = function (pFields) +{ + this._append(pFields, "select", true); + return this; +} + +/** + * Adds a select distinct clause to the sql. + * @param {String|String[]} pFields + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.selectDistinct = function (pFields) +{ + this._append(pFields, "select distinct", true); + return this; +} + +/** + * Adds a from clause to the sql. + * @param {String} pTable + * @param {String} [pAlias] table alias + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.from = function (pTable, pAlias) +{ + if (pAlias) + pTable += " " + pAlias; + this._append(pTable, "from"); + return this; +} + +/** + * Adds a join clause to the sql. + * @param {String} pTable + * @param {String|String[]} pCondition The where condition. This can be + * a string (without the where keyword) or an array (for prepared queries). + * @param {String} [pAlias] table alias + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.join = function (pTable, pCondition, pAlias) +{ + var joinStr = "join " + pTable; + if (pAlias) + joinStr += " " + pAlias; + this._append(joinStr + " on"); + this._append(pCondition); + return this; +} + +/** + * Adds a left join clause to the sql. + * @param {String} pTable + * @param {String|String[]} pCondition The where condition. This can be + * a string (without the where keyword) or an array (for prepared queries). + * @param {String} [pAlias] table alias + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.leftJoin = function (pTable, pCondition, pAlias) +{ + var joinStr = "left join " + pTable; + if (pAlias) + joinStr += " " + pAlias; + this._append(joinStr + " on"); + this._append(pCondition); + return this; +} + +/** + * Adds a where clause to the sql. + * + * @param {String|String[]} pCondition The where condition. This can be + * a string (without the where keyword) or an array (for prepared queries). + * + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.where = function (pCondition) +{ + this._append("where"); + this._append(pCondition); + return this; +} + +/** + * Adds a order by clause to the sql. + * @param {String} pOrderBy + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.orderBy = function (pOrderBy) +{ + this._append(pOrderBy, "order by"); + return this; +} + +/** + * Adds another SqlBuilder object as a subquery. + * @param {SqlBuilder} pSubSelect + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.subSelect = function (pSubSelect) +{ + this._append(pSubSelect); + return this; +} + +/** + * Adds a group by clause to the sql. + * @param {String|String[]} pFields + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.groupBy = function (pFields) +{ + this._append(pFields, "group by", true); + return this; +} + +/** + * Adds another SqlBuilder object or select string with union. + * @param {SqlBuilder|String} pSelect + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.union = function (pSelect) +{ + this._append("union"); + this._append(pSelect); + return this; +} + +/** + * Adds another SqlBuilder object or select string with union all. + * @param {SqlBuilder|String} pSelect + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.unionAll = function (pSelect) +{ + this._append("union all"); + this._append(pSelect); + return this; +} + +/** + * Adds a having clause to the sql. + * + * @param {String|String[]} pCondition The where condition. This can be + * a string (without the where keyword) or an array (for prepared queries). + * + * @return {SqlBuilder} current SqlBuilder object + */ +SqlBuilder.prototype.having = function (pCondition) +{ + this._append("having"); + this._append(pCondition); + return this; +} + +/** + * adds an element + * + * @param {String|String[]|SqlBuilder} pElement the element to append + * @param {String} [pPrefix] string to be added before pElement + * @param {Boolean} [pAutoJoin] if this is true and pElement is an array, it will be automatically + * joined together to a string + * + * @private + */ +SqlBuilder.prototype._append = function (pElement, pPrefix, pAutoJoin) +{ + if (pAutoJoin && pElement && typeof pElement !== "string" && pElement.length !== undefined) + pElement = pElement.join(", "); + if (pPrefix) + pElement = pPrefix + " " + pElement; + this._query.push(pPrefix + " " + pElement); +} + +/** + * builds a prepared statement out of the object + * + * @return {String[]} prepared statement + */ +SqlBuilder.prototype.build = function () +{ + var sqlStr = ""; + var preparedValues = []; + + for (let i = 0, l = this._query.length; i < l; i++) + { + let sqlPart = this._query[i]; + if (sqlPart instanceof SqlBuilder) + { + let condition = sqlPart.build(); + sqlPart = "(" + condition[0] + ")"; + preparedValues = preparedValues.concat(condition[1]); + } + //array => prepared statement + else if (typeof pElement !== "string" && pElement.length === 2 && pElement[1].length !== undefined) + { + preparedValues = preparedValues.concat(sqlPart[1]); + sqlPart = sqlPart[0]; + } + sqlStr += " " + sqlPart; + } + return [sqlStr.trim(), preparedValues]; +} + + + /** *provides functions for masking sql functions *