package de.superx.bianalysis; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringJoiner; import org.junit.Test; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import de.superx.bianalysis.models.CriteriaGroup; import de.superx.bianalysis.sqlgeneration.AttributeGroupQueryBuilder; import de.superx.bianalysis.sqlgeneration.SqlQuery; @SuppressWarnings("static-method") public class AttributeGroupQueryBuilderTest { @Test public void testInOperator() throws JsonMappingException, JsonProcessingException { String criteriaGroupsJson = """ [ { "caption":"2001 - 2005", "conditions": [ { "column" : "year_of_birth", "operator": "IN", "values": [ "2001", "2002", "2003", "2004", "2005" ] } ] }, { "caption":"2006 - 2010", "conditions": [ { "column" : "year_of_birth", "operator": "IN", "values": [ "2006", "2007", "2008", "2009" ] } ] }, { "caption":"n.a", "isElse" : true } ] """; List criteriaGroups = new ObjectMapper() .readValue(criteriaGroupsJson, new TypeReference>(){}); String tableName = "presentation.dim_person"; String columname = "myagegroup"; SqlQuery query = AttributeGroupQueryBuilder .buildColumnQuery(criteriaGroups, tableName, false, columname); Object[] expectedParams = Arrays.asList( "2001", "2002", "2003", "2004", "2005", "2001 - 2005", "2006", "2007", "2008", "2009", "2006 - 2010", "n.a" ).toArray(); String expectedSql = "UPDATE presentation.dim_person" + " SET myagegroup = CASE" + " WHEN year_of_birth IN ( ?, ?, ?, ?, ? ) THEN ?" + " WHEN year_of_birth IN ( ?, ?, ?, ? ) THEN ?" + " ELSE ? END"; int[] expectedTypes = new int[12]; Arrays.fill(expectedTypes, Types.VARCHAR); assertArrayEquals(expectedParams, query.getParams()); assertEquals(expectedSql, query.getSql()); assertArrayEquals(expectedTypes, query.getTypes()); } @Test public void testComparisonOperator() throws JsonMappingException, JsonProcessingException { String criteriaGroupsJson = """ [ { "caption" : "Unter 18", "conditions" : [ { "column" : "age", "operator" : "<", "value" : "18" } ] }, { "logic" : "AND", "caption" : "Ab 18 bis 50", "conditions" : [ { "column" : "age", "operator" : ">=", "value" : "18" }, { "column" : "age", "operator" : "<=", "value" : "50" } ] }, { "caption" : "Über 50", "conditions" : [ { "column" : "age", "operator" : ">", "value" : "50" } ] } ] """; List criteriaGroups = new ObjectMapper() .readValue(criteriaGroupsJson, new TypeReference>(){}); String tableName = "presentation.dim_age"; String columname = "myagegroup"; SqlQuery query = AttributeGroupQueryBuilder .buildColumnQuery(criteriaGroups, tableName, false, columname); Object[] expectedParams = Arrays.asList( "18", "Unter 18", "18", "50", "Ab 18 bis 50", "50", "Über 50", "n.v.").toArray(); String expectedSql = "UPDATE presentation.dim_age" + " SET myagegroup = CASE" + " WHEN age ~ E'^-?\\\\d+$' AND age::int < ? THEN ?" + " WHEN age ~ E'^-?\\\\d+$' AND age::int >= ?" + " AND age ~ E'^-?\\\\d+$' AND age::int <= ? THEN ?" + " WHEN age ~ E'^-?\\\\d+$' AND age::int > ? THEN ? ELSE ? END"; int[] expectedTypes = { Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.INTEGER, Types.VARCHAR, Types.INTEGER, Types.VARCHAR, Types.VARCHAR }; assertArrayEquals(expectedParams, query.getParams()); assertEquals(expectedSql, query.getSql()); assertArrayEquals(expectedTypes, query.getTypes()); } @Test public void testNestedConditions() throws JsonMappingException, JsonProcessingException { String criteriaGroupJson = """ { "caption":"(Teens AND High Income) OR VIP", "logic":"OR", "conditions":[ { "logic":"AND", "conditions":[ { "column":"age", "operator":">=", "value":"13" }, { "column":"age", "operator":"<", "value":"20" }, { "column":"income", "operator":">", "value":"50000" } ] }, { "column": "status", "operator": "=", "value": "VIP" } ] } """; CriteriaGroup criteriaGroup = new ObjectMapper() .readValue(criteriaGroupJson, CriteriaGroup.class); StringJoiner joiner = AttributeGroupQueryBuilder .buildConditionClause(new ArrayList(), new ArrayList(), criteriaGroup); String sql = "(age ~ E'^-?\\\\d+$'" + " AND age::int >= ? AND age ~ E'^-?\\\\d+$' " + "AND age::int < ? AND income ~ E'^-?\\\\d+$' " + "AND income::int > ?) OR status = ?"; assertEquals(sql , joiner.toString()); } @Test public void testValidationQuery() throws JsonMappingException, JsonProcessingException { String json = """ [ { "caption": "erste", "conditions": [ { "column": "first_nationality", "operator": "NOT IN", "value": "", "values": [ "Afghanistan", "Bulgarien" ] } ] }, { "caption": "zweite", "conditions": [ { "column": "first_nationality", "operator": "NOT IN", "value": "", "values": [ "Bulgarien", "Ägypten" ] }, { "column": "first_nationality", "operator": "NOT IN", "value": "", "values": [ "Frankreich" ] } ] } ], """; List groups = new ObjectMapper() .readValue(json, new TypeReference>(){}); String tableName = "presentation.dim_person_applicant"; String colList = "first_nationality"; List queries = AttributeGroupQueryBuilder.buildValidationQuery(tableName, colList, groups); assertEquals(1, queries.size()); SqlQuery query = queries.get(0); String expectedSql = "SELECT first_nationality" + " FROM presentation.dim_person_applicant" + " WHERE first_nationality NOT IN ( ?, ? )" + " INTERSECT" + " SELECT first_nationality" + " FROM presentation.dim_person_applicant" + " WHERE first_nationality NOT IN ( ?, ? )" + " AND first_nationality NOT IN ( ? )"; Object[] expectedParams = Arrays.asList( "Afghanistan", "Bulgarien", "Bulgarien", "Ägypten", "Frankreich" ).toArray(); int[] expectedTypes = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR }; assertArrayEquals(expectedParams, query.getParams()); assertEquals(expectedSql, query.getSql()); assertArrayEquals(expectedTypes, query.getTypes()); } @Test public void testValidationQueryForThree() throws JsonMappingException, JsonProcessingException { String json = """ [ { "caption": "Unter 18", "conditions": [ { "column": "age", "operator": "<", "value": "18" } ], "isElse": false, "logic": null }, { "caption": "Ab 18 bis 50", "conditions": [ { "column": "age", "columnCaption": "Alter", "operator": ">=", "value": "16" }, { "column": "age", "columnCaption": "Alter", "operator": "<=", "value": "50" } ], "isElse": false, "logic": "AND" }, { "caption": "Über 50", "conditions": [ { "column": "age", "operator": ">", "value": "50" } ], "isElse": false, "logic": null } ] """; List groups = new ObjectMapper() .readValue(json, new TypeReference>(){}); String tableName = "presentation.dim_age"; String columname = "age"; List queries = AttributeGroupQueryBuilder.buildValidationQuery(tableName, columname, groups); assertEquals(3, queries.size()); String expectedSqlFirst = "SELECT age FROM presentation.dim_age" + " WHERE age ~ E'^-?\\\\d+$' AND age::int >= ?" + " AND age ~ E'^-?\\\\d+$' AND age::int <= ?" + " INTERSECT SELECT age FROM presentation.dim_age" + " WHERE age ~ E'^-?\\\\d+$' AND age::int > ?"; String expectedSqlSecond = "SELECT age FROM presentation.dim_age" + " WHERE age ~ E'^-?\\\\d+$' AND age::int < ?" + " INTERSECT SELECT age FROM presentation.dim_age" + " WHERE age ~ E'^-?\\\\d+$' AND age::int > ?"; String expectedSqlThird = "SELECT age FROM presentation.dim_age" + " WHERE age ~ E'^-?\\\\d+$' AND age::int < ?" + " INTERSECT SELECT age FROM presentation.dim_age" + " WHERE age ~ E'^-?\\\\d+$' AND age::int >= ?" + " AND age ~ E'^-?\\\\d+$' AND age::int <= ?"; Object[] expectedParamsFirst = Arrays.asList("16", "50", "50").toArray(); Object[] expectedParamsSecond = Arrays.asList("18", "50").toArray(); Object[] expectedParamsThird = Arrays.asList("18", "16", "50").toArray(); int[] expectedTypesFirst = {Types.INTEGER, Types.INTEGER, Types.INTEGER}; int[] expectedTypesSecond = {Types.INTEGER, Types.INTEGER}; int[] expectedTypesThird = {Types.INTEGER, Types.INTEGER, Types.INTEGER}; assertArrayEquals(expectedParamsFirst, queries.get(0).getParams()); assertEquals(expectedSqlFirst, queries.get(0).getSql()); assertArrayEquals(expectedTypesFirst, queries.get(0).getTypes()); assertArrayEquals(expectedParamsSecond, queries.get(1).getParams()); assertEquals(expectedSqlSecond, queries.get(1).getSql()); assertArrayEquals(expectedTypesSecond, queries.get(1).getTypes()); assertArrayEquals(expectedParamsThird, queries.get(2).getParams()); assertEquals(expectedSqlThird, queries.get(2).getSql()); assertArrayEquals(expectedTypesThird, queries.get(2).getTypes()); } @Test public void testValidationQueryWithNV() throws JsonMappingException, JsonProcessingException { String json = """ [ { "caption": "n. v.", "isElse": true }, { "caption": "Männlich", "conditions": [ { "column": "gender", "columnCaption": "Geschlecht", "operator": "=", "value": "männlich", "values": [] } ], "isElse": false }, { "caption": "Weiblich", "conditions": [ { "column": "gender", "columnCaption": "Geschlecht", "operator": "=", "value": "weiblich", "values": [] } ], "isElse": false } ] """; List groups = new ObjectMapper() .readValue(json, new TypeReference>(){}); String tableName = "presentation.dim_person_applicant"; String columname = "gender"; List queries = AttributeGroupQueryBuilder.buildValidationQuery(tableName, columname, groups); assertEquals(1, queries.size()); String expectedSql = "SELECT gender FROM presentation.dim_person_applicant" + " WHERE gender = ? INTERSECT SELECT gender" + " FROM presentation.dim_person_applicant WHERE gender = ?"; Object[] expectedParams= Arrays.asList("männlich", "weiblich").toArray(); int[] expectedTypes = {Types.VARCHAR, Types.VARCHAR}; assertArrayEquals(expectedParams, queries.get(0).getParams()); assertEquals(expectedSql, queries.get(0).getSql()); assertArrayEquals(expectedTypes, queries.get(0).getTypes()); } }