Merged dev into feature/quartz-scheduler

This commit is contained in:
2024-03-06 19:12:39 -06:00
294 changed files with 22642 additions and 18202 deletions

View File

@ -22,20 +22,27 @@
package com.kingsrook.qqq.backend.module.rdbms;
import java.sql.Connection;
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
import com.kingsrook.qqq.backend.core.actions.interfaces.AggregateInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.module.rdbms.actions.AbstractRDBMSAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSAggregateAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSCountAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSDeleteAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSInsertAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSQueryAction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSTransaction;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSUpdateAction;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
@ -46,6 +53,10 @@ import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDe
*******************************************************************************/
public class RDBMSBackendModule implements QBackendModuleInterface
{
private static final QLogger LOG = QLogger.getLogger(RDBMSBackendModule.class);
/*******************************************************************************
** Method where a backend module must be able to provide its type (name).
*******************************************************************************/
@ -142,4 +153,24 @@ public class RDBMSBackendModule implements QBackendModuleInterface
return (new RDBMSAggregateAction());
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public QBackendTransaction openTransaction(AbstractTableActionInput input) throws QException
{
try
{
LOG.debug("Opening transaction");
Connection connection = AbstractRDBMSAction.getConnection(input);
return (new RDBMSTransaction(connection));
}
catch(Exception e)
{
throw new QException("Error opening transaction: " + e.getMessage(), e);
}
}
}

View File

@ -40,8 +40,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
import com.kingsrook.qqq.backend.core.actions.interfaces.QActionInterface;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
@ -68,6 +66,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.security.NullValueBehaviorUtil;
import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock;
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLockFilters;
@ -87,7 +86,7 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
** Base class for all core actions in the RDBMS module.
*******************************************************************************/
public abstract class AbstractRDBMSAction implements QActionInterface
public abstract class AbstractRDBMSAction
{
private static final QLogger LOG = QLogger.getLogger(AbstractRDBMSAction.class);
@ -136,7 +135,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
/*******************************************************************************
** Get a database connection, per the backend in the request.
*******************************************************************************/
protected Connection getConnection(AbstractTableActionInput qTableRequest) throws SQLException
public static Connection getConnection(AbstractTableActionInput qTableRequest) throws SQLException
{
ConnectionManager connectionManager = new ConnectionManager();
return connectionManager.getConnection((RDBMSBackendMetaData) qTableRequest.getBackend());
@ -469,7 +468,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// handle user with no values -- they can only see null values, and only iff the lock's null-value behavior is ALLOW //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(recordSecurityLock.getNullValueBehavior()))
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(NullValueBehaviorUtil.getEffectiveNullValueBehavior(recordSecurityLock)))
{
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_BLANK));
}
@ -488,7 +487,7 @@ public abstract class AbstractRDBMSAction implements QActionInterface
// else, if user/session has some values, build an IN rule - //
// noting that if the lock's null-value behavior is ALLOW, then we actually want IS_NULL_OR_IN, not just IN //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(recordSecurityLock.getNullValueBehavior()))
if(RecordSecurityLock.NullValueBehavior.ALLOW.equals(NullValueBehaviorUtil.getEffectiveNullValueBehavior(recordSecurityLock)))
{
lockCriteria.add(new QFilterCriteria(fieldName, QCriteriaOperator.IS_NULL_OR_IN, securityKeyValues));
}
@ -826,27 +825,6 @@ public abstract class AbstractRDBMSAction implements QActionInterface
/*******************************************************************************
**
*******************************************************************************/
@Override
public QBackendTransaction openTransaction(AbstractTableActionInput input) throws QException
{
try
{
LOG.debug("Opening transaction");
Connection connection = getConnection(input);
return (new RDBMSTransaction(connection));
}
catch(Exception e)
{
throw new QException("Error opening transaction: " + e.getMessage(), e);
}
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -24,7 +24,6 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
import java.io.Serializable;
import java.sql.Connection;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -38,7 +37,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
@ -56,25 +54,7 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
public InsertOutput execute(InsertInput insertInput) throws QException
{
InsertOutput rs = new InsertOutput();
if(CollectionUtils.nullSafeIsEmpty(insertInput.getRecords()))
{
LOG.debug("Insert request called with 0 records. Returning with no-op", logPair("tableName", insertInput.getTableName()));
rs.setRecords(new ArrayList<>());
return (rs);
}
QTableMetaData table = insertInput.getTable();
Instant now = Instant.now();
for(QRecord record : insertInput.getRecords())
{
///////////////////////////////////////////
// todo .. better (not hard-coded names) //
///////////////////////////////////////////
setValueIfTableHasField(record, table, "createDate", now);
setValueIfTableHasField(record, table, "modifyDate", now);
}
try
{

View File

@ -54,6 +54,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.Pair;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
@ -260,7 +261,7 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
throw (new QUserFacingException("Query was cancelled."));
}
LOG.warn("Error executing query", e);
LOG.warn("Error executing query", e, logPair("tableName", queryInput.getTableName()), logPair("filter", queryInput.getFilter()));
throw new QException("Error executing query", e);
}
}

