mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Introduce the concept of RDBMSActionStrategyInterface - to use strategy pattern for refinement of how different RDBMS sub-backends may need to behave (e.g., to support SQLite, and FULLTEXT INDEX in MySQL).
This commit is contained in:
@ -23,10 +23,14 @@ package com.kingsrook.qqq.backend.module.rdbms.model.metadata;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.strategy.BaseRDBMSActionStrategy;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.strategy.RDBMSActionStrategyInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -50,6 +54,9 @@ public class RDBMSBackendMetaData extends QBackendMetaData
|
||||
|
||||
private RDBMSBackendMetaData readOnlyBackendMetaData;
|
||||
|
||||
private QCodeReference actionStrategyCodeReference;
|
||||
private RDBMSActionStrategyInterface actionStrategy;
|
||||
|
||||
private List<String> queriesForNewConnections = null;
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -466,6 +473,83 @@ public class RDBMSBackendMetaData extends QBackendMetaData
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for actionStrategyCodeReference
|
||||
*******************************************************************************/
|
||||
public QCodeReference getActionStrategyCodeReference()
|
||||
{
|
||||
return (this.actionStrategyCodeReference);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for actionStrategyCodeReference
|
||||
*******************************************************************************/
|
||||
public void setActionStrategyCodeReference(QCodeReference actionStrategyCodeReference)
|
||||
{
|
||||
this.actionStrategyCodeReference = actionStrategyCodeReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for actionStrategyCodeReference
|
||||
*******************************************************************************/
|
||||
public RDBMSBackendMetaData withActionStrategyCodeReference(QCodeReference actionStrategyCodeReference)
|
||||
{
|
||||
this.actionStrategyCodeReference = actionStrategyCodeReference;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@JsonIgnore
|
||||
public RDBMSActionStrategyInterface getActionStrategy()
|
||||
{
|
||||
if(actionStrategy == null)
|
||||
{
|
||||
if(actionStrategyCodeReference != null)
|
||||
{
|
||||
actionStrategy = QCodeLoader.getAdHoc(RDBMSActionStrategyInterface.class, actionStrategyCodeReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
actionStrategy = new BaseRDBMSActionStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
return (actionStrategy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* note - protected - meant for sub-classes to use in their implementation of
|
||||
* getActionStrategy, but not for public use.
|
||||
***************************************************************************/
|
||||
protected RDBMSActionStrategyInterface getActionStrategyField()
|
||||
{
|
||||
return (actionStrategy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* note - protected - meant for sub-classes to use in their implementation of
|
||||
* getActionStrategy, but not for public use.
|
||||
***************************************************************************/
|
||||
protected void setActionStrategyField(RDBMSActionStrategyInterface actionStrategy)
|
||||
{
|
||||
this.actionStrategy = actionStrategy;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queriesForNewConnections
|
||||
*******************************************************************************/
|
||||
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.module.rdbms.model.metadata;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QSupplementalFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.strategy.RDBMSActionStrategyInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RDBMSFieldMetaData extends QSupplementalFieldMetaData
|
||||
{
|
||||
private QCodeReference actionStrategyCodeReference;
|
||||
private RDBMSActionStrategyInterface actionStrategy;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RDBMSFieldMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static RDBMSFieldMetaData of(QFieldMetaData field)
|
||||
{
|
||||
return ((RDBMSFieldMetaData) field.getSupplementalMetaData(RDBMSBackendModule.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** either get the object attached to a field - or create a new one and attach
|
||||
** it to the field, and return that.
|
||||
*******************************************************************************/
|
||||
public static RDBMSFieldMetaData ofOrWithNew(QFieldMetaData field)
|
||||
{
|
||||
RDBMSFieldMetaData rdbmsFieldMetaData = of(field);
|
||||
if(rdbmsFieldMetaData == null)
|
||||
{
|
||||
rdbmsFieldMetaData = new RDBMSFieldMetaData();
|
||||
field.withSupplementalMetaData(rdbmsFieldMetaData);
|
||||
}
|
||||
return (rdbmsFieldMetaData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return (RDBMSBackendModule.NAME);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@JsonIgnore
|
||||
public RDBMSActionStrategyInterface getActionStrategy()
|
||||
{
|
||||
if(actionStrategy == null)
|
||||
{
|
||||
if(actionStrategyCodeReference != null)
|
||||
{
|
||||
actionStrategy = QCodeLoader.getAdHoc(RDBMSActionStrategyInterface.class, actionStrategyCodeReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
return (actionStrategy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for actionStrategyCodeReference
|
||||
*******************************************************************************/
|
||||
public QCodeReference getActionStrategyCodeReference()
|
||||
{
|
||||
return (this.actionStrategyCodeReference);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for actionStrategyCodeReference
|
||||
*******************************************************************************/
|
||||
public void setActionStrategyCodeReference(QCodeReference actionStrategyCodeReference)
|
||||
{
|
||||
this.actionStrategyCodeReference = actionStrategyCodeReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for actionStrategyCodeReference
|
||||
*******************************************************************************/
|
||||
public RDBMSFieldMetaData withActionStrategyCodeReference(QCodeReference actionStrategyCodeReference)
|
||||
{
|
||||
this.actionStrategyCodeReference = actionStrategyCodeReference;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* note - protected - meant for sub-classes to use in their implementation of
|
||||
* getActionStrategy, but not for public use.
|
||||
***************************************************************************/
|
||||
protected RDBMSActionStrategyInterface getActionStrategyField()
|
||||
{
|
||||
return (actionStrategy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* note - protected - meant for sub-classes to use in their implementation of
|
||||
* getActionStrategy, but not for public use.
|
||||
***************************************************************************/
|
||||
protected void setActionStrategyField(RDBMSActionStrategyInterface actionStrategy)
|
||||
{
|
||||
this.actionStrategy = actionStrategy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,873 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.module.rdbms.strategy;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
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.possiblevalues.PossibleValueEnum;
|
||||
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;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class BaseRDBMSActionStrategy implements RDBMSActionStrategyInterface
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(BaseRDBMSActionStrategy.class);
|
||||
|
||||
private static final int MILLIS_PER_SECOND = 1000;
|
||||
|
||||
public static final int DEFAULT_PAGE_SIZE = 2000;
|
||||
public static int PAGE_SIZE = DEFAULT_PAGE_SIZE;
|
||||
|
||||
private boolean collectStatistics = false;
|
||||
private final Map<String, Integer> statistics = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
public static final String STAT_QUERIES_RAN = "queriesRan";
|
||||
public static final String STAT_BATCHES_RAN = "batchesRan";
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
public Integer appendCriterionToWhereClause(QFilterCriteria criterion, StringBuilder clause, String column, List<Serializable> values, QFieldMetaData field)
|
||||
{
|
||||
clause.append(column);
|
||||
|
||||
switch(criterion.getOperator())
|
||||
{
|
||||
case EQUALS ->
|
||||
{
|
||||
clause.append(" = ?");
|
||||
return (1);
|
||||
}
|
||||
case NOT_EQUALS ->
|
||||
{
|
||||
clause.append(" != ?");
|
||||
return (1);
|
||||
}
|
||||
case NOT_EQUALS_OR_IS_NULL ->
|
||||
{
|
||||
clause.append(" != ? OR ").append(column).append(" IS NULL ");
|
||||
return (1);
|
||||
}
|
||||
case IN ->
|
||||
{
|
||||
if(values.isEmpty())
|
||||
{
|
||||
///////////////////////////////////////////////////////
|
||||
// if there are no values, then we want a false here //
|
||||
///////////////////////////////////////////////////////
|
||||
clause.delete(0, clause.length());
|
||||
clause.append(" 0 = 1 ");
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
clause.append(" IN (").append(values.stream().map(x -> "?").collect(Collectors.joining(","))).append(")");
|
||||
return (values.size());
|
||||
}
|
||||
}
|
||||
case IS_NULL_OR_IN ->
|
||||
{
|
||||
clause.append(" IS NULL ");
|
||||
|
||||
if(!values.isEmpty())
|
||||
{
|
||||
clause.append(" OR ").append(column).append(" IN (").append(values.stream().map(x -> "?").collect(Collectors.joining(","))).append(")");
|
||||
return (values.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
case NOT_IN ->
|
||||
{
|
||||
if(values.isEmpty())
|
||||
{
|
||||
//////////////////////////////////////////////////////
|
||||
// if there are no values, then we want a true here //
|
||||
//////////////////////////////////////////////////////
|
||||
clause.delete(0, clause.length());
|
||||
clause.append(" 1 = 1 ");
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
clause.append(" NOT IN (").append(values.stream().map(x -> "?").collect(Collectors.joining(","))).append(")");
|
||||
return (values.size());
|
||||
}
|
||||
}
|
||||
case LIKE ->
|
||||
{
|
||||
clause.append(" LIKE ?");
|
||||
return (1);
|
||||
}
|
||||
case NOT_LIKE ->
|
||||
{
|
||||
clause.append(" NOT LIKE ?");
|
||||
return (1);
|
||||
}
|
||||
case STARTS_WITH ->
|
||||
{
|
||||
clause.append(" LIKE ?");
|
||||
ActionHelper.editFirstValue(values, (s -> s + "%"));
|
||||
return (1);
|
||||
}
|
||||
case ENDS_WITH ->
|
||||
{
|
||||
clause.append(" LIKE ?");
|
||||
ActionHelper.editFirstValue(values, (s -> "%" + s));
|
||||
return (1);
|
||||
}
|
||||
case CONTAINS ->
|
||||
{
|
||||
clause.append(" LIKE ?");
|
||||
ActionHelper.editFirstValue(values, (s -> "%" + s + "%"));
|
||||
return (1);
|
||||
}
|
||||
case NOT_STARTS_WITH ->
|
||||
{
|
||||
clause.append(" NOT LIKE ?");
|
||||
ActionHelper.editFirstValue(values, (s -> s + "%"));
|
||||
return (1);
|
||||
}
|
||||
case NOT_ENDS_WITH ->
|
||||
{
|
||||
clause.append(" NOT LIKE ?");
|
||||
ActionHelper.editFirstValue(values, (s -> "%" + s));
|
||||
return (1);
|
||||
}
|
||||
case NOT_CONTAINS ->
|
||||
{
|
||||
clause.append(" NOT LIKE ?");
|
||||
ActionHelper.editFirstValue(values, (s -> "%" + s + "%"));
|
||||
return (1);
|
||||
}
|
||||
case LESS_THAN ->
|
||||
{
|
||||
clause.append(" < ?");
|
||||
return (1);
|
||||
}
|
||||
case LESS_THAN_OR_EQUALS ->
|
||||
{
|
||||
clause.append(" <= ?");
|
||||
return (1);
|
||||
}
|
||||
case GREATER_THAN ->
|
||||
{
|
||||
clause.append(" > ?");
|
||||
return (1);
|
||||
}
|
||||
case GREATER_THAN_OR_EQUALS ->
|
||||
{
|
||||
clause.append(" >= ?");
|
||||
return (1);
|
||||
}
|
||||
case IS_BLANK ->
|
||||
{
|
||||
clause.append(" IS NULL");
|
||||
if(field.getType().isStringLike())
|
||||
{
|
||||
clause.append(" OR ").append(column).append(" = ''");
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
case IS_NOT_BLANK ->
|
||||
{
|
||||
clause.append(" IS NOT NULL");
|
||||
if(field.getType().isStringLike())
|
||||
{
|
||||
clause.append(" AND ").append(column).append(" != ''");
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
case BETWEEN ->
|
||||
{
|
||||
clause.append(" BETWEEN ? AND ?");
|
||||
return (2);
|
||||
}
|
||||
case NOT_BETWEEN ->
|
||||
{
|
||||
clause.append(" NOT BETWEEN ? AND ?");
|
||||
return (2);
|
||||
}
|
||||
case TRUE ->
|
||||
{
|
||||
clause.delete(0, clause.length());
|
||||
clause.append(" 1 = 1 ");
|
||||
return (0);
|
||||
}
|
||||
case FALSE ->
|
||||
{
|
||||
clause.delete(0, clause.length());
|
||||
clause.append(" 0 = 1 ");
|
||||
return (0);
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected operator: " + criterion.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Serializable getFieldValueFromResultSet(QFieldType type, ResultSet resultSet, int i) throws SQLException
|
||||
{
|
||||
return switch(type)
|
||||
{
|
||||
case STRING, TEXT, HTML, PASSWORD -> (QueryManager.getString(resultSet, i));
|
||||
case INTEGER -> (QueryManager.getInteger(resultSet, i));
|
||||
case LONG -> (QueryManager.getLong(resultSet, i));
|
||||
case DECIMAL -> (QueryManager.getBigDecimal(resultSet, i));
|
||||
case DATE -> (QueryManager.getDate(resultSet, i));// todo - queryManager.getLocalDate?
|
||||
case TIME -> (QueryManager.getLocalTime(resultSet, i));
|
||||
case DATE_TIME -> (QueryManager.getInstant(resultSet, i));
|
||||
case BOOLEAN -> (QueryManager.getBoolean(resultSet, i));
|
||||
case BLOB -> (QueryManager.getByteArray(resultSet, i));
|
||||
default -> throw new IllegalStateException("Unexpected field type: " + type);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public PreparedStatement executeUpdate(Connection connection, String sql, List<Object> params) throws SQLException
|
||||
{
|
||||
try(PreparedStatement statement = prepareStatementAndBindParams(connection, sql, new List[] { params }))
|
||||
{
|
||||
incrementStatistic(STAT_QUERIES_RAN);
|
||||
statement.executeUpdate();
|
||||
return (statement);
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
LOG.warn("SQLException", e, logPair("sql", sql));
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void executeBatchUpdate(Connection connection, String updateSQL, List<List<Serializable>> values) throws SQLException
|
||||
{
|
||||
for(List<List<Serializable>> page : CollectionUtils.getPages(values, PAGE_SIZE))
|
||||
{
|
||||
PreparedStatement updatePS = connection.prepareStatement(updateSQL);
|
||||
for(List<Serializable> row : page)
|
||||
{
|
||||
Object[] params = new Object[row.size()];
|
||||
for(int i = 0; i < row.size(); i++)
|
||||
{
|
||||
params[i] = row.get(i);
|
||||
}
|
||||
|
||||
bindParams(params, updatePS);
|
||||
updatePS.addBatch();
|
||||
}
|
||||
incrementStatistic(STAT_BATCHES_RAN);
|
||||
updatePS.executeBatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Serializable> executeInsertForGeneratedIds(Connection connection, String sql, List<Object> params, QFieldMetaData primaryKeyField) throws SQLException
|
||||
{
|
||||
try(PreparedStatement statement = connection.prepareStatement(sql, new String[] { getColumnName(primaryKeyField) }))
|
||||
{
|
||||
bindParams(params.toArray(), statement);
|
||||
incrementStatistic(STAT_QUERIES_RAN);
|
||||
statement.executeUpdate();
|
||||
|
||||
ResultSet generatedKeys = statement.getGeneratedKeys();
|
||||
List<Serializable> rs = new ArrayList<>();
|
||||
while(generatedKeys.next())
|
||||
{
|
||||
rs.add(getFieldValueFromResultSet(primaryKeyField.getType(), generatedKeys, 1));
|
||||
}
|
||||
return (rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Integer executeUpdateForRowCount(Connection connection, String sql, Object... params) throws SQLException
|
||||
{
|
||||
try(PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params))
|
||||
{
|
||||
incrementStatistic(STAT_QUERIES_RAN);
|
||||
int rowCount = statement.executeUpdate();
|
||||
return (rowCount);
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
LOG.warn("SQLException", e, logPair("sql", sql));
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void executeStatement(PreparedStatement statement, CharSequence sql, ResultSetProcessor processor, Object... params) throws SQLException, QException
|
||||
{
|
||||
ResultSet resultSet = null;
|
||||
|
||||
try
|
||||
{
|
||||
bindParams(params, statement);
|
||||
incrementStatistic(STAT_QUERIES_RAN);
|
||||
statement.execute();
|
||||
resultSet = statement.getResultSet();
|
||||
|
||||
if(processor != null)
|
||||
{
|
||||
processor.processResultSet(resultSet);
|
||||
}
|
||||
}
|
||||
catch(SQLException e)
|
||||
{
|
||||
if(sql != null)
|
||||
{
|
||||
LOG.warn("SQLException", e, logPair("sql", sql));
|
||||
}
|
||||
throw (e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(resultSet != null)
|
||||
{
|
||||
resultSet.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Integer getPageSize(AbstractActionInput actionInput)
|
||||
{
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected PreparedStatement prepareStatementAndBindParams(Connection connection, String sql, Object[] params) throws SQLException
|
||||
{
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
bindParams(params, statement);
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void bindParams(Object[] params, PreparedStatement statement) throws SQLException
|
||||
{
|
||||
int paramIndex = 0;
|
||||
if(params != null)
|
||||
{
|
||||
for(Object param : params)
|
||||
{
|
||||
int paramsBound = bindParamObject(statement, (paramIndex + 1), param);
|
||||
paramIndex += paramsBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* index is 1-based!!
|
||||
*******************************************************************************/
|
||||
protected int bindParamObject(PreparedStatement statement, int index, Object value) throws SQLException
|
||||
{
|
||||
if(value instanceof Integer i)
|
||||
{
|
||||
bindParam(statement, index, i);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Short s)
|
||||
{
|
||||
bindParam(statement, index, s.intValue());
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Long l)
|
||||
{
|
||||
bindParam(statement, index, l);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Double d)
|
||||
{
|
||||
bindParam(statement, index, d);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof String s)
|
||||
{
|
||||
bindParam(statement, index, s);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Boolean b)
|
||||
{
|
||||
bindParam(statement, index, b);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Timestamp ts)
|
||||
{
|
||||
bindParam(statement, index, ts);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Date)
|
||||
{
|
||||
bindParam(statement, index, (Date) value);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Calendar c)
|
||||
{
|
||||
bindParam(statement, index, c);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof BigDecimal bd)
|
||||
{
|
||||
bindParam(statement, index, bd);
|
||||
return (1);
|
||||
}
|
||||
else if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.CHAR);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Collection<?> c)
|
||||
{
|
||||
int paramsBound = 0;
|
||||
for(Object o : c)
|
||||
{
|
||||
paramsBound += bindParamObject(statement, (index + paramsBound), o);
|
||||
}
|
||||
return (paramsBound);
|
||||
}
|
||||
else if(value instanceof byte[] ba)
|
||||
{
|
||||
statement.setBytes(index, ba);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof Instant i)
|
||||
{
|
||||
statement.setObject(index, i);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof LocalDate ld)
|
||||
{
|
||||
@SuppressWarnings("deprecation")
|
||||
Date date = new Date(ld.getYear() - 1900, ld.getMonthValue() - 1, ld.getDayOfMonth());
|
||||
statement.setDate(index, date);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof LocalTime lt)
|
||||
{
|
||||
@SuppressWarnings("deprecation")
|
||||
Time time = new Time(lt.getHour(), lt.getMinute(), lt.getSecond());
|
||||
statement.setTime(index, time);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof OffsetDateTime odt)
|
||||
{
|
||||
long epochMillis = odt.toEpochSecond() * MILLIS_PER_SECOND;
|
||||
Timestamp timestamp = new Timestamp(epochMillis);
|
||||
statement.setTimestamp(index, timestamp);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof LocalDateTime ldt)
|
||||
{
|
||||
ZoneOffset offset = OffsetDateTime.now().getOffset();
|
||||
long epochMillis = ldt.toEpochSecond(offset) * MILLIS_PER_SECOND;
|
||||
Timestamp timestamp = new Timestamp(epochMillis);
|
||||
statement.setTimestamp(index, timestamp);
|
||||
return (1);
|
||||
}
|
||||
else if(value instanceof PossibleValueEnum<?> pve)
|
||||
{
|
||||
return (bindParamObject(statement, index, pve.getPossibleValueId()));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new SQLException("Unexpected value type [" + value.getClass().getSimpleName() + "] in bindParamObject."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Integer value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.INTEGER);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setInt(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Long value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.INTEGER);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setLong(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Double value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.DOUBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setDouble(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, String value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.CHAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setString(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Boolean value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.BOOLEAN);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setBoolean(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Date value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.DATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setDate(index, new Date(value.getTime()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Timestamp value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.TIMESTAMP);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setTimestamp(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, Calendar value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.DATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setTimestamp(index, new Timestamp(value.getTimeInMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, LocalDate value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.DATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LocalDateTime localDateTime = value.atTime(0, 0);
|
||||
Timestamp timestamp = new Timestamp(localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond() * MILLIS_PER_SECOND); // TimeStamp expects millis, not seconds, after epoch
|
||||
statement.setTimestamp(index, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, LocalDateTime value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.TIMESTAMP);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timestamp timestamp = new Timestamp(value.atZone(ZoneId.systemDefault()).toEpochSecond() * MILLIS_PER_SECOND); // TimeStamp expects millis, not seconds, after epoch
|
||||
statement.setTimestamp(index, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, BigDecimal value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.DECIMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setBigDecimal(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void bindParam(PreparedStatement statement, int index, byte[] value) throws SQLException
|
||||
{
|
||||
if(value == null)
|
||||
{
|
||||
statement.setNull(index, Types.ARRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
statement.setBytes(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void bindParamNull(PreparedStatement statement, int index) throws SQLException
|
||||
{
|
||||
statement.setNull(index, Types.NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Increment a statistic
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void incrementStatistic(String statName)
|
||||
{
|
||||
if(collectStatistics)
|
||||
{
|
||||
statistics.putIfAbsent(statName, 0);
|
||||
statistics.put(statName, statistics.get(statName) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for collectStatistics
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCollectStatistics(boolean collectStatistics)
|
||||
{
|
||||
this.collectStatistics = collectStatistics;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** clear the map of statistics
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void resetStatistics()
|
||||
{
|
||||
statistics.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for statistics
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Integer> getStatistics()
|
||||
{
|
||||
return statistics;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for pageSize
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setPageSize(int pageSize)
|
||||
{
|
||||
BaseRDBMSActionStrategy.PAGE_SIZE = pageSize;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the column name to use for a field in the RDBMS, from the fieldMetaData.
|
||||
**
|
||||
** That is, field.backendName if set -- else, field.name
|
||||
*******************************************************************************/
|
||||
protected String getColumnName(QFieldMetaData field)
|
||||
{
|
||||
if(field.getBackendName() != null)
|
||||
{
|
||||
return (field.getBackendName());
|
||||
}
|
||||
return (field.getName());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2025. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.module.rdbms.strategy;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** RDBMS action strategy for a field with a FULLTEXT INDEX on it in a MySQL
|
||||
** database. Makes a LIKE or CONTAINS (or NOT those) query use the special
|
||||
** syntax that hits the FULLTEXT INDEX.
|
||||
*******************************************************************************/
|
||||
public class MySQLFullTextIndexFieldStrategy extends BaseRDBMSActionStrategy
|
||||
{
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Integer appendCriterionToWhereClause(QFilterCriteria criterion, StringBuilder clause, String column, List<Serializable> values, QFieldMetaData field)
|
||||
{
|
||||
switch(criterion.getOperator())
|
||||
{
|
||||
case LIKE, CONTAINS ->
|
||||
{
|
||||
clause.append(" MATCH (").append(column).append(") AGAINST (?) ");
|
||||
return (1);
|
||||
}
|
||||
case NOT_LIKE, NOT_CONTAINS ->
|
||||
{
|
||||
clause.append(" NOT MATCH (").append(column).append(") AGAINST (?) ");
|
||||
return (1);
|
||||
}
|
||||
default ->
|
||||
{
|
||||
return super.appendCriterionToWhereClause(criterion, clause, column, values, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.module.rdbms.strategy;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface RDBMSActionStrategyInterface
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
* modifies the clause StringBuilder (appending to it)
|
||||
* returning the number of expected number of params to bind
|
||||
***************************************************************************/
|
||||
Integer appendCriterionToWhereClause(QFilterCriteria criterion, StringBuilder clause, String column, List<Serializable> values, QFieldMetaData field);
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
Serializable getFieldValueFromResultSet(QFieldType type, ResultSet resultSet, int i) throws SQLException;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
PreparedStatement executeUpdate(Connection connection, String sql, List<Object> params) throws SQLException;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
void executeBatchUpdate(Connection connection, String updateSQL, List<List<Serializable>> values) throws SQLException;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
List<Serializable> executeInsertForGeneratedIds(Connection connection, String sql, List<Object> params, QFieldMetaData primaryKeyField) throws SQLException;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
Integer executeUpdateForRowCount(Connection connection, String sql, Object... params) throws SQLException;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
void executeStatement(PreparedStatement statement, CharSequence sql, ResultSetProcessor processor, Object... params) throws SQLException, QException;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
Integer getPageSize(AbstractActionInput actionInput);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@FunctionalInterface
|
||||
interface ResultSetProcessor
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void processResultSet(ResultSet rs) throws SQLException, QException;
|
||||
}
|
||||
}
|
@ -23,10 +23,13 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||
|
||||
|
||||
import java.sql.Connection;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.BaseTest;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||
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.strategy.BaseRDBMSActionStrategy;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
|
||||
@ -42,9 +45,10 @@ public class RDBMSActionTest extends BaseTest
|
||||
@AfterEach
|
||||
void afterEachRDBMSActionTest()
|
||||
{
|
||||
QueryManager.resetPageSize();
|
||||
QueryManager.resetStatistics();
|
||||
QueryManager.setCollectStatistics(false);
|
||||
BaseRDBMSActionStrategy actionStrategy = getBaseRDBMSActionStrategy();
|
||||
actionStrategy.setPageSize(BaseRDBMSActionStrategy.DEFAULT_PAGE_SIZE);
|
||||
actionStrategy.resetStatistics();
|
||||
actionStrategy.setCollectStatistics(false);
|
||||
}
|
||||
|
||||
|
||||
@ -59,6 +63,31 @@ public class RDBMSActionTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
protected static BaseRDBMSActionStrategy getBaseRDBMSActionStrategy()
|
||||
{
|
||||
RDBMSBackendMetaData backend = (RDBMSBackendMetaData) QContext.getQInstance().getBackend(TestUtils.DEFAULT_BACKEND_NAME);
|
||||
BaseRDBMSActionStrategy actionStrategy = (BaseRDBMSActionStrategy) backend.getActionStrategy();
|
||||
return actionStrategy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
***************************************************************************/
|
||||
protected static BaseRDBMSActionStrategy getBaseRDBMSActionStrategyAndActivateCollectingStatistics()
|
||||
{
|
||||
BaseRDBMSActionStrategy actionStrategy = getBaseRDBMSActionStrategy();
|
||||
actionStrategy.setCollectStatistics(true);
|
||||
actionStrategy.resetStatistics();
|
||||
return actionStrategy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user