From fe30d2654b24b7428239c238ecd8e334299c60b2 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 20 Jan 2023 10:05:44 -0600 Subject: [PATCH] update to implicity add a queryJoin, if a filter field calls out a table name that matches a join in the instance --- .../reporting/GenerateReportAction.java | 4 +- .../actions/tables/query/JoinsContext.java | 113 ++++++++++++++++-- .../rdbms/actions/RDBMSAggregateAction.java | 2 +- .../rdbms/actions/RDBMSCountAction.java | 2 +- .../rdbms/actions/RDBMSDeleteAction.java | 2 +- .../rdbms/actions/RDBMSQueryAction.java | 2 +- .../rdbms/actions/RDBMSQueryActionTest.java | 20 +++- 7 files changed, 125 insertions(+), 20 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java index 617783ff..c748e813 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java @@ -225,7 +225,7 @@ public class GenerateReportAction JoinsContext joinsContext = null; if(StringUtils.hasContent(dataSource.getSourceTable())) { - joinsContext = new JoinsContext(exportInput.getInstance(), dataSource.getSourceTable(), dataSource.getQueryJoins()); + joinsContext = new JoinsContext(exportInput.getInstance(), dataSource.getSourceTable(), dataSource.getQueryJoins(), dataSource.getQueryFilter()); } List fields = new ArrayList<>(); @@ -308,7 +308,7 @@ public class GenerateReportAction queryInput.setQueryJoins(dataSource.getQueryJoins()); queryInput.setShouldTranslatePossibleValues(true); - queryInput.setFieldsToTranslatePossibleValues(setupFieldsToTranslatePossibleValues(reportInput, dataSource, new JoinsContext(reportInput.getInstance(), dataSource.getSourceTable(), dataSource.getQueryJoins()))); + queryInput.setFieldsToTranslatePossibleValues(setupFieldsToTranslatePossibleValues(reportInput, dataSource, new JoinsContext(reportInput.getInstance(), dataSource.getSourceTable(), dataSource.getQueryJoins(), queryInput.getFilter()))); if(dataSource.getQueryInputCustomizer() != null) { diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/JoinsContext.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/JoinsContext.java index d155e45e..af829759 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/JoinsContext.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/JoinsContext.java @@ -23,8 +23,12 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; @@ -55,7 +59,7 @@ public class JoinsContext ** Constructor ** *******************************************************************************/ - public JoinsContext(QInstance instance, String tableName, List queryJoins) throws QException + public JoinsContext(QInstance instance, String tableName, List queryJoins, QQueryFilter filter) throws QException { this.instance = instance; this.mainTableName = tableName; @@ -63,13 +67,7 @@ public class JoinsContext for(QueryJoin queryJoin : this.queryJoins) { - QTableMetaData joinTable = instance.getTable(queryJoin.getJoinTable()); - String tableNameOrAlias = queryJoin.getJoinTableOrItsAlias(); - if(aliasToTableNameMap.containsKey(tableNameOrAlias)) - { - throw (new QException("Duplicate table name or alias: " + tableNameOrAlias)); - } - aliasToTableNameMap.put(tableNameOrAlias, joinTable.getName()); + processQueryJoin(queryJoin); } /////////////////////////////////////////////////////////////// @@ -92,11 +90,16 @@ public class JoinsContext { join = join.flip(); } - this.queryJoins.add(new QueryJoin().withJoinMetaData(join).withType(QueryJoin.Type.INNER)); // todo aliases? probably. + + QueryJoin queryJoin = new QueryJoin().withJoinMetaData(join).withType(QueryJoin.Type.INNER); + this.queryJoins.add(queryJoin); // todo something else with aliases? probably. + processQueryJoin(queryJoin); } } } + ensureFilterIsRepresented(filter); + /* todo!! for(QueryJoin queryJoin : queryJoins) { @@ -111,6 +114,22 @@ public class JoinsContext + /******************************************************************************* + ** + *******************************************************************************/ + private void processQueryJoin(QueryJoin queryJoin) throws QException + { + QTableMetaData joinTable = QContext.getQInstance().getTable(queryJoin.getJoinTable()); + String tableNameOrAlias = queryJoin.getJoinTableOrItsAlias(); + if(aliasToTableNameMap.containsKey(tableNameOrAlias)) + { + throw (new QException("Duplicate table name or alias: " + tableNameOrAlias)); + } + aliasToTableNameMap.put(tableNameOrAlias, joinTable.getName()); + } + + + /******************************************************************************* ** Getter for queryJoins ** @@ -202,6 +221,82 @@ public class JoinsContext + /******************************************************************************* + ** + *******************************************************************************/ + private void ensureFilterIsRepresented(QQueryFilter filter) throws QException + { + Set filterTables = new HashSet<>(); + populateFilterTablesSet(filter, filterTables); + + for(String filterTable : filterTables) + { + if(!aliasToTableNameMap.containsKey(filterTable) && !Objects.equals(mainTableName, filterTable)) + { + for(QJoinMetaData join : CollectionUtils.nonNullMap(QContext.getQInstance().getJoins()).values()) + { + QueryJoin queryJoin = null; + if(join.getLeftTable().equals(mainTableName) && join.getRightTable().equals(filterTable)) + { + queryJoin = new QueryJoin().withJoinMetaData(join).withType(QueryJoin.Type.INNER); + } + else + { + join = join.flip(); + if(join.getLeftTable().equals(mainTableName) && join.getRightTable().equals(filterTable)) + { + queryJoin = new QueryJoin().withJoinMetaData(join).withType(QueryJoin.Type.INNER); + } + } + + if(queryJoin != null) + { + this.queryJoins.add(queryJoin); // todo something else with aliases? probably. + processQueryJoin(queryJoin); + } + } + } + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void populateFilterTablesSet(QQueryFilter filter, Set filterTables) + { + if(filter != null) + { + for(QFilterCriteria criteria : CollectionUtils.nonNullList(filter.getCriteria())) + { + getTableNameFromFieldNameAndAddToSet(criteria.getFieldName(), filterTables); + getTableNameFromFieldNameAndAddToSet(criteria.getOtherFieldName(), filterTables); + } + + for(QQueryFilter subFilter : CollectionUtils.nonNullList(filter.getSubFilters())) + { + populateFilterTablesSet(subFilter, filterTables); + } + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void getTableNameFromFieldNameAndAddToSet(String fieldName, Set filterTables) + { + if(fieldName != null && fieldName.contains(".")) + { + String tableName = fieldName.replaceFirst("\\..*", ""); + filterTables.add(tableName); + } + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSAggregateAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSAggregateAction.java index 779b7cfc..9cec0a47 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSAggregateAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSAggregateAction.java @@ -64,7 +64,7 @@ public class RDBMSAggregateAction extends AbstractRDBMSAction implements Aggrega { QTableMetaData table = aggregateInput.getTable(); - JoinsContext joinsContext = new JoinsContext(aggregateInput.getInstance(), table.getName(), aggregateInput.getQueryJoins()); + JoinsContext joinsContext = new JoinsContext(aggregateInput.getInstance(), table.getName(), aggregateInput.getQueryJoins(), aggregateInput.getFilter()); String fromClause = makeFromClause(aggregateInput.getInstance(), table.getName(), joinsContext); List selectClauses = buildSelectClauses(aggregateInput, joinsContext); diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSCountAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSCountAction.java index 37fbacd5..e3809579 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSCountAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSCountAction.java @@ -56,7 +56,7 @@ public class RDBMSCountAction extends AbstractRDBMSAction implements CountInterf { QTableMetaData table = countInput.getTable(); - JoinsContext joinsContext = new JoinsContext(countInput.getInstance(), countInput.getTableName(), countInput.getQueryJoins()); + JoinsContext joinsContext = new JoinsContext(countInput.getInstance(), countInput.getTableName(), countInput.getQueryJoins(), countInput.getFilter()); String sql = "SELECT count(*) as record_count FROM " + makeFromClause(countInput.getInstance(), table.getName(), joinsContext); diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java index 45db8596..5c669444 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java @@ -260,7 +260,7 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte QTableMetaData table = deleteInput.getTable(); String tableName = getTableName(table); - JoinsContext joinsContext = new JoinsContext(deleteInput.getInstance(), table.getName(), Collections.emptyList()); + JoinsContext joinsContext = new JoinsContext(deleteInput.getInstance(), table.getName(), Collections.emptyList(), deleteInput.getQueryFilter()); String whereClause = makeWhereClause(deleteInput.getInstance(), deleteInput.getSession(), table, joinsContext, filter, params); // todo sql customization - can edit sql and/or param list? diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryAction.java index e1596527..16d32f4c 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryAction.java @@ -70,7 +70,7 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf StringBuilder sql = new StringBuilder("SELECT ").append(makeSelectClause(queryInput)); - JoinsContext joinsContext = new JoinsContext(queryInput.getInstance(), tableName, queryInput.getQueryJoins()); + JoinsContext joinsContext = new JoinsContext(queryInput.getInstance(), tableName, queryInput.getQueryJoins(), queryInput.getFilter()); sql.append(" FROM ").append(makeFromClause(queryInput.getInstance(), tableName, joinsContext)); QQueryFilter filter = queryInput.getFilter(); diff --git a/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryActionTest.java b/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryActionTest.java index 2430c5a2..2cb80417 100644 --- a/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryActionTest.java +++ b/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSQueryActionTest.java @@ -639,6 +639,21 @@ public class RDBMSQueryActionTest extends RDBMSActionTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testFilterFromJoinTableImplicitly() throws QException + { + QueryInput queryInput = initQueryRequest(); + queryInput.setFilter(new QQueryFilter(new QFilterCriteria("personalIdCard.idNumber", QCriteriaOperator.EQUALS, "19800531"))); + QueryOutput queryOutput = new QueryAction().execute(queryInput); + assertEquals(1, queryOutput.getRecords().size(), "Query should find 1 rows"); + assertThat(queryOutput.getRecords()).anyMatch(r -> r.getValueString("firstName").equals("Darin")); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -999,7 +1014,6 @@ public class RDBMSQueryActionTest extends RDBMSActionTest @Test void testRecordSecurityPrimaryKeyFieldNoFilters() throws QException { - QInstance qInstance = TestUtils.defineInstance(); QueryInput queryInput = new QueryInput(); queryInput.setTableName(TestUtils.TABLE_NAME_STORE); @@ -1044,7 +1058,6 @@ public class RDBMSQueryActionTest extends RDBMSActionTest @Test void testRecordSecurityForeignKeyFieldNoFilters() throws QException { - QInstance qInstance = TestUtils.defineInstance(); QueryInput queryInput = new QueryInput(); queryInput.setTableName(TestUtils.TABLE_NAME_ORDER); @@ -1087,7 +1100,6 @@ public class RDBMSQueryActionTest extends RDBMSActionTest @Test void testRecordSecurityWithFilters() throws QException { - QInstance qInstance = TestUtils.defineInstance(); QueryInput queryInput = new QueryInput(); queryInput.setTableName(TestUtils.TABLE_NAME_ORDER); @@ -1124,7 +1136,6 @@ public class RDBMSQueryActionTest extends RDBMSActionTest @Test void testRecordSecurityWithOrQueries() throws QException { - QInstance qInstance = TestUtils.defineInstance(); QueryInput queryInput = new QueryInput(); queryInput.setTableName(TestUtils.TABLE_NAME_ORDER); @@ -1156,7 +1167,6 @@ public class RDBMSQueryActionTest extends RDBMSActionTest @Test void testRecordSecurityWithSubFilters() throws QException { - QInstance qInstance = TestUtils.defineInstance(); QueryInput queryInput = new QueryInput(); queryInput.setTableName(TestUtils.TABLE_NAME_ORDER);