mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Initial checkin
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,9 @@
|
|||||||
|
target/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
## Original contents from github template: ##
|
||||||
|
#############################################
|
||||||
# Compiled class file
|
# Compiled class file
|
||||||
*.class
|
*.class
|
||||||
|
|
||||||
|
242
checkstyle.xml
Normal file
242
checkstyle.xml
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||||
|
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
|
||||||
|
<!--
|
||||||
|
See reference at https://checkstyle.sourceforge.io/checks.html
|
||||||
|
-->
|
||||||
|
<module name = "Checker">
|
||||||
|
<property name="charset" value="UTF-8"/>
|
||||||
|
|
||||||
|
<property name="severity" value="warning"/>
|
||||||
|
|
||||||
|
<property name="fileExtensions" value="java, properties, xml"/>
|
||||||
|
<!-- Checks for whitespace -->
|
||||||
|
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||||
|
<module name="FileTabCharacter">
|
||||||
|
<property name="eachLine" value="true"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<module name="LineLength">
|
||||||
|
<property name="max" value="100"/>
|
||||||
|
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||||
|
</module>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module name="TreeWalker">
|
||||||
|
<module name="OuterTypeFilename"/>
|
||||||
|
<module name="IllegalTokenText">
|
||||||
|
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
|
||||||
|
<property name="format" value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||||
|
<property name="message" value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||||
|
</module>
|
||||||
|
<module name="AvoidEscapedUnicodeCharacters">
|
||||||
|
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||||
|
<property name="allowByTailComment" value="true"/>
|
||||||
|
<property name="allowNonPrintableEscapes" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="AvoidStarImport"/>
|
||||||
|
<module name="OneTopLevelClass"/>
|
||||||
|
<module name="NoLineWrap"/>
|
||||||
|
<module name="EmptyBlock">
|
||||||
|
<property name="option" value="TEXT"/>
|
||||||
|
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||||
|
</module>
|
||||||
|
<module name="NeedBraces"/>
|
||||||
|
<module name="LeftCurly">
|
||||||
|
<property name="option" value="nl"/>
|
||||||
|
</module>
|
||||||
|
<module name="RightCurly">
|
||||||
|
<property name="option" value="alone"/>
|
||||||
|
</module>
|
||||||
|
<!--
|
||||||
|
<module name="WhitespaceAround">
|
||||||
|
<property name="allowEmptyConstructors" value="true"/>
|
||||||
|
<property name="allowEmptyMethods" value="true"/>
|
||||||
|
<property name="allowEmptyTypes" value="true"/>
|
||||||
|
<property name="allowEmptyLoops" value="true"/>
|
||||||
|
<message key="ws.notFollowed"
|
||||||
|
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
|
||||||
|
<message key="ws.notPreceded"
|
||||||
|
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||||
|
</module>
|
||||||
|
-->
|
||||||
|
<module name="OneStatementPerLine"/>
|
||||||
|
<module name="MultipleVariableDeclarations"/>
|
||||||
|
<module name="ArrayTypeStyle"/>
|
||||||
|
<module name="MissingSwitchDefault"/>
|
||||||
|
<module name="FallThrough"/>
|
||||||
|
<module name="UpperEll"/>
|
||||||
|
<module name="ModifierOrder"/>
|
||||||
|
<module name="EmptyLineSeparator">
|
||||||
|
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<property name="id" value="SeparatorWrapDot"/>
|
||||||
|
<property name="tokens" value="DOT"/>
|
||||||
|
<property name="option" value="nl"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<property name="id" value="SeparatorWrapComma"/>
|
||||||
|
<property name="tokens" value="COMMA"/>
|
||||||
|
<property name="option" value="EOL"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
|
||||||
|
<property name="id" value="SeparatorWrapEllipsis"/>
|
||||||
|
<property name="tokens" value="ELLIPSIS"/>
|
||||||
|
<property name="option" value="EOL"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
|
||||||
|
<property name="id" value="SeparatorWrapArrayDeclarator"/>
|
||||||
|
<property name="tokens" value="ARRAY_DECLARATOR"/>
|
||||||
|
<property name="option" value="EOL"/>
|
||||||
|
</module>
|
||||||
|
<module name="SeparatorWrap">
|
||||||
|
<property name="id" value="SeparatorWrapMethodRef"/>
|
||||||
|
<property name="tokens" value="METHOD_REF"/>
|
||||||
|
<property name="option" value="nl"/>
|
||||||
|
</module>
|
||||||
|
<module name="PackageName">
|
||||||
|
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="TypeName">
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="MemberName">
|
||||||
|
<property name="format" value="^[_a-zA-Z]([a-z0-9A-Z][a-zA-Z0-9]*)?$"/>
|
||||||
|
<message key="name.invalidPattern" value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="ParameterName">
|
||||||
|
<property name="format" value="^[a-zA-Z]([a-z0-9A-Z][a-zA-Z0-9]*)?$"/>
|
||||||
|
<message key="name.invalidPattern" value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="CatchParameterName">
|
||||||
|
<property name="format" value="^[a-zA-Z]([a-z0-9A-Z][a-zA-Z0-9]*)?$"/>
|
||||||
|
<message key="name.invalidPattern" value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="LocalVariableName">
|
||||||
|
<property name="tokens" value="VARIABLE_DEF"/>
|
||||||
|
<property name="format" value="^[a-zA-Z]([a-z0-9A-Z][a-zA-Z0-9]*)?$"/>
|
||||||
|
<message key="name.invalidPattern" value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="ClassTypeParameterName">
|
||||||
|
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][_A-Z0-9]*$)"/>
|
||||||
|
<message key="name.invalidPattern" value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="MethodTypeParameterName">
|
||||||
|
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][_A-Z0-9]*$)"/>
|
||||||
|
<message key="name.invalidPattern" value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="InterfaceTypeParameterName">
|
||||||
|
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][_A-Z0-9]*$)"/>
|
||||||
|
<message key="name.invalidPattern" value="Interface type name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="NoFinalizer"/>
|
||||||
|
<module name="GenericWhitespace">
|
||||||
|
<message key="ws.followed" value="GenericWhitespace ''{0}'' is followed by whitespace."/>
|
||||||
|
<message key="ws.preceded" value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
|
||||||
|
<message key="ws.illegalFollow" value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||||
|
<message key="ws.notPreceded" value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||||
|
</module>
|
||||||
|
<module name="Indentation">
|
||||||
|
<property name="basicOffset" value="3"/>
|
||||||
|
<property name="braceAdjustment" value="0"/>
|
||||||
|
<property name="caseIndent" value="3"/>
|
||||||
|
<property name="throwsIndent" value="6"/>
|
||||||
|
<property name="lineWrappingIndentation" value="3"/>
|
||||||
|
<property name="arrayInitIndent" value="2"/>
|
||||||
|
</module>
|
||||||
|
<!--
|
||||||
|
<module name="AbbreviationAsWordInName">
|
||||||
|
<property name="ignoreFinal" value="false"/>
|
||||||
|
<property name="allowedAbbreviationLength" value="1"/>
|
||||||
|
</module>
|
||||||
|
-->
|
||||||
|
<module name="OverloadMethodsDeclarationOrder"/>
|
||||||
|
<module name="VariableDeclarationUsageDistance"/>
|
||||||
|
<!--
|
||||||
|
<module name="CustomImportOrder">
|
||||||
|
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||||
|
<property name="separateLineBetweenGroups" value="true"/>
|
||||||
|
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
|
||||||
|
</module>
|
||||||
|
-->
|
||||||
|
<module name="CustomImportOrder">
|
||||||
|
<property name="customImportOrderRules" value="SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE###STATIC"/>
|
||||||
|
<property name="specialImportsRegExp" value="^javax\."/>
|
||||||
|
<property name="standardPackageRegExp" value="^java\."/>
|
||||||
|
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||||
|
<property name="separateLineBetweenGroups" value="false"/>
|
||||||
|
</module>
|
||||||
|
<module name="MethodParamPad"/>
|
||||||
|
<module name="NoWhitespaceBefore">
|
||||||
|
<property name="tokens" value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
|
||||||
|
<property name="allowLineBreaks" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="ParenPad"/>
|
||||||
|
<module name="OperatorWrap">
|
||||||
|
<property name="option" value="NL"/>
|
||||||
|
<property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
|
||||||
|
</module>
|
||||||
|
<module name="AnnotationLocation">
|
||||||
|
<property name="id" value="AnnotationLocationMostCases"/>
|
||||||
|
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
|
||||||
|
</module>
|
||||||
|
<module name="AnnotationLocation">
|
||||||
|
<property name="id" value="AnnotationLocationVariables"/>
|
||||||
|
<property name="tokens" value="VARIABLE_DEF"/>
|
||||||
|
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||||
|
</module>
|
||||||
|
<module name="NonEmptyAtclauseDescription"/>
|
||||||
|
<!-- <module name="JavadocTagContinuationIndentation"/> -->
|
||||||
|
<!--
|
||||||
|
<module name="SummaryJavadoc">
|
||||||
|
<property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||||
|
</module>
|
||||||
|
-->
|
||||||
|
<!-- <module name="JavadocParagraph"/> -->
|
||||||
|
<module name="AtclauseOrder">
|
||||||
|
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||||
|
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||||
|
</module>
|
||||||
|
<module name="JavadocMethod">
|
||||||
|
<property name="allowMissingParamTags" value="true"/>
|
||||||
|
<property name="allowMissingReturnTag" value="true"/>
|
||||||
|
<property name="allowedAnnotations" value="Override, Test"/>
|
||||||
|
</module>
|
||||||
|
<module name="MissingJavadocMethod">
|
||||||
|
<property name="scope" value="private"/>
|
||||||
|
</module>
|
||||||
|
<module name="MethodName">
|
||||||
|
<property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
|
||||||
|
<message key="name.invalidPattern"
|
||||||
|
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||||
|
</module>
|
||||||
|
<module name="SingleLineJavadoc">
|
||||||
|
<property name="ignoreInlineTags" value="false"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="MagicNumber">
|
||||||
|
<property name="severity" value="info"/>
|
||||||
|
<property name="tokens" value="NUM_DOUBLE, NUM_FLOAT, NUM_INT"/>
|
||||||
|
<property name="ignoreNumbers" value="0, 1, 2, 3, 4, 5, 6, 7, 8"/>
|
||||||
|
<property name="ignoreFieldDeclaration" value="true"/>
|
||||||
|
<property name="ignoreAnnotation" value="true"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<module name="EmptyCatchBlock">
|
||||||
|
<property name="exceptionVariableName" value="expected"/>
|
||||||
|
</module>
|
||||||
|
<module name="CommentsIndentation"/>
|
||||||
|
|
||||||
|
<!-- this would be nice, but requires the the @inheritDoc javadoc tag... -->
|
||||||
|
<module name="MissingOverride"/>
|
||||||
|
|
||||||
|
</module>
|
||||||
|
</module>
|
139
pom.xml
Normal file
139
pom.xml
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
|
<artifactId>qqq-backend-module-rdbms</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<!-- props specifically to this module -->
|
||||||
|
<!-- none at this time -->
|
||||||
|
|
||||||
|
<!-- Common props for all qqq modules -->
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
|
||||||
|
<maven.compiler.showWarnings>true</maven.compiler.showWarnings>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- other qqq modules deps -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
|
<artifactId>qqq-backend-core</artifactId>
|
||||||
|
<version>0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 3rd party deps specifically for this module -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.26</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<version>1.4.197</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Common deps for all qqq modules -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>3.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<version>2.14.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<version>2.14.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>5.8.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- plugins specifically for this module -->
|
||||||
|
<!-- none at this time -->
|
||||||
|
|
||||||
|
<!-- Common plugins for all qqq modules -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.0.0-M5</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>3.1.2</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
|
<artifactId>checkstyle</artifactId>
|
||||||
|
<version>9.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>validate</id>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<configuration>
|
||||||
|
<configLocation>checkstyle.xml</configLocation>
|
||||||
|
<!-- <suppressionsLocation>checkstyle-suppressions.xml</suppressionsLocation> -->
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<consoleOutput>true</consoleOutput>
|
||||||
|
<failsOnError>false</failsOnError>
|
||||||
|
<failOnViolation>true</failOnViolation>
|
||||||
|
<violationSeverity>warning</violationSeverity>
|
||||||
|
<excludes>**/target/generated-sources/*.*</excludes>
|
||||||
|
<!-- <linkXRef>false</linkXRef> -->
|
||||||
|
</configuration>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>github</id>
|
||||||
|
<name>GitHub kingsrook Maven Packages</name>
|
||||||
|
<url>https://maven.pkg.github.com/Kingsrook/qqq-maven-registry</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>github</id>
|
||||||
|
<name>GitHub kingsrook Maven Packages</name>
|
||||||
|
<url>https://maven.pkg.github.com/Kingsrook/qqq-maven-registry</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,83 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RDBSMBackendMetaData extends QBackendMetaData
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public RDBSMBackendMetaData(QBackendMetaData source)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
setName(source.getName());
|
||||||
|
setValues(source.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getVendor()
|
||||||
|
{
|
||||||
|
return getValue("vendor");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getHostName()
|
||||||
|
{
|
||||||
|
return getValue("hostName");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getPort()
|
||||||
|
{
|
||||||
|
return getValue("port");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getDatabaseName()
|
||||||
|
{
|
||||||
|
return getValue("databaseName");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getUsername()
|
||||||
|
{
|
||||||
|
return getValue("username");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getPassword()
|
||||||
|
{
|
||||||
|
return getValue("password");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.interfaces.QModuleInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSInsertAction;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSQueryAction;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RDBSMModule implements QModuleInterface
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QueryInterface getQueryInterface()
|
||||||
|
{
|
||||||
|
return new RDBMSQueryAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public InsertInterface getInsertInterface()
|
||||||
|
{
|
||||||
|
return (new RDBMSInsertAction());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public abstract class AbstractRDBMSAction
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
protected String getColumnName(QFieldMetaData field)
|
||||||
|
{
|
||||||
|
if(field.getBackendName() != null)
|
||||||
|
{
|
||||||
|
return (field.getBackendName());
|
||||||
|
}
|
||||||
|
return (field.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.InsertRequest;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.InsertResult;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QFilterCriteria;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QFilterOrderBy;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecordWithStatus;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.interfaces.InsertInterface;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.RDBSMBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public InsertResult execute(InsertRequest insertRequest) throws QException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InsertResult rs = new InsertResult();
|
||||||
|
QTableMetaData table = insertRequest.getTable();
|
||||||
|
|
||||||
|
List<QFieldMetaData> insertableFields = table.getFields().stream()
|
||||||
|
.filter(field -> !field.getName().equals("id")) // todo - intent here is to avoid non-insertable fields.
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
String columns = insertableFields.stream()
|
||||||
|
.map(this::getColumnName)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
String questionMarks = insertableFields.stream()
|
||||||
|
.map(x -> "?")
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
|
||||||
|
String tableName = table.getName();
|
||||||
|
StringBuilder sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(columns).append(") VALUES");
|
||||||
|
List<Object> params = new ArrayList<>();
|
||||||
|
|
||||||
|
int recordIndex = 0;
|
||||||
|
for(QRecord record : insertRequest.getRecords())
|
||||||
|
{
|
||||||
|
if(recordIndex++ > 0)
|
||||||
|
{
|
||||||
|
sql.append(",");
|
||||||
|
}
|
||||||
|
sql.append("(").append(questionMarks).append(")");
|
||||||
|
for(QFieldMetaData field : insertableFields)
|
||||||
|
{
|
||||||
|
params.add(record.getValue(field.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo sql customization - can edit sql and/or param list
|
||||||
|
|
||||||
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
|
Connection connection = connectionManager.getConnection(new RDBSMBackendMetaData(insertRequest.getBackend()));
|
||||||
|
|
||||||
|
// QueryResult rs = new QueryResult();
|
||||||
|
// List<QRecord> records = new ArrayList<>();
|
||||||
|
// rs.setRecords(records);
|
||||||
|
|
||||||
|
// todo - non-serial-id style tables
|
||||||
|
// todo - other generated values, e.g., createDate... maybe need to re-select?
|
||||||
|
List<Integer> idList = QueryManager.executeInsertForGeneratedIds(connection, sql.toString(), params);
|
||||||
|
List<QRecordWithStatus> recordsWithStatus = new ArrayList<>();
|
||||||
|
rs.setRecords(recordsWithStatus);
|
||||||
|
int index = 0;
|
||||||
|
for(QRecord record : insertRequest.getRecords())
|
||||||
|
{
|
||||||
|
Integer id = idList.get(index);
|
||||||
|
QRecordWithStatus recordWithStatus = new QRecordWithStatus(record);
|
||||||
|
recordWithStatus.setPrimaryKey(id);
|
||||||
|
recordWithStatus.setValue(table.getPrimaryKeyField(), id);
|
||||||
|
recordsWithStatus.add(recordWithStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new QException("Error executing insert: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String makeWhereClause(QTableMetaData table, List<QFilterCriteria> criteria, List<Serializable> params) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
List<String> clauses = new ArrayList<>();
|
||||||
|
for(QFilterCriteria criterion : criteria)
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(criterion.getFieldName());
|
||||||
|
String column = getColumnName(field);
|
||||||
|
String clause = column;
|
||||||
|
Integer expectedNoOfParams = null;
|
||||||
|
switch(criterion.getOperator())
|
||||||
|
{
|
||||||
|
case EQUALS:
|
||||||
|
{
|
||||||
|
clause += " = ? ";
|
||||||
|
expectedNoOfParams = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NOT_EQUALS:
|
||||||
|
{
|
||||||
|
clause += " != ? ";
|
||||||
|
expectedNoOfParams = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IN:
|
||||||
|
{
|
||||||
|
clause += " IN (" + criterion.getValues().stream().map(x -> "?").collect(Collectors.joining(",")) + ") ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Unexpected operator: " + criterion.getOperator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clauses.add(clause);
|
||||||
|
if(expectedNoOfParams != null && criterion.getValues().size() != expectedNoOfParams)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Incorrect number of values given for criteria [" + field.getName() + "]");
|
||||||
|
}
|
||||||
|
params.addAll(criterion.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String.join(" AND ", clauses));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String makeOrderByClause(QTableMetaData table, List<QFilterOrderBy> orderBys)
|
||||||
|
{
|
||||||
|
List<String> clauses = new ArrayList<>();
|
||||||
|
|
||||||
|
for(QFilterOrderBy orderBy : orderBys)
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(orderBy.getFieldName());
|
||||||
|
String column = getColumnName(field);
|
||||||
|
clauses.add(column + " " + (orderBy.getIsAscending() ? "ASC" : "DESC"));
|
||||||
|
}
|
||||||
|
return (String.join(", ", clauses));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QFilterCriteria;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QFilterOrderBy;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QQueryFilter;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QueryRequest;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QueryResult;
|
||||||
|
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.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.interfaces.QueryInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.RDBSMBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RDBMSQueryAction extends AbstractRDBMSAction implements QueryInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QueryResult execute(QueryRequest queryRequest) throws QException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QTableMetaData table = queryRequest.getTable();
|
||||||
|
String tableName = table.getName();
|
||||||
|
|
||||||
|
String columns = table.getFields().stream()
|
||||||
|
.map(this::getColumnName)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
|
||||||
|
String sql = "SELECT " + columns + " FROM " + tableName;
|
||||||
|
|
||||||
|
QQueryFilter filter = queryRequest.getFilter();
|
||||||
|
List<Serializable> params = new ArrayList<>();
|
||||||
|
if(filter != null && CollectionUtils.nullSafeHasContents(filter.getCriteria()))
|
||||||
|
{
|
||||||
|
sql += " WHERE " + makeWhereClause(table, filter.getCriteria(), params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(filter != null && CollectionUtils.nullSafeHasContents(filter.getOrderBys()))
|
||||||
|
{
|
||||||
|
sql += " ORDER BY " + makeOrderByClause(table, filter.getOrderBys());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(queryRequest.getLimit() != null)
|
||||||
|
{
|
||||||
|
sql += " LIMIT " + queryRequest.getLimit();
|
||||||
|
|
||||||
|
if(queryRequest.getSkip() != null)
|
||||||
|
{
|
||||||
|
// todo - other sql grammars?
|
||||||
|
sql += " OFFSET " + queryRequest.getSkip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo sql customization - can edit sql and/or param list
|
||||||
|
|
||||||
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
|
Connection connection = connectionManager.getConnection(new RDBSMBackendMetaData(queryRequest.getBackend()));
|
||||||
|
|
||||||
|
QueryResult rs = new QueryResult();
|
||||||
|
List<QRecord> records = new ArrayList<>();
|
||||||
|
rs.setRecords(records);
|
||||||
|
|
||||||
|
QueryManager.executeStatement(connection, sql, ((ResultSet resultSet) ->
|
||||||
|
{
|
||||||
|
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||||
|
while(resultSet.next())
|
||||||
|
{
|
||||||
|
// todo - should refactor this for view etc to use too.
|
||||||
|
QRecord record = new QRecord();
|
||||||
|
records.add(record);
|
||||||
|
record.setTableName(table.getName());
|
||||||
|
LinkedHashMap<String, Serializable> values = new LinkedHashMap<>();
|
||||||
|
record.setValues(values);
|
||||||
|
|
||||||
|
for(int i = 1; i <= metaData.getColumnCount(); i++)
|
||||||
|
{
|
||||||
|
QFieldMetaData qFieldMetaData = table.getFields().get(i - 1);
|
||||||
|
String value = QueryManager.getString(resultSet, i); // todo - types!
|
||||||
|
values.put(qFieldMetaData.getName(), value);
|
||||||
|
if(qFieldMetaData.getName().equals(table.getPrimaryKeyField()))
|
||||||
|
{
|
||||||
|
record.setPrimaryKey(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}), params);
|
||||||
|
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new QException("Error executing query", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String makeWhereClause(QTableMetaData table, List<QFilterCriteria> criteria, List<Serializable> params) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
List<String> clauses = new ArrayList<>();
|
||||||
|
for(QFilterCriteria criterion : criteria)
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(criterion.getFieldName());
|
||||||
|
String column = getColumnName(field);
|
||||||
|
String clause = column;
|
||||||
|
Integer expectedNoOfParams = null;
|
||||||
|
switch(criterion.getOperator())
|
||||||
|
{
|
||||||
|
case EQUALS:
|
||||||
|
{
|
||||||
|
clause += " = ? ";
|
||||||
|
expectedNoOfParams = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NOT_EQUALS:
|
||||||
|
{
|
||||||
|
clause += " != ? ";
|
||||||
|
expectedNoOfParams = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IN:
|
||||||
|
{
|
||||||
|
clause += " IN (" + criterion.getValues().stream().map(x -> "?").collect(Collectors.joining(",")) + ") ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Unexpected operator: " + criterion.getOperator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clauses.add(clause);
|
||||||
|
if(expectedNoOfParams != null && criterion.getValues().size() != expectedNoOfParams)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Incorrect number of values given for criteria [" + field.getName() + "]");
|
||||||
|
}
|
||||||
|
params.addAll(criterion.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String.join(" AND ", clauses));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String makeOrderByClause(QTableMetaData table, List<QFilterOrderBy> orderBys)
|
||||||
|
{
|
||||||
|
List<String> clauses = new ArrayList<>();
|
||||||
|
|
||||||
|
for(QFilterOrderBy orderBy : orderBys)
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(orderBy.getFieldName());
|
||||||
|
String column = getColumnName(field);
|
||||||
|
clauses.add(column + " " + (orderBy.getIsAscending() ? "ASC" : "DESC"));
|
||||||
|
}
|
||||||
|
return (String.join(", ", clauses));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.jdbc;
|
||||||
|
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.RDBSMBackendMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ConnectionManager
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Connection getConnection(RDBSMBackendMetaData backend) throws SQLException
|
||||||
|
{
|
||||||
|
String jdbcURL;
|
||||||
|
|
||||||
|
switch (backend.getVendor())
|
||||||
|
{
|
||||||
|
case "mysql":
|
||||||
|
{
|
||||||
|
jdbcURL = "jdbc:mysql://" + backend.getHostName() + ":" + backend.getPort() + "/" + backend.getDatabaseName() + "?rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "h2":
|
||||||
|
{
|
||||||
|
jdbcURL = "jdbc:h2:" + backend.getHostName() + ":" + backend.getDatabaseName() + ";MODE=MySQL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Unsupported rdbms backend vendor: " + backend.getVendor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DriverManager.getConnection(jdbcURL, backend.getUsername(), backend.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
208
src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/SimpleEntity.java
Executable file
208
src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/SimpleEntity.java
Executable file
@ -0,0 +1,208 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.jdbc;
|
||||||
|
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class SimpleEntity extends HashMap<String, Object>
|
||||||
|
{
|
||||||
|
private String tableName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SimpleEntity()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SimpleEntity with(String key, Object value)
|
||||||
|
{
|
||||||
|
put(key, value);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Return the current value of tableName
|
||||||
|
**
|
||||||
|
** @return tableName
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getTableName()
|
||||||
|
{
|
||||||
|
return (tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Set the current value of tableName
|
||||||
|
**
|
||||||
|
** @param tableName
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTableName(String tableName)
|
||||||
|
{
|
||||||
|
this.tableName = tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SimpleEntity withTableName(String tableName)
|
||||||
|
{
|
||||||
|
setTableName(tableName);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Boolean getBoolean(String columnName)
|
||||||
|
{
|
||||||
|
Object o = get(columnName);
|
||||||
|
if(o == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(o instanceof Boolean)
|
||||||
|
{
|
||||||
|
return ((Boolean) o);
|
||||||
|
}
|
||||||
|
else if(o instanceof Number)
|
||||||
|
{
|
||||||
|
int i = ((Number) o).intValue();
|
||||||
|
return (i != 0);
|
||||||
|
}
|
||||||
|
else if(o instanceof String)
|
||||||
|
{
|
||||||
|
String s = (String) o;
|
||||||
|
return (s.equalsIgnoreCase("1") || s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Could not get value of object of type [" + o.getClass() + "] as Boolean.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getString(String columnName)
|
||||||
|
{
|
||||||
|
Object o = get(columnName);
|
||||||
|
if(o == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
if(o instanceof String)
|
||||||
|
{
|
||||||
|
return ((String) o);
|
||||||
|
}
|
||||||
|
else if(o instanceof byte[])
|
||||||
|
{
|
||||||
|
return (new String((byte[]) o));
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.valueOf(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getInteger(String columnName)
|
||||||
|
{
|
||||||
|
Object o = get(columnName);
|
||||||
|
if(o instanceof Long)
|
||||||
|
{
|
||||||
|
return ((Long) o).intValue();
|
||||||
|
}
|
||||||
|
else if(o instanceof Short)
|
||||||
|
{
|
||||||
|
return ((Short) o).intValue();
|
||||||
|
}
|
||||||
|
else if(o instanceof String)
|
||||||
|
{
|
||||||
|
return (Integer.parseInt((String) o));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Integer) o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public BigDecimal getBigDecimal(String columnName)
|
||||||
|
{
|
||||||
|
Object o = get(columnName);
|
||||||
|
if(o == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(o instanceof BigDecimal)
|
||||||
|
{
|
||||||
|
return ((BigDecimal) o);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new BigDecimal(String.valueOf(o));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Long getLong(String columnName)
|
||||||
|
{
|
||||||
|
Object o = get(columnName);
|
||||||
|
if(o instanceof Integer)
|
||||||
|
{
|
||||||
|
return ((Integer) o).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Long) o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void trimStrings()
|
||||||
|
{
|
||||||
|
for(String key : keySet())
|
||||||
|
{
|
||||||
|
Object value = get(key);
|
||||||
|
if(value != null && value instanceof String)
|
||||||
|
{
|
||||||
|
put(key, ((String) value).trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.RDBSMBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RDBMSActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
protected QInstance defineInstance()
|
||||||
|
{
|
||||||
|
QInstance qInstance = new QInstance();
|
||||||
|
qInstance.addBackend(defineBackend());
|
||||||
|
qInstance.addTable(defineTablePerson());
|
||||||
|
return (qInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
protected QBackendMetaData defineBackend()
|
||||||
|
{
|
||||||
|
return new QBackendMetaData()
|
||||||
|
.withName("default")
|
||||||
|
.withType("rdbms")
|
||||||
|
.withValue("vendor", "h2")
|
||||||
|
.withValue("hostName", "mem")
|
||||||
|
.withValue("databaseName", "test_database")
|
||||||
|
.withValue("username", "sa")
|
||||||
|
.withValue("password", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData defineTablePerson()
|
||||||
|
{
|
||||||
|
return new QTableMetaData()
|
||||||
|
.withName("person")
|
||||||
|
.withBackendName(defineBackend().getName())
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date"))
|
||||||
|
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withBackendName("modify_date"))
|
||||||
|
.withField(new QFieldMetaData("firstName", QFieldType.STRING).withBackendName("first_name"))
|
||||||
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name"))
|
||||||
|
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
||||||
|
.withField(new QFieldMetaData("email", QFieldType.STRING));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void primeTestDatabase() throws Exception
|
||||||
|
{
|
||||||
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
|
Connection connection = connectionManager.getConnection(new RDBSMBackendMetaData(defineBackend()));
|
||||||
|
InputStream primeTestDatabaseSqlStream = RDBMSActionTest.class.getResourceAsStream("/prime-test-database.sql");
|
||||||
|
assertNotNull(primeTestDatabaseSqlStream);
|
||||||
|
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
||||||
|
String joinedSQL = String.join("\n", lines);
|
||||||
|
for(String sql : joinedSQL.split(";"))
|
||||||
|
{
|
||||||
|
QueryManager.executeUpdate(connection, sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QCriteriaOperator;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QFilterCriteria;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QQueryFilter;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QueryRequest;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.QueryResult;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class RDBMSQueryActionTest extends RDBMSActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
public void beforeEach() throws Exception
|
||||||
|
{
|
||||||
|
super.primeTestDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testUnfilteredQuery() throws QException
|
||||||
|
{
|
||||||
|
QueryRequest queryRequest = initQueryRequest();
|
||||||
|
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
||||||
|
Assertions.assertEquals(5, queryResult.getRecords().size(), "Unfiltered query should find all rows");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testEqualsQuery() throws QException
|
||||||
|
{
|
||||||
|
String email = "darin.kelkhoff@gmail.com";
|
||||||
|
|
||||||
|
QueryRequest queryRequest = initQueryRequest();
|
||||||
|
queryRequest.setFilter(new QQueryFilter()
|
||||||
|
.withCriteria(new QFilterCriteria()
|
||||||
|
.withFieldName("email")
|
||||||
|
.withOperator(QCriteriaOperator.EQUALS)
|
||||||
|
.withValues(List.of(email)))
|
||||||
|
);
|
||||||
|
QueryResult queryResult = new RDBMSQueryAction().execute(queryRequest);
|
||||||
|
Assertions.assertEquals(1, queryResult.getRecords().size(), "Equals query should find 1 row");
|
||||||
|
Assertions.assertEquals(email, queryResult.getRecords().get(0).getValueString("email"), "Should find expected email address");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private QueryRequest initQueryRequest()
|
||||||
|
{
|
||||||
|
QueryRequest queryRequest = new QueryRequest();
|
||||||
|
queryRequest.setInstance(defineInstance());
|
||||||
|
queryRequest.setTableName(defineTablePerson().getName());
|
||||||
|
return queryRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/test/resources/prime-test-database.sql
Normal file
18
src/test/resources/prime-test-database.sql
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
DROP TABLE IF EXISTS person;
|
||||||
|
CREATE TABLE person
|
||||||
|
(
|
||||||
|
id SERIAL,
|
||||||
|
create_date TIMESTAMP DEFAULT now(),
|
||||||
|
modify_date TIMESTAMP DEFAULT now(),
|
||||||
|
|
||||||
|
first_name VARCHAR(80) NOT NULL,
|
||||||
|
last_name VARCHAR(80) NOT NULL,
|
||||||
|
birth_date DATE,
|
||||||
|
email VARCHAR(250) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
||||||
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (2, 'James', 'Maes', '1980-05-15', 'jmaes@mmltholdings.com');
|
||||||
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (3, 'Tim', 'Chamberlain', '1976-05-28', 'tchamberlain@mmltholdings.com');
|
||||||
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (4, 'Tyler', 'Samples', '1990-01-01', 'tsamples@mmltholdings.com');
|
||||||
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (5, 'Garret', 'Richardson', '1981-01-01', 'grichardson@mmltholdings.com');
|
Reference in New Issue
Block a user