View File

@ -25,19 +25,18 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Map;
import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
import com.kingsrook.qqq.backend.core.actions.tables.helpers.UpdateActionRecordSplitHelper;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.ListingHash;
@ -66,60 +65,15 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
*******************************************************************************/
public UpdateOutput execute(UpdateInput updateInput) throws QException
{
UpdateOutput rs = new UpdateOutput();
if(CollectionUtils.nullSafeIsEmpty(updateInput.getRecords()))
{
LOG.debug("Update request called with 0 records. Returning with no-op");
rs.setRecords(new ArrayList<>());
return (rs);
}
QTableMetaData table = updateInput.getTable();
Instant now = Instant.now();
List<QRecord> outputRecords = new ArrayList<>();
rs.setRecords(outputRecords);
UpdateActionRecordSplitHelper updateActionRecordSplitHelper = new UpdateActionRecordSplitHelper();
updateActionRecordSplitHelper.init(updateInput);
/////////////////////////////////////////////////////////////////////////////////////////////
// we want to do batch updates. But, since we only update the columns that //
// are present in each record, it means we may have different update SQL for each //
// record. So, we will first "hash" up the records by their list of fields being updated. //
/////////////////////////////////////////////////////////////////////////////////////////////
ListingHash<List<String>, QRecord> recordsByFieldBeingUpdated = new ListingHash<>();
boolean haveAnyWithoutErorrs = false;
for(QRecord record : updateInput.getRecords())
{
////////////////////////////////////////////
// todo .. better (not a hard-coded name) //
////////////////////////////////////////////
setValueIfTableHasField(record, table, "modifyDate", now);
UpdateOutput rs = new UpdateOutput();
rs.setRecords(updateActionRecordSplitHelper.getOutputRecords());
List<String> updatableFields = table.getFields().values().stream()
.map(QFieldMetaData::getName)
// todo - intent here is to avoid non-updateable fields - but this
// should be like based on field.isUpdatable once that attribute exists
.filter(name -> !name.equals("id"))
.filter(name -> record.getValues().containsKey(name))
.toList();
recordsByFieldBeingUpdated.add(updatableFields, record);
if(CollectionUtils.nullSafeIsEmpty(record.getErrors()))
{
haveAnyWithoutErorrs = true;
}
//////////////////////////////////////////////////////////////////////////////
// go ahead and put the record into the output list at this point in time, //
// so that the output list's order matches the input list order //
// note that if we want to capture updated values (like modify dates), then //
// we may want a map of primary key to output record, for easy updating. //
//////////////////////////////////////////////////////////////////////////////
QRecord outputRecord = new QRecord(record);
outputRecords.add(outputRecord);
}
if(!haveAnyWithoutErorrs)
if(!updateActionRecordSplitHelper.getHaveAnyWithoutErrors())
{
LOG.info("Exiting early - all records have some error.");
return (rs);
@ -144,9 +98,10 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
/////////////////////////////////////////////////////////////////////////////////////////////
// process each distinct list of fields being updated (e.g., each different SQL statement) //
/////////////////////////////////////////////////////////////////////////////////////////////
for(List<String> fieldsBeingUpdated : recordsByFieldBeingUpdated.keySet())
ListingHash<List<String>, QRecord> recordsByFieldBeingUpdated = updateActionRecordSplitHelper.getRecordsByFieldBeingUpdated();
for(Map.Entry<List<String>, List<QRecord>> entry : recordsByFieldBeingUpdated.entrySet())
{
updateRecordsWithMatchingListOfFields(updateInput, connection, table, recordsByFieldBeingUpdated.get(fieldsBeingUpdated), fieldsBeingUpdated);
updateRecordsWithMatchingListOfFields(updateInput, connection, table, entry.getValue(), entry.getKey());
}
}
finally
@ -177,16 +132,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
// check for an optimization - if all of the records have the same values for //
// all fields being updated, just do 1 update, with an IN list on the ids. //
////////////////////////////////////////////////////////////////////////////////
boolean allAreTheSame;
if(updateInput.getAreAllValuesBeingUpdatedTheSame() != null)
{
allAreTheSame = updateInput.getAreAllValuesBeingUpdatedTheSame();
}
else
{
allAreTheSame = areAllValuesBeingUpdatedTheSame(recordList, fieldsBeingUpdated);
}
boolean allAreTheSame = UpdateActionRecordSplitHelper.areAllValuesBeingUpdatedTheSame(updateInput, recordList, fieldsBeingUpdated);
if(allAreTheSame)
{
updateRecordsWithMatchingValuesAndFields(updateInput, connection, table, recordList, fieldsBeingUpdated);
@ -312,43 +258,6 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
/*******************************************************************************
**
*******************************************************************************/
private boolean areAllValuesBeingUpdatedTheSame(List<QRecord> recordList, List<String> fieldsBeingUpdated)
{
if(recordList.size() == 1)
{
return (true);
}
QRecord record0 = recordList.get(0);
for(int i = 1; i < recordList.size(); i++)
{
QRecord record = recordList.get(i);
if(CollectionUtils.nullSafeHasContents(record.getErrors()))
{
///////////////////////////////////////////////////////
// skip records w/ errors (that we won't be updating //
///////////////////////////////////////////////////////
continue;
}
for(String fieldName : fieldsBeingUpdated)
{
if(!Objects.equals(record0.getValue(fieldName), record.getValue(fieldName)))
{
return (false);
}
}
}
return (true);
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -40,7 +40,7 @@ public class RDBMSActionTest extends BaseTest
**
*******************************************************************************/
@AfterEach
private void afterEachRDBMSActionTest()
void afterEachRDBMSActionTest()
{
QueryManager.resetPageSize();
QueryManager.resetStatistics();

View File

@ -196,7 +196,7 @@ public class RDBMSCountActionTest extends RDBMSActionTest
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true));
assertThat(new CountAction().execute(countInput).getCount()).isEqualTo(8);
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(2, 3)));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 2).withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 3));
assertThat(new CountAction().execute(countInput).getCount()).isEqualTo(5);
}

