diff --git a/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml index 372497186413416a3a27831bd933c08792bbd0d2..a6e5c99db425623c89a8aaa4446df2b04a77fdb0 100644 --- a/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml +++ b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml @@ -15,7 +15,7 @@ <changeSet dbms="!derby" author="b.ulrich" id="85ba6a61-9318-4118-ac4c-e33730f6581d"> <dropPrimaryKey tableName="DOCUMENTTEMPLATE" constraintName="PK_DOCUMENTTEMPLATE_DOCUMENTTEMPLATEID" dropIndex="true"/> - <dropNotNullConstraint tableName="DOCUMENTTEMPLATE" columnName="DOCUMENTTEMPLATEID"/> + <dropNotNullConstraint tableName="DOCUMENTTEMPLATE" columnName="DOCUMENTTEMPLATEID" columnDataType="VARCHAR(36)"/> <modifyDataType tableName="DOCUMENTTEMPLATE" columnName="DOCUMENTTEMPLATEID" newDataType="CHAR(36)"/> <addNotNullConstraint columnName="DOCUMENTTEMPLATEID" tableName="DOCUMENTTEMPLATE" columnDataType="CHAR(36)" validate="true"/> <addPrimaryKey tableName="DOCUMENTTEMPLATE" constraintName="PK_DOCUMENTTEMPLATE_DOCUMENTTEMPLATEID" columnNames="DOCUMENTTEMPLATEID"/> diff --git a/entity/Appointment_entity/Appointment_entity.aod b/entity/Appointment_entity/Appointment_entity.aod index 6f51538041ffc0b890e44450ea85fd73235b5185..2b98d6bd2c33292ef54ca82d1d5c8f624b353cbf 100644 --- a/entity/Appointment_entity/Appointment_entity.aod +++ b/entity/Appointment_entity/Appointment_entity.aod @@ -171,11 +171,6 @@ </entityParameter> <entityConsumer> <name>AppointmentLinks</name> - <dependency> - <name>dependency</name> - <entityName>AppointmentLink_entity</entityName> - <fieldName>Links</fieldName> - </dependency> <children> <entityParameter> <name>AppointmentId_param</name> @@ -187,6 +182,11 @@ <expose v="false" /> </entityParameter> </children> + <dependency> + <name>dependency</name> + <entityName>AppointmentLink_entity</entityName> + <fieldName>Links</fieldName> + </dependency> </entityConsumer> <entityActionField> <name>deleteSeries</name> @@ -254,6 +254,11 @@ <name>#PROVIDER_AGGREGATES</name> <useAggregates v="true" /> </entityProvider> + <entityParameter> + <name>ErrorOnPermissionDenied</name> + <valueProcess>%aditoprj%/entity/Appointment_entity/entityfields/erroronpermissiondenied/valueProcess.js</valueProcess> + <expose v="true" /> + </entityParameter> </entityFields> <recordContainers> <jDitoRecordContainer> diff --git a/entity/Appointment_entity/entityfields/erroronpermissiondenied/valueProcess.js b/entity/Appointment_entity/entityfields/erroronpermissiondenied/valueProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..e5bfa3bbe7f58d2ffaf401248014a6d1a560d2de --- /dev/null +++ b/entity/Appointment_entity/entityfields/erroronpermissiondenied/valueProcess.js @@ -0,0 +1,3 @@ +import("system.result"); + +result.string("true"); \ No newline at end of file diff --git a/entity/Appointment_entity/grantDeleteProcess.js b/entity/Appointment_entity/grantDeleteProcess.js index 4caa2d99cfdda2637190ab5c76a15565666b79b5..aef302f111201f63dc427328d2e4db900ac4c0d3 100644 --- a/entity/Appointment_entity/grantDeleteProcess.js +++ b/entity/Appointment_entity/grantDeleteProcess.js @@ -2,6 +2,10 @@ import("system.vars"); import("system.result"); import("system.calendars"); import("system.text"); +import("system.tools"); -var owner = text.decodeMS(JSON.parse(vars.get("$param.Entry_param"))["h"])[1].split(":")[1]; -result.string(calendars.hasPermission([owner], calendars.VEVENT, "WRITE")); \ No newline at end of file + +var user = tools.getCurrentUser(); +var calUser = calendars.getCalendarUser(user["title"]); +var calUserCn = text.decodeMS(calUser)[1].split(":")[1]; +result.string(calendars.hasPermission(calUserCn, calendars.VEVENT, "WRITE")); \ No newline at end of file diff --git a/entity/Appointment_entity/grantUpdateProcess.js b/entity/Appointment_entity/grantUpdateProcess.js index 3562ea4a6c4ba8fda784eb7ea85abd591e022f87..e6ac4c8426c460fd26d1f16844a7844c09300153 100644 --- a/entity/Appointment_entity/grantUpdateProcess.js +++ b/entity/Appointment_entity/grantUpdateProcess.js @@ -2,7 +2,13 @@ import("system.vars"); import("system.result"); import("system.calendars"); import("system.text"); +import("system.tools"); +import("system.logging"); -var owner = text.decodeMS(JSON.parse(vars.get("$param.Entry_param"))["h"])[1].split(":")[1]; -result.string(calendars.hasPermission([owner], calendars.VEVENT, "WRITE")); +var user = tools.getCurrentUser(); +var calUser = calendars.getCalendarUser(user["title"]); +var calUserCn = text.decodeMS(calUser)[1].split(":")[1]; +var permitted = calendars.hasPermission(calUserCn, calendars.VEVENT, "WRITE"); + +result.string(permitted); diff --git a/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js b/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js index e56415a0faf52007f91bcc4e92f9ae20aebfa819..709bfac8d00e3b805a383dc0c78c0cb8b91a07d1 100644 --- a/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js @@ -1,3 +1,4 @@ +import("Calendar_lib"); import("Employee_lib"); import("system.tools"); import("system.db"); @@ -9,6 +10,7 @@ import("system.datetime"); import("system.eMath"); import("system.util"); import("system.neon"); +import("system.text"); var appointmentSelect = newSelect("APPOINTMENT_ID").from("AB_APPOINTMENTLINK"); var appointmentUids; @@ -27,14 +29,14 @@ if(vars.exists("$param.Entry_param") && vars.get("$param.Entry_param")) //@TODO Icon result.object([ - buildEntry(entry, masterEntry) + CalendarUtil.buildEntry(entry, masterEntry) ]); } else if(vars.get("$sys.recordstate") != neon.OPERATINGSTATE_NEW && vars.get("$local.idvalues") != null && vars.get("$local.idvalues") != "") { var selectedids = vars.get("$local.idvalues"); - result.object([buildEntry(calendars.getEntry(selectedids, null, null), null)]); + result.object([CalendarUtil.buildEntry(calendars.getEntry(selectedids, null, null), null)]); } else if(vars.getString("$param.LinkedAppointmentsFromDashlet_param")) @@ -42,7 +44,7 @@ else if(vars.getString("$param.LinkedAppointmentsFromDashlet_param")) var contactid = EmployeeUtils.getCurrentContactId(); appointmentSelect.whereIfSet("AB_APPOINTMENTLINK.OBJECT_ROWID", contactid) - result.object(buildEntriesFromUids(appointmentSelect.table())); + result.object(CalendarUtil.buildEntriesFromUids(appointmentSelect.table())); } /** @@ -51,78 +53,5 @@ else if(vars.getString("$param.LinkedAppointmentsFromDashlet_param")) else if(vars.getString("$param.LinkedObjectId_param") != undefined) { appointmentSelect.whereIfSet("AB_APPOINTMENTLINK.OBJECT_ROWID", "$param.LinkedObjectId_param") - result.object(buildEntriesFromUids(appointmentSelect.table())); -} - -function buildEntriesFromUids(appointmentUids) -{ - var entryArray = new Array(appointmentUids.length); - - for(var i = 0; i < appointmentUids.length; i++) - entryArray[i] = buildEntry(calendars.getEntry(appointmentUids[i], null, null), null); - - return entryArray; -} - - -function buildEntry(pEntry, pMasterentry) -{ - var uid = pEntry[calendars.ID]; - var summary = pEntry[calendars.SUMMARY]; - var attendees = pEntry[calendars.AFFECTEDUSERS]; - var startdate = pEntry[calendars.DTSTART]; - var enddate = pEntry[calendars.DTEND]; - var links = pEntry[calendars.LINKS]; - var description = pEntry[calendars.DESCRIPTION]; - if(pEntry[calendars.ORGANIZER2] != undefined) - var organizer = pEntry[calendars.ORGANIZER2]["paramvalue"]; - if(pEntry[calendars.USER2] != undefined) - var owner = pEntry[calendars.USER2]["paramvalue"]; - var status = pEntry[calendars.STATUS]; - var location = pEntry[calendars.LOCATION]; - var reminder = pEntry[calendars.REMINDER_DURATION]; - var remindercheck = pEntry[calendars.HASREMINDER] - var classification = pEntry[calendars.CLASSIFICATION]; - var transparency = pEntry[calendars.TRANSPARENCY]; - var categories = pEntry[calendars.CATEGORIES]; - var isAllDay = pEntry["X-ADITO-ISALLDAYEVENT"] != null ? pEntry["X-ADITO-ISALLDAYEVENT"] : "FALSE"; - - var masterBegin = pMasterentry != null ? pMasterentry[calendars.DTSTART] : null - var masterEnd = pMasterentry != null ? pMasterentry[calendars.DTEND] : null - - // Recurrence - var recurrenceID = pEntry[calendars.RECURRENCEID]; - var rrule = null; - if (pMasterentry != null) { // Entry is a recurrence exception, therefore get rrule from master - rrule = pMasterentry[calendars.RRULE] != null ? pMasterentry[calendars.RRULE][0] : null; - } else { - rrule = pEntry[calendars.RRULE] != null ? pEntry[calendars.RRULE][0] : null; - } - - return [ - uid, - attendees.length, - startdate, - enddate, - summary, - organizer, - owner, - attendees, - status, - description, - location, - '', - isAllDay, - classification, - transparency, - categories, - reminder, - remindercheck, - rrule, - recurrenceID, - null, - masterBegin, - masterEnd, - null - ]; + result.object(CalendarUtil.buildEntriesFromUids(appointmentSelect.table())); } diff --git a/entity/Appointment_entity/recordcontainers/jdito/onDelete.js b/entity/Appointment_entity/recordcontainers/jdito/onDelete.js index 4e0e5c7a5c1257293965989052765e861a71fff7..6f6249aee33bd1be9f2247d09814ffba59a1d904 100644 --- a/entity/Appointment_entity/recordcontainers/jdito/onDelete.js +++ b/entity/Appointment_entity/recordcontainers/jdito/onDelete.js @@ -1,20 +1,30 @@ +import("system.logging"); import("Sql_lib"); import("system.neon"); import("system.calendars"); import("system.vars"); -if (vars.exists("$param.Entry_param")) +var uid; + +if (vars.get("$param.Entry_param") != null) { var entry = JSON.parse(vars.getString("$param.Entry_param")); var reccurenceid = entry[calendars.RECURRENCEID]; + if (reccurenceid == undefined) reccurenceid = null; - calendars.removeEntryByUID(calendars.VEVENT, entry[calendars.USER2]["cn"], entry[calendars.ID], reccurenceid) + uid = entry[calendars.ID]; + calendars.removeEntryByUID(calendars.VEVENT, entry[calendars.USER2]["cn"], uid, reccurenceid); +} +else if(vars.get("$field.OWNER")) +{ + uid = vars.get("$field.UID"); + calendars.removeEntryByUID(calendars.VEVENT, JSON.parse(vars.get("$field.OWNER"))["cn"], uid, vars.get("$field.RECURRENCEID")); +} /** * Deletes ApointmentLinks referring to the deleted Appointment. */ - newWhereIfSet("AB_APPOINTMENTLINK.APPOINTMENT_ID", entry[calendars.ID]) - .deleteData(); -} \ No newline at end of file + newWhereIfSet("AB_APPOINTMENTLINK.APPOINTMENT_ID", uid) + .deleteData(); \ No newline at end of file diff --git a/entity/Appointment_entity/recordcontainers/jdito/rowCountProcess.js b/entity/Appointment_entity/recordcontainers/jdito/rowCountProcess.js index afff252f743faff586199e13333a707e5d52c51e..d6495461f9409c2d28cd62951d09cc6797a4eb69 100644 --- a/entity/Appointment_entity/recordcontainers/jdito/rowCountProcess.js +++ b/entity/Appointment_entity/recordcontainers/jdito/rowCountProcess.js @@ -1,3 +1,4 @@ +import("Calendar_lib"); import("system.db"); import("Employee_lib"); import("Sql_lib"); @@ -5,7 +6,7 @@ import("system.vars"); import("system.result"); var rowCount = "0"; -var cond = newSelect("count(APPOINTMENT_ID)") +var cond = newSelect("APPOINTMENT_ID") .from("AB_APPOINTMENTLINK"); if (vars.exists("$local.idvalues") && vars.get("$local.idvalues")) @@ -13,7 +14,7 @@ if (vars.exists("$local.idvalues") && vars.get("$local.idvalues")) else if (vars.getString("$param.LinkedAppointmentsFromDashlet_param")) { cond.whereIfSet("AB_APPOINTMENTLINK.OBJECT_ROWID", EmployeeUtils.getCurrentContactId()); - rowCount = cond.cell(); + rowCount = CalendarUtil.countEntriesFromUids(cond.table()); } /** @@ -22,7 +23,7 @@ else if (vars.getString("$param.LinkedAppointmentsFromDashlet_param")) else if (vars.getString("$param.LinkedObjectId_param") != undefined) { cond.whereIfSet("AB_APPOINTMENTLINK.OBJECT_ROWID", "$param.LinkedObjectId_param"); - rowCount = cond.cell(); + rowCount = CalendarUtil.countEntriesFromUids(cond.table()); } /** * Will be used, if the user is operating the calendar. diff --git a/entity/BulkMailRecipient_entity/BulkMailRecipient_entity.aod b/entity/BulkMailRecipient_entity/BulkMailRecipient_entity.aod index bae83161b6a2b2580cbc7734093346ce3596a028..60d85496e220808f40709d4fd7fc80bbba176c0a 100644 --- a/entity/BulkMailRecipient_entity/BulkMailRecipient_entity.aod +++ b/entity/BulkMailRecipient_entity/BulkMailRecipient_entity.aod @@ -121,6 +121,13 @@ <iconId>VAADIN:BAN</iconId> <tooltipProcess>%aditoprj%/entity/BulkMailRecipient_entity/entityfields/recipientactions/children/removewithcommrestriction/tooltipProcess.js</tooltipProcess> </entityActionField> + <entityActionField> + <name>startMarketingWorkflows</name> + <title>Start marketing mailing</title> + <onActionProcess>%aditoprj%/entity/BulkMailRecipient_entity/entityfields/recipientactions/children/startmarketingworkflows/onActionProcess.js</onActionProcess> + <isObjectAction v="false" /> + <iconId>VAADIN:ENVELOPES</iconId> + </entityActionField> </children> </entityActionGroup> <entityField> diff --git a/entity/BulkMailRecipient_entity/entityfields/recipientactions/children/startmarketingworkflows/onActionProcess.js b/entity/BulkMailRecipient_entity/entityfields/recipientactions/children/startmarketingworkflows/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..cbe91449e5c258643491b9020a7bc6d1b534e7ec --- /dev/null +++ b/entity/BulkMailRecipient_entity/entityfields/recipientactions/children/startmarketingworkflows/onActionProcess.js @@ -0,0 +1,34 @@ +import("Util_lib"); +import("system.entities"); +import("Context_lib"); +import("system.vars"); +import("system.neon"); + +var rows = vars.get("$sys.selectionRows"); +var filter = vars.get("$sys.filter").filter; +var targets = []; + +if (Utils.isNullOrEmpty(rows)) +{ + let loadConfig = entities.createConfigForLoadingRows() + .entity("BulkMailRecipient_entity") + .provider("BulkMailRecipients") + .fields(["CONTACT_ID", "TARGETCONTEXT"]) + .addParameter("BulkMailId_param", vars.get("$param.BulkMailId_param")); + + if (filter) + loadConfig.filter(JSON.stringify(filter)); + + rows = entities.getRows(loadConfig); +} + +rows = rows.map(function (row) +{ + return [row["CONTACT_ID"], row["TARGETCONTEXT"]]; +}); + + +neon.openContext("MarketingWorkflowLauncher", "MarketingWorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, { + "ObjectIds_param": JSON.stringify(rows), + "ObjectType_param": ContextUtils.getCurrentContextId() +}); \ No newline at end of file diff --git a/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/hascommrestriction.value/expression.js b/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/hascommrestriction.value/expression.js index 3020cb618cdf0f0aac9fbf0f9201753a29563a37..04cd6d4dc91c5a7e36cd82b78301acf456fc05ff 100644 --- a/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/hascommrestriction.value/expression.js +++ b/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/hascommrestriction.value/expression.js @@ -5,5 +5,5 @@ import("system.db"); import("system.result"); var commRestrictionCond = ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail()); -var sql = "case when (" + commRestrictionCond.toString() + ") then 'true' else 'false' end"; -result.string(sql); +var sql = SqlBuilder.caseWhen(commRestrictionCond).thenString("true").elseString("false"); +result.string(sql.toString()); diff --git a/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/status.displayvalue/expression.js b/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/status.displayvalue/expression.js index 115c35f85e46db99d439362dca426fd984657802..49b6fefd59233f6aa50934a21ce43f06a3a61172 100644 --- a/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/status.displayvalue/expression.js +++ b/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/status.displayvalue/expression.js @@ -1,17 +1,12 @@ import("Sql_lib"); import("Contact_lib"); import("system.translate"); -import("system.db"); -import("Bulkmail_lib"); import("system.result"); import("Keyword_lib"); import("KeywordRegistry_basic"); -var commRestrictionCond = ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail()).build(); +var commRestrictionCond = ContactUtils.getCommRestrictionCondition($KeywordRegistry.communicationMediumCampaign$mail()); var keywordSql = KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.bulkMailRecipientStatus(), "BULKMAILRECIPIENT.STATUS"); -// TODO: is prepared possible? -var sql = "case when (" + SqlUtils.translateStatementWithQuotes(commRestrictionCond) - + ") then '" + translate.text("Advertising ban") - + "' else (" + keywordSql + ") end"; -result.string(sql); +var sql = SqlBuilder.caseWhen(commRestrictionCond).thenString(translate.text("Advertising ban")).elseValue(keywordSql); +result.string(sql.toString()); diff --git a/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js b/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js index 9bac722a3fa50b14fe0fd7fcf9cb92ebd8e49fba..5247fde75b3f57fdb34fb70500efb8bca84d6906 100644 --- a/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js +++ b/entity/BulkMailRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js @@ -1,7 +1,7 @@ +import("Sql_lib"); import("Context_lib"); import("system.result"); -// TODO: is prepared possible? -result.string("case when PERSON_ID is null then '" + ContextUtils.getContextName("Organisation") - + "' when CONTACT.ORGANISATION_ID is not null and CONTACT.PERSON_ID is not null then '" + ContextUtils.getContextName("Person") - + "' else '' end"); \ No newline at end of file +var sql = SqlBuilder.caseWhen("PERSON_ID is null").thenString(ContextUtils.getContextName("Organisation")) + .when(newWhere("CONTACT.ORGANISATION_ID is not null").and("CONTACT.PERSON_ID is not null")).thenString(ContextUtils.getContextName("Person")) +result.string(sql.toString()); \ No newline at end of file diff --git a/entity/CampaignParticipant_entity/CampaignParticipant_entity.aod b/entity/CampaignParticipant_entity/CampaignParticipant_entity.aod index 3c8e5a5655f3c8320c4188939e9588988e7b9b44..4d3b86ba02c4c01afcd977df57bbd15e493c3c08 100644 --- a/entity/CampaignParticipant_entity/CampaignParticipant_entity.aod +++ b/entity/CampaignParticipant_entity/CampaignParticipant_entity.aod @@ -177,6 +177,13 @@ <tooltip>Update campaign step</tooltip> <tooltipProcess>%aditoprj%/entity/CampaignParticipant_entity/entityfields/filterviewactiongroup/children/setsteptoparticipantselection/tooltipProcess.js</tooltipProcess> </entityActionField> + <entityActionField> + <name>startMarketingWorkflows</name> + <title>Start marketing mailing</title> + <onActionProcess>%aditoprj%/entity/CampaignParticipant_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js</onActionProcess> + <isObjectAction v="false" /> + <iconId>VAADIN:ENVELOPES</iconId> + </entityActionField> </children> </entityActionGroup> <entityField> diff --git a/entity/CampaignParticipant_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js b/entity/CampaignParticipant_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..40e60ff20d2ca20af3b447981c2a988959d2de63 --- /dev/null +++ b/entity/CampaignParticipant_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js @@ -0,0 +1,36 @@ +import("Util_lib"); +import("system.entities"); +import("Context_lib"); +import("system.vars"); +import("system.neon"); + +var rows = vars.get("$sys.selectionRows"); +var filter = vars.get("$sys.filter").filter; +var targets = []; + +if (Utils.isNullOrEmpty(rows)) +{ + let loadConfig = entities.createConfigForLoadingRows() + .entity("CampaignParticipant_entity") + .provider("CampaignParticipantsProvider") + .fields(["CONTACT_ID", "CONTACTCONTEXT"]) + .addParameter("CampaignId_param", vars.get("$param.CampaignId_param")) + .addParameter("CampaignStepId_param", vars.get("$param.CampaignStepId_param")) + .addParameter("ContactId_param", vars.get("$param.ContactId_param")); + + if (filter) + loadConfig.filter(JSON.stringify(filter)); + + rows = entities.getRows(loadConfig); +} + +rows = rows.map(function (row) +{ + return [row["CONTACT_ID"], row["CONTACTCONTEXT"]]; +}); + + +neon.openContext("MarketingWorkflowLauncher", "MarketingWorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, { + "ObjectIds_param": JSON.stringify(rows), + "ObjectType_param": ContextUtils.getCurrentContextId() +}); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/conditionProcess.js b/entity/Campaign_entity/recordcontainers/db/conditionProcess.js index b56a17e4e112b773aa2b1f6f5339c986b5d205bf..ea77837ea6f8defb3e4e66200740f5b8614adae5 100644 --- a/entity/Campaign_entity/recordcontainers/db/conditionProcess.js +++ b/entity/Campaign_entity/recordcontainers/db/conditionProcess.js @@ -7,19 +7,11 @@ import("Sql_lib"); var recordState = vars.get("$sys.recordstate"); +var condition = newWhere(); if(vars.get("$param.ShowOnlyCurrentUsersCampaigns_param") == 'true') { - //TODO: use a preparedCondition (.build instead of .translate) when available #1030812 #1034026 - result.string(newWhere("CAMPAIGN.EMPLOYEE_CONTACT_ID", EmployeeUtils.getCurrentContactId()).toString()); -} else if (recordState != neon.OPERATINGSTATE_NEW && recordState != neon.OPERATINGSTATE_EDIT) { - var condition = new SqlBuilder() - .whereIfSet("STEPDATESTART_TABLEALIAS.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID") - .andIfSet("STEPDATEEND_TABLEALIAS.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID") - ; + condition.and("CAMPAIGN.EMPLOYEE_CONTACT_ID", EmployeeUtils.getCurrentContactId()); +} - result.string(condition.toString()); -} else { - - result.string(newWhere().toString()); -} \ No newline at end of file +result.string(condition.toString()); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js b/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js index 5eec4c678e0303f56f160d22534f7c2fbe2bd302..f1704c63ce08d64a2b42eaa2192c87e929b2c290 100644 --- a/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js +++ b/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js @@ -7,10 +7,11 @@ var recordState = vars.get("$sys.recordstate"); var res = "CAMPAIGN"; if (recordState != neon.OPERATINGSTATE_NEW && recordState != neon.OPERATINGSTATE_EDIT) { - var subSelectDateStart = "(select min(DATE_START) as STEPDATESTART_ALIAS, CAMPAIGN_ID from CAMPAIGNSTEP group by CAMPAIGN_ID) as STEPDATESTART_TABLEALIAS"; - var subSelectDateEnd = "(select max(DATE_END) as STEPDATEEND_ALIAS, CAMPAIGN_ID from CAMPAIGNSTEP group by CAMPAIGN_ID) as STEPDATEEND_TABLEALIAS"; - - res += ", " + subSelectDateStart + ", " + subSelectDateEnd; + res += " join (select min(DATE_START) as STEPDATESTART_ALIAS, CAMPAIGN_ID from CAMPAIGNSTEP group by CAMPAIGN_ID) STEPDATESTART_TABLEALIAS" + + " on STEPDATESTART_TABLEALIAS.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID " + + " join (select max(DATE_END) as STEPDATEEND_ALIAS, CAMPAIGN_ID from CAMPAIGNSTEP group by CAMPAIGN_ID) STEPDATEEND_TABLEALIAS" + + " on STEPDATEEND_TABLEALIAS.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID "; + } result.string(res); diff --git a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js index fa780bd3a980c26cd0931459951df89c31b7d4a3..dd188aaf77933759617acc567c9f1ba0cb1313dc 100644 --- a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js +++ b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js @@ -1,6 +1,11 @@ +import("Context_lib"); +import("Sql_lib"); import("system.vars"); import("system.result"); +//!LibFunction +var cond = newWhere(null, newSelect("ACTIVITYLINK.OBJECT_ROWID").from("ACTIVITYLINK") + .join("ACTIVITY", newWhere("ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID") + .and("ACTIVITYLINK.OBJECT_TYPE", ContextUtils.getCurrentContextId())) + .where(vars.get("$local.condition")), SqlBuilder.EXISTS()); -var from = "ACTIVITYLINK join ACTIVITY on ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID and ACTIVITYLINK.OBJECT_TYPE = 'Campaign'"; - -result.string("CAMPAIGNID in (select ACTIVITYLINK.OBJECT_ROWID from " + from + " where " + vars.get("$local.condition")+ ")"); \ No newline at end of file +result.string(cond.toString()); \ No newline at end of file diff --git a/entity/ClassificationAdmin_entity/recordcontainers/jdito/onUpdate.js b/entity/ClassificationAdmin_entity/recordcontainers/jdito/onUpdate.js index 43a6304543f7b01dab728e1774e8d6f9e06980e0..ea803f184c537724212607c29cfa59f9342de57c 100644 --- a/entity/ClassificationAdmin_entity/recordcontainers/jdito/onUpdate.js +++ b/entity/ClassificationAdmin_entity/recordcontainers/jdito/onUpdate.js @@ -178,7 +178,7 @@ function _update() } } - cond = newWhereIfSet("CLASSIFICATIONTYPE.CLASSIFICATIONTYPEID = '" + text.decodeMS(uid)[1] + "'"); + cond = newWhereIfSet("CLASSIFICATIONTYPE.CLASSIFICATIONTYPEID", text.decodeMS(uid)[1]); columns.push("SCORETYPE"); values.push(vars.get("$field.CLASSIFICATIONTYPEIDDISPLAYVALUE")); cond.updateData(true, table, columns, null, values); @@ -195,13 +195,13 @@ function _update() .where("CLASSIFICATIONGROUP.CLASSIFICATIONGROUPID", id) .cell(); - cond = newWhereIfSet("CLASSIFICATIONTYPE.CLASSIFICATIONGROUP_ID = '" + classificationGroupId + "'"); + cond = newWhereIfSet("CLASSIFICATIONTYPE.CLASSIFICATIONGROUP_ID", classificationGroupId); var groupTable = "CLASSIFICATIONGROUP"; var groupColumns = ["SORTING", "TITLE"]; var groupName = rowdata["CLASSIFICATIONGROUP.value"] == classificationGroupId ? rowdata["CLASSIFICATIONGROUP.displayValue"] : rowdata["CLASSIFICATIONGROUP.value"]; var groupValues = [vars.get("$field.SORTING"), groupName]; - var groupCond = newWhereIfSet("CLASSIFICATIONGROUP.CLASSIFICATIONGROUPID = '" + classificationGroupId + "'"); + var groupCond = newWhereIfSet("CLASSIFICATIONGROUP.CLASSIFICATIONGROUPID", classificationGroupId); groupCond.updateData(true, groupTable, groupColumns, null, groupValues); } } \ No newline at end of file diff --git a/entity/Competition_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js b/entity/Competition_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js index 33554680cccd2c3d363443686457c41e0c1c5729..fb69d484cfa8fc6aa1c45987d94b793c35efd20a 100644 --- a/entity/Competition_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js +++ b/entity/Competition_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js @@ -1,4 +1,4 @@ import("system.result"); import("Context_lib"); -result.string(ContextUtils.getNameSubselectSql("OBJECT_TYPE", "OBJECT_ROWID")) \ No newline at end of file +result.string(ContextUtils.getNameSubselectSql("COMPETITION.OBJECT_TYPE", "COMPETITION.OBJECT_ROWID")) \ No newline at end of file diff --git a/entity/Contract_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js b/entity/Contract_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js index c2197272407c3509180dc90692e2edc59e2d6d7a..dd188aaf77933759617acc567c9f1ba0cb1313dc 100644 --- a/entity/Contract_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js +++ b/entity/Contract_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js @@ -1,6 +1,11 @@ +import("Context_lib"); +import("Sql_lib"); import("system.vars"); import("system.result"); +//!LibFunction +var cond = newWhere(null, newSelect("ACTIVITYLINK.OBJECT_ROWID").from("ACTIVITYLINK") + .join("ACTIVITY", newWhere("ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID") + .and("ACTIVITYLINK.OBJECT_TYPE", ContextUtils.getCurrentContextId())) + .where(vars.get("$local.condition")), SqlBuilder.EXISTS()); -var from = "ACTIVITYLINK join ACTIVITY on ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID and ACTIVITYLINK.OBJECT_TYPE = 'Contract'"; - -result.string("CONTRACTID in (select ACTIVITYLINK.OBJECT_ROWID from " + from + " where " + vars.get("$local.condition")+ ")"); \ No newline at end of file +result.string(cond.toString()); \ No newline at end of file diff --git a/entity/DocumentTemplate_entity/DocumentTemplate_entity.aod b/entity/DocumentTemplate_entity/DocumentTemplate_entity.aod index 9cf1d9cca301bb4240acea90684327824bbd201d..dbb9e49a3b635be85e5615422520d9f08d387aac 100644 --- a/entity/DocumentTemplate_entity/DocumentTemplate_entity.aod +++ b/entity/DocumentTemplate_entity/DocumentTemplate_entity.aod @@ -321,6 +321,7 @@ <entityConsumer> <name>DocumentTemplatePlaceOfUse</name> <stateProcess>%aditoprj%/entity/DocumentTemplate_entity/entityfields/documenttemplateplaceofuse/stateProcess.js</stateProcess> + <onValidation>%aditoprj%/entity/DocumentTemplate_entity/entityfields/documenttemplateplaceofuse/onValidation.js</onValidation> <dependency> <name>dependency</name> <entityName>DocumentTemplatePlaceOfUse_entity</entityName> diff --git a/entity/DocumentTemplate_entity/entityfields/documenttemplateplaceofuse/onValidation.js b/entity/DocumentTemplate_entity/entityfields/documenttemplateplaceofuse/onValidation.js new file mode 100644 index 0000000000000000000000000000000000000000..a40be7eb7d8e21b088a3cf4683b41849239e35ee --- /dev/null +++ b/entity/DocumentTemplate_entity/entityfields/documenttemplateplaceofuse/onValidation.js @@ -0,0 +1,14 @@ +import("system.translate"); +import("system.result"); +import("system.vars"); +import("Entity_lib"); + +var usages = EntityConsumerRowsHelper.getCurrentConsumerRows("DocumentTemplatePlaceOfUse", ["PLACEOFUSE"]); +var hasMarketingWorkflowUsage = usages.some(function (usage) +{ + return usage["PLACEOFUSE"] == "MarketingWorkflowLauncher"; +}); +if (hasMarketingWorkflowUsage && !vars.get("$field.Content").includes("{@workflowActionLink@}")) +{ + result.string(translate.text("The template must contain the placeholder for the worklow-link to use it with the marketing workflow")); +} diff --git a/entity/Document_entity/Document_entity.aod b/entity/Document_entity/Document_entity.aod index 420157a37135f2b6b3fd1105810584e32ac6935e..cba9173b17cbedf17fc79b500cd69af232cb8c10 100644 --- a/entity/Document_entity/Document_entity.aod +++ b/entity/Document_entity/Document_entity.aod @@ -144,6 +144,26 @@ <entityProvider> <name>Documents</name> <recordContainer>jdito</recordContainer> + <children> + <entityParameter> + <name>AssignmentName_param</name> + <valueProcess>%aditoprj%/entity/Document_entity/entityfields/documents/children/assignmentname_param/valueProcess.js</valueProcess> + <expose v="true" /> + <documentation>%aditoprj%/entity/Document_entity/entityfields/documents/children/assignmentname_param/documentation.adoc</documentation> + </entityParameter> + <entityParameter> + <name>AssignmentRowId_param</name> + <expose v="true" /> + </entityParameter> + <entityParameter> + <name>AssignmentTable_param</name> + <expose v="true" /> + </entityParameter> + <entityParameter> + <name>Keyword_param</name> + <expose v="true" /> + </entityParameter> + </children> <dependencies> <entityDependency> <name>1eae1907-53ea-4d6f-bcf1-772052365020</name> @@ -225,7 +245,7 @@ </entityDependency> <entityDependency> <name>2e6fcf27-ee98-4f7d-a99d-7ce02774076b</name> - <entityName>UserhelpResources</entityName> + <entityName>UserhelpResources_entity</entityName> <fieldName>Documents</fieldName> <isConsumer v="false" /> </entityDependency> @@ -242,12 +262,23 @@ <isConsumer v="false" /> </entityDependency> </dependencies> + </entityProvider> + <entityProvider> + <name>MainDocuments</name> + <recordContainer>jdito</recordContainer> <children> + <entityParameter> + <name>Keyword_param</name> + <valueProcess>%aditoprj%/entity/Document_entity/entityfields/maindocuments/children/keyword_param/valueProcess.js</valueProcess> + <expose v="true" /> + <mandatory v="true" /> + <description>TODO: expose auf false. aktuell wird der Code nicht ausgeführt, wenn Expose false ist.</description> + </entityParameter> <entityParameter> <name>AssignmentName_param</name> - <valueProcess>%aditoprj%/entity/Document_entity/entityfields/documents/children/assignmentname_param/valueProcess.js</valueProcess> + <valueProcess>%aditoprj%/entity/Document_entity/entityfields/maindocuments/children/assignmentname_param/valueProcess.js</valueProcess> <expose v="true" /> - <documentation>%aditoprj%/entity/Document_entity/entityfields/documents/children/assignmentname_param/documentation.adoc</documentation> + <documentation>%aditoprj%/entity/Document_entity/entityfields/maindocuments/children/assignmentname_param/documentation.adoc</documentation> </entityParameter> <entityParameter> <name>AssignmentRowId_param</name> @@ -258,14 +289,10 @@ <expose v="true" /> </entityParameter> <entityParameter> - <name>Keyword_param</name> - <expose v="true" /> + <name>DisallowCreate_param</name> + <expose v="false" /> </entityParameter> </children> - </entityProvider> - <entityProvider> - <name>MainDocuments</name> - <recordContainer>jdito</recordContainer> <dependencies> <entityDependency> <name>87d738a5-5d5e-425e-b013-007371475a38</name> @@ -310,33 +337,6 @@ <isConsumer v="false" /> </entityDependency> </dependencies> - <children> - <entityParameter> - <name>Keyword_param</name> - <valueProcess>%aditoprj%/entity/Document_entity/entityfields/maindocuments/children/keyword_param/valueProcess.js</valueProcess> - <expose v="true" /> - <mandatory v="true" /> - <description>TODO: expose auf false. aktuell wird der Code nicht ausgeführt, wenn Expose false ist.</description> - </entityParameter> - <entityParameter> - <name>AssignmentName_param</name> - <valueProcess>%aditoprj%/entity/Document_entity/entityfields/maindocuments/children/assignmentname_param/valueProcess.js</valueProcess> - <expose v="true" /> - <documentation>%aditoprj%/entity/Document_entity/entityfields/maindocuments/children/assignmentname_param/documentation.adoc</documentation> - </entityParameter> - <entityParameter> - <name>AssignmentRowId_param</name> - <expose v="true" /> - </entityParameter> - <entityParameter> - <name>AssignmentTable_param</name> - <expose v="true" /> - </entityParameter> - <entityParameter> - <name>DisallowCreate_param</name> - <expose v="false" /> - </entityParameter> - </children> </entityProvider> <entityParameter> <name>DisallowCreate_param</name> @@ -346,14 +346,6 @@ <entityProvider> <name>SingleDocument</name> <titlePlural>Document</titlePlural> - <dependencies> - <entityDependency> - <name>91f87622-d0e8-43c6-99a0-5f9cebf79aaf</name> - <entityName>SerialLetter_entity</entityName> - <fieldName>Documents</fieldName> - <isConsumer v="false" /> - </entityDependency> - </dependencies> <children> <entityParameter> <name>AssignmentName_param</name> @@ -365,6 +357,14 @@ <expose v="true" /> </entityParameter> </children> + <dependencies> + <entityDependency> + <name>91f87622-d0e8-43c6-99a0-5f9cebf79aaf</name> + <entityName>SerialLetter_entity</entityName> + <fieldName>Documents</fieldName> + <isConsumer v="false" /> + </entityDependency> + </dependencies> </entityProvider> <entityProvider> <name>#PROVIDER_AGGREGATES</name> diff --git a/entity/Forecast_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js b/entity/Forecast_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js index 33554680cccd2c3d363443686457c41e0c1c5729..856c1bb3cfff78abcc06bc817a49a40757e3529f 100644 --- a/entity/Forecast_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js +++ b/entity/Forecast_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js @@ -1,4 +1,4 @@ import("system.result"); import("Context_lib"); -result.string(ContextUtils.getNameSubselectSql("OBJECT_TYPE", "OBJECT_ROWID")) \ No newline at end of file +result.string(ContextUtils.getNameSubselectSql("FORECAST.OBJECT_TYPE", "FORECAST.OBJECT_ROWID")) \ No newline at end of file diff --git a/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js b/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js index 9bac722a3fa50b14fe0fd7fcf9cb92ebd8e49fba..b9a588dfe867d2a870ad80b9eb25ef5803ddfa4b 100644 --- a/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js +++ b/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js @@ -1,7 +1,7 @@ +import("Sql_lib"); import("Context_lib"); import("system.result"); -// TODO: is prepared possible? -result.string("case when PERSON_ID is null then '" + ContextUtils.getContextName("Organisation") - + "' when CONTACT.ORGANISATION_ID is not null and CONTACT.PERSON_ID is not null then '" + ContextUtils.getContextName("Person") - + "' else '' end"); \ No newline at end of file +var sql = SqlBuilder.caseWhen("PERSON_ID is null").thenString(ContextUtils.getContextName("Organisation")) + .when(newWhere("CONTACT.ORGANISATION_ID is not null").and("CONTACT.PERSON_ID is not null")).thenString(ContextUtils.getContextName("Person")); +result.string(sql.toString()); \ No newline at end of file diff --git a/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod b/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod index 40b9b39c8993d2b421f368b11fca27d80abb24f5..791b08d72b2e85a807d11a6c47284056ae16a977 100644 --- a/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod +++ b/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod @@ -14,7 +14,7 @@ </entityProvider> <entityField> <name>DOCUMENTTEMPLATE_ID</name> - <title>Document template</title> + <title>Document Template</title> <consumer>EmailTemplates</consumer> <mandatory v="true" /> <state>EDITABLE</state> @@ -80,6 +80,7 @@ <recordContainers> <datalessRecordContainer> <name>dataLess</name> + <alias>Data_alias</alias> </datalessRecordContainer> </recordContainers> </entity> diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js index b81df3d4fb93fc9608febd7783247052a61d4acd..cea637a710a0e3e0903248241654aec944c88137 100644 --- a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js +++ b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js @@ -2,6 +2,7 @@ import("system.vars"); import("system.result"); var variables = { - documentTemplate: vars.get("$field.DOCUMENTTEMPLATE_ID") + documentTemplateId: vars.get("$field.DOCUMENTTEMPLATE_ID"), + originUrl: vars.get("$sys.origin") }; result.string(JSON.stringify(variables)); \ No newline at end of file diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js index 6a28aafa528aa4130e913b642f80e04cfadc8b19..cca5f0e8d7ce5b6b8bb2ad60f3ffb068c4c6f1a1 100644 --- a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js +++ b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js @@ -1,13 +1,17 @@ import("Util_lib"); import("system.vars"); import("system.result"); +import("FilterViewAction_lib"); var context = vars.get("$param.ObjectType_param"); -var targets = Utils.parseJSON(vars.get("$param.ObjectIds_param")) || []; -targets = targets.map(function (targetId) +var targets = Utils.parseJSON(vars.get("$param.ObjectIds_param")); +var filter = Utils.parseJSON(vars.get("$param.ObjectFilter_param")); + +targets = FilterViewActionUtils.getUidsBySelectionOrFilter(context, targets, filter).map(function (targetId) { if (Utils.isString(targetId)) return [targetId, context]; //todo: context dynamic (eg for participants) return targetId; }); + result.string(JSON.stringify(targets)); \ No newline at end of file diff --git a/entity/Member_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js b/entity/Member_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js index 000d055cfacc970e2ca0dc70689b4c793e0bc0cd..a5d62617bee8630b78204e4bc85c851dba3b10df 100644 --- a/entity/Member_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js +++ b/entity/Member_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js @@ -5,6 +5,6 @@ import("Context_lib"); //TODO: refactor: //whenever we want to shrink data for a single object it's not needed to resolve the objects name where we're from if (vars.get("$param.ObjectType_param") == null) - result.string(ContextUtils.getNameSubselectSql("OBJECT_TYPE", "OBJECT_ROWID")); + result.string(ContextUtils.getNameSubselectSql("OBJECTMEMBER.OBJECT_TYPE", "OBJECTMEMBER.OBJECT_ROWID")); else result.string("'OBJECT_ROWID.displayValue not loaded'"); \ No newline at end of file diff --git a/entity/Notification_entity/Notification_entity.aod b/entity/Notification_entity/Notification_entity.aod index 8dead6bc118e4d353c6c708976a037b3ace5c45e..cf3203213ac627ef13ec8064010448a7db4a5970 100644 --- a/entity/Notification_entity/Notification_entity.aod +++ b/entity/Notification_entity/Notification_entity.aod @@ -175,8 +175,7 @@ <dbRecordContainer> <name>db</name> <alias>_____SYSTEMALIAS</alias> - <maximumDbRows v="200" /> - <isPageable v="false" /> + <isPageable v="true" /> <fromClauseProcess>%aditoprj%/entity/Notification_entity/recordcontainers/db/fromClauseProcess.js</fromClauseProcess> <conditionProcess>%aditoprj%/entity/Notification_entity/recordcontainers/db/conditionProcess.js</conditionProcess> <orderClauseProcess>%aditoprj%/entity/Notification_entity/recordcontainers/db/orderClauseProcess.js</orderClauseProcess> diff --git a/entity/Offer_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js b/entity/Offer_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js index 9a3d04480545203f0da83c3f6be762e684c8883a..dd188aaf77933759617acc567c9f1ba0cb1313dc 100644 --- a/entity/Offer_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js +++ b/entity/Offer_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js @@ -1,6 +1,11 @@ +import("Context_lib"); +import("Sql_lib"); import("system.vars"); import("system.result"); +//!LibFunction +var cond = newWhere(null, newSelect("ACTIVITYLINK.OBJECT_ROWID").from("ACTIVITYLINK") + .join("ACTIVITY", newWhere("ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID") + .and("ACTIVITYLINK.OBJECT_TYPE", ContextUtils.getCurrentContextId())) + .where(vars.get("$local.condition")), SqlBuilder.EXISTS()); -var from = "ACTIVITYLINK join ACTIVITY on ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID and ACTIVITYLINK.OBJECT_TYPE = 'Offer'"; - -result.string("OFFERID in (select ACTIVITYLINK.OBJECT_ROWID from " + from + " where " + vars.get("$local.condition")+ ")"); \ No newline at end of file +result.string(cond.toString()); \ No newline at end of file diff --git a/entity/Offer_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js b/entity/Offer_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js index 33554680cccd2c3d363443686457c41e0c1c5729..c0332af5cb599a99d062e3828f354ebfd005273f 100644 --- a/entity/Offer_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js +++ b/entity/Offer_entity/recordcontainers/db/recordfieldmappings/object_rowid.displayvalue/expression.js @@ -1,4 +1,4 @@ import("system.result"); import("Context_lib"); -result.string(ContextUtils.getNameSubselectSql("OBJECT_TYPE", "OBJECT_ROWID")) \ No newline at end of file +result.string(ContextUtils.getNameSubselectSql("OFFER.OBJECT_TYPE", "OFFER.OBJECT_ROWID")) \ No newline at end of file diff --git a/entity/Offeritem_entity/entityfields/product_id/onValueChange.js b/entity/Offeritem_entity/entityfields/product_id/onValueChange.js index 3a5de6feaba1a19a9d36f5ed067305250b098734..8ff2c784424efb6750081f6cbbb1aaaeaae7faab 100644 --- a/entity/Offeritem_entity/entityfields/product_id/onValueChange.js +++ b/entity/Offeritem_entity/entityfields/product_id/onValueChange.js @@ -21,7 +21,7 @@ if(pid != "") var productInfoSubSql = newSelect("DESCRIPTION") .from("DESCRIPTIONTRANSLATION") .whereIfSet("DESCRIPTIONTRANSLATION.OBJECT_ROWID", "$local.value") - .and("DESCRIPTIONTRANSLATION.OBJECT_TYPE = 'Product'") + .and("DESCRIPTIONTRANSLATION.OBJECT_TYPE", "Product") .andIfSet("DESCRIPTIONTRANSLATION.LANG", "$param.Language_param") .toString(); var ProductDetails = ProductUtils.getProductDetails(pid, PriceListFilter, diff --git a/entity/Order_entity/recordcontainers/db/recordfieldmappings/offer_id.displayvalue/expression.js b/entity/Order_entity/recordcontainers/db/recordfieldmappings/offer_id.displayvalue/expression.js index a86ac585f271d61227c89ec425d97d7c43e2a73d..2aec63a8d1bbd3bd15e9522ccb53fa52f74f7623 100644 --- a/entity/Order_entity/recordcontainers/db/recordfieldmappings/offer_id.displayvalue/expression.js +++ b/entity/Order_entity/recordcontainers/db/recordfieldmappings/offer_id.displayvalue/expression.js @@ -1,4 +1,5 @@ import("system.result"); import("Context_lib"); +import("system.db"); -result.string(ContextUtils.getNameSubselectSql("'Offer'", "SALESORDER.OFFER_ID")); \ No newline at end of file +result.string(db.translateStatement(ContextUtils.getNameSql("Offer", "SALESORDER.OFFER_ID"))); \ No newline at end of file diff --git a/entity/Organisation_entity/Organisation_entity.aod b/entity/Organisation_entity/Organisation_entity.aod index 4d5db6ed1a8789383791d9793b7c5791ae8f30a6..50afcd2e32295cc01c67e21a154d33520e99a7ce 100644 --- a/entity/Organisation_entity/Organisation_entity.aod +++ b/entity/Organisation_entity/Organisation_entity.aod @@ -812,6 +812,10 @@ <name>LinkedObjectId_param</name> <valueProcess>%aditoprj%/entity/Organisation_entity/entityfields/linkedappointments/children/linkedobjectid_param/valueProcess.js</valueProcess> </entityParameter> + <entityParameter> + <name>ErrorOnPermissionDenied</name> + <valueProcess>%aditoprj%/entity/Organisation_entity/entityfields/linkedappointments/children/erroronpermissiondenied/valueProcess.js</valueProcess> + </entityParameter> </children> </entityConsumer> <entityConsumer> @@ -955,6 +959,13 @@ <tooltip>Export fields of this table</tooltip> <tooltipProcess>%aditoprj%/entity/Organisation_entity/entityfields/filterviewactiongroup/children/export/tooltipProcess.js</tooltipProcess> </entityActionField> + <entityActionField> + <name>startMarketingWorkflows</name> + <title>Start marketing mailing</title> + <onActionProcess>%aditoprj%/entity/Organisation_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js</onActionProcess> + <isObjectAction v="false" /> + <iconId>VAADIN:ENVELOPES</iconId> + </entityActionField> </children> </entityActionGroup> <entityActionField> diff --git a/entity/Organisation_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js b/entity/Organisation_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..2b04867cc90fd72a300747605800b32664d4b5b4 --- /dev/null +++ b/entity/Organisation_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js @@ -0,0 +1,9 @@ +import("Context_lib"); +import("system.vars"); +import("system.neon"); + +neon.openContext("MarketingWorkflowLauncher", "MarketingWorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, { + "ObjectIds_param": JSON.stringify(vars.get("$sys.selection")), + "ObjectFilter_param": JSON.stringify(vars.get("$sys.filter")), + "ObjectType_param": ContextUtils.getCurrentContextId() +}); \ No newline at end of file diff --git a/entity/Organisation_entity/entityfields/linkedappointments/children/erroronpermissiondenied/valueProcess.js b/entity/Organisation_entity/entityfields/linkedappointments/children/erroronpermissiondenied/valueProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..15b1f8d0322593145f40d707c61dfdfd9babf0fe --- /dev/null +++ b/entity/Organisation_entity/entityfields/linkedappointments/children/erroronpermissiondenied/valueProcess.js @@ -0,0 +1,3 @@ +import("system.result"); + +result.string("false"); \ No newline at end of file diff --git a/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationgroup_filter/groupQueryProcess.js b/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationgroup_filter/groupQueryProcess.js index 768e6ca7501cdd94caba44242bd5d9f1b3c76859..aad0c1782f7ca0b380aa12d11d4855978b9d3648 100644 --- a/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationgroup_filter/groupQueryProcess.js +++ b/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationgroup_filter/groupQueryProcess.js @@ -13,7 +13,8 @@ var name = vars.get("$local.name"); var stmt = newSelect(isCount ? groupedColumns : columns) .from("ORGANISATION") .join("CONTACT", "ORGANISATIONID = ORGANISATION_ID and PERSON_ID is null") - .leftJoin("CLASSIFICATIONSTORAGE", "CLASSIFICATIONSTORAGE.OBJECT_ROWID = CONTACT.CONTACTID and OBJECT_TYPE = 'Organisation'") + .leftJoin("CLASSIFICATIONSTORAGE", newWhere("CLASSIFICATIONSTORAGE.OBJECT_ROWID = CONTACT.CONTACTID") + .and("CLASSIFICATIONSTORAGE.OBJECT_TYPE", "Organisation")) if (condition) { diff --git a/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js b/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js index ccf8f498ce2171f22150fbf2c26e89f495ba169b..a4e9edc5b2c7f90da86619beb5d4d968bb0a392b 100644 --- a/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js +++ b/entity/Organisation_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js @@ -11,15 +11,18 @@ var groupedColumns = vars.get("$local.groupedlist") // The coloumns, used for gr var order = vars.get("$local.order"); // The order of the result var classificationId = vars.get("$local.name"); classificationId = classificationId.slice(classificationId.lastIndexOf(".") + 1, classificationId.length); -var valuefield = "''" -var stmt = ""; -stmt = newSelect(isCount ? "1" : columns) +var sql = newSelect(isCount ? "1" : columns) .from("ORGANISATION") .join("CONTACT", "ORGANISATIONID = ORGANISATION_ID and PERSON_ID is null") - .leftJoin("CLASSIFICATION", "CLASSIFICATION.OBJECT_ROWID = CONTACT.CONTACTID and OBJECT_TYPE = 'Organisation' and CLASSIFICATION.CLASSIFICATIONTYPE_ID = '" + classificationId + "' ") - .leftJoin("CLASSIFICATIONSCORE", "CLASSIFICATIONSCOREID = CLASSIFICATION.CLASSIFICATIONSCORE_ID " + (condition != " " ? " WHERE " + condition : "")) - .groupBy(groupedColumns + (order != null && !isCount ? " ORDER BY " + order : "")) - .toString(); + .leftJoin("CLASSIFICATION", newWhere("CLASSIFICATION.OBJECT_ROWID = CONTACT.CONTACTID") + .and("CLASSIFICATION.OBJECT_TYPE", "Organisation") + .and("CLASSIFICATION.CLASSIFICATIONTYPE_ID", classificationId)) + .leftJoin("CLASSIFICATIONSCORE", "CLASSIFICATIONSCOREID = CLASSIFICATION.CLASSIFICATIONSCORE_ID") + .whereIfSet(condition.trim()) + .groupBy(groupedColumns); -result.string(stmt); \ No newline at end of file +if (order != null && !isCount) + sql.orderBy(order); + +result.string(sql.toString()); \ No newline at end of file diff --git a/entity/PermissionOverview_entity/recordcontainers/jdito/contentProcess.js b/entity/PermissionOverview_entity/recordcontainers/jdito/contentProcess.js index 0a21aef128bcefe95904d2fbed4bfd44cf0bccc8..293144a2513456337e2e290106ec4020e21269a3 100644 --- a/entity/PermissionOverview_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/PermissionOverview_entity/recordcontainers/jdito/contentProcess.js @@ -74,7 +74,7 @@ for each (var entry in rolesOrEntities) { // entry contains either a role or an .select("ASYS_PERMISSIONSETID") .from("ASYS_PERMISSIONSET") .where("ASYS_PERMISSIONSET.ASYS_PERMISSIONSET_ID", entityPermSetId) - .and("ACCESSTYPE = 'R'") + .and("ASYS_PERMISSIONSET.ACCESSTYPE", "R") .arrayColumn(); currOverview = [entityPermSetId, entry, "VAADIN:CLOSE", "VAADIN:CLOSE", "VAADIN:CLOSE", "VAADIN:CLOSE", "VAADIN:CLOSE"]; diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod index c66ce949329c5b9e71486cb5802b41b0b2244ddf..42f436e7093dbe2303fabd9df2a098fc792ca049 100644 --- a/entity/Person_entity/Person_entity.aod +++ b/entity/Person_entity/Person_entity.aod @@ -884,6 +884,10 @@ <name>LinkedObjectId_param</name> <valueProcess>%aditoprj%/entity/Person_entity/entityfields/appointments/children/linkedobjectid_param/valueProcess.js</valueProcess> </entityParameter> + <entityParameter> + <name>ErrorOnPermissionDenied</name> + <valueProcess>%aditoprj%/entity/Person_entity/entityfields/appointments/children/erroronpermissiondenied/valueProcess.js</valueProcess> + </entityParameter> </children> </entityConsumer> <entityField> @@ -1099,9 +1103,10 @@ </entityActionField> <entityActionField> <name>startMarketingWorkflows</name> - <title>Marketing Workflow</title> + <title>Start marketing mailing</title> <onActionProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js</onActionProcess> <isObjectAction v="false" /> + <iconId>VAADIN:ENVELOPES</iconId> </entityActionField> </children> </entityActionGroup> diff --git a/entity/Person_entity/entityfields/appointments/children/erroronpermissiondenied/valueProcess.js b/entity/Person_entity/entityfields/appointments/children/erroronpermissiondenied/valueProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..15b1f8d0322593145f40d707c61dfdfd9babf0fe --- /dev/null +++ b/entity/Person_entity/entityfields/appointments/children/erroronpermissiondenied/valueProcess.js @@ -0,0 +1,3 @@ +import("system.result"); + +result.string("false"); \ No newline at end of file diff --git a/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js b/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js index 3e462ab4498eb4215bac2daa8457aee59ae8cd2a..2b04867cc90fd72a300747605800b32664d4b5b4 100644 --- a/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js +++ b/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js @@ -4,5 +4,6 @@ import("system.neon"); neon.openContext("MarketingWorkflowLauncher", "MarketingWorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, { "ObjectIds_param": JSON.stringify(vars.get("$sys.selection")), + "ObjectFilter_param": JSON.stringify(vars.get("$sys.filter")), "ObjectType_param": ContextUtils.getCurrentContextId() }); \ No newline at end of file diff --git a/entity/Product_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js b/entity/Product_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js index b8141bc3b760b0439c6a4e6e07c99b38dda33d54..dd188aaf77933759617acc567c9f1ba0cb1313dc 100644 --- a/entity/Product_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js +++ b/entity/Product_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js @@ -1,6 +1,11 @@ +import("Context_lib"); +import("Sql_lib"); import("system.vars"); import("system.result"); +//!LibFunction +var cond = newWhere(null, newSelect("ACTIVITYLINK.OBJECT_ROWID").from("ACTIVITYLINK") + .join("ACTIVITY", newWhere("ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID") + .and("ACTIVITYLINK.OBJECT_TYPE", ContextUtils.getCurrentContextId())) + .where(vars.get("$local.condition")), SqlBuilder.EXISTS()); -var from = "ACTIVITYLINK join ACTIVITY on ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID and ACTIVITYLINK.OBJECT_TYPE = 'Product'"; - -result.string("PRODUCTID in (select ACTIVITYLINK.OBJECT_ROWID from " + from + " where " + vars.get("$local.condition")+ ")"); \ No newline at end of file +result.string(cond.toString()); \ No newline at end of file diff --git a/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js b/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js index 95781d32513a9442d468d93568947555bfcdef3d..2f3dad2864f82b5ebd688e2ffea700eec78eaa78 100644 --- a/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/SalesprojectConversionRate_entity/recordcontainers/jdito/contentProcess.js @@ -37,7 +37,13 @@ if (filter != null) })).length > 0 })[0]; phasenFilter.operator = "OR"; - let pre = newSelect("PRE.KEYID").from("AB_KEYWORD_ENTRY").join("AB_KEYWORD_ENTRY", "AB_KEYWORD_ENTRY.SORTING -1 = PRE.SORTING", "PRE").where("AB_KEYWORD_ENTRY.CONTAINER", $KeywordRegistry.salesprojectPhase()).and("PRE.CONTAINER = '" + $KeywordRegistry.salesprojectPhase() + "'").and("AB_KEYWORD_ENTRY.KEYID", phasenFilter.childs[0].value).cell() + let pre = newSelect("PRE.KEYID") + .from("AB_KEYWORD_ENTRY") + .join("AB_KEYWORD_ENTRY", "AB_KEYWORD_ENTRY.SORTING -1 = PRE.SORTING", "PRE") + .where("AB_KEYWORD_ENTRY.CONTAINER", $KeywordRegistry.salesprojectPhase()) + .and(["AB_KEYWORD_ENTRY", "CONTAINER", "PRE"], $KeywordRegistry.salesprojectPhase()) + .and("AB_KEYWORD_ENTRY.KEYID", phasenFilter.childs[0].value) + .cell() if (pre != "") { let temp = JSON.parse(JSON.stringify(phasenFilter.childs[0])); temp.value = temp.key = pre; diff --git a/entity/Salesproject_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js b/entity/Salesproject_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js index 524e35692ad0f51d4bebd9dce80d82ebfc6efc80..cf3462e69ddf08a90ec5e2a230b1c0d8bcdd3856 100644 --- a/entity/Salesproject_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js +++ b/entity/Salesproject_entity/recordcontainers/db/filterextensions/classificationtype_filter/groupQueryProcess.js @@ -10,13 +10,17 @@ var groupedColumns = vars.get("$local.groupedlist") // The coloumns, used for gr var order = vars.get("$local.order"); // The order of the result var classificationId = vars.get("$local.name"); classificationId = classificationId.slice(classificationId.lastIndexOf(".") + 1, classificationId.length); -var valuefield = "''" -var stmt = ""; -stmt = newSelect(isCount ? "1" : columns) - .from("SALESPROJECT") - .leftJoin("CLASSIFICATION", "CLASSIFICATION.OBJECT_ROWID = SALESPROJECT.SALESPROJECTID and CLASSIFICATION.OBJECT_TYPE = 'Salesproject' and CLASSIFICATION.CLASSIFICATIONTYPE_ID = '" + classificationId + "' ") - .leftJoin("CLASSIFICATIONSCORE", "CLASSIFICATIONSCORE.CLASSIFICATIONSCOREID = CLASSIFICATION.CLASSIFICATIONSCORE_ID" + (condition != " " ? " WHERE " + condition : "")) - .groupBy(groupedColumns + (order != null && !isCount ? " ORDER BY " + order : "")) - .toString(); -result.string(stmt); \ No newline at end of file +var sql = newSelect(isCount ? "1" : columns) + .from("SALESPROJECT") + .leftJoin("CLASSIFICATION", newWhere("CLASSIFICATION.OBJECT_ROWID = SALESPROJECT.SALESPROJECTID") + .and("CLASSIFICATION.OBJECT_TYPE", "Salesproject") + .and("CLASSIFICATION.CLASSIFICATIONTYPE_ID", classificationId)) + .leftJoin("CLASSIFICATIONSCORE", "CLASSIFICATIONSCORE.CLASSIFICATIONSCOREID = CLASSIFICATION.CLASSIFICATIONSCORE_ID") + .whereIfSet(condition.trim()) + .groupBy(groupedColumns); + +if (order != null && !isCount) + sql.orderBy(order); + +result.string(sql.toString()); \ No newline at end of file diff --git a/entity/Salesproject_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js b/entity/Salesproject_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js index 3a8b1fd9f8491be342a16fd7967c756ef82b0e21..dd188aaf77933759617acc567c9f1ba0cb1313dc 100644 --- a/entity/Salesproject_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js +++ b/entity/Salesproject_entity/recordcontainers/db/recordfieldmappings/activities/filterConditionProcess.js @@ -1,6 +1,11 @@ +import("Context_lib"); +import("Sql_lib"); import("system.vars"); import("system.result"); +//!LibFunction +var cond = newWhere(null, newSelect("ACTIVITYLINK.OBJECT_ROWID").from("ACTIVITYLINK") + .join("ACTIVITY", newWhere("ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID") + .and("ACTIVITYLINK.OBJECT_TYPE", ContextUtils.getCurrentContextId())) + .where(vars.get("$local.condition")), SqlBuilder.EXISTS()); -var from = "ACTIVITYLINK join ACTIVITY on ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID and ACTIVITYLINK.OBJECT_TYPE = 'Salesproject'"; - -result.string("SALESPROJECTID in (select ACTIVITYLINK.OBJECT_ROWID from " + from + " where " + vars.get("$local.condition")+ ")"); \ No newline at end of file +result.string(cond.toString()); \ No newline at end of file diff --git a/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js b/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js index bd20eceda69bc4ed288c1090ba77ee4918831b57..fd0e3bd7a6f2c7518d54d02f9351a842f3d25d9b 100644 --- a/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js @@ -27,8 +27,8 @@ import("system.translate"); */ -var turnoverCategory = translate.text('Turnover'); -var forecastCategory = translate.text('Forecast'); +var turnoverCategory = translate.text("Turnover"); +var forecastCategory = translate.text("Forecast"); var maxYear = parseInt(vars.get("$param.MaxYear_param")); var yearCountToShow = parseInt(vars.get("$param.YearCountToShow_param")); diff --git a/entity/UserhelpResources/UserhelpResources.aod b/entity/UserhelpResources_entity/UserhelpResources_entity.aod similarity index 70% rename from entity/UserhelpResources/UserhelpResources.aod rename to entity/UserhelpResources_entity/UserhelpResources_entity.aod index 7775d3fd5a4ba8d43ec112062c7772b437bd68c9..32f253d41162e3e5c8b4e33f1bcba45bdc803965 100644 --- a/entity/UserhelpResources/UserhelpResources.aod +++ b/entity/UserhelpResources_entity/UserhelpResources_entity.aod @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.17" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.17"> - <name>UserhelpResources</name> + <name>UserhelpResources_entity</name> <majorModelMode>DISTRIBUTED</majorModelMode> - <documentation>%aditoprj%/entity/UserhelpResources/documentation.adoc</documentation> + <documentation>%aditoprj%/entity/UserhelpResources_entity/documentation.adoc</documentation> <entityFields> <entityProvider> <name>#PROVIDER</name> @@ -12,21 +12,21 @@ </entityField> <entityConsumer> <name>Documents</name> - <dependency> - <name>dependency</name> - <entityName>Document_entity</entityName> - <fieldName>Documents</fieldName> - </dependency> <children> <entityParameter> <name>AssignmentTable_param</name> - <valueProcess>%aditoprj%/entity/UserhelpResources/entityfields/documents/children/assignmenttable_param/valueProcess.js</valueProcess> + <valueProcess>%aditoprj%/entity/UserhelpResources_entity/entityfields/documents/children/assignmenttable_param/valueProcess.js</valueProcess> </entityParameter> <entityParameter> <name>AssignmentRowId_param</name> - <valueProcess>%aditoprj%/entity/UserhelpResources/entityfields/documents/children/assignmentrowid_param/valueProcess.js</valueProcess> + <valueProcess>%aditoprj%/entity/UserhelpResources_entity/entityfields/documents/children/assignmentrowid_param/valueProcess.js</valueProcess> </entityParameter> </children> + <dependency> + <name>dependency</name> + <entityName>Document_entity</entityName> + <fieldName>Documents</fieldName> + </dependency> </entityConsumer> <entityProvider> <name>#PROVIDER_AGGREGATES</name> diff --git a/entity/UserhelpResources/documentation.adoc b/entity/UserhelpResources_entity/documentation.adoc similarity index 100% rename from entity/UserhelpResources/documentation.adoc rename to entity/UserhelpResources_entity/documentation.adoc diff --git a/entity/UserhelpResources/entityfields/documents/children/assignmentrowid_param/valueProcess.js b/entity/UserhelpResources_entity/entityfields/documents/children/assignmentrowid_param/valueProcess.js similarity index 100% rename from entity/UserhelpResources/entityfields/documents/children/assignmentrowid_param/valueProcess.js rename to entity/UserhelpResources_entity/entityfields/documents/children/assignmentrowid_param/valueProcess.js diff --git a/entity/UserhelpResources/entityfields/documents/children/assignmenttable_param/valueProcess.js b/entity/UserhelpResources_entity/entityfields/documents/children/assignmenttable_param/valueProcess.js similarity index 100% rename from entity/UserhelpResources/entityfields/documents/children/assignmenttable_param/valueProcess.js rename to entity/UserhelpResources_entity/entityfields/documents/children/assignmenttable_param/valueProcess.js diff --git a/entity/VisitPlanEntry_entity/recordcontainers/jdito/contentProcess.js b/entity/VisitPlanEntry_entity/recordcontainers/jdito/contentProcess.js index ce8bb62314fa0a0ae0023f81b31d95a3871bd812..ae8d3918edde1c772c1f09bb3623506cce40cdc1 100644 --- a/entity/VisitPlanEntry_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/VisitPlanEntry_entity/recordcontainers/jdito/contentProcess.js @@ -46,19 +46,19 @@ if(entryData.length > 0) { for(var i = 0; i < entryData.length; i++) { - var entryDateRaw, visitPlanEntryId, beginn_time, end_time, organisationContact_id, contact_id, status, visitplanemployeeweek_id, appointmentid; - [entryDateRaw, visitPlanEntryId, beginn_time, end_time, organisationContact_id, contact_id, status, visitplanemployeeweek_id, appointmentid] = entryData[i] + var entryDateRaw, visitPlanEntryId, beginTime, endTime, organisationContactId, contactId, status, visitplanEmployeeWeekId, appointmentid; + [entryDateRaw, visitPlanEntryId, beginTime, endTime, organisationContactId, contactId, status, visitplanEmployeeWeekId, appointmentid] = entryData[i] - var contactname = db.cell(PersUtils.getResolvingDisplaySubSql("'" + contact_id + "'")); - var orgname = OrganisationUtils.getNameByContactId(organisationContact_id); + var contactname = ContactUtils.getTitleByContactId(contactId); + var orgname = OrganisationUtils.getNameByContactId(organisationContactId); var parentName = translate.text(datetime.toDate(entryDateRaw, "EEEE")); entryDate = datetime.toDate(entryDateRaw, "dd.MM.yyyy"); var statusDisplay = KeywordUtils.getViewValue($KeywordRegistry.visitPlanEntryStatus(), status) var alias = SqlUtils.getSystemAlias(); - items.push([visitPlanEntryId, false, parentName + "#" + entryDate, "", beginn_time - , end_time, organisationContact_id, orgname, contact_id, contactname, entryDateRaw, status, visitplanemployeeweek_id, appointmentid, statusDisplay]); + items.push([visitPlanEntryId, false, parentName + "#" + entryDate, "", beginTime + , endTime, organisationContactId, orgname, contactId, contactname, entryDateRaw, status, visitplanEmployeeWeekId, appointmentid, statusDisplay]); if(!vars.get("$local.idvalues")) { diff --git a/entity/VisitRecommendation_entity/recordcontainers/jdito/contentProcess.js b/entity/VisitRecommendation_entity/recordcontainers/jdito/contentProcess.js index 7effd511c0a20b96a072e8df4ba4e7650ede81c9..42fecc4e3d198603e333edf0c71beed523ff615a 100644 --- a/entity/VisitRecommendation_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/VisitRecommendation_entity/recordcontainers/jdito/contentProcess.js @@ -271,7 +271,7 @@ function _getPrioByDueDateSubSql (pDueDateField, pPriorityField) { var currentDate = datetime.date(); var sqlMasker = new SqlMaskingUtils(); - + //!SqlBuilder var subSql = "case when " + pDueDateField + " < ? then '" + $KeywordRegistry.visitRecommendationPriority$critical() + "' when " + pDueDateField + " < ? then '" + $KeywordRegistry.visitRecommendationPriority$veryHigh() + "' when " + pDueDateField + " < ? then '" + $KeywordRegistry.visitRecommendationPriority$high() diff --git a/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod b/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod index f1640dc1aacfcbb6ebd9de2ce5afb3d6ca8b92c9..e5749fe5101007e83c45d26c9f24bd15561458b1 100644 --- a/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod +++ b/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod @@ -88,6 +88,7 @@ <recordContainers> <datalessRecordContainer> <name>dataLess</name> + <alias>Data_alias</alias> </datalessRecordContainer> </recordContainers> </entity> diff --git a/entity/WorkflowTask_entity/afterSave.js b/entity/WorkflowTask_entity/afterSave.js index 68fae8b0d2432769e1c21ae7d594d02fd20cdb87..61b54c53434b45f42ffd7184e88c153966cfac5c 100644 --- a/entity/WorkflowTask_entity/afterSave.js +++ b/entity/WorkflowTask_entity/afterSave.js @@ -30,9 +30,9 @@ if (entityData["FORMRESULT"]) else { var params = { - "TaskTitle_param" : rowData["NAME.value"] + "TaskTitle_param": entityData["NAME"] }; //if you try to open the task now, it will display "Task done" - neon.openContext("WorkflowTask", "WorkflowTaskPreview_view", [rowData["UID.value"]], neon.OPERATINGSTATE_VIEW, params); + neon.openContext("WorkflowTask", "WorkflowTaskPreview_view", [entityData["UID"]], neon.OPERATINGSTATE_VIEW, params); } } \ No newline at end of file diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod index bee7fd6513ec22226a7dec19b5ee03fd0a3c2cdf..3439544cfe83b426af1216d5545709508f9cdf3e 100644 --- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod +++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod @@ -7293,6 +7293,9 @@ <entry> <key>Standard Zip</key> </entry> + <entry> + <key>Outstanding Amount</key> + </entry> </keyValueMap> <font name="Dialog" style="0" size="11" /> <sqlModels> diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod index b3d003710b7d14ec99d63e66bbfcee469231a149..5ae81ef6a8a2856d375b73be7156726e401553e4 100644 --- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod +++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod @@ -2795,6 +2795,10 @@ <key>new</key> <value>neu</value> </entry> + <entry> + <key>Start marketing mailing</key> + <value>Marketing Mailing starten</value> + </entry> <entry> <key>Adviser</key> <value>Berater</value> @@ -6548,7 +6552,7 @@ </entry> <entry> <key>Order number</key> - <value>Belegsnummer</value> + <value>Belegnummer</value> </entry> <entry> <key>Permission Action</key> @@ -6568,7 +6572,7 @@ </entry> <entry> <key>Print reminder</key> - <value>Mahnung drucken</value> + <value>Mahnung anzeigen</value> </entry> <entry> <key>Rech.-Betrag</key> @@ -6576,7 +6580,7 @@ </entry> <entry> <key>Order date</key> - <value>Belegsdatum</value> + <value>Belegdatum</value> </entry> <entry> <key>Due date</key> @@ -6628,7 +6632,7 @@ </entry> <entry> <key>This error should never appear - contact administrator (PermissionDetail_entity.PermissionAction.onValidation).</key> - <value>Dieser Fehler sollte nie erscheinen - kontaktieren sie einen Administrator (PermissionDetail_entity.PermissionAction.onValidation).</value> + <value>Dieser Fehler sollte nie erscheinen - kontaktieren Sie einen Administrator (PermissionDetail_entity.PermissionAction.onValidation).</value> </entry> <entry> <key>Empty actions are invalid!</key> @@ -9270,7 +9274,7 @@ Bitte Datumseingabe prüfen</value> </entry> <entry> <key>Child Attributes</key> - <value>Untergeordnete Eigenschaften</value> + <value>Diagrameigenschaften</value> </entry> <entry> <key>Recalculate all Classifications</key> @@ -9430,16 +9434,16 @@ Bitte Datumseingabe prüfen</value> </value> </entry> <entry> - <key>LinkedIn (Person)</key> - <value>LinkedIn (Person)</value> + <key>Linked in (Person)</key> + <value>Linked In (Person)</value> </entry> <entry> <key>Mobile number (Organisation)</key> <value>Handynummer (Organisation)</value> </entry> <entry> - <key>LinkedIn (Organisation)</key> - <value>LinkedIn (Organisation)</value> + <key>Linked in (Organisation)</key> + <value>Linked In (Organisation)</value> </entry> <entry> <key>Xing (Organisation)</key> @@ -9674,6 +9678,10 @@ Bitte Datumseingabe prüfen</value> <key>Standard Zip</key> <value>Standart Plz</value> </entry> + <entry> + <key>Outstanding Amount</key> + <value>Offener Betrag</value> + </entry> <entry> <key>#rememberme</key> <value>Angemeldet bleiben</value> diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod index 5cdb447d6f2e8ede8872d869542c99486b40818c..193aaea85b4963c84362c964b8e24578e77c0212 100644 --- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod +++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod @@ -7374,6 +7374,9 @@ <entry> <key>Standard Zip</key> </entry> + <entry> + <key>Outstanding Amount</key> + </entry> <entry> <key>#rememberme</key> <value>Stay logged in</value> diff --git a/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod b/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod index bad0c03850983d94a74b3d3af4896308fb1e2086..e200a8a70f878ecb8c691752d3585cf3880e5bef 100644 --- a/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod +++ b/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.1"> <name>MarketingWorkflowLauncher</name> - <title>f</title> + <title>Marketing workflow</title> <majorModelMode>DISTRIBUTED</majorModelMode> <entity>MarketingWorkflowLauncher_entity</entity> <references> diff --git a/neonContext/Userhelp/Userhelp.aod b/neonContext/Userhelp/Userhelp.aod index 435de68c2c1e230ca426a074593bb1004a7ebf6d..057b38dda494f9366cb2e2f617314104f8fd2dd3 100644 --- a/neonContext/Userhelp/Userhelp.aod +++ b/neonContext/Userhelp/Userhelp.aod @@ -3,7 +3,7 @@ <name>Userhelp</name> <majorModelMode>DISTRIBUTED</majorModelMode> <filterView>Userhelp_FilterView</filterView> - <entity>UserhelpResources</entity> + <entity>UserhelpResources_entity</entity> <references> <neonViewReference> <name>2a1dd62b-0f30-442b-aa1d-969b46312d2a</name> diff --git a/neonView/SalesprojectAnalyses_view/SalesprojectAnalyses_view.aod b/neonView/SalesprojectAnalyses_view/SalesprojectAnalyses_view.aod index 1228d3cc49bdac80030aec42937bcdb4fc9c643a..67c3c7369040ce1004d8d223db8fa989e450cef7 100644 --- a/neonView/SalesprojectAnalyses_view/SalesprojectAnalyses_view.aod +++ b/neonView/SalesprojectAnalyses_view/SalesprojectAnalyses_view.aod @@ -8,7 +8,7 @@ <name>SalesprojectPhases</name> <title>Salesproject phases</title> <description>Shows how many sales projects are in the various sales phases</description> - <fragment>Salesproject/filter?search=eyJ0eXBlIjoiZ3JvdXAiLCJvcGVyYXRvciI6IkFORCIsImNoaWxkcyI6W3sidHlwZSI6InJvdyIsIm5hbWUiOiJQSEFTRSIsIm9wZXJhdG9yIjoiTk9UX0VRVUFMIiwidmFsdWUiOiJOZWdvdGlhdGlvbiIsImtleSI6IlNBTFBST0pQSEFTRU5FR08iLCJjb250ZW50dHlwZSI6IlRFWFQifV19&axes=COUNT&grouping=%23EXTENSION.Phase_filterExtention.Phase_filterExtention%23TEXT</fragment> + <fragment>Salesproject/filter?search=eyJ0eXBlIjoiZ3JvdXAiLCJvcGVyYXRvciI6IkFORCIsImNoaWxkcyI6W3sidHlwZSI6InJvdyIsIm5hbWUiOiJQSEFTRSIsIm9wZXJhdG9yIjoiTk9UX0VRVUFMIiwidmFsdWUiOiJOZWdvdGlhdGlvbiIsImtleSI6IlNBTFBST0pQSEFTRU5FR08iLCJjb250ZW50dHlwZSI6IlRFWFQifSx7InR5cGUiOiJyb3ciLCJuYW1lIjoiU1RBVFVTIiwib3BlcmF0b3IiOiJFUVVBTCIsInZhbHVlIjoiT2ZmZW4iLCJrZXkiOiJTQUxQUk9KU1RBVE9QRU4iLCJjb250ZW50dHlwZSI6IlRFWFQifV19&axes=COUNT&grouping=%23EXTENSION.Phase_filterExtention.Phase_filterExtention%23TEXT</fragment> <singleton v="true" /> <storeRoles> <element>PROJECT_FieldStaff</element> diff --git a/process/Calendar_lib/process.js b/process/Calendar_lib/process.js index 0a9a4b99e7c0c1abbe9d41af4f6ca2b2a734cab1..e9f96a4a9089f1ff65bb69dfb21ff41063f90ab8 100644 --- a/process/Calendar_lib/process.js +++ b/process/Calendar_lib/process.js @@ -538,4 +538,113 @@ CalendarUtil.getCalendarSystemType = function(pScope) // Everything is none return calendars.BACKEND_NONE; +} + +CalendarUtil.buildEntriesFromUids = function(appointmentUids) +{ + var entryArray = new Array(appointmentUids.length); + + for(var i = 0; i < appointmentUids.length; i++) + { + var hasPermission = true; + + if(vars.get("$param.ErrorOnPermissionDenied") == "false" || vars.getString("$param.LinkedAppointmentsFromDashlet_param")) + hasPermission = hasUserPermissionForReadingEntry(getEntryOwnerCn(appointmentUids[i])); + + if(hasPermission) + entryArray[i] = CalendarUtil.buildEntry(calendars.getEntry(appointmentUids[i], null, null), null); + } + + //filter out all null + var filteredEntryArray = entryArray.filter(function (el) { + return el != null; + }); + + return filteredEntryArray; +} + + +CalendarUtil.countEntriesFromUids = function(appointmentUids) +{ + return CalendarUtil.buildEntriesFromUids(appointmentUids).length; +} + +CalendarUtil.buildEntry = function (pEntry, pMasterentry) +{ + var uid = pEntry[calendars.ID]; + var summary = pEntry[calendars.SUMMARY]; + var attendees = pEntry[calendars.AFFECTEDUSERS]; + var startdate = pEntry[calendars.DTSTART]; + var enddate = pEntry[calendars.DTEND]; + var links = pEntry[calendars.LINKS]; + var description = pEntry[calendars.DESCRIPTION]; + if(pEntry[calendars.ORGANIZER2] != undefined) + var organizer = pEntry[calendars.ORGANIZER2]["paramvalue"]; + if(pEntry[calendars.USER2] != undefined) + var owner = JSON.stringify(pEntry[calendars.USER2]); + var status = pEntry[calendars.STATUS]; + var location = pEntry[calendars.LOCATION]; + var reminder = pEntry[calendars.REMINDER_DURATION]; + var remindercheck = pEntry[calendars.HASREMINDER] + var classification = pEntry[calendars.CLASSIFICATION]; + var transparency = pEntry[calendars.TRANSPARENCY]; + var categories = pEntry[calendars.CATEGORIES]; + var isAllDay = pEntry["X-ADITO-ISALLDAYEVENT"] != null ? pEntry["X-ADITO-ISALLDAYEVENT"] : "FALSE"; + + var masterBegin = pMasterentry != null ? pMasterentry[calendars.DTSTART] : null + var masterEnd = pMasterentry != null ? pMasterentry[calendars.DTEND] : null + + // Recurrence + var recurrenceID = pEntry[calendars.RECURRENCEID]; + var rrule = null; + if (pMasterentry != null) { // Entry is a recurrence exception, therefore get rrule from master + rrule = pMasterentry[calendars.RRULE] != null ? pMasterentry[calendars.RRULE][0] : null; + } else { + rrule = pEntry[calendars.RRULE] != null ? pEntry[calendars.RRULE][0] : null; + } + + return [ + uid, + attendees.length, + startdate, + enddate, + summary, + organizer, + owner, + attendees, + status, + description, + location, + '', + isAllDay, + classification, + transparency, + categories, + reminder, + remindercheck, + rrule, + recurrenceID, + null, + masterBegin, + masterEnd, + null + ]; +} + + +function hasUserPermissionForReadingEntry(calUserCn) +{ + return calendars.hasPermission(calUserCn, calendars.VEVENT, "READ"); +} + +function getEntryOwnerCn(appointmentUid) +{ + + var owner = newSelect("ASYS_CALENDARBACKEND.OWNER", "_____SYSTEMALIAS") + .from("ASYS_CALENDARBACKEND") + .whereIfSet("ASYS_CALENDARBACKEND.ELEMENTUID", appointmentUid) + .cell(true); + + var ownerArr = text.decodeMS(owner); + return ownerArr[1].split(":")[1]; } \ No newline at end of file diff --git a/process/Contact_lib/process.js b/process/Contact_lib/process.js index 627ec11b149a9b0ef93163901dda95b23f7f98b9..4d53dde63a7f80b5e864330f7aec39f0d3f405ee 100644 --- a/process/Contact_lib/process.js +++ b/process/Contact_lib/process.js @@ -528,7 +528,7 @@ ContactUtils.getActiveCommRestrictionsSubselect = function() .and(newWhere() .or("COMMRESTRICTION.CONTACT_ID = CONTACT.CONTACTID") .or("COMMRESTRICTION.CONTACT_ID", orgContactSubselect)); - + //!SqlBuilder parts.push("case when exists(" + subquery.toString() + ") then '" + pMedium[1] + "' else '' end"); }) @@ -661,7 +661,7 @@ function ContactTitleRenderer(pContact, pOptions) var maskingUtil = new SqlMaskingUtils(); var res = maskingUtil.concat([this.contact.salutation, this.contact.title, this.contact.firstname, this.contact.middlename, this.contact.lastname].filter(function (e){ return e != ""; - }), " "); + }), " ", false); //binary AND check for possibility to check serveral options if (this._options & ContactTitleRenderer.OPTIONS.IncludeOrganisation && this.contact.organisationName) res = maskingUtil.concat([res, this.contact.organisationName], " | "); diff --git a/process/Context_lib/process.js b/process/Context_lib/process.js index 31d608284325922fc657f5e9388ee3782d68e8eb..a9b9eac3121960b68e3d6a4cf4d740fa3aa21457 100644 --- a/process/Context_lib/process.js +++ b/process/Context_lib/process.js @@ -494,10 +494,14 @@ ContextSelector.prototype.setGroupBy = function(pValue) ContextUtils.getSelectMap = function() { var maskingUtils = new SqlMaskingUtils(); + var isOracle = maskingUtils.dbType == db.DBTYPE_ORACLE10_CLUSTER + || maskingUtils.dbType == db.DBTYPE_ORACLE10_OCI + || maskingUtils.dbType == db.DBTYPE_ORACLE10_THIN; + return { "Organisation": ContextSelector.create("ORGANISATION", "CONTACT.CONTACTID", "ORGANISATION.NAME") .setJoinExpression("join CONTACT on ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID and CONTACT.PERSON_ID is null") - .setCondition(newWhere("ORGANISATION.ORGANISATIONID != '0'")) + .setCondition(newWhere("ORGANISATION.ORGANISATIONID", "0", SqlBuilder.NOT_EQUAL())) .setSubContexts({ "Person": [newSelect("CONTACTID").from("CONTACT").where("PERSON_ID is not null"), "CONTACT.ORGANISATION_ID", ["Offer", "Order", "Contract", "SupportTicket"]] }) @@ -536,31 +540,31 @@ ContextUtils.getSelectMap = function() .setStateField("STATUS") .setActiveStates([$KeywordRegistry.salesprojectState$open(), $KeywordRegistry.salesprojectState$postponed()]) ,"Contract": ContextSelector.create("CONTRACT", "CONTRACTID") - .setTitleExpression(maskingUtils.concat([ + .setTitleExpression(maskingUtils.cast(maskingUtils.concat([ KeywordUtils.getResolvedTitleSqlPart("ContractType", "CONTRACTTYPE"), maskingUtils.cast("CONTRACTCODE", SQLTYPES.VARCHAR, 10) - ], " ")) + ], " "), isOracle ? SQLTYPES.NVARCHAR : SQLTYPES.VARCHAR, 50)) .setContactIdField("CONTACT_ID") .setCreationDateField("CONTRACTSTART") .setStateField("CONTRACTSTATUS") .setActiveStates([$KeywordRegistry.contractState$validLimited(), $KeywordRegistry.contractState$validUnlimited(), $KeywordRegistry.contractState$notSigned()]) ,"Offer": ContextSelector.create("OFFER", "OFFERID") - .setTitleExpression(maskingUtils.concat([ + .setTitleExpression(maskingUtils.cast(maskingUtils.concat([ "'" + translate.text("Offer") + "'", "' '", maskingUtils.cast("OFFERCODE", SQLTYPES.VARCHAR, 10), "'-'", maskingUtils.cast("VERSNR", SQLTYPES.VARCHAR, 10) - ], "", false)) + ], "", false), isOracle ? SQLTYPES.NVARCHAR : SQLTYPES.VARCHAR, 50)) .setContactIdField("CONTACT_ID") .setCreationDateField("OFFERDATE") .setStateField("STATUS") .setActiveStates([$KeywordRegistry.offerStatus$open(), $KeywordRegistry.offerStatus$checked(), $KeywordRegistry.offerStatus$sent()]) ,"Order": ContextSelector.create("SALESORDER", "SALESORDERID") - .setTitleExpression(maskingUtils.concat([ + .setTitleExpression(maskingUtils.cast(maskingUtils.concat([ KeywordUtils.getResolvedTitleSqlPart("OrderType", "ORDERTYPE"), maskingUtils.cast("SALESORDERCODE", SQLTYPES.VARCHAR, 10) - ], " ")) + ], " "), isOracle ? SQLTYPES.NVARCHAR : SQLTYPES.VARCHAR, 50)) .setContactIdField("CONTACT_ID") .setCreationDateField("SALESORDERDATE") .setStateField("ORDERSTATUS") @@ -607,20 +611,19 @@ ContextUtils.getSelectMap = function() */ ContextUtils.getNameSubselectSql = function(pContextIdDbField, pRowIdDbField) { - // TODO: prepared? - - var select = "(case " + pContextIdDbField + " "; + var select = SqlBuilder.caseStatement() - var selectMap = ContextUtils.getSelectMap () + var selectMap = ContextUtils.getSelectMap(); for (let contextId in selectMap) { - select += "when '" + contextId + "' then (select " + selectMap[contextId].titleExpression + " from " + selectMap[contextId].getFullFromClause() + (pRowIdDbField ? " where " + selectMap[contextId].getFullIdField() + " = " + pRowIdDbField : " ") + ") "; + let titleSelect = newSelect(selectMap[contextId].titleExpression) + .from(selectMap[contextId].getFullFromClause()) + .where(selectMap[contextId].getFullIdField() + " = " + pRowIdDbField); + + select.when(pContextIdDbField, contextId).then(titleSelect); } - select += "else 'Not defined in ContextUtils.getNameSql()!'"; - select += "end)"; - - return select; + return select.toString(); } /** diff --git a/process/FilterViewAction_lib/process.js b/process/FilterViewAction_lib/process.js index b0fa04291d03107498b6eaf03adbe5aa17326186..afd89d4d6d45e7afbd01146356a20eadd053896f 100644 --- a/process/FilterViewAction_lib/process.js +++ b/process/FilterViewAction_lib/process.js @@ -40,7 +40,7 @@ FilterViewActionUtils.getUidsByEntityFilter = function (pContext, pFilter) { return new SqlBuilder() .selectDistinct("CONTACT.CONTACTID") - .from("PERSON") + .from("ORGANISATION") .join("CONTACT", newWhere("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID").and("CONTACT.PERSON_ID is null")) .leftJoin("ADDRESS", "ADDRESS.ADDRESSID = CONTACT.ADDRESS_ID") .leftJoin("CLASSIFICATIONSTORAGE", "CLASSIFICATIONSTORAGE.OBJECT_ROWID = CONTACT.CONTACTID") @@ -52,7 +52,10 @@ FilterViewActionUtils.getUidsByEntityFilter = function (pContext, pFilter) var loadRowsConfig = entities.createConfigForLoadingRows() .entity(ContextUtils.getEntity(pContext)) .fields(["#UID"]) - .filter(JSON.stringify(pFilter.filter || pFilter)); + if (pFilter.filter) + loadRowsConfig.filter(JSON.stringify(pFilter.filter)); + else if (pFilter) + loadRowsConfig.filter(JSON.stringify(pFilter)); return entities.getRows(loadRowsConfig).map(function (row) { diff --git a/process/KeywordAttribute_test/KeywordAttribute_test.aod b/process/KeywordAttribute_test/KeywordAttribute_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..5956980e85aba58177a5e931c819b50b4894f796 --- /dev/null +++ b/process/KeywordAttribute_test/KeywordAttribute_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>KeywordAttribute_test</name> + <title>[TEST] KeywordAttribute_lib</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/KeywordAttribute_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/KeywordAttribute_test/process.js b/process/KeywordAttribute_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..888e3a79bc304ec2fca6ccce31ec19b6cf546955 --- /dev/null +++ b/process/KeywordAttribute_test/process.js @@ -0,0 +1,144 @@ +import("system.result"); +import("system.translate"); +import("system.vars"); +import("Keyword_lib"); +import("UnitTest_lib"); +import("Sql_lib"); + + +var constructor = new TestSuite("KeywordAttribute.constructor", [ + new Test("should throw error if no data is found and no default value is defined", + function(pTester) { + var exception = new Error(translate.withArguments("no keyword attribute \"%0\" found in keyword container \"%1\"", ["contacts", "AddressType"])); + pTester.expectThat(function() { + new KeywordAttribute("AddressType", "contacts"); + }).throwsException(exception).assert(); + } + ), + + new Test("should not throw error if no data is found but default value is defined", + function(pTester) { + pTester.expectThat(function() { + new KeywordAttribute("AddressType", "contact", "testDefault"); + }).not().throwsException().assert(); + } + ), +]); + + +var getValue = new TestSuite("KeywordAttribute.getValue", [ + new Test("should throw error if attribute does not exist in container and no default value is defined", + function(pTester) { + var exception = new Error(translate.withArguments("no keyword attribute \"%0\" found in keyword container \"%1\"", ["asdf", "AddressType"])); + + pTester.expectThat(function() { + var ka = new KeywordAttribute("AddressType", "asdf"); + ka.getValue("abc"); + }).throwsException(exception).assert(); + } + ), + + new Test("should throw error if attribute is not assigned to keyword and no default value is defined", + function(pTester) { + var exception = new Error(translate.withArguments("no keyword attribute \"%0\" found in keyword \"%1\" from container \"%2\"", ["contact", "abc", "AddressType"])); + + pTester.expectThat(function() { + var ka = new KeywordAttribute("AddressType", "contact"); + ka.getValue("abc"); + }).throwsException(exception).assert(); + } + ), + + new Test("should return default value if defined but attribute does not exist in container", + function(pTester) { + var ka = new KeywordAttribute("AddressType", "asdf", "testDefault"); + var actualValue = ka.getValue("HOMEADDR"); + + pTester.expectThat(actualValue).equals("testDefault").assert(); + } + ), + + new Test("should return default value if defined and attribute exists in container but is not assigned to keyword", + function(pTester) { + var ka = new KeywordAttribute("AddressType", "contact", "testDefault"); + var actualValue = ka.getValue("abc"); + + pTester.expectThat(actualValue).equals("testDefault").assert(); + } + ), + + new Test("should return keywords boolean value (actually a number)", + function(pTester) { + var ka = new KeywordAttribute("AddressType", "organisation"); + var actualValue = ka.getValue("HOMEADDR"); + + pTester.expectThat(actualValue).isNumeric().assert(); + pTester.expectThat(actualValue).equals("0").assert(); + } + ), + + new Test("should return keywords number value (actually a string)", + function(pTester) { + var ka = new KeywordAttribute("PaymentTerm", "dayNumber"); + var actualValue = ka.getValue("PAYTERM30"); + + pTester.expectThat(actualValue).isNumeric().assert(); + pTester.expectThat(actualValue).isString().assert(); + pTester.expectThat(actualValue).equals("30.00").assert(); + } + ), + + new Test("should return keywords char value (string)", + function(pTester) { + var ka = new KeywordAttribute("TaskStatus", "icon"); + var actualValue = ka.getValue("ASSIGNED"); + + pTester.expectThat(actualValue).isString().assert(); + pTester.expectThat(actualValue).equals("NEON:STATUS_ASSIGNED").assert(); + } + ), + + new Test("should return keywords long char value (string)", + function(pTester) { + var ka = new KeywordAttribute("TicketType", "attributes"); + var actualValue = ka.getValue("SUPPORTTICKET"); + + pTester.expectThat(actualValue).isString().assert(); + pTester.expectThat(actualValue).equals('["ff8b1caf-cf30-4edb-b5ca-a9a219ba8399"]').assert(); + } + ), +]); + + +var getSqlBuilderSelect = new TestSuite("KeywordAttribute.getSqlBuilderSelect", [ + new Test("should return a SqlBuilder instance", + function(pTester) { + var ka = new KeywordAttribute("MemberRole", "Intern"); + /** @type {SqlBuilder} */ + var actualValue = ka.getSqlBuilderSelect(); + + var expectQueryResult = [ + "039fd6ae-b4ad-431e-86bf-59ed2f4df0a9", + "8cb1b843-713a-4193-aa50-9f5ca06820f8", + "9c421b0b-8529-4e07-9463-28d59fd027b6", + "b72294cd-3a46-4f71-ab93-72824f63f7f4", + "f78f229f-f809-4bd2-aca8-24e2f82fa220", + ]; + var actualQueryResult = actualValue.orderBy("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID").arrayColumn(); + + pTester.expectThat(actualValue).isInstanceOf("SqlBuilder").assert(); + pTester.expectThat(actualQueryResult).equals(expectQueryResult).assert(); + } + ), +]); + + +var tester = new Tester("Test KeywordAttribute_lib"); +tester.initCoverage(KeywordAttribute); +tester.test(constructor); +tester.test(getValue); +tester.test(getSqlBuilderSelect); + +tester.summary(); + +result.object(tester.getResults()); diff --git a/process/Keyword_lib/process.js b/process/Keyword_lib/process.js index ea1736e5c13412a67527ebff0a4ab5d4bdae0293..994fd55c07d07fda603f24db728838663dd844f2 100644 --- a/process/Keyword_lib/process.js +++ b/process/Keyword_lib/process.js @@ -107,6 +107,7 @@ KeywordUtils.getContainerNames = function() //do not cache this list since // a) the list can easly change when a new container is created // b) where this is called it's not relevant in terms of performance + //!SqlBuilder var list = db.array(db.COLUMN, "select distinct AB_KEYWORD_ENTRY.CONTAINER from AB_KEYWORD_ENTRY order by AB_KEYWORD_ENTRY.CONTAINER asc"); return list; }; diff --git a/process/Keyword_test/Keyword_test.aod b/process/Keyword_test/Keyword_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..e654f56663b71ec5ed3e6241aa1be9bd76dc1d87 --- /dev/null +++ b/process/Keyword_test/Keyword_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>Keyword_test</name> + <title>[TEST] Keyword_lib</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/Keyword_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/Keyword_test/process.js b/process/Keyword_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..d1b1d910e9dfd985b8c089830f410b21f0151c25 --- /dev/null +++ b/process/Keyword_test/process.js @@ -0,0 +1,143 @@ +import("system.result"); +import("system.translate"); +import("system.vars"); +import("Keyword_lib"); +import("UnitTest_lib"); + +//this test will not work currently +//TODO: renable and fix the tests + +//var getContainerNames = new TestSuite("KeywordUtils.getContainerNames", [ +// new Test("should return an alphabetically ascending ordered list of all keyword containers", +// function(pTester) { +// var actualValue = KeywordUtils.getContainerNames(); +// +// pTester.expectThat(actualValue).isArray().assert(); +// pTester.expectThat(actualValue).hasMinLength(1).assert(); +// pTester.expectThat(actualValue).elementAt(0).equals("ActivityCategory").assert(); +// pTester.expectThat(actualValue).elementAt(-1).equals("YesNo").assert(); +// } +// ) +//]); +// +// +//var getCategoryNameById = new TestSuite("KeywordUtils.getCategoryNameById", [ +// new Test("should return existing keyword category name for correct uuid", +// function(pTester) { +// var actualValue = KeywordUtils.getCategoryNameById("a55654b1-6a19-4d0c-b08d-cfbc12b5f7b0"); +// +// pTester.expectThat(actualValue).equals("MemberRole").assert(); +// } +// ), +// +// new Test("should return non-existing keyword category name for wrong uuid", +// function(pTester) { +// var actualValue = KeywordUtils.getCategoryNameById("a55654b1-6a19-4d0c-b08d-cfbc12b5f7b1"); +// +// pTester.expectThat(actualValue).equals("<unknown>").assert(); +// } +// ), +// +// new Test("should return non-existing keyword category name for missing uuid", +// function(pTester) { +// var actualValue = KeywordUtils.getCategoryNameById(); +// +// pTester.expectThat(actualValue).equals("<unknown>").assert(); +// } +// ), +//]); +// +// +//var getCategoryIdByName = new TestSuite("KeywordUtils.getCategoryIdByName", [ +// new Test("should return existing keyword uuid for correct category name", +// function(pTester) { +// var actualValue = KeywordUtils.getCategoryIdByName("MemberRole"); +// +// pTester.expectThat(actualValue).equals("a55654b1-6a19-4d0c-b08d-cfbc12b5f7b0").assert(); +// } +// ), +// +// new Test("should throw exception for wrong keyword category name", +// function(pTester) { +// var exception = new Error(translate.withArguments("no keyword category \"%0\" found", ["AddressTypes"])); +// pTester.expectThat(function() { +// KeywordUtils.getCategoryIdByName("AddressTypes"); +// }).throwsException(exception).assert(); +// } +// ), +// +// new Test("should throw exception for missing keyword category name", +// function(pTester) { +// var exception = new Error(translate.withArguments("no keyword category \"%0\" found", [""])); +// pTester.expectThat(function() { +// KeywordUtils.getCategoryIdByName(); +// }).throwsException(exception).assert(); +// } +// ), +//]); +// +// +//var getEntryNamesAndIdsByContainer = new TestSuite("KeywordUtils.getEntryNamesAndIdsByContainer", [ +// new Test("should return an array of all keywords and their ID's for given container", +// function(pTester) { +// var actualValue = KeywordUtils.getEntryNamesAndIdsByContainer("ActivityDirection"); +// +// pTester.expectThat(actualValue).isArray().assert(); +// pTester.expectThat(actualValue).hasMinLength(1, {name: "array"}).assert(); +// pTester.expectThat(actualValue).elementAt(0).isArray().assert(); +// pTester.expectThat(actualValue).elementAt(0).hasLength(2).assert(); +// } +// ), +// +// new Test("should return an empty array for non-existent container", +// function(pTester) { +// var actualValue = KeywordUtils.getEntryNamesAndIdsByContainer("Asdf"); +// +// pTester.expectThat(actualValue).isArray().assert(); +// pTester.expectThat(actualValue).hasLength(0, {name: "array"}).assert(); +// } +// ), +//]); +// +// +//var exists = new TestSuite("KeywordUtils.exists", [ +// new Test("should return a boolean indicating that a known keyword in a known container exists", +// function(pTester) { +// var actualValue = KeywordUtils.exists("VISIT", "ActivityCategory"); +// +// pTester.expectThat(actualValue).isBoolean().assert(); +// pTester.expectThat(actualValue).equals(true, "known keyword exists in known container").assert(); +// } +// ), +// +// new Test("should return a boolean indicating that an unknown keyword in a known container does not exist", +// function(pTester) { +// var actualValue = KeywordUtils.exists("ASDF", "ActivityCategory"); +// +// pTester.expectThat(actualValue).isBoolean().assert(); +// pTester.expectThat(actualValue).equals(false, "unknown keyword does not exist in known container").assert(); +// } +// ), +// +// new Test("should return a boolean indicating that a known keyword in an unknown container does not exist", +// function(pTester) { +// var actualValue = KeywordUtils.exists("VISIT", "Asdf"); +// +// pTester.expectThat(actualValue).isBoolean().assert(); +// pTester.expectThat(actualValue).equals(false, "known keyword does not exist in unknown container").assert(); +// } +// ), +//]); +// +// +//var tester = new Tester("Test Keyword_lib"); +//tester.initCoverage(KeywordUtils); +//tester.test(getContainerNames); +//tester.test(getCategoryNameById); +//tester.test(getCategoryIdByName); +//tester.test(getEntryNamesAndIdsByContainer); +//tester.test(exists); +// +//tester.summary(); +// +//result.object(tester.getResults()); \ No newline at end of file diff --git a/process/Leadimport_lib/process.js b/process/Leadimport_lib/process.js index ea0f5c14c0b084b0ecca76fceee7841a1b247a04..de9d13b2c7bb525960c5503b3e20eb28d9f2190d 100644 --- a/process/Leadimport_lib/process.js +++ b/process/Leadimport_lib/process.js @@ -794,7 +794,7 @@ LeadImportUtils.getLeadAttr = function(pImportDefID) .from("AB_ATTRIBUTERELATION") .join("AB_ATTRIBUTEUSAGE", "AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID") .where("AB_ATTRIBUTERELATION.OBJECT_ROWID", pImportDefID) - .and("AB_ATTRIBUTERELATION.OBJECT_TYPE = 'Leadimport'") + .and("AB_ATTRIBUTERELATION.OBJECT_TYPE", "Leadimport") .table() }; } diff --git a/process/ObjectRelation_lib/process.js b/process/ObjectRelation_lib/process.js index 93063469bb275bf252eac8485933805cea091570..c99e2322413f0dda7eb287c8dfd033f048066895 100644 --- a/process/ObjectRelation_lib/process.js +++ b/process/ObjectRelation_lib/process.js @@ -37,6 +37,7 @@ ObjectRelationUtils.getPossibleRelationTypes = function(pObjectTypes, pFullInfo, // only id and title: if (pFullInfo) { + //!SqlBuilder fields = fields.concat([ "main.RELATION_TYPE", "case when type2.AB_OBJECTRELATIONTYPEID is null then 'same' \n\ diff --git a/process/Offer_lib/process.js b/process/Offer_lib/process.js index 7c9504fa26da75fa05ae7753f287070f922dd250..f5a8cd0138d503694a5e0e0a52b21bb277eb156c 100644 --- a/process/Offer_lib/process.js +++ b/process/Offer_lib/process.js @@ -502,7 +502,7 @@ OfferItemUtils.prototype.insertPartsList = function(pProductId, pAssignedTo, pCu "( " + newSelect("DESCRIPTION") .from("DESCRIPTIONTRANSLATION") .where("DESCRIPTIONTRANSLATION.OBJECT_ROWID = PRODUCT.PRODUCTID") - .and("DESCRIPTIONTRANSLATION.OBJECT_TYPE = 'Product'") + .and("DESCRIPTIONTRANSLATION.OBJECT_TYPE", "Product") .and("DESCRIPTIONTRANSLATION.LANG", pLanguage) .toString() + ")"]]]]); diff --git a/process/Order_lib/process.js b/process/Order_lib/process.js index d6938458c59687ef679f1d437661ec456e01f2e8..bcb1b8428693ab99e51713ecb61a1b44fc6a4857 100644 --- a/process/Order_lib/process.js +++ b/process/Order_lib/process.js @@ -545,7 +545,8 @@ OrderUtils.buildReminderReport = function (pOrderID) "Ordernumber": translate.text("Order number",language), "Orderdate": translate.text("Order date",language), "Orderamount": translate.text("Order amount",language), - "Dunninglevel": translate.text("Dunning level",language) + "Dunninglevel": translate.text("Dunning level",language), + "OutstandingAmount": translate.text("Outstanding Amount",language) }; diff --git a/process/SendEmail_workflowService/process.js b/process/SendEmail_workflowService/process.js index 6ccbfe3e76006ca51544b503453320d416d35951..14247ad4e4b3dda3ab4be65989fa896e1434a894 100644 --- a/process/SendEmail_workflowService/process.js +++ b/process/SendEmail_workflowService/process.js @@ -10,19 +10,24 @@ import("Workflow_lib"); var processInstanceId = vars.get("$local.uid"); var variables = JSON.parse(vars.get("$local.value")); -var recipientContactId = variables.recipientContactId; +var recipientContactId = variables.recipientContactId || variables.targetId; var documentTemplateId = variables.documentTemplateId; var senderName = variables.senderName; var mailSubject = variables.mailSubject; +var aditoUrl = variables.originUrl; var actionParams = Utils.clone(variables); actionParams.processInstanceId = processInstanceId; -var linkPlaceholder = new Placeholder("workflowActionLink", Placeholder.types.CALLBACKFUNCTION, function () +var additionalPlaceholders = []; +if (aditoUrl) { - return WorkflowLinkActions.getActionLink("https://localhost:8443", actionParams.linkActionType, actionParams.redirectLink, actionParams); -}); + additionalPlaceholders.push(linkPlaceholder = new Placeholder("workflowActionLink", Placeholder.types.CALLBACKFUNCTION, function () + { + return WorkflowLinkActions.getActionLink(aditoUrl, actionParams.linkActionType, actionParams.redirectLink, actionParams); + })); +} -var email = Email.fromTemplate(documentTemplateId, recipientContactId, null, [linkPlaceholder]); +var email = Email.fromTemplate(documentTemplateId, recipientContactId, null, additionalPlaceholders); email.subject = mailSubject; email.toRecipients = [CommUtil.getStandardMail(recipientContactId)]; diff --git a/process/SqlBuilder_test/SqlBuilder_test.aod b/process/SqlBuilder_test/SqlBuilder_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..3992282911646839e2344fc4154d6a0a30666daf --- /dev/null +++ b/process/SqlBuilder_test/SqlBuilder_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>SqlBuilder_test</name> + <title>[TEST] Sql_lib - SqlBuilder</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/SqlBuilder_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/SqlBuilder_test/process.js b/process/SqlBuilder_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..3ec9ec86ddb15cafc04a2bed81a81e28afc3cf79 --- /dev/null +++ b/process/SqlBuilder_test/process.js @@ -0,0 +1,1266 @@ +import("system.db"); +import("system.result"); +import("system.vars"); +import("system.translate"); +import("system.logging"); +import("system.SQLTYPES"); +import("Sql_lib"); +import("UnitTest_lib"); + +//SqlBuilder-tests: +var newSelectTests = new TestSuite("SqlLib.newSelect", [ + new Test("newSelect with just a string should just use it as select", + function(pTester) + { + var actualValue = newSelect("MySuper, Field, String") + + pTester.expectThat(actualValue).elementAt("_select").elementAt("_sqlStorage").equals("select MySuper, Field, String").assert(); + pTester.expectThat(actualValue).elementAt("_select").elementAt("preparedValues").hasLength(0).assert(); + } + ), + + new Test("newSelect with just an array of strings should just use them concatenated as select", + function(pTester) + { + var actualValue = newSelect(["MySuper", "Field", "String"]) + + pTester.expectThat(actualValue).elementAt("_select").elementAt("_sqlStorage").equals("select MySuper, Field, String").assert(); + pTester.expectThat(actualValue).elementAt("_select").elementAt("preparedValues").hasLength(0).assert(); + } + ), + + new Test("newSelect with just an SqlBuilder should use it as subselect", + function(pTester) + { + var actualValue = newSelect(new SqlBuilder().select("PERSONID").from("PERSON").where("PERSON.FIRSTNAME", "Fritz")) + + pTester.expectThat(actualValue).elementAt("_select").elementAt("_sqlStorage").equals("select (select PERSONID from PERSON where PERSON.FIRSTNAME = ?)").assert(); + pTester.expectThat(actualValue).elementAt("_select").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("newSelect an array of Strings and SqlBuilders should add them all", + function(pTester) + { + var actualValue = newSelect(["MySuper", "Field", "String", new SqlBuilder().select("PERSONID").from("PERSON").where("PERSON.FIRSTNAME", "Fritz")]) + + pTester.expectThat(actualValue).elementAt("_select").elementAt("_sqlStorage").equals("select MySuper, Field, String, (select PERSONID from PERSON where PERSON.FIRSTNAME = ?)").assert(); + pTester.expectThat(actualValue).elementAt("_select").elementAt("preparedValues").hasLength(1).assert(); + } + ), +]); + + +var validAndUsageTests = new TestSuite("SqlLib.validAndUsage", [ + new Test("and should just add simple strings as condition just as it is", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME = 'Tim'") // NOTE: you should not do this as this does not add a real prepared statement with "?" + .and("PERSON.LASTNAME = 'Admin'") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = 'Tim' and PERSON.LASTNAME = 'Admin'").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0).assert(); + } + ), + + new Test("and should add a condition if field and value are passed", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim") + .and("PERSON.LASTNAME", "Admin") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and should add a condition if value is an empty string", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "") + .and("PERSON.LASTNAME", "") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and should add a condition if field and value as jdito-var are passed", + function(pTester) + { + vars.set("$global.TestUnitValueName", "Tim"); + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "$global.TestUnitValueName") + + pTester.expectThat(actualValue.toString()).equals("( PERSON.FIRSTNAME = 'Tim' ) ").assert(); + } + ), + + new Test("$ should be escaped by a second $ and the string should therefore just be used as string and not as jdito variable", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "$$mySuperString") + + pTester.expectThat(actualValue.toString()).equals("( PERSON.FIRSTNAME = '$mySuperString' ) ").assert(); + } + ), + + new Test("and should add a condition if value is a jdito-var containing an empty string", + function(pTester) + { + vars.set("$global.TestingVarEmptyString", ""); + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "$global.TestingVarEmptyString") + .and("PERSON.LASTNAME", "$global.TestingVarEmptyString") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and should use the given condition pattern", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim", "# <> ?") + .and("PERSON.LASTNAME", "Admin") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME <> ? and PERSON.LASTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and should use the given SQLTYPE if provided", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", 6, null, SQLTYPES.INTEGER) + .and("PERSON.LASTNAME", 7, undefined, SQLTYPES.INTEGER) + .and("PERSON.LASTNAME", 8, "# <> ?", SQLTYPES.INTEGER) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? and PERSON.LASTNAME <> ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(3).assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").elementAt(0).elementAt(1).equals(SQLTYPES.INTEGER).assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").elementAt(1).elementAt(1).equals(SQLTYPES.INTEGER).assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").elementAt(2).elementAt(1).equals(SQLTYPES.INTEGER).assert(); + } + ), + + new Test("and only with a prepared statement-array should just use it as it is", + function(pTester) + { + var actualValue = new SqlBuilder() + .where([ + "PERSON.FIRSTNAME = ?", [["Peter", 12]] + ]) + .and([ + "exists (select * FROM CONTACT where PERSON_ID = PERSONID)", [] + ]) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.FIRSTNAME = ? ) and ( exists (select * FROM CONTACT where PERSON_ID = PERSONID) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("and only with a SqlBulder object should just use the condition from it", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(new SqlBuilder() + .select("TEST") + .from("PERSON") + .where("PERSON.FIRSTNAME", "Tim") + .and("PERSON.LASTNAME", "Admin")) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and with a builder as value and condition (field is null|undefined) should add the whole builder as subquery", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(null, new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON") + .where("PERSON.FIRSTNAME", "Tim") + .and("PERSON.LASTNAME", "Admin"), + "exists ?") // Note: you can use SqlBuilder.EXISTS() instead of "exists ?" + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("exists ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and with a builder as value and field should add the whole builder as subquery with field = (subquery)", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON") + .where("PERSON.FIRSTNAME", "Tim") + .and("PERSON.LASTNAME", "Admin")) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and with a prepared statement-array as value and field is null|undefined should add the whole statement as subquery", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(null, ["select FIRSTNAME from PERSON.FIRSTNAME = ?", [["Peter", 12]]], "exists ?") + .and(null, ["exists (select FIRSTNAME from PERSON.FIRSTNAME = ?)", [["Peter", 12]]]) // also without pCond it should work as the condition could be included in the prep statement + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("exists ( select FIRSTNAME from PERSON.FIRSTNAME = ? ) and ( exists (select FIRSTNAME from PERSON.FIRSTNAME = ?) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("and with a prepared statement-array as value and field should add the whole statement as subquery with field = (subquery)", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", ["select FIRSTNAME from PERSON.FIRSTNAME = ?", [["Peter", 12]]]) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ( select FIRSTNAME from PERSON.FIRSTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(1).assert(); + } + ), +]); + + +var validOrUsageTests = new TestSuite("SqlLib.validOrUsage", [ + new Test("or should just add simple strings as condition just as it is", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME = 'Tim'") // NOTE: you should not do this as this does not add a real prepared statement with "?" + .or("PERSON.LASTNAME = 'Admin'") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = 'Tim' or PERSON.LASTNAME = 'Admin'").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0).assert(); + } + ), + + new Test("or should add a condition if field and value are passed", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim") + .or("PERSON.LASTNAME", "Admin") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("or should use the given condition pattern", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim", "# <> ?") + .or("PERSON.LASTNAME", "Admin") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME <> ? or PERSON.LASTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("or should use the given SQLTYPE if provided", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", 6, null, SQLTYPES.INTEGER) + .or("PERSON.LASTNAME", 7, undefined, SQLTYPES.INTEGER) + .or("PERSON.LASTNAME", 8, "# <> ?", SQLTYPES.INTEGER) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? or PERSON.LASTNAME <> ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(3).assert(); + } + ), + + new Test("or only with a prepared statement-array should just use it as it is", + function(pTester) + { + var actualValue = new SqlBuilder() + .where([ + "PERSON.FIRSTNAME = ?", [["Peter", 12]] + ]) + .or([ + "exists (select * FROM CONTACT where PERSON_ID = PERSONID)", [] + ]) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.FIRSTNAME = ? ) or ( exists (select * FROM CONTACT where PERSON_ID = PERSONID) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("or only with a SqlBulder object should just use the condition from it", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim") + .or("PERSON.LASTNAME", "Admin")) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("or with a builder as value and condition (field is null|undefined) should add the whole builder as subquery", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(null, new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON") + .where("PERSON.FIRSTNAME", "Tim") + .or("PERSON.LASTNAME", "Admin"), + "exists ?") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("exists ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("or with a builder as value and field should add the whole builder as subquery with field = (subquery)", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON") + .where("PERSON.FIRSTNAME", "Tim") + .or("PERSON.LASTNAME", "Admin")) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("or with a prepared statement-array as value and field is null|undefined should add the whole statement as subquery", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(null, ["select FIRSTNAME from PERSON.FIRSTNAME = ?", [["Peter", 12]]], "exists ?") + .or(null, ["exists (select FIRSTNAME from PERSON.FIRSTNAME = ?)", [["Peter", 12]]]) // also without pCond it should work as the condition could be included in the prep statement + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("exists ( select FIRSTNAME from PERSON.FIRSTNAME = ? ) or ( exists (select FIRSTNAME from PERSON.FIRSTNAME = ?) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), +]); + +var combinedAndOrTests = new TestSuite("SqlLib.combinedAndOr", [ + new Test("or combining two and", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim") + .and("PERSON.LASTNAME", "Admin") + .or(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Peter") + .and("PERSON.LASTNAME", "Müller")) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("(PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?) or ( PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(4).assert(); + } + ), + + new Test("and combining two or", + function(pTester) + { + var actualValue = new SqlBuilder() + .where(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim") + .or("PERSON.LASTNAME", "Admin")) + .and(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Peter") + .or("PERSON.LASTNAME", "Müller")) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) and ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(4).assert(); + } + ), + + new Test("some and/or combinations in one select", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", "Tim") + .or("PERSON.FIRSTNAME", "Franz") + .and("PERSON.LASTNAME", "Admin") + .and(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Peter") + .or("PERSON.LASTNAME", "Müller")) + .or("PERSON.FIRSTNAME", "Franz") + .and("PERSON.FIRSTNAME", "Franz") + .or(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Peter") + .and("PERSON.LASTNAME", "Müller") + .and(new SqlBuilder() + .where("PERSON.FIRSTNAME", "Peter") + .or("PERSON.LASTNAME", "Müller"))) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME = ? or PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? and ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) or (PERSON.FIRSTNAME = ?) and PERSON.FIRSTNAME = ? or ( PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? and ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(11).assert(); + } + ), +]); + + +var ifSetTests = new TestSuite("SqlLib.ifSet", [ + new Test("simple and if set with all types of empty values.", + function(pTester) + { + var actualValue = new SqlBuilder() + .whereIfSet("PERSON.LASTNAME", null) + .andIfSet("PERSON.LASTNAME", undefined) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("", "no sql should be added").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0, "no params should be added").assert(); + } + ), + + new Test("jdito variable with null", + function(pTester) + { + vars.set("$global.TestingVarNull", null); + + var actualValue = new SqlBuilder() + .whereIfSet("PERSON.FIRSTNAME", "$global.TestingVarNull") + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("", "no sql should be added").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0, "no params should be added").assert(); + } + ), + + new Test("empty simple conditions", + function(pTester) + { + var actualValue = new SqlBuilder() + .whereIfSet("") + .andIfSet(["", []]) + .andIfSet(new SqlBuilder()) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("", "no sql should be added").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0, "no params should be added").assert(); + } + ), + + new Test("empty subqueries", + function(pTester) + { + var actualValue = new SqlBuilder() + .whereIfSet("PERSON.FIRSTNAME", ["", []]) + .andIfSet("PERSON.LASTNAME", new SqlBuilder()) + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("", "no sql should be added").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0, "no params should be added").assert(); + } + ), +]); + + +function cleanWrapperTests() +{ + try { + db.runStatement("drop table SQL_LIB_TEST_TABLE"); + } catch(ex) {} + + try { + db.deleteData("PERSON", "PERSONID in ('TEST-5', 'TEST-6')") + } catch(ex) {} + +} + + +var dbWrapperTests = new TestSuite("SqlLib.dbWrapper", [ + new Test("cell should load only one value", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON") + .where("PERSON.PERSONID", "TEST-5") + var actualValue = builder.cell() + + pTester.expectThat(actualValue).equals("Franz").assert(); + } + ), + + new Test("cell should just return '' if no condition set but pExecuteOnlyIfConditionExists is true", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON") + var actualValue = builder.cell(true) + + pTester.expectThat(actualValue).equals("").assert(); + } + ), + + new Test("cell should return a value if no condition set and pExecuteOnlyIfConditionExists is false", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME") + .from("PERSON"); + + var actualValue = builder.cell(false) + + pTester.expectThat(actualValue).not().equals("").assert(); + pTester.expectThat(actualValue).not().isNull().assert(); + pTester.expectThat(actualValue).not().isUndefined().assert(); + } + ), + + new Test("array should load an array of values", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME, LASTNAME") + .from("PERSON") + .where("PERSON.PERSONID", "TEST-5"); + + var actualValue = builder.array(db.ROW); + pTester.expectThat(actualValue).elementAt(0).equals("Franz", {name: "firstname"}).assert(); + pTester.expectThat(actualValue).elementAt(1).equals("Müller", {name: "lastname"}).assert(); + } + ), + + new Test("array should return an empty array if no condition set but pExecuteOnlyIfConditionExists is true", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME, LASTNAME") + .from("PERSON") + + var actualValue = builder.array(db.ROW, true); + pTester.expectThat(actualValue).hasLength(0).assert(); + } + ), + + new Test("array should return a non-empty array if no condition set and pExecuteOnlyIfConditionExists is false", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME, LASTNAME") + .from("PERSON") + + var actualValue = builder.array(db.ROW, false); + pTester.expectThat(actualValue).hasMinLength(1).assert(); + } + ), + + new Test("table should load an array of arrays with values", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME, LASTNAME") + .from("PERSON") + .where("PERSON.PERSONID", "TEST-5") + .or("PERSON.PERSONID", "TEST-6") + .orderBy("PERSONID asc"); + + var actualValue = builder.table(); + pTester.expectThat(actualValue).elementAt(0).elementAt(0).equals("Franz", {name: "firstname"}).assert(); + pTester.expectThat(actualValue).elementAt(0).elementAt(1).equals("Müller", {name: "lastname"}).assert(); + + pTester.expectThat(actualValue).elementAt(1).elementAt(0).equals("Marco", {name: "firstname"}).assert(); + pTester.expectThat(actualValue).elementAt(1).elementAt(1).equals("Polo", {name: "lastname"}).assert(); + } + ), + + new Test("table should return an empty array if no condition set but pExecuteOnlyIfConditionExists is true", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME, LASTNAME") + .from("PERSON"); + + var actualValue = builder.table(true); + + pTester.expectThat(actualValue).hasLength(0).assert(); + } + ), + + new Test("table should return a non-empty array if no condition set and pExecuteOnlyIfConditionExists is false", + function(pTester) + { + var builder = new SqlBuilder() + .select("FIRSTNAME, LASTNAME") + .from("PERSON"); + + var actualValue = builder.table(false); + pTester.expectThat(actualValue).hasMinLength(1).assert(); + } + ), + + new Test("delete should delete the data and use the from and condition from the builder", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + + var builder = new SqlBuilder() + .from("SQL_LIB_TEST_TABLE") + .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); + + var actualValue = builder.deleteData(); + pTester.expectThat(actualValue).equals(1).assert(); + } + ), + + new Test("delete should delete the data from the provided table and use the condition from the builder. It ignores .from if a table is given.", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + + var builder = new SqlBuilder() + .from("PERSON") + .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); + + var actualValue = builder.deleteData(false, "SQL_LIB_TEST_TABLE"); + pTester.expectThat(actualValue).equals(1).assert(); + } + ), + + new Test("delete should delete ALL data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is false", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Ludwig", "Fischer"]); + + var builder = new SqlBuilder() + .from("SQL_LIB_TEST_TABLE") + + var actualValue = builder.deleteData(false); + pTester.expectThat(actualValue).equals(2).assert(); + } + ), + + new Test("delete should delete NO data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is true", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Ludwig", "Fischer"]); + + var builder = new SqlBuilder() + .from("SQL_LIB_TEST_TABLE") + + var actualValue = builder.deleteData(true); + pTester.expectThat(actualValue).equals(0).assert(); + } + ), + + new Test("update should update the data and use the from and condition from the builder", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + + var builder = new SqlBuilder() + .from("SQL_LIB_TEST_TABLE") + .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); + + builder.updateData(false, undefined, ["FIRSTNAME"], null, ["Fritz"]); + + var actualValue = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") + + pTester.expectThat(actualValue).equals("Fritz").assert(); + } + ), + + new Test("update should update the data from the provided table and use the condition from the builder. It ignores .from if a table is given.", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + + var builder = new SqlBuilder() + .from("PERSON") + .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); + + builder.updateData(false, "SQL_LIB_TEST_TABLE", ["FIRSTNAME"], null, ["Fritz"]); + + var actualValue = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") + + pTester.expectThat(actualValue).equals("Fritz").assert(); + } + ), + + new Test("update should update ALL data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is false", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')"); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Franz", "Fischer"]); + + var builder = new SqlBuilder() + .from("SQL_LIB_TEST_TABLE") + + builder.updateData(false, undefined, ["FIRSTNAME"], null, ["Fritz"]); + + var actualValue1 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") + var actualValue2 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-8'") + + pTester.expectThat(actualValue1).equals("Fritz", "TEST-7 should have Firstname Fritz").assert(); + pTester.expectThat(actualValue2).equals("Fritz", "TEST-8 should have Firstname Fritz").assert(); + } + ), + + new Test("update should update NO data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is true", + function(pTester) + { + db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')") + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); + db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Franz", "Fischer"]); + + var builder = new SqlBuilder() + .from("SQL_LIB_TEST_TABLE") + + builder.updateData(true, undefined, ["FIRSTNAME"], null, ["Fritz"]); + + var actualValue1 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") + var actualValue2 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-8'") + + pTester.expectThat(actualValue1).equals("Ludwig", "TEST-7 should have Firstname Ludwig").assert(); + pTester.expectThat(actualValue2).equals("Franz", "TEST-8 should have Firstname Franz").assert(); + } + ), +], function preAll() +{ + // remove data which may exist if previous test-run failed and postAll was not executed + cleanWrapperTests(); + + // add table for save testing of deletes + db.runStatement("create table SQL_LIB_TEST_TABLE (TESTID varchar(36), FIRSTNAME varchar(100), LASTNAME varchar(100))"); + + // add test persons + db.insertData("PERSON", ["PERSONID", "FIRSTNAME", "LASTNAME", "USER_NEW", "DATE_NEW"], null, ["TEST-5", "Franz", "Müller", "testuser", vars.get("$sys.date")]) + db.insertData("PERSON", ["PERSONID", "FIRSTNAME", "LASTNAME", "USER_NEW", "DATE_NEW"], null, ["TEST-6", "Marco", "Polo", "testuser", vars.get("$sys.date")]) +}, undefined, undefined, function postAll() +{ + cleanWrapperTests(); +}) + + +var mandatoryErrorTests = new TestSuite("SqlLib.mandatoryError", [ +// and + new Test("and without parameter should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or(); + }).throwsException(SqlBuilder._ERROR_NO_PARAMETER_PROVIDED()).assert(); + } + ), + + new Test("and with null as value should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", null); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + new Test("and with undefined as value should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", undefined); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + new Test("and with a jdito-var containing null should error", + function(pTester) + { + vars.set("$global.TestingVarNull", null); + + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", "$global.TestingVarNull"); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY_JDITO_VAR()).assert(); + } + ), + + new Test("and with an empty sql-builder as subquery should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", new SqlBuilder()); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + new Test("and with an empty prepared statement as subquery should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", ["", []]); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + +// or + new Test("or without parameter should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or(); + }).throwsException(SqlBuilder._ERROR_NO_PARAMETER_PROVIDED()).assert(); + } + ), + + new Test("or with null as value should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", null); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + new Test("or with undefined as value should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", undefined); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + new Test("or with a jdito-var containing null should error", + function(pTester) + { + vars.set("$global.TestingVarNull", null); + + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", "$global.TestingVarNull"); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY_JDITO_VAR()).assert(); + } + ), + + new Test("or with an empty sql-builder as subquery should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", new SqlBuilder()); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), + + new Test("or with an empty prepared statement as subquery should error", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where().or("PERSON.FIRSTNAME", ["", []]); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), +]); + + +var inStatementTests = new TestSuite("SqlLib.inStatement", [ + new Test("simple and in", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.LASTNAME", ["Franz", "Fritz"], SqlBuilder.IN()) // Note: you can use SqlBuilder.IN(), SqlBuilder.NOT_IN(), "# in ?", etc. as 3rd parameter + .or("PERSON.LASTNAME", ["Peter", "Mayer"], SqlBuilder.IN()); + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.LASTNAME in (?, ?) ) or ( PERSON.LASTNAME in (?, ?) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(4).assert(); + } + ), + + new Test("simple and not in", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.LASTNAME", ["Franz", "Fritz"], "# not in ?"); // Note: you can use SqlBuilder.IN(), SqlBuilder.NOT_IN(), "# in ?", etc. as 3rd parameter + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( PERSON.LASTNAME not in (?, ?) ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(2).assert(); + } + ), + + new Test("in with subquery", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", new SqlBuilder() + .select("PERSON.FIRSTNAME") + .from("PERSON") + .where("PERSON.LASTNAME", "Fritz") + , "# in ?"); // Note: you can use SqlBuilder.IN() instead of "# in ?" + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME in ( select PERSON.FIRSTNAME from PERSON where PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("in with prepared statement-array", + function(pTester) + { + var actualValue = new SqlBuilder() + .where("PERSON.FIRSTNAME", ["select PERSON.FIRSTNAME from PERSON where PERSON.LASTNAME = ?", [["Fritz", SQLTYPES.VARCHAR]]] + , "# in ?"); // Note: you can use SqlBuilder.IN() instead of "# in ?" + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("PERSON.FIRSTNAME in ( select PERSON.FIRSTNAME from PERSON where PERSON.LASTNAME = ? ) ").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("andIfSet should ignore empty array", + function(pTester) + { + var actualValue = new SqlBuilder() + .whereIfSet("PERSON.LASTNAME", []); + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals("").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(0).assert(); + } + ), + + new Test("and should error on an empty array", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where("PERSON.LASTNAME", []); + }).throwsException(SqlBuilder._ERROR_VALUE_IS_MANDATORY()).assert(); + } + ), +]); + + +var testConstantFunctions = new TestSuite("SqlLib.testConstantFunc", [ + new Test("SqlBuilder.IN()", + function(pTester) + { + var actualValue = SqlBuilder.IN(); + pTester.expectThat(actualValue).equals("# in ?").assert(); + } + ), + + new Test("SqlBuilder.NOT_IN()", + function(pTester) + { + var actualValue = SqlBuilder.NOT_IN(); + pTester.expectThat(actualValue).equals("# not in ?").assert(); + } + ), + + new Test("SqlBuilder.EXISTS()", + function(pTester) + { + var actualValue = SqlBuilder.EXISTS(); + pTester.expectThat(actualValue).equals("exists ?").assert(); + } + ), +]); + + +var selectTests = new TestSuite("SqlLib.select", [ + new Test("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 actualValue = new SqlBuilder() + .select(["AB_ATTRIBUTEID", "AB_ATTRIBUTEUSAGEID", countSubQuery]) + .from("AB_ATTRIBUTE") + + pTester.expectThat(actualValue).elementAt("_select").elementAt("_sqlStorage").equals("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)").assert(); + pTester.expectThat(actualValue).elementAt("_select").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("a sql-builder in from is used as subselect", + function(pTester) + { + var subQuery = newSelect("FIRSTNAME") + .from("PERSON") + .where("PERSON.LASTNAME", "Meier") + + var actualValue = new SqlBuilder() + .select("*") + .from(subQuery) + + pTester.expectThat(actualValue).elementAt("_from").elementAt("_sqlStorage").equals("from (select FIRSTNAME from PERSON where PERSON.LASTNAME = ?)").assert(); + pTester.expectThat(actualValue).elementAt("_from").elementAt("preparedValues").hasLength(1).assert(); + } + ), +]); + + +var joinTests = new TestSuite("SqlLib.join", [ + new Test("SqlBuilder as on-condition should only add the conditon of the builder", + function(pTester) + { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.NAME", "Adito") + + var actualValue = new SqlBuilder() + .select("*") + .from("PERSON") + .join("ORGANISATION", subQuery) + + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("_sqlStorage").equals("join ORGANISATION on ORGANISATION.NAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("SqlBuilder as table for join is added as subselect", + function(pTester) + { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.NAME", "Adito") + + var actualValue = new SqlBuilder() + .select("*") + .from("PERSON") + .join(subQuery, "orgname.NAME = TABLE2.NAME", "orgname") + + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("_sqlStorage").equals("join (select NAME from ORGANISATION where ORGANISATION.NAME = ?) orgname on orgname.NAME = TABLE2.NAME").assert(); + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("just use a string also containing a condition as join without additional condition", + function(pTester) + { + var actualValue = new SqlBuilder() + .select("*") + .from("PERSON") + .join("TABLE1 on TABLE1.NAME = TABLE2.NAME") + + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("_sqlStorage").equals("join TABLE1 on TABLE1.NAME = TABLE2.NAME").assert(); + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("preparedValues").hasLength(0).assert(); + } + ), +]); + + +var subqueryAsFieldTests = new TestSuite("SqlLib.subqueryAsField", [ + new Test("Test if a Subselect as field works if pValue is provided. This should be added as subselect.", + function(pTester) + { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID") + .and("PERSON.FIRSTNAME", "val1") // test if the value is added at the correct place + + var actualValue = new SqlBuilder().where(subQuery, "val2", "# = ?", SQLTYPES.VARCHAR) + .and("PERSON.FIRSTNAME", "val3"); + + + pTester.expectThat(actualValue).elementAt("_where").elementAt("_sqlStorage").equals(" ( ( select NAME from ORGANISATION where ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID and PERSON.FIRSTNAME = ? ) = ? ) and PERSON.FIRSTNAME = ?").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").hasLength(3).assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").elementAt(0).elementAt(0).equals("val1").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").elementAt(1).elementAt(0).equals("val2").assert(); + pTester.expectThat(actualValue).elementAt("_where").elementAt("preparedValues").elementAt(2).elementAt(0).equals("val3").assert(); + } + ), + + new Test("Test if a Subselect as field should error if no SQLTYPE is provided.", + function(pTester) + { + pTester.expectThat(function() { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID") + .and("PERSON.FIRSTNAME", "val1") // test if the value is added at the correct place + new SqlBuilder().where(subQuery, "val2", "# = ?"); + }).throwsException(SqlBuilder._ERROR_SUBSELECT_AS_FIELD_NO_FIELD_TYPE()).assert(); + } + ), + + new Test("Test if a Subselect as field should error if it is not a full select.", + function(pTester) + { + pTester.expectThat(function() { + var subQuery = newSelect("NAME") + .where("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID") + .and("PERSON.FIRSTNAME", "val1") // test if the value is added at the correct place + + new SqlBuilder().where(subQuery, "val2", "# = ?", SQLTYPES.VARCHAR); + }).throwsException(SqlBuilder._ERROR_SUBSELECT_AS_FIELD_NOT_COMPLETE()).assert(); + } + ), +]); + + +var conditionFormatTests = new TestSuite("SqlLib.conditionFormat", [ + new Test("pCondition should not fail if # an ? exist in correct order", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder() + .where("PERSON.FIRSTNAME", "val1", "# = ?") + .and("PERSON.FIRSTNAME", "val1", "asdf # fdsa=asdf ?fdas") + ; + }).not().throwsException().assert(); + } + ), + + new Test("pCondition should not fail if # an ? exist in correct order and there are additional, escaped # and ?", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "\\? # \\#= ?"); + }).not().throwsException().assert(); + } + ), + + new Test("pCondition should not fail if only ? exists", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "?") + }).not().throwsException().assert(); + } + ), + + new Test("pCondition should fail if more than one ? exists", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "? test ?") + }).throwsException(SqlBuilder._ERROR_CONDITION_WRONG_FORMAT()).assert(); + } + ), + + new Test("pCondition should fail if more than one # exists", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "# test #") + }).throwsException(SqlBuilder._ERROR_CONDITION_WRONG_FORMAT()).assert(); + } + ), + + new Test("pCondition should fail if # and ? are in wrong order", + function(pTester) + { + pTester.expectThat(function() { + new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "? = #") + }).throwsException(SqlBuilder._ERROR_CONDITION_WRONG_FORMAT()).assert(); + } + ), +]); + + +var subqueryAliasTests = new TestSuite("SqlLib.subqueryAlias", [ + new Test("subselectAlias should be added for subquery in .select", + function(pTester) + { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.NAME", "Adito") + .subselectAlias("testAlias") + + var actualValue = new SqlBuilder() + .select([subQuery, "FIRSTNAME"]) + .from("PERSON") + + pTester.expectThat(actualValue).elementAt("_select").elementAt("_sqlStorage").equals("select (select NAME from ORGANISATION where ORGANISATION.NAME = ?) testAlias, FIRSTNAME").assert(); + pTester.expectThat(actualValue).elementAt("_select").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("subselectAlias should be added for subquery in .from", + function(pTester) + { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.NAME", "Adito") + .subselectAlias("testAlias") + + var actualValue = new SqlBuilder() + .from(subQuery) + + pTester.expectThat(actualValue).elementAt("_from").elementAt("_sqlStorage").equals("from (select NAME from ORGANISATION where ORGANISATION.NAME = ?) testAlias").assert(); + pTester.expectThat(actualValue).elementAt("_from").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("subselectAlias should be overruled by the param in in .from", + function(pTester) + { + var subQuery = newSelect("NAME") + .from("ORGANISATION") + .where("ORGANISATION.NAME", "Adito") + .subselectAlias("testAlias") + + var actualValue = new SqlBuilder() + .from(subQuery, "overwriteAlias") + + pTester.expectThat(actualValue).elementAt("_from").elementAt("_sqlStorage").equals("from (select NAME from ORGANISATION where ORGANISATION.NAME = ?) overwriteAlias").assert(); + pTester.expectThat(actualValue).elementAt("_from").elementAt("preparedValues").hasLength(1).assert(); + } + ), + + new Test("subselectAlias should be added for subquery in .join", + function(pTester) + { + var subQuery = newSelect("NAME, ORGANISATIONID") + .from("ORGANISATION") + .where("ORGANISATION.NAME", "Adito") + .subselectAlias("testAlias") + + var actualValue = new SqlBuilder() + .from("CONTACT") + .join(subQuery, "testAlias.ORGANISATIONID = ORGANISATION_ID") + .join(subQuery, "testAlias.ORGANISATIONID = ORGANISATION_ID", "overwriteAlias") + + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("_sqlStorage").equals("join (select NAME, ORGANISATIONID from ORGANISATION where ORGANISATION.NAME = ?) testAlias on testAlias.ORGANISATIONID = ORGANISATION_ID").assert(); + pTester.expectThat(actualValue).elementAt("_joins").elementAt(0).elementAt("preparedValues").hasLength(1).assert(); + + pTester.expectThat(actualValue).elementAt("_joins").elementAt(1).elementAt("_sqlStorage").equals("join (select NAME, ORGANISATIONID from ORGANISATION where ORGANISATION.NAME = ?) overwriteAlias on testAlias.ORGANISATIONID = ORGANISATION_ID").assert(); + pTester.expectThat(actualValue).elementAt("_joins").elementAt(1).elementAt("preparedValues").hasLength(1).assert(); + } + ), +]); + + +var tester = new Tester("Test SqlBuilder"); +tester.test(newSelectTests); +tester.test(validAndUsageTests); +tester.test(validOrUsageTests); +tester.test(combinedAndOrTests); +tester.test(ifSetTests); +tester.test(dbWrapperTests); +tester.test(mandatoryErrorTests); +tester.test(inStatementTests); +tester.test(testConstantFunctions); +tester.test(selectTests); +tester.test(joinTests); +tester.test(subqueryAsFieldTests); +tester.test(conditionFormatTests); +tester.test(subqueryAliasTests); + +tester.summary(); + +result.object(tester.getResults()); \ No newline at end of file diff --git a/process/SqlLib_tests/process.js b/process/SqlLib_tests/process.js deleted file mode 100644 index 924162e2a4ef98f5dc93515f648fdad355ced736..0000000000000000000000000000000000000000 --- a/process/SqlLib_tests/process.js +++ /dev/null @@ -1,1015 +0,0 @@ -import("system.db"); -import("system.vars"); -import("system.translate"); -import("system.logging"); -import("system.SQLTYPES"); -import("Sql_lib"); -import("UnitTest_lib"); - -var newSelectTests = new TestSuite([ - ["newSelect with just a string schould just use it as select", function(pTester) - { - var actual = newSelect("MySuper, Field, String") - - pTester.assert("select MySuper, Field, String", actual._select._sqlStorage, "prepared sql"); - pTester.assert(0, actual._select.preparedValues.length, "number of params"); - }], - - ["newSelect with just an array of strings schould just use them concatenated as select", function(pTester) - { - var actual = newSelect(["MySuper", "Field", "String"]) - - pTester.assert("select MySuper, Field, String", actual._select._sqlStorage, "prepared sql"); - pTester.assert(0, actual._select.preparedValues.length, "number of params"); - }], - - ["newSelect with just an SqlBuilder should use it as subselect", function(pTester) - { - var actual = newSelect(new SqlBuilder().select("PERSONID").from("PERSON").where("PERSON.FIRSTNAME", "Fritz")) - - pTester.assert("select (select PERSONID from PERSON where PERSON.FIRSTNAME = ?)", actual._select._sqlStorage, "prepared sql"); - pTester.assert(1, actual._select.preparedValues.length, "number of params"); - }], - - ["newSelect an array of Strings and SqlBuilders should add them all", function(pTester) - { - var actual = newSelect(["MySuper", "Field", "String", new SqlBuilder().select("PERSONID").from("PERSON").where("PERSON.FIRSTNAME", "Fritz")]) - - pTester.assert("select MySuper, Field, String, (select PERSONID from PERSON where PERSON.FIRSTNAME = ?)", actual._select._sqlStorage, "prepared sql"); - pTester.assert(1, actual._select.preparedValues.length, "number of params"); - }], -]); - -var validAndUsageTests = new TestSuite([ - ["and should just add simple strings as condition just as it is", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME = 'Tim'") // NOTE: you should not do this as this does not add a real prepared statement with "?" - .and("PERSON.LASTNAME = 'Admin'") - - pTester.assert("PERSON.FIRSTNAME = 'Tim' and PERSON.LASTNAME = 'Admin'", actual._where._sqlStorage, "prepared sql"); - pTester.assert(0, actual._where.preparedValues.length, "number of params"); - }], - - ["and should add a condition if field and value are passed", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim") - .and("PERSON.LASTNAME", "Admin") - - pTester.assert("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and should add a condition if value is an empty string", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "") - .and("PERSON.LASTNAME", "") - - pTester.assert("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and should add a condition if field and value as jdito-var are passed", function(pTester) - { - vars.set("$global.TestUnitValueName", "Tim"); - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "$global.TestUnitValueName") - - pTester.assert("( PERSON.FIRSTNAME = 'Tim' ) ", actual.toString()); - }], - - ["$ should be escaped by a second $ and the string should therefore just be used as string and not as jdito variable", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "$$mySuperString") - - pTester.assert("( PERSON.FIRSTNAME = '$mySuperString' ) ", actual.toString()); - }], - - ["and should add a condition if value is a jdito-var containing an empty string", function(pTester) - { - vars.set("$global.TestingVarEmptyString", ""); - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "$global.TestingVarEmptyString") - .and("PERSON.LASTNAME", "$global.TestingVarEmptyString") - - pTester.assert("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and should use the given condition pattern", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim", "# <> ?") - .and("PERSON.LASTNAME", "Admin") - - pTester.assert("PERSON.FIRSTNAME <> ? and PERSON.LASTNAME = ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and should use the given SQLTYPE if provided", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", 6, null, SQLTYPES.INTEGER) - .and("PERSON.LASTNAME", 7, undefined, SQLTYPES.INTEGER) - .and("PERSON.LASTNAME", 8, "# <> ?", SQLTYPES.INTEGER) - - pTester.assert("PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? and PERSON.LASTNAME <> ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(3, actual._where.preparedValues.length, "number of params"); - pTester.assert(SQLTYPES.INTEGER, actual._where.preparedValues[0][1], "sql type of param 1 is the provided type"); - pTester.assert(SQLTYPES.INTEGER, actual._where.preparedValues[1][1], "sql type of param 2 is the provided type"); - pTester.assert(SQLTYPES.INTEGER, actual._where.preparedValues[2][1], "sql type of param 3 is the provided type"); - }], - - ["and only with a prepared statement-array should just use it as it is", function(pTester) - { - var actual = new SqlBuilder() - .where([ - "PERSON.FIRSTNAME = ?", [["Peter", 12]] - ]) - .and([ - "exists (select * FROM CONTACT where PERSON_ID = PERSONID)", [] - ]) - - pTester.assert(" ( PERSON.FIRSTNAME = ? ) and ( exists (select * FROM CONTACT where PERSON_ID = PERSONID) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(1, actual._where.preparedValues.length, "number of params"); - }], - - ["and only with a SqlBulder object should just use the condition from it", function(pTester) - { - var actual = new SqlBuilder() - .where(new SqlBuilder() - .select("TEST") - .from("PERSON") - .where("PERSON.FIRSTNAME", "Tim") - .and("PERSON.LASTNAME", "Admin")) - - pTester.assert(" ( PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and with a builder as value and condition (field is null|undefined) should add the whole builder as subquery", function(pTester) - { - var actual = new SqlBuilder() - .where(null, new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON") - .where("PERSON.FIRSTNAME", "Tim") - .and("PERSON.LASTNAME", "Admin"), - "exists ?") // Note: you can use SqlBuilder.EXISTS() instead of "exists ?" - - pTester.assert("exists ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and with a builder as value and field should add the whole builder as subquery with field = (subquery)", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON") - .where("PERSON.FIRSTNAME", "Tim") - .and("PERSON.LASTNAME", "Admin")) - - pTester.assert("PERSON.FIRSTNAME = ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and with a prepared statement-array as value and field is null|undefined should add the whole statement as subquery", function(pTester) - { - var actual = new SqlBuilder() - .where(null, ["select FIRSTNAME from PERSON.FIRSTNAME = ?", [["Peter", 12]]], "exists ?") - .and(null, ["exists (select FIRSTNAME from PERSON.FIRSTNAME = ?)", [["Peter", 12]]]) // also without pCond it should work as the condition could be included in the prep statement - - pTester.assert("exists ( select FIRSTNAME from PERSON.FIRSTNAME = ? ) and ( exists (select FIRSTNAME from PERSON.FIRSTNAME = ?) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["and with a prepared statement-array as value and field should add the whole statement as subquery with field = (subquery)", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", ["select FIRSTNAME from PERSON.FIRSTNAME = ?", [["Peter", 12]]]) - - pTester.assert("PERSON.FIRSTNAME = ( select FIRSTNAME from PERSON.FIRSTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(1, actual._where.preparedValues.length, "number of params"); - }] -]); - -var validOrUsageTests = new TestSuite([ - ["or should just add simple strings as condition just as it is", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME = 'Tim'") // NOTE: you should not do this as this does not add a real prepared statement with "?" - .or("PERSON.LASTNAME = 'Admin'") - - pTester.assert("PERSON.FIRSTNAME = 'Tim' or PERSON.LASTNAME = 'Admin'", actual._where._sqlStorage, "prepared sql"); - pTester.assert(0, actual._where.preparedValues.length, "number of params"); - }], - - ["or should add a condition if field and value are passed", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim") - .or("PERSON.LASTNAME", "Admin") - - pTester.assert("PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["or should use the given condition pattern", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim", "# <> ?") - .or("PERSON.LASTNAME", "Admin") - - pTester.assert("PERSON.FIRSTNAME <> ? or PERSON.LASTNAME = ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["or should use the given SQLTYPE if provided", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", 6, null, SQLTYPES.INTEGER) - .or("PERSON.LASTNAME", 7, undefined, SQLTYPES.INTEGER) - .or("PERSON.LASTNAME", 8, "# <> ?", SQLTYPES.INTEGER) - - pTester.assert("PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? or PERSON.LASTNAME <> ?", actual._where._sqlStorage, "prepared sql"); - pTester.assert(3, actual._where.preparedValues.length, "number of params"); - }], - - ["or only with a prepared statement-array should just use it as it is", function(pTester) - { - var actual = new SqlBuilder() - .where([ - "PERSON.FIRSTNAME = ?", [["Peter", 12]] - ]) - .or([ - "exists (select * FROM CONTACT where PERSON_ID = PERSONID)", [] - ]) - - pTester.assert(" ( PERSON.FIRSTNAME = ? ) or ( exists (select * FROM CONTACT where PERSON_ID = PERSONID) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(1, actual._where.preparedValues.length, "number of params"); - }], - - ["or only with a SqlBulder object should just use the condition from it", function(pTester) - { - var actual = new SqlBuilder() - .where(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim") - .or("PERSON.LASTNAME", "Admin")) - - pTester.assert(" ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["or with a builder as value and condition (field is null|undefined) should add the whole builder as subquery", function(pTester) - { - var actual = new SqlBuilder() - .where(null, new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON") - .where("PERSON.FIRSTNAME", "Tim") - .or("PERSON.LASTNAME", "Admin"), - "exists ?") - - pTester.assert("exists ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["or with a builder as value and field should add the whole builder as subquery with field = (subquery)", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON") - .where("PERSON.FIRSTNAME", "Tim") - .or("PERSON.LASTNAME", "Admin")) - - pTester.assert("PERSON.FIRSTNAME = ( select FIRSTNAME from PERSON where PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["or with a prepared statement-array as value and field is null|undefined should add the whole statement as subquery", function(pTester) - { - var actual = new SqlBuilder() - .where(null, ["select FIRSTNAME from PERSON.FIRSTNAME = ?", [["Peter", 12]]], "exists ?") - .or(null, ["exists (select FIRSTNAME from PERSON.FIRSTNAME = ?)", [["Peter", 12]]]) // also without pCond it should work as the condition could be included in the prep statement - - pTester.assert("exists ( select FIRSTNAME from PERSON.FIRSTNAME = ? ) or ( exists (select FIRSTNAME from PERSON.FIRSTNAME = ?) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }] -]); - -var combinedAndOrTests = new TestSuite([ - ["or combining two and", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim") - .and("PERSON.LASTNAME", "Admin") - .or(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Peter") - .and("PERSON.LASTNAME", "Müller")) - - pTester.assert("(PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ?) or ( PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(4, actual._where.preparedValues.length, "number of params"); - }], - - ["and combining two or", function(pTester) - { - var actual = new SqlBuilder() - .where(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim") - .or("PERSON.LASTNAME", "Admin")) - .and(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Peter") - .or("PERSON.LASTNAME", "Müller")) - - pTester.assert(" ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) and ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(4, actual._where.preparedValues.length, "number of params"); - }], - - ["some and/or combinations in one select", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", "Tim") - .or("PERSON.FIRSTNAME", "Franz") - .and("PERSON.LASTNAME", "Admin") - .and(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Peter") - .or("PERSON.LASTNAME", "Müller")) - .or("PERSON.FIRSTNAME", "Franz") - .and("PERSON.FIRSTNAME", "Franz") - .or(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Peter") - .and("PERSON.LASTNAME", "Müller") - .and(new SqlBuilder() - .where("PERSON.FIRSTNAME", "Peter") - .or("PERSON.LASTNAME", "Müller"))) - - pTester.assert("PERSON.FIRSTNAME = ? or PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? and ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) or (PERSON.FIRSTNAME = ?) and PERSON.FIRSTNAME = ? or ( PERSON.FIRSTNAME = ? and PERSON.LASTNAME = ? and ( PERSON.FIRSTNAME = ? or PERSON.LASTNAME = ? ) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(11, actual._where.preparedValues.length, "number of params"); - }] -]); - -var ifSetTests = new TestSuite([ - ["simple and if set with all types of empty values.", function(pTester) - { - var actual = new SqlBuilder() - .whereIfSet("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"); - }], - - ["jdito variable with null", function(pTester) - { - vars.set("$global.TestingVarNull", null); - - var actual = new SqlBuilder() - .whereIfSet("PERSON.FIRSTNAME", "$global.TestingVarNull") - - pTester.assert("", actual._where._sqlStorage, "no sql should be added"); - pTester.assert(0, actual._where.preparedValues.length, "no params should be added"); - }], - - ["empty simple conditions", function(pTester) - { - var actual = new SqlBuilder() - .whereIfSet("") - .andIfSet(["", []]) - .andIfSet(new SqlBuilder()) - - pTester.assert("", actual._where._sqlStorage, "no sql should be added"); - pTester.assert(0, actual._where.preparedValues.length, "no params should be added"); - }], - - ["empty subqueries", function(pTester) - { - var actual = new SqlBuilder() - .whereIfSet("PERSON.FIRSTNAME", ["", []]) - .andIfSet("PERSON.LASTNAME", new SqlBuilder()) - - pTester.assert("", actual._where._sqlStorage, "no sql should be added"); - pTester.assert(0, actual._where.preparedValues.length, "no params should be added"); - }] -]); - -function cleanWrapperTests() -{ - try { - db.runStatement("drop table SQL_LIB_TEST_TABLE"); - } catch(ex) {} - - try { - db.deleteData("PERSON", "PERSONID in ('TEST-5', 'TEST-6')") - } catch(ex) {} - -} - -var dbWrapperTests = new TestSuite([ - ["cell should load only one value", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON") - .where("PERSON.PERSONID", "TEST-5") - pTester.assert("Franz", builder.cell()); - }], - - ["cell should just return '' if no condition set but pExecuteOnlyIfConditionExists is true", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON") - pTester.assert("", builder.cell(true)); - }], - - ["cell should return a value if no condition set and pExecuteOnlyIfConditionExists is false", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME") - .from("PERSON"); - - var actual = builder.cell(false) - pTester.assert(true, actual !== "" && actual !== null && actual !== undefined); - }], - - ["array should load an array of values", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME, LASTNAME") - .from("PERSON") - .where("PERSON.PERSONID", "TEST-5"); - - var actual = builder.array(db.ROW); - pTester.assert("Franz", actual[0], "firstname should be 'Franz'"); - pTester.assert("Müller", actual[1], "lastname should be 'Müller'"); - }], - - ["array should return an empty array if no condition set but pExecuteOnlyIfConditionExists is true", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME, LASTNAME") - .from("PERSON") - - var actual = builder.array(db.ROW, true); - pTester.assert(0, actual.length); - }], - - ["array should return a non-empty array if no condition set and pExecuteOnlyIfConditionExists is false", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME, LASTNAME") - .from("PERSON") - - var actual = builder.array(db.ROW, false); - pTester.assert(true, actual.length > 0); - }], - - ["table should load an array of arrays with values", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME, LASTNAME") - .from("PERSON") - .where("PERSON.PERSONID", "TEST-5") - .or("PERSON.PERSONID", "TEST-6") - .orderBy("PERSONID asc"); - - var actual = builder.table(); - pTester.assert("Franz", actual[0][0], "firstname should be 'Franz'"); - pTester.assert("Müller", actual[0][1], "lastname should be 'Müller'"); - - pTester.assert("Marco", actual[1][0], "firstname should be 'Marco'"); - pTester.assert("Polo", actual[1][1], "lastname should be 'Polo'"); - }], - - ["table should return an empty array if no condition set but pExecuteOnlyIfConditionExists is true", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME, LASTNAME") - .from("PERSON"); - - var actual = builder.table(true); - pTester.assert(0, actual.length); - }], - - ["table should return a non-empty array if no condition set and pExecuteOnlyIfConditionExists is false", function(pTester) - { - var builder = new SqlBuilder() - .select("FIRSTNAME, LASTNAME") - .from("PERSON"); - - var actual = builder.table(false); - pTester.assert(true, actual.length > 0); - }], - - ["delete should delete the data and use the from and condition from the builder", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - - var builder = new SqlBuilder() - .from("SQL_LIB_TEST_TABLE") - .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); - - var deletedRows = builder.deleteData(); - pTester.assert(1, deletedRows); - }], - - ["delete should delete the data from the provided table and use the condition from the builder. It ignores .from if a table is given.", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - - var builder = new SqlBuilder() - .from("PERSON") - .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); - - var deletedRows = builder.deleteData(false, "SQL_LIB_TEST_TABLE"); - pTester.assert(1, deletedRows); - }], - - ["delete should delete ALL data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is false", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Ludwig", "Fischer"]); - - var builder = new SqlBuilder() - .from("SQL_LIB_TEST_TABLE") - - var deletedRows = builder.deleteData(false); - pTester.assert(2, deletedRows); - }], - - ["delete should delete NO data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is true", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Ludwig", "Fischer"]); - - var builder = new SqlBuilder() - .from("SQL_LIB_TEST_TABLE") - - var deletedRows = builder.deleteData(true); - pTester.assert(0, deletedRows); - }], - - ["update should update the data and use the from and condition from the builder", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - - var builder = new SqlBuilder() - .from("SQL_LIB_TEST_TABLE") - .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); - - builder.updateData(false, undefined, ["FIRSTNAME"], null, ["Fritz"]); - - var actual = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") - - pTester.assert("Fritz", actual); - }], - - ["update should update the data from the provided table and use the condition from the builder. It ignores .from if a table is given.", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID = 'TEST-7'"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - - var builder = new SqlBuilder() - .from("PERSON") - .where("SQL_LIB_TEST_TABLE.TESTID", "TEST-7"); - - builder.updateData(false, "SQL_LIB_TEST_TABLE", ["FIRSTNAME"], null, ["Fritz"]); - - var actual = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") - - pTester.assert("Fritz", actual); - }], - - ["update should update ALL data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is false", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')"); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Franz", "Fischer"]); - - var builder = new SqlBuilder() - .from("SQL_LIB_TEST_TABLE") - - builder.updateData(false, undefined, ["FIRSTNAME"], null, ["Fritz"]); - - var actual1 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") - var actual2 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-8'") - - pTester.assert("Fritz", actual1, "TEST-7 should have Firstname Fritz"); - pTester.assert("Fritz", actual2, "TEST-8 should have Firstname Fritz"); - }], - - ["update should update NO data from a table if the builder has no condition and pExecuteOnlyIfConditionExists is true", function(pTester) - { - db.deleteData("SQL_LIB_TEST_TABLE", "TESTID in ('TEST-7', 'TEST-8')") - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-7", "Ludwig", "Fischer"]); - db.insertData("SQL_LIB_TEST_TABLE", ["TESTID", "FIRSTNAME", "LASTNAME"], null, ["TEST-8", "Franz", "Fischer"]); - - var builder = new SqlBuilder() - .from("SQL_LIB_TEST_TABLE") - - builder.updateData(true, undefined, ["FIRSTNAME"], null, ["Fritz"]); - - var actual1 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-7'") - var actual2 = db.cell("select FIRSTNAME from SQL_LIB_TEST_TABLE where SQL_LIB_TEST_TABLE.TESTID = 'TEST-8'") - - pTester.assert("Ludwig", actual1, "TEST-7 should have Firstname Ludwig"); - pTester.assert("Franz", actual2, "TEST-8 should have Firstname Franz"); - }] -], function preAll() -{ - // remove data which may exist if previous test-run failed and postAll was not executed - cleanWrapperTests() - - // add table for save testing of deletes - db.runStatement("create table SQL_LIB_TEST_TABLE (TESTID varchar(36), FIRSTNAME varchar(100), LASTNAME varchar(100))"); - - // add test persons - db.insertData("PERSON", ["PERSONID", "FIRSTNAME", "LASTNAME", "USER_NEW", "DATE_NEW"], null, ["TEST-5", "Franz", "Müller", "testuser", vars.get("$sys.date")]) - db.insertData("PERSON", ["PERSONID", "FIRSTNAME", "LASTNAME", "USER_NEW", "DATE_NEW"], null, ["TEST-6", "Marco", "Polo", "testuser", vars.get("$sys.date")]) -}, undefined, undefined, function postAll() -{ - cleanWrapperTests() -}) - -var mandatoryErrorTests = new TestSuite([ -// and - ["and without parameter should error", function(pTester) - { - new SqlBuilder().where().or(); - }, SqlBuilder._ERROR_NO_PARAMETER_PROVIDED()], - - ["and with null as value should error", function(pTester) - { - 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); - - new SqlBuilder().where().or("PERSON.FIRSTNAME", "$global.TestingVarNull"); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY_JDITO_VAR()], - - ["and with an empty sql-builder as subquery should error", function(pTester) - { - new SqlBuilder().where().or("PERSON.FIRSTNAME", new SqlBuilder()); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY()], - - ["and with an empty prepared statement as subquery should error", function(pTester) - { - new SqlBuilder().where().or("PERSON.FIRSTNAME", ["", []]); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY()], - - -// or - ["or without parameter should error", function(pTester) - { - new SqlBuilder().where().or(); - }, SqlBuilder._ERROR_NO_PARAMETER_PROVIDED()], - - ["or with null as value should error", function(pTester) - { - 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); - - new SqlBuilder().where().or("PERSON.FIRSTNAME", "$global.TestingVarNull"); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY_JDITO_VAR()], - - ["or with an empty sql-builder as subquery should error", function(pTester) - { - new SqlBuilder().where().or("PERSON.FIRSTNAME", new SqlBuilder()); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY()], - - ["or with an empty prepared statement as subquery should error", function(pTester) - { - new SqlBuilder().where().or("PERSON.FIRSTNAME", ["", []]); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY()], -]); - -var inStatementTests = new TestSuite([ - ["simple and in", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.LASTNAME", ["Franz", "Fritz"], SqlBuilder.IN()) // Note: you can use SqlBuilder.IN(), SqlBuilder.NOT_IN(), "# in ?", etc. as 3rd parameter - .or("PERSON.LASTNAME", ["Peter", "Mayer"], SqlBuilder.IN()); - - pTester.assert(" ( PERSON.LASTNAME in (?, ?) ) or ( PERSON.LASTNAME in (?, ?) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(4, actual._where.preparedValues.length, "number of params"); - }], - - ["simple and not in", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.LASTNAME", ["Franz", "Fritz"], "# not in ?"); // Note: you can use SqlBuilder.IN(), SqlBuilder.NOT_IN(), "# in ?", etc. as 3rd parameter - - pTester.assert(" ( PERSON.LASTNAME not in (?, ?) ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(2, actual._where.preparedValues.length, "number of params"); - }], - - ["in with subquery", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", new SqlBuilder() - .select("PERSON.FIRSTNAME") - .from("PERSON") - .where("PERSON.LASTNAME", "Fritz") - , "# in ?"); // Note: you can use SqlBuilder.IN() instead of "# in ?" - - pTester.assert("PERSON.FIRSTNAME in ( select PERSON.FIRSTNAME from PERSON where PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(1, actual._where.preparedValues.length, "number of params"); - }], - - ["in with prepared statement-array", function(pTester) - { - var actual = new SqlBuilder() - .where("PERSON.FIRSTNAME", ["select PERSON.FIRSTNAME from PERSON where PERSON.LASTNAME = ?", [["Fritz", SQLTYPES.VARCHAR]]] - , "# in ?"); // Note: you can use SqlBuilder.IN() instead of "# in ?" - - pTester.assert("PERSON.FIRSTNAME in ( select PERSON.FIRSTNAME from PERSON where PERSON.LASTNAME = ? ) ", actual._where._sqlStorage, "prepared sql"); - pTester.assert(1, actual._where.preparedValues.length, "number of params"); - }], - - ["andIfSet should ignore empty array", function(pTester) - { - var actual = new SqlBuilder() - .whereIfSet("PERSON.LASTNAME", []); - - pTester.assert("", actual._where._sqlStorage, "prepared sql should be empty"); - pTester.assert(0, actual._where.preparedValues.length, "number of params should be 0"); - }], - - ["and should error on an empty array", function(pTester) - { - new SqlBuilder() - .where("PERSON.LASTNAME", []); - }, SqlBuilder._ERROR_VALUE_IS_MANDATORY()] -]); - -var testConstantFunctions = new TestSuite([ - ["SqlBuilder.IN()", function(pTester) - { - pTester.assert("# in ?", SqlBuilder.IN()); - }], - - ["SqlBuilder.NOT_IN()", function(pTester) - { - pTester.assert("# not in ?", SqlBuilder.NOT_IN()); - }], - - ["SqlBuilder.EXISTS()", function(pTester) - { - pTester.assert("exists ?", SqlBuilder.EXISTS()); - }] -]); - -var selectTests = new TestSuite([ - ["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 = new SqlBuilder() - .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"); - }], - - ["a sql-builder in from is used as subselect", function(pTester) - { - var subQuery = newSelect("FIRSTNAME") - .from("PERSON") - .where("PERSON.LASTNAME", "Meier") - - var actual = new SqlBuilder() - .select("*") - .from(subQuery) - - pTester.assert("from (select FIRSTNAME from PERSON where PERSON.LASTNAME = ?)", actual._from._sqlStorage, "prepared select-sql"); - pTester.assert(1, actual._from.preparedValues.length, "number of params"); - }] -]); - -var joinTests = new TestSuite([ - ["SqlBuilder as on-condition should only add the conditon of the builder", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.NAME", "Adito") - - var actual = new SqlBuilder() - .select("*") - .from("PERSON") - .join("ORGANISATION", subQuery) - - pTester.assert("join ORGANISATION on ORGANISATION.NAME = ?", actual._joins[0]._sqlStorage, "prepared select-sql"); - pTester.assert(1, actual._joins[0].preparedValues.length, "number of params"); - }], - - ["SqlBuilder as table for join is added as subselect", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.NAME", "Adito") - - var actual = new SqlBuilder() - .select("*") - .from("PERSON") - .join(subQuery, "orgname.NAME = TABLE2.NAME", "orgname") - - pTester.assert("join (select NAME from ORGANISATION where ORGANISATION.NAME = ?) orgname on orgname.NAME = TABLE2.NAME", actual._joins[0]._sqlStorage, "prepared select-sql"); - pTester.assert(1, actual._joins[0].preparedValues.length, "number of params"); - }], - - ["just use a string also containing a condition as join without additional condition", function(pTester) - { - var actual = new SqlBuilder() - .select("*") - .from("PERSON") - .join("TABLE1 on TABLE1.NAME = TABLE2.NAME") - - pTester.assert("join TABLE1 on TABLE1.NAME = TABLE2.NAME", actual._joins[0]._sqlStorage, "prepared select-sql"); - pTester.assert(0, actual._joins[0].preparedValues.length, "number of params"); - }] -]); - -var subqueryAsFieldTests = new TestSuite([ - ["Test if a Subselect as field works if pValue is provided. This should be added as subselect.", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID") - .and("PERSON.FIRSTNAME", "val1") // test if the value is added at the correct place - - var actual = new SqlBuilder().where(subQuery, "val2", "# = ?", SQLTYPES.VARCHAR) - .and("PERSON.FIRSTNAME", "val3"); - - - pTester.assert(" ( ( select NAME from ORGANISATION where ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID and PERSON.FIRSTNAME = ? ) = ? ) and PERSON.FIRSTNAME = ?", actual._where._sqlStorage, "prepared select-sql"); - pTester.assert(3, actual._where.preparedValues.length, "number of params"); - pTester.assert("val1", actual._where.preparedValues[0][0], "param 1 is correct value"); - pTester.assert("val2", actual._where.preparedValues[1][0], "param 2 is correct value"); - pTester.assert("val3", actual._where.preparedValues[2][0], "param 3 is correct value"); - }], - - ["Test if a Subselect as field should error if no SQLTYPE is provided.", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID") - .and("PERSON.FIRSTNAME", "val1") // test if the value is added at the correct place - new SqlBuilder().where(subQuery, "val2", "# = ?"); - }, SqlBuilder._ERROR_SUBSELECT_AS_FIELD_NO_FIELD_TYPE()], - - ["Test if a Subselect as field should error if it is not a full select.", function(pTester) - { - var subQuery = newSelect("NAME") - .where("ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID") - .and("PERSON.FIRSTNAME", "val1") // test if the value is added at the correct place - - new SqlBuilder().where(subQuery, "val2", "# = ?", SQLTYPES.VARCHAR); - }, SqlBuilder._ERROR_SUBSELECT_AS_FIELD_NOT_COMPLETE()] -]); - -var conditionFormatTests = new TestSuite([ - ["pCondition should not fail if # an ? exist in correct order", function(pTester) - { - new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "# = ?") - .and("PERSON.FIRSTNAME", "val1", "asdf # fdsa=asdf ?fdas") - }], - - ["pCondition should not fail if # an ? exist in correct order and there are additional, escaped # and ?", function(pTester) - { - new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "\\? # \\#= ?"); - }], - - ["pCondition should not fail if only ? exists", function(pTester) - { - new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "?") - }], - - ["pCondition should fail if more than one ? exists", function(pTester) - { - new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "? test ?") - }, SqlBuilder._ERROR_CONDITION_WRONG_FORMAT()], - - ["pCondition should fail if more than one # exists", function(pTester) - { - new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "# test #") - }, SqlBuilder._ERROR_CONDITION_WRONG_FORMAT()], - - ["pCondition should fail if # and ? are in wrong order", function(pTester) - { - new SqlBuilder().where("PERSON.FIRSTNAME", "val1", "? = #") - }, SqlBuilder._ERROR_CONDITION_WRONG_FORMAT()] -]); - -var subqueryAliasTests = new TestSuite([ - ["subselectAlias should be added for subquery in .select", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.NAME", "Adito") - .subselectAlias("testAlias") - - var actual = new SqlBuilder() - .select([subQuery, "FIRSTNAME"]) - .from("PERSON") - - pTester.assert("select (select NAME from ORGANISATION where ORGANISATION.NAME = ?) testAlias, FIRSTNAME", actual._select._sqlStorage, "prepared select-sql"); - pTester.assert(1, actual._select.preparedValues.length, "number of params"); - }], - - ["subselectAlias should be added for subquery in .from", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.NAME", "Adito") - .subselectAlias("testAlias") - - var actual = new SqlBuilder() - .from(subQuery) - - pTester.assert("from (select NAME from ORGANISATION where ORGANISATION.NAME = ?) testAlias", actual._from._sqlStorage, "prepared select-sql"); - pTester.assert(1, actual._from.preparedValues.length, "number of params"); - }], - - ["subselectAlias should be overruled by the param in in .from", function(pTester) - { - var subQuery = newSelect("NAME") - .from("ORGANISATION") - .where("ORGANISATION.NAME", "Adito") - .subselectAlias("testAlias") - - var actual = new SqlBuilder() - .from(subQuery, "overwriteAlias") - - pTester.assert("from (select NAME from ORGANISATION where ORGANISATION.NAME = ?) overwriteAlias", actual._from._sqlStorage, "prepared select-sql"); - pTester.assert(1, actual._from.preparedValues.length, "number of params"); - }], - - ["subselectAlias should be added for subquery in .join", function(pTester) - { - var subQuery = newSelect("NAME, ORGANISATIONID") - .from("ORGANISATION") - .where("ORGANISATION.NAME", "Adito") - .subselectAlias("testAlias") - - var actual = new SqlBuilder() - .from("CONTACT") - .join(subQuery, "testAlias.ORGANISATIONID = ORGANISATION_ID") - .join(subQuery, "testAlias.ORGANISATIONID = ORGANISATION_ID", "overwriteAlias") - - pTester.assert("join (select NAME, ORGANISATIONID from ORGANISATION where ORGANISATION.NAME = ?) testAlias on testAlias.ORGANISATIONID = ORGANISATION_ID", actual._joins[0]._sqlStorage, "prepared select-sql join 1"); - pTester.assert(1, actual._joins[0].preparedValues.length, "number of params join 1"); - - pTester.assert("join (select NAME, ORGANISATIONID from ORGANISATION where ORGANISATION.NAME = ?) overwriteAlias on testAlias.ORGANISATIONID = ORGANISATION_ID", actual._joins[1]._sqlStorage, "prepared select-sql join 2"); - pTester.assert(1, actual._joins[1].preparedValues.length, "number of params join 2"); - }] -]) - -var tester = new Tester("Test SqlBuilder"); -tester.test(newSelectTests); -tester.test(validAndUsageTests); -tester.test(validOrUsageTests); -tester.test(combinedAndOrTests); -tester.test(ifSetTests); -tester.test(dbWrapperTests); -tester.test(mandatoryErrorTests); -tester.test(inStatementTests); -tester.test(testConstantFunctions); -tester.test(selectTests); -tester.test(joinTests); -tester.test(subqueryAsFieldTests); -tester.test(conditionFormatTests); -tester.test(subqueryAliasTests); - -logging.log("-------------------------"); -tester.printResults(); diff --git a/process/SqlMaskingUtils_test/SqlMaskingUtils_test.aod b/process/SqlMaskingUtils_test/SqlMaskingUtils_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..8636a3707b101a2e7e0b22e10e54c6d596508b53 --- /dev/null +++ b/process/SqlMaskingUtils_test/SqlMaskingUtils_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>SqlMaskingUtils_test</name> + <title>[TEST] Sql_lib - SqlMaskingUtils</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/SqlMaskingUtils_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/SqlMaskingUtils_test/process.js b/process/SqlMaskingUtils_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..533a1b32e9411f7e4af25222bfb28a6758b5edf3 --- /dev/null +++ b/process/SqlMaskingUtils_test/process.js @@ -0,0 +1,158 @@ +import("system.result"); +import("system.db"); +import("Sql_lib"); +import("UnitTest_lib"); + +function _createDummyMaskingUtil(pDbType) +{ + var currentAlias = db.getCurrentAlias(); + if (!currentAlias) + throw new Error("alias required for test is not set"); + var currentAliasType = db.getDatabaseType(currentAlias); + if (!currentAliasType) + throw new Error("alias type required for test is not set"); + var createdObject = new SqlMaskingUtils(currentAlias); + createdObject.dbType = pDbType; + return createdObject; +} + +var constructorTest = new TestSuite("SqlMaskingUtils.constructor", [ + new Test("constructor sets correct specified alias", + function(pTester) + { + var currentAlias = db.getCurrentAlias(); + if (!currentAlias) + throw new Error("alias required for test is not set"); + var createdObject = new SqlMaskingUtils(currentAlias); + pTester.expectThat(createdObject.alias).equals(currentAlias).assert(); + } + ), + new Test("constructor sets correct default alias", + function(pTester) + { + var currentAlias = db.getCurrentAlias(); + if (!currentAlias) + throw new Error("alias required for test is not set"); + var createdObject = new SqlMaskingUtils(); + pTester.expectThat(createdObject.alias).equals(currentAlias).assert(); + } + ), + new Test("constructor sets correct alias type", + function(pTester) + { + var currentAlias = db.getCurrentAlias(); + if (!currentAlias) + throw new Error("alias required for test is not set"); + var currentAliasType = db.getDatabaseType(currentAlias); + if (!currentAliasType) + throw new Error("alias type required for test is not set"); + var createdObject = new SqlMaskingUtils(currentAlias); + pTester.expectThat(createdObject.dbType).equals(currentAliasType).assert(); + } + ), + new Test("overwrite constructors dbType with derby", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_DERBY10); + pTester.expectThat(res.dbType).equals(db.DBTYPE_DERBY10).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with mariaDB", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_MARIADB10); + pTester.expectThat(res.dbType).equals(db.DBTYPE_MARIADB10).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with mySql", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_MYSQL4); + pTester.expectThat(res.dbType).equals(db.DBTYPE_MYSQL4).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with oracle-cluster", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_ORACLE10_CLUSTER); + pTester.expectThat(res.dbType).equals(db.DBTYPE_ORACLE10_CLUSTER).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with oracle-oci", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_ORACLE10_OCI); + pTester.expectThat(res.dbType).equals(db.DBTYPE_ORACLE10_OCI).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with oracle-thin", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_ORACLE10_THIN); + pTester.expectThat(res.dbType).equals(db.DBTYPE_ORACLE10_THIN).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with postgresql", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_POSTGRESQL8); + pTester.expectThat(res.dbType).equals(db.DBTYPE_POSTGRESQL8).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ), + new Test("overwrite constructors dbType with ms sql", + function(pTester) + { + var res = _createDummyMaskingUtil(db.DBTYPE_SQLSERVER2000); + pTester.expectThat(res.dbType).equals(db.DBTYPE_SQLSERVER2000).assert(); + pTester.expectThat(res.alias).isNull().assert(); + } + ) + ]); + + +var getConcatSymbolTest = new TestSuite("SqlMaskingUtils.getConcatSymbol", [ + new Test("getConcatSymbol returns a non empty string", + function(pTester) + { + var maskingHelper = _createDummyMaskingUtil(db.DBTYPE_SQLSERVER2000); + var res = maskingHelper.getConcatSymbol(); + pTester.expectThat(res).not().isNull().assert(); + pTester.expectThat(res).not().isUndefined().assert(); + pTester.expectThat(res).isString().assert(); + pTester.expectThat(res.length).isInteger().assert(); + pTester.expectThat(res.length).isGreater(0).assert(); + } + ), + new Test("+ for MS SQL", + function(pTester) + { + var maskingHelper = _createDummyMaskingUtil(db.DBTYPE_SQLSERVER2000); + var res = maskingHelper.getConcatSymbol(); + pTester.expectThat(res.trim()).equals("+").assert(); + } + ), + new Test("|| for Oracle", + function(pTester) + { + var maskingHelper = _createDummyMaskingUtil(db.DBTYPE_ORACLE10_THIN); + var res = maskingHelper.getConcatSymbol(); + pTester.expectThat(res.trim()).equals("||").assert(); + } + ) + ]); + +var tester = new Tester("Test SqlMaskingUtils"); +tester.initCoverage(SqlMaskingUtils); +tester.test(constructorTest); +tester.test(getConcatSymbolTest); +//TODO: add full test coverage +tester.summary(); + +result.object(tester.getResults()); \ No newline at end of file diff --git a/process/Sql_lib/documentation.adoc b/process/Sql_lib/documentation.adoc index 8b903c2155e9d54f160b06ef6fa80a586a8335e6..417d8aa237bf0311576e048625e9b055ff1e2db8 100644 --- a/process/Sql_lib/documentation.adoc +++ b/process/Sql_lib/documentation.adoc @@ -17,10 +17,10 @@ include::_default_attributes_EN.adoc[] This document describes the functionality and the usage of the SqlBuilder, which is included in the library *Sql_lib* of the ADITO xRM project (see "Projects" window, under process > libraries). The documentation may not contain all features of the SqlBuilder. It is supplemental to the documentation you find in the code itself: A usage will often be possible in an intuitive way, so just try coding using code completion and JSDoc, where all parameters are documented. -You may also take a look at the library *SqlLib_tests* (also under process > libraries), as it contains many possible ways to use the SqlBuilder. +You may also take a look at the library *Sql_test* (also under process > libraries), as it contains many possible ways to use the SqlBuilder. [NOTE] -The tests included in the library SqlLib_tests use the UnitTest_lib for unit testing. You can use this functionality also in other contexts, according to your requirements. +The tests included in the library Sql_test use the UnitTest_lib for unit testing. You can use this functionality also in other contexts, according to your requirements. == Benefits diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js index 35b87999459da0cd88f21f0b11c737c3060ce26e..75c6923e24957c4f574efec077d73d60d9a52680 100644 --- a/process/Sql_lib/process.js +++ b/process/Sql_lib/process.js @@ -801,8 +801,6 @@ function SqlBuilder (pAlias) this._where = {}; this._initWhere(); - - SqlBuilder.defineCanBuildSql(this); } /** @@ -823,6 +821,8 @@ SqlBuilder.checkCanBuildSql = function (pObject) return pObject[SqlBuilder.getCanBuildSqlSymbol()]; } +SqlBuilder.defineCanBuildSql(SqlBuilder.prototype); + /** * Deep copies the SqlBuilder object and returns a new one.<br/> * Use this if you want to add for example add additional parameters without modifying the current builder. @@ -830,25 +830,7 @@ SqlBuilder.checkCanBuildSql = function (pObject) */ SqlBuilder.prototype.copy = function() { - var newBuilder = _deepCopyByJson(this, new SqlBuilder()); - return newBuilder; - - // NOTE: this works only with simple data types. - // Here we only use strings, arrays, booleans and null, so this should work - function _deepCopyByJson(pObject, pNewObject) - { - // deep copy by using json - var deepCopied = JSON.parse(JSON.stringify(pObject)); - - // set the props of the new object to the deepCopied ones. - // without this all functions would be lost - for (let prop in deepCopied) - { - pNewObject[prop] = deepCopied[prop] - } - - return pNewObject; - } + return Utils.clone(this); } // errors which are thrown by the SqlBuilder @@ -3100,6 +3082,14 @@ SqlBuilder.caseWhen = function (pFieldOrCond, pValue, pCondition, pFieldType) return new SqlBuilder._CaseStatement().when(pFieldOrCond, pValue, pCondition, pFieldType); } +/** + * @return {SqlBuilder._CaseStatement} + */ +SqlBuilder.caseStatement = function () +{ + return new SqlBuilder._CaseStatement(); +} + /** * Represents a case-when statement */ @@ -3109,9 +3099,10 @@ SqlBuilder._CaseStatement = function () this._whenThens = []; this._elseValue = null; this._afterWhenMask = new SqlBuilder._CaseWhen(this); - SqlBuilder.defineCanBuildSql(this); } +SqlBuilder.defineCanBuildSql(SqlBuilder._CaseStatement.prototype); + /** * @param {String|String[]|SqlBuilder|PreparedSqlArray} [pFieldOrCond] If this is the only parameter, it is used as Subselect <br/> * else it is used as Field. <br/> @@ -3167,7 +3158,7 @@ SqlBuilder._CaseStatement.prototype.toString = function (pAlias) return db.translateStatement(this.build(), pAlias || db.getCurrentAlias()); } -SqlBuilder._CaseStatement.prototype.build = function () +SqlBuilder._CaseStatement.prototype.build = function (pParameters) { var caseStatement = ["case"]; var preparedValues = []; @@ -3373,6 +3364,8 @@ SqlMaskingUtils.prototype.cast = function (pField, pTargetDatatype, pTargetLengt return "char"; case SQLTYPES.VARCHAR: return "char"; + case SQLTYPES.NVARCHAR: + return "nvarchar"; case SQLTYPES.INTEGER: return "int"; case SQLTYPES.DECIMAL: @@ -3388,6 +3381,7 @@ SqlMaskingUtils.prototype.cast = function (pField, pTargetDatatype, pTargetLengt case db.DBTYPE_DERBY10: switch(pTargetDatatype) { + case SQLTYPES.NVARCHAR: case SQLTYPES.VARCHAR: // Because of a Derby bug, you can't cast INTEGER into VARCHAR // Therefor first cast to char then to varchar @@ -3412,6 +3406,7 @@ SqlMaskingUtils.prototype.cast = function (pField, pTargetDatatype, pTargetLengt case db.DBTYPE_MYSQL4: switch(pTargetDatatype) { + case SQLTYPES.NVARCHAR: case SQLTYPES.VARCHAR: case SQLTYPES.CHAR: case SQLTYPES.INTEGER: @@ -3429,6 +3424,9 @@ SqlMaskingUtils.prototype.cast = function (pField, pTargetDatatype, pTargetLengt case SQLTYPES.VARCHAR: sqlDataType = "varchar2"; break; + case SQLTYPES.NVARCHAR: + sqlDataType = "nvarchar2"; + break; case SQLTYPES.INTEGER: sqlDataType = "number"; pTargetLength = "10" @@ -3448,18 +3446,23 @@ SqlMaskingUtils.prototype.cast = function (pField, pTargetDatatype, pTargetLengt case SQLTYPES.INTEGER: case SQLTYPES.CHAR: case SQLTYPES.VARCHAR: + case SQLTYPES.NVARCHAR: sqlDataType = _mapDefaults(pTargetDatatype); break; } break; case db.DBTYPE_SQLSERVER2000: - case SQLTYPES.DATE: - case SQLTYPES.DECIMAL: - case SQLTYPES.INTEGER: - case SQLTYPES.CHAR: - case SQLTYPES.VARCHAR: - sqlDataType = _mapDefaults(pTargetDatatype); - break; + switch(pTargetDatatype) + { + case SQLTYPES.DATE: + case SQLTYPES.DECIMAL: + case SQLTYPES.INTEGER: + case SQLTYPES.CHAR: + case SQLTYPES.VARCHAR: + case SQLTYPES.NVARCHAR: + sqlDataType = _mapDefaults(pTargetDatatype); + break; + } //TODO: firebird support? } @@ -3589,7 +3592,7 @@ SqlMaskingUtils.prototype.concat = function (pFields, pSeparator, pAutoTrimField if (pSeparator === null || pSeparator === undefined) pSeparator = "' '"; - else if (pSeparator) + else if (pSeparator || pSeparator === "") pSeparator = "'" + db.quote(pSeparator, this.alias) + "'"; var doEmptyStringCheck = true; @@ -4152,7 +4155,7 @@ SqlUtils.getResolvingCaseWhen = function(pKeyValueArray, pDbFieldName, pLocale) else return translate.text(value); }; - + //!SqlBuilder var resSql = "case ", preparedValues = []; var colTypeKeyId = SQLTYPES.CHAR; var colTypeTitle = SQLTYPES.NVARCHAR; diff --git a/process/SqlLib_tests/SqlLib_tests.aod b/process/Terminal_lib/Terminal_lib.aod similarity index 67% rename from process/SqlLib_tests/SqlLib_tests.aod rename to process/Terminal_lib/Terminal_lib.aod index 9f2866f8f91251c708400d6998ee92c248385334..9fa0811425e089b731f59a376c4089e526725b17 100644 --- a/process/SqlLib_tests/SqlLib_tests.aod +++ b/process/Terminal_lib/Terminal_lib.aod @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> - <name>SqlLib_tests</name> + <name>Terminal_lib</name> <majorModelMode>DISTRIBUTED</majorModelMode> - <process>%aditoprj%/process/SqlLib_tests/process.js</process> - <alias>Data_alias</alias> + <documentation>%aditoprj%/process/Terminal_lib/documentation.adoc</documentation> + <process>%aditoprj%/process/Terminal_lib/process.js</process> <variants> <element>LIBRARY</element> </variants> diff --git a/process/Terminal_lib/process.js b/process/Terminal_lib/process.js new file mode 100644 index 0000000000000000000000000000000000000000..13a0188495d15d6728d4560c288546ccc0c9d283 --- /dev/null +++ b/process/Terminal_lib/process.js @@ -0,0 +1,342 @@ +import("system.logging"); +import("Util_lib"); + + +/** + * This library gives you helpful colored output on the terminal + * You can use the predefined helper methods or use your own color- and format combinations + * + * @example + * var t = new Terminal(); + * logging.log(t.success("It works!")); + * logging.log(t.color(t.fg.green).background(t.bg.red).output("I would never use green text on red background...")); + * + * @see https://en.wikipedia.org/wiki/ANSI_escape_code + * @class + */ +function Terminal() +{ + this.mod = { + reset : 0 + }; + + this.fg = { + reset : 39, + black : 30, + red : 31, + green : 32, + yellow : 33, + blue : 34, + magenta : 35, + cyan : 36, + white : 37, + brightBlack : 90, + brightRed : 91, + brightGreen : 92, + brightYellow : 93, + brightBlue : 94, + brightMagenta : 95, + brightCyan : 96, + brightWhite : 97 + }; + + this.bg = { + reset : 49, + black : 40, + red : 41, + green : 42, + yellow : 43, + blue : 44, + magenta : 45, + cyan : 46, + white : 47, + brightBlack : 100, + brightRed : 101, + brightGreen : 102, + brightYellow : 103, + brightBlue : 104, + brightMagenta : 105, + brightCyan : 106, + brightWhite : 107 + }; + + this.formats = { + weightBold : 1, + weightLight : 2, + weightOff : 22, + italic : 3, + italicOff : 23, + underline : 4, + underlineDouble : 21, + underlineOff : 24, + strike : 9, + strikeOff : 29 + }; + + this._defaultConfig = { + colorText: this.fg.reset, + colorBackground: this.bg.reset, + bold: this.formats.weightOff, + italic: this.formats.italicOff, + underline: this.formats.underlineOff, + strike: this.formats.strikeOff + }; + + this.outputConfig = Utils.clone(this._defaultConfig); +} + + +/** + * Reset the output config by cloning and setting the default + * + * @return {void} + */ +Terminal.prototype._resetConfig = function () +{ + this.outputConfig = Utils.clone(this._defaultConfig); +} + +/** + * Set or reset the text color + * + * @param {int} pValue + * @return {Terminal} + */ +Terminal.prototype.color = function (pValue) +{ + this.outputConfig.colorText = this._contains(this.fg, pValue) ? pValue : this.fg.reset; + + return this; +} + +/** + * Set or reset the background color + * + * @param {int} pValue + * @return {Terminal} + */ +Terminal.prototype.background = function (pValue) +{ + this.outputConfig.colorBackground = this._contains(this.bg, pValue) ? pValue : this.bg.reset; + + return this; +} + +/** + * Set, unset or add a formatting to the output config + * + * @param {int} pValue + * @return {Terminal} + */ +Terminal.prototype.format = function (pValue) +{ + var allowedWeightValues = [this.formats.weightBold, this.formats.weightLight, this.formats.weightOff]; + this.outputConfig.bold = this._contains(allowedWeightValues, pValue) ? pValue : this.formats.weightOff; + + var allowedItalicValues = [this.formats.italic, this.formats.italicOff]; + this.outputConfig.italic = this._contains(allowedItalicValues, pValue) ? pValue : this.formats.italicOff; + + var allowedUnderlineValues = [this.formats.underline, this.formats.underlineDouble, this.formats.underlineOff]; + this.outputConfig.underline = this._contains(allowedUnderlineValues, pValue) ? pValue : this.formats.underlineOff; + + var allowedStrikeValues = [this.formats.strike, this.formats.strikeOff]; + this.outputConfig.strike = this._contains(allowedStrikeValues, pValue) ? pValue : this.formats.strikeOff; + + return this; +} + +/** + * Returns a string wrapped in escape sequences according to previous formatting instructions + * Must be called after `.color()`, `.background()` and/or `.format()`. + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.output = function (pString) +{ + var output = ""; + var seqValues = []; + + Object.keys(this.outputConfig).forEach(function(pKey) { + seqValues.push(this.outputConfig[pKey]); + }, this); + + output += this._generateSequence(seqValues); + output += pString; + output += this._generateSequence(this.mod.reset); + + this._resetConfig(); + return output; +} + +/** + * Returns the given string formatted as light-colored text + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.debug = function (pString) +{ + return this.color(this.fg.white).output(pString); +} + +/** + * Returns the given string formatted as bold black text on green background + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.successBlock = function (pString) +{ + return this.color(this.fg.brightBlack).background(this.bg.green).format(this.formats.weightBold).output(pString); +} + +/** + * Returns the given string formatted as bold green text + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.success = function (pString) +{ + return this.color(this.fg.green).format(this.formats.weightBold).output(pString); +} + +/** + * Returns the given string formatted as bold black text on green background + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.successBlock = function (pString) +{ + return this.color(this.fg.brightBlack).background(this.bg.green).format(this.formats.weightBold).output(" " + pString + " "); +} + +/** + * Returns the given string formatted as bold blue text + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.info = function (pString) +{ + return this.color(this.fg.blue).format(this.formats.weightBold).output(pString); +} + +/** + * Returns the given string formatted as bold white text on blue background + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.infoBlock = function (pString) +{ + return this.color(this.fg.brightWhite).background(this.bg.blue).format(this.formats.weightBold).output(" " + pString + " "); +} + +/** + * Returns the given string formatted as bold magenta text + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.important = function (pString) +{ + return this.color(this.fg.magenta).format(this.formats.weightBold).output(pString); +} + +/** + * Returns the given string formatted as bold white text on magenta background + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.importantBlock = function (pString) +{ + return this.color(this.fg.brightWhite).background(this.bg.magenta).format(this.formats.weightBold).output(" " + pString + " "); +} + +/** + * Returns the given string formatted as bold yellow text + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.warning = function (pString) +{ + return this.color(this.fg.yellow).format(this.formats.weightBold).output(pString); +} + +/** + * Returns the given string formatted as bold black text on yellow background + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.warningBlock = function (pString) +{ + return this.color(this.fg.brightBlack).background(this.bg.yellow).format(this.formats.weightBold).output(" " + pString + " "); +} + +/** + * Returns the given string formatted as bold red text + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.error = function (pString) +{ + return this.color(this.fg.red).format(this.formats.weightBold).output(pString); +} + +/** + * Returns the given string formatted as bold white text on red background + * + * @param {String} pString the string to format + * @return {String} + */ +Terminal.prototype.errorBlock = function (pString) +{ + return this.color(this.fg.brightWhite).background(this.bg.red).format(this.formats.weightBold).output(" " + pString + " "); +} + +/** + * Checks if a specific value is in a given array or object + * + * @param {(Array|Object)} pType + * @param {Any} pValue + * @return {Boolean} + */ +Terminal.prototype._contains = function (pType, pValue) +{ + var res = false; + + if(Array.isArray(pType)) { + res = pType.indexOf(pValue) !== -1; + } else { + Object.keys(pType).forEach(function(pKey) { + if(pType[pKey] === pValue) { + res = true; + } + }, this); + } + + return res; +} + +/** + * Generates and returns a terminal escape sequence + * + * @param {(int|int[])} pSequences A single or multiple escape sequence commands + */ +Terminal.prototype._generateSequence = function (pSequences) +{ + var seq = Array.isArray(pSequences) ? pSequences : [pSequences]; + + seq = seq.filter(function(pElement) { + return Number.isInteger(parseFloat(pElement)) && isFinite(pElement); + }); + + return "\033[" + seq.join(";") + "m"; +} diff --git a/process/Turnover_lib/process.js b/process/Turnover_lib/process.js index 14080be4ee9b533ea4a1c88331e3d6f45f64f364..1e69ad37d5f05c94e3779b5fe5c6edb3fe81cbc5 100644 --- a/process/Turnover_lib/process.js +++ b/process/Turnover_lib/process.js @@ -26,24 +26,45 @@ function TurnoverUtil() {} */ TurnoverUtil.getTurnoverData = function (pMaxYear, pYearCount, pSalesprojectId) { - var turnoverCategory = translate.text('Turnover'); - + var turnoverCategory = translate.text("Turnover"); var minYear = pMaxYear - pYearCount + 1; + var sqlMask = new SqlMaskingUtils(); // load data - return newSelect("'" + turnoverCategory + "', year(SALESORDERDATE) yearNum, month(SALESORDERDATE) monthNum, SALESORDERITEM.DISCOUNT discount, SALESORDERITEM.VAT vat, SALESORDERITEM.PRICE price, sum(SALESORDERITEM.QUANTITY) quantity, SALESORDERITEM.GROUPCODEID prodGroup, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.productGroupcode(), "SALESORDERITEM.GROUPCODEID") + ") prodGroupName") - .from("SALESORDER") - .join("SALESORDERITEM", "SALESORDERITEM.SALESORDER_ID = SALESORDER.SALESORDERID") - .where("SALESORDER.ORDERTYPE = 'ORDTYPEINVO'") - .and("SALESORDER.ORDERSTATUS = 1") - .and("SALESORDER.CANCELLATION <> 1") - .and("SALESORDERITEM.OPTIONAL <> 1") - .and("SALESORDER.SALESORDERDATE", pMaxYear, "year(#) <= ?", SQLTYPES.INTEGER) - .and("SALESORDER.SALESORDERDATE", minYear, "year(#) >= ?", SQLTYPES.INTEGER) - .andIfSet("SALESORDER.SALESPROJECT_ID", pSalesprojectId) - .groupBy("year(SALESORDERDATE), month(SALESORDERDATE), SALESORDERITEM.GROUPCODEID, SALESORDERITEM.DISCOUNT, SALESORDERITEM.VAT, SALESORDERITEM.PRICE") - .orderBy("yearNum, monthNum") - .table(); + + return newSelect([ + "'" + turnoverCategory + "'", + sqlMask.yearFromDate("SALESORDERDATE"), + sqlMask.monthFromDate("SALESORDERDATE"), + "SALESORDERITEM.DISCOUNT", + "SALESORDERITEM.VAT", + "SALESORDERITEM.PRICE", + "sum(SALESORDERITEM.QUANTITY)", + "SALESORDERITEM.GROUPCODEID", + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.productGroupcode(), "SALESORDERITEM.GROUPCODEID") + ]) + .from("SALESORDER") + .join("SALESORDERITEM", "SALESORDERITEM.SALESORDER_ID = SALESORDER.SALESORDERID") + .where("SALESORDER.ORDERTYPE", "ORDTYPEINVO") + .and("SALESORDER.ORDERSTATUS", "1") + .and("SALESORDER.CANCELLATION", "1", SqlBuilder.NOT_EQUAL()) + .and("SALESORDERITEM.OPTIONAL", "1", SqlBuilder.NOT_EQUAL()) + .and("SALESORDER.SALESORDERDATE", pMaxYear, sqlMask.yearFromDate("#") + " <= ?", SQLTYPES.INTEGER) + .and("SALESORDER.SALESORDERDATE", minYear, sqlMask.yearFromDate("#") + " >= ?", SQLTYPES.INTEGER) + .andIfSet("SALESORDER.SALESPROJECT_ID", pSalesprojectId) + .groupBy([ + sqlMask.yearFromDate("SALESORDERDATE"), + sqlMask.monthFromDate("SALESORDERDATE"), + "SALESORDERITEM.GROUPCODEID", + "SALESORDERITEM.DISCOUNT", + "SALESORDERITEM.VAT", + "SALESORDERITEM.PRICE" + ]) + .orderBy([ + sqlMask.yearFromDate("SALESORDERDATE"), + sqlMask.monthFromDate("SALESORDERDATE") + ]) + .table(); } /** diff --git a/process/UnitTest_lib/UnitTest_lib.aod b/process/UnitTest_lib/UnitTest_lib.aod index 225ac2303844a684c92ac95b0426318362598cb0..a44993167651207727a423951deff7db60238dfb 100644 --- a/process/UnitTest_lib/UnitTest_lib.aod +++ b/process/UnitTest_lib/UnitTest_lib.aod @@ -2,6 +2,7 @@ <process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> <name>UnitTest_lib</name> <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE_O</icon> <process>%aditoprj%/process/UnitTest_lib/process.js</process> <alias>Data_alias</alias> <variants> diff --git a/process/UnitTest_lib/process.js b/process/UnitTest_lib/process.js index 0ce141d4828e7b396f4cc4368c4daae06aec5dd1..382d37e021567c924734a1350a7a368acd1796d3 100644 --- a/process/UnitTest_lib/process.js +++ b/process/UnitTest_lib/process.js @@ -1,235 +1,1265 @@ import("system.logging"); +import("Terminal_lib"); +import("Util_lib"); + +/** + * @param {String} pName the name/description of the test + * @param {Function} pCallback the actual test callback to execute + * @param {Function} pDataProviderCallback an optional callback to deliver multiple datasets to the test + * @param {Boolean} pRerunOnError an optional flag indicating if a test should get rerun without try-catch if an error occurs (default: false) + * + * @class + */ +function Test(pName, pCallback, pDataProviderCallback, pRerunOnError) +{ + this.name = pName; + this.callback = pCallback; + this.dataProviderCallback = pDataProviderCallback || function() { return null; }; + this.rerunOnError = !!pRerunOnError; +} /** * A TestSuite combines several tests - * @param {Array} pTests this is a n array of Tests in the following form:<br/> - * [<br/> - * ["Test description", function(pTester) <br/> - * {<br/> - * // the test which may use pTester.assert(...)<br/> - * }, {Optional: an expected error}<br/> - * ],<br/> - * [...]<br/> - * ]<br/> + * + * @param {String} pName name of the TestSuite + * @param {Array} pTests this is a n array of Tests + * + * @example + * var myTest = new TestSuite("MyObject.myTest", [ + * new Test("Test description", + * function(pTester) { + * var expectValue = 5; + * var var actualValue = 20; + * pTester.expectThat(actualValue).isGreater(expectValue).assert(); + * }, + * ), + * new Test(...) + * ]; + + * @example + * // Using a DataProvider + * var myTest = new TestSuite("MyObject.myTest", [ + * new Test("Test description", + * function(pTester, pDataProvider) { + * var obj = new MyObject("Something"); + * var expectValue = pDataProvider[0]; + * var var actualValue = obj.getNumber(); + * pTester.expectThat(actualValue).isGreater(expectValue).assert(); + * }, + * function dataProvider() { + * return [ + * [0], + * [10], + * [100], + * ]; + * }, + * ), + * new Test(...) + * ]; + * * @param {functionCallback} [pPreAll] a callback, called once before all tests * @param {functionCallback} [pPreTest] a callback, called once before each test * @param {functionCallback} [pPostTest] a callback, called once after each test * @param {functionCallback} [pPostAll] a callback, called once after all tests - * + * + * TODO: set callbacks via separate methods + * * @class */ -function TestSuite(pTests, pPreAll, pPreTest, pPostTest, pPostAll) +function TestSuite(pName, pTests, pPreAll, pPreTest, pPostTest, pPostAll) { + this.name = pName; this.tests = pTests; - this.preAll = (pPreAll ? pPreAll : function() {}); - this.preTest = (pPreTest ? pPreTest : function() {}); - this.postTest = (pPostTest ? pPostTest : function() {}); - this.postAll = (pPostAll ? pPostAll : function() {}); + this.preAll = pPreAll || function() {}; + this.preTest = pPreTest || function() {}; + this.postTest = pPostTest || function() {}; + this.postAll = pPostAll || function() {}; } /** - * The tester can test TestSuites. - * It will be passed as paramter to each test. - * + * The tester runs TestSuites. + * It will be passed as parameter to each test. + * * @param {String} pCollectionName + * + * @example + * var myTest = new TestSuite("MyObject.myTest", [...]); + * var tester = new Tester("Test SqlBuilder", SqlBuilder); + * tester.test(myTest); + * // More test suites using tester.test() + * // ... + * + * tester.summary(); + * + * @class + * + * TODO: Implement `isEmpty()` + * TODO: Implement `hasKey()` + * TODO: Implement `contains()` + * TODO: Implement `containsIgnoreCase()` + * TODO: Implement `isPrimitive()` + * TODO: Implement `matches()` + * TODO: Implement `matchesIgnoreCase()` + * TODO: Move multiple used code blocks into separate methods (like the logging output + reset) + * TODO: Use more getters, especially when implementing `elementAt()` + * TODO: Add examples to test methods + */ +function Tester(pCollectionName) +{ + this.collectionName = pCollectionName; + this.instanceName = undefined; + this.methods = []; + this.methodsCalled = []; + + this.actualValue = undefined; + this.actualDisplayValue = undefined; + this.actualOriginalValue = undefined; + this.actualOriginalDisplayValue = undefined; + this.actualValueElementHierarchy = []; + this.expectedValue = undefined; + this.expectedDisplayValue = undefined; + this._assertDescription = ""; + this._testResult = false; + this._useNegation = false; + this.dataProvider = undefined; + this.currentTestSuite = undefined; + + this.testCount = 0; + this.successCount = 0; + this.failCount = 0; + this.startTime = new Date().getTime(); + this.endTime = null; + + this.t = new Terminal(); + this.outputEnabled = true; + this.output = ""; +} + +/** + * Set the value to test + * + * @param {*} pValue + * @return {Tester} + */ +Tester.prototype.expectThat = function(pValue) +{ + this.actualValue = pValue; + this.actualDisplayValue = pValue; + this.actualOriginalValue = pValue; + this.actualOriginalDisplayValue = pValue; + this._useNegation = false; + + return this; +} + +/** + * Retrieve the result of the current test + * + * @return {Boolean} + */ +Tester.prototype.getTestResult = function() +{ + return this._useNegation ? !this._testResult : this._testResult; +} + +/** + * Enable or disable the output + * + * @param {Boolean} pIsEnabled whether the output should be enabled or not + * @return {Tester} + */ +Tester.prototype.setOutputEnabled = function(pIsEnabled) +{ + this.outputEnabled = pIsEnabled; + return this; +} + +/** + * Assert makes the test eventually pass or fail by looking at the result and writing into the output + * + * @return {void} + */ +Tester.prototype.assert = function() +{ + if(this.getTestResult() === true) + { + this.successCount++; + this._log("success", "\t\t\u2705 " + this._assertDescription); + } + else + { + this.failCount++; + this._log("error", "\t\t\u274C " + this._assertDescription); + + if(this.actualDisplayValue !== undefined && this.expectedDisplayValue !== undefined) + { + this._log("warning", "\t\t\t expected: " + JSON.stringify(this.expectedDisplayValue, null, "\t")); + this._log("error", "\t\t\t actual: " + JSON.stringify(this.actualDisplayValue, null, "\t")); + } + } +} + +/** + * Activate test negation + * + * @return {Tester} + */ +Tester.prototype.not = function() +{ + this._useNegation = true; + + return this; +} + +/** + * Select a child element of `actualValue` to work with + * + * @param {(String|Number)} pKey the key of the child + * @return {Tester} * * @example - * var tester = new Tester("Test SqlBuilder"); - * tester.test(newSelectTests); - * tester.test(validAndUsageTests); - * tester.test(validOrUsageTests); + * // Grab first array element to test + * pTester.expectThat(actualValue).elementAt(0).equals("MyValue").assert(); * - * logging.log("-------------------------"); - * tester.printResults(); + * // Grab last array element to test + * pTester.expectThat(actualValue).elementAt(-1).equals("MyValue").assert(); * - * @class + * // Grab object element to test + * pTester.expectThat(actualValue).elementAt("myKey").equals("MyValue").assert(); + * + * // Grab nested element in array/object structure to test, in this case `actualValue[5].myKey[2].someChild` + * pTester.expectThat(actualValue).elementAt(5).elementAt("myKey").elementAt(2).elementAt("someChild").equals("MyValue").assert(); */ -function Tester(pCollectionName) +Tester.prototype.elementAt = function(pKey) { - this.collectionName = pCollectionName; - this.testResults = []; + if(!Array.isArray(this.actualValue) && !Utils.isObject(this.actualValue)) + { + var error = new Error("actualValue must be array or object to use elementAt('" + pKey + "')"); + error.name = "UnitTest_lib Error"; + throw error; + } + + var key = Array.isArray(this.actualValue) && pKey === -1 ? this.actualValue.length - 1 : pKey; - // if no assert was called during a test, no test-message would be added. -> Add a success message that no error occoured. - this.currentTestHadAlreadyAssert = false; + this.actualValueElementHierarchy.push(key); + this.actualValue = this.actualValue[key]; + this.actualDisplayValue = this.actualDisplayValue[key]; + + return this; } /** - * generates a summary of the test results - * - * @return {Obect} + * Test if a value is equal to a given value + * + * @param {*} pExpect the value to compare + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.equals = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + + if(Utils.isObject(this.actualValue) || Utils.isObject(this.expectedValue)) + { + this.expectedDisplayValue = JSON.stringify(this.actualValue); + this._testResult = Utils.isEqual(this.actualValue, this.expectedValue); + this._generateAssertDescription({custom: pCustomDescription, operator: "===", name: "Object value"}); + } + else + { + this._testResult = this.actualValue === this.expectedValue; + this._generateAssertDescription({custom: pCustomDescription, operator: "==="}); + } + + return this; +} + +/** + * Test if a value is greater than a given compare value + * + * @param {Number} pExpect the value to compare + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isGreater = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + this._testResult = this.actualValue > this.expectedValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: ">"}); + + return this; +} + +/** + * Test if a value is greater or equal than a given compare value + * + * @param {Number} pExpect the value to compare + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isGreaterEqual = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + this._testResult = this.actualValue >= this.expectedValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: ">="}); + + return this; +} + +/** + * Test if a value is lower than a given compare value + * + * @param {Number} pExpect the value to compare + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isLower = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + this._testResult = this.actualValue < this.expectedValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "<"}); + + return this; +} + +/** + * Test if a value is lower or equal than a given compare value + * + * @param {Number} pExpect the value to compare + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isLowerEqual = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + this._testResult = this.actualValue <= this.expectedValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "<="}); + + return this; +} + +/** + * Test if a value is a boolean + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isBoolean = function(pCustomDescription) +{ + this._setExpectValue("boolean"); + this._testResult = Utils.isBoolean(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is a number + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isNumber = function(pCustomDescription) +{ + this._setExpectValue("number"); + this._testResult = Utils.isNumber(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is numeric + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isNumeric = function(pCustomDescription) +{ + this._setExpectValue("numeric"); + this._testResult = Utils.isNumeric(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is"}); + + return this; +} + +/** + * Test if a value is NaN (not a number) + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isNaN = function(pCustomDescription) +{ + this._setExpectValue("NaN"); + this._testResult = Number.isNaN(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is an integer + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isInteger = function(pCustomDescription) +{ + this._setExpectValue("integer"); + this._testResult = Utils.isInteger(this.actualValue); + + this.actualDisplayValue = typeof this.actualValue; + this.expectedDisplayValue = "number"; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is", expected: this.expectedValue}); + + return this; +} + +/** + * Test if a value is a float + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isFloat = function(pCustomDescription) +{ + this._setExpectValue("float"); + this._testResult = Utils.isFloat(this.actualValue); + + this.actualDisplayValue = typeof this.actualValue; + this.expectedDisplayValue = "number"; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is", expected: this.expectedValue}); + + return this; +} + +/** + * Test if a value is a string + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isString = function(pCustomDescription) +{ + this._setExpectValue("string"); + this._testResult = Utils.isString(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is an array + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isArray = function(pCustomDescription) +{ + this._setExpectValue("array"); + this._testResult = Array.isArray(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is an object + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isObject = function(pCustomDescription) +{ + this._setExpectValue("object"); + this._testResult = Utils.isObject(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is a function + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isFunction = function(pCustomDescription) +{ + this._setExpectValue("function"); + this._testResult = Utils.isFunction(this.actualValue); + this.actualDisplayValue = typeof this.actualValue; + + this._generateAssertDescription({custom: pCustomDescription, operator: "type is"}); + + return this; +} + +/** + * Test if a value is null + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isNull = function(pCustomDescription) +{ + this._setExpectValue("null"); + this._testResult = this.actualValue === null; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is"}); + + return this; +} + +/** + * Test if a value is undefined + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isUndefined = function(pCustomDescription) +{ + this._setExpectValue("undefined"); + this._testResult = this.actualValue === undefined || typeof this.actualValue === "undefined"; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is"}); + + return this; +} + +/** + * Test if a string value is lowercase + * + * An additional check of the opposite must be made to prevent strings with non-letter characters passing the test + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isUpperCase = function(pCustomDescription) +{ + this._setExpectValue("uppercase"); + this._testResult = Utils.isString(this.actualValue) + && this.actualValue === this.actualValue.toUpperCase() + && this.actualValue !== this.actualValue.toLowerCase() + ; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is"}); + + return this; +} + +/** + * Test if a string value is lowercase + * + * An additional check of the opposite must be made to prevent strings with non-letter characters passing the test + * + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isLowerCase = function(pCustomDescription) +{ + this._setExpectValue("lowercase"); + this._testResult = Utils.isString(this.actualValue) + && this.actualValue === this.actualValue.toLowerCase() + && this.actualValue !== this.actualValue.toUpperCase() + ; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is"}); + + return this; +} + +/** + * Test if a value starts with a given string + * + * An additional check of the opposite must be made to prevent strings with non-letter characters passing the test + * + * @param {Number} pExpect the expected string beginning + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.startsWith = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + this._testResult = Utils.isString(this.actualValue) && this.actualValue.startsWith(this.expectedValue); + + this._generateAssertDescription({custom: pCustomDescription, operator: "starts with"}); + + return this; +} + +/** + * Test if a value end with a given string + * + * An additional check of the opposite must be made to prevent strings with non-letter characters passing the test + * + * @param {Number} pExpect the expected string beginning + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.endsWith = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + this._testResult = Utils.isString(this.actualValue) && this.actualValue.endsWith(this.expectedValue); + + this._generateAssertDescription({custom: pCustomDescription, operator: "ends with"}); + + return this; +} + +/** + * Test if value is an instance of the expected "class" + * + * @param {Number} pExpect the expected instance name + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.isInstanceOf = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + + // Checks the name of the constructor and runs a function to check the actual instance. + // To prevent security issues by using `eval()`, a double nested function was needed. + // The outer one to evaluate the code, the inner one to be able to pass an argument, that will be evaluated. + // TODO: Also check for isObject() before + this._testResult = Utils.isObject(this.actualValue) + && this.actualValue.constructor.name === this.expectedValue + && Function('"use strict"; return function(obj) {return obj instanceof ' + this.expectedValue + ';};')()(this.actualValue); + this.actualDisplayValue = this.actualValue.constructor.name; + + this._generateAssertDescription({custom: pCustomDescription, operator: "is instance of"}); + + return this; +} + +/** + * Test if value (array, string, object) has the expected length + * + * @param {Number} pExpect the expected length + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.hasLength = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + + var length = this._getLength(this.actualValue); + this._testResult = length === this.expectedValue; + this.actualDisplayValue = length; + + this._generateAssertDescription({custom: pCustomDescription, operator: "===", nameSuffix: ".length"}); + + return this; +} + +/** + * Test if value (array, string, object) has a minimum expected length + * + * @param {Number} pExpect the expected length + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.hasMinLength = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + + var length = this._getLength(this.actualValue); + this._testResult = length >= this.expectedValue; + this.actualDisplayValue = length; + + this._generateAssertDescription({custom: pCustomDescription, operator: ">=", nameSuffix: ".length"}); + + return this; +} + +/** + * Test if value (array, string, object) has a maximum expected length + * + * @param {Number} pExpect the expected length + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} + */ +Tester.prototype.hasMaxLength = function(pExpect, pCustomDescription) +{ + this._setExpectValue(pExpect); + + var length = this._getLength(this.actualValue); + this._testResult = length <= this.expectedValue; + this.actualDisplayValue = length; + + this._generateAssertDescription({custom: pCustomDescription, operator: "<=", nameSuffix: ".length"}); + + return this; +} + + +/** + * Test if a callback function throws an exception + * + * @param {Number} pExpect the expected error + * @param {(String|Object)} pCustomDescription an optional custom assert description or config object overwrite + * @return {Tester} */ -Tester.prototype.getSummary = function () +Tester.prototype.throwsException = function(pExpect, pCustomDescription) { - var summary = { - failures : 0, - successes : 0, - failedTests : [], - getMessage : function () + this._setExpectValue(pExpect); + this._generateAssertDescription({custom: pCustomDescription, operator: "throws", expected: "exception", name: " "}); + + if(this._useNegation) + { + try + { + this.actualValue(); + } + catch(e) + { + this._testResult = true; // Actually `false` and therefore failed, but must be `true` to make negation work + this.actualDisplayValue = e; + throw e; + } + + this._testResult = false; // Actually `true` and therefore successful, but must be `false` to make negation work + } + else + { + try { - var message = "-------------------------\n" - + (this.failures ? "Test failure" : "Test success") - + "\n-------------------------\nTests performed: " + (this.successes + this.failures) - + "\nTests successful: " + this.successes - + "\nTests failed: " + this.failures; - if (this.failedTests.length) + this.actualValue(); + } + catch(e) + { + this._testResult = e.toSource() === this.expectedValue.toSource(); + + if (!this._testResult) { - message += "\nFailures:"; - this.failedTests.forEach(function (testName) - { - message += "\n\t" + testName; - }); + this.actualDisplayValue = e; + throw e; } - return message; } } - this.testResults.forEach(function ([testName,, successful]) - { - if (successful) - summary.successes++; + + return this; +} + +/** + * Executes all tests in a TestSuite + * + * @param {TestSuite} pTestSuite the TestSuite which should be tested + * @return {void} + */ +Tester.prototype.test = function(pTestSuite) +{ + this.currentTestSuite = pTestSuite; + this._log("important", "\u2692 Suite: " + this.currentTestSuite.name); + this._registerMethodTestCall(); + + this.currentTestSuite.preAll(this); + + this.currentTestSuite.tests.forEach(function(pTest) { + this._resetTest(); + + this.currentTestSuite.preTest(this); + this.dataProvider = pTest.dataProviderCallback(); + + if(Array.isArray(this.dataProvider) && this.dataProvider.length > 0) + { + this.dataProvider.forEach(function(pElement, pIndex) { + this._runTest(pTest, pIndex); + }, this); + } else { - summary.failures++; - summary.failedTests.push(testName); + this._runTest(pTest); } + + this.currentTestSuite.postTest(this); + }, this); + + this.currentTestSuite.postAll(this); +} + +/** + * Calculate test duration + * + * Will we used in the results and summary output. + * + * @return {Number} the duration in milliseconds + */ +Tester.prototype.getDuration = function() +{ + if(this.endTime === null) + { + this.endTime = new Date().getTime(); + } + + return this.endTime - this.startTime; +} + +/** + * Initializes test coverage by registering available and testable methods of given class + * + * @param {Object=} pInstanceName an optional class instance to make test coverage work + * @return {void} + */ +Tester.prototype.initCoverage = function(pInstanceName) +{ + if(pInstanceName !== undefined) + { + this.instanceName = pInstanceName; + + var instanceMethods = Object.getOwnPropertyNames(this.instanceName.prototype).filter(function(property) { + return typeof this.instanceName.prototype[property] === 'function'; + }, this); + var staticMethods = Object.getOwnPropertyNames(this.instanceName).filter(function(property) { + return typeof this.instanceName[property] === 'function'; + }, this); + + this.methods = instanceMethods.concat(staticMethods); + } +} + +/** + * Get the results of current tester as object + * + * @return {Object} the test results + */ +Tester.prototype.getResults = function() +{ + return { + testCount: this.testCount, + assertCount: this.successCount + this.failCount, + successCount: this.successCount, + failCount: this.failCount, + duration: this.getDuration(), + coverage: this._getCoverageRate(), + methodsTotal: this.methods.length, + methodsCalled: this.methodsCalled.length + }; +} + +/** + * Output the summary for a single or multiple test suites to the server log + * + * The results of multiple tests get cumulated. + * There will be no log output if it has been disabled. + * + * @param {(Object|Object[])} pTestSuiteResults the test suite result(s) to log a summary for + * @return {void} + */ +Tester.prototype.summary = function(pTestSuiteResults) +{ + var testSuiteResults = pTestSuiteResults !== undefined && Array.isArray(pTestSuiteResults) ? pTestSuiteResults : [this.getResults()]; + var divider = testSuiteResults.length > 1 ? "=" : "-"; + var title = testSuiteResults.length > 1 ? "All Tests" : this.collectionName; + + var testCount = 0; + var assertCount = 0; + var successCount = 0; + var failCount = 0; + var duration = 0; + + testSuiteResults.forEach(function(pTestResult) { + testCount += pTestResult.testCount; + assertCount += pTestResult.assertCount; + successCount += pTestResult.successCount; + failCount += pTestResult.failCount; + duration += pTestResult.duration; }); - return summary; + + this._log("info", "\n" + title + " Summary:"); + this._log("info", divider.repeat(32)); + this._log("", "Total: " + this.t.important(testCount + " Tests, " + assertCount + " Assertions")); + this._log("", "Passed: " + (successCount === assertCount ? this.t.success(successCount) : this.t.warning(successCount))); + this._log("", "Failed: " + (failCount === 0 ? this.t.success(failCount) : this.t.error(failCount))); + this._log("", "Time: " + this.t.important(duration + "ms")); + this._log("", "Coverage: " + this._getCoverageOutput(testSuiteResults)); + this._log("", "\n\n"); + + this._print(); } /** - * With assert you can test if a variable is the same like an expected value.<br/> - * The test result is added to the Tester<br/> + * Write a certain message type to the output + * + * If the given message type is not valid/allowed, the output will be plain unformatted text. + * + * @param {String} pType the message type + * @param {String} pOutput the actual message + * @return {void} * - * Note: the values are compared by === so also the type is checked.<br/> - * By using assert you can Test everything you want.<br/> + * @private + */ +Tester.prototype._log = function(pType, pOutput) +{ + var allowedTerminalMethods = ["debug", "success", "info", "error", "warning", "important"]; + + if(allowedTerminalMethods.indexOf(pType) !== -1) + { + this.output += "\n" + this.t[pType](pOutput); + } + else + { + this.output += "\n" + pOutput; + } +} + +/** + * Set the value to test against + * + * @param {*} pValue + * @return {void} * - * @param {AnyValue} pExpect the expected value - * @param {AnyValue} pActual the actual value - * @param {String} [pTestDescription] this is an optional description. You should use it, if you have more than one .assert in your test. + * @private */ -Tester.prototype.assert = function (pExpect, pActual, pTestDescription) +Tester.prototype._setExpectValue = function(pValue) { - this.currentTestHadAlreadyAssert = true; - - var res = pActual === pExpect; + this.expectedValue = pValue; + this.expectedDisplayValue = pValue; +} + +/** + * Determine, whether an error is expected in the current test run + * + * @return {Boolean} + * + * @private + */ +Tester.prototype._testExpectsError = function() +{ + return this.expectedValue instanceof Error; +} + +/** + * Write the ouput to the log and reset the output to an empty string + * + * @return {Tester} + * + * @private + */ +Tester.prototype._print = function() +{ + if(this.outputEnabled) + { + logging.log(this.output); + } - this.testResults.push([ - this._currentTest, - pTestDescription, - res, - pExpect, - pActual - ]); + this.output = ""; + return this; } /** - * Executes all tests in a TestSuite - * @param {TestSuite} pTestSuite the TestSuite which should be tested + * Generates and sets an assert description by given config object or simply set a given custom string + * + * It also handles using the correct operators when negation via `not()` is used + * + * @param {Object} pDescriptionConfig a config object + * @return {void} + * + * @private */ -Tester.prototype.test = function (pTestSuite) +Tester.prototype._generateAssertDescription = function(pDescriptionConfig) { - pTestSuite.preAll(this); + if(Utils.isString(pDescriptionConfig.custom)) + { + this._assertDescription = pDescriptionConfig.custom; + return; + } - pTestSuite.tests.forEach(function(pTest) { - logging.log("Testing " + pTest[0]); - - this.currentTestHadAlreadyAssert = false; - - this._currentTest = pTest[0]; - pTestSuite.preTest(this); - - if (pTest.length >= 3) + Object.assign(pDescriptionConfig, pDescriptionConfig.custom); + var valueName = pDescriptionConfig.name || "value"; + var valueNameSuffix = pDescriptionConfig.nameSuffix || ""; + var operator = pDescriptionConfig.operator.trim(); + var expectedValue = pDescriptionConfig.expected || this.expectedDisplayValue; + expectedValue = Utils.isString(expectedValue) ? "`" + expectedValue + "`" : expectedValue + ""; + + if(this._useNegation) + { + switch(operator) { - var errorThrowed = false; - - try { - pTest[1](this); - } catch (ex) { - errorThrowed = true; - - if (ex.toSource() == pTest[2].toSource()) - { - this.testResults.push([ - this._currentTest, - "Expected error throwed", - true, - pTest[2].toSource(), - ex.toSource() - ]); - - // don't throw as it's expected and no detailed stacktrace is needed - } - else - { - this.testResults.push([ - this._currentTest, - "Expected error throwed", - false, - pTest[2].toSource(), - ex.toSource() - ]); - - logging.log("Expected error: " + pTest[2].toSource() + ", but wrong error occoured.\nRunning test again without try catch to get detailed error stack trace") - - pTestSuite.preTest(this); - pTest[1](this); - pTestSuite.postTest(this); - return; - } - } - - if (!errorThrowed) - { - // if it didn't fail - this.testResults.push([ - this._currentTest, - "Expected error throwed", - false, - pTest[2].toSource(), - "no error" - ]); - } + case "===": + operator = "!=="; + break; + case ">": + operator = "<="; + break; + case ">=": + operator = "<"; + break; + case "<": + operator = ">="; + break; + case "<=": + operator = ">"; + break; + case "is": + case "type is": + case "has": + operator += " not"; + break; + case "is instance of": + operator += "is not instance of"; + break; + case "starts with": + case "ends with": + case "throws": + default: + operator = "not " + operator; + break; } - else + } + + this.actualValueElementHierarchy.forEach(function(pElement) { + valueName += typeof pElement === "number" ? "[" + pElement + "]" : "." + pElement; + }, this); + + var description = valueName + valueNameSuffix + " " + operator + " " + expectedValue; + this._assertDescription = description.trim(); + this.actualValueElementHierarchy = []; +} + +/** + * Reset test-related properties to their initial state + * + * This is done before every test run to prevent side-effects or expired/invalid data and states + * + * @return {Tester} + * + * @private + */ +Tester.prototype._resetTest = function() +{ + this.actualValue = undefined; + this.actualDisplayValue = undefined; + this.actualOriginalValue = undefined; + this.actualOriginalDisplayValue = undefined; + this.actualValueElementHierarchy = []; + this.expectedValue = undefined; + this.expectedDisplayValue = undefined; + this._assertDescription = ""; + this._testResult = false; + this._useNegation = false; + + return this; +} + +/** + * Get the length of a given value or undefined if it is not an array, object or string + * + * @param {(Array|Object|String)} pActualValue the value to get the length from + * @return {Number} + * + * @private + */ +Tester.prototype._getLength = function(pActualValue) +{ + if(Array.isArray(pActualValue) || Utils.isString(pActualValue)) + { + return pActualValue.length; + } + else if(Utils.isObject(pActualValue)) + { + return Object.keys(pActualValue).length; + } + + return undefined; +} + +/** + * Get the percentage of test coverage + * + * Will we used in the results and summary output. + * + * @return {?Number} the duration in milliseconds + */ +Tester.prototype._getCoverageRate = function() +{ + if(this.methods.length === 0 && this.methodsCalled.length === 0) + { + return null; + } + + if(this.methods.length === 0 || this.methodsCalled.length === 0) + { + return 0.00; + } + + var coverage = (this.methodsCalled.length / this.methods.length) * 100; + coverage = Number.parseFloat(Number.parseFloat(coverage).toFixed(2)); + + return coverage > 100 ? 100.00 : coverage; +} + +/** + * Register, which method of the given class has been called + * + * It takes the name of the TestSuite and splits it to get the class name and the method. + * Then, it checks if the class has such a method. It gets added to the call-list, if it has not been added yet. + * This is necessary to calculate the test coverage. + * All available class methods get registered beforehand and will be compared to this list later in `_getCoverageRate()`. + * + * @return {void} + * + * @private + */ +Tester.prototype._registerMethodTestCall = function() +{ + if(this.instanceName !== undefined) + { + var callParts = this.currentTestSuite.name.split("."); + + if(callParts[0] === this.instanceName.prototype.constructor.name && this.methods.indexOf(callParts[1]) !== -1) { - // run without try catch as no error expected - pTest[1](this); + if(this.methodsCalled.indexOf(callParts[1]) === -1) + { + this.methodsCalled.push(callParts[1]); + } } - - if (!this.currentTestHadAlreadyAssert && pTest.length < 3) // only add message if no error expected - { - this.testResults.push([ - this._currentTest, - "Expected no error", - true, - "no error", - "no error" - ]); + } +} + +/** + * Renders the output for the test coverage + * + * The results of multiple tests get cumulated. + * + * @param {Object[]} pTestSuiteResults the test suite(s) to log a summary for + * @return {String} the test coverage output + */ +Tester.prototype._getCoverageOutput = function(pTestSuiteResults) +{ + var coverageOutput = this.t.debug("unknown"); + var methodsTotal = 0; + var methodsCalled = 0; + var coverage = null; + var avgCoverage = null; + var coverageMethodCount = null; + + pTestSuiteResults.forEach(function(pTestResult) { + methodsTotal += pTestResult.methodsTotal; + methodsCalled += pTestResult.methodsCalled; + + if(pTestResult.coverage !== null) { + coverage += pTestResult.coverage; } - - pTestSuite.postTest(this); - }, this); - - pTestSuite.postAll(this); + }); + + if(coverage !== null) + { + avgCoverage = coverage / pTestSuiteResults.length; + coverageMethodCount = "(" + methodsCalled + "/" + methodsTotal + ")"; + } + + if(avgCoverage >= 80) + { + coverageOutput = this.t.success(avgCoverage + "% " + coverageMethodCount); + } + else if(avgCoverage >= 50) + { + coverageOutput = this.t.warning(avgCoverage + "% " + coverageMethodCount); + } + else if(avgCoverage > 0) + { + coverageOutput = this.t.error(avgCoverage + "% " + coverageMethodCount); + } + + return coverageOutput; } /** - * Prints the test results to the log + * Generates the title for the test about to run + * + * @param {Test} pTest the test to run + * @param {Number} pDataProviderIndex the current index of the data provider + * @return {void} + * + * @private */ -Tester.prototype.printResults = function () +Tester.prototype._generateTestTitle = function(pTest, pDataProviderIndex) { - var lastTestDescription = ""; - logging.log("Test results for \"" + this.collectionName + "\"") - this.testResults.forEach(function(pResult) { - - if (lastTestDescription != pResult[0]) + if(pDataProviderIndex !== undefined) + { + var titleValues = []; + + this.dataProvider[pDataProviderIndex].forEach(function(pElement) { + titleValues.push(pElement === undefined ? "undefined" : JSON.stringify(pElement)); + }); + this._log("", this.t.info("\t\u2699 Test: " + pTest.name) + this.t.debug(" (#" + (pDataProviderIndex + 1) + ": " + titleValues.join(" | ") + ")")); + } + else + { + this._log("info", "\t\u2699 Test: " + pTest.name); + } +} + +/** + * Runs a single test iteration and handles errors + * + * @param {Test} pTest the test to run + * @param {Number} pDataProviderIndex the current index of the data provider + * @return {void} + * + * @private + */ +Tester.prototype._runTest = function(pTest, pDataProviderIndex) +{ + this._generateTestTitle(pTest, pDataProviderIndex); + this.testCount++; + + var dataProvider = pDataProviderIndex !== undefined ? this.dataProvider[pDataProviderIndex] : undefined; + + try + { + pTest.callback(this, dataProvider); + } + catch (e) + { + this.assert(); + + // Expected, but wrong error + if (this._testExpectsError() && e.toSource() !== this.expectedValue.toSource()) { - logging.log("Test \"" + pResult[0] + "\":"); + this._log("error", "Wrong error occurred"); + this._log("warning", "\t\t expected: " + this.expectedValue.toSource()); + this._log("error", "\t\t actual: " + e.toSource()); } - - var message = (pResult[1] ? " - " + pResult[1] : " - Test result ") + ": " + (pResult[2] ? "success" : "fail\nexpected: " + JSON.stringify(pResult[3], null, "\t") + "\nactual: " + JSON.stringify(pResult[4], null, "\t")); - - logging.log(message); - lastTestDescription = pResult[0]; - }, this); - logging.log(this.getSummary().getMessage()); -} \ No newline at end of file + else + { // Unexpected error + this._log("error", "Unexpected error occurred"); + } + + var exception = logging.toLogString(e["rhinoException"] !== undefined ? e["rhinoException"] : e, true); + this._log("error", e.name + ":\n" + exception.replace(/\s+(at|\[->\])\s/g, "\n\t$1 ")); + this._log("error", "jDito callstack:\n" + e.stack); + + if(pTest.rerunOnError) + { + this._log("debug", "Rerun without try-catch to get detailed error stack trace"); + this._print(); + + this.currentTestSuite.preTest(this); + pTest.callback(this, dataProvider); + this.currentTestSuite.postTest(this); + } + } +} diff --git a/process/UnitTest_test/UnitTest_test.aod b/process/UnitTest_test/UnitTest_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..095a395529bdac348b397a4854c6939cccab89f3 --- /dev/null +++ b/process/UnitTest_test/UnitTest_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>UnitTest_test</name> + <title>[TEST] UnitTest_lib</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/UnitTest_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/UnitTest_test/process.js b/process/UnitTest_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..7d80b7995e42cc7b6bc74c8b3f417f2ce3ae0329 --- /dev/null +++ b/process/UnitTest_test/process.js @@ -0,0 +1,1141 @@ +import("system.result"); +import("system.vars"); +import("Keyword_lib"); +import("UnitTest_lib"); + + +var equals = new TestSuite("Tester.equals", [ + new Test("should test value equality", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).equals(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + var num = 0; + var str = '0'; + var objStr = new String('0'); + var obj_1 = {a: 1, b: 2, c: 3}; + var obj_2 = {x: null, y: "test", z: true}; + + return [ + [true, num, num], + [true, str, str], + [true, true, true], + [true, objStr, objStr], + [true, obj_1, obj_1], + [true, obj_2, obj_2], + [false, true, false], + [false, obj_1, obj_2], + [false, num, objStr], + [false, num, str], + [false, objStr, str], + [false, null, undefined], + [false, objStr, null], + [false, objStr, undefined], + [false, null, "null"], + ]; + } + ) +]); + +var isGreater = new TestSuite("Tester.isGreater", [ + new Test("should test if value is greater than another", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isGreater(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 1, 0], + [true, 100, 10], + [false, 3, 3], + [false, 0, 5], + [false, 1234, 5678], + ]; + } + ) +]); + +var isGreaterEqual = new TestSuite("Tester.isGreaterEqual", [ + new Test("should test if value is greater or equal than another", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isGreaterEqual(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 1, 0], + [true, 101, 100], + [true, 3, 3], + [false, 0, 5], + [false, 1234, 5678], + ]; + } + ) +]); + +var isLower = new TestSuite("Tester.isLower", [ + new Test("should test if value is lower than another", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isLower(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 0, 1], + [true, 10, 100], + [false, 3, 3], + [false, 5, 0], + [false, 5678, 1234], + ]; + } + ) +]); + +var isLowerEqual = new TestSuite("Tester.isLowerEqual", [ + new Test("should test if value is greater or equal than another", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isLowerEqual(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 0, 1], + [true, 100, 101], + [true, 3, 3], + [false, 5, 0], + [false, 5678, 1234], + ]; + } + ) +]); + +var isBoolean = new TestSuite("Tester.isBoolean", [ + new Test("should test if value is a boolean", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isBoolean().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, true], + [true, false], + [false, "true"], + [false, "false"], + [false, ""], + [false, "0"], + [false, 0], + [false, new Object()], + [false, []], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isNumber = new TestSuite("Tester.isNumber", [ + new Test("should test if value is a number", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isNumber().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 0], + [true, 100], + [true, 33.33333], + [true, 0xFFFFFF], + [true, 0777], // Octal + //[true, 0o777], // New octal format since ECMAScript 2015 + //[true, 0b11111111], // Seems like binary numbers are not supported + [true, 2e6], // Exponentiation + [true, 0.1e2], // Exponentiation + [true, +Infinity], + [true, -Infinity], + [true, NaN], // This should actually fail. Needs fix in Utils + [false, ""], + [false, "0"], + [false, new Object()], + [false, []], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isNumeric = new TestSuite("Tester.isNumeric", [ + new Test("should test if value is numeric", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isNumeric().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 0], + [true, 100], + [true, 33.33333], + [true, "0777"], // Octal + [true, "2e6"], // Exponentiation + [true, "0.1e2"], // Exponentiation + [true, +Infinity], + [true, -Infinity], + [true, NaN], // This should actually fail. Needs fix in Utils + [true, "50000"], + [true, "0"], + [false, ""], + [false, new Object()], + [false, []], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isNotANumber = new TestSuite("Tester.isNaN", [ + new Test("should test if value is not NaN", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isNaN().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, NaN], + [false, 0], + [false, 100], + [false, 33.33333], + [false, "0777"], // Octal + [false, "2e6"], // Exponentiation + [false, "0.1e2"], // Exponentiation + [false, +Infinity], + [false, -Infinity], + [false, "50000"], + [false, "0"], + [false, ""], + [false, new Object()], + [false, []], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isInteger = new TestSuite("Tester.isInteger", [ + new Test("should test if value is an integer", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isInteger().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 0], + [true, 100], + [true, 0xFFFFFF], + [true, 0777], // Octal + [true, 2e6], // Exponentiation + [true, 0.1e2], // Exponentiation + [true, "0"], + [false, 33.33333], + [false, +Infinity], + [false, -Infinity], + [false, NaN], + [false, ""], + [false, new Object()], + [false, []], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isFloat = new TestSuite("Tester.isFloat", [ + new Test("should test if value is a float", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isFloat().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, 33.33333], + [false, 0], + [false, 100], + [false, 0xFFFFFF], + [false, 0777], // Octal + [false, 2e6], // Exponentiation + [false, 0.1e2], // Exponentiation + [false, +Infinity], + [false, -Infinity], + [false, NaN], + [false, ""], + [false, "0"], + [false, new Object()], + [false, []], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isString = new TestSuite("Tester.isString", [ + new Test("should test if value is a string", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isString().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, ""], + [true, "Hello"], + [true, "0"], + [false, new String('Hello')], + [false, []], + [false, 0], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isArray = new TestSuite("Tester.isArray", [ + new Test("should test if value is an array", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isArray().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, []], + [true, ["a", 2, null]], + [true, new Array()], + [false, ""], + [false, "0"], + [false, new Object()], + [false, new Function()], + [false, 0], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isObject = new TestSuite("Tester.isObject", [ + new Test("should test if value is an object", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isObject().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, {}], + [true, []], + [true, ["a", 2, null]], + [true, new Array()], + [true, new Object()], + [true, new String("hello")], + [false, new Function()], + [false, ""], + [false, "0"], + [false, 0], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isFunction = new TestSuite("Tester.isFunction", [ + new Test("should test if value is a function", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isFunction().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, new Function()], + [true, function(){}], + [true, Math.sin], + [true, Array.isArray], + [false, new Array()], + [false, new Object()], + [false, ""], + [false, "0"], + [false, 0], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isNull = new TestSuite("Tester.isNull", [ + new Test("should test if value is null", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isNull().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, null], + [false, ""], + [false, "Hello"], + [false, "0"], + [false, new String('Hello')], + [false, []], + [false, 0], + [false, true], + [false, undefined], + ]; + } + ) +]); + +var isUndefined = new TestSuite("Tester.isUndefined", [ + new Test("should test if value is undefined", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isUndefined().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, undefined], + [false, ""], + [false, "Hello"], + [false, "0"], + [false, new String('Hello')], + [false, []], + [false, 0], + [false, true], + [false, null], + ]; + } + ) +]); + +var isUpperCase = new TestSuite("Tester.isUpperCase", [ + new Test("should test if value is an uppercase string", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isUpperCase().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "HELLO"], + [false, "HeLlo"], + [false, "hello"], + [false, "0"], + [false, new String('Hello')], + [false, []], + [false, 0], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var isLowerCase = new TestSuite("Tester.isLowerCase", [ + new Test("should test if value is a lowercase string", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isLowerCase().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "hello"], + [false, "HELLO"], + [false, "HeLlo"], + [false, "0"], + [false, new String('Hello')], + [false, []], + [false, 0], + [false, true], + [false, null], + [false, undefined], + ]; + } + ) +]); + +var startsWith = new TestSuite("Tester.startsWith", [ + new Test("should test if value starts with a given string", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).startsWith(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "Millenium Falcon", "Mill"], + [false, "Millenium Falcon", "MILL"], + [false, "Millenium Falcon", "Abc"], + [false, "Millenium Falcon", "0"], + ]; + } + ) +]); + +var endsWith = new TestSuite("Tester.endsWith", [ + new Test("should test if value ends with a given string", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).endsWith(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "Millenium Falcon", "con"], + [false, "Millenium Falcon", "CON"], + [false, "Millenium Falcon", "Abc"], + [false, "Millenium Falcon", "0"], + ]; + } + ) +]); + +var isInstanceOf = new TestSuite("Tester.isInstanceOf", [ + new Test("should test if value is an instance of given class", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).isInstanceOf(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, new Tester(), "Tester"], + [true, [], "Array"], + [true, {}, "Object"], + [false, "abc", "String"], + [false, true, "Boolean"], + [false, 0, "Number"], + ]; + } + ) +]); + +var hasLength = new TestSuite("Tester.hasLength", [ + new Test("should test if value has the expected length", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).hasLength(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "", 0], + [true, [], 0], + [true, {}, 0], + [true, "abc", 3], + [true, ["a", "z"], 2], + [true, new String("?!"), 2], + [false, 0, 1], + [false, true, 1], + [false, null, 1], + [false, undefined, 1], + ]; + } + ) +]); + + +var hasMinLength = new TestSuite("Tester.hasMinLength", [ + new Test("should test if value has the expected minimum length", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).hasMinLength(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "", 0], + [true, [], 0], + [true, {}, 0], + [true, "abc", 3], + [true, "abc", 2], + [true, ["a", "z"], 2], + [true, ["a", "z"], 1], + [true, new String("?!"), 2], + [false, "abc", 4], + [false, ["a", "z"], 5], + [false, 0, 1], + [false, true, 1], + [false, null, 1], + [false, undefined, 1], + ]; + } + ) +]); + + +var hasMaxLength = new TestSuite("Tester.hasMaxLength", [ + new Test("should test if value has the expected maximum length", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).hasMaxLength(pDataProvider[2]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "", 0], + [true, [], 0], + [true, {}, 0], + [true, "abc", 3], + [true, "abc", 4], + [true, ["a", "z"], 2], + [true, ["a", "z"], 3], + [true, new String("?!"), 2], + [false, "abc", 2], + [false, ["a", "z"], 1], + [false, 0, 1], + [false, true, 1], + [false, null, 1], + [false, undefined, 1], + ]; + } + ) +]); + +var not = new TestSuite("Tester.not", [ + new Test("should test negation of compare tests", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var method = pDataProvider[1]; + var actualValue = dummyTester.expectThat(pDataProvider[2]).not()[method](pDataProvider[3]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + var num = 0; + var str = '0'; + var objStr = new String('0'); + var obj_1 = {a: 1, b: 2, c: 3}; + var obj_2 = {x: null, y: "test", z: true}; + + return [ + [true, "equals", true, false], + [true, "equals", obj_1, obj_2], + [true, "equals", num, objStr], + [false, "equals", num, num], + [false, "equals", str, str], + [false, "equals", true, true], + [true, "isGreater", 3, 3], + [true, "isGreater", 0, 5], + [true, "isGreater", 1234, 5678], + [false, "isGreater", 1, 0], + [false, "isGreater", 100, 10], + [true, "isGreaterEqual", 0, 5], + [true, "isGreaterEqual", 1234, 5678], + [false, "isGreaterEqual", 1, 0], + [false, "isGreaterEqual", 101, 100], + [false, "isGreaterEqual", 3, 3], + [true, "isLower", 3, 3], + [true, "isLower", 5, 0], + [true, "isLower", 5678, 1234], + [false, "isLower", 0, 1], + [false, "isLower", 10, 100], + [true, "isLowerEqual", 5, 0], + [true, "isLowerEqual", 5678, 1234], + [false, "isLowerEqual", 0, 1], + [false, "isLowerEqual", 100, 101], + [false, "isLowerEqual", 3, 3], + [true, "startsWith", "Millenium Falcon", "MILL"], + [true, "startsWith", "Millenium Falcon", "Abc"], + [true, "startsWith", "Millenium Falcon", "0"], + [false, "startsWith", "Millenium Falcon", "Mill"], + [true, "endsWith", "Millenium Falcon", "CON"], + [true, "endsWith", "Millenium Falcon", "Abc"], + [true, "endsWith", "Millenium Falcon", "0"], + [false, "endsWith", "Millenium Falcon", "con"], + [true, "isInstanceOf", "abc", "String"], + [true, "isInstanceOf", true, "Boolean"], + [true, "isInstanceOf", 0, "Number"], + [false, "isInstanceOf", new Tester(), "Tester"], + [false, "isInstanceOf", [], "Array"], + [false, "isInstanceOf", {}, "Object"], + [true, "hasLength", 0, 1], + [true, "hasLength", true, 1], + [true, "hasLength", null, 1], + [true, "hasLength", undefined, 1], + [false, "hasLength", "", 0], + [false, "hasLength", [], 0], + [false, "hasLength", {}, 0], + [false, "hasLength", "abc", 3], + [false, "hasLength", ["a", "z"], 2], + [false, "hasLength", new String("?!"), 2], + ]; + } + ), + new Test("should test negation of type tests", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var method = pDataProvider[1]; + var actualValue = dummyTester.expectThat(pDataProvider[2]).not()[method]().getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, "isBoolean", "true"], + [true, "isBoolean", "false"], + [true, "isBoolean", ""], + [true, "isBoolean", "0"], + [true, "isBoolean", 0], + [true, "isBoolean", new Object()], + [true, "isBoolean", []], + [true, "isBoolean", null], + [true, "isBoolean", undefined], + [false, "isBoolean", true], + [false, "isBoolean", false], + [true, "isNumber", ""], + [true, "isNumber", "0"], + [true, "isNumber", new Object()], + [true, "isNumber", []], + [true, "isNumber", true], + [true, "isNumber", null], + [true, "isNumber", undefined], + [false, "isNumber", 0], + [false, "isNumber", 100], + [false, "isNumber", 33.33333], + [false, "isNumber", 0xFFFFFF], + [false, "isNumber", 0777], // Octal + [false, "isNumber", 2e6], // Exponentiation + [false, "isNumber", 0.1e2], // Exponentiation + [false, "isNumber", +Infinity], + [false, "isNumber", -Infinity], + [false, "isNumber", NaN], + [true, "isNumeric", ""], + [true, "isNumeric", new Object()], + [true, "isNumeric", []], + [true, "isNumeric", true], + [true, "isNumeric", null], + [true, "isNumeric", undefined], + [false, "isNumeric", 0], + [false, "isNumeric", 100], + [false, "isNumeric", 33.33333], + [false, "isNumeric", "0777"], // Octal + [false, "isNumeric", "2e6"], // Exponentiation + [false, "isNumeric", "0.1e2"], // Exponentiation + [false, "isNumeric", +Infinity], + [false, "isNumeric", -Infinity], + [false, "isNumeric", NaN], + [false, "isNumeric", "50000"], + [false, "isNumeric", "0"], + [true, "isNaN", 0], + [true, "isNaN", 100], + [true, "isNaN", 33.33333], + [true, "isNaN", "0777"], // Octal + [true, "isNaN", "2e6"], // Exponentiation + [true, "isNaN", "0.1e2"], // Exponentiation + [true, "isNaN", +Infinity], + [true, "isNaN", -Infinity], + [true, "isNaN", "50000"], + [true, "isNaN", "0"], + [true, "isNaN", ""], + [true, "isNaN", new Object()], + [true, "isNaN", []], + [true, "isNaN", true], + [true, "isNaN", null], + [true, "isNaN", undefined], + [false, "isNaN", NaN], + [true, "isInteger", 33.33333], + [true, "isInteger", +Infinity], + [true, "isInteger", -Infinity], + [true, "isInteger", NaN], + [true, "isInteger", ""], + [true, "isInteger", new Object()], + [true, "isInteger", []], + [true, "isInteger", true], + [true, "isInteger", null], + [true, "isInteger", undefined], + [false, "isInteger", 0], + [false, "isInteger", 100], + [false, "isInteger", 0xFFFFFF], + [false, "isInteger", 0777], // Octal + [false, "isInteger", 2e6], // Exponentiation + [false, "isInteger", 0.1e2], // Exponentiation + [false, "isInteger", "0"], + [true, "isFloat", 0], + [true, "isFloat", 100], + [true, "isFloat", 0xFFFFFF], + [true, "isFloat", 0777], // Octal + [true, "isFloat", 2e6], // Exponentiation + [true, "isFloat", 0.1e2], // Exponentiation + [true, "isFloat", +Infinity], + [true, "isFloat", -Infinity], + [true, "isFloat", NaN], + [true, "isFloat", ""], + [true, "isFloat", "0"], + [true, "isFloat", new Object()], + [true, "isFloat", []], + [true, "isFloat", true], + [true, "isFloat", null], + [true, "isFloat", undefined], + [false, "isFloat", 33.33333], + [true, "isString", new String('Hello')], + [true, "isString", []], + [true, "isString", 0], + [true, "isString", true], + [true, "isString", null], + [true, "isString", undefined], + [false, "isString", ""], + [false, "isString", "Hello"], + [false, "isString", "0"], + [true, "isArray", ""], + [true, "isArray", "0"], + [true, "isArray", new Object()], + [true, "isArray", new Function()], + [true, "isArray", 0], + [true, "isArray", true], + [true, "isArray", null], + [true, "isArray", undefined], + [false, "isArray", []], + [false, "isArray", ["a", 2, null]], + [false, "isArray", new Array()], + [true, "isObject", new Function()], + [true, "isObject", ""], + [true, "isObject", "0"], + [true, "isObject", 0], + [true, "isObject", true], + [true, "isObject", null], + [true, "isObject", undefined], + [false, "isObject", {}], + [false, "isObject", []], + [false, "isObject", ["a", 2, null]], + [false, "isObject", new Array()], + [false, "isObject", new Object()], + [false, "isObject", new String("hello")], + [true, "isFunction", new Array()], + [true, "isFunction", new Object()], + [true, "isFunction", ""], + [true, "isFunction", "0"], + [true, "isFunction", 0], + [true, "isFunction", true], + [true, "isFunction", null], + [true, "isFunction", undefined], + [false, "isFunction", new Function()], + [false, "isFunction", function(){}], + [false, "isFunction", Math.sin], + [false, "isFunction", Array.isArray], + [true, "isNull", ""], + [true, "isNull", "Hello"], + [true, "isNull", "0"], + [true, "isNull", new String('Hello')], + [true, "isNull", []], + [true, "isNull", 0], + [true, "isNull", true], + [true, "isNull", undefined], + [false, "isNull", null], + [true, "isUndefined", ""], + [true, "isUndefined", "Hello"], + [true, "isUndefined", "0"], + [true, "isUndefined", new String('Hello')], + [true, "isUndefined", []], + [true, "isUndefined", 0], + [true, "isUndefined", true], + [true, "isUndefined", null], + [false, "isUndefined", undefined], + [true, "isUpperCase", "HeLlo"], + [true, "isUpperCase", "hello"], + [true, "isUpperCase", "0"], + [true, "isUpperCase", new String('Hello')], + [true, "isUpperCase", []], + [true, "isUpperCase", 0], + [true, "isUpperCase", true], + [true, "isUpperCase", null], + [true, "isUpperCase", undefined], + [false, "isUpperCase", "HELLO"], + [true, "isLowerCase", "HELLO"], + [true, "isLowerCase", "HeLlo"], + [true, "isLowerCase", "0"], + [true, "isLowerCase", new String('Hello')], + [true, "isLowerCase", []], + [true, "isLowerCase", 0], + [true, "isLowerCase", true], + [true, "isLowerCase", null], + [true, "isLowerCase", undefined], + [false, "isLowerCase", "hello"], + ]; + } + ), + new Test("should not affect other assertions", + function(pTester) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + //first assertion with not()-call + var expectValue = true; + var actualValue = dummyTester.expectThat("this value").not().equals("that other value").getTestResult(); + pTester.expectThat(actualValue).equals(expectValue).assert(); + + //second test without not()-call => the first not()-call should not affect the second assertion + expectValue = false; + actualValue = dummyTester.expectThat("this value").equals("that other value").getTestResult(); + pTester.expectThat(actualValue).equals(expectValue).assert(); + } + ) +]); + +var elementAt = new TestSuite("Tester.elementAt", [ + new Test("should test if value element at key position passes test", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var key = pDataProvider[2]; + var method = pDataProvider[3]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).elementAt(key)[method](pDataProvider[4]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, ["a", "z", ["x", true, 42]], 0, "isString", undefined], + [true, ["a", "z", ["x", true, 42]], 1, "equals", "z"], + [true, ["a", "z", ["x", true, 42]], 2, "isArray", undefined], + [true, ["a", "z", ["x", true, 42]], 2, "hasLength", 3], + [true, ["a", "z", {"first": "x", "second": true}], 2, "isObject", undefined], + [true, ["a", "z", {"first": "x", "second": true}], 2, "hasLength", 2], + [false, ["a", "z", ["x", true, 42]], 0, "isNumeric", undefined], + [false, ["a", "z", ["x", true, 42]], 1, "equals", "a"], + [false, ["a", "z", ["x", true, 42]], 2, "isString", undefined], + [false, ["a", "z", ["x", true, 42]], 2, "hasLength", 1], + [false, ["a", "z", {"first": "x", "second": true}], 2, "isArray", undefined], + [false, ["a", "z", {"first": "x", "second": true}], 2, "hasLength", 1], + ]; + } + ), + new Test("should test if nested value element at key position passes test", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + var key1 = pDataProvider[2]; + var key2 = pDataProvider[3]; + var method = pDataProvider[4]; + var actualValue = dummyTester.expectThat(pDataProvider[1]).elementAt(key1).elementAt(key2)[method](pDataProvider[5]).getTestResult(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [true, [["x", true, [42]]], 0, 0, "isString", undefined], + [true, [["x", true, [42]]], 0, 0, "equals", "x"], + [true, [["x", true, [42]]], 0, 1, "isBoolean", undefined], + [true, [["x", true, [42]]], 0, 1, "equals", true], + [true, [["x", true, [42]]], 0, 2, "isArray", undefined], + [true, [{"first": "a", "second": 42}], 0, "first", "equals", "a"], + [true, [{"first": "a", "second": 42}], 0, "second", "equals", 42], + [true, {"outer": {"inner": "a"}}, "outer", "inner", "isString", undefined], + [true, {"outer": {"inner": "a"}}, "outer", "inner", "equals", "a"], + [false, [["x", true, [42]]], 0, 1, "equals", "a"], + [false, [["x", true, [42]]], 0, 2, "isNumber", undefined], + [false, {"outer": {"inner": "a"}}, "outer", "inner", "isNumber", undefined], + ]; + } + ) +]); + +var getCoverageRate = new TestSuite("Tester._getCoverageRate", [ + new Test("should test if coverage is correctly calculated", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[0]; + dummyTester.methods = pDataProvider[1]; + dummyTester.methodsCalled = pDataProvider[2]; + var actualValue = dummyTester._getCoverageRate(); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + [100, ["method1", "method2", "method3"], ["method1", "method2", "method3"]], + [33.33, ["method1", "method2", "method3"], ["method1"]], + [66.67, ["method1", "method2", "method3"], ["method1", "method2"]], + [100, ["method1"], ["method1", "method2", "method3"]], + [0, ["method1"], []], + [0, [], ["method1"]], + [null, [], []], + ]; + } + ) +]); + +var getLength = new TestSuite("Tester._getLength", [ + new Test("should test if value has the expected length", + function(pTester, pDataProvider) { + + var dummyTester = (new Tester("Test Dummy")).setOutputEnabled(false); + var expectValue = pDataProvider[1]; + var actualValue = dummyTester._getLength(pDataProvider[0]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() { + return [ + ["", 0], + [[], 0], + [{}, 0], + ["abc", 3], + [["a", "z"], 2], + [new String("?!"), 2], + [{first: "xyz"}, 1], + [0, undefined], + [true, undefined], + [null, undefined], + [undefined, undefined], + ]; + } + ) +]); + + + +var tester = new Tester("Test UnitTest_lib"); +tester.initCoverage(Tester); +tester.test(equals); +tester.test(isGreater); +tester.test(isGreaterEqual); +tester.test(isLower); +tester.test(isLowerEqual); +tester.test(isBoolean); +tester.test(isNumber); +tester.test(isNumeric); +tester.test(isNotANumber); +tester.test(isInteger); +tester.test(isFloat); +tester.test(isString); +tester.test(isArray); +tester.test(isObject); +tester.test(isFunction); +tester.test(isNull); +tester.test(isUndefined); +tester.test(isUpperCase); +tester.test(isLowerCase); +tester.test(startsWith); +tester.test(endsWith); +tester.test(isInstanceOf); +tester.test(hasLength); +tester.test(hasMinLength); +tester.test(hasMaxLength); +tester.test(not); +tester.test(elementAt); +tester.test(getCoverageRate); +tester.test(getLength); + +tester.summary(); + +result.object(tester.getResults()); diff --git a/process/Util_lib/process.js b/process/Util_lib/process.js index 9dc7208091da2758a798b3804912729a0fb6c775..778e4ae46cb0b4b5a7c5e2887baef1e71b2884a2 100644 --- a/process/Util_lib/process.js +++ b/process/Util_lib/process.js @@ -53,7 +53,7 @@ Utils.isNullOrEmpty = function (pObject) } /** - * Creates a deep copy of the given object. Also works with arrays. + * Creates a deep copy of the given object. Also works with arrays, maps and sets. * * @param {Object} pObject the object to create a copy of * @return {Object} the cloned object @@ -69,7 +69,7 @@ Utils.isNullOrEmpty = function (pObject) * * logging.log(original.name != copy.name); //true * logging.log(copy instanceof MyObject()); //true, prototypes are set correctly - * logging.log(copy.obj1 === copy.obj2); //true, relative object references are kept + * logging.log(copy.obj1 === copy.obj2); //true, relative object references are preserved */ Utils.clone = function (pObject) { @@ -84,21 +84,48 @@ Utils.clone = function (pObject) if (referenceMap.has(pObject)) return referenceMap.get(pObject); - var clonedObject = Array.isArray(pObject) - ? [] - : Object.create(Object.getPrototypeOf(pObject)); //set the prototype of the given object + var clonedObject; + if (Array.isArray(pObject)) + clonedObject = []; + else if (pObject instanceof Map) + clonedObject = new Map(); + else if (pObject instanceof Set) + clonedObject = new Set(); + else + clonedObject = Object.create(Object.getPrototypeOf(pObject)); //set the prototype of the given object /* keeps track of all encountered objects and maps the original to the copy, this makes it possible to: - have the same relative references in the copy as in the original - copy cyclic references without error */ referenceMap.set(pObject, clonedObject); - for (let key in pObject) + if (pObject instanceof Map) + { + pObject.forEach(function (value, key) + { + clonedObject.set(_clone(key), _clone(value)); + }); + } + else if (pObject instanceof Set) + { + pObject.forEach(function (value) + { + clonedObject.add(_clone(value)); + }); + } + else { - var value = pObject[key]; - clonedObject[key] = _clone(value); //Recursively (deep) copy for nested objects, including arrays + for (let key in pObject) + { + clonedObject[key] = _clone(pObject[key]); //Recursively (deep) copy for nested objects, including arrays + } } + Object.getOwnPropertySymbols(pObject).forEach(function (sym) + { + clonedObject[sym] = _clone(pObject[sym]); + }); + return clonedObject; } } @@ -183,6 +210,39 @@ Utils.isNumber = function (pValue) return typeof pValue === "number"; } +/** + * Checks if the given value is numeric. + * + * @param {Object} pValue the value to check + * @return {Boolean} true if the value is numeric + */ +Utils.isNumeric = function (pValue) +{ + return Utils.isNumber(pValue) || (!isNaN(parseFloat(pValue)) && isFinite(pValue)); +} + +/** + * Checks if the given value is an integer. + * + * @param {Object} pValue the value to check + * @return {Boolean} true if the value is an integer + */ +Utils.isInteger = function (pValue) +{ + return Number.isInteger(parseFloat(pValue)) && isFinite(pValue); +} + +/** + * Checks if the given value is a floating point number. + * + * @param {Object} pValue the value to check + * @return {Boolean} true if the value is a float + */ +Utils.isFloat = function (pValue) +{ + return !Number.isInteger(parseFloat(pValue)) && !isNaN(parseFloat(pValue)) && isFinite(pValue); +} + /** * Checks if the given value is an object. Be careful, null is also considered "object". * @@ -191,7 +251,7 @@ Utils.isNumber = function (pValue) */ Utils.isObject = function (pValue) { - return typeof pValue === "object"; + return typeof pValue === "object" && pValue !== null; } /** diff --git a/process/Workflow_lib/process.js b/process/Workflow_lib/process.js index d8705a1e95f0b7475a3e0301ba5ef9fe4fc4283b..38627a87e22539c50660b586e22538dee5c0ad9a 100644 --- a/process/Workflow_lib/process.js +++ b/process/Workflow_lib/process.js @@ -46,15 +46,18 @@ WorkflowUtils.openNewInstance = function (pVariables, pTargetIds, pTargetContext { if ((!pTargetIds || pTargetIds.length === 0) && pSelectionFilter) pTargetIds = []; + else if (!pTargetIds) + pTargetIds = [WorkflowVariables.TARGET_ID.getDefaultValue()]; if (!pVariables) pVariables = {}; Object.assign(pVariables, WorkflowVariables.getTargetVariables(pTargetIds, pTargetContext)); neon.openContext("WorkflowLauncher", "WorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, { - "ProcessVariables_param" : JSON.stringify(pVariables), - "TargetContext_param" : pVariables[WorkflowVariables.TARGET_CONTEXT()], - "TargetFilter_param" : pSelectionFilter ? JSON.stringify(pSelectionFilter) : "" + "ProcessVariables_param": JSON.stringify(pVariables), + "TargetContext_param": pVariables[WorkflowVariables.TARGET_CONTEXT()], + "TargetFilter_param": pSelectionFilter ? JSON.stringify(pSelectionFilter) : "", + "Targets_param": JSON.stringify(pTargetIds) }); } diff --git a/process/_all_test/_all_test.aod b/process/_all_test/_all_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..4336a9ddb94b6e8c5741887bbfd4e636f23b0541 --- /dev/null +++ b/process/_all_test/_all_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1"> + <name>_all_test</name> + <title>[TEST] .All</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/_all_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/_all_test/process.js b/process/_all_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..cbc75f35849b71f8514f1c4330683ee568e08ba0 --- /dev/null +++ b/process/_all_test/process.js @@ -0,0 +1,23 @@ +import("system.logging"); +import("system.process"); +import("UnitTest_lib"); +import("Terminal_lib"); + + +var testResults = []; + +process.getProcesses([process.VARIANT_EXECUTABLE]).forEach(function(pProcessName) { + // Run all executable processes ending with "_test" except THIS one + if(pProcessName !== "_all_test" && pProcessName.substr(-5, 5) === "_test") { + var startConfig = process.createStartConfig().setName(pProcessName); + var testResult = JSON.parse(process.start(startConfig)); + + if(testResult !== null && typeof testResult === "object") { + testResults.push(testResult); + } + } +}); + +var tester = new Tester(""); +tester.summary(testResults); + diff --git a/report/Reminder_report/reportData.jrxml b/report/Reminder_report/reportData.jrxml index 5e0e92752aff29c9212d7fed72e0a86f5592701e..1347b1ef959b34c58be528e8eecfb4bc139ff51a 100644 --- a/report/Reminder_report/reportData.jrxml +++ b/report/Reminder_report/reportData.jrxml @@ -2,7 +2,7 @@ <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Mahnung" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="e7a916c8-3f9a-497d-84bb-3909b15271ea"> <property name="ireport.zoom" value="2.1435888100000016"/> <property name="ireport.x" value="0"/> - <property name="ireport.y" value="144"/> + <property name="ireport.y" value="0"/> <parameter name="myAddr" class="java.lang.String"/> <parameter name="Kontenabstimmung" class="java.lang.String"/> <parameter name="Rech.-Nr" class="java.lang.String"/> @@ -22,6 +22,7 @@ <parameter name="Due" class="java.lang.String"/> <parameter name="DUEDATE" class="java.lang.String"/> <parameter name="Dunninglevel" class="java.lang.String"/> + <parameter name="OutstandingAmount" class="java.lang.String"/> <field name="PAYED" class="java.lang.String"/> <field name="RELATION_ID" class="java.lang.String"/> <field name="CURRENCY" class="java.lang.String"/> @@ -41,89 +42,89 @@ <textField> <reportElement x="13" y="0" width="68" height="15" uuid="0a515534-8d2a-4e3e-9370-6cac4c65ef68"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$P{Ordernumber}]]></textFieldExpression> </textField> <textField> <reportElement x="104" y="0" width="63" height="15" uuid="87fc2f40-ffdc-47d5-9fd8-7a8caf821114"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$P{Orderdate}]]></textFieldExpression> </textField> <textField> - <reportElement x="202" y="0" width="62" height="15" uuid="86eacb27-6bb5-4ce8-b8cf-c3f0993380ad"/> + <reportElement x="202" y="0" width="76" height="15" uuid="86eacb27-6bb5-4ce8-b8cf-c3f0993380ad"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$P{DueDate}]]></textFieldExpression> </textField> - <textField> - <reportElement x="429" y="0" width="59" height="15" uuid="62a0909f-ef03-4242-969a-8a9532d1aa9a"/> - <textElement textAlignment="Right"> - <font size="8"/> - </textElement> - <textFieldExpression><![CDATA[$P{Due}]]></textFieldExpression> - </textField> <line> <reportElement x="13" y="33" width="527" height="1" uuid="d5108302-191f-4e27-8920-fcd330d335e8"/> </line> <textField> <reportElement x="104" y="36" width="64" height="15" uuid="ca4c366a-1954-4aee-91c4-05c093b04df5"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$F{ORDERDATE}]]></textFieldExpression> </textField> <textField> <reportElement x="13" y="36" width="68" height="15" uuid="3fcb3ee0-fe4d-409e-8cb8-7a0e6ceca5ab"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$F{ORDERCODE}]]></textFieldExpression> </textField> <textField> <reportElement x="202" y="36" width="62" height="15" uuid="b5e006cf-5d37-42a1-bf74-0b49d3a39b27"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$F{DUEDATE}]]></textFieldExpression> </textField> <textField> - <reportElement x="428" y="36" width="60" height="15" uuid="d57eeb7b-f517-4c85-a925-cdc3c1ea0830"/> + <reportElement x="451" y="36" width="60" height="15" uuid="d57eeb7b-f517-4c85-a925-cdc3c1ea0830"/> <textElement textAlignment="Right"> - <font size="8" isBold="true"/> + <font size="8" isBold="true"/> </textElement> <textFieldExpression><![CDATA[$F{OFFEN}]]></textFieldExpression> </textField> <textField> - <reportElement x="307" y="35" width="56" height="15" uuid="72a49ece-7fc0-4cd7-a00c-94580845d150"/> + <reportElement x="332" y="35" width="56" height="15" uuid="72a49ece-7fc0-4cd7-a00c-94580845d150"/> <textElement textAlignment="Right"> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$F{BRUTTO}]]></textFieldExpression> </textField> <textField> - <reportElement x="307" y="15" width="56" height="15" uuid="a991ccab-0b04-4550-bbd2-2033a5fad0f0"/> + <reportElement x="332" y="15" width="56" height="15" uuid="a991ccab-0b04-4550-bbd2-2033a5fad0f0"/> <textElement textAlignment="Right"> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$F{CURRENCY}]]></textFieldExpression> </textField> <textField> - <reportElement x="429" y="15" width="59" height="15" uuid="8e257160-536a-418a-b9df-80fa020268b8"/> + <reportElement x="452" y="15" width="59" height="15" uuid="8e257160-536a-418a-b9df-80fa020268b8"/> <textElement textAlignment="Right"> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$F{CURRENCY}]]></textFieldExpression> </textField> <textField> - <reportElement x="326" y="0" width="62" height="15" uuid="000feb72-9b7d-42e6-ade9-8e12359c3eef"/> + <reportElement x="307" y="0" width="81" height="15" uuid="000feb72-9b7d-42e6-ade9-8e12359c3eef"/> + <textElement> + <font size="8"/> + </textElement> + <textFieldExpression><![CDATA[$R{Rechnungsbetrag}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="430" y="0" width="81" height="15" uuid="8eee46c0-f3c3-4563-b1b1-746aeb7e73c6"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> - <textFieldExpression><![CDATA[$R{Rech.-Betrag}]]></textFieldExpression> + <textFieldExpression><![CDATA[$P{OutstandingAmount}]]></textFieldExpression> </textField> </band> </groupHeader> @@ -140,7 +141,7 @@ <textField> <reportElement x="13" y="88" width="527" height="20" forecolor="#000000" uuid="a47fa80c-6b70-4c8a-938d-3d44273b1ffb"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$P{Address}]]></textFieldExpression> </textField> @@ -157,35 +158,35 @@ <textField isStretchWithOverflow="true"> <reportElement x="13" y="122" width="152" height="20" uuid="c8514bfb-5e34-43f4-a256-7899cb58f0c1"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$P{ReminderAddress}]]></textFieldExpression> </textField> <textField> <reportElement x="13" y="172" width="132" height="20" uuid="d21620a9-4a49-496e-80f6-db842f0b70a9"/> <textElement> - <font size="14" isBold="true"/> + <font size="14" isBold="true"/> </textElement> <textFieldExpression><![CDATA[$P{Reminder}]]></textFieldExpression> </textField> <textField pattern="dd.MM.yyyy"> <reportElement x="388" y="192" width="100" height="20" uuid="5141d92f-3325-445b-b616-90630c1648f7"/> <textElement textAlignment="Right"> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[new java.util.Date()]]></textFieldExpression> </textField> <textField> <reportElement x="13" y="232" width="294" height="20" uuid="3f7d1c4a-a326-436b-831d-5da9fd255bf0"/> <textElement> - <font size="8" isBold="true"/> + <font size="8" isBold="true"/> </textElement> <textFieldExpression><![CDATA[$F{DUNNINGTEXT}]]></textFieldExpression> </textField> <textField> <reportElement x="13" y="212" width="214" height="20" uuid="52834aec-d107-4cc7-9662-1cdd73ba15c1"/> <textElement> - <font size="8" isBold="true"/> + <font size="8" isBold="true"/> </textElement> <textFieldExpression><![CDATA[$P{Dunninglevel} + " " + $F{DUNNINGLEVEL}]]></textFieldExpression> </textField> @@ -196,21 +197,21 @@ <textField pattern="EEEEE dd MMMMM yyyy"> <reportElement x="340" y="13" width="112" height="15" forecolor="#999999" uuid="26510f19-a203-4b34-8093-f6a9f7f6050e"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[new java.util.Date()]]></textFieldExpression> </textField> <textField> <reportElement x="452" y="13" width="48" height="15" forecolor="#999999" uuid="218ef560-390f-4807-b7f6-98e6f6162892"/> <textElement textAlignment="Right"> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[$R{Seite}+" "+$V{PAGE_NUMBER}+" "+$R{von}]]></textFieldExpression> </textField> <textField evaluationTime="Report"> <reportElement x="500" y="13" width="40" height="15" forecolor="#999999" uuid="7ac354ed-0f8f-41fa-80a5-c2a0f74f7e09"/> <textElement> - <font size="8"/> + <font size="8"/> </textElement> <textFieldExpression><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression> </textField>