Refactor to use RDBMSActionStrategy

This commit is contained in:
2025-01-03 16:49:50 -06:00
parent dc6d37aad3
commit db1269824c
10 changed files with 108 additions and 267 deletions

View File

@ -39,8 +39,6 @@ import java.util.ListIterator;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
@ -63,6 +61,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.AbstractFilterExpression; import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.AbstractFilterExpression;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat; import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
@ -80,9 +79,10 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import com.kingsrook.qqq.backend.core.utils.memoization.Memoization; import com.kingsrook.qqq.backend.core.utils.memoization.Memoization;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager; import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSFieldMetaData;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
import com.kingsrook.qqq.backend.module.rdbms.strategy.RDBMSActionStrategyInterface;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -101,6 +101,9 @@ public abstract class AbstractRDBMSAction
private static Memoization<String, Boolean> doesSelectClauseRequireDistinctMemoization = new Memoization<String, Boolean>() private static Memoization<String, Boolean> doesSelectClauseRequireDistinctMemoization = new Memoization<String, Boolean>()
.withTimeout(Duration.ofDays(365)); .withTimeout(Duration.ofDays(365));
private RDBMSBackendMetaData backendMetaData;
private RDBMSActionStrategyInterface actionStrategy;
/******************************************************************************* /*******************************************************************************
@ -313,9 +316,9 @@ public abstract class AbstractRDBMSAction
} }
joinClauseList.add(escapeIdentifier(baseTableOrAlias) joinClauseList.add(escapeIdentifier(baseTableOrAlias)
+ "." + escapeIdentifier(getColumnName(leftTable.getField(joinOn.getLeftField()))) + "." + escapeIdentifier(getColumnName(leftTable.getField(joinOn.getLeftField())))
+ " = " + escapeIdentifier(joinTableOrAlias) + " = " + escapeIdentifier(joinTableOrAlias)
+ "." + escapeIdentifier(getColumnName((rightTable.getField(joinOn.getRightField()))))); + "." + escapeIdentifier(getColumnName((rightTable.getField(joinOn.getRightField())))));
} }
if(CollectionUtils.nullSafeHasContents(queryJoin.getSecurityCriteria())) if(CollectionUtils.nullSafeHasContents(queryJoin.getSecurityCriteria()))
@ -479,172 +482,25 @@ public abstract class AbstractRDBMSAction
JoinsContext.FieldAndTableNameOrAlias fieldAndTableNameOrAlias = joinsContext.getFieldAndTableNameOrAlias(criterion.getFieldName()); JoinsContext.FieldAndTableNameOrAlias fieldAndTableNameOrAlias = joinsContext.getFieldAndTableNameOrAlias(criterion.getFieldName());
List<Serializable> values = criterion.getValues() == null ? new ArrayList<>() : new ArrayList<>(criterion.getValues()); List<Serializable> values = criterion.getValues() == null ? new ArrayList<>() : new ArrayList<>(criterion.getValues());
QFieldMetaData field = fieldAndTableNameOrAlias.field(); QFieldMetaData field = fieldAndTableNameOrAlias.field();
String column = escapeIdentifier(fieldAndTableNameOrAlias.tableNameOrAlias()) + "." + escapeIdentifier(getColumnName(field)); String column = escapeIdentifier(fieldAndTableNameOrAlias.tableNameOrAlias()) + "." + escapeIdentifier(getColumnName(field));
String clause = column; StringBuilder clause = new StringBuilder();
Integer expectedNoOfParams = null;
switch(criterion.getOperator())
{
case EQUALS ->
{
clause += " = ?";
expectedNoOfParams = 1;
}
case NOT_EQUALS ->
{
clause += " != ?";
expectedNoOfParams = 1;
}
case NOT_EQUALS_OR_IS_NULL ->
{
clause += " != ? OR " + column + " IS NULL ";
expectedNoOfParams = 1;
}
case IN ->
{
if(values.isEmpty())
{
///////////////////////////////////////////////////////
// if there are no values, then we want a false here //
///////////////////////////////////////////////////////
clause = " 0 = 1 ";
}
else
{
clause += " IN (" + values.stream().map(x -> "?").collect(Collectors.joining(",")) + ")";
}
}
case IS_NULL_OR_IN ->
{
clause += " IS NULL ";
if(!values.isEmpty()) RDBMSActionStrategyInterface actionStrategy = getActionStrategy();
{
clause += " OR " + column + " IN (" + values.stream().map(x -> "?").collect(Collectors.joining(",")) + ")"; RDBMSFieldMetaData rdbmsFieldMetaData = RDBMSFieldMetaData.of(field);
} if(rdbmsFieldMetaData != null)
} {
case NOT_IN -> RDBMSActionStrategyInterface fieldActionStrategy = rdbmsFieldMetaData.getActionStrategy();
if(fieldActionStrategy != null)
{ {
if(values.isEmpty()) actionStrategy = fieldActionStrategy;
{
//////////////////////////////////////////////////////
// if there are no values, then we want a true here //
//////////////////////////////////////////////////////
clause = " 1 = 1 ";
}
else
{
clause += " NOT IN (" + values.stream().map(x -> "?").collect(Collectors.joining(",")) + ")";
}
} }
case LIKE ->
{
clause += " LIKE ?";
expectedNoOfParams = 1;
}
case NOT_LIKE ->
{
clause += " NOT LIKE ?";
expectedNoOfParams = 1;
}
case STARTS_WITH ->
{
clause += " LIKE ?";
ActionHelper.editFirstValue(values, (s -> s + "%"));
expectedNoOfParams = 1;
}
case ENDS_WITH ->
{
clause += " LIKE ?";
ActionHelper.editFirstValue(values, (s -> "%" + s));
expectedNoOfParams = 1;
}
case CONTAINS ->
{
clause += " LIKE ?";
ActionHelper.editFirstValue(values, (s -> "%" + s + "%"));
expectedNoOfParams = 1;
}
case NOT_STARTS_WITH ->
{
clause += " NOT LIKE ?";
ActionHelper.editFirstValue(values, (s -> s + "%"));
expectedNoOfParams = 1;
}
case NOT_ENDS_WITH ->
{
clause += " NOT LIKE ?";
ActionHelper.editFirstValue(values, (s -> "%" + s));
expectedNoOfParams = 1;
}
case NOT_CONTAINS ->
{
clause += " NOT LIKE ?";
ActionHelper.editFirstValue(values, (s -> "%" + s + "%"));
expectedNoOfParams = 1;
}
case LESS_THAN ->
{
clause += " < ?";
expectedNoOfParams = 1;
}
case LESS_THAN_OR_EQUALS ->
{
clause += " <= ?";
expectedNoOfParams = 1;
}
case GREATER_THAN ->
{
clause += " > ?";
expectedNoOfParams = 1;
}
case GREATER_THAN_OR_EQUALS ->
{
clause += " >= ?";
expectedNoOfParams = 1;
}
case IS_BLANK ->
{
clause += " IS NULL";
if(field.getType().isStringLike())
{
clause += " OR " + column + " = ''";
}
expectedNoOfParams = 0;
}
case IS_NOT_BLANK ->
{
clause += " IS NOT NULL";
if(field.getType().isStringLike())
{
clause += " AND " + column + " != ''";
}
expectedNoOfParams = 0;
}
case BETWEEN ->
{
clause += " BETWEEN ? AND ?";
expectedNoOfParams = 2;
}
case NOT_BETWEEN ->
{
clause += " NOT BETWEEN ? AND ?";
expectedNoOfParams = 2;
}
case TRUE ->
{
clause = " 1 = 1 ";
expectedNoOfParams = 0;
}
case FALSE ->
{
clause = " 0 = 1 ";
expectedNoOfParams = 0;
}
default -> throw new IllegalStateException("Unexpected operator: " + criterion.getOperator());
} }
Integer expectedNoOfParams = actionStrategy.appendCriterionToWhereClause(criterion, clause, column, values, field);
if(expectedNoOfParams != null) if(expectedNoOfParams != null)
{ {
if(expectedNoOfParams.equals(1) && StringUtils.hasContent(criterion.getOtherFieldName())) if(expectedNoOfParams.equals(1) && StringUtils.hasContent(criterion.getOtherFieldName()))
@ -652,7 +508,7 @@ public abstract class AbstractRDBMSAction
JoinsContext.FieldAndTableNameOrAlias otherFieldAndTableNameOrAlias = joinsContext.getFieldAndTableNameOrAlias(criterion.getOtherFieldName()); JoinsContext.FieldAndTableNameOrAlias otherFieldAndTableNameOrAlias = joinsContext.getFieldAndTableNameOrAlias(criterion.getOtherFieldName());
String otherColumn = escapeIdentifier(otherFieldAndTableNameOrAlias.tableNameOrAlias()) + "." + escapeIdentifier(getColumnName(otherFieldAndTableNameOrAlias.field())); String otherColumn = escapeIdentifier(otherFieldAndTableNameOrAlias.tableNameOrAlias()) + "." + escapeIdentifier(getColumnName(otherFieldAndTableNameOrAlias.field()));
clause = clause.replace("?", otherColumn); clause = new StringBuilder(clause.toString().replace("?", otherColumn));
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// make sure we don't add any values in this case, just in case... // // make sure we don't add any values in this case, just in case... //
@ -797,53 +653,7 @@ public abstract class AbstractRDBMSAction
*******************************************************************************/ *******************************************************************************/
protected Serializable getFieldValueFromResultSet(QFieldType type, ResultSet resultSet, int i) throws SQLException protected Serializable getFieldValueFromResultSet(QFieldType type, ResultSet resultSet, int i) throws SQLException
{ {
switch(type) return (actionStrategy.getFieldValueFromResultSet(type, resultSet, i));
{
case STRING:
case TEXT:
case HTML:
case PASSWORD:
{
return (QueryManager.getString(resultSet, i));
}
case INTEGER:
{
return (QueryManager.getInteger(resultSet, i));
}
case LONG:
{
return (QueryManager.getLong(resultSet, i));
}
case DECIMAL:
{
return (QueryManager.getBigDecimal(resultSet, i));
}
case DATE:
{
// todo - queryManager.getLocalDate?
return (QueryManager.getDate(resultSet, i));
}
case TIME:
{
return (QueryManager.getLocalTime(resultSet, i));
}
case DATE_TIME:
{
return (QueryManager.getInstant(resultSet, i));
}
case BOOLEAN:
{
return (QueryManager.getBoolean(resultSet, i));
}
case BLOB:
{
return (QueryManager.getByteArray(resultSet, i));
}
default:
{
throw new IllegalStateException("Unexpected field type: " + type);
}
}
} }
@ -1151,4 +961,26 @@ public abstract class AbstractRDBMSAction
return (filter.clone()); return (filter.clone());
} }
} }
/*******************************************************************************
** Setter for backendMetaData
**
*******************************************************************************/
protected void setBackendMetaData(QBackendMetaData backendMetaData)
{
this.backendMetaData = (RDBMSBackendMetaData) backendMetaData;
this.actionStrategy = this.backendMetaData.getActionStrategy();
}
/***************************************************************************
*
***************************************************************************/
protected RDBMSActionStrategyInterface getActionStrategy()
{
return (this.actionStrategy);
}
} }