View File

@ -65,7 +65,7 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
{
InsertInput insertInput = initInsertRequest();
insertInput.setRecords(null);
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
InsertOutput insertOutput = new InsertAction().execute(insertInput);
assertEquals(0, insertOutput.getRecords().size());
}
@ -79,7 +79,7 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
{
InsertInput insertInput = initInsertRequest();
insertInput.setRecords(Collections.emptyList());
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
InsertOutput insertOutput = new InsertAction().execute(insertInput);
assertEquals(0, insertOutput.getRecords().size());
}
@ -98,7 +98,7 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
.withValue("email", "jamestk@starfleet.net")
.withValue("birthDate", "2210-05-20");
insertInput.setRecords(List.of(record));
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
InsertOutput insertOutput = new InsertAction().execute(insertInput);
assertEquals(1, insertOutput.getRecords().size(), "Should return 1 row");
assertNotNull(insertOutput.getRecords().get(0).getValue("id"), "Should have an id in the row");
// todo - add errors to QRecord? assertTrue(insertResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
@ -132,7 +132,7 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
.withValue("email", "doctor@starfleet.net")
.withValue("birthDate", "2320-06-26");
insertInput.setRecords(List.of(record1, record2, record3));
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
InsertOutput insertOutput = new InsertAction().execute(insertInput);
assertEquals(3, insertOutput.getRecords().size(), "Should return right # of rows");
assertEquals(6, insertOutput.getRecords().get(0).getValue("id"), "Should have next id in the row");
assertEquals(7, insertOutput.getRecords().get(1).getValue("id"), "Should have next id in the row");

