diff --git a/entity/Person_entity/entityfields/campaignactiongroup/children/sqltests/onActionProcess.js b/entity/Person_entity/entityfields/campaignactiongroup/children/sqltests/onActionProcess.js index 1faa5af6eb2300d2def337d6f08ce21ce703d583..cf678759fdee9daa9a89f879d1e7a81a44b60f56 100644 --- a/entity/Person_entity/entityfields/campaignactiongroup/children/sqltests/onActionProcess.js +++ b/entity/Person_entity/entityfields/campaignactiongroup/children/sqltests/onActionProcess.js @@ -289,11 +289,12 @@ var combinedAndOrTests = new TestSuite([ ]); var ifSetTests = new TestSuite([ - ["simple or if set with all types of empty values. Note that undefined leads to using the first parameter as subquery", function(pTester) + ["simple and if set with all types of empty values. Note that undefined leads to using the first parameter as subquery", function(pTester) { var actual = new SqlBuilder() .whereIfSet("PERSON.FIRSTNAME", "") .andIfSet("PERSON.LASTNAME", null) + .andIfSet("PERSON.LASTNAME", undefined) pTester.assert("", actual._where._sqlStorage, "no sql should be added"); pTester.assert(0, actual._where.preparedValues.length, "no params should be added"); @@ -595,6 +596,11 @@ var mandatoryErrorTests = new TestSuite([ new SqlBuilder().where().or("PERSON.FIRSTNAME", null); }, SqlBuilder.ERROR_VALUE_IS_MANDATORY()], + ["and with undefined as value should error", function(pTester) + { + new SqlBuilder().where().or("PERSON.FIRSTNAME", undefined); + }, SqlBuilder.ERROR_VALUE_IS_MANDATORY()], + ["and with a jdito-var containing null should error", function(pTester) { vars.set("$global.TestingVarNull", null); @@ -643,6 +649,11 @@ var mandatoryErrorTests = new TestSuite([ new SqlBuilder().where().or("PERSON.FIRSTNAME", null); }, SqlBuilder.ERROR_VALUE_IS_MANDATORY()], + ["or with undefined as value should error", function(pTester) + { + new SqlBuilder().where().or("PERSON.FIRSTNAME", undefined); + }, SqlBuilder.ERROR_VALUE_IS_MANDATORY()], + ["or with a jdito-var containing null should error", function(pTester) { vars.set("$global.TestingVarNull", null); @@ -751,6 +762,23 @@ var testConstantFunctions = new TestSuite([ }] ]); +var selectTests = new TestSuite([ + ["test if a sql-builder in a fields-array is translated to sql correctly", function(pTester) + { + var countSubQuery = newSelect("count(*)") + .from("AB_ATTRIBUTEUSAGE") + .where("AB_ATTRIBUTEUSAGE.OBJECT_TYPE", "myType") + .and("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID"); + + var actual = SqlBuilder.begin() + .select(["AB_ATTRIBUTEID", "AB_ATTRIBUTEUSAGEID", countSubQuery]) + .from("AB_ATTRIBUTE") + + pTester.assert("select AB_ATTRIBUTEID, AB_ATTRIBUTEUSAGEID, (select count(*) from AB_ATTRIBUTEUSAGE where AB_ATTRIBUTEUSAGE.OBJECT_TYPE = ? and AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID)", actual._select._sqlStorage, "prepared select-sql"); + pTester.assert(1, actual._select.preparedValues.length, "number of params"); + }], +]) + var tester = new Tester("Test SqlBuilder"); tester.test(validAndUsageTests); tester.test(validOrUsageTests); @@ -760,6 +788,7 @@ tester.test(dbWrapperTests); tester.test(mandatoryErrorTests); tester.test(inStatementTests); tester.test(testConstantFunctions); +tester.test(selectTests); logging.log("-------------------------"); tester.printResults(); diff --git a/process/Attribute_lib/process.js b/process/Attribute_lib/process.js index a05e631dba124f8220ab5356ee6138c588e0e8b4..94546d31f18beac5cd6da9a3880142f2805442af 100644 --- a/process/Attribute_lib/process.js +++ b/process/Attribute_lib/process.js @@ -407,9 +407,6 @@ AttributeRelationUtils.getAttribute = function (pAttributeId, pObjectRowId, pObj */ AttributeRelationUtils.getAttributeSqlBuilder = function (pFields, pObjectRowId, pObjectType) { - if (!pObjectType) - pObjectType = null; - return newSelect(pFields) .from("AB_ATTRIBUTERELATION") .join("AB_ATTRIBUTE", "AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID") @@ -684,15 +681,12 @@ AttributeRelationUtils.countAttributeRelations = function (pRowId, pObjectType, //unchanged (already stored) row ==> increase count var countObj = {}; - var condition = SqlCondition.begin() - .andPrepare("AB_ATTRIBUTERELATION.OBJECT_ROWID", pRowId) - .andPrepareIfSet("AB_ATTRIBUTERELATION.OBJECT_TYPE", pObjectType); - - var storedAttributeRelations = db.table(condition.buildSql( - "select AB_ATTRIBUTERELATIONID, AB_ATTRIBUTE_ID from AB_ATTRIBUTERELATION", - "1=2" - )); - + var storedAttributeRelations = newSelect("AB_ATTRIBUTERELATIONID, AB_ATTRIBUTE_ID") + .from("AB_ATTRIBUTERELATION") + .where("AB_ATTRIBUTERELATION.OBJECT_ROWID", pRowId) + .andIfSet("AB_ATTRIBUTERELATION.OBJECT_TYPE", pObjectType) + .table(); + storedAttributeRelations.forEach(function ([storedAttrRelationId, storedAttributeId]) { var currentAttributeId = storedAttributeId; //merging the data that is stored in the DB and the provided changes @@ -1038,21 +1032,20 @@ AttributeUsageUtil.insertChildrenUsages = function (pAttributeId, pObjectType) var columns = ["AB_ATTRIBUTEUSAGEID", "AB_ATTRIBUTE_ID", "OBJECT_TYPE"]; var types = db.getColumnTypes(table, columns); - var sqlSelect = "select AB_ATTRIBUTEID, " - + " (select count(*) from AB_ATTRIBUTEUSAGE where AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID and OBJECT_TYPE = '" - + pObjectType + "') = 0 from AB_ATTRIBUTE"; - var inserts = []; _addInserts(pAttributeId, pObjectType); db.inserts(inserts); function _addInserts (pAttributeId, pObjectType) { - var condition = SqlCondition.begin() - .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, "# != ?") - .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", pAttributeId); - var attributes = db.table(condition.buildSql(sqlSelect)); - + var attributes = newSelect("AB_ATTRIBUTEID, " + + " (select count(*) from AB_ATTRIBUTEUSAGE where AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID and OBJECT_TYPE = '" + + pObjectType + "') = 0") + .from("AB_ATTRIBUTE") + .where("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, "# != ?") + .and("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", pAttributeId) + .table(); + attributes.forEach(function (row) { if (row[1] == "true") @@ -1080,10 +1073,10 @@ AttributeUsageUtil.updateChildrenUsages = function (pAttributeId, pOldObjectType var table = "AB_ATTRIBUTEUSAGE"; - var countSubQuery = SqlCondition.begin() - .andPrepare("AB_ATTRIBUTEUSAGE.OBJECT_TYPE", pNewObjectType) - .and("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID") - .buildSql("select count(*) from AB_ATTRIBUTEUSAGE"); + var countSubQuery = newSelect("count(*)") + .from("AB_ATTRIBUTEUSAGE") + .where("AB_ATTRIBUTEUSAGE.OBJECT_TYPE", pNewObjectType) + .and("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID"); var sqlSelect = SqlBuilder.begin() .select(["AB_ATTRIBUTEID", "AB_ATTRIBUTEUSAGEID", countSubQuery]) diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js index 1747da97edf54ac82fa41bbbfd5f354cddf7fb32..3c3b7d4340db0adf8bbb5bf0965c3da38c57b13e 100644 --- a/process/Sql_lib/process.js +++ b/process/Sql_lib/process.js @@ -759,7 +759,7 @@ SqlBuilder.ERROR_INVALID_SUBQUERY_TYPE = function() SqlBuilder.ERROR_VALUE_IS_MANDATORY = function() { - return new Error(translate.text("SqlBuilder.and/or: pValue has to be not null or \"\" or []")); + return new Error(translate.text("SqlBuilder.and/or: pValue has to be not null or \"\" or [] or undefined")); } SqlBuilder.ERROR_VALUE_IS_MANDATORY_JDITO_VAR = function() @@ -1133,7 +1133,30 @@ SqlBuilder.prototype._addWhere = function(pFieldOrCond, pValue, pMandatory, pCon if (pFieldOrCond === undefined && pValue === undefined && pCond === undefined && pFieldType === undefined) throw SqlBuilder.ERROR_NO_PARAMETER_PROVIDED(); - + + // Special case: if only pFieldOrCond is set and we can identify it as a valid field-string (e.g. "Table.Field") we assume that it is not just a condition string. + // --> we can check pValue for undefined and also allow simple string-conditions + // --> this only works if isFullFieldQualifier() can detect if the supplied string is a valid field-string or if it is some sql. + // currently it checks for some special characters which should not exist in any field-string but in conditions. + // If there is a special case missing -> add it to the regexp in isFullFieldQualifier() + if (pValue === undefined && pCond === undefined && pFieldType === undefined && typeof pFieldOrCond == "string" && SqlUtils.isFullFieldQualifier(pFieldOrCond)) + { + if (pMandatory) + throw SqlBuilder.ERROR_VALUE_IS_MANDATORY(); + else + return this; + } + + // Special case: if 1 parameter and NOT mandatory -> throw error, as e.g. andIfSet("null) or andIfSet("") would not make any sense + // And it allows to check if pValue is undefined (e.g. if pValue is a not initialized variable) + // Without this error no it would not be possible to decide if pValue is undefined, because the function is called with andIfSet("my super sql") + // or if it is called with + // var uninitializedVar; + // andIfSet("Table.Column", uninitializedVar) + // as both would result in pValue === undefined + // --> We declare a constellation such as andIfSet( + + // For now: treat "" as null just like db.insert, db.table etc. Maybe otion for later: more pMandatory-types if (pValue === "") pValue = null; @@ -1239,7 +1262,7 @@ SqlBuilder.prototype._addWhere = function(pFieldOrCond, pValue, pMandatory, pCon SqlBuilder.prototype._and = function(pFieldOrCond, pValue, pMandatory, pCond, pFieldType) { var that = this; - + return this._addWhere(pFieldOrCond, pValue, pMandatory, pCond, pFieldType, function(pPreparedCondition) { that._where._previouslyOnlyOr = false; @@ -2493,6 +2516,7 @@ function SqlUtils() {} * <br/> 1. the name of the table if also a pColumnName is specified * <br/> 2. the name of the table and columname as "tablename.columnname" (e.g. "ORGANISATION.NAME") if no pColumnName is specified * <br/> 3. an array with 2 elements: [tablename, columnname] (e.g. ["ORGANISATION", "NAME"]) if no pColumnName is specified +* <br/> 4. an array with 3 elements: [tablename, columnname, tablealias] (e.g. ["ORGANISATION", "NAME", "org"]) if no pColumnName is specified * <br/> Everything else will raise an error * * @param {String} [pColumnName] depending on pFieldOrTableName this should be undefined/null or the name of a column @@ -2500,13 +2524,22 @@ function SqlUtils() {} * @return {Object|TypeError} TypeError if something wrong has been passed or returns a object with these properties: * 1. "table" which is the tablename * 2. "column" which is the columnname -* e.g. {table: "ORGANISATION", column: "NAME"} +* 3. "tableAlias" which is the tableAlias if it exists. else it is also the table +* e.g. {table: "ORGANISATION", column: "NAME", tableAlias: "org"} * * */ SqlUtils._parseFieldQualifier = function(pFieldOrTableName, pColumnName) { - var tableName, columnName; + var fnName = "SqlUtils._parseFieldQualifier";//for return errors + + if (typeof pFieldOrTableName == "string") + { + if (pFieldOrTableName.search(/[\s=\(\)<>!]/) != -1) + return new TypeError(translate.withArguments("[%0]%1 has to be a string without empty spaces, (, ), =, <, > but it contains at least one of them", [fnName, "pFieldOrTableName"])); + } + + var tableName, columnName, tableAlias; if (pColumnName != undefined) { tableName = pFieldOrTableName; @@ -2514,7 +2547,6 @@ SqlUtils._parseFieldQualifier = function(pFieldOrTableName, pColumnName) } else { - var fnName = "SqlUtils._parseFieldQualifier";//for return errors var fieldVarType = typeof(pFieldOrTableName); if (fieldVarType == "string") { @@ -2526,28 +2558,43 @@ SqlUtils._parseFieldQualifier = function(pFieldOrTableName, pColumnName) fieldVarType])); } - if (pFieldOrTableName.hasOwnProperty("length")) + if (Array.isArray(pFieldOrTableName)) { - if (pFieldOrTableName.length != 2) - return new TypeError(translate.withArguments("[%0]has now an incorrect length; estimated 2 elements but got %1", [ - fnName, pFieldOrTableName.length ])); - - tableName = pFieldOrTableName[0]; - columnName = pFieldOrTableName[1]; + if (pFieldOrTableName.length == 3) + { + tableName = pFieldOrTableName[0]; + columnName = pFieldOrTableName[1]; + tableAlias = pFieldOrTableName[2]; + } + else if (pFieldOrTableName.length == 2) + { + tableName = pFieldOrTableName[0]; + columnName = pFieldOrTableName[1]; + } + else + { + return new TypeError(translate.withArguments("[%0]has now an incorrect length; estimated 2 or 3 elements but got %1", [fnName, pFieldOrTableName.length ])); + } } else //check for object happens since there exists JavaArrays and JavaScript arrays which are both valid return new TypeError(translate.withArguments("[%0]%1 is an object but seems not to be a valid array or array-like", [ fnName, "pFieldOrTableName"])); } + if (!tableAlias) + tableAlias = tableName; + if (typeof(columnName) != "string") return new TypeError(translate.withArguments("[%0]the columnName is not a string after interpreting", [fnName])); if (typeof(tableName) != "string") return new TypeError(translate.withArguments("[%0]the tableName is not a string after interpreting", [fnName])); + if (typeof(tableAlias) != "string") + return new TypeError(translate.withArguments("[%0]the tableAlias is not a string after interpreting", [fnName])); return { table: tableName, - column: columnName + column: columnName, + tableAlias: tableAlias }; }; @@ -2559,6 +2606,7 @@ SqlUtils._parseFieldQualifier = function(pFieldOrTableName, pColumnName) * <br/> 1. the name of the table if also a pColumnName is specified * <br/> 2. the name of the table and columname as "tablename.columnname" (e.g. "ORGANISATION.NAME") if no pColumnName is specified * <br/> 3. an array with 2 elements: [tablename, columnname] (e.g. ["ORGANISATION", "NAME"]) if no pColumnName is specified +* <br/> 4. an array with 3 elements: [tablename, columnname, tablealias] (e.g. ["ORGANISATION", "NAME", "org"]) if no pColumnName is specified * <br/> Everything else will raise an error * * @param {String} [pColumnName] depending on pFieldOrTableName this should be undefined/null or the name of a column @@ -2581,6 +2629,7 @@ SqlUtils.isFullFieldQualifier = function(pFieldOrTableName, pColumnName) * <br/> 1. the name of the table if also a pColumnName is specified * <br/> 2. the name of the table and columname as "tablename.columnname" (e.g. "ORGANISATION.NAME") if no pColumnName is specified * <br/> 3. an array with 2 elements: [tablename, columnname] (e.g. ["ORGANISATION", "NAME"]) if no pColumnName is specified +* <br/> 4. an array with 3 elements: [tablename, columnname, tablealias] (e.g. ["ORGANISATION", "NAME", "org"]) if no pColumnName is specified * <br/> Everything else will raise an error * * @param {String} [pColumnName] depending on pFieldOrTableName this should be undefined/null or the name of a column