├── .github
└── workflows
│ └── CI.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE.txt
├── README.md
├── THIRD_PARTY.txt
├── codecov.yml
├── dco.txt
├── license-header.txt
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── qstd
│ ├── ColumnMappingPart.java
│ ├── ColumnNamesComparator.java
│ ├── ColumnNamesExtractor.java
│ ├── ColumnOrdersFinder.java
│ ├── ColumnValueFormatter.java
│ ├── ColumnsMapping.java
│ ├── ColumnsMappingGroup.java
│ ├── ColumnsMappingsFinder.java
│ ├── DatabaseMetadataFinder.java
│ ├── DatasetRow.java
│ ├── DatasetRowComparatorBuilder.java
│ ├── DatasetRowSet.java
│ ├── DatasetRowsFinder.java
│ ├── DatasetRowsGenerator.java
│ ├── DeleteToSelectTransformer.java
│ ├── InsertStatementsGenerator.java
│ ├── MissingNotNullColumnsFinder.java
│ ├── NotNullColumnsFinder.java
│ ├── PreparedStatementBuilder.java
│ ├── PrimaryKeyColumnsFinder.java
│ ├── QuickSqlTestData.java
│ ├── ReferencedTable.java
│ ├── ReferencedTableSet.java
│ ├── ReferencedTablesFinder.java
│ ├── RowFinder.java
│ ├── SelectTransformer.java
│ ├── SelectTransformerFactory.java
│ ├── SqlQuery.java
│ ├── UpdateToSelectTransformer.java
│ └── dbtype
│ ├── BaseColumnOrdersFinder.java
│ ├── BaseColumnsMappingsFinder.java
│ ├── BaseNotNullColumnsFinder.java
│ ├── BasePrimaryKeyColumnsFinder.java
│ ├── BaseReferencedTablesFinder.java
│ ├── DatabaseMetadataFinderFactory.java
│ ├── DatabaseMetadataFinderWithCache.java
│ ├── DatabaseType.java
│ ├── DatabaseUrlFinder.java
│ ├── DefaultColumnOrdersFinder.java
│ ├── DefaultDatabaseMetadataFinder.java
│ ├── DefaultNotNullColumnsFinder.java
│ ├── DefaultPrimaryKeyColumnsFinder.java
│ ├── H2MetadataFinder.java
│ ├── HsqlDbMetadataFinder.java
│ ├── MSSQLServerMetadataFinder.java
│ ├── MariaDBMySQLMetadataFinder.java
│ ├── OracleMetadataFinder.java
│ ├── PostgreSqlMariaDbReferencedTablesFinder.java
│ └── PostgreSqlMetadataFinder.java
└── test
├── java
└── org
│ └── qstd
│ └── test
│ ├── DataSourceBuilder.java
│ ├── DatasetRowApiTest.java
│ ├── DatasetRowsMergingTest.java
│ ├── DeleteTest.java
│ ├── FastTestSuite.java
│ ├── H2Config.java
│ ├── H2DateTypesTest.java
│ ├── H2Test.java
│ ├── HsqlDbTest.java
│ ├── InsertTest.java
│ ├── JdbcRoundtripTest.java
│ ├── MSSQLServerTest.java
│ ├── MariaDBSlowTest.java
│ ├── MariaDBTest.java
│ ├── NotFullyManagedDatabaseTest.java
│ ├── OracleTest.java
│ ├── PostgreSqlTest.java
│ ├── SelectTest.java
│ ├── SortInsertStatementsTest.java
│ ├── SortInsertStatementsWithPkTest.java
│ ├── SqlExecutor.java
│ ├── TestTable.java
│ └── UpdateTest.java
└── resources
├── junit-platform.properties
└── logback-test.xml
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | linux:
7 | runs-on: ubuntu-latest
8 | name: Java ${{ matrix.java }}
9 | strategy:
10 | matrix:
11 | java: [8, 11]
12 | env:
13 | REPO_SLUG: ${{ github.repository }}
14 | BRANCH: ${{ github.head_ref }}
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up JDK ${{ matrix.java }}
18 | uses: actions/setup-java@v1
19 | with:
20 | java-version: ${{ matrix.java }}
21 | - name: Cache Maven dependencies
22 | uses: actions/cache@v2
23 | with:
24 | path: ~/.m2
25 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
26 | restore-keys: ${{ runner.os }}-m2
27 | - name: Execute tests
28 | run: mvn verify
29 | - name: check license header is present in all files
30 | run: mvn license:check
31 | - name: Upload coverage to Codecov
32 | run: bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Maven
2 | target
3 |
4 | # IntelliJ
5 | .idea
6 | *.iml
7 | out
8 |
9 | # Eclipse
10 | .classpath
11 | .project
12 | .settings
13 |
14 | # NetBeans
15 | .nbattrs
16 |
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quick-perf/quick-sql-test-data/4e6439f0f4c54b70d3166c7bd2bf805646967876/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quick SQL test data
2 |
3 |
4 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ## Why use *Quick SQL test data*?
23 | Writing datasets with SQL may be tedious and time-consuming because of database integrity constraints.
24 |
25 | *This Java library aims to ease the generation of datasets to test SQL queries. It produces INSERT statements taking account of integrity constraints.*
26 |
27 | The library automatically:
28 | * identifies *NOT NULL columns* and provides values by requesting the database
29 | * adds rows of dependent tables in case of *foreign key constraints*
30 | * sorts insert statements to accommodate *foreign key constraints*
31 | * sorts insert statements following *primary key values*
32 |
33 | _[Another project](https://github.com/quick-perf/quick-sql-test-data-web) provides a web page to ease the use of the _Quick SQL test data_ library._
34 |
35 | ## How to use the library
36 |
37 | With Maven, you have to add the following dependency:
38 |
39 | ```xml
40 |
41 |
42 | org.quickperf
43 | quick-sql-test-data
44 | 0.1
45 |
46 | ```
47 |
48 | You can generate the insert statements with the help of an instance of `org.qstd.QuickSqlTestData` class.
49 |
50 | _Quick SQL test data_ works with:
51 | * PostgreSQL
52 | * Oracle
53 | * MariaDB
54 | * MySQL
55 | * Microsoft SQL Server
56 | * H2
57 | * HSQLDB
58 |
59 | ## Use cases
60 |
61 | This library can be helpful in the two following situations.
62 |
63 | ### Create a dataset before starting the writing of an SQL query
64 |
65 | This case happens when you develop SQL queries with *Test-Driven Development* (TDD).
66 |
67 | You can read below an example where we define a dataset row for which we generate the INSERT statement:
68 | ```java
69 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(dataSource);
70 | DatasetRow datasetRow = DatasetRow.ofTable("Player")
71 | .addColumnValue("lastName","Pogba");
72 | List insertStatements = quickSqlTestData.generateInsertListFor(datasetRow);
73 |
74 | System.out.println(insertStatements);
75 | ```
76 |
77 | The console displays the following result:
78 | ```
79 | [INSERT INTO PLAYER(FIRSTNAME, LASTNAME) VALUES('Paul', 'Pogba')]
80 | ```
81 | FIRSTNAME column owns a NOT NULL constraint. For this reason, the library has retrieved a FIRSTNAME value for the Pogba LASTNAME and has used it in the generated statement.
82 |
83 | ### Test an existing SQL query
84 | Let's take an example:
85 |
86 | ```java
87 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(dataSource);
88 | String selectStatement = "SELECT * FROM Player WHERE LASTNAME = 'Pogba'";
89 | String insertScript = quickSqlTestData.generateInsertScriptFor(selectStatement);
90 | System.out.println(insertScript);
91 | ```
92 |
93 | The console displays the following queries:
94 | ```
95 | INSERT INTO TEAM(ID, NAME) VALUES(1, 'Manchester United');
96 | INSERT INTO PLAYER(ID, FIRSTNAME, LASTNAME, TEAM_ID) VALUES(1, 'Paul', 'Pogba', 1);
97 | ```
98 | The library has done its best to generate INSERT queries allowing to test the SELECT query.
99 | It has detected a foreign key constraint and has generated a first statement inserting on a Team table. This one contains a value for the NAME column that must not be null.
100 |
101 | ## License
102 |
103 | [Apache License 2.0](/LICENSE.txt)
104 |
--------------------------------------------------------------------------------
/THIRD_PARTY.txt:
--------------------------------------------------------------------------------
1 | Quick SQL test data library uses:
2 | * JSqlParser licensed under Apache Software License, Version 2.0 (https://github.com/JSQLParser/JSqlParser/blob/master/LICENSE_APACHEV2) or LGPL V2.1 (https://github.com/JSQLParser/JSqlParser/blob/master/LICENSE_LGPLV21)
3 |
4 | Quick SQL test data library uses only for testing and doesn't ship with:
5 | * JUnit 5 licensed under Eclipse Public License - v 2.0 (https://github.com/junit-team/junit5/blob/main/LICENSE.md)
6 | * AssertJ licensed under Apache Software License, Version 2.0 (https://github.com/assertj/assertj-core/blob/main/LICENSE.txt)
7 | * AssertJ-DB licensed under Apache Software License, Version 2.0 (https://github.com/assertj/assertj-db/blob/main/LICENSE.txt)
8 | * QuickPerf licensed under Apache Software License, Version 2.0 (https://github.com/quick-perf/quickperf/blob/master/LICENSE.txt)
9 | * Testcontainers licensed under MIT License (https://github.com/testcontainers/testcontainers-java/blob/master/LICENSE)
10 | * HikariCP licensed under Apache Software License, Version 2.0 (https://github.com/brettwooldridge/HikariCP/blob/dev/LICENSE)
11 | * Logback licensed under Eclipse Public License v1.0 or GNU Lesser General Public License version 2.1 (https://github.com/qos-ch/logback/blob/master/LICENSE.txt)
12 | * H2 licensed under Mozilla Public License Version 2.0 or Eclipse Public License v1.0 (https://github.com/h2database/h2database/blob/master/LICENSE.txt)
13 | * MariaDB Docker licenced under GNU General Public License v2.0 (https://github.com/MariaDB/mariadb-docker/blob/master/LICENSE)
14 | * MariaDB java connector licenced under GNU Lesser General Public License version 2.1 (https://github.com/mariadb-corporation/mariadb-connector-j/blob/master/LICENSE)
15 | Please read this: https://mariadb.com/kb/en/licensing-faq/#licenses-used-by-mariadb
16 | * Microsoft SQL Server Docker image licensed under End-User Licensing Agreement (https://hub.docker.com/_/microsoft-mssql-server#environment-variables)
17 | * Microsoft JDBC Driver for SQL Server licensed under MIT License (https://github.com/microsoft/mssql-jdbc/blob/dev/LICENSE)
18 | * PostgreSQL Docker image licensed under MIT License (https://github.com/docker-library/postgres/blob/master/LICENSE)
19 | * PostgreSQL JDBC Driver licensed under BSD 2-Clause "Simplified" License (https://github.com/pgjdbc/pgjdbc/blob/master/LICENSE)
20 | * Oracle Database Express Edition licensed under Oracle Free Use Terms and Conditions (https://docs.oracle.com/en/database/oracle/oracle-database/18/xelic/licensing-information.html#GUID-5D29C372-9B49-4A4D-A9AF-70ACA12CCF46, https://www.oracle.com/downloads/licenses/oracle-free-license.html)
21 | * Oracle JDBC driver licensed under Oracle Free Use Terms and Conditions (https://www.oracle.com/downloads/licenses/oracle-free-license.html)
22 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | require_ci_to_pass: yes
3 |
4 | coverage:
5 | round: nearest
6 | precision: 2
7 |
8 | parsers:
9 | gcov:
10 | branch_detection:
11 | conditional: yes
12 | loop: yes
13 | method: no
14 | macro: no
--------------------------------------------------------------------------------
/dco.txt:
--------------------------------------------------------------------------------
1 | Developer Certificate of Origin
2 | Version 1.1
3 |
4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
5 | 1 Letterman Drive
6 | Suite D4700
7 | San Francisco, CA, 94129
8 |
9 | Everyone is permitted to copy and distribute verbatim copies of this
10 | license document, but changing it is not allowed.
11 |
12 |
13 | Developer's Certificate of Origin 1.1
14 |
15 | By making a contribution to this project, I certify that:
16 |
17 | (a) The contribution was created in whole or in part by me and I
18 | have the right to submit it under the open source license
19 | indicated in the file; or
20 |
21 | (b) The contribution is based upon previous work that, to the best
22 | of my knowledge, is covered under an appropriate open source
23 | license and I have the right under that license to submit that
24 | work with modifications, whether created in whole or in part
25 | by me, under the same open source license (unless I am
26 | permitted to submit under a different license), as indicated
27 | in the file; or
28 |
29 | (c) The contribution was provided directly to me by some other
30 | person who certified (a), (b) or (c) and I have not modified
31 | it.
32 |
33 | (d) I understand and agree that this project and the contribution
34 | are public and that a record of the contribution (including all
35 | personal information I submit with it, including my sign-off) is
36 | maintained indefinitely and may be redistributed consistent with
37 | this project or the open source license(s) involved.
38 |
--------------------------------------------------------------------------------
/license-header.txt:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
2 | the License. You may obtain a copy of the License at
3 |
4 | http://www.apache.org/licenses/LICENSE-2.0
5 |
6 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
7 | an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
8 | specific language governing permissions and limitations under the License.
9 |
10 | Copyright ${project.inceptionYear}-${currentYear} the original author or authors.
11 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnMappingPart.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | public class ColumnMappingPart {
16 |
17 | final String tableName;
18 | final String tableColumn;
19 | private final String tableSchema;
20 |
21 | public ColumnMappingPart(String tableSchema, String tableName, String tableColumn) {
22 | this.tableSchema = tableSchema;
23 | this.tableName = tableName;
24 | this.tableColumn = tableColumn;
25 | }
26 |
27 | boolean hasColumn(String columnName) {
28 | return tableColumn.equals(columnName);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnNamesComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.Comparator;
16 | import java.util.HashMap;
17 | import java.util.List;
18 | import java.util.Map;
19 |
20 | class ColumnNamesComparator implements Comparator {
21 |
22 | private final Map positionByColumnName;
23 |
24 | private ColumnNamesComparator(Map positionByColumnName) {
25 | this.positionByColumnName = positionByColumnName;
26 | }
27 |
28 | public static ColumnNamesComparator from(List orderedColumns) {
29 | Map positionByColumnName = buildIndexByColumnName(orderedColumns);
30 | return new ColumnNamesComparator(positionByColumnName);
31 | }
32 |
33 | private static Map buildIndexByColumnName(List orderedColumns) {
34 | final Map positionByColumnName = new HashMap<>();
35 | for (int i = 0; i < orderedColumns.size(); i++) {
36 | positionByColumnName.put(orderedColumns.get(i), i + 1);
37 | }
38 | return positionByColumnName;
39 | }
40 |
41 | @Override
42 | public int compare(String colName1, String colName2) {
43 | return findPositionOf(colName1) - findPositionOf(colName2);
44 | }
45 |
46 | private int findPositionOf(String colName1) {
47 | return positionByColumnName.get(colName1);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnNamesExtractor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import net.sf.jsqlparser.expression.BinaryExpression;
16 | import net.sf.jsqlparser.expression.Expression;
17 | import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
18 | import net.sf.jsqlparser.schema.Column;
19 |
20 | import java.util.ArrayList;
21 | import java.util.Collection;
22 | import java.util.HashSet;
23 | import java.util.Set;
24 |
25 | class ColumnNamesExtractor {
26 |
27 | static final ColumnNamesExtractor INSTANCE = new ColumnNamesExtractor();
28 |
29 | private ColumnNamesExtractor() {
30 | }
31 |
32 | private static class ColumnExpressionVisitor extends ExpressionVisitorAdapter {
33 |
34 | private String visitedColumnName;
35 |
36 | @Override
37 | public void visit(Column column) {
38 | this.visitedColumnName = column.getColumnName();
39 | }
40 |
41 | String getVisitedColumnName() {
42 | return visitedColumnName;
43 | }
44 |
45 | }
46 |
47 | Set findColumnNamesOf(Expression expression) {
48 | Set columnNames = new HashSet<>();
49 | if (expression instanceof BinaryExpression) {
50 | // AndExpression, OrExpression, LikeExpression, ...
51 | BinaryExpression binaryExpression = (BinaryExpression) expression;
52 | Collection leftRightColumnNames = extractColumnNamesOf(binaryExpression);
53 | columnNames.addAll(leftRightColumnNames);
54 | } else if (expression != null) {
55 | // Column names
56 | ColumnExpressionVisitor columnExpressionVisitor = new ColumnExpressionVisitor();
57 | expression.accept(columnExpressionVisitor);
58 | String visitedColumnName = columnExpressionVisitor.getVisitedColumnName();
59 | if(visitedColumnName != null) {
60 | columnNames.add(visitedColumnName);
61 | }
62 | }
63 | return columnNames;
64 | }
65 |
66 | private Collection extractColumnNamesOf(BinaryExpression binaryExpression) {
67 | Collection leftRightColumnNames = new ArrayList<>();
68 | Collection leftColumnNames = findColumnNamesOf(binaryExpression.getLeftExpression());
69 | Collection rightColumnNames = findColumnNamesOf(binaryExpression.getRightExpression());
70 | leftRightColumnNames.addAll(leftColumnNames);
71 | leftRightColumnNames.addAll(rightColumnNames);
72 | return leftRightColumnNames;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnOrdersFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.List;
16 |
17 | public interface ColumnOrdersFinder {
18 |
19 | List findDatabaseColumnOrdersOf(String tableName);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnValueFormatter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.time.OffsetDateTime;
16 | import java.time.format.DateTimeFormatter;
17 | import java.time.format.DateTimeFormatterBuilder;
18 | import org.qstd.dbtype.DatabaseType;
19 |
20 | import java.sql.Time;
21 | import java.sql.Timestamp;
22 | import java.time.OffsetTime;
23 | import java.util.Calendar;
24 |
25 | class ColumnValueFormatter {
26 |
27 | static final ColumnValueFormatter INSTANCE = new ColumnValueFormatter();
28 |
29 | private ColumnValueFormatter() { }
30 |
31 | String formatColumnValue(Object columnValue, DatabaseType dbType) {
32 | if(columnValue == null) {
33 | return "NULL";
34 | } else if(DatabaseType.ORACLE.equals(dbType)
35 | && columnValue instanceof Timestamp) {
36 | Timestamp timeStamp = (Timestamp) columnValue;
37 | return buildOracleToDateFunctionFor(timeStamp);
38 | } else if(DatabaseType.ORACLE.equals(dbType)
39 | && isOracleSqlTimestamp(columnValue)) {
40 | return buildOracleToTimeStampFunctionFor(columnValue);
41 | }else if(DatabaseType.HSQLDB.equals(dbType)
42 | && columnValue instanceof OffsetDateTime){
43 | OffsetDateTime offsetDateTime = (OffsetDateTime) columnValue;
44 | return formatForHsqlDBOffsetDateTime(offsetDateTime);
45 | } else if (columnValue instanceof String
46 | || columnValue instanceof java.sql.Date
47 | || columnValue instanceof Timestamp
48 | || columnValue instanceof Time
49 | || columnValue instanceof OffsetTime
50 | || isTimestampWithTimeZoneH2Type(columnValue)
51 | || isMicrosoftDateTimeOffset(columnValue)) {
52 | String stringColumnValue = columnValue.toString();
53 | return "'" + stringColumnValue + "'";
54 | }
55 | return columnValue.toString();
56 | }
57 |
58 | private boolean isMicrosoftDateTimeOffset(Object columnValue) {
59 | Class> columnValueClass = columnValue.getClass();
60 | String classCanonicalName = columnValueClass.getCanonicalName();
61 | return "microsoft.sql.DateTimeOffset".equals(classCanonicalName);
62 | }
63 |
64 | private String formatForHsqlDBOffsetDateTime(OffsetDateTime offsetDateTime) {
65 | DateTimeFormatter fmt = new DateTimeFormatterBuilder()
66 | .appendPattern("yyyy-MM-dd HH:mm:ss")
67 | .parseLenient()
68 | .appendOffset("+HH:MM", "Z")
69 | .toFormatter();
70 | return "'" + fmt.format(offsetDateTime) + "'";
71 | }
72 |
73 | private String buildOracleToDateFunctionFor(Timestamp timeStamp) {
74 | //https://stackoverflow.com/questions/9180014/using-oracle-to-date-function-for-date-string-with-milliseconds
75 | // "An Oracle DATE does not store times with more precision than a second."
76 | Calendar calendar = Calendar.getInstance();
77 | calendar.setTime(timeStamp);
78 | int monthNumber = calendar.get(Calendar.MONTH) + 1;
79 | int secondNumber = calendar.get(Calendar.SECOND);
80 | String toDateString = calendar.get(Calendar.YEAR)
81 | + "-" + (monthNumber < 10 ? "0" : "") + monthNumber
82 | + "-" + calendar.get(Calendar.DAY_OF_MONTH)
83 | + "-" + calendar.get(Calendar.HOUR_OF_DAY)
84 | + "-" + calendar.get(Calendar.MINUTE)
85 | + "-" + (secondNumber < 10 ? "0" : "") + secondNumber;
86 | return "TO_DATE('" + toDateString + "', 'yyyy-mm-dd-HH24-mi-ss')";
87 | }
88 |
89 | private boolean isOracleSqlTimestamp(Object columnValue) {
90 | Class> columnValueClass = columnValue.getClass();
91 | String classCanonicalName = columnValueClass.getCanonicalName();
92 | return classCanonicalName.equals("oracle.sql.TIMESTAMP");
93 | }
94 |
95 | private String buildOracleToTimeStampFunctionFor(Object columnValue) {
96 | String oracleTimeStampAsString = columnValue.toString();
97 | String aDateWithMsLessThan100 = "2012-09-17 19:56:47.10";
98 | boolean dateHasMsLessThan100 = oracleTimeStampAsString.length() == aDateWithMsLessThan100.length();
99 | String dateForTimeStampCreation = dateHasMsLessThan100 ? oracleTimeStampAsString + "0" : oracleTimeStampAsString;
100 | return "TO_TIMESTAMP('" + dateForTimeStampCreation
101 | + "', 'YYYY-MM-DD HH24:MI:SS.FF')";
102 | }
103 |
104 | private boolean isTimestampWithTimeZoneH2Type(Object columnValue) {
105 | Class> columnValueClass = columnValue.getClass();
106 | String classCanonicalName = columnValueClass.getCanonicalName();
107 | return classCanonicalName.equals("org.h2.api.TimestampWithTimeZone");
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnsMapping.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | public class ColumnsMapping {
16 |
17 | private final ColumnMappingPart columnMappingPart1;
18 |
19 | private final ColumnMappingPart columnMappingPart2;
20 |
21 | public ColumnsMapping(ColumnMappingPart columnMappingPart1, ColumnMappingPart columnMappingPart2) {
22 | this.columnMappingPart1 = columnMappingPart1;
23 | this.columnMappingPart2 = columnMappingPart2;
24 | }
25 |
26 | boolean hasMappingForColumn(String columnName) {
27 | return columnMappingPart1.hasColumn(columnName);
28 | }
29 |
30 | ColumnMappingPart getMapping() {
31 | return columnMappingPart2;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnsMappingGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.ArrayList;
16 | import java.util.Collection;
17 | import java.util.Collections;
18 | import java.util.Optional;
19 |
20 | public class ColumnsMappingGroup {
21 |
22 | public static final ColumnsMappingGroup NO_MAPPING = new ColumnsMappingGroup(Collections.emptyList());
23 |
24 | private final Collection columnsMappings;
25 |
26 | public ColumnsMappingGroup(Collection columnsMappings) {
27 | this.columnsMappings = new ArrayList<>(columnsMappings);
28 | }
29 |
30 | Optional findMappingForColumn(String columnName) {
31 | return columnsMappings
32 | .stream()
33 | .filter(columnsMapping -> columnsMapping.hasMappingForColumn(columnName))
34 | .map(ColumnsMapping::getMapping)
35 | .findFirst();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ColumnsMappingsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | public interface ColumnsMappingsFinder {
16 |
17 | ColumnsMappingGroup findColumnsMappingsOf(String tableName);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DatabaseMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseMetadataFinderFactory;
16 | import org.qstd.dbtype.DatabaseMetadataFinderWithCache;
17 |
18 | import java.util.function.Function;
19 |
20 | /**
21 | * Interface describing the methods needed by the library to retrieve some database metadata.
22 | *
23 | * @see DatabaseMetadataFinderFactory
24 | * @see DatabaseMetadataFinderWithCache
25 | */
26 | public interface DatabaseMetadataFinder extends NotNullColumnsFinder
27 | , ColumnOrdersFinder
28 | , ReferencedTablesFinder
29 | , ColumnsMappingsFinder
30 | , PrimaryKeyColumnsFinder {
31 |
32 | default Function getFunctionToHaveMetadataTableName() {
33 | return tableName -> tableName;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DatasetRow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.*;
16 | import java.util.function.Function;
17 | import java.util.stream.Stream;
18 |
19 | import static java.util.stream.Collectors.toList;
20 |
21 | public class DatasetRow {
22 |
23 | private String tableName;
24 |
25 | private TreeMap columnValueByColumnName = new TreeMap<>();
26 |
27 | private DatasetRow(String tableName) {
28 | this.tableName = tableName;
29 | }
30 |
31 | public static DatasetRow ofTable(String tableName) {
32 | return new DatasetRow(tableName);
33 | }
34 |
35 | protected void addColumnValues(Map columnValues) {
36 | columnValueByColumnName.putAll(columnValues);
37 | }
38 |
39 | Set getColumnNames() {
40 | return columnValueByColumnName.keySet();
41 | }
42 |
43 | Collection getColumnValues() {
44 | return columnValueByColumnName.values();
45 | }
46 |
47 | Map getColumnValueByColumnName() {
48 | return new HashMap<>(columnValueByColumnName);
49 | }
50 |
51 | boolean hasNotNullValueForColumn(String columnName) {
52 | return columnValueByColumnName.get(columnName) != null;
53 | }
54 |
55 | void sortColumnsFollowing(List databaseColumnOrders) {
56 | if (!databaseColumnOrders.isEmpty()) {
57 | ColumnNamesComparator columnNamesComparator = ColumnNamesComparator.from(databaseColumnOrders);
58 | TreeMap columnValueByColumnName = new TreeMap<>(columnNamesComparator);
59 | columnValueByColumnName.putAll(this.columnValueByColumnName);
60 | this.columnValueByColumnName = columnValueByColumnName;
61 | }
62 | }
63 |
64 | boolean mergeWithARowOf(Collection datasetRows) {
65 | Optional optionalRowToMergeWith = searchARowToMergeIn(datasetRows);
66 | if(optionalRowToMergeWith.isPresent()) {
67 | DatasetRow rowToMergeWith = optionalRowToMergeWith.get();
68 | rowToMergeWith.addValuesOf(this);
69 | return true;
70 | }
71 | return false;
72 | }
73 |
74 | private Optional searchARowToMergeIn(Collection datasetRows) {
75 | return datasetRows
76 | .stream()
77 | .filter(this::isMergeableWith)
78 | .findFirst();
79 | }
80 |
81 | void addValuesOf(DatasetRow datasetRow) {
82 | TreeMap columnValueByColumnName = datasetRow.columnValueByColumnName;
83 | for (Map.Entry columnValueOfColumnName : columnValueByColumnName.entrySet()) {
84 | Object value = columnValueOfColumnName.getValue();
85 | if(value != null) {
86 | String columnName = columnValueOfColumnName.getKey();
87 | this.columnValueByColumnName.put(columnName, value);
88 | }
89 | }
90 | }
91 |
92 | boolean isMergeableWith(DatasetRow otherDatasetRow) {
93 | if(!this.tableName.equals(otherDatasetRow.getTableName())) {
94 | return false;
95 | }
96 | return sameNotNullColumns(otherDatasetRow);
97 | }
98 |
99 | String getTableName() {
100 | return tableName;
101 | }
102 |
103 | private boolean sameNotNullColumns(DatasetRow otherDatasetRow) {
104 | TreeMap columnValueByColumnName = otherDatasetRow.columnValueByColumnName;
105 | for (Map.Entry columnValueOfColumnName : columnValueByColumnName.entrySet()) {
106 | Object mergeableValue = columnValueOfColumnName.getValue();
107 | if(mergeableValue != null) {
108 | String column = columnValueOfColumnName.getKey();
109 | Object value = this.columnValueByColumnName.get(column);
110 | if(!mergeableValue.equals(value) && value != null) {
111 | return false;
112 | }
113 | }
114 | }
115 |
116 | return true;
117 | }
118 |
119 | Collection extractJoinedRowsFrom(ColumnsMappingGroup columnsMappingGroup) {
120 | return columnValueByColumnName
121 | .entrySet()
122 | .stream()
123 | .map(valueForColumn -> {
124 | String column = valueForColumn.getKey();
125 | Optional optionalMappingForColumn =
126 | columnsMappingGroup.findMappingForColumn(column);
127 | return buildOptionalRowFrom(valueForColumn, optionalMappingForColumn);
128 | })
129 | .flatMap(DatasetRow::streamOf)
130 | .collect(toList());
131 | }
132 |
133 | private Optional buildOptionalRowFrom(Map.Entry valueForColumn, Optional optionalMappingForColumn) {
134 | return optionalMappingForColumn.map(columnMappingPart -> {
135 | Object value = valueForColumn.getValue();
136 | DatasetRow joinedRow = new DatasetRow(columnMappingPart.tableName);
137 | joinedRow.addColumnValue(columnMappingPart.tableColumn, value);
138 | return joinedRow;
139 | });
140 | }
141 |
142 | private static Stream streamOf(Optional optional) {
143 | return optional.map(Stream::of).orElseGet(Stream::empty);
144 | }
145 |
146 | public DatasetRow addColumnValue(String columnName, Object value) {
147 | columnValueByColumnName.put(columnName, value);
148 | return this;
149 | }
150 |
151 | Object getValueOf(String columnName) {
152 | return columnValueByColumnName.get(columnName);
153 | }
154 |
155 | void updateTableNameWith(Function tableNameFunction) {
156 | String newTableName = tableNameFunction.apply(tableName);
157 | tableName = newTableName;
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DatasetRowComparatorBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.math.BigDecimal;
16 | import java.util.Comparator;
17 | import java.util.List;
18 |
19 | class DatasetRowComparatorBuilder {
20 |
21 | private DatasetRowComparatorBuilder() { }
22 |
23 | static Comparator buildFrom(DatabaseMetadataFinder databaseMetadataFinder) {
24 | ComparatorOnTableDependencies comparatorOnTableDependencies = new ComparatorOnTableDependencies(databaseMetadataFinder);
25 | ComparatorOnPrimaryKey comparatorOnPrimaryKey = new ComparatorOnPrimaryKey(databaseMetadataFinder);
26 | ComparatorOnTableName comparatorOnTableName = new ComparatorOnTableName();
27 | return comparatorOnTableDependencies.thenComparing(comparatorOnPrimaryKey)
28 | .thenComparing(comparatorOnTableName);
29 | }
30 |
31 | private static class ComparatorOnPrimaryKey implements Comparator {
32 |
33 | private final PrimaryKeyColumnsFinder primaryKeyColumnsFinder;
34 |
35 | ComparatorOnPrimaryKey(PrimaryKeyColumnsFinder primaryKeyColumnsFinder) {
36 | this.primaryKeyColumnsFinder = primaryKeyColumnsFinder;
37 | }
38 |
39 | @Override
40 | public int compare(DatasetRow datasetRow1, DatasetRow datasetRow2) {
41 |
42 | if(!sameTableNames(datasetRow1, datasetRow2)) {
43 | return 0;
44 | }
45 |
46 | String tableName = datasetRow1.getTableName();
47 | List primaryKeyColumns = primaryKeyColumnsFinder.findPrimaryColumnsOf(tableName);
48 |
49 | for (String primaryKeyColumn : primaryKeyColumns) {
50 | int intComparison = compareIntPkValues(primaryKeyColumn, datasetRow1, datasetRow2);
51 | if(intComparison != 0) {
52 | return intComparison;
53 | }
54 | }
55 |
56 | return 0;
57 |
58 | }
59 |
60 | private boolean sameTableNames(DatasetRow datasetRow1, DatasetRow datasetRow2) {
61 | return datasetRow1.getTableName().equals(datasetRow2.getTableName());
62 | }
63 |
64 | private int compareIntPkValues(String primaryKeyColumn, DatasetRow datasetRow1, DatasetRow datasetRow2) {
65 | Object pkValue1 = datasetRow1.getValueOf(primaryKeyColumn);
66 | Object pkValue2 = datasetRow2.getValueOf(primaryKeyColumn);
67 | boolean integerPrimaryKey = pkValue1 instanceof Integer
68 | || pkValue1 instanceof Long
69 | || pkValue1 instanceof BigDecimal;
70 | if(integerPrimaryKey) {
71 | Number pkValue1AsNumber = (Number) pkValue1;
72 | Number pkValue2AsNumber = (Number) pkValue2;
73 | long pkValue1AsLong = pkValue1AsNumber.longValue();
74 | long pkValue2AsLong = pkValue2AsNumber.longValue();
75 | return Long.compare(pkValue1AsLong, pkValue2AsLong );
76 | }
77 | return 0;
78 | }
79 |
80 | }
81 |
82 | private static class ComparatorOnTableDependencies implements Comparator {
83 |
84 | private final ReferencedTablesFinder referencedTablesFinder;
85 |
86 | public ComparatorOnTableDependencies(ReferencedTablesFinder referencedTablesFinder) {
87 | this.referencedTablesFinder = referencedTablesFinder;
88 | }
89 |
90 | @Override
91 | public int compare(DatasetRow datasetRow1, DatasetRow datasetRow2) {
92 |
93 | String tableName1 = datasetRow1.getTableName();
94 | String tableName2 = datasetRow2.getTableName();
95 |
96 | ReferencedTableSet referencedTableSetOfTable1
97 | = referencedTablesFinder.findReferencedTablesOf(tableName1);
98 | if(referencedTableSetOfTable1.referencesTable(tableName2)) {
99 | return 1;
100 | }
101 |
102 | ReferencedTableSet referencedTableSetOfTable2
103 | = referencedTablesFinder.findReferencedTablesOf(tableName2);
104 | if(referencedTableSetOfTable2.referencesTable(tableName1)) {
105 | return -1;
106 | }
107 |
108 | return 0;
109 |
110 | }
111 |
112 | }
113 |
114 | private static class ComparatorOnTableName implements Comparator {
115 |
116 | @Override
117 | public int compare(DatasetRow row1, DatasetRow row2) {
118 | String row1TableName = row1.getTableName();
119 | String row2TableName = row2.getTableName();
120 | return row1TableName.compareTo(row2TableName);
121 | }
122 |
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DatasetRowSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseType;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.*;
19 | import java.util.function.Function;
20 |
21 | class DatasetRowSet {
22 |
23 | private final MissingNotNullColumnsFinder missingNotNullColumnsFinder;
24 |
25 | private final DatabaseMetadataFinder databaseMetadataFinder;
26 |
27 | private final Collection datasetRows = new ArrayDeque<>();
28 |
29 | DatasetRowSet( DataSource dataSource
30 | , DatabaseType dbType
31 | , DatabaseMetadataFinder databaseMetadataFinder) {
32 | this.databaseMetadataFinder = databaseMetadataFinder;
33 | this.missingNotNullColumnsFinder = new MissingNotNullColumnsFinder(dataSource
34 | , dbType
35 | , databaseMetadataFinder);
36 | }
37 |
38 | void add(Collection datasetRows) {
39 | for (DatasetRow datasetRow : datasetRows) {
40 | add(datasetRow);
41 | }
42 | }
43 |
44 | private void add(DatasetRow datasetRow) {
45 |
46 | Function functionToHaveMetadataTableName = databaseMetadataFinder.getFunctionToHaveMetadataTableName();
47 | datasetRow.updateTableNameWith(functionToHaveMetadataTableName);
48 |
49 | boolean rowIsMerged = datasetRow.mergeWithARowOf(datasetRows);
50 |
51 | if (!rowIsMerged) {
52 | Map missingNotNullColumns =
53 | missingNotNullColumnsFinder.findMissingNoNullColumnsOf(datasetRow);
54 | datasetRow.addColumnValues(missingNotNullColumns);
55 |
56 | datasetRows.add(datasetRow);
57 |
58 | Collection joinedRows = findJoinedRowsOf(datasetRow);
59 | for (DatasetRow joinRow : joinedRows) {
60 | add(joinRow);
61 | }
62 | }
63 |
64 | }
65 |
66 | private Collection findJoinedRowsOf(DatasetRow datasetRow) {
67 | String tableName = datasetRow.getTableName();
68 | ColumnsMappingGroup columnsMappingGroup =
69 | databaseMetadataFinder.findColumnsMappingsOf(tableName);
70 | return datasetRow.extractJoinedRowsFrom(columnsMappingGroup);
71 | }
72 |
73 | List sort() {
74 | sortColumnsFollowingDatabaseDeclaration(datasetRows);
75 | return sortRows();
76 | }
77 |
78 | private void sortColumnsFollowingDatabaseDeclaration(Collection allRows) {
79 | for (DatasetRow datasetRow : allRows) {
80 | String tableName = datasetRow.getTableName();
81 | List databaseColumnOrders = databaseMetadataFinder.findDatabaseColumnOrdersOf(tableName);
82 | datasetRow.sortColumnsFollowing(databaseColumnOrders);
83 | }
84 | }
85 |
86 | private List sortRows() {
87 | List rowsAsList = new ArrayList<>(datasetRows);
88 | Comparator datasetRowComparator =
89 | DatasetRowComparatorBuilder.buildFrom(databaseMetadataFinder);
90 | rowsAsList.sort(datasetRowComparator);
91 | return rowsAsList;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DatasetRowsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import net.sf.jsqlparser.JSQLParserException;
16 | import net.sf.jsqlparser.parser.CCJSqlParserUtil;
17 | import net.sf.jsqlparser.statement.Statement;
18 | import net.sf.jsqlparser.statement.select.Select;
19 | import net.sf.jsqlparser.util.TablesNamesFinder;
20 |
21 | import javax.sql.DataSource;
22 | import java.sql.*;
23 | import java.util.*;
24 |
25 | import static java.util.Collections.emptyList;
26 | import static org.qstd.SelectTransformerFactory.createSelectTransformer;
27 |
28 | class DatasetRowsFinder {
29 |
30 | private final DataSource dataSource;
31 |
32 | DatasetRowsFinder(DataSource dataSource) {
33 | this.dataSource = dataSource;
34 | }
35 |
36 | Collection findDatasetRowsOf(SqlQuery sqlQuery) {
37 |
38 | SelectTransformer selectTransformer = createSelectTransformer(sqlQuery);
39 | Optional optionalSelectQuery = selectTransformer.toSelect(sqlQuery);
40 |
41 | if (optionalSelectQuery.isPresent()) {
42 | SqlQuery selectQuery = optionalSelectQuery.get();
43 | return execute(selectQuery);
44 | }
45 |
46 | return emptyList();
47 | }
48 |
49 | private Collection execute(SqlQuery sqlQuery) {
50 |
51 | List datasetRowsToReturn = new ArrayList<>();
52 |
53 | try (Connection connection = dataSource.getConnection();
54 | PreparedStatement selectStatement = PreparedStatementBuilder.buildFrom(sqlQuery, connection)) {
55 |
56 | ResultSet resultSet = selectStatement.executeQuery();
57 |
58 | ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
59 | int columnCount = resultSetMetaData.getColumnCount();
60 |
61 | while (resultSet.next()) {
62 | Collection datasetRows =
63 | buildDatasetRowsFrom(resultSet, resultSetMetaData
64 | , columnCount, sqlQuery);
65 | datasetRowsToReturn.addAll(datasetRows);
66 | }
67 | } catch (SQLException sqlException) {
68 | sqlException.printStackTrace();
69 | }
70 |
71 | return datasetRowsToReturn;
72 |
73 | }
74 |
75 | private Collection buildDatasetRowsFrom(ResultSet resultSet, ResultSetMetaData resultSetMetaData
76 | , int columnCount, SqlQuery sqlQuery) throws SQLException {
77 | Map rowsByTableName = new HashMap<>();
78 | for (int colIndex = 1; colIndex <= columnCount; colIndex++) {
79 | final String tableName = findTableName(resultSetMetaData, colIndex, sqlQuery);
80 | DatasetRow datasetRow =
81 | rowsByTableName.computeIfAbsent(tableName
82 | , t -> DatasetRow.ofTable(tableName));
83 |
84 | String column = resultSetMetaData.getColumnName(colIndex);
85 | Object value = resultSet.getObject(colIndex);
86 | datasetRow.addColumnValue(column, value);
87 | }
88 | return rowsByTableName.values();
89 | }
90 |
91 | private String findTableName(ResultSetMetaData resultSetMetaData, int colIndex, SqlQuery sqlQuery) throws SQLException {
92 | String tableName = resultSetMetaData.getTableName(colIndex);
93 | if (!tableName.isEmpty()) {
94 | return tableName;
95 | }
96 | String queryAsString = sqlQuery.getQueryAsString();
97 | return extractTableNameFrom(queryAsString);
98 | }
99 |
100 | private String extractTableNameFrom(String sqlQueryAsString) {
101 | try {
102 | Statement statement = CCJSqlParserUtil.parse(sqlQueryAsString);
103 | Select select = (Select) statement;
104 | TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
105 | List tableList = tablesNamesFinder.getTableList(select);
106 | if(tableList.size() == 1) {
107 | return tableList.get(0);
108 | }
109 | } catch (JSQLParserException e) {
110 | e.printStackTrace();
111 | }
112 | return "";
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DatasetRowsGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseType;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.List;
20 |
21 | class DatasetRowsGenerator {
22 |
23 | private final DataSource dataSource;
24 |
25 | private final DatabaseType dbType;
26 |
27 | private final DatabaseMetadataFinder databaseMetadataFinder;
28 |
29 | private final DatasetRowsFinder datasetRowsFinder;
30 |
31 | DatasetRowsGenerator(DataSource dataSource
32 | , DatabaseType dbType
33 | , DatabaseMetadataFinder databaseMetadataFinder) {
34 | this.dataSource = dataSource;
35 | this.dbType = dbType;
36 | this.databaseMetadataFinder = databaseMetadataFinder;
37 | this.datasetRowsFinder = new DatasetRowsFinder(dataSource);
38 | }
39 |
40 | List generateDatasetRowsFor(List sqlQueries) {
41 | DatasetRowSet datasetRowSet = new DatasetRowSet(dataSource, dbType, databaseMetadataFinder);
42 | for (SqlQuery sqlQuery : sqlQueries) {
43 | Collection datasetRows = datasetRowsFinder.findDatasetRowsOf(sqlQuery);
44 | datasetRowSet.add(datasetRows);
45 | }
46 | return datasetRowSet.sort();
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/DeleteToSelectTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import net.sf.jsqlparser.expression.Expression;
16 | import net.sf.jsqlparser.statement.delete.Delete;
17 |
18 | import java.util.Optional;
19 |
20 | class DeleteToSelectTransformer implements SelectTransformer {
21 |
22 | private Delete deleteStatement;
23 |
24 | DeleteToSelectTransformer(Delete delete) {
25 | deleteStatement = delete;
26 | }
27 |
28 | @Override
29 | public Optional toSelect(SqlQuery sqlQuery) {
30 | String deleteAsString = sqlQuery.getQueryAsString();
31 | String deleteString = toSelect(deleteAsString);
32 | SqlQuery deleteQuery = new SqlQuery(deleteString);
33 | return Optional.of(deleteQuery);
34 | }
35 |
36 | private String toSelect(String sqlQueryAsString) {
37 | String tableName = deleteStatement.getTable().getName();
38 |
39 | String whereClauseAsString = findWhereClauseAsString();
40 |
41 | return " SELECT " + "*"
42 | + " FROM " + tableName
43 | + whereClauseAsString;
44 | }
45 |
46 | private String findWhereClauseAsString() {
47 | Expression whereExpression = deleteStatement.getWhere();
48 | String whereClauseAsString = whereExpression == null ? ""
49 | :" WHERE " + whereExpression;
50 | return whereClauseAsString;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/InsertStatementsGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseType;
16 |
17 | import java.util.Collection;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | import static java.lang.System.lineSeparator;
22 | import static java.util.stream.Collectors.joining;
23 | import static java.util.stream.Collectors.toList;
24 |
25 | class InsertStatementsGenerator {
26 |
27 | private final DatabaseType dbType;
28 |
29 | InsertStatementsGenerator(DatabaseType dbType) {
30 | this.dbType = dbType;
31 | }
32 |
33 | String generateInsertScriptFor(List datasetRows) {
34 | return datasetRows
35 | .stream()
36 | .map(this::generateInsertStatementFrom)
37 | .map(insertStatement -> insertStatement + ";" + lineSeparator())
38 | .collect(joining());
39 | }
40 |
41 | private String generateInsertStatementFrom(DatasetRow datasetRow) {
42 | String tableName = datasetRow.getTableName();
43 | Set columnNames = datasetRow.getColumnNames();
44 | Collection columnValues = datasetRow.getColumnValues();
45 | return "INSERT INTO " + tableName + "(" + formatColumnNames(columnNames) + ")"
46 | + " VALUES(" + formatColumnValues(columnValues) + ")";
47 | }
48 |
49 | private String formatColumnNames(Set columnNames) {
50 | return String.join(", ", columnNames);
51 | }
52 |
53 | private String formatColumnValues(Collection columnValues) {
54 | return columnValues
55 | .stream()
56 | .map(columnValue -> ColumnValueFormatter.INSTANCE
57 | .formatColumnValue(columnValue, dbType))
58 | .collect(joining(", "));
59 | }
60 |
61 | List generateInsertStatementsFor(List datasetRows) {
62 | return datasetRows
63 | .stream()
64 | .map(this::generateInsertStatementFrom)
65 | .collect(toList());
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/MissingNotNullColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseType;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.Collections;
20 | import java.util.Map;
21 |
22 | import static java.util.stream.Collectors.toList;
23 |
24 | class MissingNotNullColumnsFinder {
25 |
26 | private final DataSource dataSource;
27 |
28 | private final DatabaseType dbType;
29 |
30 | private final DatabaseMetadataFinder databaseMetadataFinder;
31 |
32 | MissingNotNullColumnsFinder(DataSource dataSource, DatabaseType dbType, DatabaseMetadataFinder databaseMetadataFinder) {
33 | this.dataSource = dataSource;
34 | this.dbType = dbType;
35 | this.databaseMetadataFinder = databaseMetadataFinder;
36 | }
37 |
38 | Map findMissingNoNullColumnsOf(DatasetRow datasetRow) {
39 |
40 | String tableName = datasetRow.getTableName();
41 |
42 | Collection notNullColumns = databaseMetadataFinder.findNotNullColumnsOf(tableName);
43 |
44 | Collection missingNotNullColumns = notNullColumns
45 | .stream()
46 | .filter(columnName -> !datasetRow.hasNotNullValueForColumn(columnName))
47 | .collect(toList());
48 |
49 | if (!missingNotNullColumns.isEmpty()) {
50 | RowFinder rowFinder = new RowFinder(dataSource, dbType);
51 | DatasetRow datasetRowWithMissingNotNullColumns = rowFinder.findOneRowFrom(datasetRow.getTableName(), missingNotNullColumns, datasetRow);
52 | return datasetRowWithMissingNotNullColumns.getColumnValueByColumnName();
53 | }
54 |
55 | return Collections.emptyMap();
56 |
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/NotNullColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.Collection;
16 |
17 | public interface NotNullColumnsFinder {
18 |
19 | Collection findNotNullColumnsOf(String tableName);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/PreparedStatementBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.sql.Connection;
16 | import java.sql.PreparedStatement;
17 | import java.sql.SQLException;
18 | import java.util.List;
19 |
20 | public class PreparedStatementBuilder {
21 |
22 | private PreparedStatementBuilder() {
23 | }
24 |
25 | public static PreparedStatement buildFrom(SqlQuery sqlQuery, Connection connection) throws SQLException {
26 | String queryAsString = sqlQuery.getQueryAsString();
27 | PreparedStatement preparedStatement = connection.prepareStatement(queryAsString);
28 | List parameters = sqlQuery.getParameters();
29 | for (int i = 0; i < parameters.size(); i++) {
30 | preparedStatement.setObject(i + 1, parameters.get(i));
31 | }
32 | return preparedStatement;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/PrimaryKeyColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.List;
16 |
17 | public interface PrimaryKeyColumnsFinder {
18 |
19 | List findPrimaryColumnsOf(String tableName);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ReferencedTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | public class ReferencedTable {
16 |
17 | private final String tableName;
18 |
19 | private final String referencedTableName;
20 |
21 | private final int level;
22 |
23 | public ReferencedTable(String tableName, String referencedTableName, int level) {
24 | this.tableName = tableName;
25 | this.referencedTableName = referencedTableName;
26 | this.level = level;
27 | }
28 |
29 | boolean references(String tableName) {
30 | return tableName.equals(referencedTableName);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ReferencedTableSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.Collection;
16 |
17 | import static java.util.Collections.emptyList;
18 |
19 | public class ReferencedTableSet {
20 |
21 | public static final ReferencedTableSet NONE = new ReferencedTableSet(emptyList());
22 |
23 | private final Collection referencedTablesOfTable;
24 |
25 | public ReferencedTableSet(Collection referencedTablesOfTable) {
26 | this.referencedTablesOfTable = referencedTablesOfTable;
27 | }
28 |
29 | boolean referencesTable(String tableName) {
30 | for (ReferencedTable referencedTable : referencedTablesOfTable) {
31 | if (referencedTable.references(tableName)) {
32 | return true;
33 | }
34 | }
35 | return false;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/ReferencedTablesFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | public interface ReferencedTablesFinder {
16 |
17 | ReferencedTableSet findReferencedTablesOf(String tableName);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/RowFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseType;
16 |
17 | import javax.sql.DataSource;
18 | import java.sql.Connection;
19 | import java.sql.PreparedStatement;
20 | import java.sql.ResultSet;
21 | import java.sql.SQLException;
22 | import java.util.Collection;
23 |
24 | class RowFinder {
25 |
26 | private final DataSource dataSource;
27 |
28 | private final DatabaseType dbType;
29 |
30 | RowFinder(DataSource dataSource, DatabaseType dbType) {
31 | this.dataSource = dataSource;
32 | this.dbType = dbType;
33 | }
34 |
35 | DatasetRow findOneRowFrom(String tableName
36 | , Collection columnNamesToSearch
37 | , DatasetRow rowToSearch) {
38 |
39 | SqlQuery missingColumnValuesQuery =
40 | SqlQuery.buildFromRow(columnNamesToSearch, rowToSearch, dbType);
41 |
42 | DatasetRow missingColumnValues = DatasetRow.ofTable(tableName);
43 | try (Connection connection = dataSource.getConnection();
44 | PreparedStatement missingColumnStatement = PreparedStatementBuilder.buildFrom(missingColumnValuesQuery, connection)) {
45 | ResultSet queryResult = missingColumnStatement.executeQuery();
46 |
47 | queryResult.next(); // We keep only the first row found
48 |
49 | for (String missingColumnName : columnNamesToSearch) {
50 | Object columnValue = queryResult.getObject(missingColumnName);
51 | missingColumnValues.addColumnValue(missingColumnName, columnValue);
52 | }
53 | } catch (SQLException sqlException) {
54 | System.err.println("Unable to execute " + missingColumnValuesQuery);
55 | sqlException.printStackTrace();
56 | }
57 | return missingColumnValues;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/SelectTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import java.util.Optional;
16 |
17 | interface SelectTransformer {
18 |
19 | SelectTransformer NO_SELECT_TRANSFORMER = new SelectTransformer() {
20 | @Override
21 | public Optional toSelect(SqlQuery sqlQuery) {
22 | return Optional.empty();
23 | }
24 | };
25 |
26 | Optional toSelect(SqlQuery sqlQuery);
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/SelectTransformerFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import net.sf.jsqlparser.JSQLParserException;
16 | import net.sf.jsqlparser.parser.CCJSqlParserUtil;
17 | import net.sf.jsqlparser.statement.Statement;
18 | import net.sf.jsqlparser.statement.delete.Delete;
19 | import net.sf.jsqlparser.statement.select.Select;
20 | import net.sf.jsqlparser.statement.update.Update;
21 |
22 | import java.util.Optional;
23 |
24 | class SelectTransformerFactory {
25 |
26 | private SelectTransformerFactory() {
27 | }
28 |
29 | private static final SelectTransformer SELECT_TO_SELECT_TRANSFORMER =
30 |
31 | new SelectTransformer() {
32 | @Override
33 | public Optional toSelect(SqlQuery sqlQuery) {
34 | return Optional.of(sqlQuery);
35 | }
36 | };
37 |
38 | static SelectTransformer createSelectTransformer(SqlQuery sqlQuery) {
39 |
40 | String sqlQueryAsString = sqlQuery.getQueryAsString();
41 | Statement statement = parse(sqlQueryAsString);
42 |
43 | if(statement instanceof Select) {
44 | return SELECT_TO_SELECT_TRANSFORMER;
45 | }
46 | if(statement instanceof Update) {
47 | Update update = (Update) statement;
48 | return new UpdateToSelectTransformer(update);
49 | }
50 | if(statement instanceof Delete) {
51 | Delete delete = (Delete) statement;
52 | return new DeleteToSelectTransformer(delete);
53 | }
54 |
55 | return SelectTransformer.NO_SELECT_TRANSFORMER;
56 | }
57 |
58 | private static Statement parse(String sqlQuery) {
59 | try {
60 | return CCJSqlParserUtil.parse(sqlQuery);
61 | } catch (JSQLParserException e) {
62 | e.printStackTrace();
63 | return null;
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/SqlQuery.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import org.qstd.dbtype.DatabaseType;
16 |
17 | import java.util.*;
18 |
19 | import static java.util.stream.Collectors.joining;
20 |
21 | /**
22 | * Class to represent an SQL query
23 | */
24 | public class SqlQuery {
25 |
26 | private final String queryAsString;
27 |
28 | private final List parameters;
29 |
30 | /**
31 | * Constructor to instantiate an SQL Query from an SQL query as String
32 | * @param queryAsString An SQL query as string
33 | */
34 | public SqlQuery(String queryAsString) {
35 | this.queryAsString = queryAsString;
36 | this.parameters = Collections.emptyList();
37 | }
38 |
39 | /**
40 | * Constructor to instantiate an SQL query from an SQL query with bind parameters and its bind parameter values
41 | * @param queryAsString An SQL query as String with bind parameters
42 | * @param parameters Bind parameter values
43 | */
44 | public SqlQuery(String queryAsString, List parameters) {
45 | this.queryAsString = queryAsString;
46 | this.parameters = parameters;
47 | }
48 |
49 | static SqlQuery buildFromRow(DatasetRow rowToSearch, DatabaseType dbType) {
50 | Set columnNames = rowToSearch.getColumnNames();
51 | return buildFromRow(columnNames, rowToSearch, dbType);
52 |
53 | }
54 |
55 | static SqlQuery buildFromRow(Collection columnNamesToSearch
56 | , DatasetRow rowToSearch
57 | , DatabaseType dbType) {
58 | Map valuesToMatch = rowToSearch.getColumnValueByColumnName();
59 | String whereConditions =
60 | valuesToMatch.entrySet()
61 | .stream()
62 | .map(entry -> {
63 | String columnName = entry.getKey();
64 | return columnName
65 | + (entry.getValue() == null
66 | ? " IS NULL"
67 | : "=" + ColumnValueFormatter.INSTANCE
68 | .formatColumnValue(entry.getValue(), dbType));
69 | })
70 | .collect(joining(" AND "));
71 | String queryAsString =
72 | "SELECT "
73 | + String.join(", ", columnNamesToSearch)
74 | + " FROM " + rowToSearch.getTableName()
75 | + " WHERE " + whereConditions;
76 | return new SqlQuery(queryAsString);
77 |
78 | }
79 |
80 | @Override
81 | public String toString() {
82 | return getQueryAsString();
83 | }
84 |
85 | String getQueryAsString() {
86 | return queryAsString;
87 | }
88 |
89 | List getParameters() {
90 | return parameters;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/UpdateToSelectTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd;
14 |
15 | import net.sf.jsqlparser.expression.Expression;
16 | import net.sf.jsqlparser.schema.Column;
17 | import net.sf.jsqlparser.statement.update.Update;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collection;
21 | import java.util.List;
22 | import java.util.Optional;
23 |
24 | import static java.util.stream.Collectors.toList;
25 |
26 | class UpdateToSelectTransformer implements SelectTransformer {
27 |
28 | private Update updateStatement;
29 |
30 | UpdateToSelectTransformer(Update update) {
31 | updateStatement = update;
32 | }
33 |
34 | @Override
35 | public Optional toSelect(SqlQuery sqlQuery) {
36 | String tableName = updateStatement.getTable().getName();
37 | String selectAsString = " SELECT " + findSelectedColumnsSeparatedWithCommas()
38 | + " FROM " + tableName
39 | + findWhereClauseIfExists();
40 | List parameters = sqlQuery.getParameters();
41 | SqlQuery selectQuery = new SqlQuery(selectAsString, parameters);
42 | return Optional.of(selectQuery);
43 | }
44 |
45 | private String findSelectedColumnsSeparatedWithCommas() {
46 | Collection columns = findColumnsToSelect();
47 | return String.join(", ", columns);
48 | }
49 |
50 | private Collection findColumnsToSelect() {
51 | Collection columnNames = findUpdatedColumnNames();
52 | Collection columnsToSelect = new ArrayList<>(columnNames);
53 | Collection whereColumnNames = findWhereColumnNames();
54 | columnsToSelect.addAll(whereColumnNames);
55 | return columnsToSelect;
56 | }
57 |
58 | private List findUpdatedColumnNames() {
59 | return updateStatement
60 | .getColumns()
61 | .stream()
62 | .map(Column::getColumnName)
63 | .collect(toList());
64 | }
65 |
66 | private String findWhereClauseIfExists() {
67 | Expression whereExpression = updateStatement.getWhere();
68 | return whereExpression == null ? ""
69 | :" WHERE " + whereExpression;
70 | }
71 |
72 | private Collection findWhereColumnNames() {
73 | Expression whereExpression = updateStatement.getWhere();
74 | return ColumnNamesExtractor.INSTANCE.findColumnNamesOf(whereExpression);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/BaseColumnOrdersFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.ColumnOrdersFinder;
16 | import org.qstd.PreparedStatementBuilder;
17 | import org.qstd.SqlQuery;
18 |
19 | import javax.sql.DataSource;
20 | import java.sql.Connection;
21 | import java.sql.PreparedStatement;
22 | import java.sql.ResultSet;
23 | import java.sql.SQLException;
24 | import java.util.ArrayList;
25 | import java.util.Collections;
26 | import java.util.List;
27 |
28 | class BaseColumnOrdersFinder implements ColumnOrdersFinder {
29 |
30 | private final DataSource dataSource;
31 |
32 | private final SqlQuery notNullColumnsQuery;
33 |
34 | BaseColumnOrdersFinder(DataSource dataSource, SqlQuery notNullColumnsQuery) {
35 | this.dataSource = dataSource;
36 | this.notNullColumnsQuery = notNullColumnsQuery;
37 | }
38 |
39 | @Override
40 | public List findDatabaseColumnOrdersOf(String tableName) {
41 | try (Connection connection = dataSource.getConnection();
42 | PreparedStatement columnOrderStatement = PreparedStatementBuilder.buildFrom(notNullColumnsQuery, connection)) {
43 | columnOrderStatement.setString(1, tableName);
44 | ResultSet queryResult = columnOrderStatement.executeQuery();
45 | return findColumnOrderFrom(queryResult);
46 | } catch (SQLException sqlException) {
47 | sqlException.printStackTrace();
48 | }
49 | return Collections.emptyList();
50 | }
51 |
52 | private List findColumnOrderFrom(ResultSet queryResult) throws SQLException {
53 | List columnOrder = new ArrayList<>();
54 | while (queryResult.next()) {
55 | String columnName = queryResult.getString(3);
56 | columnOrder.add(columnName);
57 | }
58 | return columnOrder;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/BaseColumnsMappingsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.sql.Connection;
19 | import java.sql.PreparedStatement;
20 | import java.sql.ResultSet;
21 | import java.sql.SQLException;
22 | import java.util.ArrayList;
23 | import java.util.Collection;
24 |
25 | class BaseColumnsMappingsFinder implements ColumnsMappingsFinder {
26 |
27 | private final DataSource dataSource;
28 |
29 | private final SqlQuery columnsMappingQuery;
30 |
31 | public BaseColumnsMappingsFinder(DataSource dataSource, SqlQuery columnsMappingQuery) {
32 | this.dataSource = dataSource;
33 | this.columnsMappingQuery = columnsMappingQuery;
34 | }
35 |
36 | @Override
37 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
38 |
39 | Collection columnsMappings = new ArrayList<>();
40 |
41 | try (Connection connection = dataSource.getConnection();
42 | PreparedStatement referencedTablesStatement = PreparedStatementBuilder.buildFrom(columnsMappingQuery, connection)) {
43 | referencedTablesStatement.setString(1, tableName);
44 |
45 | ResultSet queryResult = referencedTablesStatement.executeQuery();
46 |
47 | while (queryResult.next()) {
48 | ColumnsMapping columnsMapping = buildColumnsMappingFrom(queryResult);
49 | columnsMappings.add(columnsMapping);
50 | }
51 |
52 |
53 | } catch (SQLException sqlException) {
54 | sqlException.printStackTrace();
55 | }
56 |
57 |
58 | return new ColumnsMappingGroup(columnsMappings);
59 |
60 | }
61 |
62 | private ColumnsMapping buildColumnsMappingFrom(ResultSet queryResult) throws SQLException {
63 | String firstTableSchema = queryResult.getString(1);
64 | String firstTableName = queryResult.getString(2);
65 | String firstTableColumn = queryResult.getString(3);
66 |
67 | ColumnMappingPart columnMappingPart1
68 | = new ColumnMappingPart(firstTableSchema, firstTableName, firstTableColumn);
69 |
70 | String secondTableSchema = queryResult.getString(4);
71 | String secondTableName = queryResult.getString(5);
72 | String secondTableColumn = queryResult.getString(6);
73 |
74 | ColumnMappingPart columnMappingPart2
75 | = new ColumnMappingPart(secondTableSchema, secondTableName, secondTableColumn);
76 |
77 | return new ColumnsMapping(columnMappingPart1, columnMappingPart2);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/BaseNotNullColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.NotNullColumnsFinder;
16 | import org.qstd.PreparedStatementBuilder;
17 | import org.qstd.SqlQuery;
18 |
19 | import javax.sql.DataSource;
20 | import java.sql.Connection;
21 | import java.sql.PreparedStatement;
22 | import java.sql.ResultSet;
23 | import java.sql.SQLException;
24 | import java.util.ArrayList;
25 | import java.util.Collection;
26 | import java.util.Collections;
27 | import java.util.List;
28 |
29 | public class BaseNotNullColumnsFinder implements NotNullColumnsFinder {
30 |
31 | private final DataSource dataSource;
32 |
33 | private final SqlQuery notNullColumnsQuery;
34 |
35 | BaseNotNullColumnsFinder(DataSource dataSource, SqlQuery notNullColumnsQuery) {
36 | this.dataSource = dataSource;
37 | this.notNullColumnsQuery = notNullColumnsQuery;
38 | }
39 |
40 | @Override
41 | public Collection findNotNullColumnsOf(String tableName) {
42 | try (Connection connection = dataSource.getConnection();
43 | PreparedStatement columnOrderStatement = PreparedStatementBuilder.buildFrom(notNullColumnsQuery, connection)) {
44 | columnOrderStatement.setString(1, tableName);
45 | ResultSet queryResult = columnOrderStatement.executeQuery();
46 | return findNotNullColumnsFrom(queryResult);
47 | } catch (SQLException sqlException) {
48 | sqlException.printStackTrace();
49 | }
50 | return Collections.emptyList();
51 | }
52 |
53 | private List findNotNullColumnsFrom(ResultSet resultSet) throws SQLException {
54 | List notNullColumns = new ArrayList<>();
55 | while (resultSet.next()) {
56 | String columnName = resultSet.getString(3);
57 | notNullColumns.add(columnName);
58 | }
59 | return notNullColumns;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/BasePrimaryKeyColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.PreparedStatementBuilder;
16 | import org.qstd.PrimaryKeyColumnsFinder;
17 | import org.qstd.SqlQuery;
18 |
19 | import javax.sql.DataSource;
20 | import java.sql.Connection;
21 | import java.sql.PreparedStatement;
22 | import java.sql.ResultSet;
23 | import java.sql.SQLException;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | class BasePrimaryKeyColumnsFinder implements PrimaryKeyColumnsFinder {
28 |
29 | private final DataSource dataSource;
30 |
31 | private final SqlQuery primaryKeyColumnsQuery;
32 |
33 | public BasePrimaryKeyColumnsFinder(DataSource dataSource, SqlQuery primaryKeyColumnsQuery) {
34 | this.dataSource = dataSource;
35 | this.primaryKeyColumnsQuery = primaryKeyColumnsQuery;
36 | }
37 |
38 | @Override
39 | public List findPrimaryColumnsOf(String tableName) {
40 |
41 | List primaryKeyColumns = new ArrayList<>();
42 |
43 | try (Connection connection = dataSource.getConnection();
44 | PreparedStatement primaryKeyColumnsStatement = PreparedStatementBuilder.buildFrom(primaryKeyColumnsQuery, connection)) {
45 |
46 | primaryKeyColumnsStatement.setString(1, tableName);
47 | ResultSet queryResult = primaryKeyColumnsStatement.executeQuery();
48 |
49 | while(queryResult.next()) {
50 | String column = queryResult.getString(4);
51 | primaryKeyColumns.add(column);
52 | }
53 |
54 | } catch (SQLException sqlException) {
55 | sqlException.printStackTrace();
56 | }
57 |
58 | return primaryKeyColumns;
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/BaseReferencedTablesFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.sql.Connection;
19 | import java.sql.PreparedStatement;
20 | import java.sql.ResultSet;
21 | import java.sql.SQLException;
22 | import java.util.ArrayList;
23 | import java.util.Collection;
24 |
25 | class BaseReferencedTablesFinder implements ReferencedTablesFinder {
26 |
27 | private final DataSource dataSource;
28 |
29 | private final SqlQuery referencedTableQuery;
30 |
31 | BaseReferencedTablesFinder(DataSource dataSource, SqlQuery referencedTableQuery) {
32 | this.dataSource = dataSource;
33 | this.referencedTableQuery = referencedTableQuery;
34 | }
35 |
36 | @Override
37 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
38 |
39 | Collection referencedTables = new ArrayList<>();
40 | try (Connection connection = dataSource.getConnection();
41 | PreparedStatement referencedTablesStatement = PreparedStatementBuilder.buildFrom(referencedTableQuery, connection)) {
42 |
43 | referencedTablesStatement.setString(1, tableName);
44 | ResultSet queryResult = referencedTablesStatement.executeQuery();
45 |
46 | while(queryResult.next()) {
47 | ReferencedTable referencedTable = buildReferencedTableFrom(queryResult);
48 | referencedTables.add(referencedTable);
49 | }
50 |
51 | } catch (SQLException sqlException) {
52 | sqlException.printStackTrace();
53 | }
54 | return new ReferencedTableSet(referencedTables);
55 | }
56 |
57 | private ReferencedTable buildReferencedTableFrom(ResultSet queryResult) throws SQLException {
58 | String resultTableName = queryResult.getString(1);
59 | String referencedTableName = queryResult.getString(2);
60 | int level = queryResult.getInt(3);
61 | return new ReferencedTable(resultTableName
62 | , referencedTableName
63 | , level);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DatabaseMetadataFinderFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.DatabaseMetadataFinder;
16 |
17 | import javax.sql.DataSource;
18 |
19 | import static org.qstd.dbtype.DatabaseType.*;
20 |
21 | /**
22 | * Factory to create an instance of {@link org.qstd.DatabaseMetadataFinder}.
23 | */
24 | public class DatabaseMetadataFinderFactory {
25 |
26 | private DatabaseMetadataFinderFactory() { }
27 |
28 | /**
29 | * Creates a DatabaseMetadataFinder
30 | * @param dataSource A data source
31 | * @param dbType A database type
32 | * @return An instance of DatabaseMetadataFinder
33 | */
34 | public static DatabaseMetadataFinder createDatabaseMetadataFinderFrom(DataSource dataSource, DatabaseType dbType) {
35 |
36 | if(dbType.equals(H2)) {
37 | return new H2MetadataFinder(dataSource);
38 | }
39 |
40 | if(dbType.equals(HSQLDB)) {
41 | return new HsqlDbMetadataFinder(dataSource);
42 | }
43 |
44 | if(dbType.equals(POSTGRE_SQL)) {
45 | return new PostgreSqlMetadataFinder(dataSource);
46 | }
47 |
48 | if (dbType.equals(MARIA_DB) || dbType.equals(MY_SQL)) {
49 | return new MariaDBMySQLMetadataFinder(dataSource);
50 | }
51 |
52 | if(dbType.equals(MICROSOFT_SQL_SERVER)) {
53 | return new MSSQLServerMetadataFinder(dataSource);
54 | }
55 |
56 | if(dbType.equals(ORACLE)) {
57 | return new OracleMetadataFinder(dataSource);
58 | }
59 |
60 | return new DefaultDatabaseMetadataFinder(dataSource);
61 |
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DatabaseMetadataFinderWithCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.ColumnsMappingGroup;
16 | import org.qstd.DatabaseMetadataFinder;
17 | import org.qstd.ReferencedTableSet;
18 |
19 | import java.util.Collection;
20 | import java.util.List;
21 | import java.util.concurrent.ConcurrentHashMap;
22 | import java.util.function.Function;
23 |
24 | /**
25 | * A DatabaseMetadataFinder caching method calls
26 | */
27 | public class DatabaseMetadataFinderWithCache implements DatabaseMetadataFinder {
28 |
29 | private final DatabaseMetadataFinder delegate;
30 |
31 | private final ConcurrentHashMap> notNullColumnsByTableName = new ConcurrentHashMap<>();
32 |
33 | private final ConcurrentHashMap> databaseColumnOrdersByTableName = new ConcurrentHashMap<>();
34 |
35 | private final ConcurrentHashMap columnsMappingsByTableName = new ConcurrentHashMap<>();
36 |
37 | private final ConcurrentHashMap referencedTableSetByTableName = new ConcurrentHashMap<>();
38 |
39 | private final ConcurrentHashMap> primaryColumnsByTableName = new ConcurrentHashMap<>();
40 |
41 | public DatabaseMetadataFinderWithCache(DatabaseMetadataFinder delegate) {
42 | this.delegate = delegate;
43 | }
44 |
45 | public static DatabaseMetadataFinder buildFrom(DatabaseMetadataFinder databaseMetadataFinder) {
46 | return new DatabaseMetadataFinderWithCache(databaseMetadataFinder);
47 | }
48 |
49 | @Override
50 | public List findDatabaseColumnOrdersOf(String tableName) {
51 | return databaseColumnOrdersByTableName.computeIfAbsent(tableName, t -> delegate.findDatabaseColumnOrdersOf(tableName));
52 | }
53 |
54 | @Override
55 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
56 | return columnsMappingsByTableName.computeIfAbsent(tableName, t -> delegate.findColumnsMappingsOf(tableName));
57 | }
58 |
59 | @Override
60 | public Collection findNotNullColumnsOf(String tableName) {
61 | return notNullColumnsByTableName.computeIfAbsent(tableName, t -> delegate.findNotNullColumnsOf(tableName));
62 | }
63 |
64 | @Override
65 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
66 | return referencedTableSetByTableName.computeIfAbsent(tableName, t -> delegate.findReferencedTablesOf(tableName));
67 | }
68 |
69 | @Override
70 | public List findPrimaryColumnsOf(String tableName) {
71 | return primaryColumnsByTableName.computeIfAbsent(tableName, t -> delegate.findPrimaryColumnsOf(tableName));
72 | }
73 |
74 | @Override
75 | public Function getFunctionToHaveMetadataTableName() {
76 | return delegate.getFunctionToHaveMetadataTableName();
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DatabaseType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import static java.util.Arrays.stream;
16 |
17 | /**
18 | * Database type
19 | */
20 | public enum DatabaseType {
21 |
22 | /**H2*/
23 | H2("jdbc:h2")
24 | ,/**HSQLDB*/
25 | HSQLDB("jdbc:hsqldb")
26 | ,/**MariaDB*/
27 | MARIA_DB("jdbc:mariadb")
28 | ,/**Microsoft SQL Server*/
29 | MICROSOFT_SQL_SERVER("jdbc:sqlserver")
30 | ,/**MySQL*/
31 | MY_SQL("jdbc:mysql")
32 | ,/**Oracle*/
33 | ORACLE("jdbc:oracle")
34 | ,/**PostgreSQL*/
35 | POSTGRE_SQL("jdbc:postgresql")
36 | ,/**Other database type*/
37 | OTHER("jdbc:");
38 |
39 | private final String jdbcUrlStart;
40 |
41 | DatabaseType(String jdbcUrlStart) {
42 | this.jdbcUrlStart = jdbcUrlStart;
43 | }
44 |
45 | /**
46 | * Find the database type from the JDBC URL
47 | * @param jdbcUrl A JDBC URL
48 | * @return The database type
49 | */
50 | public static DatabaseType findFromDbUrl(String jdbcUrl) {
51 | DatabaseType[] databaseTypes = DatabaseType.values();
52 | return stream(databaseTypes)
53 | .filter(dbType -> dbType.accept(jdbcUrl))
54 | .findFirst()
55 | .get();
56 | }
57 |
58 | private boolean accept(String jdbcUrl) {
59 | return jdbcUrl.startsWith(jdbcUrlStart);
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DatabaseUrlFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import javax.sql.DataSource;
16 | import java.sql.Connection;
17 | import java.sql.DatabaseMetaData;
18 | import java.sql.SQLException;
19 |
20 | /**
21 | * Class helping to find database URL
22 | */
23 | public class DatabaseUrlFinder {
24 |
25 | public static final DatabaseUrlFinder INSTANCE = new DatabaseUrlFinder();
26 |
27 | /**
28 | * Find the database URL from a data source
29 | * @param dataSource A data source
30 | * @return The database URL
31 | */
32 | public static String findDbUrlFrom(DataSource dataSource) {
33 | try (Connection connection = dataSource.getConnection()) {
34 | DatabaseMetaData metaData = connection.getMetaData();
35 | return metaData.getURL().toLowerCase();
36 | } catch (SQLException sqlException) {
37 | throw new IllegalStateException(sqlException);
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DefaultColumnOrdersFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.ColumnOrdersFinder;
16 | import org.qstd.SqlQuery;
17 |
18 | import javax.sql.DataSource;
19 | import java.util.List;
20 |
21 | class DefaultColumnOrdersFinder implements ColumnOrdersFinder {
22 |
23 | private static final SqlQuery COLUMN_ORDER_QUERY = new SqlQuery(
24 | " select table_schema," +
25 | " table_name," +
26 | " column_name," +
27 | " ordinal_position as position" +
28 | " from information_schema.columns" +
29 | " where table_name=?" +
30 | " order by position");
31 |
32 | private BaseColumnOrdersFinder delegate;
33 |
34 | DefaultColumnOrdersFinder(DataSource dataSource) {
35 | delegate = new BaseColumnOrdersFinder(dataSource, COLUMN_ORDER_QUERY);
36 | }
37 |
38 | @Override
39 | public List findDatabaseColumnOrdersOf(String tableName) {
40 | return delegate.findDatabaseColumnOrdersOf(tableName);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DefaultDatabaseMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.ColumnsMappingGroup;
16 | import org.qstd.DatabaseMetadataFinder;
17 | import org.qstd.ReferencedTableSet;
18 |
19 | import javax.sql.DataSource;
20 | import java.util.Collection;
21 | import java.util.Collections;
22 | import java.util.List;
23 |
24 | class DefaultDatabaseMetadataFinder implements DatabaseMetadataFinder {
25 |
26 |
27 | private final DefaultNotNullColumnsFinder defaultNotNullColumnsFinder;
28 |
29 | public DefaultDatabaseMetadataFinder(DataSource dataSource) {
30 | this.defaultNotNullColumnsFinder = new DefaultNotNullColumnsFinder(dataSource);
31 | }
32 |
33 | @Override
34 | public List findDatabaseColumnOrdersOf(String tableName) {
35 | return Collections.emptyList();
36 | }
37 |
38 | @Override
39 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
40 | return ReferencedTableSet.NONE;
41 | }
42 |
43 | @Override
44 | public Collection findNotNullColumnsOf(String tableName) {
45 | return defaultNotNullColumnsFinder.findNotNullColumnsOf(tableName);
46 | }
47 |
48 | @Override
49 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
50 | return ColumnsMappingGroup.NO_MAPPING;
51 | }
52 |
53 | @Override
54 | public List findPrimaryColumnsOf(String tableName) {
55 | return Collections.emptyList();
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DefaultNotNullColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.NotNullColumnsFinder;
16 | import org.qstd.SqlQuery;
17 |
18 | import javax.sql.DataSource;
19 | import java.util.Collection;
20 |
21 | class DefaultNotNullColumnsFinder implements NotNullColumnsFinder {
22 |
23 | private static final SqlQuery NOT_NULL_COLUMNS_QUERY = new SqlQuery(
24 | "select table_schema as table_schema,\n" +
25 | " table_name as table_name,\n" +
26 | " column_name as not_null_column\n" +
27 | "from information_schema.columns\n" +
28 | "where is_nullable = 'NO'\n" +
29 | " AND table_name=?");
30 |
31 | private BaseNotNullColumnsFinder delegate;
32 |
33 | DefaultNotNullColumnsFinder(DataSource dataSource) {
34 | delegate = new BaseNotNullColumnsFinder(dataSource, NOT_NULL_COLUMNS_QUERY);
35 | }
36 |
37 | @Override
38 | public Collection findNotNullColumnsOf(String tableName) {
39 | return delegate.findNotNullColumnsOf(tableName);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/DefaultPrimaryKeyColumnsFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.PrimaryKeyColumnsFinder;
16 | import org.qstd.SqlQuery;
17 |
18 | import javax.sql.DataSource;
19 | import java.util.List;
20 |
21 | class DefaultPrimaryKeyColumnsFinder implements PrimaryKeyColumnsFinder {
22 |
23 | private static final SqlQuery PRIMARY_COLUMNS_QUERY = new SqlQuery(
24 | "select \n" +
25 | " cons.table_schema,\n" +
26 | " cons.table_name,\n" +
27 | " cons.constraint_name,\n" +
28 | " cols.column_name,\n" +
29 | " cols.ordinal_position as position\n" +
30 | " from information_schema.table_constraints cons\n" +
31 | " join information_schema.key_column_usage cols on (cons.table_schema = cols.table_schema \n" +
32 | " and cons.table_name = cols.table_name\n" +
33 | " and cons.constraint_name = cols.constraint_name)\n" +
34 | " where cons.table_name = ?" + "\n" +
35 | " and cons.constraint_type='PRIMARY KEY'"
36 | );
37 |
38 | private final PrimaryKeyColumnsFinder delegate;
39 |
40 | DefaultPrimaryKeyColumnsFinder(DataSource dataSource) {
41 | delegate = new BasePrimaryKeyColumnsFinder(dataSource, PRIMARY_COLUMNS_QUERY);
42 | }
43 |
44 | @Override
45 | public List findPrimaryColumnsOf(String tableName) {
46 | return delegate.findPrimaryColumnsOf(tableName);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/H2MetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.List;
20 |
21 | class H2MetadataFinder implements DatabaseMetadataFinder {
22 |
23 | private static final SqlQuery H2_REFERENCED_TABLES_QUERY = new SqlQuery(
24 | "with\n" +
25 | " recursive parent_child_tree (table_name, ref_table_name, level) as\n" +
26 | " (\n" +
27 | " select distinct\n" +
28 | " child.table_name as table_name,\n" +
29 | " parent.table_name as ref_table_name,\n" +
30 | " 1 as level\n" +
31 | " from information_schema.table_constraints child\n" +
32 | " join information_schema.referential_constraints rco\n" +
33 | " on rco.constraint_name = child.constraint_name\n" +
34 | " join information_schema.constraints parent\n" +
35 | " on parent.unique_index_name = rco.unique_constraint_name\n" +
36 | " where\n" +
37 | " child.table_name != parent.table_name and\n" +
38 | " child.table_name=?\n" +
39 | " UNION ALL\n" +
40 | " select pc.table_name, pc.ref_table_name, pct.level + 1 as level\n" +
41 | " from\n" +
42 | " (\n" +
43 | " select \n" +
44 | " child.table_name as table_name,\n" +
45 | " parent.table_name as ref_table_name,\n" +
46 | " 1 as level\n" +
47 | " from information_schema.table_constraints child\n" +
48 | " join information_schema.referential_constraints rco\n" +
49 | " on rco.constraint_name = child.constraint_name\n" +
50 | " join information_schema.constraints parent\n" +
51 | " on parent.unique_index_name = rco.unique_constraint_name\n" +
52 | " where\n" +
53 | " child.table_name != parent.table_name\n" +
54 | " ) pc\n" +
55 | " join parent_child_tree pct on (pc.table_name = pct.ref_table_name)\n" +
56 | " )\n" +
57 | "select distinct *\n" +
58 | "from parent_child_tree\n" +
59 | "order by level desc");
60 |
61 | private static final SqlQuery H2_COLUMNS_MAPPINGS_QUERY = new SqlQuery(
62 | "select \n" +
63 | " fktable_schema as table_schema,\n" +
64 | " fktable_name as table_name,\n" +
65 | " fkcolumn_name as column_name,\n" +
66 | " pktable_schema as ref_table_schema,\n" +
67 | " pktable_name as ref_table_name,\n" +
68 | " pkcolumn_name as ref_column_name\n" +
69 | " from information_schema.cross_references \n" +
70 | " where fktable_name = ?"
71 | );
72 |
73 | private final DefaultColumnOrdersFinder defaultColumnOrdersFinder;
74 |
75 | private final NotNullColumnsFinder defaultNotNullColumnsFinder;
76 |
77 | private final ReferencedTablesFinder h2ReferencedTablesFinder;
78 |
79 | private final ColumnsMappingsFinder h2ColumnsMappingsFinder;
80 |
81 | private final PrimaryKeyColumnsFinder primaryKeyColumnsFinder;
82 |
83 | H2MetadataFinder(DataSource dataSource) {
84 | this.defaultColumnOrdersFinder = new DefaultColumnOrdersFinder(dataSource);
85 | this.defaultNotNullColumnsFinder = new DefaultNotNullColumnsFinder(dataSource);
86 | this.h2ReferencedTablesFinder = new BaseReferencedTablesFinder(dataSource, H2_REFERENCED_TABLES_QUERY);
87 | this.h2ColumnsMappingsFinder = new BaseColumnsMappingsFinder(dataSource, H2_COLUMNS_MAPPINGS_QUERY);
88 | this.primaryKeyColumnsFinder = new DefaultPrimaryKeyColumnsFinder(dataSource);
89 | }
90 |
91 | @Override
92 | public List findDatabaseColumnOrdersOf(String tableName) {
93 | return defaultColumnOrdersFinder.findDatabaseColumnOrdersOf(tableName);
94 | }
95 |
96 | @Override
97 | public Collection findNotNullColumnsOf(String tableName) {
98 | return defaultNotNullColumnsFinder.findNotNullColumnsOf(tableName);
99 | }
100 |
101 | @Override
102 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
103 | return h2ReferencedTablesFinder.findReferencedTablesOf(tableName);
104 | }
105 |
106 | @Override
107 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
108 | return h2ColumnsMappingsFinder.findColumnsMappingsOf(tableName);
109 | }
110 |
111 | @Override
112 | public List findPrimaryColumnsOf(String tableName) {
113 | return primaryKeyColumnsFinder.findPrimaryColumnsOf(tableName);
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/HsqlDbMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.List;
20 |
21 | class HsqlDbMetadataFinder implements DatabaseMetadataFinder {
22 |
23 | private static final SqlQuery HSQL_DB_REFERENCED_TABLES_QUERY = new SqlQuery(
24 | "with\n" +
25 | " recursive parent_child_tree (table_name, ref_table_name, level) as\n" +
26 | " (\n" +
27 | " select distinct\n" +
28 | " child.table_name as table_name,\n" +
29 | " parent.table_name as ref_table_name,\n" +
30 | " 1 as level\n" +
31 | " from information_schema.table_constraints child\n" +
32 | " join information_schema.referential_constraints rco\n" +
33 | " on rco.constraint_name = child.constraint_name\n" +
34 | " join information_schema.table_constraints parent\n" +
35 | " on parent.constraint_name = rco.unique_constraint_name\n" +
36 | " where\n" +
37 | " child.table_name != parent.table_name and\n" +
38 | " child.table_name=?\n" +
39 | " UNION\n" +
40 | " select pc.table_name, pc.ref_table_name, pct.level + 1 as level\n" +
41 | " from\n" +
42 | " (\n" +
43 | " select distinct\n" +
44 | " child.table_name as table_name,\n" +
45 | " parent.table_name as ref_table_name,\n" +
46 | " 1 as level\n" +
47 | " from information_schema.table_constraints child\n" +
48 | " join information_schema.referential_constraints rco\n" +
49 | " on rco.constraint_name = child.constraint_name\n" +
50 | " join information_schema.table_constraints parent\n" +
51 | " on parent.constraint_name = rco.unique_constraint_name\n" +
52 | " where\n" +
53 | " child.table_name != parent.table_name\n" +
54 | " ) pc\n" +
55 | " join parent_child_tree pct on (pc.table_name = pct.ref_table_name)\n" +
56 | " )\n" +
57 | "select distinct *\n" +
58 | "from parent_child_tree\n" +
59 | "order by level desc");
60 |
61 | private static final SqlQuery HSQL_DB_COLUMNS_MAPPINGS_QUERY = new SqlQuery(
62 | "select\n" +
63 | " child_constraint.table_schema as table_schema,\n" +
64 | " child_constraint.table_name as table_name,\n" +
65 | " child_cons_cols.column_name as column_name,\n" +
66 | " parent_cons_cols.table_schema as ref_table_schema,\n" +
67 | " parent_cons_cols.table_name as ref_table_name,\n" +
68 | " parent_cons_cols.column_name as ref_column_name\n" +
69 | " from information_schema.table_constraints as child_constraint\n" +
70 | " join information_schema.key_column_usage as child_cons_cols\n" +
71 | " on (child_constraint.constraint_schema = child_cons_cols.constraint_schema\n" +
72 | " and\n" +
73 | " child_constraint.constraint_name = child_cons_cols.constraint_name\n" +
74 | " and\n" +
75 | " child_constraint.table_schema = child_cons_cols.table_schema)\n" +
76 | " join information_schema.referential_constraints as ref\n" +
77 | " on (child_constraint.constraint_schema = ref.constraint_schema\n" +
78 | " and\n" +
79 | " child_constraint.constraint_name = ref.constraint_name)\n" +
80 | " join information_schema.key_column_usage as parent_cons_cols\n" +
81 | " on (parent_cons_cols.constraint_schema = ref.unique_constraint_schema\n" +
82 | " and\n" +
83 | " parent_cons_cols.constraint_name = ref.unique_constraint_name)\n" +
84 | "where child_constraint.constraint_type = 'FOREIGN KEY' and child_constraint.table_name=?"
85 | );
86 |
87 | private final DefaultColumnOrdersFinder defaultColumnOrdersFinder;
88 |
89 | private final NotNullColumnsFinder defaultNotNullColumnsFinder;
90 |
91 | private final ReferencedTablesFinder hsqlDbReferencedTablesFinder;
92 |
93 | private final ColumnsMappingsFinder hsqlDbColumnsMappingsFinder;
94 |
95 | private final DefaultPrimaryKeyColumnsFinder primaryKeyColumnsFinder;
96 |
97 | HsqlDbMetadataFinder(DataSource dataSource) {
98 | this.defaultColumnOrdersFinder = new DefaultColumnOrdersFinder(dataSource);
99 | this.defaultNotNullColumnsFinder = new DefaultNotNullColumnsFinder(dataSource);
100 | this.hsqlDbReferencedTablesFinder = new BaseReferencedTablesFinder(dataSource, HSQL_DB_REFERENCED_TABLES_QUERY);
101 | this.hsqlDbColumnsMappingsFinder = new BaseColumnsMappingsFinder(dataSource, HSQL_DB_COLUMNS_MAPPINGS_QUERY);
102 | this.primaryKeyColumnsFinder = new DefaultPrimaryKeyColumnsFinder(dataSource);
103 | }
104 |
105 | @Override
106 | public List findDatabaseColumnOrdersOf(String tableName) {
107 | return defaultColumnOrdersFinder.findDatabaseColumnOrdersOf(tableName);
108 | }
109 |
110 | @Override
111 | public Collection findNotNullColumnsOf(String tableName) {
112 | return defaultNotNullColumnsFinder.findNotNullColumnsOf(tableName);
113 | }
114 |
115 | @Override
116 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
117 | return hsqlDbReferencedTablesFinder.findReferencedTablesOf(tableName);
118 | }
119 |
120 | @Override
121 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
122 | return hsqlDbColumnsMappingsFinder.findColumnsMappingsOf(tableName);
123 | }
124 |
125 | @Override
126 | public List findPrimaryColumnsOf(String tableName) {
127 | return primaryKeyColumnsFinder.findPrimaryColumnsOf(tableName);
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/MSSQLServerMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | class MSSQLServerMetadataFinder implements DatabaseMetadataFinder {
23 |
24 | private static final SqlQuery MS_SQL_SERVER_REFERENCED_TABLES_QUERY = new SqlQuery(
25 | "with\n" +
26 | " parent_child_tree as\n" +
27 | " (\n" +
28 | " select distinct\n" +
29 | " child.table_name as table_name,\n" +
30 | " parent.table_name as ref_table_name,\n" +
31 | " 1 as level\n" +
32 | " from information_schema.referential_constraints rco\n" +
33 | " join information_schema.table_constraints child\n" +
34 | " on rco.constraint_name = child.constraint_name\n" +
35 | " and rco.constraint_schema = child.table_schema\n" +
36 | " join information_schema.table_constraints parent\n" +
37 | " on rco.unique_constraint_name = parent.constraint_name\n" +
38 | " and rco.unique_constraint_schema = parent.table_schema\n" +
39 | " where child.table_name != parent.table_name\n" +
40 | " and child.table_name=?\n" +
41 | " UNION ALL\n" +
42 | " select pc.table_name, pc.ref_table_name, pct.level + 1 as level\n" +
43 | " from\n" +
44 | " (\n" +
45 | " select \n" +
46 | " child.table_name as table_name,\n" +
47 | " parent.table_name as ref_table_name,\n" +
48 | " 1 as level\n" +
49 | " from information_schema.referential_constraints rco\n" +
50 | " join information_schema.table_constraints child\n" +
51 | " on rco.constraint_name = child.constraint_name\n" +
52 | " and rco.constraint_schema = child.table_schema\n" +
53 | " join information_schema.table_constraints parent\n" +
54 | " on rco.unique_constraint_name = parent.constraint_name\n" +
55 | " and rco.unique_constraint_schema = parent.table_schema\n" +
56 | " where child.table_name != parent.table_name\n" +
57 | " ) pc\n" +
58 | " join parent_child_tree pct on (pc.table_name = pct.ref_table_name)\n" +
59 | " )\n" +
60 | "select distinct *\n" +
61 | "from parent_child_tree\n" +
62 | "order by level desc");
63 |
64 | private static final SqlQuery MS_SQL_SERVER_COLUMNS_MAPPINGS_QUERY = new SqlQuery(
65 | "select\n" +
66 | " child_constraint.table_schema as table_schema,\n" +
67 | " child_constraint.table_name as table_name,\n" +
68 | " child_cons_cols.column_name as column_name,\n" +
69 | " parent_cons_cols.table_schema as ref_table_schema,\n" +
70 | " parent_cons_cols.table_name as ref_table_name,\n" +
71 | " parent_cons_cols.column_name as ref_column_name\n" +
72 | " from information_schema.table_constraints as child_constraint\n" +
73 | " join information_schema.key_column_usage as child_cons_cols\n" +
74 | " on (child_constraint.constraint_schema = child_cons_cols.constraint_schema\n" +
75 | " and\n" +
76 | " child_constraint.constraint_name = child_cons_cols.constraint_name\n" +
77 | " and\n" +
78 | " child_constraint.table_schema = child_cons_cols.table_schema)\n" +
79 | " join information_schema.referential_constraints as ref\n" +
80 | " on (child_constraint.constraint_schema = ref.constraint_schema\n" +
81 | " and\n" +
82 | " child_constraint.constraint_name = ref.constraint_name)\n" +
83 | " join information_schema.key_column_usage as parent_cons_cols\n" +
84 | " on (parent_cons_cols.constraint_schema = ref.unique_constraint_schema\n" +
85 | " and\n" +
86 | " parent_cons_cols.constraint_name = ref.unique_constraint_name)\n" +
87 | "where child_constraint.constraint_type = 'FOREIGN KEY' and child_constraint.table_name=?");
88 |
89 | private final DefaultColumnOrdersFinder defaultColumnOrdersFinder;
90 |
91 | private final NotNullColumnsFinder defaultNotNullColumnsFinder;
92 |
93 | private final ReferencedTablesFinder mssqlServerReferencedTablesFinder;
94 |
95 | private final ColumnsMappingsFinder mssqlServerColumnsMappingsFinder;
96 |
97 | MSSQLServerMetadataFinder(DataSource dataSource) {
98 | this.defaultColumnOrdersFinder = new DefaultColumnOrdersFinder(dataSource);
99 | this.defaultNotNullColumnsFinder = new DefaultNotNullColumnsFinder(dataSource);
100 | this.mssqlServerReferencedTablesFinder = new BaseReferencedTablesFinder(dataSource, MS_SQL_SERVER_REFERENCED_TABLES_QUERY);
101 | this.mssqlServerColumnsMappingsFinder = new BaseColumnsMappingsFinder(dataSource, MS_SQL_SERVER_COLUMNS_MAPPINGS_QUERY);
102 | }
103 |
104 | @Override
105 | public List findDatabaseColumnOrdersOf(String tableName) {
106 | return defaultColumnOrdersFinder.findDatabaseColumnOrdersOf(tableName);
107 | }
108 |
109 | @Override
110 | public Collection findNotNullColumnsOf(String tableName) {
111 | return defaultNotNullColumnsFinder.findNotNullColumnsOf(tableName);
112 | }
113 |
114 | @Override
115 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
116 | return mssqlServerReferencedTablesFinder.findReferencedTablesOf(tableName);
117 | }
118 |
119 | @Override
120 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
121 | return mssqlServerColumnsMappingsFinder.findColumnsMappingsOf(tableName);
122 | }
123 |
124 | @Override
125 | public List findPrimaryColumnsOf(String tableName) {
126 | return Collections.emptyList();
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/MariaDBMySQLMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | class MariaDBMySQLMetadataFinder implements DatabaseMetadataFinder {
23 |
24 | private static final SqlQuery MARIA_DB_MY_SQL_COLUMNS_MAPPINGS_QUERY
25 | = new SqlQuery("select\n" +
26 | " child_constraint.table_schema as table_schema,\n" +
27 | " child_constraint.table_name as table_name,\n" +
28 | " child_cons_cols.column_name as column_name,\n" +
29 | " child_cons_cols.referenced_table_schema as ref_table_schema,\n" +
30 | " child_cons_cols.referenced_table_name as ref_table_name,\n" +
31 | " child_cons_cols.referenced_column_name as ref_column_name\n" +
32 | " from information_schema.table_constraints as child_constraint\n" +
33 | " join information_schema.key_column_usage as child_cons_cols\n" +
34 | " on (child_constraint.constraint_schema = child_cons_cols.constraint_schema\n" +
35 | " and\n" +
36 | " child_constraint.constraint_name = child_cons_cols.constraint_name\n" +
37 | " and\n" +
38 | " child_constraint.table_schema = child_cons_cols.table_schema\n" +
39 | " and\n" +
40 | " child_constraint.table_name = child_cons_cols.table_name)\n" +
41 | "where child_constraint.constraint_type = 'FOREIGN KEY' and child_constraint.table_name=?");
42 |
43 | private final DefaultColumnOrdersFinder defaultColumnOrdersFinder;
44 |
45 | private final NotNullColumnsFinder defaultNotNullColumnsFinder;
46 |
47 | private final PostgreSqlMariaDbReferencedTablesFinder postgreSqlMariaDbReferencedTablesFinder;
48 |
49 | private final BaseColumnsMappingsFinder mariaDbMySqlColumnsMappingsFinder;
50 |
51 | private final PrimaryKeyColumnsFinder primaryKeyColumnsFinder;
52 |
53 | MariaDBMySQLMetadataFinder(DataSource dataSource) {
54 | this.defaultColumnOrdersFinder = new DefaultColumnOrdersFinder(dataSource);
55 | this.defaultNotNullColumnsFinder = new DefaultNotNullColumnsFinder(dataSource);
56 | this.postgreSqlMariaDbReferencedTablesFinder = new PostgreSqlMariaDbReferencedTablesFinder(dataSource);
57 | this.mariaDbMySqlColumnsMappingsFinder = new BaseColumnsMappingsFinder(dataSource, MARIA_DB_MY_SQL_COLUMNS_MAPPINGS_QUERY);
58 | this.primaryKeyColumnsFinder = new DefaultPrimaryKeyColumnsFinder(dataSource);
59 | }
60 |
61 | @Override
62 | public List findDatabaseColumnOrdersOf(String tableName) {
63 | return defaultColumnOrdersFinder.findDatabaseColumnOrdersOf(tableName);
64 | }
65 |
66 | @Override
67 | public Collection findNotNullColumnsOf(String tableName) {
68 | return defaultNotNullColumnsFinder.findNotNullColumnsOf(tableName);
69 | }
70 |
71 | @Override
72 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
73 | return postgreSqlMariaDbReferencedTablesFinder.findReferencedTablesOf(tableName);
74 | }
75 |
76 | @Override
77 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
78 | return mariaDbMySqlColumnsMappingsFinder.findColumnsMappingsOf(tableName);
79 | }
80 |
81 | @Override
82 | public List findPrimaryColumnsOf(String tableName) {
83 | return Collections.emptyList();
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/OracleMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.List;
20 | import java.util.function.Function;
21 |
22 | public class OracleMetadataFinder implements DatabaseMetadataFinder {
23 |
24 | private static final SqlQuery COLUMNS_ORDER_QUERY = new SqlQuery(
25 | "select owner as table_schema," +
26 | " table_name as table_name," +
27 | " column_name as column_name," +
28 | " column_id as position" +
29 | " from all_tab_columns\n" +
30 | " where table_name = ?" +
31 | " order by position"
32 | );
33 |
34 | private static final SqlQuery NOT_NULL_COLUMNS_QUERY = new SqlQuery(
35 | "select owner as table_schema," +
36 | " table_name as table_name," +
37 | " column_name as mandatory_column" +
38 | " from all_tab_columns" +
39 | " where table_name = ?" +
40 | " and nullable = 'N'"
41 | );
42 |
43 | private static final SqlQuery REFERENCED_TABLES_QUERY = new SqlQuery(
44 | "select\n" +
45 | " table_name,\n" +
46 | " ref_table_name,\n" +
47 | " level\n" +
48 | " from\n" +
49 | " (\n" +
50 | " select\n" +
51 | " c.owner as table_schema,\n" +
52 | " c.table_name,\n" +
53 | " c.r_owner as ref_table_schema,\n" +
54 | " ref_c.table_name as ref_table_name\n" +
55 | " from\n" +
56 | " all_constraints c\n" +
57 | " inner join all_constraints ref_c on ref_c.constraint_name = c.r_constraint_name\n" +
58 | " where\n" +
59 | " c.constraint_type = 'R'\n" +
60 | " and c.table_name != ref_c.table_name\n" +
61 | " )\n" +
62 | " start with table_name = ?\n" +
63 | " connect by table_name = prior ref_table_name\n" +
64 | "order by level desc"
65 | );
66 |
67 | private static final SqlQuery COLUMNS_MAPPING_QUERY = new SqlQuery(
68 | "select\n" +
69 | " c.owner as table_schema,\n" +
70 | " c.table_name,\n" +
71 | " col.column_name,\n" +
72 | " c.r_owner as ref_table_schema,\n" +
73 | " ref_col.table_name as ref_table_name,\n" +
74 | " ref_col.column_name as ref_column_name\n" +
75 | " from\n" +
76 | " all_constraints c\n" +
77 | " inner join all_cons_columns col on col.owner = c.owner\n" +
78 | " and col.constraint_name = c.constraint_name\n" +
79 | " inner join all_cons_columns ref_col on ref_col.owner = c.r_owner\n" +
80 | " and ref_col.constraint_name = c.r_constraint_name\n" +
81 | " and ref_col.position = col.position\n" +
82 | " where \n" +
83 | " c.table_name = ?\n" +
84 | " and c.constraint_type = 'R'");
85 |
86 | private static final SqlQuery PRIMARY_KEY_QUERY = new SqlQuery(
87 | "select\n" +
88 | " c.owner as table_schema,\n" +
89 | " c.table_name,\n" +
90 | " c.constraint_name,\n" +
91 | " col.column_name,\n" +
92 | " col.position\n" +
93 | " from\n" +
94 | " all_constraints c\n" +
95 | " inner join all_cons_columns col on col.owner = c.owner\n" +
96 | " and col.constraint_name = c.constraint_name\n" +
97 | " where c.table_name = ?\n" +
98 | " and c.constraint_type = 'P'\n" +
99 | " order by position");
100 |
101 | private final BaseColumnOrdersFinder columnOrdersFinder;
102 |
103 | private final NotNullColumnsFinder notNullColumnsFinder;
104 |
105 | private final ReferencedTablesFinder referencedTablesFinder;
106 |
107 | private final BaseColumnsMappingsFinder columnsMappingsFinder;
108 |
109 | private final PrimaryKeyColumnsFinder primaryKeyColumnsFinder;
110 |
111 | @Override
112 | public Function getFunctionToHaveMetadataTableName() {
113 | return tableName -> tableName.toUpperCase();
114 | }
115 |
116 | OracleMetadataFinder(DataSource dataSource) {
117 | columnOrdersFinder = new BaseColumnOrdersFinder(dataSource, COLUMNS_ORDER_QUERY);
118 | notNullColumnsFinder = new BaseNotNullColumnsFinder(dataSource, NOT_NULL_COLUMNS_QUERY);
119 | referencedTablesFinder = new BaseReferencedTablesFinder(dataSource, REFERENCED_TABLES_QUERY);
120 | columnsMappingsFinder = new BaseColumnsMappingsFinder(dataSource, COLUMNS_MAPPING_QUERY);
121 | primaryKeyColumnsFinder = new BasePrimaryKeyColumnsFinder(dataSource, PRIMARY_KEY_QUERY);
122 | }
123 |
124 | @Override
125 | public List findDatabaseColumnOrdersOf(String tableName) {
126 | return columnOrdersFinder.findDatabaseColumnOrdersOf(tableName);
127 | }
128 |
129 | @Override
130 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
131 | return columnsMappingsFinder.findColumnsMappingsOf(tableName);
132 | }
133 |
134 | @Override
135 | public Collection findNotNullColumnsOf(String tableName) {
136 | return notNullColumnsFinder.findNotNullColumnsOf(tableName);
137 | }
138 |
139 | @Override
140 | public List findPrimaryColumnsOf(String tableName) {
141 | return primaryKeyColumnsFinder.findPrimaryColumnsOf(tableName);
142 | }
143 |
144 | @Override
145 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
146 | return referencedTablesFinder.findReferencedTablesOf(tableName);
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/PostgreSqlMariaDbReferencedTablesFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.ReferencedTableSet;
16 | import org.qstd.ReferencedTablesFinder;
17 | import org.qstd.SqlQuery;
18 |
19 | import javax.sql.DataSource;
20 |
21 | class PostgreSqlMariaDbReferencedTablesFinder implements ReferencedTablesFinder {
22 |
23 | private static final SqlQuery REFERENCED_TABLES_QUERY = new SqlQuery("with \n" +
24 | " recursive parent_child_tree as\n" +
25 | " (\n" +
26 | " with parent_child as\n" +
27 | " (\n" +
28 | " select distinct\n" +
29 | " child.table_schema as table_schema,\n" +
30 | " child.table_name as table_name,\n" +
31 | " parent.table_schema as ref_table_schema,\n" +
32 | " parent.table_name as ref_table_name\n" +
33 | " from information_schema.referential_constraints rco\n" +
34 | " join information_schema.table_constraints child\n" +
35 | " on rco.constraint_name = child.constraint_name\n" +
36 | " and rco.constraint_schema = child.table_schema\n" +
37 | " join information_schema.table_constraints parent\n" +
38 | " on rco.unique_constraint_name = parent.constraint_name\n" +
39 | " and rco.unique_constraint_schema = parent.table_schema\n" +
40 | " where child.table_name != parent.table_name\n" +
41 | " )\n" +
42 | " select table_name, ref_table_name, 1 as level\n" +
43 | " from parent_child\n" +
44 | " where table_name=?\n" +
45 | " UNION\n" +
46 | " select pc.table_name, pc.ref_table_name, pct.level + 1 as level\n" +
47 | " from parent_child_tree pct\n" +
48 | " join parent_child pc on (pc.table_name = pct.ref_table_name)\n" +
49 | " )\n" +
50 | "select *\n" +
51 | "from parent_child_tree\n" +
52 | "order by level desc");
53 |
54 | private final BaseReferencedTablesFinder referencedTablesFinder;
55 |
56 | PostgreSqlMariaDbReferencedTablesFinder(DataSource dataSource) {
57 | this.referencedTablesFinder = new BaseReferencedTablesFinder(dataSource, REFERENCED_TABLES_QUERY);
58 | }
59 |
60 | @Override
61 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
62 | return referencedTablesFinder.findReferencedTablesOf(tableName);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/org/qstd/dbtype/PostgreSqlMetadataFinder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.dbtype;
14 |
15 | import org.qstd.*;
16 |
17 | import javax.sql.DataSource;
18 | import java.util.Collection;
19 | import java.util.List;
20 |
21 | class PostgreSqlMetadataFinder implements DatabaseMetadataFinder {
22 |
23 | private static final SqlQuery POSTGRE_SQL_COLUMNS_MAPPINGS_QUERY = new SqlQuery("select\n" +
24 | " tc.table_schema as table_schema,\n" +
25 | " tc.table_name as table_name,\n" +
26 | " kcu.column_name as column_name,\n" +
27 | " ccu.table_schema as ref_table_schema,\n" +
28 | " ccu.table_name as ref_table_name,\n" +
29 | " ccu.column_name as ref_column_name\n" +
30 | " from information_schema.table_constraints as tc\n" +
31 | " join information_schema.key_column_usage as kcu\n" +
32 | " using (constraint_schema, constraint_name, table_schema)\n" +
33 | " join information_schema.constraint_column_usage as ccu\n" +
34 | " using (constraint_schema, constraint_name, table_schema)\n" +
35 | "where tc.constraint_type = 'FOREIGN KEY' and tc.table_name=?");
36 |
37 | private final DefaultColumnOrdersFinder defaultColumnOrdersFinder;
38 |
39 | private final NotNullColumnsFinder defaultNotNullColumnsFinder;
40 |
41 | private final PostgreSqlMariaDbReferencedTablesFinder postgreSqlMariaDbReferencedTablesFinder;
42 |
43 | private final ColumnsMappingsFinder postgreSqlColumnsMappingsFinder;
44 |
45 | private final PrimaryKeyColumnsFinder primaryKeyColumnsFinder;
46 |
47 | PostgreSqlMetadataFinder(DataSource dataSource) {
48 | this.defaultColumnOrdersFinder = new DefaultColumnOrdersFinder(dataSource);
49 | this.defaultNotNullColumnsFinder = new DefaultNotNullColumnsFinder(dataSource);
50 | this.postgreSqlMariaDbReferencedTablesFinder = new PostgreSqlMariaDbReferencedTablesFinder(dataSource);
51 | this.postgreSqlColumnsMappingsFinder = new BaseColumnsMappingsFinder(dataSource, POSTGRE_SQL_COLUMNS_MAPPINGS_QUERY);
52 | this.primaryKeyColumnsFinder = new DefaultPrimaryKeyColumnsFinder(dataSource);
53 | }
54 |
55 | @Override
56 | public List findDatabaseColumnOrdersOf(String tableName) {
57 | return defaultColumnOrdersFinder.findDatabaseColumnOrdersOf(tableName);
58 | }
59 |
60 | @Override
61 | public Collection findNotNullColumnsOf(String tableName) {
62 | return defaultNotNullColumnsFinder.findNotNullColumnsOf(tableName);
63 | }
64 |
65 | @Override
66 | public ReferencedTableSet findReferencedTablesOf(String tableName) {
67 | return postgreSqlMariaDbReferencedTablesFinder.findReferencedTablesOf(tableName);
68 | }
69 |
70 | @Override
71 | public ColumnsMappingGroup findColumnsMappingsOf(String tableName) {
72 | return postgreSqlColumnsMappingsFinder.findColumnsMappingsOf(tableName);
73 | }
74 |
75 | @Override
76 | public List findPrimaryColumnsOf(String tableName) {
77 | return primaryKeyColumnsFinder.findPrimaryColumnsOf(tableName);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/DataSourceBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import com.zaxxer.hikari.HikariConfig;
16 | import com.zaxxer.hikari.HikariDataSource;
17 |
18 | import javax.sql.DataSource;
19 |
20 | class DataSourceBuilder {
21 |
22 | static final DataSourceBuilder INSTANCE = new DataSourceBuilder();
23 |
24 | private DataSourceBuilder() { }
25 |
26 | static DataSource build(String jdbcUrl, String dbUserName, String dbPassword) {
27 | HikariConfig hikariConfig = new HikariConfig();
28 | hikariConfig.setJdbcUrl(jdbcUrl);
29 | hikariConfig.setUsername(dbUserName);
30 | hikariConfig.setPassword(dbPassword);
31 | return new HikariDataSource(hikariConfig);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/DatasetRowApiTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.qstd.DatasetRow;
17 | import org.qstd.QuickSqlTestData;
18 |
19 | import java.util.List;
20 |
21 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
22 | import static org.qstd.test.TestTable.buildUniqueTable;
23 |
24 | public class DatasetRowApiTest extends H2Config {
25 |
26 | @Test public void
27 | should_generate_working_insert_from_a_dataset_row() {
28 |
29 | // GIVEN
30 | TestTable playerTable =
31 | buildUniqueTable(DATA_SOURCE
32 | , "Player"
33 | , " id bigint"
34 | + ", firstName varchar(255)"
35 | + ", lastName varchar(255)")
36 | .create()
37 | .insertValues("1, 'Paul', 'Pogba'");
38 |
39 | // WHEN
40 | DatasetRow datasetRow =
41 | DatasetRow.ofTable(playerTable.getTableName())
42 | .addColumnValue("id", 1)
43 | .addColumnValue("firstName", "Paul")
44 | .addColumnValue("lastName", "Pogba");
45 |
46 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
47 | List insertStatements = quickSqlTestData.generateInsertListFor(datasetRow);
48 |
49 | // THEN
50 | playerTable.recreate();
51 | SQL_EXECUTOR.execute(insertStatements);
52 | assertThat(playerTable).withGeneratedInserts(insertStatements)
53 | .hasNumberOfRows(1)
54 | .row(0).hasValues(1, "Paul", "Pogba");
55 |
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/DatasetRowsMergingTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.qstd.QuickSqlTestData;
17 |
18 | import java.util.Random;
19 |
20 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
21 |
22 | public class DatasetRowsMergingTest extends H2Config {
23 |
24 | @Test public void
25 | should_merge_dataset_rows_if_columns_in_common_have_same_values() {
26 |
27 | // GIVEN
28 | TestTable table =
29 | TestTable.buildUniqueTable(DATA_SOURCE
30 | , "Table"
31 | , "col1 varchar(255)"
32 | + ", col2 varchar(255)"
33 | + ", col3 varchar(255)"
34 | )
35 | .create()
36 | .insertValues("'val1', 'val2', 'val3'");
37 |
38 | String tableName = table.getTableName();
39 | String select1 = "SELECT col1, col2 FROM " + tableName;
40 | String select2 = "SELECT col1, col3 FROM " + tableName;
41 |
42 | // WHEN
43 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
44 | String insertScript = quickSqlTestData.generateInsertScriptFor(select1, select2);
45 |
46 | // THEN
47 | table.recreate();
48 | SQL_EXECUTOR.execute(insertScript);
49 | assertThat(table).withScript(insertScript)
50 | .hasNumberOfRows(1)
51 | .row(0).hasValues("val1", "val2", "val3");
52 |
53 | }
54 |
55 | @Test public void
56 | should_merge_dataset_rows_in_case_of_joined_rows() {
57 |
58 | // GIVEN
59 | TestTable sponsorTable =
60 | TestTable.buildUniqueTable(DATA_SOURCE
61 | , "Sponsor"
62 | , " id bigint" +
63 | ", name varchar(255) not null" +
64 | ", country varchar(255)" +
65 | ", primary key (id)"
66 | )
67 | .create()
68 | .insertValues("1, 'Sponsor name', 'France'");
69 |
70 | String teamSponsorForeignKey = "add constraint team_sponsor_fk" + generateRandomPositiveInt()
71 | + " foreign key (sponsor_id)"
72 | + " references " + sponsorTable.getTableName();
73 |
74 | TestTable teamTable =
75 | TestTable.buildUniqueTable(DATA_SOURCE
76 | , "Team"
77 | ," id bigint not null" +
78 | ", name varchar(255) not null" +
79 | ", sponsor_id bigint not null" +
80 | ", primary key (id)"
81 | )
82 | .create()
83 | .alter(teamSponsorForeignKey)
84 | .insertValues("1, 'Manchester United', 1");
85 |
86 | String playerTeamForeignKey = "add constraint player_team_fk" + generateRandomPositiveInt()
87 | + " foreign key (team_id)"
88 | + " references " + teamTable.getTableName();
89 | TestTable playerTable =
90 | TestTable.buildUniqueTable(DATA_SOURCE
91 | , "Player"
92 | , "id bigint not null"
93 | + ", firstName varchar(255)"
94 | + ", lastName varchar(255)"
95 | + ", team_id bigint not null"
96 | + ", primary key (id)"
97 | )
98 | .create()
99 | .alter(playerTeamForeignKey)
100 | .insertValues("1, 'Paul', 'Pogba', 1");
101 |
102 | String playerSelect = "SELECT * FROM " + playerTable.getTableName();
103 | String sponsorSelect = "SELECT * FROM " + sponsorTable.getTableName();
104 |
105 | // WHEN
106 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
107 | String insertScript = quickSqlTestData.generateInsertScriptFor(playerSelect, sponsorSelect);
108 |
109 | // THEN
110 | playerTable.drop();
111 | teamTable.drop();
112 | sponsorTable.drop().create();
113 | teamTable.create().alter(teamSponsorForeignKey);
114 | playerTable.create().alter(playerTeamForeignKey);
115 | SQL_EXECUTOR.execute(insertScript);
116 |
117 | assertThat(sponsorTable).withScript(insertScript)
118 | .hasNumberOfRows(1)
119 | .row(0).hasValues(1, "Sponsor name", "France");
120 |
121 | }
122 |
123 | private int generateRandomPositiveInt() {
124 | Random random = new Random();
125 | return Math.abs(random.nextInt());
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/DeleteTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.qstd.QuickSqlTestData;
17 |
18 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
19 | import static org.qstd.test.TestTable.buildUniqueTable;
20 |
21 | public class DeleteTest extends H2Config {
22 |
23 | @Test
24 | public void
25 | should_generate_insert_if_all_rows_are_deleted_and_no_mandatory_columns() {
26 |
27 | // GIVEN
28 | TestTable table1 =
29 | buildUniqueTable(DATA_SOURCE
30 | , "Table_1"
31 | , " id bigint"
32 | + ", Col_A varchar(255)"
33 | + ", Col_B varchar(255)"
34 | + ", Col_dec decimal")
35 | .create()
36 | .insertValues("1, 'A1', 'B1', 1.80")
37 | .insertValues("2, 'A2', 'B2', 2.99");
38 |
39 | String deleteQuery = "DELETE FROM " + table1.getTableName();
40 |
41 | // WHEN
42 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
43 | String insertScript = quickSqlTestData.generateInsertScriptFor(deleteQuery);
44 |
45 | // THEN
46 | table1.recreate();
47 | SQL_EXECUTOR.execute(insertScript);
48 | assertThat(table1).withScript(insertScript)
49 | .hasNumberOfRows(2)
50 | .row(0).hasValues(1, "A1", "B1", 1.80)
51 | .row(1).hasValues(2, "A2", "B2", 2.99);
52 | }
53 |
54 | @Test
55 | public void
56 | should_generate_one_insert_if_one_rows_is_deleted() {
57 |
58 | // GIVEN
59 | TestTable table1 =
60 | buildUniqueTable(DATA_SOURCE
61 | , "Table_1"
62 | , " id bigint"
63 | + ", Col_A varchar(255)"
64 | + ", Col_B varchar(255)"
65 | + ", Col_dec decimal")
66 | .create()
67 | .insertValues("1, 'A1', 'B1', 1.80")
68 | .insertValues("2, 'A2', 'B2', 2.99");
69 |
70 | String updateQuery = "DELETE FROM " + table1.getTableName()
71 | + " WHERE Col_A = 'A1'";
72 |
73 | // WHEN
74 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
75 | String insertScript = quickSqlTestData.generateInsertScriptFor(updateQuery);
76 |
77 | // THEN
78 | table1.recreate();
79 | SQL_EXECUTOR.execute(insertScript);
80 | assertThat(table1).withScript(insertScript)
81 | .hasNumberOfRows(1)
82 | .row(0).hasValues(1, "A1", "B1", 1.80);
83 |
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/FastTestSuite.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.platform.runner.JUnitPlatform;
16 | import org.junit.platform.suite.api.SelectClasses;
17 | import org.junit.platform.suite.api.SuiteDisplayName;
18 | import org.junit.runner.RunWith;
19 |
20 | @RunWith(JUnitPlatform.class)
21 | @SuiteDisplayName("Fast tests")
22 | @SelectClasses( { H2Test.class
23 | , NotFullyManagedDatabaseTest.class
24 | , DatasetRowApiTest.class
25 | , SelectTest.class
26 | , UpdateTest.class
27 | , DeleteTest.class
28 | , InsertTest.class
29 | , H2DateTypesTest.class
30 | , SortInsertStatementsTest.class
31 | , SortInsertStatementsWithPkTest.class
32 | , DatasetRowsMergingTest.class
33 | , JdbcRoundtripTest.class} )
34 | public class FastTestSuite {
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/H2Config.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.BeforeAll;
16 | import org.quickperf.junit5.QuickPerfTest;
17 |
18 | import javax.sql.DataSource;
19 |
20 | import static org.quickperf.sql.config.QuickPerfSqlDataSourceBuilder.aDataSourceBuilder;
21 |
22 | @QuickPerfTest
23 | class H2Config {
24 |
25 | static DataSource DATA_SOURCE;
26 |
27 | static SqlExecutor SQL_EXECUTOR;
28 |
29 | @BeforeAll
30 | public static void beforeAll() {
31 | DataSource h2Datasource = DataSourceBuilder.build("jdbc:h2:mem:test", "user", "pwd");
32 | DATA_SOURCE = aDataSourceBuilder().buildProxy(h2Datasource);
33 | SQL_EXECUTOR = new SqlExecutor(DATA_SOURCE);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/H2DateTypesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.assertj.core.api.Assertions;
16 | import org.junit.jupiter.api.Test;
17 | import org.qstd.QuickSqlTestData;
18 |
19 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
20 | import static org.qstd.test.TestTable.buildUniqueTable;
21 |
22 | public class H2DateTypesTest extends H2Config {
23 |
24 | @Test public void
25 | should_generate_an_insert_statement_with_a_date_type() {
26 |
27 | // GIVEN
28 | TestTable playerTable =
29 | buildUniqueTable(DATA_SOURCE
30 | , "Table"
31 | , "date Date"
32 | )
33 | .create()
34 | .insertValues("'2012-09-17'");
35 |
36 | // WHEN
37 | String playerTableName = playerTable.getTableName();
38 | String select = "SELECT * FROM " + playerTableName;
39 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
40 | String insertScript = quickSqlTestData.generateInsertScriptFor(select);
41 |
42 | // THEN
43 | playerTable.recreate();
44 | SQL_EXECUTOR.execute(insertScript);
45 | assertThat(playerTable).withScript(insertScript)
46 | .hasNumberOfRows(1)
47 | .row(0).hasValues("2012-09-17");
48 |
49 | }
50 |
51 | @Test public void
52 | should_generate_an_insert_statement_with_a_timestamp_type() {
53 |
54 | // GIVEN
55 | TestTable playerTable =
56 | buildUniqueTable(DATA_SOURCE
57 | , "Table"
58 | , "timestampCol TIMESTAMP"
59 | )
60 | .create()
61 | .insertValues("'2012-09-17 19:56:47.32'");
62 |
63 | // WHEN
64 | String playerTableName = playerTable.getTableName();
65 | String select = "SELECT * FROM " + playerTableName;
66 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
67 | String insertScript = quickSqlTestData.generateInsertScriptFor(select);
68 |
69 | // THEN
70 | playerTable.recreate();
71 | SQL_EXECUTOR.execute(insertScript);
72 | assertThat(playerTable).withScript(insertScript)
73 | .hasNumberOfRows(1);
74 | Assertions.assertThat(insertScript).contains("'2012-09-17 19:56:47.32'");
75 |
76 | }
77 |
78 | @Test public void
79 | should_generate_an_insert_statement_with_a_timestamp_with_time_zone_type() {
80 |
81 | // GIVEN
82 | TestTable playerTable =
83 | buildUniqueTable(DATA_SOURCE
84 | , "Table"
85 | , "col TIMESTAMP WITH TIME ZONE"
86 | )
87 | .create()
88 | .insertValues("'2012-09-17 19:56:47.32 UTC'");
89 |
90 | // WHEN
91 | String playerTableName = playerTable.getTableName();
92 | String select = "SELECT * FROM " + playerTableName;
93 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
94 | String insertScript = quickSqlTestData.generateInsertScriptFor(select);
95 |
96 | // THEN
97 | playerTable.recreate();
98 | SQL_EXECUTOR.execute(insertScript);
99 | assertThat(playerTable).withScript(insertScript)
100 | .hasNumberOfRows(1);
101 |
102 | }
103 |
104 | @Test public void
105 | should_generate_an_insert_statement_with_a_time_type() {
106 |
107 | // GIVEN
108 | TestTable playerTable =
109 | buildUniqueTable(DATA_SOURCE
110 | , "Table"
111 | , "col TIME"
112 | )
113 | .create()
114 | .insertValues("'23:59:59'");
115 |
116 | // WHEN
117 | String playerTableName = playerTable.getTableName();
118 | String select = "SELECT * FROM " + playerTableName;
119 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
120 | String insertScript = quickSqlTestData.generateInsertScriptFor(select);
121 |
122 | // THEN
123 | playerTable.recreate();
124 | SQL_EXECUTOR.execute(insertScript);
125 | assertThat(playerTable).withScript(insertScript)
126 | .hasNumberOfRows(1)
127 | .row(0).hasValues("23:59:59");
128 |
129 | }
130 |
131 | @Test public void
132 | should_generate_an_insert_statement_with_a_time_with_timezone_type() {
133 |
134 | // GIVEN
135 | TestTable playerTable =
136 | buildUniqueTable(DATA_SOURCE
137 | , "Table"
138 | , "col TIME WITH TIME ZONE"
139 | )
140 | .create()
141 | .insertValues("'23:59:59 UTC'");
142 |
143 | // WHEN
144 | String playerTableName = playerTable.getTableName();
145 | String select = "SELECT * FROM " + playerTableName;
146 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
147 | String insertScript = quickSqlTestData.generateInsertScriptFor(select);
148 |
149 | // THEN
150 | playerTable.recreate();
151 | SQL_EXECUTOR.execute(insertScript);
152 | assertThat(playerTable).withScript(insertScript)
153 | .hasNumberOfRows(1);
154 |
155 | }
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/InsertTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.quickperf.sql.annotation.ExpectJdbcQueryExecution;
17 | import org.qstd.QuickSqlTestData;
18 |
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | public class InsertTest extends H2Config {
22 |
23 | @Test public void
24 | should_generate_an_empty_insert_script_for_an_insert_input() {
25 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
26 | String anInsertStatement = "INSERT INTO A_TABLE VALUES(1, 2, 3)";
27 | String insertScript = quickSqlTestData.generateInsertScriptFor(anInsertStatement);
28 | assertThat(insertScript).isEmpty();
29 | }
30 |
31 | @Test @ExpectJdbcQueryExecution(0) public void
32 | should_not_use_jdbc_execution_for_an_insert_input() {
33 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
34 | String anInsertStatement = "INSERT INTO A_TABLE VALUES(1, 2, 3)";
35 | quickSqlTestData.generateInsertScriptFor(anInsertStatement);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/JdbcRoundtripTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.AfterEach;
16 | import org.junit.jupiter.api.BeforeEach;
17 | import org.junit.jupiter.api.Test;
18 | import org.quickperf.sql.annotation.ExpectJdbcQueryExecution;
19 | import org.qstd.QuickSqlTestData;
20 |
21 | import java.util.Random;
22 |
23 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
24 |
25 | public class JdbcRoundtripTest extends H2Config {
26 |
27 | private TestTable t1Table;
28 | private TestTable t2Table;
29 | private TestTable t3Table;
30 | private String t2TableConstraint;
31 | private String insertScript;
32 |
33 | @BeforeEach
34 | public void prepare_test_data() {
35 |
36 | t1Table =
37 | TestTable.buildUniqueTable(DATA_SOURCE
38 | , "t1"
39 | , "id_t1 bigint not null" +
40 | ", c2_t1 varchar(255) not null" +
41 | ", c3_t1 varchar(255) not null" +
42 | ", c4_t1 varchar(255) not null" +
43 | ", primary key (id_t1)"
44 | )
45 | .create()
46 | .insertValues("1, 't1_r1_c1_val', 't1_r1_c2_val', 't1_r1_c3_val'")
47 | .insertValues("2, 't1_r2_c1_val', 't1_r2_c2_val', 't1_r2_c3_val'");
48 |
49 | t2TableConstraint = "add constraint t1_t2_fk" + generateRandomPositiveInt()
50 | + " foreign key (t1_id)"
51 | + " references " + t1Table.getTableName();
52 |
53 | t2Table =
54 | TestTable.buildUniqueTable(DATA_SOURCE
55 | , "t2"
56 | , "id_t2 bigint not null" +
57 | ", t1_id bigint not null" +
58 | ", c1_t2 varchar(255) not null" +
59 | ", c2_t2 varchar(255) not null" +
60 | ", c3_t2 varchar(255) not null" +
61 | ", primary key (id_t2)")
62 | .create()
63 | .alter(t2TableConstraint)
64 | .insertValues("1, 1, 't2_r1_c1_val', 't2_r1_c2_val', 't2_r1_c3_val'")
65 | .insertValues("2, 2, 't2_r2_c1_val', 't2_r2_c2_val', 't2_r2_c3_val'");
66 |
67 | t3Table =
68 | TestTable.buildUniqueTable(DATA_SOURCE
69 | , "t3"
70 | , "id_t3 bigint not null" +
71 | ", c2_t3 varchar(255) not null" +
72 | ", c3_t3 varchar(255) not null" +
73 | ", c4_t3 varchar(255) not null" +
74 | ", primary key (id_t3)")
75 | .create()
76 | .insertValues("1, 't3_r1_c1_val', 't3_r1_c2_val', 't3_r1_c3_val'")
77 | .insertValues("2, 't3_r2_c1_val', 't3_r2_c2_val', 't3_r2_c3_val'");
78 |
79 | }
80 |
81 | private int generateRandomPositiveInt() {
82 | Random random = new Random();
83 | return Math.abs(random.nextInt());
84 | }
85 |
86 | @ExpectJdbcQueryExecution(23)
87 | @Test public void
88 | should_limit_jdbc_roundtrips() {
89 | String t2Select = "SELECT c1_t2 FROM " + t2Table.getTableName();
90 | String t3Select = "SELECT c2_t3 FROM " + t3Table.getTableName();
91 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
92 | insertScript = quickSqlTestData.generateInsertScriptFor(t2Select, t3Select);
93 | }
94 |
95 | @AfterEach
96 | public void check_inserted_data() {
97 | t3Table.recreate();
98 | t2Table.drop();
99 | t1Table.drop().create();
100 | t2Table.create().alter(t2TableConstraint);
101 | SQL_EXECUTOR.execute(insertScript);
102 | assertThat(t1Table).withScript(insertScript)
103 | .hasNumberOfRows(2);
104 | assertThat(t2Table).withScript(insertScript)
105 | .hasNumberOfRows(2);
106 | assertThat(t3Table).withScript(insertScript)
107 | .hasNumberOfRows(2);
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/MariaDBSlowTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.BeforeAll;
16 | import org.junit.jupiter.api.Test;
17 | import org.qstd.QuickSqlTestData;
18 | import org.testcontainers.containers.MariaDBContainer;
19 |
20 | import javax.sql.DataSource;
21 | import java.util.List;
22 | import java.util.Random;
23 |
24 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
25 | import static org.qstd.test.TestTable.buildUniqueTable;
26 |
27 | public class MariaDBSlowTest {
28 |
29 | private static final String DB_USER_NAME = "user";
30 |
31 | private static final String DB_PASSWORD = "pwd";
32 |
33 | private static final MariaDBContainer MARIA_DB_CONTAINER
34 | = new MariaDBContainer<>("mariadb:10.5.2")
35 | .withDatabaseName("mariadb")
36 | .withUsername(DB_USER_NAME)
37 | .withPassword(DB_PASSWORD);
38 |
39 | private static DataSource DATA_SOURCE;
40 |
41 | private static SqlExecutor SQL_EXECUTOR;
42 |
43 | @BeforeAll
44 | public static void beforeAll() {
45 | MARIA_DB_CONTAINER.start();
46 | String jdbcUrl = MARIA_DB_CONTAINER.getJdbcUrl();
47 | DATA_SOURCE = DataSourceBuilder.INSTANCE.build(jdbcUrl, DB_USER_NAME, DB_PASSWORD);
48 | SQL_EXECUTOR = new SqlExecutor(DATA_SOURCE);
49 | }
50 |
51 | @Test public void
52 | should_sort_insert_statements_following_table_dependencies() {
53 |
54 | // GIVEN
55 | TestTable teamTable =
56 | buildUniqueTable(DATA_SOURCE
57 | , "Team"
58 | ," id bigint not null" +
59 | ", name varchar(255)" +
60 | ", primary key (id)")
61 | .create()
62 | .insertValues("1, 'Manchester United'");
63 |
64 | String playerTableConstraint = "add constraint player_team_fk" + generateRandomPositiveInt()
65 | + " foreign key (team_id)"
66 | + " references " + teamTable.getTableName() + " (id)";
67 | TestTable playerTable =
68 | buildUniqueTable(DATA_SOURCE
69 | , "Player"
70 | , "id bigint not null"
71 | + ", firstName varchar(255)"
72 | + ", lastName varchar(255)"
73 | + ", team_id bigint"
74 | + ", primary key (id)")
75 | .create()
76 | .alter(playerTableConstraint)
77 | .insertValues("1, 'Paul', 'Pogba', 1");
78 |
79 | // WHEN
80 | String playerSelect = "SELECT * FROM " + playerTable.getTableName();
81 | String teamSelect = "SELECT * FROM " + teamTable.getTableName();
82 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
83 | List insertStatements = quickSqlTestData.generateInsertListFor(playerSelect, teamSelect);
84 |
85 | // THEN
86 | playerTable.drop();
87 | teamTable.drop().create();
88 | playerTable.create().alter(playerTableConstraint);
89 | SQL_EXECUTOR.execute(insertStatements);
90 | assertThat(playerTable).withGeneratedInserts(insertStatements)
91 | .hasNumberOfRows(1);
92 | assertThat(teamTable).withGeneratedInserts(insertStatements)
93 | .hasNumberOfRows(1);
94 |
95 | }
96 |
97 | private int generateRandomPositiveInt() {
98 | Random random = new Random();
99 | return Math.abs(random.nextInt());
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/NotFullyManagedDatabaseTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.qstd.DatabaseMetadataFinder;
17 | import org.qstd.QuickSqlTestData;
18 | import org.qstd.dbtype.DatabaseType;
19 |
20 | import static org.qstd.dbtype.DatabaseMetadataFinderFactory.createDatabaseMetadataFinderFrom;
21 | import static org.qstd.test.TestTable.*;
22 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
23 |
24 | public class NotFullyManagedDatabaseTest extends H2Config {
25 |
26 | @Test public void
27 | should_generate_insert_statements_without_necessarily_taking_account_of_database_constraints_if_the_database_is_not_supposed_to_be_fully_managed() {
28 |
29 | // GIVEN
30 | TestTable table =
31 | buildUniqueTable(DATA_SOURCE
32 | , "Table"
33 | , "col1 varchar(25)"
34 | + ", col2 varchar(25)"
35 | + ", col3 varchar(25)"
36 | )
37 | .create()
38 | .insertValues("'val1', 'val2', 'val3'")
39 | .insertValues("'val3', 'val4', 'val5'");
40 |
41 | DatabaseMetadataFinder databaseMetadataFinderOfNotFullyManagedDatabase =
42 | createDatabaseMetadataFinderFrom(DATA_SOURCE, DatabaseType.OTHER);
43 | QuickSqlTestData quickSqlTestDataOfNotFullyManagedDatabase =
44 | QuickSqlTestData.buildFrom(DATA_SOURCE, DatabaseType.OTHER
45 | , databaseMetadataFinderOfNotFullyManagedDatabase);
46 |
47 | String select = "SELECT col1, col2 FROM " + table.getTableName();
48 |
49 | // WHEN
50 | String insertScript = quickSqlTestDataOfNotFullyManagedDatabase.generateInsertScriptFor(select);
51 |
52 | // THEN
53 | table.recreate();
54 | SQL_EXECUTOR.execute(insertScript);
55 | assertThat(table).withScript(insertScript)
56 | .hasNumberOfRows(2);
57 |
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/SelectTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.qstd.QuickSqlTestData;
17 |
18 | import java.util.Arrays;
19 | import java.util.List;
20 |
21 | import static org.qstd.test.TestTable.*;
22 | import static org.qstd.test.TestTable.TestTableAssert.*;
23 |
24 | public class SelectTest extends H2Config {
25 |
26 | @Test public void
27 | should_generate_working_insert_from_a_select_statement() {
28 |
29 | // GIVEN
30 | TestTable playerTable =
31 | buildUniqueTable(DATA_SOURCE
32 | , "Player"
33 | , " id bigint"
34 | + ", firstName varchar(255)"
35 | + ", lastName varchar(255)"
36 | )
37 | .create()
38 | .insertValues("1, 'Paul', 'Pogba'")
39 | .insertValues("2, 'Antoine', 'Griezmann'");
40 |
41 | // WHEN
42 | String playerTableName = playerTable.getTableName();
43 | String select = "SELECT * FROM " + playerTableName;
44 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
45 | String insertScript = quickSqlTestData.generateInsertScriptFor(select);
46 |
47 | // THEN
48 | playerTable.recreate();
49 | SQL_EXECUTOR.execute(insertScript);
50 | assertThat(playerTable).withScript(insertScript)
51 | .hasNumberOfRows(2)
52 | .row(0).hasValues(1, "Paul", "Pogba")
53 | .row(1).hasValues(2, "Antoine", "Griezmann");
54 |
55 | }
56 |
57 | @Test public void
58 | should_generate_an_insert_statement_from_a_select_containing_bind_parameters() {
59 |
60 | // GIVEN
61 | TestTable table =
62 | buildUniqueTable(DATA_SOURCE
63 | , "Table"
64 | , "col1 varchar(25)"
65 | + ", col2 varchar(25)"
66 | + ", col3 varchar(25)"
67 | )
68 | .create()
69 | .insertValues("'val1', 'val2', 'val3'");
70 |
71 | String tableName = table.getTableName();
72 | String select = " SELECT col1, col2, col3 FROM " + tableName
73 | + " WHERE col2=? AND col3=?";
74 |
75 | List parameterValues = Arrays.asList("val2", "val3");
76 |
77 | // WHEN
78 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
79 | String insertScript = quickSqlTestData.generateInsertScriptFor(select, parameterValues);
80 |
81 | // THEN
82 | table.recreate();
83 | SQL_EXECUTOR.execute(insertScript);
84 | assertThat(table).withScript(insertScript)
85 | .hasNumberOfRows(1)
86 | .row(0).hasValues("val1", "val2", "val3");
87 |
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/SortInsertStatementsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.RepeatedTest;
16 | import org.qstd.QuickSqlTestData;
17 |
18 | import java.util.List;
19 | import java.util.Random;
20 |
21 | import static org.assertj.core.api.Assertions.assertThat;
22 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
23 | import static org.qstd.test.TestTable.buildUniqueTable;
24 |
25 | public class SortInsertStatementsTest extends H2Config {
26 |
27 | @RepeatedTest(9) public void
28 | should_sort_insert_statements_following_table_dependencies() {
29 |
30 | // GIVEN
31 | TestTable teamTable =
32 | buildUniqueTable(DATA_SOURCE
33 | , "Team"
34 | ," id bigint not null" +
35 | ", name varchar(255)" +
36 | ", primary key (id)"
37 | )
38 | .create()
39 | .insertValues("1, 'Manchester United'");
40 |
41 | String playerTableConstraint = "add constraint player_team_fk" + generateRandomPositiveInt()
42 | + " foreign key (team_id)"
43 | + " references " + teamTable.getTableName();
44 | TestTable playerTable =
45 | buildUniqueTable(DATA_SOURCE
46 | , "Player"
47 | , "id bigint not null"
48 | + ", firstName varchar(255)"
49 | + ", lastName varchar(255)"
50 | + ", team_id bigint"
51 | + ", primary key (id)"
52 | )
53 | .create()
54 | .alter(playerTableConstraint)
55 | .insertValues("1, 'Paul', 'Pogba', 1");
56 |
57 | String playerSelect = "SELECT * FROM " + playerTable.getTableName();
58 | String teamSelect = "SELECT * FROM " + teamTable.getTableName();
59 |
60 | // WHEN
61 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
62 | String insertScript = quickSqlTestData.generateInsertScriptFor(playerSelect, teamSelect);
63 |
64 | // THEN
65 | playerTable.drop();
66 | teamTable.drop().create();
67 | playerTable.create().alter(playerTableConstraint);
68 | SQL_EXECUTOR.execute(insertScript);
69 | assertThat(playerTable).withScript(insertScript)
70 | .hasNumberOfRows(1);
71 | assertThat(teamTable).withScript(insertScript)
72 | .hasNumberOfRows(1);
73 |
74 | }
75 |
76 | private int generateRandomPositiveInt() {
77 | Random random = new Random();
78 | return Math.abs(random.nextInt());
79 | }
80 |
81 | @RepeatedTest(9) public void
82 | should_sort_insert_statements_following_table_names_if_independent_tables() {
83 |
84 | TestTable testTable1 =
85 | buildUniqueTable(DATA_SOURCE
86 | , "TABLE_1"
87 | , "col varchar(20)"
88 | )
89 | .create()
90 | .insertValues("'value_col_tab1'");
91 |
92 | TestTable testTable2 =
93 | buildUniqueTable(DATA_SOURCE
94 | , "TABLE_2"
95 | , "col varchar(20)"
96 | )
97 | .create()
98 | .insertValues("'value_col_tab2'");
99 |
100 | String tab1Select = "SELECT * FROM " + testTable1.getTableName();
101 | String tab2Select = "SELECT * FROM " + testTable2.getTableName();
102 |
103 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
104 | List insertStatements = quickSqlTestData.generateInsertListFor(tab2Select, tab1Select);
105 |
106 | assertThat(insertStatements.get(0)).contains(testTable1.getTableName());
107 | assertThat(insertStatements.get(1)).contains(testTable2.getTableName());
108 |
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/SqlExecutor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import javax.sql.DataSource;
16 | import java.sql.Connection;
17 | import java.sql.PreparedStatement;
18 | import java.sql.SQLException;
19 | import java.util.List;
20 |
21 | public class SqlExecutor {
22 |
23 | private final DataSource dataSource;
24 |
25 | SqlExecutor(DataSource dataSource) {
26 | this.dataSource = dataSource;
27 | }
28 |
29 | void execute(List queries) {
30 | for (String query : queries) {
31 | execute(query);
32 | }
33 | }
34 |
35 | void execute(String sql) {
36 | try (Connection connection = dataSource.getConnection();
37 | PreparedStatement statement = connection.prepareStatement(sql)) {
38 | statement.execute();
39 | } catch (SQLException e) {
40 | throw new IllegalStateException("Unable to execute " + System.lineSeparator() + sql, e);
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/TestTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.assertj.core.api.AbstractAssert;
16 | import org.assertj.db.api.Assertions;
17 | import org.assertj.db.api.TableAssert;
18 | import org.assertj.db.api.TableRowAssert;
19 | import org.assertj.db.type.Table;
20 |
21 | import javax.sql.DataSource;
22 | import java.util.List;
23 | import java.util.Random;
24 |
25 | class TestTable {
26 |
27 | private final String tableName;
28 |
29 | private final String creationScript;
30 |
31 | private final DataSource dataSource;
32 |
33 | private final SqlExecutor sqlExecutor;
34 |
35 | TestTable(DataSource dataSource, String tableName, String creationScript) {
36 | this.tableName = tableName;
37 | this.creationScript = creationScript;
38 | this.dataSource = dataSource;
39 | this.sqlExecutor = new SqlExecutor(dataSource);
40 | }
41 |
42 | static TestTable buildUniqueTable(DataSource dataSource
43 | , String baseTableName
44 | , String colDescsAndConstraints) {
45 | String tableName = buildUniqueTableName(baseTableName);
46 | String creationScript = "create table " + tableName
47 | + "(" + colDescsAndConstraints + ")";
48 | return new TestTable(dataSource, tableName, creationScript);
49 | }
50 |
51 | private static String buildUniqueTableName(String baseTableName) {
52 | return baseTableName + "_" + generateRandomPositiveInt();
53 | }
54 |
55 | private static int generateRandomPositiveInt() {
56 | Random random = new Random();
57 | return Math.abs(random.nextInt());
58 | }
59 |
60 | TestTable recreate() {
61 | drop();
62 | create();
63 | return this;
64 | }
65 |
66 | TestTable drop() {
67 | sqlExecutor.execute("drop table " + tableName);
68 | return this;
69 | }
70 |
71 | TestTable create() {
72 | sqlExecutor.execute(creationScript);
73 | return this;
74 | }
75 |
76 | TestTable insertValues(String valuesSeparatedWithCommas) {
77 | String insert = "INSERT INTO " + tableName + " VALUES (" +valuesSeparatedWithCommas + ")";
78 | sqlExecutor.execute(insert);
79 | return this;
80 | }
81 |
82 | String getTableName() {
83 | return tableName;
84 | }
85 |
86 | TestTable alter(String alterCode) {
87 | sqlExecutor.execute("alter table " + tableName + " " + alterCode);
88 | return this;
89 | }
90 |
91 | static class TestTableAssert extends AbstractAssert {
92 |
93 | private static final String LINE_SEPARATOR = System.lineSeparator();
94 | private Table assertJDbTable;
95 |
96 | TestTableAssert(TestTable testTable, Class> selfType) {
97 | super(testTable, TestTableAssert.class);
98 | }
99 |
100 | static TestTableAssert assertThat(TestTable testTable) {
101 | TestTableAssert testTableAssert = new TestTableAssert(testTable, TestTableAssert.class);
102 | testTableAssert.assertJDbTable = new Table(testTable.dataSource, testTable.tableName);
103 | return testTableAssert;
104 | }
105 |
106 | TableAssert hasNumberOfRows(int expected) {
107 | return Assertions.assertThat(assertJDbTable).hasNumberOfRows(expected);
108 | }
109 |
110 | TableAssert withScript(String sqlScript) {
111 | String description = LINE_SEPARATOR
112 | + "SQL script: "
113 | + LINE_SEPARATOR
114 | + sqlScript
115 | + LINE_SEPARATOR;
116 | return Assertions.assertThat(assertJDbTable).as(description);
117 | }
118 |
119 | TableRowAssert row(int index) {
120 | return Assertions.assertThat(assertJDbTable).row(index);
121 | }
122 |
123 | TableAssert withGeneratedInserts(List generatedInsertStatements) {
124 | String description = LINE_SEPARATOR
125 | + "Queries: "
126 | + LINE_SEPARATOR
127 | + String.join(LINE_SEPARATOR, generatedInsertStatements);
128 | return Assertions.assertThat(assertJDbTable).as(description);
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/test/java/org/qstd/test/UpdateTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
3 | * the License. You may obtain a copy of the License at
4 | *
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | *
7 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 | * specific language governing permissions and limitations under the License.
10 | *
11 | * Copyright 2021-2022 the original author or authors.
12 | */
13 | package org.qstd.test;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.qstd.QuickSqlTestData;
17 |
18 | import static org.qstd.test.TestTable.TestTableAssert.assertThat;
19 | import static org.qstd.test.TestTable.buildUniqueTable;
20 |
21 | public class UpdateTest extends H2Config {
22 |
23 | @Test public void
24 | should_generate_one_insert_if_all_rows_are_updated_and_no_mandatory_columns() {
25 |
26 | // GIVEN
27 | TestTable foodTable =
28 | buildUniqueTable(DATA_SOURCE
29 | , "Food"
30 | , " id bigint"
31 | + ", Dishname varchar(255)"
32 | + ", Allergy varchar(255)"
33 | + ", Price decimal")
34 | .create()
35 | .insertValues("1, 'Spaghetti Bolognese', 'cheese', 6.80")
36 | .insertValues("2, 'Pizza Margherita', 'pasta', 7.99");
37 |
38 | // WHEN
39 | String foodTableName = foodTable.getTableName();
40 | String updateQuery = "UPDATE " + foodTableName
41 | + " SET Price = 7.00, Allergy = 'none'";
42 |
43 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
44 | String insertScript = quickSqlTestData.generateInsertScriptFor(updateQuery);
45 |
46 | // THEN
47 | foodTable.recreate();
48 | SQL_EXECUTOR.execute(insertScript);
49 | assertThat(foodTable).withScript(insertScript)
50 | .hasNumberOfRows(2)
51 | .row(0).hasValues(null, null, "cheese", 6.80);
52 |
53 | }
54 |
55 | @Test public void
56 | should_generate_insert_statements_from_update_containing_where_or_like() {
57 |
58 | // GIVEN
59 | TestTable foodTable =
60 | buildUniqueTable(DATA_SOURCE
61 | , "Food"
62 | , " id bigint"
63 | + ", Dishname varchar(255)"
64 | + ", Allergy varchar(255)"
65 | + ", Price decimal")
66 | .create()
67 | .insertValues("1, 'Spaghetti Bolognese', 'cheese', 6.80")
68 | .insertValues("2, 'Pizza', 'pasta', 10.99");
69 |
70 | // WHEN
71 | String foodTableName = foodTable.getTableName();
72 | String updateQuery = "UPDATE " + foodTableName + " SET Price = 7.00"
73 | + " WHERE Allergy LIKE 'past%' OR Allergy = 'cheese'"
74 | + " OR Dishname = 'Pizza'";
75 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
76 | String insertScript = quickSqlTestData.generateInsertScriptFor(updateQuery);
77 |
78 | // THEN
79 | foodTable.recreate();
80 | SQL_EXECUTOR.execute(insertScript);
81 | assertThat(foodTable).withScript(insertScript)
82 | .hasNumberOfRows(2)
83 | .column(0).hasOnlyNullValues()
84 | .column(1).containsValues("Spaghetti Bolognese", "Pizza")
85 | .column(2).containsValues("cheese", "pasta")
86 | .column(3).containsValues(6.80, 10.99);
87 |
88 | }
89 |
90 |
91 | @Test public void
92 | should_generate_insert_statements_from_update_containing_where_columnnames_values_positions_are_swapped() {
93 |
94 | // GIVEN
95 | TestTable foodTable =
96 | buildUniqueTable(DATA_SOURCE
97 | , "Food"
98 | , " id bigint"
99 | + ", Dishname varchar(255)"
100 | + ", Allergy varchar(255)"
101 | + ", Price decimal")
102 | .create()
103 | .insertValues("1, 'Spaghetti Bolognese', 'cheese', 6.80")
104 | .insertValues("2, 'Pizza', 'pasta', 10.99");
105 |
106 | // WHEN
107 | String foodTableName = foodTable.getTableName();
108 | String updateQuery = "UPDATE " + foodTableName + " SET Price = 7.00"
109 | + " WHERE Allergy LIKE 'past%' OR 'cheese' = Allergy"
110 | + " OR 'Pizza' = Dishname";
111 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
112 | String insertScript = quickSqlTestData.generateInsertScriptFor(updateQuery);
113 |
114 | // THEN
115 | foodTable.recreate();
116 | SQL_EXECUTOR.execute(insertScript);
117 | assertThat(foodTable).withScript(insertScript)
118 | .hasNumberOfRows(2)
119 | .column(0).hasOnlyNullValues()
120 | .column(1).containsValues("Spaghetti Bolognese", "Pizza")
121 | .column(2).containsValues("cheese", "pasta")
122 | .column(3).containsValues(6.80, 10.99);
123 |
124 | }
125 |
126 | @Test public void
127 | should_generate_insert_statement_from_update_containing_where_like_and() {
128 |
129 | // GIVEN
130 | TestTable foodTable =
131 | buildUniqueTable(DATA_SOURCE
132 | , "Food"
133 | , " id bigint"
134 | + ", Dishname varchar(255)"
135 | + ", Allergy varchar(255)"
136 | + ", Price decimal")
137 | .create()
138 | .insertValues("1, 'Spaghetti Bolognese', 'cheese', 6.80")
139 | .insertValues("2, 'Pizza', 'pasta', 10.99");
140 |
141 | // WHEN
142 | String foodTableName = foodTable.getTableName();
143 | String updateQuery = "UPDATE " + foodTableName + " SET Price = 7.00"
144 | + " WHERE Allergy LIKE 'past%'"
145 | + " AND Dishname = 'Pizza'";
146 | QuickSqlTestData quickSqlTestData = QuickSqlTestData.buildFrom(DATA_SOURCE);
147 | String insertScript = quickSqlTestData.generateInsertScriptFor(updateQuery);
148 |
149 | // THEN
150 | foodTable.recreate();
151 | SQL_EXECUTOR.execute(insertScript);
152 | assertThat(foodTable).withScript(insertScript)
153 | .hasNumberOfRows(1)
154 | .row(0).hasValues(null, "Pizza", "pasta", 10.99);
155 |
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/src/test/resources/junit-platform.properties:
--------------------------------------------------------------------------------
1 | junit.jupiter.displayname.generator.default = \
2 | org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
19 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------