View File

@ -635,7 +635,7 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON);
InsertAction insertAction = new InsertAction();
QBackendTransaction transaction = insertAction.openTransaction(insertInput);
QBackendTransaction transaction = QBackendTransaction.openFor(insertInput);
insertInput.setTransaction(transaction);
insertInput.setRecords(List.of(
@ -1325,13 +1325,13 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
QContext.setQSession(new QSession());
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, null));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, null));
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, Collections.emptyList()));
QContext.setQSession(new QSession().withSecurityKeyValues(Map.of(TestUtils.TABLE_NAME_STORE, Collections.emptyList())));
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 3)));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 1).withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 3));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(2)
.anyMatch(r -> r.getValueInteger("id").equals(1))
@ -1369,13 +1369,13 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
QContext.setQSession(new QSession());
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, null));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, null));
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, Collections.emptyList()));
QContext.setQSession(new QSession().withSecurityKeyValues(Map.of(TestUtils.TABLE_NAME_STORE, Collections.emptyList())));
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 3)));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 1).withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 3));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(6)
.allMatch(r -> r.getValueInteger("storeId").equals(1) || r.getValueInteger("storeId").equals(3));
@ -1411,7 +1411,7 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
queryInput.setFilter(new QQueryFilter(new QFilterCriteria("storeId", QCriteriaOperator.IN, List.of(1, 2))));
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 3)));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 1).withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 3));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(3)
.allMatch(r -> r.getValueInteger("storeId").equals(1));
@ -1556,10 +1556,17 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// user with list of all ids shouldn't see the nulls (given that default null-behavior on this key type is DENY) //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 2, 3, 4, 5)));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(8)
.noneMatch(hasNullStoreId);
{
QSession qSession = new QSession();
for(Integer i : List.of(1, 2, 3, 4, 5))
{
qSession.withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, i);
}
QContext.setQSession(qSession);
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(8)
.noneMatch(hasNullStoreId);
}
//////////////////////////////////////////////////////////////////////////
// specifically set the null behavior to deny - repeat the last 2 tests //
@ -1569,10 +1576,17 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
QContext.setQSession(new QSession());
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 2, 3, 4, 5)));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(8)
.noneMatch(hasNullStoreId);
{
QSession qSession = new QSession();
for(Integer i : List.of(1, 2, 3, 4, 5))
{
qSession.withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, i);
}
QContext.setQSession(qSession);
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(8)
.noneMatch(hasNullStoreId);
}
///////////////////////////////////
// change null behavior to ALLOW //
@ -1598,10 +1612,17 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
////////////////////////////////////////////////////
// user with list of all ids should see the nulls //
////////////////////////////////////////////////////
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 2, 3, 4, 5)));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(10)
.anyMatch(hasNullStoreId);
{
QSession qSession = new QSession();
for(Integer i : List.of(1, 2, 3, 4, 5))
{
qSession.withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, i);
}
QContext.setQSession(qSession);
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(10)
.anyMatch(hasNullStoreId);
}
}
@ -1644,7 +1665,7 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
assertThat(new QueryAction().execute(queryInput).getRecords()).isEmpty();
queryInput.setFilter(new QQueryFilter(new QFilterCriteria("storeId", QCriteriaOperator.IN, List.of(1, 2))));
QContext.setQSession(new QSession().withSecurityKeyValues(TestUtils.TABLE_NAME_STORE, List.of(1, 3)));
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 1).withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 3));
assertThat(new QueryAction().execute(queryInput).getRecords())
.hasSize(3)
.allMatch(r -> r.getValueInteger("storeId").equals(1));