mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Merge branch 'release/0.2.0'
This commit is contained in:
@ -24,6 +24,8 @@ commands:
|
|||||||
name: Run Maven
|
name: Run Maven
|
||||||
command: |
|
command: |
|
||||||
mvn -s .circleci/mvn-settings.xml << parameters.maven_subcommand >>
|
mvn -s .circleci/mvn-settings.xml << parameters.maven_subcommand >>
|
||||||
|
- store_artifacts:
|
||||||
|
path: target/site/jacoco
|
||||||
- run:
|
- run:
|
||||||
name: Save test results
|
name: Save test results
|
||||||
command: |
|
command: |
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
target/
|
target/
|
||||||
*.iml
|
*.iml
|
||||||
|
.env
|
||||||
|
|
||||||
#############################################
|
#############################################
|
||||||
## Original contents from github template: ##
|
## Original contents from github template: ##
|
||||||
|
88
pom.xml
88
pom.xml
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<groupId>com.kingsrook.qqq</groupId>
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
<artifactId>qqq-backend-module-rdbms</artifactId>
|
<artifactId>qqq-backend-module-rdbms</artifactId>
|
||||||
<version>0.1.0</version>
|
<version>0.2.0</version>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:git@github.com:Kingsrook/qqq-backend-module-rdbms.git</connection>
|
<connection>scm:git:git@github.com:Kingsrook/qqq-backend-module-rdbms.git</connection>
|
||||||
@ -44,6 +44,8 @@
|
|||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
|
<maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
|
||||||
<maven.compiler.showWarnings>true</maven.compiler.showWarnings>
|
<maven.compiler.showWarnings>true</maven.compiler.showWarnings>
|
||||||
|
<coverage.haltOnFailure>true</coverage.haltOnFailure>
|
||||||
|
<coverage.instructionCoveredRatioMinimum>0.80</coverage.instructionCoveredRatioMinimum>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -51,7 +53,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.kingsrook.qqq</groupId>
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
<artifactId>qqq-backend-core</artifactId>
|
<artifactId>qqq-backend-core</artifactId>
|
||||||
<version>0.1.0</version>
|
<version>0.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 3rd party deps specifically for this module -->
|
<!-- 3rd party deps specifically for this module -->
|
||||||
@ -116,6 +118,9 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>3.0.0-M5</version>
|
<version>3.0.0-M5</version>
|
||||||
|
<configuration>
|
||||||
|
<argLine>@{jaCoCoArgLine}</argLine>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@ -165,7 +170,84 @@
|
|||||||
<versionDigitToIncrement>1</versionDigitToIncrement> <!-- In general, we update the minor -->
|
<versionDigitToIncrement>1</versionDigitToIncrement> <!-- In general, we update the minor -->
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jacoco</groupId>
|
||||||
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
|
<version>0.8.8</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>pre-unit-test</id>
|
||||||
|
<goals>
|
||||||
|
<goal>prepare-agent</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<propertyName>jaCoCoArgLine</propertyName>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>unit-test-check</id>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<!-- Gives us the ability to pass a parameter to not fail due to coverage E.g. -Dcoverage.haltOnFailure=false -->
|
||||||
|
<haltOnFailure>${coverage.haltOnFailure}</haltOnFailure>
|
||||||
|
<rules>
|
||||||
|
<rule>
|
||||||
|
<element>BUNDLE</element>
|
||||||
|
<limits>
|
||||||
|
<limit>
|
||||||
|
<counter>INSTRUCTION</counter>
|
||||||
|
<value>COVEREDRATIO</value>
|
||||||
|
<minimum>${coverage.instructionCoveredRatioMinimum}</minimum>
|
||||||
|
</limit>
|
||||||
|
</limits>
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>post-unit-test</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>report</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>test-coverage-summary</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>exec</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<executable>sh</executable>
|
||||||
|
<arguments>
|
||||||
|
<argument>-c</argument>
|
||||||
|
<argument>
|
||||||
|
<![CDATA[
|
||||||
|
echo "Element\nInstructions Missed\nInstruction Coverage\nBranches Missed\nBranch Coverage\nComplexity Missed\nComplexity Hit\nLines Missed\nLines Hit\nMethods Missed\nMethods Hit\nClasses Missed\nClasses Hit\n" > /tmp/$$.headers
|
||||||
|
xpath -q -e '/html/body/table/tfoot/tr[1]/td/text()' target/site/jacoco/index.html > /tmp/$$.values
|
||||||
|
echo
|
||||||
|
echo "Jacoco coverage summary report:"
|
||||||
|
echo " See also target/site/jacoco/index.html"
|
||||||
|
echo " and https://www.jacoco.org/jacoco/trunk/doc/counters.html"
|
||||||
|
echo "------------------------------------------------------------"
|
||||||
|
paste /tmp/$$.headers /tmp/$$.values | tail +2 | awk -v FS='\t' '{printf("%-20s %s\n",$1,$2)}'
|
||||||
|
rm /tmp/$$.headers /tmp/$$.values
|
||||||
|
]]>
|
||||||
|
</argument>
|
||||||
|
</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
@ -22,14 +22,14 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms;
|
package com.kingsrook.qqq.backend.module.rdbms;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableBackendDetails;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.CountInterface;
|
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.DeleteInterface;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.QBackendModuleInterface;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.UpdateInterface;
|
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSCountAction;
|
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSCountAction;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSDeleteAction;
|
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSDeleteAction;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSInsertAction;
|
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSInsertAction;
|
||||||
|
@ -29,12 +29,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractQTableRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
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.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
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.model.metadata.RDBMSBackendMetaData;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||||
@ -85,7 +85,7 @@ public abstract class AbstractRDBMSAction
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Get a database connection, per the backend in the request.
|
** Get a database connection, per the backend in the request.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
protected Connection getConnection(AbstractQTableRequest qTableRequest) throws SQLException
|
protected Connection getConnection(AbstractTableActionInput qTableRequest) throws SQLException
|
||||||
{
|
{
|
||||||
ConnectionManager connectionManager = new ConnectionManager();
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
return connectionManager.getConnection((RDBMSBackendMetaData) qTableRequest.getBackend());
|
return connectionManager.getConnection((RDBMSBackendMetaData) qTableRequest.getBackend());
|
||||||
|
@ -25,15 +25,14 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.count.CountRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.count.CountResult;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.CountInterface;
|
|
||||||
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;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -52,16 +51,16 @@ public class RDBMSCountAction extends AbstractRDBMSAction implements CountInterf
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public CountResult execute(CountRequest countRequest) throws QException
|
public CountOutput execute(CountInput countInput) throws QException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
QTableMetaData table = countRequest.getTable();
|
QTableMetaData table = countInput.getTable();
|
||||||
String tableName = getTableName(table);
|
String tableName = getTableName(table);
|
||||||
|
|
||||||
String sql = "SELECT count(*) as record_count FROM " + tableName;
|
String sql = "SELECT count(*) as record_count FROM " + tableName;
|
||||||
|
|
||||||
QQueryFilter filter = countRequest.getFilter();
|
QQueryFilter filter = countInput.getFilter();
|
||||||
List<Serializable> params = new ArrayList<>();
|
List<Serializable> params = new ArrayList<>();
|
||||||
if(filter != null && CollectionUtils.nullSafeHasContents(filter.getCriteria()))
|
if(filter != null && CollectionUtils.nullSafeHasContents(filter.getCriteria()))
|
||||||
{
|
{
|
||||||
@ -70,13 +69,12 @@ public class RDBMSCountAction extends AbstractRDBMSAction implements CountInterf
|
|||||||
|
|
||||||
// todo sql customization - can edit sql and/or param list
|
// todo sql customization - can edit sql and/or param list
|
||||||
|
|
||||||
CountResult rs = new CountResult();
|
CountOutput rs = new CountOutput();
|
||||||
|
|
||||||
try(Connection connection = getConnection(countRequest))
|
try(Connection connection = getConnection(countInput))
|
||||||
{
|
{
|
||||||
QueryManager.executeStatement(connection, sql, ((ResultSet resultSet) ->
|
QueryManager.executeStatement(connection, sql, ((ResultSet resultSet) ->
|
||||||
{
|
{
|
||||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
|
||||||
if(resultSet.next())
|
if(resultSet.next())
|
||||||
{
|
{
|
||||||
rs.setCount(resultSet.getInt("record_count"));
|
rs.setCount(resultSet.getInt("record_count"));
|
||||||
|
@ -27,13 +27,17 @@ import java.sql.Connection;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.delete.DeleteRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.delete.DeleteResult;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||||
|
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.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.DeleteInterface;
|
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -41,45 +45,63 @@ import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInterface
|
public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInterface
|
||||||
{
|
{
|
||||||
|
private static final Logger LOG = LogManager.getLogger(RDBMSDeleteAction.class);
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public DeleteResult execute(DeleteRequest deleteRequest) throws QException
|
@Override
|
||||||
|
public boolean supportsQueryFilterInput()
|
||||||
|
{
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public DeleteOutput execute(DeleteInput deleteInput) throws QException
|
||||||
|
{
|
||||||
|
DeleteOutput deleteOutput = new DeleteOutput();
|
||||||
|
deleteOutput.setRecordsWithErrors(new ArrayList<>());
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Our strategy is: //
|
||||||
|
// - if there's a query filter, try to do a delete WHERE that filter. //
|
||||||
|
// - - if that has an error, or if there wasn't a query filter, then continue: //
|
||||||
|
// - if there's only 1 pkey to delete, just run a delete where $pkey=? query //
|
||||||
|
// - else if there's a list, try to delete it, but upon error: //
|
||||||
|
// - - do a single-delete for each entry in the list. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
try(Connection connection = getConnection(deleteInput))
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if there's a query filter, try to do a single-delete with that filter in the WHERE clause //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(deleteInput.getQueryFilter() != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DeleteResult rs = new DeleteResult();
|
deleteInput.getAsyncJobCallback().updateStatus("Running bulk delete via query filter.");
|
||||||
QTableMetaData table = deleteRequest.getTable();
|
deleteQueryFilter(connection, deleteInput, deleteOutput);
|
||||||
|
return (deleteOutput);
|
||||||
String tableName = getTableName(table);
|
}
|
||||||
String primaryKeyName = getColumnName(table.getField(table.getPrimaryKeyField()));
|
catch(Exception e)
|
||||||
String sql = "DELETE FROM "
|
|
||||||
+ tableName
|
|
||||||
+ " WHERE "
|
|
||||||
+ primaryKeyName
|
|
||||||
+ " IN ("
|
|
||||||
+ deleteRequest.getPrimaryKeys().stream().map(x -> "?").collect(Collectors.joining(","))
|
|
||||||
+ ")";
|
|
||||||
List<Serializable> params = deleteRequest.getPrimaryKeys();
|
|
||||||
|
|
||||||
// todo sql customization - can edit sql and/or param list
|
|
||||||
|
|
||||||
try(Connection connection = getConnection(deleteRequest))
|
|
||||||
{
|
{
|
||||||
QueryManager.executeUpdateForRowCount(connection, sql, params);
|
deleteInput.getAsyncJobCallback().updateStatus("Error running bulk delete via filter. Fetching keys for individual deletes.");
|
||||||
List<QRecord> outputRecords = new ArrayList<>();
|
LOG.info("Exception trying to delete by filter query. Moving on to deleting by id now.");
|
||||||
rs.setRecords(outputRecords);
|
deleteInput.setPrimaryKeys(DeleteAction.getPrimaryKeysFromQueryFilter(deleteInput));
|
||||||
for(Serializable primaryKey : deleteRequest.getPrimaryKeys())
|
|
||||||
{
|
|
||||||
QRecord qRecord = new QRecord().withTableName(deleteRequest.getTableName()).withValue("id", primaryKey);
|
|
||||||
// todo uh, identify any errors?
|
|
||||||
QRecord outputRecord = new QRecord(qRecord);
|
|
||||||
outputRecords.add(outputRecord);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rs;
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// at this point, there either wasn't a query filter, or there was an error executing it (in which case, the query should //
|
||||||
|
// have been converted to a list of primary keys in the deleteInput). so, proceed now by deleting a list of pkeys. //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
deleteList(connection, deleteInput, deleteOutput);
|
||||||
|
return (deleteOutput);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
@ -87,4 +109,142 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void deleteList(Connection connection, DeleteInput deleteInput, DeleteOutput deleteOutput)
|
||||||
|
{
|
||||||
|
List<Serializable> primaryKeys = deleteInput.getPrimaryKeys();
|
||||||
|
if(primaryKeys.size() == 1)
|
||||||
|
{
|
||||||
|
doDeleteOne(connection, deleteInput.getTable(), primaryKeys.get(0), deleteOutput);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// todo - page this? or binary-tree it?
|
||||||
|
try
|
||||||
|
{
|
||||||
|
deleteInput.getAsyncJobCallback().updateStatus("Running bulk delete via key list.");
|
||||||
|
doDeleteList(connection, deleteInput.getTable(), primaryKeys, deleteOutput);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
deleteInput.getAsyncJobCallback().updateStatus("Error running bulk delete via key list. Performing individual deletes.");
|
||||||
|
LOG.info("Caught an error doing list-delete - going to single-deletes now", e);
|
||||||
|
int current = 1;
|
||||||
|
for(Serializable primaryKey : primaryKeys)
|
||||||
|
{
|
||||||
|
deleteInput.getAsyncJobCallback().updateStatus(current++, primaryKeys.size());
|
||||||
|
doDeleteOne(connection, deleteInput.getTable(), primaryKey, deleteOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void doDeleteOne(Connection connection, QTableMetaData table, Serializable primaryKey, DeleteOutput deleteOutput)
|
||||||
|
{
|
||||||
|
String tableName = getTableName(table);
|
||||||
|
String primaryKeyName = getColumnName(table.getField(table.getPrimaryKeyField()));
|
||||||
|
|
||||||
|
// todo sql customization - can edit sql and/or param list?
|
||||||
|
String sql = "DELETE FROM "
|
||||||
|
+ tableName
|
||||||
|
+ " WHERE "
|
||||||
|
+ primaryKeyName + " = ?";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int rowCount = QueryManager.executeUpdateForRowCount(connection, sql, primaryKey);
|
||||||
|
deleteOutput.addToDeletedRecordCount(rowCount);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// it seems like maybe we shouldn't do the below - ids that aren't found will hit this condition, //
|
||||||
|
// but we (1) don't care and (2) can't detect this case when doing an in-list delete, so, let's //
|
||||||
|
// make the results match, and just avoid adding to the deleted count, not marking it as an error. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if(rowCount == 1)
|
||||||
|
// {
|
||||||
|
// deleteOutput.addToDeletedRecordCount(1);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// LOG.debug("rowCount 0 trying to delete [" + tableName + "][" + primaryKey + "]");
|
||||||
|
// deleteOutput.addRecordWithError(new QRecord(table, primaryKey).withError("Record was not deleted (but no error was given from the database)"));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.debug("Exception trying to delete [" + tableName + "][" + primaryKey + "]", e);
|
||||||
|
deleteOutput.addRecordWithError(new QRecord(table, primaryKey).withError("Record was not deleted: " + e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void doDeleteList(Connection connection, QTableMetaData table, List<Serializable> primaryKeys, DeleteOutput deleteOutput) throws QException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String tableName = getTableName(table);
|
||||||
|
String primaryKeyName = getColumnName(table.getField(table.getPrimaryKeyField()));
|
||||||
|
String sql = "DELETE FROM "
|
||||||
|
+ tableName
|
||||||
|
+ " WHERE "
|
||||||
|
+ primaryKeyName
|
||||||
|
+ " IN ("
|
||||||
|
+ primaryKeys.stream().map(x -> "?").collect(Collectors.joining(","))
|
||||||
|
+ ")";
|
||||||
|
|
||||||
|
// todo sql customization - can edit sql and/or param list
|
||||||
|
|
||||||
|
Integer rowCount = QueryManager.executeUpdateForRowCount(connection, sql, primaryKeys);
|
||||||
|
deleteOutput.addToDeletedRecordCount(rowCount);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new QException("Error executing delete: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void deleteQueryFilter(Connection connection, DeleteInput deleteInput, DeleteOutput deleteOutput) throws QException
|
||||||
|
{
|
||||||
|
QQueryFilter filter = deleteInput.getQueryFilter();
|
||||||
|
List<Serializable> params = new ArrayList<>();
|
||||||
|
QTableMetaData table = deleteInput.getTable();
|
||||||
|
|
||||||
|
String tableName = getTableName(table);
|
||||||
|
String whereClause = makeWhereClause(table, filter.getCriteria(), params);
|
||||||
|
|
||||||
|
// todo sql customization - can edit sql and/or param list?
|
||||||
|
String sql = "DELETE FROM "
|
||||||
|
+ tableName
|
||||||
|
+ " WHERE "
|
||||||
|
+ whereClause;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int rowCount = QueryManager.executeUpdateForRowCount(connection, sql, params);
|
||||||
|
|
||||||
|
deleteOutput.setDeletedRecordCount(rowCount);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new QException("Error executing delete with filter: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,13 @@ import java.time.Instant;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.insert.InsertRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.insert.InsertResult;
|
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.core.model.metadata.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface;
|
|
||||||
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;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -53,21 +53,21 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public InsertResult execute(InsertRequest insertRequest) throws QException
|
public InsertOutput execute(InsertInput insertInput) throws QException
|
||||||
{
|
{
|
||||||
InsertResult rs = new InsertResult();
|
InsertOutput rs = new InsertOutput();
|
||||||
|
|
||||||
if(CollectionUtils.nullSafeIsEmpty(insertRequest.getRecords()))
|
if(CollectionUtils.nullSafeIsEmpty(insertInput.getRecords()))
|
||||||
{
|
{
|
||||||
LOG.info("Insert request called with 0 records. Returning with no-op");
|
LOG.info("Insert request called with 0 records. Returning with no-op");
|
||||||
rs.setRecords(new ArrayList<>());
|
rs.setRecords(new ArrayList<>());
|
||||||
return (rs);
|
return (rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTableMetaData table = insertRequest.getTable();
|
QTableMetaData table = insertInput.getTable();
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
|
|
||||||
for(QRecord record : insertRequest.getRecords())
|
for(QRecord record : insertInput.getRecords())
|
||||||
{
|
{
|
||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
// todo .. better (not hard-coded names) //
|
// todo .. better (not hard-coded names) //
|
||||||
@ -89,15 +89,18 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
|
|||||||
.map(x -> "?")
|
.map(x -> "?")
|
||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
|
|
||||||
|
List<QRecord> outputRecords = new ArrayList<>();
|
||||||
|
rs.setRecords(outputRecords);
|
||||||
|
|
||||||
|
try(Connection connection = getConnection(insertInput))
|
||||||
|
{
|
||||||
|
for(List<QRecord> page : CollectionUtils.getPages(insertInput.getRecords(), QueryManager.PAGE_SIZE))
|
||||||
|
{
|
||||||
String tableName = getTableName(table);
|
String tableName = getTableName(table);
|
||||||
StringBuilder sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(columns).append(") VALUES");
|
StringBuilder sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(columns).append(") VALUES");
|
||||||
List<Object> params = new ArrayList<>();
|
List<Object> params = new ArrayList<>();
|
||||||
|
|
||||||
try(Connection connection = getConnection(insertRequest))
|
|
||||||
{
|
|
||||||
for(List<QRecord> page : CollectionUtils.getPages(insertRequest.getRecords(), QueryManager.PAGE_SIZE))
|
|
||||||
{
|
|
||||||
int recordIndex = 0;
|
int recordIndex = 0;
|
||||||
|
|
||||||
for(QRecord record : page)
|
for(QRecord record : page)
|
||||||
{
|
{
|
||||||
if(recordIndex++ > 0)
|
if(recordIndex++ > 0)
|
||||||
@ -117,10 +120,8 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
|
|||||||
// 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<Integer> idList = QueryManager.executeInsertForGeneratedIds(connection, sql.toString(), params);
|
List<Integer> idList = QueryManager.executeInsertForGeneratedIds(connection, sql.toString(), params);
|
||||||
List<QRecord> outputRecords = new ArrayList<>();
|
|
||||||
rs.setRecords(outputRecords);
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for(QRecord record : insertRequest.getRecords())
|
for(QRecord record : page)
|
||||||
{
|
{
|
||||||
Integer id = idList.get(index++);
|
Integer id = idList.get(index++);
|
||||||
QRecord outputRecord = new QRecord(record);
|
QRecord outputRecord = new QRecord(record);
|
||||||
|
@ -24,27 +24,26 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QFilterOrderBy;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QueryRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult;
|
|
||||||
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.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface;
|
|
||||||
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;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@ -61,11 +60,11 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public QueryResult execute(QueryRequest queryRequest) throws QException
|
public QueryOutput execute(QueryInput queryInput) throws QException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
QTableMetaData table = queryRequest.getTable();
|
QTableMetaData table = queryInput.getTable();
|
||||||
String tableName = getTableName(table);
|
String tableName = getTableName(table);
|
||||||
|
|
||||||
List<QFieldMetaData> fieldList = new ArrayList<>(table.getFields().values());
|
List<QFieldMetaData> fieldList = new ArrayList<>(table.getFields().values());
|
||||||
@ -75,7 +74,7 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
|
|||||||
|
|
||||||
String sql = "SELECT " + columns + " FROM " + tableName;
|
String sql = "SELECT " + columns + " FROM " + tableName;
|
||||||
|
|
||||||
QQueryFilter filter = queryRequest.getFilter();
|
QQueryFilter filter = queryInput.getFilter();
|
||||||
List<Serializable> params = new ArrayList<>();
|
List<Serializable> params = new ArrayList<>();
|
||||||
if(filter != null && CollectionUtils.nullSafeHasContents(filter.getCriteria()))
|
if(filter != null && CollectionUtils.nullSafeHasContents(filter.getCriteria()))
|
||||||
{
|
{
|
||||||
@ -87,34 +86,31 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
|
|||||||
sql += " ORDER BY " + makeOrderByClause(table, filter.getOrderBys());
|
sql += " ORDER BY " + makeOrderByClause(table, filter.getOrderBys());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(queryRequest.getLimit() != null)
|
if(queryInput.getLimit() != null)
|
||||||
{
|
{
|
||||||
sql += " LIMIT " + queryRequest.getLimit();
|
sql += " LIMIT " + queryInput.getLimit();
|
||||||
|
|
||||||
if(queryRequest.getSkip() != null)
|
if(queryInput.getSkip() != null)
|
||||||
{
|
{
|
||||||
// todo - other sql grammars?
|
// todo - other sql grammars?
|
||||||
sql += " OFFSET " + queryRequest.getSkip();
|
sql += " OFFSET " + queryInput.getSkip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo sql customization - can edit sql and/or param list
|
// todo sql customization - can edit sql and/or param list
|
||||||
|
|
||||||
QueryResult rs = new QueryResult();
|
QueryOutput queryOutput = new QueryOutput(queryInput);
|
||||||
List<QRecord> records = new ArrayList<>();
|
|
||||||
rs.setRecords(records);
|
|
||||||
|
|
||||||
try(Connection connection = getConnection(queryRequest))
|
try(Connection connection = getConnection(queryInput))
|
||||||
{
|
{
|
||||||
QueryManager.executeStatement(connection, sql, ((ResultSet resultSet) ->
|
PreparedStatement statement = createStatement(connection, sql, queryInput);
|
||||||
|
QueryManager.executeStatement(statement, ((ResultSet resultSet) ->
|
||||||
{
|
{
|
||||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||||
while(resultSet.next())
|
while(resultSet.next())
|
||||||
{
|
{
|
||||||
// todo - should refactor this for view etc to use too.
|
|
||||||
// todo - Add display values (String labels for possibleValues, formatted #'s, etc)
|
// todo - Add display values (String labels for possibleValues, formatted #'s, etc)
|
||||||
QRecord record = new QRecord();
|
QRecord record = new QRecord();
|
||||||
records.add(record);
|
|
||||||
record.setTableName(table.getName());
|
record.setTableName(table.getName());
|
||||||
LinkedHashMap<String, Serializable> values = new LinkedHashMap<>();
|
LinkedHashMap<String, Serializable> values = new LinkedHashMap<>();
|
||||||
record.setValues(values);
|
record.setValues(values);
|
||||||
@ -125,12 +121,14 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
|
|||||||
Serializable value = getValue(qFieldMetaData, resultSet, i);
|
Serializable value = getValue(qFieldMetaData, resultSet, i);
|
||||||
values.put(qFieldMetaData.getName(), value);
|
values.put(qFieldMetaData.getName(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queryOutput.addRecord(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
}), params);
|
}), params);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rs;
|
return queryOutput;
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
@ -141,6 +139,32 @@ public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterf
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private PreparedStatement createStatement(Connection connection, String sql, QueryInput queryInput) throws SQLException
|
||||||
|
{
|
||||||
|
RDBMSBackendMetaData backend = (RDBMSBackendMetaData) queryInput.getBackend();
|
||||||
|
PreparedStatement statement;
|
||||||
|
if("mysql".equals(backend.getVendor()))
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// mysql "optimization", presumably here - from Result Set section of https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html //
|
||||||
|
// without this change, we saw ~10 seconds of "wait" time, before results would start to stream out of a large query (e.g., > 1,000,000 rows). //
|
||||||
|
// with this change, we start to get results immediately, and the total runtime also seems lower... //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||||
|
statement.setFetchSize(Integer.MIN_VALUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement = connection.prepareStatement(sql);
|
||||||
|
}
|
||||||
|
return (statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -31,13 +31,13 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult;
|
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.model.metadata.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.modules.interfaces.UpdateInterface;
|
|
||||||
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;
|
||||||
@ -58,23 +58,25 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
{
|
{
|
||||||
private static final Logger LOG = LogManager.getLogger(RDBMSUpdateAction.class);
|
private static final Logger LOG = LogManager.getLogger(RDBMSUpdateAction.class);
|
||||||
|
|
||||||
|
private int statusCounter = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public UpdateResult execute(UpdateRequest updateRequest) throws QException
|
public UpdateOutput execute(UpdateInput updateInput) throws QException
|
||||||
{
|
{
|
||||||
UpdateResult rs = new UpdateResult();
|
UpdateOutput rs = new UpdateOutput();
|
||||||
|
|
||||||
if(CollectionUtils.nullSafeIsEmpty(updateRequest.getRecords()))
|
if(CollectionUtils.nullSafeIsEmpty(updateInput.getRecords()))
|
||||||
{
|
{
|
||||||
LOG.info("Update request called with 0 records. Returning with no-op");
|
LOG.info("Update request called with 0 records. Returning with no-op");
|
||||||
rs.setRecords(new ArrayList<>());
|
rs.setRecords(new ArrayList<>());
|
||||||
return (rs);
|
return (rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTableMetaData table = updateRequest.getTable();
|
QTableMetaData table = updateInput.getTable();
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
|
|
||||||
List<QRecord> outputRecords = new ArrayList<>();
|
List<QRecord> outputRecords = new ArrayList<>();
|
||||||
@ -86,7 +88,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
// record. So, we will first "hash" up the records by their list of fields being updated. //
|
// record. So, we will first "hash" up the records by their list of fields being updated. //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
ListingHash<List<String>, QRecord> recordsByFieldBeingUpdated = new ListingHash<>();
|
ListingHash<List<String>, QRecord> recordsByFieldBeingUpdated = new ListingHash<>();
|
||||||
for(QRecord record : updateRequest.getRecords())
|
for(QRecord record : updateInput.getRecords())
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// todo .. better (not a hard-coded name) //
|
// todo .. better (not a hard-coded name) //
|
||||||
@ -112,14 +114,14 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
outputRecords.add(outputRecord);
|
outputRecords.add(outputRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
try(Connection connection = getConnection(updateRequest))
|
try(Connection connection = getConnection(updateInput))
|
||||||
{
|
{
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// process each distinct list of fields being updated (e.g., each different SQL statement) //
|
// process each distinct list of fields being updated (e.g., each different SQL statement) //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
for(List<String> fieldsBeingUpdated : recordsByFieldBeingUpdated.keySet())
|
for(List<String> fieldsBeingUpdated : recordsByFieldBeingUpdated.keySet())
|
||||||
{
|
{
|
||||||
updateRecordsWithMatchingListOfFields(connection, table, recordsByFieldBeingUpdated.get(fieldsBeingUpdated), fieldsBeingUpdated);
|
updateRecordsWithMatchingListOfFields(updateInput, connection, table, recordsByFieldBeingUpdated.get(fieldsBeingUpdated), fieldsBeingUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rs;
|
return rs;
|
||||||
@ -136,15 +138,25 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private void updateRecordsWithMatchingListOfFields(Connection connection, QTableMetaData table, List<QRecord> recordList, List<String> fieldsBeingUpdated) throws SQLException
|
private void updateRecordsWithMatchingListOfFields(UpdateInput updateInput, Connection connection, QTableMetaData table, List<QRecord> recordList, List<String> fieldsBeingUpdated) throws SQLException
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// check for an optimization - if all of the records have the same values for //
|
// check for an optimization - if all of the records have the same values for //
|
||||||
// all fields being updated, just do 1 update, with an IN list on the ids. //
|
// all fields being updated, just do 1 update, with an IN list on the ids. //
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
if(areAllValuesBeingUpdatedTheSame(recordList, fieldsBeingUpdated))
|
boolean allAreTheSame;
|
||||||
|
if(updateInput.getAreAllValuesBeingUpdatedTheSame() != null)
|
||||||
{
|
{
|
||||||
updateRecordsWithMatchingValuesAndFields(connection, table, recordList, fieldsBeingUpdated);
|
allAreTheSame = updateInput.getAreAllValuesBeingUpdatedTheSame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allAreTheSame = areAllValuesBeingUpdatedTheSame(recordList, fieldsBeingUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(allAreTheSame)
|
||||||
|
{
|
||||||
|
updateRecordsWithMatchingValuesAndFields(updateInput, connection, table, recordList, fieldsBeingUpdated);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,10 +186,12 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
// let query manager do the batch updates - note that it will internally page //
|
// let query manager do the batch updates - note that it will internally page //
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
QueryManager.executeBatchUpdate(connection, sql, values);
|
QueryManager.executeBatchUpdate(connection, sql, values);
|
||||||
|
incrementStatus(updateInput, recordList.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -198,7 +212,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private void updateRecordsWithMatchingValuesAndFields(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, QueryManager.PAGE_SIZE))
|
||||||
{
|
{
|
||||||
@ -230,6 +244,7 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
// let query manager do the update //
|
// let query manager do the update //
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
QueryManager.executeUpdate(connection, sql, params);
|
QueryManager.executeUpdate(connection, sql, params);
|
||||||
|
incrementStatus(updateInput, page.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,4 +276,14 @@ public class RDBMSUpdateAction extends AbstractRDBMSAction implements UpdateInte
|
|||||||
return (true);
|
return (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void incrementStatus(UpdateInput updateInput, int amount)
|
||||||
|
{
|
||||||
|
statusCounter += amount;
|
||||||
|
updateInput.getAsyncJobCallback().updateStatus(statusCounter, updateInput.getRecords().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,9 @@ import org.apache.commons.lang.NotImplementedException;
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class QueryManager
|
public class QueryManager
|
||||||
{
|
{
|
||||||
public static final int PAGE_SIZE = 2000;
|
public static final int DEFAULT_PAGE_SIZE = 2000;
|
||||||
|
public static int PAGE_SIZE = DEFAULT_PAGE_SIZE;
|
||||||
|
|
||||||
private static final int MS_PER_SEC = 1000;
|
private static final int MS_PER_SEC = 1000;
|
||||||
private static final int NINETEEN_HUNDRED = 1900;
|
private static final int NINETEEN_HUNDRED = 1900;
|
||||||
|
|
||||||
@ -85,19 +87,13 @@ public class QueryManager
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static void executeStatement(Connection connection, String sql, ResultSetProcessor procesor, Object... params) throws SQLException
|
public static void executeStatement(Connection connection, String sql, ResultSetProcessor processor, Object... params) throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement statement = null;
|
PreparedStatement statement = null;
|
||||||
ResultSet resultSet = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
statement = prepareStatementAndBindParams(connection, sql, params);
|
statement = prepareStatementAndBindParams(connection, sql, params);
|
||||||
statement.execute();
|
executeStatement(statement, processor, params);
|
||||||
incrementStatistic(STAT_QUERIES_RAN);
|
|
||||||
resultSet = statement.getResultSet();
|
|
||||||
|
|
||||||
procesor.processResultSet(resultSet);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -105,7 +101,30 @@ public class QueryManager
|
|||||||
{
|
{
|
||||||
statement.close();
|
statement.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Let the caller provide their own prepared statement (e.g., possibly with some
|
||||||
|
** customized settings/optimizations).
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void executeStatement(PreparedStatement statement, ResultSetProcessor processor, Object... params) throws SQLException
|
||||||
|
{
|
||||||
|
ResultSet resultSet = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bindParams(statement, params);
|
||||||
|
incrementStatistic(STAT_QUERIES_RAN);
|
||||||
|
statement.execute();
|
||||||
|
resultSet = statement.getResultSet();
|
||||||
|
|
||||||
|
processor.processResultSet(resultSet);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
if(resultSet != null)
|
if(resultSet != null)
|
||||||
{
|
{
|
||||||
resultSet.close();
|
resultSet.close();
|
||||||
@ -354,8 +373,8 @@ public class QueryManager
|
|||||||
public static PreparedStatement executeUpdate(Connection connection, String sql, Object... params) throws SQLException
|
public static PreparedStatement executeUpdate(Connection connection, String sql, Object... params) throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params);
|
PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params);
|
||||||
statement.executeUpdate();
|
|
||||||
incrementStatistic(STAT_QUERIES_RAN);
|
incrementStatistic(STAT_QUERIES_RAN);
|
||||||
|
statement.executeUpdate();
|
||||||
return (statement);
|
return (statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,8 +386,8 @@ public class QueryManager
|
|||||||
public static PreparedStatement executeUpdate(Connection connection, String sql, List<Object> params) throws SQLException
|
public static PreparedStatement executeUpdate(Connection connection, String sql, List<Object> params) throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params);
|
PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params);
|
||||||
statement.executeUpdate();
|
|
||||||
incrementStatistic(STAT_QUERIES_RAN);
|
incrementStatistic(STAT_QUERIES_RAN);
|
||||||
|
statement.executeUpdate();
|
||||||
return (statement);
|
return (statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,8 +432,8 @@ public class QueryManager
|
|||||||
{
|
{
|
||||||
try(PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params))
|
try(PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params))
|
||||||
{
|
{
|
||||||
statement.executeUpdate();
|
|
||||||
incrementStatistic(STAT_QUERIES_RAN);
|
incrementStatistic(STAT_QUERIES_RAN);
|
||||||
|
statement.executeUpdate();
|
||||||
return (statement.getUpdateCount());
|
return (statement.getUpdateCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,9 +492,9 @@ public class QueryManager
|
|||||||
try(PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS))
|
try(PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS))
|
||||||
{
|
{
|
||||||
bindParams(params.toArray(), statement);
|
bindParams(params.toArray(), statement);
|
||||||
|
incrementStatistic(STAT_QUERIES_RAN);
|
||||||
statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
ResultSet generatedKeys = statement.getGeneratedKeys();
|
ResultSet generatedKeys = statement.getGeneratedKeys();
|
||||||
incrementStatistic(STAT_QUERIES_RAN);
|
|
||||||
while(generatedKeys.next())
|
while(generatedKeys.next())
|
||||||
{
|
{
|
||||||
rs.add(getInteger(generatedKeys, 1));
|
rs.add(getInteger(generatedKeys, 1));
|
||||||
@ -565,8 +584,8 @@ public class QueryManager
|
|||||||
bindParams(updatePS, params);
|
bindParams(updatePS, params);
|
||||||
updatePS.addBatch();
|
updatePS.addBatch();
|
||||||
}
|
}
|
||||||
updatePS.executeBatch();
|
|
||||||
incrementStatistic(STAT_BATCHES_RAN);
|
incrementStatistic(STAT_BATCHES_RAN);
|
||||||
|
updatePS.executeBatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,7 +659,7 @@ public class QueryManager
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
*
|
* index is 1-based!!
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static int bindParamObject(PreparedStatement statement, int index, Object value) throws SQLException
|
public static int bindParamObject(PreparedStatement statement, int index, Object value) throws SQLException
|
||||||
@ -651,34 +670,34 @@ public class QueryManager
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else*/
|
else*/
|
||||||
if(value instanceof Integer)
|
if(value instanceof Integer i)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, (Integer) value);
|
bindParam(statement, index, i);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Short)
|
else if(value instanceof Short s)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, ((Short) value).intValue());
|
bindParam(statement, index, s.intValue());
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Long)
|
else if(value instanceof Long l)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, ((Long) value).intValue());
|
bindParam(statement, index, l.intValue());
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof String)
|
else if(value instanceof String s)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, (String) value);
|
bindParam(statement, index, s);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Boolean)
|
else if(value instanceof Boolean b)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, (Boolean) value);
|
bindParam(statement, index, b);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Timestamp)
|
else if(value instanceof Timestamp ts)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, (Timestamp) value);
|
bindParam(statement, index, ts);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Date)
|
else if(value instanceof Date)
|
||||||
@ -686,14 +705,14 @@ public class QueryManager
|
|||||||
bindParam(statement, index, (Date) value);
|
bindParam(statement, index, (Date) value);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Calendar)
|
else if(value instanceof Calendar c)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, (Calendar) value);
|
bindParam(statement, index, c);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof BigDecimal)
|
else if(value instanceof BigDecimal bd)
|
||||||
{
|
{
|
||||||
bindParam(statement, index, (BigDecimal) value);
|
bindParam(statement, index, bd);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value == null)
|
else if(value == null)
|
||||||
@ -701,42 +720,47 @@ public class QueryManager
|
|||||||
statement.setNull(index, Types.CHAR);
|
statement.setNull(index, Types.CHAR);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Collection)
|
else if(value instanceof Collection c)
|
||||||
{
|
{
|
||||||
Collection<?> collection = (Collection<?>) value;
|
|
||||||
int paramsBound = 0;
|
int paramsBound = 0;
|
||||||
for(Object o : collection)
|
for(Object o : c)
|
||||||
{
|
{
|
||||||
paramsBound += bindParamObject(statement, (index + paramsBound), o);
|
paramsBound += bindParamObject(statement, (index + paramsBound), o);
|
||||||
}
|
}
|
||||||
return (paramsBound);
|
return (paramsBound);
|
||||||
}
|
}
|
||||||
else if(value instanceof byte[])
|
else if(value instanceof byte[] ba)
|
||||||
{
|
{
|
||||||
statement.setBytes(index, (byte[]) value);
|
statement.setBytes(index, ba);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof Instant)
|
else if(value instanceof Instant i)
|
||||||
{
|
{
|
||||||
Timestamp timestamp = new Timestamp(((Instant) value).toEpochMilli());
|
long epochMillis = i.toEpochMilli();
|
||||||
|
Timestamp timestamp = new Timestamp(epochMillis);
|
||||||
statement.setTimestamp(index, timestamp);
|
statement.setTimestamp(index, timestamp);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof LocalDate)
|
else if(value instanceof LocalDate ld)
|
||||||
{
|
{
|
||||||
Timestamp timestamp = new Timestamp(((LocalDate) value).atTime(0, 0).toEpochSecond(ZoneOffset.UTC) * MS_PER_SEC);
|
ZoneOffset offset = OffsetDateTime.now().getOffset();
|
||||||
|
long epochMillis = ld.atStartOfDay().toEpochSecond(offset) * MS_PER_SEC;
|
||||||
|
Timestamp timestamp = new Timestamp(epochMillis);
|
||||||
statement.setTimestamp(index, timestamp);
|
statement.setTimestamp(index, timestamp);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof OffsetDateTime)
|
else if(value instanceof OffsetDateTime odt)
|
||||||
{
|
{
|
||||||
Timestamp timestamp = new Timestamp(((OffsetDateTime) value).toEpochSecond() * MS_PER_SEC);
|
long epochMillis = odt.toEpochSecond() * MS_PER_SEC;
|
||||||
|
Timestamp timestamp = new Timestamp(epochMillis);
|
||||||
statement.setTimestamp(index, timestamp);
|
statement.setTimestamp(index, timestamp);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
else if(value instanceof LocalDateTime)
|
else if(value instanceof LocalDateTime ldt)
|
||||||
{
|
{
|
||||||
Timestamp timestamp = new Timestamp(((LocalDateTime) value).toEpochSecond(ZoneOffset.UTC) * MS_PER_SEC);
|
ZoneOffset offset = OffsetDateTime.now().getOffset();
|
||||||
|
long epochMillis = ldt.toEpochSecond(offset) * MS_PER_SEC;
|
||||||
|
Timestamp timestamp = new Timestamp(epochMillis);
|
||||||
statement.setTimestamp(index, timestamp);
|
statement.setTimestamp(index, timestamp);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@ -1120,15 +1144,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static BigDecimal getBigDecimal(ResultSet resultSet, String column) throws SQLException
|
public static BigDecimal getBigDecimal(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
BigDecimal value = resultSet.getBigDecimal(column);
|
BigDecimal value = resultSet.getBigDecimal(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1153,15 +1174,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Date getDate(ResultSet resultSet, String column) throws SQLException
|
public static Date getDate(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Date value = resultSet.getDate(column);
|
Date value = resultSet.getDate(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1186,8 +1204,6 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Calendar getCalendar(ResultSet resultSet, String column) throws SQLException
|
public static Calendar getCalendar(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
@ -1196,7 +1212,6 @@ public class QueryManager
|
|||||||
Calendar rs = Calendar.getInstance();
|
Calendar rs = Calendar.getInstance();
|
||||||
rs.setTimeInMillis(value.getTime());
|
rs.setTimeInMillis(value.getTime());
|
||||||
return (rs);
|
return (rs);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1206,8 +1221,6 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Calendar getCalendar(ResultSet resultSet, int column) throws SQLException
|
public static Calendar getCalendar(ResultSet resultSet, int column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
@ -1216,7 +1229,6 @@ public class QueryManager
|
|||||||
Calendar rs = Calendar.getInstance();
|
Calendar rs = Calendar.getInstance();
|
||||||
rs.setTimeInMillis(value.getTime());
|
rs.setTimeInMillis(value.getTime());
|
||||||
return (rs);
|
return (rs);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1227,8 +1239,6 @@ public class QueryManager
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static LocalDate getLocalDate(ResultSet resultSet, String column) throws SQLException
|
public static LocalDate getLocalDate(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
@ -1237,7 +1247,24 @@ public class QueryManager
|
|||||||
|
|
||||||
LocalDate date = LocalDate.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate());
|
LocalDate date = LocalDate.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate());
|
||||||
return (date);
|
return (date);
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static LocalDate getLocalDate(ResultSet resultSet, int column) throws SQLException
|
||||||
|
{
|
||||||
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
|
if(resultSet.wasNull())
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDate date = LocalDate.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate());
|
||||||
|
return (date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1248,8 +1275,6 @@ public class QueryManager
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static LocalDateTime getLocalDateTime(ResultSet resultSet, String column) throws SQLException
|
public static LocalDateTime getLocalDateTime(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
@ -1258,7 +1283,6 @@ public class QueryManager
|
|||||||
|
|
||||||
LocalDateTime dateTime = LocalDateTime.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), 0);
|
LocalDateTime dateTime = LocalDateTime.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), 0);
|
||||||
return (dateTime);
|
return (dateTime);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1287,8 +1311,6 @@ public class QueryManager
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static OffsetDateTime getOffsetDateTime(ResultSet resultSet, String column) throws SQLException
|
public static OffsetDateTime getOffsetDateTime(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
@ -1297,7 +1319,24 @@ public class QueryManager
|
|||||||
|
|
||||||
OffsetDateTime dateTime = OffsetDateTime.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), 0, OffsetDateTime.now().getOffset());
|
OffsetDateTime dateTime = OffsetDateTime.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), 0, OffsetDateTime.now().getOffset());
|
||||||
return (dateTime);
|
return (dateTime);
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static OffsetDateTime getOffsetDateTime(ResultSet resultSet, int column) throws SQLException
|
||||||
|
{
|
||||||
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
|
if(resultSet.wasNull())
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
OffsetDateTime dateTime = OffsetDateTime.of(value.getYear() + NINETEEN_HUNDRED, value.getMonth() + 1, value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), 0, OffsetDateTime.now().getOffset());
|
||||||
|
return (dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1307,15 +1346,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Boolean getBoolean(ResultSet resultSet, String column) throws SQLException
|
public static Boolean getBoolean(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Boolean value = resultSet.getBoolean(column);
|
Boolean value = resultSet.getBoolean(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1325,15 +1361,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Boolean getBoolean(ResultSet resultSet, int column) throws SQLException
|
public static Boolean getBoolean(ResultSet resultSet, int column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Boolean value = resultSet.getBoolean(column);
|
Boolean value = resultSet.getBoolean(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1343,15 +1376,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Long getLong(ResultSet resultSet, int column) throws SQLException
|
public static Long getLong(ResultSet resultSet, int column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
long value = resultSet.getLong(column);
|
long value = resultSet.getLong(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1361,15 +1391,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Long getLong(ResultSet resultSet, String column) throws SQLException
|
public static Long getLong(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
long value = resultSet.getLong(column);
|
long value = resultSet.getLong(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1379,15 +1406,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Timestamp getTimestamp(ResultSet resultSet, int column) throws SQLException
|
public static Timestamp getTimestamp(ResultSet resultSet, int column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1397,15 +1421,12 @@ public class QueryManager
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static Timestamp getTimestamp(ResultSet resultSet, String column) throws SQLException
|
public static Timestamp getTimestamp(ResultSet resultSet, String column) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
Timestamp value = resultSet.getTimestamp(column);
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
if(resultSet.wasNull())
|
if(resultSet.wasNull())
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
return (value);
|
return (value);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1620,4 +1641,25 @@ public class QueryManager
|
|||||||
return statistics;
|
return statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Note - this changes a static field that impacts all usages. Really, it's meant
|
||||||
|
** to only be called in unit tests (at least as of the time of this writing).
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void setPageSize(int pageSize)
|
||||||
|
{
|
||||||
|
PAGE_SIZE = pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void resetPageSize()
|
||||||
|
{
|
||||||
|
PAGE_SIZE = DEFAULT_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms.jdbc;
|
package com.kingsrook.qqq.backend.module.rdbms.jdbc;
|
||||||
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
@ -31,199 +30,199 @@ import java.util.HashMap;
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class SimpleEntity extends HashMap<String, Object>
|
public class SimpleEntity extends HashMap<String, Object>
|
||||||
{
|
{
|
||||||
private String tableName;
|
// private String tableName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public SimpleEntity()
|
// public SimpleEntity()
|
||||||
{
|
// {
|
||||||
super();
|
// super();
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public SimpleEntity with(String key, Object value)
|
// public SimpleEntity with(String key, Object value)
|
||||||
{
|
// {
|
||||||
put(key, value);
|
// put(key, value);
|
||||||
return (this);
|
// return (this);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
** Return the current value of tableName
|
// ** Return the current value of tableName
|
||||||
**
|
// **
|
||||||
** @return tableName
|
// ** @return tableName
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public String getTableName()
|
// public String getTableName()
|
||||||
{
|
// {
|
||||||
return (tableName);
|
// return (tableName);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
** Set the current value of tableName
|
// ** Set the current value of tableName
|
||||||
**
|
// **
|
||||||
** @param tableName
|
// ** @param tableName
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public void setTableName(String tableName)
|
// public void setTableName(String tableName)
|
||||||
{
|
// {
|
||||||
this.tableName = tableName;
|
// this.tableName = tableName;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public SimpleEntity withTableName(String tableName)
|
// public SimpleEntity withTableName(String tableName)
|
||||||
{
|
// {
|
||||||
setTableName(tableName);
|
// setTableName(tableName);
|
||||||
return (this);
|
// return (this);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public Boolean getBoolean(String columnName)
|
// public Boolean getBoolean(String columnName)
|
||||||
{
|
// {
|
||||||
Object o = get(columnName);
|
// Object o = get(columnName);
|
||||||
if(o == null)
|
// if(o == null)
|
||||||
{
|
// {
|
||||||
return (null);
|
// return (null);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(o instanceof Boolean)
|
// if(o instanceof Boolean)
|
||||||
{
|
// {
|
||||||
return ((Boolean) o);
|
// return ((Boolean) o);
|
||||||
}
|
// }
|
||||||
else if(o instanceof Number)
|
// else if(o instanceof Number)
|
||||||
{
|
// {
|
||||||
int i = ((Number) o).intValue();
|
// int i = ((Number) o).intValue();
|
||||||
return (i != 0);
|
// return (i != 0);
|
||||||
}
|
// }
|
||||||
else if(o instanceof String)
|
// else if(o instanceof String)
|
||||||
{
|
// {
|
||||||
String s = (String) o;
|
// String s = (String) o;
|
||||||
return (s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t"));
|
// return (s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t"));
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
throw new IllegalArgumentException("Could not get value of object of type [" + o.getClass() + "] as Boolean.");
|
// throw new IllegalArgumentException("Could not get value of object of type [" + o.getClass() + "] as Boolean.");
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public String getString(String columnName)
|
// public String getString(String columnName)
|
||||||
{
|
// {
|
||||||
Object o = get(columnName);
|
// Object o = get(columnName);
|
||||||
if(o == null)
|
// if(o == null)
|
||||||
{
|
// {
|
||||||
return (null);
|
// return (null);
|
||||||
}
|
// }
|
||||||
if(o instanceof String)
|
// if(o instanceof String)
|
||||||
{
|
// {
|
||||||
return ((String) o);
|
// return ((String) o);
|
||||||
}
|
// }
|
||||||
else if(o instanceof byte[])
|
// else if(o instanceof byte[])
|
||||||
{
|
// {
|
||||||
return (new String((byte[]) o));
|
// return (new String((byte[]) o));
|
||||||
}
|
// }
|
||||||
|
|
||||||
return String.valueOf(o);
|
// return String.valueOf(o);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public Integer getInteger(String columnName)
|
// public Integer getInteger(String columnName)
|
||||||
{
|
// {
|
||||||
Object o = get(columnName);
|
// Object o = get(columnName);
|
||||||
if(o instanceof Long)
|
// if(o instanceof Long)
|
||||||
{
|
// {
|
||||||
return ((Long) o).intValue();
|
// return ((Long) o).intValue();
|
||||||
}
|
// }
|
||||||
else if(o instanceof Short)
|
// else if(o instanceof Short)
|
||||||
{
|
// {
|
||||||
return ((Short) o).intValue();
|
// return ((Short) o).intValue();
|
||||||
}
|
// }
|
||||||
else if(o instanceof String)
|
// else if(o instanceof String)
|
||||||
{
|
// {
|
||||||
return (Integer.parseInt((String) o));
|
// return (Integer.parseInt((String) o));
|
||||||
}
|
// }
|
||||||
|
|
||||||
return ((Integer) o);
|
// return ((Integer) o);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public BigDecimal getBigDecimal(String columnName)
|
// public BigDecimal getBigDecimal(String columnName)
|
||||||
{
|
// {
|
||||||
Object o = get(columnName);
|
// Object o = get(columnName);
|
||||||
if(o == null)
|
// if(o == null)
|
||||||
{
|
// {
|
||||||
return (null);
|
// return (null);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(o instanceof BigDecimal)
|
// if(o instanceof BigDecimal)
|
||||||
{
|
// {
|
||||||
return ((BigDecimal) o);
|
// return ((BigDecimal) o);
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
return new BigDecimal(String.valueOf(o));
|
// return new BigDecimal(String.valueOf(o));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public Long getLong(String columnName)
|
// public Long getLong(String columnName)
|
||||||
{
|
// {
|
||||||
Object o = get(columnName);
|
// Object o = get(columnName);
|
||||||
if(o instanceof Integer)
|
// if(o instanceof Integer)
|
||||||
{
|
// {
|
||||||
return ((Integer) o).longValue();
|
// return ((Integer) o).longValue();
|
||||||
}
|
// }
|
||||||
|
|
||||||
return ((Long) o);
|
// return ((Long) o);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
// /*******************************************************************************
|
||||||
**
|
// **
|
||||||
*******************************************************************************/
|
// *******************************************************************************/
|
||||||
public void trimStrings()
|
// public void trimStrings()
|
||||||
{
|
// {
|
||||||
for(String key : keySet())
|
// for(String key : keySet())
|
||||||
{
|
// {
|
||||||
Object value = get(key);
|
// Object value = get(key);
|
||||||
if(value != null && value instanceof String)
|
// if(value != null && value instanceof String)
|
||||||
{
|
// {
|
||||||
put(key, ((String) value).trim());
|
// put(key, ((String) value).trim());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms.model.metadata;
|
package com.kingsrook.qqq.backend.module.rdbms.model.metadata;
|
||||||
|
|
||||||
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QTableBackendDetails;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule;
|
import com.kingsrook.qqq.backend.module.rdbms.RDBMSBackendModule;
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms;
|
package com.kingsrook.qqq.backend.module.rdbms;
|
||||||
|
|
||||||
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
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.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
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.RDBMSTableBackendDetails;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
|
||||||
|
|
||||||
@ -36,6 +36,10 @@ import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDe
|
|||||||
public class TestUtils
|
public class TestUtils
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public static final String DEFAULT_BACKEND_NAME = "default";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -54,13 +58,12 @@ public class TestUtils
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static RDBMSBackendMetaData defineBackend()
|
public static RDBMSBackendMetaData defineBackend()
|
||||||
{
|
{
|
||||||
RDBMSBackendMetaData rdbmsBackendMetaData = new RDBMSBackendMetaData()
|
return (new RDBMSBackendMetaData()
|
||||||
|
.withName(DEFAULT_BACKEND_NAME)
|
||||||
.withVendor("h2")
|
.withVendor("h2")
|
||||||
.withHostName("mem")
|
.withHostName("mem")
|
||||||
.withDatabaseName("test_database")
|
.withDatabaseName("test_database")
|
||||||
.withUsername("sa");
|
.withUsername("sa"));
|
||||||
rdbmsBackendMetaData.setName("default");
|
|
||||||
return (rdbmsBackendMetaData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ 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.ConnectionManager;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import static junit.framework.Assert.assertNotNull;
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
|
||||||
|
|
||||||
@ -38,17 +39,39 @@ import static junit.framework.Assert.assertNotNull;
|
|||||||
public class RDBMSActionTest
|
public class RDBMSActionTest
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@AfterEach
|
||||||
|
private void afterEachRDBMSActionTest()
|
||||||
|
{
|
||||||
|
QueryManager.resetPageSize();
|
||||||
|
QueryManager.resetStatistics();
|
||||||
|
QueryManager.setCollectStatistics(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
protected void primeTestDatabase() throws Exception
|
||||||
|
{
|
||||||
|
primeTestDatabase("prime-test-database.sql");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void primeTestDatabase() throws Exception
|
protected void primeTestDatabase(String sqlFileName) throws Exception
|
||||||
{
|
{
|
||||||
ConnectionManager connectionManager = new ConnectionManager();
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
try(Connection connection = connectionManager.getConnection(TestUtils.defineBackend()))
|
try(Connection connection = connectionManager.getConnection(TestUtils.defineBackend()))
|
||||||
{
|
{
|
||||||
InputStream primeTestDatabaseSqlStream = RDBMSActionTest.class.getResourceAsStream("/prime-test-database.sql");
|
InputStream primeTestDatabaseSqlStream = RDBMSActionTest.class.getResourceAsStream("/" + sqlFileName);
|
||||||
assertNotNull(primeTestDatabaseSqlStream);
|
assertNotNull(primeTestDatabaseSqlStream);
|
||||||
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
||||||
lines = lines.stream().filter(line -> !line.startsWith("-- ")).toList();
|
lines = lines.stream().filter(line -> !line.startsWith("-- ")).toList();
|
||||||
|
@ -24,11 +24,11 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.count.CountRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.count.CountResult;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -58,9 +58,9 @@ public class RDBMSCountActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUnfilteredCount() throws QException
|
public void testUnfilteredCount() throws QException
|
||||||
{
|
{
|
||||||
CountRequest countRequest = initCountRequest();
|
CountInput countInput = initCountRequest();
|
||||||
CountResult countResult = new RDBMSCountAction().execute(countRequest);
|
CountOutput countOutput = new RDBMSCountAction().execute(countInput);
|
||||||
Assertions.assertEquals(5, countResult.getCount(), "Unfiltered query should find all rows");
|
Assertions.assertEquals(5, countOutput.getCount(), "Unfiltered query should find all rows");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,15 +73,15 @@ public class RDBMSCountActionTest extends RDBMSActionTest
|
|||||||
{
|
{
|
||||||
String email = "darin.kelkhoff@gmail.com";
|
String email = "darin.kelkhoff@gmail.com";
|
||||||
|
|
||||||
CountRequest countRequest = initCountRequest();
|
CountInput countInput = initCountRequest();
|
||||||
countRequest.setFilter(new QQueryFilter()
|
countInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.EQUALS)
|
.withOperator(QCriteriaOperator.EQUALS)
|
||||||
.withValues(List.of(email)))
|
.withValues(List.of(email)))
|
||||||
);
|
);
|
||||||
CountResult countResult = new RDBMSCountAction().execute(countRequest);
|
CountOutput countOutput = new RDBMSCountAction().execute(countInput);
|
||||||
Assertions.assertEquals(1, countResult.getCount(), "Expected # of rows");
|
Assertions.assertEquals(1, countOutput.getCount(), "Expected # of rows");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -94,15 +94,15 @@ public class RDBMSCountActionTest extends RDBMSActionTest
|
|||||||
{
|
{
|
||||||
String email = "darin.kelkhoff@gmail.com";
|
String email = "darin.kelkhoff@gmail.com";
|
||||||
|
|
||||||
CountRequest countRequest = initCountRequest();
|
CountInput countInput = initCountRequest();
|
||||||
countRequest.setFilter(new QQueryFilter()
|
countInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.NOT_EQUALS)
|
.withOperator(QCriteriaOperator.NOT_EQUALS)
|
||||||
.withValues(List.of(email)))
|
.withValues(List.of(email)))
|
||||||
);
|
);
|
||||||
CountResult countResult = new RDBMSCountAction().execute(countRequest);
|
CountOutput countOutput = new RDBMSCountAction().execute(countInput);
|
||||||
Assertions.assertEquals(4, countResult.getCount(), "Expected # of rows");
|
Assertions.assertEquals(4, countOutput.getCount(), "Expected # of rows");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -110,12 +110,12 @@ public class RDBMSCountActionTest extends RDBMSActionTest
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private CountRequest initCountRequest()
|
private CountInput initCountRequest()
|
||||||
{
|
{
|
||||||
CountRequest countRequest = new CountRequest();
|
CountInput countInput = new CountInput();
|
||||||
countRequest.setInstance(TestUtils.defineInstance());
|
countInput.setInstance(TestUtils.defineInstance());
|
||||||
countRequest.setTableName(TestUtils.defineTablePerson().getName());
|
countInput.setTableName(TestUtils.defineTablePerson().getName());
|
||||||
return countRequest;
|
return countInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -23,9 +23,16 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.delete.DeleteRequest;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.delete.DeleteResult;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
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.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 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;
|
||||||
@ -56,11 +63,11 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteAll() throws Exception
|
public void testDeleteAll() throws Exception
|
||||||
{
|
{
|
||||||
DeleteRequest deleteRequest = initDeleteRequest();
|
DeleteInput deleteInput = initStandardPersonDeleteRequest();
|
||||||
deleteRequest.setPrimaryKeys(List.of(1, 2, 3, 4, 5));
|
deleteInput.setPrimaryKeys(List.of(1, 2, 3, 4, 5));
|
||||||
DeleteResult deleteResult = new RDBMSDeleteAction().execute(deleteRequest);
|
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
|
||||||
assertEquals(5, deleteResult.getRecords().size(), "Unfiltered delete should return all rows");
|
assertEquals(5, deleteResult.getDeletedRecordCount(), "Unfiltered delete should return all rows");
|
||||||
// todo - add errors to QRecord? assertTrue(deleteResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
|
assertEquals(0, deleteResult.getRecordsWithErrors().size(), "should have no errors");
|
||||||
runTestSql("SELECT id FROM person", (rs -> assertFalse(rs.next())));
|
runTestSql("SELECT id FROM person", (rs -> assertFalse(rs.next())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,11 +79,11 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteOne() throws Exception
|
public void testDeleteOne() throws Exception
|
||||||
{
|
{
|
||||||
DeleteRequest deleteRequest = initDeleteRequest();
|
DeleteInput deleteInput = initStandardPersonDeleteRequest();
|
||||||
deleteRequest.setPrimaryKeys(List.of(1));
|
deleteInput.setPrimaryKeys(List.of(1));
|
||||||
DeleteResult deleteResult = new RDBMSDeleteAction().execute(deleteRequest);
|
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
|
||||||
assertEquals(1, deleteResult.getRecords().size(), "Should delete one row");
|
assertEquals(1, deleteResult.getDeletedRecordCount(), "Should delete one row");
|
||||||
// todo - add errors to QRecord? assertTrue(deleteResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
|
assertEquals(0, deleteResult.getRecordsWithErrors().size(), "should have no errors");
|
||||||
runTestSql("SELECT id FROM person WHERE id = 1", (rs -> assertFalse(rs.next())));
|
runTestSql("SELECT id FROM person WHERE id = 1", (rs -> assertFalse(rs.next())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,11 +95,11 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteSome() throws Exception
|
public void testDeleteSome() throws Exception
|
||||||
{
|
{
|
||||||
DeleteRequest deleteRequest = initDeleteRequest();
|
DeleteInput deleteInput = initStandardPersonDeleteRequest();
|
||||||
deleteRequest.setPrimaryKeys(List.of(1, 3, 5));
|
deleteInput.setPrimaryKeys(List.of(1, 3, 5));
|
||||||
DeleteResult deleteResult = new RDBMSDeleteAction().execute(deleteRequest);
|
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
|
||||||
assertEquals(3, deleteResult.getRecords().size(), "Should delete one row");
|
assertEquals(3, deleteResult.getDeletedRecordCount(), "Should delete one row");
|
||||||
// todo - add errors to QRecord? assertTrue(deleteResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
|
assertEquals(0, deleteResult.getRecordsWithErrors().size(), "should have no errors");
|
||||||
runTestSql("SELECT id FROM person", (rs -> {
|
runTestSql("SELECT id FROM person", (rs -> {
|
||||||
int rowsFound = 0;
|
int rowsFound = 0;
|
||||||
while(rs.next())
|
while(rs.next())
|
||||||
@ -110,12 +117,110 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private DeleteRequest initDeleteRequest()
|
@Test
|
||||||
|
void testDeleteSomeIdsThatExistAndSomeThatDoNot() throws Exception
|
||||||
{
|
{
|
||||||
DeleteRequest deleteRequest = new DeleteRequest();
|
DeleteInput deleteInput = initStandardPersonDeleteRequest();
|
||||||
deleteRequest.setInstance(TestUtils.defineInstance());
|
deleteInput.setPrimaryKeys(List.of(1, -1));
|
||||||
deleteRequest.setTableName(TestUtils.defineTablePerson().getName());
|
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
|
||||||
return deleteRequest;
|
assertEquals(1, deleteResult.getDeletedRecordCount(), "Should delete one row");
|
||||||
|
assertEquals(0, deleteResult.getRecordsWithErrors().size(), "should have no errors (the one not found is just noop)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private DeleteInput initStandardPersonDeleteRequest()
|
||||||
|
{
|
||||||
|
DeleteInput deleteInput = new DeleteInput();
|
||||||
|
deleteInput.setInstance(TestUtils.defineInstance());
|
||||||
|
deleteInput.setTableName(TestUtils.defineTablePerson().getName());
|
||||||
|
return deleteInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testDeleteWhereForeignKeyBlocksSome() throws Exception
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// load the parent-child tables, with foreign keys and instance //
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
super.primeTestDatabase("prime-test-database-parent-child-tables.sql");
|
||||||
|
DeleteInput deleteInput = initChildTableInstanceAndDeleteRequest();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// try to delete all of the child records - 2 should fail, because they are referenced by parent_table.child_id //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
deleteInput.setPrimaryKeys(List.of(1, 2, 3, 4, 5));
|
||||||
|
|
||||||
|
QueryManager.setCollectStatistics(true);
|
||||||
|
QueryManager.resetStatistics();
|
||||||
|
|
||||||
|
DeleteOutput deleteResult = new RDBMSDeleteAction().execute(deleteInput);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// assert that 6 queries ran - the initial delete (which failed), then 6 more //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QueryManager.setCollectStatistics(false);
|
||||||
|
Map<String, Integer> queryStats = QueryManager.getStatistics();
|
||||||
|
assertEquals(6, queryStats.get(QueryManager.STAT_QUERIES_RAN), "Number of queries ran");
|
||||||
|
|
||||||
|
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");
|
||||||
|
assertEquals(3, deleteResult.getDeletedRecordCount(), "Should get back that 3 were deleted");
|
||||||
|
|
||||||
|
runTestSql("SELECT id FROM child_table", (rs -> {
|
||||||
|
int rowsFound = 0;
|
||||||
|
while(rs.next())
|
||||||
|
{
|
||||||
|
rowsFound++;
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// child_table rows 1 & 3 should survive //
|
||||||
|
///////////////////////////////////////////
|
||||||
|
assertTrue(rs.getInt(1) == 1 || rs.getInt(1) == 3);
|
||||||
|
}
|
||||||
|
assertEquals(2, rowsFound);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private DeleteInput initChildTableInstanceAndDeleteRequest()
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
|
||||||
|
String childTableName = "childTable";
|
||||||
|
qInstance.addTable(new QTableMetaData()
|
||||||
|
.withName(childTableName)
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||||
|
.withBackendDetails(new RDBMSTableBackendDetails()
|
||||||
|
.withTableName("child_table")));
|
||||||
|
|
||||||
|
qInstance.addTable(new QTableMetaData()
|
||||||
|
.withName("parentTable")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("name", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("childId", QFieldType.INTEGER).withBackendName("child_id"))
|
||||||
|
.withBackendDetails(new RDBMSTableBackendDetails()
|
||||||
|
.withTableName("parent_table")));
|
||||||
|
|
||||||
|
DeleteInput deleteInput = new DeleteInput();
|
||||||
|
deleteInput.setInstance(qInstance);
|
||||||
|
deleteInput.setTableName(childTableName);
|
||||||
|
return deleteInput;
|
||||||
|
}
|
||||||
}
|
}
|
@ -25,10 +25,11 @@ 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 com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.insert.InsertRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.insert.InsertResult;
|
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 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;
|
||||||
@ -58,10 +59,10 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testInsertNullList() throws QException
|
public void testInsertNullList() throws QException
|
||||||
{
|
{
|
||||||
InsertRequest insertRequest = initInsertRequest();
|
InsertInput insertInput = initInsertRequest();
|
||||||
insertRequest.setRecords(null);
|
insertInput.setRecords(null);
|
||||||
InsertResult insertResult = new RDBMSInsertAction().execute(insertRequest);
|
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
|
||||||
assertEquals(0, insertResult.getRecords().size());
|
assertEquals(0, insertOutput.getRecords().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,10 +73,10 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testInsertEmptyList() throws QException
|
public void testInsertEmptyList() throws QException
|
||||||
{
|
{
|
||||||
InsertRequest insertRequest = initInsertRequest();
|
InsertInput insertInput = initInsertRequest();
|
||||||
insertRequest.setRecords(Collections.emptyList());
|
insertInput.setRecords(Collections.emptyList());
|
||||||
InsertResult insertResult = new RDBMSInsertAction().execute(insertRequest);
|
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
|
||||||
assertEquals(0, insertResult.getRecords().size());
|
assertEquals(0, insertOutput.getRecords().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -86,28 +87,18 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testInsertOne() throws Exception
|
public void testInsertOne() throws Exception
|
||||||
{
|
{
|
||||||
InsertRequest insertRequest = initInsertRequest();
|
InsertInput insertInput = initInsertRequest();
|
||||||
QRecord record = new QRecord().withTableName("person")
|
QRecord record = new QRecord().withTableName("person")
|
||||||
.withValue("firstName", "James")
|
.withValue("firstName", "James")
|
||||||
.withValue("lastName", "Kirk")
|
.withValue("lastName", "Kirk")
|
||||||
.withValue("email", "jamestk@starfleet.net")
|
.withValue("email", "jamestk@starfleet.net")
|
||||||
.withValue("birthDate", "2210-05-20");
|
.withValue("birthDate", "2210-05-20");
|
||||||
insertRequest.setRecords(List.of(record));
|
insertInput.setRecords(List.of(record));
|
||||||
InsertResult insertResult = new RDBMSInsertAction().execute(insertRequest);
|
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
|
||||||
assertEquals(1, insertResult.getRecords().size(), "Should return 1 row");
|
assertEquals(1, insertOutput.getRecords().size(), "Should return 1 row");
|
||||||
assertNotNull(insertResult.getRecords().get(0).getValue("id"), "Should have an id in the row");
|
assertNotNull(insertOutput.getRecords().get(0).getValue("id"), "Should have an id in the row");
|
||||||
// todo - add errors to QRecord? assertTrue(insertResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
|
// todo - add errors to QRecord? assertTrue(insertResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
|
||||||
runTestSql("SELECT * FROM person WHERE last_name = 'Kirk'", (rs -> {
|
assertAnInsertedPersonRecord("James", "Kirk", 6);
|
||||||
int rowsFound = 0;
|
|
||||||
while(rs.next())
|
|
||||||
{
|
|
||||||
rowsFound++;
|
|
||||||
assertEquals(6, rs.getInt("id"));
|
|
||||||
assertEquals("James", rs.getString("first_name"));
|
|
||||||
assertNotNull(rs.getString("create_date"));
|
|
||||||
}
|
|
||||||
assertEquals(1, rowsFound);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -118,7 +109,9 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testInsertMany() throws Exception
|
public void testInsertMany() throws Exception
|
||||||
{
|
{
|
||||||
InsertRequest insertRequest = initInsertRequest();
|
QueryManager.setPageSize(2);
|
||||||
|
|
||||||
|
InsertInput insertInput = initInsertRequest();
|
||||||
QRecord record1 = new QRecord().withTableName("person")
|
QRecord record1 = new QRecord().withTableName("person")
|
||||||
.withValue("firstName", "Jean-Luc")
|
.withValue("firstName", "Jean-Luc")
|
||||||
.withValue("lastName", "Picard")
|
.withValue("lastName", "Picard")
|
||||||
@ -129,29 +122,35 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
|
|||||||
.withValue("lastName", "Riker")
|
.withValue("lastName", "Riker")
|
||||||
.withValue("email", "notthomas@starfleet.net")
|
.withValue("email", "notthomas@starfleet.net")
|
||||||
.withValue("birthDate", "2320-05-20");
|
.withValue("birthDate", "2320-05-20");
|
||||||
insertRequest.setRecords(List.of(record1, record2));
|
QRecord record3 = new QRecord().withTableName("person")
|
||||||
InsertResult insertResult = new RDBMSInsertAction().execute(insertRequest);
|
.withValue("firstName", "Beverly")
|
||||||
assertEquals(2, insertResult.getRecords().size(), "Should return 1 row");
|
.withValue("lastName", "Crusher")
|
||||||
assertEquals(6, insertResult.getRecords().get(0).getValue("id"), "Should have next id in the row");
|
.withValue("email", "doctor@starfleet.net")
|
||||||
assertEquals(7, insertResult.getRecords().get(1).getValue("id"), "Should have next id in the row");
|
.withValue("birthDate", "2320-06-26");
|
||||||
// todo - add errors to QRecord? assertTrue(insertResult.getRecords().stream().noneMatch(qrs -> CollectionUtils.nullSafeHasContents(qrs.getErrors())), "There should be no errors");
|
insertInput.setRecords(List.of(record1, record2, record3));
|
||||||
runTestSql("SELECT * FROM person WHERE last_name = 'Picard'", (rs -> {
|
InsertOutput insertOutput = new RDBMSInsertAction().execute(insertInput);
|
||||||
int rowsFound = 0;
|
assertEquals(3, insertOutput.getRecords().size(), "Should return right # of rows");
|
||||||
while(rs.next())
|
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");
|
||||||
rowsFound++;
|
assertEquals(8, insertOutput.getRecords().get(2).getValue("id"), "Should have next id in the row");
|
||||||
assertEquals(6, rs.getInt("id"));
|
assertAnInsertedPersonRecord("Jean-Luc", "Picard", 6);
|
||||||
assertEquals("Jean-Luc", rs.getString("first_name"));
|
assertAnInsertedPersonRecord("William", "Riker", 7);
|
||||||
|
assertAnInsertedPersonRecord("Beverly", "Crusher", 8);
|
||||||
}
|
}
|
||||||
assertEquals(1, rowsFound);
|
|
||||||
}));
|
|
||||||
runTestSql("SELECT * FROM person WHERE last_name = 'Riker'", (rs -> {
|
|
||||||
|
private void assertAnInsertedPersonRecord(String firstName, String lastName, Integer id) throws Exception
|
||||||
|
{
|
||||||
|
runTestSql("SELECT * FROM person WHERE last_name = '" + lastName + "'", (rs -> {
|
||||||
int rowsFound = 0;
|
int rowsFound = 0;
|
||||||
while(rs.next())
|
while(rs.next())
|
||||||
{
|
{
|
||||||
rowsFound++;
|
rowsFound++;
|
||||||
assertEquals(7, rs.getInt("id"));
|
assertEquals(id, rs.getInt("id"));
|
||||||
assertEquals("William", rs.getString("first_name"));
|
assertEquals(firstName, rs.getString("first_name"));
|
||||||
|
assertNotNull(rs.getString("create_date"));
|
||||||
|
assertNotNull(rs.getString("modify_date"));
|
||||||
}
|
}
|
||||||
assertEquals(1, rowsFound);
|
assertEquals(1, rowsFound);
|
||||||
}));
|
}));
|
||||||
@ -162,12 +161,12 @@ public class RDBMSInsertActionTest extends RDBMSActionTest
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private InsertRequest initInsertRequest()
|
private InsertInput initInsertRequest()
|
||||||
{
|
{
|
||||||
InsertRequest insertRequest = new InsertRequest();
|
InsertInput insertInput = new InsertInput();
|
||||||
insertRequest.setInstance(TestUtils.defineInstance());
|
insertInput.setInstance(TestUtils.defineInstance());
|
||||||
insertRequest.setTableName(TestUtils.defineTablePerson().getName());
|
insertInput.setTableName(TestUtils.defineTablePerson().getName());
|
||||||
return insertRequest;
|
return insertInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -24,11 +24,11 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QueryRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -58,9 +58,9 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUnfilteredQuery() throws QException
|
public void testUnfilteredQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(5, queryResult.getRecords().size(), "Unfiltered query should find all rows");
|
Assertions.assertEquals(5, queryOutput.getRecords().size(), "Unfiltered query should find all rows");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,16 +73,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
{
|
{
|
||||||
String email = "darin.kelkhoff@gmail.com";
|
String email = "darin.kelkhoff@gmail.com";
|
||||||
|
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.EQUALS)
|
.withOperator(QCriteriaOperator.EQUALS)
|
||||||
.withValues(List.of(email)))
|
.withValues(List.of(email)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(1, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(1, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertEquals(email, queryResult.getRecords().get(0).getValueString("email"), "Should find expected email address");
|
Assertions.assertEquals(email, queryOutput.getRecords().get(0).getValueString("email"), "Should find expected email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -95,16 +95,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
{
|
{
|
||||||
String email = "darin.kelkhoff@gmail.com";
|
String email = "darin.kelkhoff@gmail.com";
|
||||||
|
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.NOT_EQUALS)
|
.withOperator(QCriteriaOperator.NOT_EQUALS)
|
||||||
.withValues(List.of(email)))
|
.withValues(List.of(email)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(4, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(4, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().noneMatch(r -> r.getValueString("email").equals(email)), "Should NOT find expected email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().noneMatch(r -> r.getValueString("email").equals(email)), "Should NOT find expected email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -115,16 +115,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testInQuery() throws QException
|
public void testInQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.IN)
|
.withOperator(QCriteriaOperator.IN)
|
||||||
.withValues(List.of(2, 4)))
|
.withValues(List.of(2, 4)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(2) || r.getValueInteger("id").equals(4)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(2) || r.getValueInteger("id").equals(4)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -135,16 +135,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testNotInQuery() throws QException
|
public void testNotInQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.NOT_IN)
|
.withOperator(QCriteriaOperator.NOT_IN)
|
||||||
.withValues(List.of(2, 3, 4)))
|
.withValues(List.of(2, 3, 4)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -155,16 +155,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testStartsWith() throws QException
|
public void testStartsWith() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.STARTS_WITH)
|
.withOperator(QCriteriaOperator.STARTS_WITH)
|
||||||
.withValues(List.of("darin")))
|
.withValues(List.of("darin")))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(1, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(1, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueString("email").matches("darin.*")), "Should find matching email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueString("email").matches("darin.*")), "Should find matching email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -175,16 +175,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testContains() throws QException
|
public void testContains() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.CONTAINS)
|
.withOperator(QCriteriaOperator.CONTAINS)
|
||||||
.withValues(List.of("kelkhoff")))
|
.withValues(List.of("kelkhoff")))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(1, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(1, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueString("email").matches(".*kelkhoff.*")), "Should find matching email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueString("email").matches(".*kelkhoff.*")), "Should find matching email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -195,16 +195,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testEndsWith() throws QException
|
public void testEndsWith() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.ENDS_WITH)
|
.withOperator(QCriteriaOperator.ENDS_WITH)
|
||||||
.withValues(List.of("gmail.com")))
|
.withValues(List.of("gmail.com")))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(1, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(1, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueString("email").matches(".*gmail.com")), "Should find matching email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueString("email").matches(".*gmail.com")), "Should find matching email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -215,16 +215,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testNotStartsWith() throws QException
|
public void testNotStartsWith() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.NOT_STARTS_WITH)
|
.withOperator(QCriteriaOperator.NOT_STARTS_WITH)
|
||||||
.withValues(List.of("darin")))
|
.withValues(List.of("darin")))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(4, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(4, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().noneMatch(r -> r.getValueString("email").matches("darin.*")), "Should find matching email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().noneMatch(r -> r.getValueString("email").matches("darin.*")), "Should find matching email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,16 +235,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testNotContains() throws QException
|
public void testNotContains() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.NOT_CONTAINS)
|
.withOperator(QCriteriaOperator.NOT_CONTAINS)
|
||||||
.withValues(List.of("kelkhoff")))
|
.withValues(List.of("kelkhoff")))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(4, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(4, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().noneMatch(r -> r.getValueString("email").matches(".*kelkhoff.*")), "Should find matching email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().noneMatch(r -> r.getValueString("email").matches(".*kelkhoff.*")), "Should find matching email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -255,16 +255,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testNotEndsWith() throws QException
|
public void testNotEndsWith() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("email")
|
.withFieldName("email")
|
||||||
.withOperator(QCriteriaOperator.NOT_ENDS_WITH)
|
.withOperator(QCriteriaOperator.NOT_ENDS_WITH)
|
||||||
.withValues(List.of("gmail.com")))
|
.withValues(List.of("gmail.com")))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(4, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(4, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().noneMatch(r -> r.getValueString("email").matches(".*gmail.com")), "Should find matching email address");
|
Assertions.assertTrue(queryOutput.getRecords().stream().noneMatch(r -> r.getValueString("email").matches(".*gmail.com")), "Should find matching email address");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -275,16 +275,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testLessThanQuery() throws QException
|
public void testLessThanQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.LESS_THAN)
|
.withOperator(QCriteriaOperator.LESS_THAN)
|
||||||
.withValues(List.of(3)))
|
.withValues(List.of(3)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(2)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(2)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -295,16 +295,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testLessThanOrEqualsQuery() throws QException
|
public void testLessThanOrEqualsQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.LESS_THAN_OR_EQUALS)
|
.withOperator(QCriteriaOperator.LESS_THAN_OR_EQUALS)
|
||||||
.withValues(List.of(2)))
|
.withValues(List.of(2)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(2)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(2)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -315,16 +315,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testGreaterThanQuery() throws QException
|
public void testGreaterThanQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.GREATER_THAN)
|
.withOperator(QCriteriaOperator.GREATER_THAN)
|
||||||
.withValues(List.of(3)))
|
.withValues(List.of(3)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(4) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(4) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -335,16 +335,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testGreaterThanOrEqualsQuery() throws QException
|
public void testGreaterThanOrEqualsQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.GREATER_THAN_OR_EQUALS)
|
.withOperator(QCriteriaOperator.GREATER_THAN_OR_EQUALS)
|
||||||
.withValues(List.of(4)))
|
.withValues(List.of(4)))
|
||||||
);
|
);
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(4) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(4) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -355,15 +355,15 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testIsBlankQuery() throws QException
|
public void testIsBlankQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("birthDate")
|
.withFieldName("birthDate")
|
||||||
.withOperator(QCriteriaOperator.IS_BLANK)
|
.withOperator(QCriteriaOperator.IS_BLANK)
|
||||||
));
|
));
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(1, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(1, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValue("birthDate") == null), "Should find expected row");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValue("birthDate") == null), "Should find expected row");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -374,16 +374,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testBetweenQuery() throws QException
|
public void testBetweenQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.BETWEEN)
|
.withOperator(QCriteriaOperator.BETWEEN)
|
||||||
.withValues(List.of(2, 4))
|
.withValues(List.of(2, 4))
|
||||||
));
|
));
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(3, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(3, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(2) || r.getValueInteger("id").equals(3) || r.getValueInteger("id").equals(4)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(2) || r.getValueInteger("id").equals(3) || r.getValueInteger("id").equals(4)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -394,16 +394,16 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testNotBetweenQuery() throws QException
|
public void testNotBetweenQuery() throws QException
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = initQueryRequest();
|
QueryInput queryInput = initQueryRequest();
|
||||||
queryRequest.setFilter(new QQueryFilter()
|
queryInput.setFilter(new QQueryFilter()
|
||||||
.withCriteria(new QFilterCriteria()
|
.withCriteria(new QFilterCriteria()
|
||||||
.withFieldName("id")
|
.withFieldName("id")
|
||||||
.withOperator(QCriteriaOperator.NOT_BETWEEN)
|
.withOperator(QCriteriaOperator.NOT_BETWEEN)
|
||||||
.withValues(List.of(2, 4))
|
.withValues(List.of(2, 4))
|
||||||
));
|
));
|
||||||
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
QueryOutput queryOutput = new RDBMSQueryAction().execute(queryInput);
|
||||||
Assertions.assertEquals(2, queryResult.getRecords().size(), "Expected # of rows");
|
Assertions.assertEquals(2, queryOutput.getRecords().size(), "Expected # of rows");
|
||||||
Assertions.assertTrue(queryResult.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
Assertions.assertTrue(queryOutput.getRecords().stream().allMatch(r -> r.getValueInteger("id").equals(1) || r.getValueInteger("id").equals(5)), "Should find expected ids");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -411,12 +411,12 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private QueryRequest initQueryRequest()
|
private QueryInput initQueryRequest()
|
||||||
{
|
{
|
||||||
QueryRequest queryRequest = new QueryRequest();
|
QueryInput queryInput = new QueryInput();
|
||||||
queryRequest.setInstance(TestUtils.defineInstance());
|
queryInput.setInstance(TestUtils.defineInstance());
|
||||||
queryRequest.setTableName(TestUtils.defineTablePerson().getName());
|
queryInput.setTableName(TestUtils.defineTablePerson().getName());
|
||||||
return queryRequest;
|
return queryInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -27,16 +27,18 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult;
|
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.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.jdbc.QueryManager;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
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;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
|
||||||
@ -59,17 +61,6 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
@AfterEach
|
|
||||||
public void afterEach() throws Exception
|
|
||||||
{
|
|
||||||
QueryManager.resetStatistics();
|
|
||||||
QueryManager.setCollectStatistics(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
@ -77,9 +68,9 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateNullList() throws QException
|
public void testUpdateNullList() throws QException
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = initUpdateRequest();
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
updateRequest.setRecords(null);
|
updateInput.setRecords(null);
|
||||||
UpdateResult updateResult = new RDBMSUpdateAction().execute(updateRequest);
|
UpdateOutput updateResult = new RDBMSUpdateAction().execute(updateInput);
|
||||||
assertEquals(0, updateResult.getRecords().size());
|
assertEquals(0, updateResult.getRecords().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,10 +82,10 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateEmptyList() throws QException
|
public void testUpdateEmptyList() throws QException
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = initUpdateRequest();
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
updateRequest.setRecords(Collections.emptyList());
|
updateInput.setRecords(Collections.emptyList());
|
||||||
new RDBMSUpdateAction().execute(updateRequest);
|
new RDBMSUpdateAction().execute(updateInput);
|
||||||
UpdateResult updateResult = new RDBMSUpdateAction().execute(updateRequest);
|
UpdateOutput updateResult = new RDBMSUpdateAction().execute(updateInput);
|
||||||
assertEquals(0, updateResult.getRecords().size());
|
assertEquals(0, updateResult.getRecords().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,16 +97,16 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateOne() throws Exception
|
public void testUpdateOne() throws Exception
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = initUpdateRequest();
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
QRecord record = new QRecord().withTableName("person")
|
QRecord record = new QRecord().withTableName("person")
|
||||||
.withValue("id", 2)
|
.withValue("id", 2)
|
||||||
.withValue("firstName", "James")
|
.withValue("firstName", "James")
|
||||||
.withValue("lastName", "Kirk")
|
.withValue("lastName", "Kirk")
|
||||||
.withValue("email", "jamestk@starfleet.net")
|
.withValue("email", "jamestk@starfleet.net")
|
||||||
.withValue("birthDate", "2210-05-20");
|
.withValue("birthDate", "2210-05-20");
|
||||||
updateRequest.setRecords(List.of(record));
|
updateInput.setRecords(List.of(record));
|
||||||
|
|
||||||
UpdateResult updateResult = new RDBMSUpdateAction().execute(updateRequest);
|
UpdateOutput updateResult = new RDBMSUpdateAction().execute(updateInput);
|
||||||
Map<String, Integer> statistics = QueryManager.getStatistics();
|
Map<String, Integer> statistics = QueryManager.getStatistics();
|
||||||
assertEquals(1, statistics.get(QueryManager.STAT_QUERIES_RAN));
|
assertEquals(1, statistics.get(QueryManager.STAT_QUERIES_RAN));
|
||||||
|
|
||||||
@ -149,7 +140,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateManyWithDifferentColumnsAndValues() throws Exception
|
public void testUpdateManyWithDifferentColumnsAndValues() throws Exception
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = initUpdateRequest();
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
QRecord record1 = new QRecord().withTableName("person")
|
QRecord record1 = new QRecord().withTableName("person")
|
||||||
.withValue("id", 1)
|
.withValue("id", 1)
|
||||||
.withValue("firstName", "Darren")
|
.withValue("firstName", "Darren")
|
||||||
@ -166,9 +157,9 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
.withValue("firstName", "Richard")
|
.withValue("firstName", "Richard")
|
||||||
.withValue("birthDate", null);
|
.withValue("birthDate", null);
|
||||||
|
|
||||||
updateRequest.setRecords(List.of(record1, record2, record3));
|
updateInput.setRecords(List.of(record1, record2, record3));
|
||||||
|
|
||||||
UpdateResult updateResult = new RDBMSUpdateAction().execute(updateRequest);
|
UpdateOutput updateResult = new RDBMSUpdateAction().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 = QueryManager.getStatistics();
|
||||||
@ -224,7 +215,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateManyWithSameColumnsDifferentValues() throws Exception
|
public void testUpdateManyWithSameColumnsDifferentValues() throws Exception
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = initUpdateRequest();
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
QRecord record1 = new QRecord().withTableName("person")
|
QRecord record1 = new QRecord().withTableName("person")
|
||||||
.withValue("id", 1)
|
.withValue("id", 1)
|
||||||
.withValue("firstName", "Darren")
|
.withValue("firstName", "Darren")
|
||||||
@ -237,9 +228,9 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
.withValue("lastName", "Tim's Uncle")
|
.withValue("lastName", "Tim's Uncle")
|
||||||
.withValue("birthDate", null);
|
.withValue("birthDate", null);
|
||||||
|
|
||||||
updateRequest.setRecords(List.of(record1, record2));
|
updateInput.setRecords(List.of(record1, record2));
|
||||||
|
|
||||||
UpdateResult updateResult = new RDBMSUpdateAction().execute(updateRequest);
|
UpdateOutput updateResult = new RDBMSUpdateAction().execute(updateInput);
|
||||||
Map<String, Integer> statistics = QueryManager.getStatistics();
|
Map<String, Integer> statistics = QueryManager.getStatistics();
|
||||||
assertEquals(1, statistics.get(QueryManager.STAT_BATCHES_RAN));
|
assertEquals(1, statistics.get(QueryManager.STAT_BATCHES_RAN));
|
||||||
|
|
||||||
@ -281,7 +272,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
@Test
|
@Test
|
||||||
public void testUpdateManyWithSameColumnsSameValues() throws Exception
|
public void testUpdateManyWithSameColumnsSameValues() throws Exception
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = initUpdateRequest();
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
List<QRecord> records = new ArrayList<>();
|
List<QRecord> records = new ArrayList<>();
|
||||||
for(int i = 1; i <= 5; i++)
|
for(int i = 1; i <= 5; i++)
|
||||||
{
|
{
|
||||||
@ -290,9 +281,9 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
.withValue("birthDate", "1999-09-09"));
|
.withValue("birthDate", "1999-09-09"));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRequest.setRecords(records);
|
updateInput.setRecords(records);
|
||||||
|
|
||||||
UpdateResult updateResult = new RDBMSUpdateAction().execute(updateRequest);
|
UpdateOutput updateResult = new RDBMSUpdateAction().execute(updateInput);
|
||||||
Map<String, Integer> statistics = QueryManager.getStatistics();
|
Map<String, Integer> statistics = QueryManager.getStatistics();
|
||||||
assertEquals(1, statistics.get(QueryManager.STAT_QUERIES_RAN));
|
assertEquals(1, statistics.get(QueryManager.STAT_QUERIES_RAN));
|
||||||
|
|
||||||
@ -314,12 +305,54 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private UpdateRequest initUpdateRequest()
|
@Test
|
||||||
|
void testModifyDateGetsUpdated() throws Exception
|
||||||
{
|
{
|
||||||
UpdateRequest updateRequest = new UpdateRequest();
|
String originalModifyDate = selectModifyDate(1);
|
||||||
updateRequest.setInstance(TestUtils.defineInstance());
|
|
||||||
updateRequest.setTableName(TestUtils.defineTablePerson().getName());
|
UpdateInput updateInput = initUpdateRequest();
|
||||||
return updateRequest;
|
List<QRecord> records = new ArrayList<>();
|
||||||
|
records.add(new QRecord().withTableName("person")
|
||||||
|
.withValue("id", 1)
|
||||||
|
.withValue("firstName", "Johnny Updated"));
|
||||||
|
updateInput.setRecords(records);
|
||||||
|
new RDBMSUpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
String updatedModifyDate = selectModifyDate(1);
|
||||||
|
|
||||||
|
assertTrue(StringUtils.hasContent(originalModifyDate));
|
||||||
|
assertTrue(StringUtils.hasContent(updatedModifyDate));
|
||||||
|
assertNotEquals(originalModifyDate, updatedModifyDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String selectModifyDate(Integer id) throws Exception
|
||||||
|
{
|
||||||
|
StringBuilder modifyDate = new StringBuilder();
|
||||||
|
runTestSql("SELECT modify_date FROM person WHERE id = " + id, (rs -> {
|
||||||
|
if(rs.next())
|
||||||
|
{
|
||||||
|
modifyDate.append(rs.getString("modify_date"));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return (modifyDate.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private UpdateInput initUpdateRequest()
|
||||||
|
{
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setInstance(TestUtils.defineInstance());
|
||||||
|
updateInput.setTableName(TestUtils.defineTablePerson().getName());
|
||||||
|
return updateInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.jdbc;
|
||||||
|
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.Date;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.Month;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
class QueryManagerTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
void beforeEach() throws SQLException
|
||||||
|
{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
QueryManager.executeUpdate(connection, "CREATE TABLE t (i INTEGER, dt DATETIME, c CHAR(1), d DATE)");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@AfterEach
|
||||||
|
void afterEach() throws SQLException
|
||||||
|
{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
QueryManager.executeUpdate(connection, "DROP TABLE t");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Connection getConnection() throws SQLException
|
||||||
|
{
|
||||||
|
return new ConnectionManager().getConnection(TestUtils.defineBackend());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test the various overloads that bind params.
|
||||||
|
** Note, we're just confirming that these methods don't throw...
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testBindParams() throws SQLException
|
||||||
|
{
|
||||||
|
long ctMillis = System.currentTimeMillis();
|
||||||
|
Connection connection = getConnection();
|
||||||
|
PreparedStatement ps = connection.prepareStatement("UPDATE t SET i = ? WHERE i > 0");
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// these calls - we just want to assert that they don't throw any exceptions //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
QueryManager.bindParamObject(ps, 1, (short) 1);
|
||||||
|
QueryManager.bindParamObject(ps, 1, (long) 1);
|
||||||
|
QueryManager.bindParamObject(ps, 1, true);
|
||||||
|
QueryManager.bindParamObject(ps, 1, BigDecimal.ONE);
|
||||||
|
QueryManager.bindParamObject(ps, 1, "hello".getBytes(StandardCharsets.UTF_8));
|
||||||
|
QueryManager.bindParamObject(ps, 1, new Timestamp(ctMillis));
|
||||||
|
QueryManager.bindParamObject(ps, 1, new Date(ctMillis));
|
||||||
|
QueryManager.bindParamObject(ps, 1, new GregorianCalendar());
|
||||||
|
QueryManager.bindParamObject(ps, 1, LocalDate.now());
|
||||||
|
QueryManager.bindParamObject(ps, 1, OffsetDateTime.now());
|
||||||
|
QueryManager.bindParamObject(ps, 1, LocalDateTime.now());
|
||||||
|
|
||||||
|
assertThrows(SQLException.class, () ->
|
||||||
|
{
|
||||||
|
QueryManager.bindParamObject(ps, 1, new Object());
|
||||||
|
});
|
||||||
|
|
||||||
|
QueryManager.bindParam(ps, 1, (Integer) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (Boolean) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (BigDecimal) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (byte[]) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (Timestamp) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (String) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (Date) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (GregorianCalendar) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (LocalDate) null);
|
||||||
|
QueryManager.bindParam(ps, 1, (LocalDateTime) null);
|
||||||
|
|
||||||
|
QueryManager.bindParam(ps, 1, 1);
|
||||||
|
QueryManager.bindParam(ps, 1, true);
|
||||||
|
QueryManager.bindParam(ps, 1, BigDecimal.ONE);
|
||||||
|
QueryManager.bindParam(ps, 1, "hello".getBytes(StandardCharsets.UTF_8));
|
||||||
|
QueryManager.bindParam(ps, 1, new Timestamp(ctMillis));
|
||||||
|
QueryManager.bindParam(ps, 1, "hello");
|
||||||
|
QueryManager.bindParam(ps, 1, new Date(ctMillis));
|
||||||
|
QueryManager.bindParam(ps, 1, new GregorianCalendar());
|
||||||
|
QueryManager.bindParam(ps, 1, LocalDate.now());
|
||||||
|
QueryManager.bindParam(ps, 1, LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test the various getXXX methods from result sets
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetValueMethods() throws SQLException
|
||||||
|
{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
QueryManager.executeUpdate(connection, "INSERT INTO t (i, dt, c) VALUES (1, now(), 'A')");
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * from t");
|
||||||
|
preparedStatement.execute();
|
||||||
|
ResultSet rs = preparedStatement.getResultSet();
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
assertEquals(1, QueryManager.getInteger(rs, "i"));
|
||||||
|
assertEquals(1, QueryManager.getInteger(rs, 1));
|
||||||
|
assertEquals(1L, QueryManager.getLong(rs, "i"));
|
||||||
|
assertEquals(1L, QueryManager.getLong(rs, 1));
|
||||||
|
assertArrayEquals(new byte[] { 0, 0, 0, 1 }, QueryManager.getByteArray(rs, "i"));
|
||||||
|
assertArrayEquals(new byte[] { 0, 0, 0, 1 }, QueryManager.getByteArray(rs, 1));
|
||||||
|
assertEquals(1, QueryManager.getObject(rs, "i"));
|
||||||
|
assertEquals(1, QueryManager.getObject(rs, 1));
|
||||||
|
assertEquals(BigDecimal.ONE, QueryManager.getBigDecimal(rs, "i"));
|
||||||
|
assertEquals(BigDecimal.ONE, QueryManager.getBigDecimal(rs, 1));
|
||||||
|
assertEquals(true, QueryManager.getBoolean(rs, "i"));
|
||||||
|
assertEquals(true, QueryManager.getBoolean(rs, 1));
|
||||||
|
assertNotNull(QueryManager.getDate(rs, "dt"));
|
||||||
|
assertNotNull(QueryManager.getDate(rs, 2));
|
||||||
|
assertNotNull(QueryManager.getCalendar(rs, "dt"));
|
||||||
|
assertNotNull(QueryManager.getCalendar(rs, 2));
|
||||||
|
assertNotNull(QueryManager.getLocalDate(rs, "dt"));
|
||||||
|
assertNotNull(QueryManager.getLocalDate(rs, 2));
|
||||||
|
assertNotNull(QueryManager.getLocalDateTime(rs, "dt"));
|
||||||
|
assertNotNull(QueryManager.getLocalDateTime(rs, 2));
|
||||||
|
assertNotNull(QueryManager.getOffsetDateTime(rs, "dt"));
|
||||||
|
assertNotNull(QueryManager.getOffsetDateTime(rs, 2));
|
||||||
|
assertNotNull(QueryManager.getTimestamp(rs, "dt"));
|
||||||
|
assertNotNull(QueryManager.getTimestamp(rs, 2));
|
||||||
|
assertEquals("A", QueryManager.getObject(rs, "c"));
|
||||||
|
assertEquals("A", QueryManager.getObject(rs, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Test the various getXXX methods from result sets, when they return null
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetValueMethodsReturningNull() throws SQLException
|
||||||
|
{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
QueryManager.executeUpdate(connection, "INSERT INTO t (i, dt, c) VALUES (null, null, null)");
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * from t");
|
||||||
|
preparedStatement.execute();
|
||||||
|
ResultSet rs = preparedStatement.getResultSet();
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
assertNull(QueryManager.getInteger(rs, "i"));
|
||||||
|
assertNull(QueryManager.getInteger(rs, 1));
|
||||||
|
assertNull(QueryManager.getLong(rs, "i"));
|
||||||
|
assertNull(QueryManager.getLong(rs, 1));
|
||||||
|
assertNull(QueryManager.getByteArray(rs, "i"));
|
||||||
|
assertNull(QueryManager.getByteArray(rs, 1));
|
||||||
|
assertNull(QueryManager.getObject(rs, "i"));
|
||||||
|
assertNull(QueryManager.getObject(rs, 1));
|
||||||
|
assertNull(QueryManager.getBigDecimal(rs, "i"));
|
||||||
|
assertNull(QueryManager.getBigDecimal(rs, 1));
|
||||||
|
assertNull(QueryManager.getBoolean(rs, "i"));
|
||||||
|
assertNull(QueryManager.getBoolean(rs, 1));
|
||||||
|
assertNull(QueryManager.getDate(rs, "dt"));
|
||||||
|
assertNull(QueryManager.getDate(rs, 2));
|
||||||
|
assertNull(QueryManager.getCalendar(rs, "dt"));
|
||||||
|
assertNull(QueryManager.getCalendar(rs, 2));
|
||||||
|
assertNull(QueryManager.getLocalDate(rs, "dt"));
|
||||||
|
assertNull(QueryManager.getLocalDate(rs, 2));
|
||||||
|
assertNull(QueryManager.getLocalDateTime(rs, "dt"));
|
||||||
|
assertNull(QueryManager.getLocalDateTime(rs, 2));
|
||||||
|
assertNull(QueryManager.getOffsetDateTime(rs, "dt"));
|
||||||
|
assertNull(QueryManager.getOffsetDateTime(rs, 2));
|
||||||
|
assertNull(QueryManager.getTimestamp(rs, "dt"));
|
||||||
|
assertNull(QueryManager.getTimestamp(rs, 2));
|
||||||
|
assertNull(QueryManager.getObject(rs, "c"));
|
||||||
|
assertNull(QueryManager.getObject(rs, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** We had a bug where LocalDates weren't being properly bound. This test
|
||||||
|
** confirms (more?) correct behavior
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testLocalDate() throws SQLException
|
||||||
|
{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
QueryManager.executeUpdate(connection, "INSERT INTO t (d) VALUES (?)", LocalDate.of(2013, Month.OCTOBER, 1));
|
||||||
|
|
||||||
|
PreparedStatement preparedStatement = connection.prepareStatement("SELECT d from t");
|
||||||
|
preparedStatement.execute();
|
||||||
|
ResultSet rs = preparedStatement.getResultSet();
|
||||||
|
rs.next();
|
||||||
|
|
||||||
|
Date date = QueryManager.getDate(rs, 1);
|
||||||
|
assertEquals(1, date.getDate(), "Date value");
|
||||||
|
assertEquals(Month.OCTOBER.getValue(), date.getMonth() + 1, "Month value");
|
||||||
|
assertEquals(2013, date.getYear() + 1900, "Year value");
|
||||||
|
|
||||||
|
LocalDate localDate = QueryManager.getLocalDate(rs, 1);
|
||||||
|
assertEquals(1, localDate.getDayOfMonth(), "Date value");
|
||||||
|
assertEquals(Month.OCTOBER, localDate.getMonth(), "Month value");
|
||||||
|
assertEquals(2013, localDate.getYear(), "Year value");
|
||||||
|
|
||||||
|
LocalDateTime localDateTime = QueryManager.getLocalDateTime(rs, 1);
|
||||||
|
assertEquals(1, localDateTime.getDayOfMonth(), "Date value");
|
||||||
|
assertEquals(Month.OCTOBER, localDateTime.getMonth(), "Month value");
|
||||||
|
assertEquals(2013, localDateTime.getYear(), "Year value");
|
||||||
|
assertEquals(0, localDateTime.getHour(), "Hour value");
|
||||||
|
assertEquals(0, localDateTime.getMinute(), "Minute value");
|
||||||
|
|
||||||
|
OffsetDateTime offsetDateTime = QueryManager.getOffsetDateTime(rs, 1);
|
||||||
|
assertEquals(1, offsetDateTime.getDayOfMonth(), "Date value");
|
||||||
|
assertEquals(Month.OCTOBER, offsetDateTime.getMonth(), "Month value");
|
||||||
|
assertEquals(2013, offsetDateTime.getYear(), "Year value");
|
||||||
|
assertEquals(0, offsetDateTime.getHour(), "Hour value");
|
||||||
|
assertEquals(0, offsetDateTime.getMinute(), "Minute value");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
--
|
||||||
|
-- QQQ - Low-code Application Framework for Engineers.
|
||||||
|
-- Copyright (C) 2021-2022. 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/>.
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS child_table;
|
||||||
|
CREATE TABLE child_table
|
||||||
|
(
|
||||||
|
id INT AUTO_INCREMENT primary key,
|
||||||
|
name VARCHAR(80) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO child_table (id, name) VALUES (1, 'Timmy');
|
||||||
|
INSERT INTO child_table (id, name) VALUES (2, 'Jimmy');
|
||||||
|
INSERT INTO child_table (id, name) VALUES (3, 'Johnny');
|
||||||
|
INSERT INTO child_table (id, name) VALUES (4, 'Gracie');
|
||||||
|
INSERT INTO child_table (id, name) VALUES (5, 'Suzie');
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS parent_table;
|
||||||
|
CREATE TABLE parent_table
|
||||||
|
(
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(80) NOT NULL,
|
||||||
|
child_id INT,
|
||||||
|
foreign key (child_id) references child_table(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO parent_table (id, name, child_id) VALUES (1, 'Tim''s Dad', 1);
|
||||||
|
INSERT INTO parent_table (id, name, child_id) VALUES (2, 'Tim''s Mom', 1);
|
||||||
|
INSERT INTO parent_table (id, name, child_id) VALUES (3, 'Childless Man', null);
|
||||||
|
INSERT INTO parent_table (id, name, child_id) VALUES (4, 'Childless Woman', null);
|
||||||
|
INSERT INTO parent_table (id, name, child_id) VALUES (5, 'Johny''s Single Dad', 3);
|
@ -22,7 +22,7 @@
|
|||||||
DROP TABLE IF EXISTS person;
|
DROP TABLE IF EXISTS person;
|
||||||
CREATE TABLE person
|
CREATE TABLE person
|
||||||
(
|
(
|
||||||
id INT AUTO_INCREMENT,
|
id INT AUTO_INCREMENT primary key ,
|
||||||
create_date TIMESTAMP DEFAULT now(),
|
create_date TIMESTAMP DEFAULT now(),
|
||||||
modify_date TIMESTAMP DEFAULT now(),
|
modify_date TIMESTAMP DEFAULT now(),
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user