Remove single-parent concept on app-children; more working version of recordLock from join

This commit is contained in:
2023-01-13 09:23:06 -06:00
parent 9a58c7683b
commit 2b0974f4a5
16 changed files with 162 additions and 157 deletions

View File

@ -310,11 +310,11 @@ public abstract class AbstractRDBMSAction implements QActionInterface
{
String whereClauseWithoutSecurity = makeWhereClauseWithoutSecurity(instance, table, joinsContext, filter, params);
QQueryFilter securityFilter = getSecurityFilter(instance, session, table, joinsContext);
if(securityFilter == null || CollectionUtils.nullSafeIsEmpty(securityFilter.getCriteria()))
if(!securityFilter.hasAnyCriteria())
{
return (whereClauseWithoutSecurity);
}
String securityWhereClause = getSqlWhereStringAndPopulateParamsListFromNonNestedFilter(instance, table, joinsContext, securityFilter.getCriteria(), QQueryFilter.BooleanOperator.AND, params);
String securityWhereClause = makeWhereClauseWithoutSecurity(instance, table, joinsContext, securityFilter, params);
return ("(" + whereClauseWithoutSecurity + ") AND (" + securityWhereClause + ")");
}
@ -367,14 +367,14 @@ public abstract class AbstractRDBMSAction implements QActionInterface
*******************************************************************************/
private QQueryFilter getSecurityFilter(QInstance instance, QSession session, QTableMetaData table, JoinsContext joinsContext)
{
QQueryFilter newFilter = new QQueryFilter();
newFilter.setBooleanOperator(QQueryFilter.BooleanOperator.AND);
List<QFilterCriteria> securityCriteria = new ArrayList<>();
newFilter.setCriteria(securityCriteria);
QQueryFilter securityFilter = new QQueryFilter();
securityFilter.setBooleanOperator(QQueryFilter.BooleanOperator.AND);
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(table.getRecordSecurityLocks()))
{
addCriteriaForRecordSecurityLock(instance, session, table, securityCriteria, recordSecurityLock, joinsContext, table.getName());
// todo - uh, if it's a RIGHT (or FULL) join, then, this should be isOuter = true, right?
boolean isOuter = false;
addSubFilterForRecordSecurityLock(instance, session, table, securityFilter, recordSecurityLock, joinsContext, table.getName(), isOuter);
}
for(QueryJoin queryJoin : CollectionUtils.nonNullList(joinsContext.getQueryJoins()))
@ -382,11 +382,12 @@ public abstract class AbstractRDBMSAction implements QActionInterface
QTableMetaData joinTable = instance.getTable(queryJoin.getJoinTable());
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(joinTable.getRecordSecurityLocks()))
{
addCriteriaForRecordSecurityLock(instance, session, joinTable, securityCriteria, recordSecurityLock, joinsContext, queryJoin.getJoinTableOrItsAlias());
boolean isOuter = queryJoin.getType().equals(QueryJoin.Type.LEFT); // todo full?
addSubFilterForRecordSecurityLock(instance, session, joinTable, securityFilter, recordSecurityLock, joinsContext, queryJoin.getJoinTableOrItsAlias(), isOuter);
}
}
return (newFilter);
return (securityFilter);
}
@ -394,7 +395,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
/*******************************************************************************
**
*******************************************************************************/
private static void addCriteriaForRecordSecurityLock(QInstance instance, QSession session, QTableMetaData table, List<QFilterCriteria> securityCriteria, RecordSecurityLock recordSecurityLock, JoinsContext joinsContext, String tableNameOrAlias)
private static void addSubFilterForRecordSecurityLock(QInstance instance, QSession session, QTableMetaData table, QQueryFilter securityFilter, RecordSecurityLock recordSecurityLock, JoinsContext joinsContext, String tableNameOrAlias, boolean isOuter)
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// check if the key type has an all-access key, and if so, if it's set to true for the current user/session //
@ -411,9 +412,12 @@ public abstract class AbstractRDBMSAction implements QActionInterface
}
}
if(CollectionUtils.nullSafeHasContents(recordSecurityLock.getJoinChain()))
String fieldName = tableNameOrAlias + "." + recordSecurityLock.getFieldName();
String fieldNameWithoutTablePrefix = recordSecurityLock.getFieldName().replaceFirst(".*\\.", "");
String fieldNameTablePrefix = recordSecurityLock.getFieldName().replaceFirst("\\..*", "");
if(CollectionUtils.nullSafeHasContents(recordSecurityLock.getJoinNameChain()))
{
for(String joinName : recordSecurityLock.getJoinChain())
for(String joinName : recordSecurityLock.getJoinNameChain())
{
QJoinMetaData joinMetaData = instance.getJoin(joinName);
@ -433,16 +437,27 @@ public abstract class AbstractRDBMSAction implements QActionInterface
throw (new RuntimeException("Could not find joinMetaData for recordSecurityLock with joinChain member [" + joinName + "]"));
}
table = instance.getTable(joinMetaData.getRightTable());
if(fieldNameTablePrefix.equals(joinMetaData.getLeftTable()))
{
table = instance.getTable(joinMetaData.getLeftTable());
}
else
{
table = instance.getTable(joinMetaData.getRightTable());
}
tableNameOrAlias = table.getName();
fieldName = tableNameOrAlias + "." + fieldNameWithoutTablePrefix;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// else - get the key values from the session and decide what kind of criterion to build //
///////////////////////////////////////////////////////////////////////////////////////////
List<Serializable> securityKeyValues = session.getSecurityKeyValues(recordSecurityLock.getSecurityKeyType(), table.getField(recordSecurityLock.getFieldName()).getType());
String fieldName = tableNameOrAlias + "." + recordSecurityLock.getFieldName();
QQueryFilter lockFilter = new QQueryFilter();
List<QFilterCriteria> lockCriteria = new ArrayList<>();
lockFilter.setCriteria(lockCriteria);
List<Serializable> securityKeyValues = session.getSecurityKeyValues(recordSecurityLock.getSecurityKeyType(), table.getField(fieldNameWithoutTablePrefix).getType());
if(CollectionUtils.nullSafeIsEmpty(securityKeyValues))
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -450,7 +465,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(recordSecurityLock.getNullValueBehavior()))
{
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_BLANK));
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_BLANK));
}
else
{
@ -458,7 +473,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
// else, if no user/session values, and null-value behavior is deny, then setup a FALSE condition, to allow no rows. //
// todo - make some explicit contradiction here - maybe even avoid running the whole query - as you're not allowed ANY records //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, Collections.emptyList()));
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, Collections.emptyList()));
}
}
else
@ -469,13 +484,26 @@ public abstract class AbstractRDBMSAction implements QActionInterface
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(recordSecurityLock.getNullValueBehavior()))
{
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_NULL_OR_IN, securityKeyValues));
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_NULL_OR_IN, securityKeyValues));
}
else
{
securityCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, securityKeyValues));
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IN, securityKeyValues));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if this field is on the outer side of an outer join, then if we do a straight filter on it, then we're basically //
// nullifying the outer join... so for an outer join use-case, OR the security field criteria with a primary-key IS NULL //
// which will make missing rows from the join be found. //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(isOuter)
{
lockFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
lockFilter.addCriteria(new QFilterCriteria(tableNameOrAlias + "." + table.getPrimaryKeyField(), QCriteriaOperator.IS_BLANK));
}
securityFilter.addSubFilter(lockFilter);
}

View File

@ -1287,8 +1287,8 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
qInstance.getTable(TestUtils.TABLE_NAME_ORDER).getRecordSecurityLocks().clear();
qInstance.getTable(TestUtils.TABLE_NAME_ORDER).withRecordSecurityLock(new RecordSecurityLock()
.withSecurityKeyType(TestUtils.TABLE_NAME_STORE)
.withJoinChain(List.of("orderJoinStore"))
.withFieldName("id"));
.withJoinNameChain(List.of("orderJoinStore"))
.withFieldName("store.id"));
queryInput.setFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.BETWEEN, List.of(2, 7))));
queryInput.setSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true));