View File

@ -48,7 +48,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; 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.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
/******************************************************************************* /*******************************************************************************
@ -70,6 +69,7 @@ public class RDBMSAggregateAction extends AbstractRDBMSAction implements Aggrega
try try
{ {
QTableMetaData table = aggregateInput.getTable(); QTableMetaData table = aggregateInput.getTable();
setBackendMetaData(aggregateInput.getBackend());
QQueryFilter filter = clonedOrNewFilter(aggregateInput.getFilter()); QQueryFilter filter = clonedOrNewFilter(aggregateInput.getFilter());
JoinsContext joinsContext = new JoinsContext(QContext.getQInstance(), table.getName(), aggregateInput.getQueryJoins(), filter); JoinsContext joinsContext = new JoinsContext(QContext.getQInstance(), table.getName(), aggregateInput.getQueryJoins(), filter);
@ -126,7 +126,7 @@ public class RDBMSAggregateAction extends AbstractRDBMSAction implements Aggrega
queryStat.setStartTimestamp(Instant.now()); queryStat.setStartTimestamp(Instant.now());
} }
QueryManager.executeStatement(statement, sql, ((ResultSet resultSet) -> getActionStrategy().executeStatement(statement, sql, ((ResultSet resultSet) ->
{ {
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// once we've started getting results, go ahead and cancel the timeout // // once we've started getting results, go ahead and cancel the timeout //

View File

@ -40,7 +40,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.JoinsContext; import com.kingsrook.qqq.backend.core.model.actions.tables.query.JoinsContext;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.BooleanUtils;
@ -63,6 +62,7 @@ public class RDBMSCountAction extends AbstractRDBMSAction implements CountInterf
try try
{ {
QTableMetaData table = countInput.getTable(); QTableMetaData table = countInput.getTable();
setBackendMetaData(countInput.getBackend());
QQueryFilter filter = clonedOrNewFilter(countInput.getFilter()); QQueryFilter filter = clonedOrNewFilter(countInput.getFilter());
JoinsContext joinsContext = new JoinsContext(QContext.getQInstance(), countInput.getTableName(), countInput.getQueryJoins(), filter); JoinsContext joinsContext = new JoinsContext(QContext.getQInstance(), countInput.getTableName(), countInput.getQueryJoins(), filter);
@ -106,7 +106,7 @@ public class RDBMSCountAction extends AbstractRDBMSAction implements CountInterf
queryStat.setStartTimestamp(Instant.now()); queryStat.setStartTimestamp(Instant.now());
} }
QueryManager.executeStatement(statement, sql, ((ResultSet resultSet) -> getActionStrategy().executeStatement(statement, sql, ((ResultSet resultSet) ->
{ {
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// once we've started getting results, go ahead and cancel the timeout // // once we've started getting results, go ahead and cancel the timeout //

View File

@ -39,7 +39,6 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage; import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
/******************************************************************************* /*******************************************************************************
@ -67,6 +66,8 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte
*******************************************************************************/ *******************************************************************************/
public DeleteOutput execute(DeleteInput deleteInput) throws QException public DeleteOutput execute(DeleteInput deleteInput) throws QException
{ {
setBackendMetaData(deleteInput.getBackend());
DeleteOutput deleteOutput = new DeleteOutput(); DeleteOutput deleteOutput = new DeleteOutput();
deleteOutput.setRecordsWithErrors(new ArrayList<>()); deleteOutput.setRecordsWithErrors(new ArrayList<>());
@ -196,7 +197,7 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte
try try
{ {
int rowCount = QueryManager.executeUpdateForRowCount(connection, sql, primaryKey); int rowCount = getActionStrategy().executeUpdateForRowCount(connection, sql, primaryKey);
deleteOutput.addToDeletedRecordCount(rowCount); deleteOutput.addToDeletedRecordCount(rowCount);
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
@ -249,7 +250,7 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte
// todo sql customization - can edit sql and/or param list // todo sql customization - can edit sql and/or param list
Integer rowCount = QueryManager.executeUpdateForRowCount(connection, sql, primaryKeys); Integer rowCount = getActionStrategy().executeUpdateForRowCount(connection, sql, primaryKeys);
deleteOutput.addToDeletedRecordCount(rowCount); deleteOutput.addToDeletedRecordCount(rowCount);
} }
catch(Exception e) catch(Exception e)
@ -287,7 +288,7 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte
try try
{ {
int rowCount = QueryManager.executeUpdateForRowCount(connection, sql, params); int rowCount = getActionStrategy().executeUpdateForRowCount(connection, sql, params);
deleteOutput.setDeletedRecordCount(rowCount); deleteOutput.setDeletedRecordCount(rowCount);
} }
catch(Exception e) catch(Exception e)

View File

@ -37,7 +37,6 @@ 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.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; 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.CollectionUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
/******************************************************************************* /*******************************************************************************
@ -56,6 +55,7 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
{ {
InsertOutput rs = new InsertOutput(); InsertOutput rs = new InsertOutput();
QTableMetaData table = insertInput.getTable(); QTableMetaData table = insertInput.getTable();
setBackendMetaData(insertInput.getBackend());
Connection connection = null; Connection connection = null;
boolean needToCloseConnection = false; boolean needToCloseConnection = false;
@ -90,7 +90,7 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
needToCloseConnection = true; needToCloseConnection = true;
} }
for(List<QRecord> page : CollectionUtils.getPages(insertInput.getRecords(), QueryManager.PAGE_SIZE)) for(List<QRecord> page : CollectionUtils.getPages(insertInput.getRecords(), getActionStrategy().getPageSize(insertInput)))
{ {
String tableName = escapeIdentifier(getTableName(table)); String tableName = escapeIdentifier(getTableName(table));
sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(columns).append(") VALUES"); sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(columns).append(") VALUES");
@ -146,7 +146,7 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
// todo sql customization - can edit sql and/or param list // todo sql customization - can edit sql and/or param list
// todo - non-serial-id style tables // todo - non-serial-id style tables
// todo - other generated values, e.g., createDate... maybe need to re-select? // todo - other generated values, e.g., createDate... maybe need to re-select?
List<Serializable> idList = QueryManager.executeInsertForGeneratedIds(connection, sql.toString(), params, table.getField(table.getPrimaryKeyField()).getType()); List<Serializable> idList = getActionStrategy().executeInsertForGeneratedIds(connection, sql.toString(), params, table.getField(table.getPrimaryKeyField()));
int index = 0; int index = 0;
for(QRecord record : page) for(QRecord record : page)
{ {
@ -155,8 +155,11 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
if(CollectionUtils.nullSafeIsEmpty(record.getErrors())) if(CollectionUtils.nullSafeIsEmpty(record.getErrors()))
{ {
Serializable id = idList.get(index++); if(idList.size() > index)
outputRecord.setValue(table.getPrimaryKeyField(), id); {
Serializable id = idList.get(index++);
outputRecord.setValue(table.getPrimaryKeyField(), id);
}
} }
} }

View File

@ -57,7 +57,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; 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.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.Pair; import com.kingsrook.qqq.backend.core.utils.Pair;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -94,6 +93,7 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
{ {
QTableMetaData table = queryInput.getTable(); QTableMetaData table = queryInput.getTable();
String tableName = queryInput.getTableName(); String tableName = queryInput.getTableName();
setBackendMetaData(queryInput.getBackend());
List<Serializable> params = new ArrayList<>(); List<Serializable> params = new ArrayList<>();
Selection selection = makeSelection(queryInput); Selection selection = makeSelection(queryInput);
@ -140,7 +140,7 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
////////////////////////////////////////////// //////////////////////////////////////////////
QueryOutput queryOutput = new QueryOutput(queryInput); QueryOutput queryOutput = new QueryOutput(queryInput);
QueryManager.executeStatement(statement, sql, ((ResultSet resultSet) -> getActionStrategy().executeStatement(statement, sql, ((ResultSet resultSet) ->
{ {
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// once we've started getting results, go ahead and cancel the timeout // // once we've started getting results, go ahead and cancel the timeout //

View File

@ -41,7 +41,6 @@ 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.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.ListingHash; import com.kingsrook.qqq.backend.core.utils.ListingHash;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
/******************************************************************************* /*******************************************************************************
@ -66,6 +65,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
public UpdateOutput execute(UpdateInput updateInput) throws QException public UpdateOutput execute(UpdateInput updateInput) throws QException
{ {
QTableMetaData table = updateInput.getTable(); QTableMetaData table = updateInput.getTable();
setBackendMetaData(updateInput.getBackend());
UpdateActionRecordSplitHelper updateActionRecordSplitHelper = new UpdateActionRecordSplitHelper(); UpdateActionRecordSplitHelper updateActionRecordSplitHelper = new UpdateActionRecordSplitHelper();
updateActionRecordSplitHelper.init(updateInput); updateActionRecordSplitHelper.init(updateInput);
@ -181,7 +181,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
try try
{ {
QueryManager.executeBatchUpdate(connection, sql, values); getActionStrategy().executeBatchUpdate(connection, sql, values);
incrementStatus(updateInput, recordList.size()); incrementStatus(updateInput, recordList.size());
} }
finally finally
@ -214,7 +214,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
*******************************************************************************/ *******************************************************************************/
private void updateRecordsWithMatchingValuesAndFields(UpdateInput updateInput, Connection connection, QTableMetaData table, List<QRecord> recordList, List<String> fieldsBeingUpdated) throws SQLException private void updateRecordsWithMatchingValuesAndFields(UpdateInput updateInput, Connection connection, QTableMetaData table, List<QRecord> recordList, List<String> fieldsBeingUpdated) throws SQLException
{ {
for(List<QRecord> page : CollectionUtils.getPages(recordList, QueryManager.PAGE_SIZE)) for(List<QRecord> page : CollectionUtils.getPages(recordList, getActionStrategy().getPageSize(updateInput)))
{ {
////////////////////////////// //////////////////////////////
// skip records with errors // // skip records with errors //
@ -256,7 +256,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
///////////////////////////////////// /////////////////////////////////////
try try
{ {
QueryManager.executeUpdate(connection, sql, params); getActionStrategy().executeUpdate(connection, sql, params);
incrementStatus(updateInput, page.size()); incrementStatus(updateInput, page.size());
} }
finally finally

View File

@ -34,8 +34,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.module.rdbms.TestUtils; import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
import com.kingsrook.qqq.backend.module.rdbms.strategy.BaseRDBMSActionStrategy;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -128,6 +128,11 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
deleteInput.setPrimaryKeys(List.of(1, -1)); deleteInput.setPrimaryKeys(List.of(1, -1));
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput); DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
assertEquals(1, deleteResult.getDeletedRecordCount(), "Should delete one row"); assertEquals(1, deleteResult.getDeletedRecordCount(), "Should delete one row");
/////////////////////////////////////////////////////////////////////////////////////
// note - that if we went to the top-level DeleteAction, then it would have pre- //
// checked that the ids existed, and it WOULD give us an error for the -1 row here //
/////////////////////////////////////////////////////////////////////////////////////
assertEquals(0, deleteResult.getRecordsWithErrors().size(), "should have no errors (the one not found is just noop)"); assertEquals(0, deleteResult.getRecordsWithErrors().size(), "should have no errors (the one not found is just noop)");
} }
@ -162,17 +167,15 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
deleteInput.setPrimaryKeys(List.of(1, 2, 3, 4, 5)); deleteInput.setPrimaryKeys(List.of(1, 2, 3, 4, 5));
QueryManager.setCollectStatistics(true); BaseRDBMSActionStrategy actionStrategy = getBaseRDBMSActionStrategyAndActivateCollectingStatistics();
QueryManager.resetStatistics();
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput); DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// assert that 6 queries ran - the initial delete (which failed), then 5 more deletes // // assert that 6 queries ran - the initial delete (which failed), then 5 more deletes //
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
QueryManager.setCollectStatistics(false); actionStrategy.setCollectStatistics(false);
Map<String, Integer> queryStats = QueryManager.getStatistics(); Map<String, Integer> queryStats = actionStrategy.getStatistics();
assertEquals(6, queryStats.get(QueryManager.STAT_QUERIES_RAN), "Number of queries ran"); assertEquals(6, queryStats.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN), "Number of queries ran");
assertEquals(2, deleteResult.getRecordsWithErrors().size(), "Should get back the 2 records with errors"); assertEquals(2, deleteResult.getRecordsWithErrors().size(), "Should get back the 2 records with errors");
assertTrue(deleteResult.getRecordsWithErrors().stream().noneMatch(r -> r.getErrors().isEmpty()), "All we got back should have errors"); assertTrue(deleteResult.getRecordsWithErrors().stream().noneMatch(r -> r.getErrors().isEmpty()), "All we got back should have errors");
@ -212,17 +215,15 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
deleteInput.setQueryFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.IN, List.of(2, 4, 5)))); deleteInput.setQueryFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.IN, List.of(2, 4, 5))));
QueryManager.setCollectStatistics(true); BaseRDBMSActionStrategy actionStrategy = getBaseRDBMSActionStrategyAndActivateCollectingStatistics();
QueryManager.resetStatistics();
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput); DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
////////////////////////////////// //////////////////////////////////
// assert that just 1 query ran // // assert that just 1 query ran //
////////////////////////////////// //////////////////////////////////
QueryManager.setCollectStatistics(false); actionStrategy.setCollectStatistics(false);
Map<String, Integer> queryStats = QueryManager.getStatistics(); Map<String, Integer> queryStats = actionStrategy.getStatistics();
assertEquals(1, queryStats.get(QueryManager.STAT_QUERIES_RAN), "Number of queries ran"); assertEquals(1, queryStats.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN), "Number of queries ran");
assertEquals(3, deleteResult.getDeletedRecordCount(), "Should get back that 3 were deleted"); assertEquals(3, deleteResult.getDeletedRecordCount(), "Should get back that 3 were deleted");
runTestSql("SELECT id FROM child_table", (rs -> runTestSql("SELECT id FROM child_table", (rs ->
@ -259,9 +260,7 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
deleteInput.setQueryFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.IN, List.of(1, 2, 3, 4, 5)))); deleteInput.setQueryFilter(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.IN, List.of(1, 2, 3, 4, 5))));
QueryManager.setCollectStatistics(true); BaseRDBMSActionStrategy actionStrategy = getBaseRDBMSActionStrategyAndActivateCollectingStatistics();
QueryManager.resetStatistics();
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput); DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
/////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////
@ -270,9 +269,9 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
// todo - maybe we shouldn't do that 2nd "try to delete 'em all by id"... why would it ever work, // // todo - maybe we shouldn't do that 2nd "try to delete 'em all by id"... why would it ever work, //
// but the original filter query didn't (other than malformed SQL)? // // but the original filter query didn't (other than malformed SQL)? //
/////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////
QueryManager.setCollectStatistics(false); actionStrategy.setCollectStatistics(false);
Map<String, Integer> queryStats = QueryManager.getStatistics(); Map<String, Integer> queryStats = actionStrategy.getStatistics();
assertEquals(8, queryStats.get(QueryManager.STAT_QUERIES_RAN), "Number of queries ran"); assertEquals(8, queryStats.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN), "Number of queries ran");
assertEquals(2, deleteResult.getRecordsWithErrors().size(), "Should get back the 2 records with errors"); assertEquals(2, deleteResult.getRecordsWithErrors().size(), "Should get back the 2 records with errors");
assertTrue(deleteResult.getRecordsWithErrors().stream().noneMatch(r -> r.getErrors().isEmpty()), "All we got back should have errors"); assertTrue(deleteResult.getRecordsWithErrors().stream().noneMatch(r -> r.getErrors().isEmpty()), "All we got back should have errors");

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.context.QContext;
@ -32,7 +33,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.module.rdbms.TestUtils; import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager; import com.kingsrook.qqq.backend.module.rdbms.strategy.BaseRDBMSActionStrategy;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -53,6 +54,8 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
public void beforeEach() throws Exception public void beforeEach() throws Exception
{ {
super.primeTestDatabase(); super.primeTestDatabase();
getBaseRDBMSActionStrategyAndActivateCollectingStatistics();
} }
@ -113,7 +116,7 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
@Test @Test
public void testInsertMany() throws Exception public void testInsertMany() throws Exception
{ {
QueryManager.setPageSize(2); getBaseRDBMSActionStrategy().setPageSize(2);
InsertInput insertInput = initInsertRequest(); InsertInput insertInput = initInsertRequest();
QRecord record1 = new QRecord().withTableName("person") QRecord record1 = new QRecord().withTableName("person")
@ -137,6 +140,10 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
assertEquals(6, insertOutput.getRecords().get(0).getValue("id"), "Should have next id in the row"); 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"); assertEquals(7, insertOutput.getRecords().get(1).getValue("id"), "Should have next id in the row");
assertEquals(8, insertOutput.getRecords().get(2).getValue("id"), "Should have next id in the row"); assertEquals(8, insertOutput.getRecords().get(2).getValue("id"), "Should have next id in the row");
Map<String, Integer> statistics = getBaseRDBMSActionStrategy().getStatistics();
assertEquals(2, statistics.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN));
assertAnInsertedPersonRecord("Jean-Luc", "Picard", 6); assertAnInsertedPersonRecord("Jean-Luc", "Picard", 6);
assertAnInsertedPersonRecord("William", "Riker", 7); assertAnInsertedPersonRecord("William", "Riker", 7);
assertAnInsertedPersonRecord("Beverly", "Crusher", 8); assertAnInsertedPersonRecord("Beverly", "Crusher", 8);

View File

@ -36,7 +36,7 @@ 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.data.QRecord;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.module.rdbms.TestUtils; import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager; import com.kingsrook.qqq.backend.module.rdbms.strategy.BaseRDBMSActionStrategy;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -61,8 +61,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
{ {
super.primeTestDatabase(); super.primeTestDatabase();
QueryManager.setCollectStatistics(true); getBaseRDBMSActionStrategyAndActivateCollectingStatistics();
QueryManager.resetStatistics();
} }
@ -112,8 +111,8 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
updateInput.setRecords(List.of(record)); updateInput.setRecords(List.of(record));
UpdateOutput updateResult = new UpdateAction().execute(updateInput); UpdateOutput updateResult = new UpdateAction().execute(updateInput);
Map<String, Integer> statistics = QueryManager.getStatistics(); Map<String, Integer> statistics = getBaseRDBMSActionStrategy().getStatistics();
assertEquals(2, statistics.get(QueryManager.STAT_QUERIES_RAN)); assertEquals(2, statistics.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN));
assertEquals(1, updateResult.getRecords().size(), "Should return 1 row"); assertEquals(1, updateResult.getRecords().size(), "Should return 1 row");
assertEquals(2, updateResult.getRecords().get(0).getValue("id"), "Should have id=2 in the row"); assertEquals(2, updateResult.getRecords().get(0).getValue("id"), "Should have id=2 in the row");
@ -169,9 +168,9 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
UpdateOutput updateResult = new UpdateAction().execute(updateInput); UpdateOutput updateResult = new UpdateAction().execute(updateInput);
// this test runs one batch and one regular query // this test runs one batch and one regular query
Map<String, Integer> statistics = QueryManager.getStatistics(); Map<String, Integer> statistics = getBaseRDBMSActionStrategy().getStatistics();
assertEquals(1, statistics.get(QueryManager.STAT_BATCHES_RAN)); assertEquals(1, statistics.get(BaseRDBMSActionStrategy.STAT_BATCHES_RAN));
assertEquals(2, statistics.get(QueryManager.STAT_QUERIES_RAN)); assertEquals(2, statistics.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN));
assertEquals(3, updateResult.getRecords().size(), "Should return 3 rows"); assertEquals(3, updateResult.getRecords().size(), "Should return 3 rows");
assertEquals(1, updateResult.getRecords().get(0).getValue("id"), "Should have expected ids in the row"); assertEquals(1, updateResult.getRecords().get(0).getValue("id"), "Should have expected ids in the row");
@ -241,8 +240,8 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
updateInput.setRecords(List.of(record1, record2)); updateInput.setRecords(List.of(record1, record2));
UpdateOutput updateResult = new UpdateAction().execute(updateInput); UpdateOutput updateResult = new UpdateAction().execute(updateInput);
Map<String, Integer> statistics = QueryManager.getStatistics(); Map<String, Integer> statistics = getBaseRDBMSActionStrategy().getStatistics();
assertEquals(1, statistics.get(QueryManager.STAT_BATCHES_RAN)); assertEquals(1, statistics.get(BaseRDBMSActionStrategy.STAT_BATCHES_RAN));
assertEquals(2, updateResult.getRecords().size(), "Should return 2 rows"); assertEquals(2, updateResult.getRecords().size(), "Should return 2 rows");
assertEquals(1, updateResult.getRecords().get(0).getValue("id"), "Should have expected ids in the row"); assertEquals(1, updateResult.getRecords().get(0).getValue("id"), "Should have expected ids in the row");
@ -296,8 +295,8 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
updateInput.setRecords(records); updateInput.setRecords(records);
UpdateOutput updateResult = new UpdateAction().execute(updateInput); UpdateOutput updateResult = new UpdateAction().execute(updateInput);
Map<String, Integer> statistics = QueryManager.getStatistics(); Map<String, Integer> statistics = getBaseRDBMSActionStrategy().getStatistics();
assertEquals(2, statistics.get(QueryManager.STAT_QUERIES_RAN)); assertEquals(2, statistics.get(BaseRDBMSActionStrategy.STAT_QUERIES_RAN));
assertEquals(5, updateResult.getRecords().size(), "Should return 5 rows"); assertEquals(5, updateResult.getRecords().size(), "Should return 5 rows");
// todo - add errors to QRecord? assertTrue(updateResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors"); // todo - add errors to QRecord? assertTrue(updateResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");