UNPKG

jsharmony-db-sqlite

Version:
909 lines (788 loc) 42 kB
/* Copyright 2017 apHarmony This file is part of jsHarmony. jsHarmony is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. jsHarmony is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this package. If not, see <http://www.gnu.org/licenses/>. */ var DB = require('jsharmony-db'); var types = DB.types; var _ = require('lodash'); var DBObjectSQL = require('./DB.sqlite.sql.object.js'); function DBsql(db){ this.db = db; this.object = new DBObjectSQL(db, this); } DBsql.prototype.getModelRecordset = function (jsh, model, sql_searchfields, allfields, sortfields, searchfields, datalockqueries, rowstart, rowcount) { var _this = this; var sql = ''; var rowcount_sql = ''; var sql_select_suffix = ''; var sql_rowcount_suffix = ''; sql_select_suffix = ' where '; //Generate SQL Suffix (where condition) var sqlwhere = '1=1'; if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); _.each(sql_searchfields, function (field) { if ('sqlwhere' in field) sqlwhere += ' and ' + _this.ParseSQL(field.sqlwhere); else sqlwhere += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); sql_select_suffix += ' %%%SQLWHERE%%% %%%DATALOCKS%%% %%%SEARCH%%%'; //Generate beginning of select statement sql = 'select '; var sql_fields = ''; for (var i = 0; i < allfields.length; i++) { var field = allfields[i]; if (i > 0) sql_fields += ','; var fieldsql = field.name; if ('sqlselect' in field) fieldsql = _this.ParseSQL(field.sqlselect); sql_fields += XfromDB(jsh, field, fieldsql); if (field.lov) sql_fields += ',' + _this.getLOVFieldTxt(jsh, model, field) + ' as __' + jsh.map.code_txt + '__' + field.name; } sql += '%%%SQLFIELDS%%% from ' + _this.getTable(jsh, model) + ' %%%SQLSUFFIX%%% '; sql_rowcount_suffix = sql_select_suffix; sql_select_suffix += ' order by %%%SORT%%% limit %%%ROWCOUNT%%% offset %%%ROWSTART%%%'; if('sqlselect' in model) sql = _this.ParseSQL(model.sqlselect).replace('%%%SQL%%%', sql); rowcount_sql = 'select count(*) as cnt from ' + _this.getTable(jsh, model) + ' %%%SQLSUFFIX%%% '; if('sqlrowcount' in model) rowcount_sql = _this.ParseSQL(model.sqlrowcount).replace('%%%SQL%%%', rowcount_sql); //Generate sort sql var sortstr = ''; _.each(sortfields, function (sortfield) { if (sortstr != '') sortstr += ','; //Get sort expression sortstr += (sortfield.sql ? _this.ParseSQL(DB.util.ReplaceAll(sortfield.sql, '%%%SQL%%%', sortfield.field)) : sortfield.field) + ' COLLATE NOCASE ' + sortfield.dir; }); if (sortstr == '') sortstr = '1'; var searchstr = ''; var parseSearch = function (_searchfields) { var rslt = ''; _.each(_searchfields, function (searchfield) { if (_.isArray(searchfield)) { if (searchfield.length) rslt += ' (' + parseSearch(searchfield) + ')'; } else if (searchfield){ rslt += ' ' + searchfield; } }); return rslt; }; if (searchfields.length){ searchstr = parseSearch(searchfields); if(searchstr) searchstr = ' and (' + searchstr + ')'; } //Replace parameters sql = sql.replace('%%%SQLFIELDS%%%', sql_fields); sql = sql.replace('%%%SQLSUFFIX%%%', sql_select_suffix); sql = sql.replace('%%%ROWSTART%%%', rowstart); sql = sql.replace('%%%ROWCOUNT%%%', rowcount); sql = sql.replace('%%%SEARCH%%%', searchstr); sql = sql.replace('%%%SORT%%%', sortstr); sql = sql.replace('%%%SQLWHERE%%%', sqlwhere); rowcount_sql = rowcount_sql.replace('%%%SQLSUFFIX%%%', sql_rowcount_suffix); rowcount_sql = rowcount_sql.replace('%%%SEARCH%%%', searchstr); rowcount_sql = rowcount_sql.replace('%%%SQLWHERE%%%', sqlwhere); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); rowcount_sql = applyDataLockSQL(rowcount_sql, datalockstr); return { sql: sql, rowcount_sql: rowcount_sql }; }; DBsql.prototype.getModelForm = function (jsh, model, selecttype, allfields, sql_allkeyfields, datalockqueries, sortfields) { var _this = this; var sql = ''; sql = 'select '; var sql_fields = ''; for (var i = 0; i < allfields.length; i++) { var field = allfields[i]; if (i > 0) sql_fields += ','; var fieldsql = field.name; if ('sqlselect' in field) fieldsql = _this.ParseSQL(field.sqlselect); sql_fields += XfromDB(jsh, field, fieldsql); if (field.lov) sql_fields += ',' + _this.getLOVFieldTxt(jsh, model, field) + ' as __' + jsh.map.code_txt + '__' + field.name; } var tbl = _this.getTable(jsh, model); sql += '%%%SQLFIELDS%%% from ' + tbl + ' where '; var sqlwhere = '1=1'; if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql += ' %%%SQLWHERE%%% %%%DATALOCKS%%%'; //Add Keys to where _.each(sql_allkeyfields, function (field) { sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); if (selecttype == 'multiple') sql += ' order by %%%SORT%%%'; if('sqlselect' in model) sql = _this.ParseSQL(model.sqlselect).replace('%%%SQL%%%', sql); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); sql = sql.replace('%%%SQLFIELDS%%%', sql_fields); sql = sql.replace('%%%SQLWHERE%%%', sqlwhere); if (selecttype == 'multiple') { //Generate sort sql var sortstr = ''; _.each(sortfields, function (sortfield) { if (sortstr != '') sortstr += ','; //Get sort expression sortstr += (sortfield.sql ? _this.ParseSQL(DB.util.ReplaceAll(sortfield.sql, '%%%SQL%%%', sortfield.field)) : sortfield.field) + ' COLLATE NOCASE ' + sortfield.dir; }); if (sortstr == '') sortstr = '1'; sql = sql.replace('%%%SORT%%%', sortstr); } return sql; }; DBsql.prototype.getModelMultisel = function (jsh, model, lovfield, allfields, sql_foreignkeyfields, datalockqueries, lov_datalockqueries, param_datalocks) { var _this = this; var sql = ''; var tbl = _this.getTable(jsh, model); var tbl_alias = tbl.replace(/[^a-zA-Z0-9]+/g, ''); if(tbl_alias.length > 50) tbl_alias = tbl_alias.substr(0,50); var sql_select_cols = ''; var sql_tbl_alias = ''; var sql_multiparent = '(%%%LOVSQL%%%) multiparent'; var sql_join = 'multiparent.' + jsh.map.code_val + ' = ' + tbl_alias + '.' + lovfield.name; sql_select_cols = 'select '; for (var i = 0; i < allfields.length; i++) { var field = allfields[i]; if (i > 0) sql_select_cols += ','; var fieldsql = field.name; if ('sqlselect' in field) fieldsql = _this.ParseSQL(field.sqlselect); sql_select_cols += XfromDB(jsh, field, fieldsql); } sql_select_cols += ' ,coalesce(cast(' + jsh.map.code_val + ' as text),cast(' + lovfield.name + ' as text)) ' + jsh.map.code_val; sql_select_cols += ' ,coalesce(coalesce(cast(' + jsh.map.code_txt + ' as text), cast(' + jsh.map.code_val + ' as text)),cast(' + lovfield.name + ' as text)) ' + jsh.map.code_txt; sql_select_cols += ', ' + jsh.map.code_seq; sql_tbl_alias = '(select * from ' + tbl + ' where 1=1 %%%DATALOCKS%%%'; //Add Keys to where if (sql_foreignkeyfields.length) _.each(sql_foreignkeyfields, function (field) { sql_tbl_alias += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); else sql_tbl_alias += ' and 0=1'; sql_tbl_alias += ') ' + tbl_alias; //Simulate FULL OUTER JOIN on sqlite sql = sql_select_cols + ' from ' + sql_tbl_alias + ' left join '+sql_multiparent+' on '+sql_join+' where (%%%SQLWHERE%%%)'; sql += ' union all ' + sql_select_cols + ' from ' + sql_multiparent + ' left join ' + sql_tbl_alias + ' on ' + sql_join + ' where ('+tbl_alias+'.'+lovfield.name+' is null) and (%%%SQLWHERE%%%)'; sql += ' order by ' + jsh.map.code_seq + ',' + jsh.map.code_txt + ' COLLATE NOCASE'; if('sqlselect' in model) sql = _this.ParseSQL(model.sqlselect).replace('%%%SQL%%%', sql); var sqlwhere = '1=1'; if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql = DB.util.ReplaceAll(sql, '%%%SQLWHERE%%%', sqlwhere); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); //Add LOVSQL to SQL var lovsql = ''; var lov = lovfield.lov; if ('sql' in lov) { lovsql = lov['sql']; } else if (lov.code || lov.code_sys || lov.code_app) { lovsql = 'select ' + jsh.map.code_val + ',' + jsh.map.code_txt + ',' + jsh.map.code_seq + ' from ' + _this.getLOVTable(jsh, model, lov) + ' where (' + jsh.map.code_end_date + ' is null or ' + jsh.map.code_end_date + ">datetime('now','localtime'))"; } else throw new Error('LOV type not supported.'); if ('sql' in lov) { //Add datalocks for dynamic LOV SQL var lov_datalockstr = ''; _.each(lov_datalockqueries, function (datalockquery) { lov_datalockstr += ' and ' + datalockquery; }); lovsql = applyDataLockSQL(lovsql, lov_datalockstr); } sql = DB.util.ReplaceAll(sql, '%%%LOVSQL%%%', lovsql); //Add datalocks for dynamic query string parameters _.each(param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); return sql; }; DBsql.prototype.getTabCode = function (jsh, model, selectfields, keys, datalockqueries) { var _this = this; var sql = ''; sql = 'select '; for (var i = 0; i < selectfields.length; i++) { var field = selectfields[i]; if (i > 0) sql += ','; var fieldsql = field.name; if ('sqlselect' in field) fieldsql = _this.ParseSQL(field.sqlselect); sql += XfromDB(jsh, field, fieldsql); } var tbl = _this.getTable(jsh, model); sql += ' from ' + tbl + ' where '; var sqlwhere = '1=1'; if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql += ' %%%SQLWHERE%%% %%%DATALOCKS%%%'; _.each(keys, function (field) { sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); if('sqlselect' in model) sql = _this.ParseSQL(model.sqlselect).replace('%%%SQL%%%', sql); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); sql = sql.replace('%%%SQLWHERE%%%', sqlwhere); return sql; }; DBsql.prototype.getTitle = function (jsh, model, sql, datalockqueries) { var _this = this; sql = _this.ParseSQL(sql); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.putModelForm = function (jsh, model, fields, keys, sql_extfields, sql_extvalues, encryptedfields, hashfields, enc_datalockqueries, param_datalocks) { var _this = this; var sql = ''; var enc_sql = ''; var fields_insert = _.filter(fields,function(field){ return (field.sqlinsert!==''); }); var sql_fields = _.map(fields_insert, function (field) { return field.name; }).concat(sql_extfields).join(','); var sql_values = _.map(fields_insert, function (field) { if(field.sqlinsert) return field.sqlinsert; return XtoDB(jsh, field, '@' + field.name); }).concat(sql_extvalues).join(','); var tbl = _this.getTable(jsh, model); sql = 'insert into ' + tbl + '(' + sql_fields + ') '; sql += ' values(' + sql_values + '); '; //Add Keys to where if (keys.length >= 1){ var sqlgetinsertkeys = 'select ' + _.map(keys, function (field) { var rslt = field.name + ' as ' + field.name; return rslt; }).join(',') + ' from ' + tbl + ' where '; //For inserts into views, use jsharmony_meta.last_insert_rowid_override to store the newly created key if(model._dbdef && (model._dbdef.table_type=='view') && (keys.length == 1)) sqlgetinsertkeys += keys[0].name + ' = (select last_insert_rowid_override from jsharmony_meta);'; else sqlgetinsertkeys += 'rowid = (select ifnull(last_insert_rowid_override,last_insert_rowid()) from jsharmony_meta);'; if('sqlgetinsertkeys' in model) sqlgetinsertkeys = model.sqlgetinsertkeys; sql += sqlgetinsertkeys; } else sql += 'select changes()+(select extra_changes from jsharmony_meta) xrowcount;'; if('sqlinsert' in model){ sql = _this.ParseSQL(model.sqlinsert).replace('%%%SQL%%%', sql); sql = DB.util.ReplaceAll(sql, '%%%TABLE%%%', _this.getTable(jsh, model)); sql = DB.util.ReplaceAll(sql, '%%%FIELDS%%%', sql_fields); sql = DB.util.ReplaceAll(sql, '%%%VALUES%%%', sql_values); } if ((encryptedfields.length > 0) || !_.isEmpty(hashfields)) { enc_sql = 'update jsharmony_meta set extra_changes=0 where extra_changes<>0;update ' + tbl + ' set ' + _.map(encryptedfields, function (field) { var rslt = field.name + '=' + XtoDB(jsh, field, '@' + field.name); return rslt; }).join(','); if(!_.isEmpty(hashfields)){ if(encryptedfields.length > 0) enc_sql += ','; enc_sql += _.map(hashfields, function (field) { var rslt = field.name + '=' + XtoDB(jsh, field, '@' + field.name); return rslt; }).join(','); } enc_sql += ' where 1=1 %%%DATALOCKS%%%'; //Add Keys to where _.each(keys, function (field) { enc_sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); enc_sql += '; select changes()+(select extra_changes from jsharmony_meta) xrowcount;'; if('sqlinsertencrypt' in model) enc_sql = _this.ParseSQL(model.sqlinsertencrypt).replace('%%%SQL%%%', enc_sql); var enc_datalockstr = ''; _.each(enc_datalockqueries, function (datalockquery) { enc_datalockstr += ' and ' + datalockquery; }); enc_sql = applyDataLockSQL(enc_sql, enc_datalockstr); } _.each(param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); return { sql: sql, enc_sql: enc_sql }; }; DBsql.prototype.postModelForm = function (jsh, model, fields, keys, sql_extfields, sql_extvalues, hashfields, param_datalocks, datalockqueries) { var _this = this; var sql = ''; var tbl = _this.getTable(jsh, model); var sql_fields = _.map(_.filter(fields,function(field){ return (field.sqlupdate!==''); }), function (field) { if (field && field.sqlupdate) return field.name + '=' + _this.ParseSQL(field.sqlupdate); return field.name + '=' + XtoDB(jsh, field, '@' + field.name); }).join(','); var sql_has_fields = (fields.length > 0); if (sql_extfields.length > 0) { var sql_extsql = ''; for (var i = 0; i < sql_extfields.length; i++) { if (sql_extsql != '') sql_extsql += ','; sql_extsql += sql_extfields[i] + '=' + sql_extvalues[i]; } if (sql_has_fields) sql_fields += ','; sql_fields += sql_extsql; sql_has_fields = true; } _.each(hashfields, function(field){ if (sql_has_fields) sql_fields += ','; sql_fields += field.name + '=' + XtoDB(jsh, field, '@' + field.name); sql_has_fields = true; }); //Add Keys to where var sql_keys = ''; _.each(keys, function (field) { sql_keys += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); sql = 'update ' + tbl + ' set ' + sql_fields + ' where (%%%SQLWHERE%%%) %%%DATALOCKS%%%' + sql_keys + '; select changes()+(select extra_changes from jsharmony_meta) xrowcount;'; if('sqlupdate' in model){ sql = _this.ParseSQL(model.sqlupdate).replace('%%%SQL%%%', sql); sql = DB.util.ReplaceAll(sql, '%%%TABLE%%%', _this.getTable(jsh, model)); sql = DB.util.ReplaceAll(sql, '%%%FIELDS%%%', sql_fields); sql = DB.util.ReplaceAll(sql, '%%%KEYS%%%', sql_keys); } _.each(param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); var sqlwhere = '1=1'; if(jsh && jsh.Config && jsh.Config.system_settings && jsh.Config.system_settings.deprecated && jsh.Config.system_settings.deprecated.disable_sqlwhere_on_form_update_delete){ /* Do nothing */ } else if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql = DB.util.ReplaceAll(sql, '%%%SQLWHERE%%%', sqlwhere); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.postModelMultisel = function (jsh, model, lovfield, lovvals, foreignkeyfields, param_datalocks, datalockqueries, lov_datalockqueries) { var _this = this; var sql = ''; var tbl = _this.getTable(jsh, model); sql = 'create temp table if not exists _VAR(xrowcount integer);'; sql += 'delete from _VAR;'; sql += 'insert into _VAR(xrowcount) values(0);'; sql += 'delete from ' + tbl + ' where (%%%SQLWHERE%%%) '; _.each(foreignkeyfields, function (field) { sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); if (lovvals.length > 0) { sql += ' and cast(' + lovfield.name + ' as text) not in ('; for (let i = 0; i < lovvals.length; i++) { if (i > 0) sql += ','; sql += XtoDB(jsh, lovfield, '@multisel' + i); } sql += ')'; } sql += ' %%%DATALOCKS%%%;'; sql += 'update _VAR set xrowcount = xrowcount + changes();'; if (lovvals.length > 0) { sql += 'insert into ' + tbl + '('; _.each(foreignkeyfields, function (field) { sql += field.name + ','; }); sql += lovfield.name + ') select '; _.each(foreignkeyfields, function (field) { sql += XtoDB(jsh, field, '@' + field.name) + ','; }); sql += jsh.map.code_val + ' from (%%%LOVSQL%%%) multiparent where cast(' + jsh.map.code_val + ' as text) in ('; for (let i = 0; i < lovvals.length; i++) { if (i > 0) sql += ','; sql += XtoDB(jsh, lovfield, '@multisel' + i); } sql += ') and ' + jsh.map.code_val + ' not in (select ' + lovfield.name + ' from ' + tbl + ' where (%%%SQLWHERE%%%) '; _.each(foreignkeyfields, function (field) { sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); sql += ' %%%DATALOCKS%%%);'; sql += 'update _VAR set xrowcount = xrowcount + changes();'; } sql += 'select (xrowcount + (select extra_changes from jsharmony_meta)) xrowcount from _VAR;'; if('sqlupdate' in model) sql = _this.ParseSQL(model.sqlupdate).replace('%%%SQL%%%', sql); _.each(param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); var sqlwhere = '1=1'; if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql = DB.util.ReplaceAll(sql, '%%%SQLWHERE%%%', sqlwhere); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); //Add LOVSQL to SQL var lovsql = ''; var lov = lovfield.lov; if ('sql' in lov) { lovsql = lov['sql']; } else if (lov.code || lov.code_sys || lov.code_app) { lovsql = 'select ' + jsh.map.code_val + ',' + jsh.map.code_txt + ',' + jsh.map.code_seq + ' from ' + _this.getLOVTable(jsh, model, lov) + ' where (' + jsh.map.code_end_date + ' is null or ' + jsh.map.code_end_date + ">datetime('now','localtime'))"; } else throw new Error('LOV type not supported.'); if ('sql' in lov) { var lov_datalockstr = ''; _.each(lov_datalockqueries, function (datalockquery) { lov_datalockstr += ' and ' + datalockquery; }); lovsql = applyDataLockSQL(lovsql, lov_datalockstr); } sql = DB.util.ReplaceAll(sql, '%%%LOVSQL%%%', lovsql); return sql; }; DBsql.prototype.postModelExec = function (jsh, model, param_datalocks, datalockqueries) { var _this = this; var sql = _this.ParseSQL(model.sqlexec); _.each(param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.deleteModelForm = function (jsh, model, keys, datalockqueries) { var _this = this; var sql = ''; var tbl = _this.getTable(jsh, model); sql += 'delete from ' + tbl + ' where (%%%SQLWHERE%%%) %%%DATALOCKS%%%'; _.each(keys, function (field) { sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); sql += '; select changes() + (select extra_changes from jsharmony_meta) xrowcount;'; if('sqldelete' in model) sql = _this.ParseSQL(model.sqldelete).replace('%%%SQL%%%', sql); var sqlwhere = '1=1'; if(jsh && jsh.Config && jsh.Config.system_settings && jsh.Config.system_settings.deprecated && jsh.Config.system_settings.deprecated.disable_sqlwhere_on_form_update_delete){ /* Do nothing */ } else if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql = DB.util.ReplaceAll(sql, '%%%SQLWHERE%%%', sqlwhere); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.Download = function (jsh, model, fields, keys, datalockqueries) { var _this = this; var sql = ''; var tbl = _this.getTable(jsh, model); sql = 'select '; for (var i = 0; i < fields.length; i++) { var field = fields[i]; if (i > 0) sql += ','; var fieldsql = field.name; if ('sqlselect' in field) fieldsql = _this.ParseSQL(field.sqlselect); sql += XfromDB(jsh, field, fieldsql); } sql += ' from ' + tbl + ' where (%%%SQLWHERE%%%) %%%DATALOCKS%%%'; //Add Keys to where _.each(keys, function (field) { sql += ' and ' + field.name + '=' + XtoDB(jsh, field, '@' + field.name); }); if('sqldownloadselect' in model) sql = _this.ParseSQL(model.sqldownloadselect).replace('%%%SQL%%%', sql); var sqlwhere = '1=1'; if (('sqlwhere' in model) && model.sqlwhere) sqlwhere = _this.ParseSQL(model.sqlwhere); sql = DB.util.ReplaceAll(sql, '%%%SQLWHERE%%%', sqlwhere); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.parseReportSQLData = function (jsh, dname, dparams, skipdatalock, datalockqueries) { var _this = this; var sql = _this.ParseSQL(dparams.sql); var datalockstr = ''; if (!skipdatalock) _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.runReportJob = function (jsh, model, datalockqueries) { var _this = this; var sql = _this.ParseSQL(model.jobqueue.sql); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.runReportBatch = function (jsh, model, datalockqueries) { var _this = this; var sql = _this.ParseSQL(model.batch.sql); var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); return sql; }; DBsql.prototype.getCMS_M = function (aspa_object) { return 'select M_Desc from ' + aspa_object + '_M where M_ID=1'; }; DBsql.prototype.getSearchTerm = function (jsh, model, field, pname, search_value, comparison) { var _this = this; var sqlsearch = ''; var fsql = field.name; if (field.lov && !field.lov.showcode) fsql = _this.getLOVFieldTxt(jsh, model, field); if (field.sqlselect) fsql = field.sqlselect; if (field.sqlsearch){ fsql = jsh.parseFieldExpression(field, _this.ParseSQL(field.sqlsearch), { SQL: fsql }); } else if (field.sql_from_db){ fsql = jsh.parseFieldExpression(field, _this.ParseSQL(field.sql_from_db), { SQL: fsql }); } var ftype = field.type; var dbtype = null; var pname_param = XSearchtoDB(jsh, field, '@' + pname); switch (ftype) { case 'boolean': dbtype = types.Boolean; if (comparison == '<>') { sqlsearch = fsql + ' <> ' + pname_param; } else sqlsearch = fsql + ' = ' + pname_param; break; case 'bigint': case 'int': case 'smallint': case 'tinyint': dbtype = types.BigInt; if (comparison == '<>') { sqlsearch = fsql + ' <> ' + pname_param; } else if (comparison == '>') { sqlsearch = fsql + ' > ' + pname_param; } else if (comparison == '<') { sqlsearch = fsql + ' < ' + pname_param; } else if (comparison == '>=') { sqlsearch = fsql + ' >= ' + pname_param; } else if (comparison == '<=') { sqlsearch = fsql + ' <= ' + pname_param; } else sqlsearch = fsql + ' = ' + pname_param; break; case 'decimal': case 'float': if (comparison == '<>') { sqlsearch = fsql + ' <> ' + pname_param; } else if (comparison == '>') { sqlsearch = fsql + ' > ' + pname_param; } else if (comparison == '<') { sqlsearch = fsql + ' < ' + pname_param; } else if (comparison == '>=') { sqlsearch = fsql + ' >= ' + pname_param; } else if (comparison == '<=') { sqlsearch = fsql + ' <= ' + pname_param; } else sqlsearch = fsql + ' = ' + pname_param; break; case 'varchar': case 'char': //.replace(/[%_]/g,"\\$&") if (comparison == '=') { sqlsearch = 'upper(' + fsql + ') like upper(' + pname_param+')'; } else if (comparison == '<>') { sqlsearch = 'upper(' + fsql + ') not like upper(' + pname_param + ')'; } else if (comparison == 'notcontains') { search_value = '%' + search_value + '%'; sqlsearch = 'upper(' + fsql + ') not like upper(' + pname_param + ')'; } else if (comparison == 'beginswith') { search_value = search_value + '%'; sqlsearch = 'upper(' + fsql + ') like upper(' + pname_param + ')'; } else if (comparison == 'endswith') { search_value = '%' + search_value; sqlsearch = 'upper(' + fsql + ') like upper(' + pname_param + ')'; } else if ((comparison == 'soundslike') && (field.sqlsearchsound)) { sqlsearch = _this.ParseSQL(field.sqlsearchsound).replace('%%%FIELD%%%', pname_param).replace('%%%SOUNDEX%%%', pname_param+'_soundex'); } else { search_value = '%' + search_value + '%'; sqlsearch = 'upper(' + fsql + ') like upper(' + pname_param + ')'; } dbtype = types.VarChar(search_value.length); break; case 'datetime': case 'date': if (ftype == 'datetime') dbtype = types.DateTime(7,(field.datatype_config && field.datatype_config.preserve_timezone)); if (comparison == '<>') { sqlsearch = fsql + ' <> ' + pname_param; } else if (comparison == '>') { sqlsearch = fsql + ' > ' + pname_param; } else if (comparison == '<') { sqlsearch = fsql + ' < ' + pname_param; } else if (comparison == '>=') { sqlsearch = fsql + ' >= ' + pname_param; } else if (comparison == '<=') { sqlsearch = fsql + ' <= ' + pname_param; } else sqlsearch = fsql + ' = ' + pname_param; break; case 'time': if (comparison == '<>') { sqlsearch = fsql + ' <> ' + pname_param; } else if (comparison == '>') { sqlsearch = fsql + ' > ' + pname_param; } else if (comparison == '<') { sqlsearch = fsql + ' < ' + pname_param; } else if (comparison == '>=') { sqlsearch = fsql + ' >= ' + pname_param; } else if (comparison == '<=') { sqlsearch = fsql + ' <= ' + pname_param; } else sqlsearch = fsql + ' = ' + pname_param; break; case 'hash': dbtype = types.VarBinary(field.length); if (comparison == '=') { sqlsearch = fsql + ' = ' + pname_param; } else if (comparison == '<>') { sqlsearch = fsql + ' <> ' + pname_param; } break; case 'binary': if (comparison == '=') { sqlsearch = 'hex(' + fsql + ') like (' + pname_param+')'; } else if (comparison == '<>') { sqlsearch = 'hex(' + fsql + ') not like (' + pname_param + ')'; } else if (comparison == 'notcontains') { search_value = '%' + search_value + '%'; sqlsearch = 'hex(' + fsql + ') not like (' + pname_param + ')'; } else if (comparison == 'beginswith') { search_value = search_value + '%'; sqlsearch = 'hex(' + fsql + ') like (' + pname_param + ')'; } else if (comparison == 'endswith') { search_value = '%' + search_value; sqlsearch = 'hex(' + fsql + ') like (' + pname_param + ')'; } else if ((comparison == 'soundslike') && (field.sqlsearchsound)) { sqlsearch = _this.ParseSQL(field.sqlsearchsound).replace('%%%FIELD%%%', pname_param); } else { search_value = '%' + search_value + '%'; sqlsearch = 'hex(' + fsql + ') like (' + pname_param + ')'; } dbtype = types.VarChar(search_value.length); break; default: throw new Error('Search type ' + field.name + '/' + ftype + ' not supported.'); } if (comparison == 'null') { if(_.includes(['varchar','char','binary'],ftype)) sqlsearch = "ifnull(" + fsql + ",'')=''"; else sqlsearch = fsql + ' is null'; } else if (comparison == 'notnull') { if(_.includes(['varchar','char','binary'],ftype)) sqlsearch = "ifnull(" + fsql + ",'')<>''"; else sqlsearch = fsql + ' is not null'; } return { sql: sqlsearch, dbtype: dbtype, search_value: search_value }; }; DBsql.prototype.getDefaultTasks = function (jsh, dflt_sql_fields) { var _this = this; var sql = ''; var sql_builder = ''; for (var i = 0; i < dflt_sql_fields.length; i++) { var field = dflt_sql_fields[i]; var fsql = XfromDB(jsh, field.field, _this.ParseSQL(field.sql)); var datalockstr = ''; _.each(field.datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); fsql = applyDataLockSQL(fsql, datalockstr); _.each(field.param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); if (sql_builder) sql_builder += ','; sql_builder += fsql; } if (sql_builder) sql += 'select ' + sql_builder; return sql; }; DBsql.prototype.getLOV = function (jsh, fname, lov, datalockqueries, param_datalocks, options) { options = _.extend({ truncate_lov: false, model: null }, options); var _this = this; var sql = ''; if ('sql' in lov) { sql = _this.ParseSQL(lov['sql']); } else if ('sql2' in lov) { sql = _this.ParseSQL(lov['sql2']); } else if ('sqlmp' in lov) { sql = _this.ParseSQL(lov['sqlmp']); } else if (lov.code || lov.code_sys || lov.code_app) { sql = 'select ' + jsh.map.code_val + ',' + jsh.map.code_txt + ',' + jsh.map.code_seq + ' from ' + _this.getLOVTable(jsh, options.model, lov) + ' where (' + jsh.map.code_end_date + ' is null or ' + jsh.map.code_end_date + ">datetime('now','localtime')) order by " + jsh.map.code_seq + ',' + jsh.map.code_txt + ' COLLATE NOCASE'; } else if (lov.code2 || lov.code2_sys || lov.code2_app) { sql = 'select ' + jsh.map.code_val + '1 as ' + jsh.map.code_parent + ',' + jsh.map.code_val + '2 as ' + jsh.map.code_val + ',' + jsh.map.code_txt + ' from ' + _this.getLOVTable(jsh, options.model, lov) + ' where (' + jsh.map.code_end_date + ' is null or ' + jsh.map.code_end_date + ">datetime('now','localtime')) order by " + jsh.map.code_seq + ',' + jsh.map.code_txt + ' COLLATE NOCASE'; } else sql = 'select 1 as ' + jsh.map.code_val + ',1 as ' + jsh.map.code_txt + ' where 1=0'; var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); var sqltruncate = ''; if(options.truncate_lov){ sqltruncate = lov.sqltruncate||''; if(sqltruncate.trim()) sqltruncate = ' and '+sqltruncate; } sql = DB.util.ReplaceAll(sql, '%%%TRUNCATE%%%', sqltruncate); _.each(param_datalocks, function (param_datalock) { sql = addDataLockSQL(sql, "select " + XtoDB(jsh, param_datalock.field, '@' + param_datalock.pname) + " as " + param_datalock.pname, param_datalock.datalockquery); }); return sql; }; DBsql.prototype.getLOVFieldTxt = function (jsh, model, field) { var _this = this; var rslt = ''; if (!field || !field.lov) return rslt; var lov = field.lov; var valsql = field.name; if ('sqlselect' in field) valsql = _this.ParseSQL(field.sqlselect); var parentsql = ''; if ('parent' in lov) { _.each(model.fields, function (pfield) { if (pfield.name == lov.parent) { if ('sqlselect' in pfield) parentsql += _this.ParseSQL(pfield.sqlselect); else parentsql = pfield.name; } }); if(!parentsql && lov.parent) parentsql = lov.parent; } if(lov.values){ if(!lov.values.length) rslt = "select NULL"; else if('parent' in lov) rslt = "(select " + jsh.map.code_txt + " from (" + _this.arrayToTable(DB.util.ParseLOVValues(jsh, lov.values)) + ") "+field.name+"_values where "+field.name+"_values."+jsh.map.code_val+"1=(" + parentsql + ") and "+field.name+"_values."+jsh.map.code_val+"2=(" + valsql + "))"; else rslt = "(select " + jsh.map.code_txt + " from (" + _this.arrayToTable(DB.util.ParseLOVValues(jsh, lov.values)) + ") "+field.name+"_values where "+field.name+"_values."+jsh.map.code_val+"=(" + valsql + "))"; } else if ('sqlselect' in lov) { rslt = _this.ParseSQL(lov['sqlselect']); } else if (lov.code || lov.code_sys || lov.code_app) { rslt = 'select ' + jsh.map.code_txt + ' from ' + _this.getLOVTable(jsh, model, lov) + ' where ' + jsh.map.code_val + '=(' + valsql + ')'; } else if (lov.code2 || lov.code2_sys || lov.code2_app) { if (!parentsql) throw new Error('Parent field not found in LOV.'); rslt = 'select ' + jsh.map.code_txt + ' from '+ _this.getLOVTable(jsh, model, lov) + ' where ' + jsh.map.code_val + '1=(' + parentsql + ') and ' + jsh.map.code_val + '2=(' + valsql + ')'; } else rslt = "select NULL"; rslt = '(' + rslt + ')'; return rslt; }; DBsql.prototype.getBreadcrumbTasks = function (jsh, model, sql, datalockqueries, bcrumb_sql_fields) { var _this = this; sql = _this.ParseSQL(sql); if(sql.indexOf('%%%DATALOCKS%%%') >= 0){ //Standard Datalock Implementation var datalockstr = ''; _.each(datalockqueries, function (datalockquery) { datalockstr += ' and ' + datalockquery; }); sql = applyDataLockSQL(sql, datalockstr); } else { //Pre-check Parameters for Stored Procedure execution _.each(datalockqueries, function (datalockquery) { sql = addDataLockSQL(sql, "%%%BCRUMBSQLFIELDS%%%", datalockquery); }); if (bcrumb_sql_fields.length) { var bcrumb_sql = 'select '; for (var i = 0; i < bcrumb_sql_fields.length; i++) { var field = bcrumb_sql_fields[i]; if (i > 0) bcrumb_sql += ','; bcrumb_sql += XtoDB(jsh, field, '@' + field.name) + " as " + field.name; } sql = DB.util.ReplaceAll(sql, '%%%BCRUMBSQLFIELDS%%%', bcrumb_sql); } } return sql; }; DBsql.prototype.getTable = function(jsh, model){ var _this = this; if(model.table=='jsharmony:models'){ var rslt = ''; for(var _modelid in jsh.Models){ var _model = jsh.Models[_modelid]; var parents = _model._inherits.join(', '); if(!rslt){ rslt += "(select "; rslt += "'" + _this.escape(_modelid) + "' as model_id,"; rslt += "'" + _this.escape(_model.title) + "' as model_title,"; rslt += "'" + _this.escape(_model.layout) + "' as model_layout,"; rslt += "'" + _this.escape(_model.table) + "' as model_table,"; rslt += "'" + _this.escape(_model.module) + "' as model_module,"; rslt += "'" + _this.escape(parents) + "' as model_parents"; } else{ rslt += " union all select "; rslt += "'" + _this.escape(_modelid) + "',"; rslt += "'" + _this.escape(_model.title) + "',"; rslt += "'" + _this.escape(_model.layout) + "',"; rslt += "'" + _this.escape(_model.table) + "',"; rslt += "'" + _this.escape(_model.module) + "',"; rslt += "'" + _this.escape(parents) + "'"; } } rslt += ")"; return rslt; } else if(model.table) { var tblname = model.table.toString(); if(tblname.indexOf('.') < 0){ if(model.module && (model.module in jsh.Modules)){ var modelModule = jsh.Modules[model.module]; if(modelModule.schema) tblname = modelModule.schema + '.' + tblname; } } else if(tblname.indexOf('.')==0) tblname = tblname.substr(1); return tblname; } return undefined; }; DBsql.prototype.getLOVTable = function(jsh, model, lov){ if(!lov) return ''; var lovtype = ''; if('code' in lov) lovtype = 'code'; else if('code2' in lov) lovtype = 'code2'; else if('code_sys' in lov) lovtype = 'code_sys'; else if('code2_sys' in lov) lovtype = 'code2_sys'; else if('code_app' in lov) lovtype = 'code_app'; else if('code2_app' in lov) lovtype = 'code2_app'; else return ''; var tblname = lov[lovtype]; if(!tblname) return ''; if(tblname.indexOf('.') < 0){ tblname = jsh.map[lovtype] + '_' + tblname; var tblschema = ''; if(lov.schema) tblschema = lov.schema; else if(model && model.module && (model.module in jsh.Modules)){ var modelModule = jsh.Modules[model.module]; if(modelModule.schema) tblschema = modelModule.schema; } if(tblschema) tblname = tblschema + '.' + tblname; } return tblname; }; DBsql.escape = function(val){ if (val === 0) return val; if (val === 0.0) return val; if (val === "0") return val; if (!val) return ''; if (!isNaN(val)) return val; val = val.toString(); if (!val) return ''; val = val.replace(/;/g, '\\;'); val = val.replace(/[\0\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]/g, ''); //eslint-disable-line no-control-regex val = val.replace(/'/g, '\'\''); return val; }; DBsql.prototype.escape = function(val){ return DBsql.escape(val); }; DBsql.prototype.ParseBatchSQL = function(val){ return [val]; }; DBsql.prototype.ParseSQL = function(sql){ return this.db.ParseSQL(sql); }; DBsql.prototype.arrayToTable = function(table){ var _this = this; var rslt = []; if(!table || !_.isArray(table) || !table.length) throw new Error('Array cannot be empty'); _.each(table, function(row,i){ var rowsql = ''; var hasvalue = false; for(var key in row){ if(rowsql) rowsql += ','; rowsql += "'" + _this.escape(row[key]) + "'" + ' as ' + key; hasvalue = true; } rowsql = 'select ' + rowsql; rslt.push(rowsql); if(!hasvalue) throw new Error('Array row '+(i+1)+' is empty'); }); return rslt.join(' union all '); }; function addDataLockSQL(sql, dsql, dquery){ return "update jsharmony_meta set errcode=-12,errmsg='INVALID ACCESS' where (case when (not exists(select * from ("+dsql+") dual where "+dquery+")) then 1 else 0 end)=1; \r\n" + sql; } function applyDataLockSQL(sql, datalockstr){ if (datalockstr) { if (!(sql.indexOf('%%%DATALOCKS%%%') >= 0)) throw new Error('SQL missing %%%DATALOCKS%%% in query: '+sql); } return DB.util.ReplaceAll(sql, '%%%DATALOCKS%%%', datalockstr||''); } function XfromDB(jsh, field, fieldsql){ var rslt = fieldsql; if(field.type && field.sql_from_db){ rslt = jsh.parseFieldExpression(field, field.sql_from_db, { SQL: (fieldsql?'('+fieldsql+')':'') }); } var cast = false; if(field.type=='boolean') cast = true; //Simplify if(!cast && (rslt == field.name)) { /* Do nothing */ } else rslt = '(' + rslt + ') as "' + field.name + (cast?('__cast_as_'+field.type):'') + '"'; return rslt; } function XtoDB(jsh, field, fieldsql){ var rslt = fieldsql; if(field.type && field.sql_to_db){ rslt = jsh.parseFieldExpression(field, field.sql_to_db, { SQL: (fieldsql?'('+fieldsql+')':'') }); } return rslt; } function XSearchtoDB(jsh, field, fieldsql){ var rslt = fieldsql; if(field.type && field.sqlsearch_to_db){ rslt = jsh.parseFieldExpression(field, field.sqlsearch_to_db, { SQL: (fieldsql?'('+fieldsql+')':'') }); } return rslt; } exports = module.exports = DBsql;