├── .github └── workflows │ └── build-and-release.yml ├── .gitignore ├── .idea ├── .gitignore ├── .name ├── discord.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── intellij-javadocs-4.0.1.xml ├── misc.xml ├── uiDesigner.xml └── vcs.xml ├── .jitpack.yml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md ├── settings.gradle ├── sql_lava_logo.png └── src ├── main └── java │ └── me │ └── cobeine │ └── sqlava │ └── connection │ ├── Callback.java │ ├── Connection.java │ ├── ConnectionResult.java │ ├── auth │ ├── AuthenticatedConnection.java │ ├── BasicMySQLCredentials.java │ ├── CredentialsHolder.java │ └── CredentialsKey.java │ ├── database │ ├── MySQLConnection.java │ ├── query │ │ ├── PreparedQuery.java │ │ ├── Query.java │ │ ├── QueryHandler.java │ │ └── impl │ │ │ ├── DeleteQuery.java │ │ │ ├── InsertQuery.java │ │ │ ├── SelectQuery.java │ │ │ └── UpdateQuery.java │ └── table │ │ ├── ForeignKey.java │ │ ├── OnDelete.java │ │ ├── Table.java │ │ ├── TableCommands.java │ │ └── column │ │ ├── Column.java │ │ ├── ColumnSettings.java │ │ └── ColumnType.java │ ├── pool │ ├── ConnectionPool.java │ └── PooledConnection.java │ ├── presets │ ├── HikariDataSourcePresets.java │ └── MysqlJDBCDriverPresets.java │ └── util │ └── JdbcUrlBuilder.java └── test └── java ├── ExampleTable.java └── Examples.java /.github/workflows/build-and-release.yml: -------------------------------------------------------------------------------- 1 | name: Build and Release ShadowJar 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build-and-release: 11 | permissions: 12 | contents: write 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v3 17 | 18 | - name: Set up Java 11 19 | uses: actions/setup-java@v3 20 | with: 21 | distribution: 'temurin' 22 | java-version: '11' 23 | 24 | - name: Extract version 25 | id: get_version 26 | run: | 27 | VERSION=$(grep -E "^version\s+['\"]" build.gradle | head -n 1 | sed -E "s/version\s+['\"]([^'\"]+)['\"]/\1/") 28 | echo "Found version: $VERSION" 29 | echo "::set-output name=VERSION::$VERSION" 30 | 31 | - name: Check if version is new 32 | id: version_check 33 | run: | 34 | CURRENT_VERSION=${{ steps.get_version.outputs.VERSION }} 35 | echo "Current version: $CURRENT_VERSION" 36 | if git rev-parse "refs/tags/${CURRENT_VERSION}" >/dev/null 2>&1; then 37 | echo "Tag ${CURRENT_VERSION} already exists. Skipping release." 38 | echo "::set-output name=new_version::false" 39 | else 40 | echo "Tag ${CURRENT_VERSION} does not exist. Proceeding with release." 41 | echo "::set-output name=new_version::true" 42 | fi 43 | - name: Grant execute permission for Gradle wrapper 44 | run: chmod +x gradlew 45 | 46 | - name: Build shadowJar 47 | if: steps.version_check.outputs.new_version == 'true' 48 | run: ./gradlew shadowJar 49 | 50 | - name: Create Release 51 | if: steps.version_check.outputs.new_version == 'true' 52 | id: create_release 53 | uses: ncipollo/release-action@v1 54 | with: 55 | tag: ${{ steps.get_version.outputs.VERSION }} 56 | name: Release ${{ steps.get_version.outputs.VERSION }} 57 | generateReleaseNotes: true 58 | 59 | - name: Upload artifact to release 60 | if: steps.version_check.outputs.new_version == 'true' 61 | uses: softprops/action-gh-release@v1 62 | with: 63 | tag_name: ${{ steps.get_version.outputs.VERSION }} 64 | files: build/libs/*-all.jar 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | SQLava -------------------------------------------------------------------------------- /.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /.idea/intellij-javadocs-4.0.1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UPDATE 6 | false 7 | true 8 | 9 | FIELD 10 | METHOD 11 | TYPE 12 | 13 | 14 | DEFAULT 15 | PROTECTED 16 | PUBLIC 17 | 18 | 19 | 20 | 21 | 22 | ^.*(public|protected|private)*.+interface\s+\w+.* 23 | /**\n 24 | * The interface ${name}.\n 25 | <#if element.typeParameters?has_content> * \n 26 | </#if> 27 | <#list element.typeParameters as typeParameter> 28 | * @param <${typeParameter.name}> the type parameter\n 29 | </#list> 30 | */ 31 | 32 | 33 | ^.*(public|protected|private)*.+enum\s+\w+.* 34 | /**\n 35 | * The enum ${name}.\n 36 | */ 37 | 38 | 39 | ^.*(public|protected|private)*.+class\s+\w+.* 40 | /**\n 41 | * The type ${name}.\n 42 | <#if element.typeParameters?has_content> * \n 43 | </#if> 44 | <#list element.typeParameters as typeParameter> 45 | * @param <${typeParameter.name}> the type parameter\n 46 | </#list> 47 | */ 48 | 49 | 50 | .+ 51 | /**\n 52 | * The type ${name}.\n 53 | */ 54 | 55 | 56 | 57 | 58 | .+ 59 | /**\n 60 | * Instantiates a new ${name}.\n 61 | <#if element.parameterList.parameters?has_content> 62 | *\n 63 | </#if> 64 | <#list element.parameterList.parameters as parameter> 65 | * @param ${parameter.name} the ${paramNames[parameter.name]}\n 66 | </#list> 67 | <#if element.throwsList.referenceElements?has_content> 68 | *\n 69 | </#if> 70 | <#list element.throwsList.referenceElements as exception> 71 | * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n 72 | </#list> 73 | */ 74 | 75 | 76 | 77 | 78 | ^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+ 79 | /**\n 80 | * Gets ${partName}.\n 81 | <#if element.typeParameters?has_content> * \n 82 | </#if> 83 | <#list element.typeParameters as typeParameter> 84 | * @param <${typeParameter.name}> the type parameter\n 85 | </#list> 86 | <#if element.parameterList.parameters?has_content> 87 | *\n 88 | </#if> 89 | <#list element.parameterList.parameters as parameter> 90 | * @param ${parameter.name} the ${paramNames[parameter.name]}\n 91 | </#list> 92 | <#if isNotVoid> 93 | *\n 94 | * @return the ${partName}\n 95 | </#if> 96 | <#if element.throwsList.referenceElements?has_content> 97 | *\n 98 | </#if> 99 | <#list element.throwsList.referenceElements as exception> 100 | * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n 101 | </#list> 102 | */ 103 | 104 | 105 | ^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+ 106 | /**\n 107 | * Sets ${partName}.\n 108 | <#if element.typeParameters?has_content> * \n 109 | </#if> 110 | <#list element.typeParameters as typeParameter> 111 | * @param <${typeParameter.name}> the type parameter\n 112 | </#list> 113 | <#if element.parameterList.parameters?has_content> 114 | *\n 115 | </#if> 116 | <#list element.parameterList.parameters as parameter> 117 | * @param ${parameter.name} the ${paramNames[parameter.name]}\n 118 | </#list> 119 | <#if isNotVoid> 120 | *\n 121 | * @return the ${partName}\n 122 | </#if> 123 | <#if element.throwsList.referenceElements?has_content> 124 | *\n 125 | </#if> 126 | <#list element.throwsList.referenceElements as exception> 127 | * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n 128 | </#list> 129 | */ 130 | 131 | 132 | ^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+ 133 | /**\n 134 | * The entry point of application.\n 135 | 136 | <#if element.parameterList.parameters?has_content> 137 | *\n 138 | </#if> 139 | * @param ${element.parameterList.parameters[0].name} the input arguments\n 140 | <#if element.throwsList.referenceElements?has_content> 141 | *\n 142 | </#if> 143 | <#list element.throwsList.referenceElements as exception> 144 | * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n 145 | </#list> 146 | */ 147 | 148 | 149 | .+ 150 | /**\n 151 | * ${name}<#if isNotVoid> ${return}</#if>.\n 152 | <#if element.typeParameters?has_content> * \n 153 | </#if> 154 | <#list element.typeParameters as typeParameter> 155 | * @param <${typeParameter.name}> the type parameter\n 156 | </#list> 157 | <#if element.parameterList.parameters?has_content> 158 | *\n 159 | </#if> 160 | <#list element.parameterList.parameters as parameter> 161 | * @param ${parameter.name} the ${paramNames[parameter.name]}\n 162 | </#list> 163 | <#if isNotVoid> 164 | *\n 165 | * @return the ${return}\n 166 | </#if> 167 | <#if element.throwsList.referenceElements?has_content> 168 | *\n 169 | </#if> 170 | <#list element.throwsList.referenceElements as exception> 171 | * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n 172 | </#list> 173 | */ 174 | 175 | 176 | 177 | 178 | ^.*(public|protected|private)*.+static.*(\w\s\w)+.+ 179 | /**\n 180 | * The constant ${element.getName()}.\n 181 | */ 182 | 183 | 184 | ^.*(public|protected|private)*.*(\w\s\w)+.+ 185 | /**\n 186 | <#if element.parent.isInterface()> 187 | * The constant ${element.getName()}.\n 188 | <#else> 189 | * The ${name}.\n 190 | </#if> */ 191 | 192 | 193 | .+ 194 | /**\n 195 | <#if element.parent.isEnum()> 196 | *${name} ${typeName}.\n 197 | <#else> 198 | * The ${name}.\n 199 | </#if>*/ 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk11 3 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'com.github.johnrengelman.shadow' version '7.1.1' 4 | id 'maven-publish' 5 | 6 | } 7 | 8 | group 'github.Cobeine' 9 | version '1.6.1-SNAPSHOT' 10 | 11 | repositories { 12 | mavenCentral() 13 | mavenLocal() 14 | } 15 | 16 | dependencies { 17 | compileOnly 'org.projectlombok:lombok:1.18.26' 18 | compileOnly 'org.jetbrains:annotations:23.0.0' 19 | compileOnly 'org.slf4j:slf4j-jdk14:1.6.0' //2.0.0 fails to bind with SLF4J somehow 20 | compileOnly 'com.zaxxer:HikariCP:4.0.3' 21 | annotationProcessor 'org.projectlombok:lombok:1.18.26' 22 | 23 | } 24 | 25 | publishing { 26 | publications { 27 | mavenJava(MavenPublication) { 28 | from components.java 29 | } 30 | } 31 | repositories { 32 | maven { 33 | url 'https://jitpack.io' 34 | } 35 | } 36 | } 37 | shadowJar { 38 | println "We have been here :P" 39 | archiveBaseName.set("SQLava") 40 | archiveClassifier.set("") 41 | } 42 | 43 | 44 | apply plugin: 'com.github.johnrengelman.shadow' 45 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobeine/SQLava/53596c99339ab0dd6dc6cc70356f698a837015fe/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Stop when "xargs" is not available. 209 | if ! command -v xargs >/dev/null 2>&1 210 | then 211 | die "xargs is not available" 212 | fi 213 | 214 | # Use "xargs" to parse quoted args. 215 | # 216 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 217 | # 218 | # In Bash we could simply go: 219 | # 220 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 221 | # set -- "${ARGS[@]}" "$@" 222 | # 223 | # but POSIX shell has neither arrays nor command substitution, so instead we 224 | # post-process each arg (as a line of input to sed) to backslash-escape any 225 | # character that might be a shell metacharacter, then use eval to reverse 226 | # that process (while maintaining the separation between arguments), and wrap 227 | # the whole thing up as a single "set" statement. 228 | # 229 | # This will of course break if any of these variables contains a newline or 230 | # an unmatched quote. 231 | # 232 | 233 | eval "set -- $( 234 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 235 | xargs -n1 | 236 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 237 | tr '\n' ' ' 238 | )" '"$@"' 239 | 240 | exec "$JAVACMD" "$@" 241 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if %ERRORLEVEL% equ 0 goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if %ERRORLEVEL% equ 0 goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | sqlava logo 2 | 3 |

CodeFactor

4 | 5 | #

SQLava

6 |

Streamline MySQL interactions with SQLava, the beginner-friendly query builder for Java!

7 |

Effortlessly construct complex queries with its intuitive syntax, designed for all skill levels

8 | 9 | ## ✨ Key Features: 10 | 11 | - Intuitive Query Building: Craft elegant queries with ease, even without extensive SQL knowledge. 12 | - Asynchronous Excellence: Experience lightning-fast performance with asynchronous handling of connections and queries. 13 | - Beginner-Friendly: Dive in without hesitation, thanks to its clear and concise syntax. 14 | - Seamless Integration: Effortlessly incorporate SQLava into your Java projects. 15 | 16 | ## Installation 17 | [![](https://jitpack.io/v/Cobeine/SQLava.svg)](https://jitpack.io/#Cobeine/SQLava) 18 |

19 | If you're using maven or gradle as a dependency manager then just follow the steps below. 20 | Otherwise, just download the jar and add it as an artifact dependency. 21 | 22 | ### Adding the repository 23 | 24 | ###### Maven 25 | ```xml 26 | 27 | 28 | jitpack.io 29 | https://jitpack.io 30 | 31 | 32 | ``` 33 | 34 | ###### Gradle 35 | ```groovy 36 | 37 | repositories { 38 | mavenCentral() 39 | maven { 40 | url 'https://jitpack.io' 41 | } 42 | } 43 | ``` 44 | 45 | ### Implementing the dependency 46 | 47 | ###### Maven 48 | ```xml 49 | 50 | com.github.Cobeine 51 | SQLava 52 | {VERSION} 53 | 54 | ``` 55 | 56 | ###### Gradle 57 | ```groovy 58 | 59 | dependencies { 60 | implementation 'com.github.Cobeine:SQLava:{VERSION}' 61 | //Please note that my library is dependant on Hikrai 5.0.1 or above 62 | //So, make sure to implement HikariCP in your project. 63 | } 64 | ``` 65 | 66 | ### Examples 67 | 68 | #### Connection Examples: 69 | ```java 70 | public class Test { 71 | /** 72 | * Connection example 73 | * for driver classes @see me.cobeine.sqlava.connection.presets.MysqlJDBCDriverPresets; 74 | */ 75 | private MySQLConnection connection; 76 | public void examples() { 77 | var url = JdbcUrlBuilder.newBuilder() 78 | .host("host") 79 | .port(3306) 80 | .setAuto_reconnect(true) 81 | .database("database") 82 | .build(); 83 | CredentialsRecord mysql_creds = CredentialsRecord.builder() 84 | .add(BasicMySQLCredentials.USERNAME,"username") 85 | .add(BasicMySQLCredentials.PASSWORD,"password") 86 | .add(BasicMySQLCredentials.DATABASE,"database") 87 | .add(BasicMySQLCredentials.PORT,3306) 88 | .add(BasicMySQLCredentials.POOL_SIZE,8) 89 | .add(BasicMySQLCredentials.JDBC_URL, url) 90 | .build(); 91 | 92 | connection = new MySQLConnection(mysql_creds); 93 | connection.connect(result -> { 94 | if (result.getException().isEmpty()) { 95 | result.getException().get().printStackTrace(); 96 | return; 97 | } 98 | //successfully connected 99 | connection.getTableCommands().createTable(new ExampleTable(),tableResult -> { 100 | if (tableResult.getException().isPresent()) { 101 | tableResult.getException().get().printStackTrace(); 102 | return; 103 | } 104 | //successfully created table 105 | }); 106 | }); 107 | 108 | PreparedQuery query = connection.prepareStatement("SELECT * FROM example WHERE uuid=test"); 109 | query = connection.prepareStatement(Query.select("example").where("uuid", "test")); 110 | 111 | query.executeQuery(); 112 | query.executeQueryAsync(result -> { 113 | if (result.getException().isPresent()) { 114 | result.getException().get().printStackTrace(); 115 | return; 116 | } 117 | //successfully executed query 118 | result.getResult().ifPresent(resultSet -> { 119 | //... 120 | }); 121 | }); 122 | 123 | Query update = Query.update("example").set("uuid","test").where("id",1).and("uuid","test2"); 124 | 125 | update = Query.update("example").set("uuid").where("id").where("uuid"); 126 | connection.prepareStatement(update) 127 | .setParameter(1,"test") 128 | .setParameter(2,1) 129 | .setParameter(3,"test2").executeUpdateAsync(result -> { 130 | 131 | if (result.getException().isPresent()) { 132 | result.getException().get().printStackTrace(); 133 | return; 134 | } 135 | //successfully executed query 136 | }); 137 | } 138 | 139 | void methods(){ 140 | connection.connect(); 141 | connection.getLogger(); 142 | connection.getPool(); 143 | connection.getCredentialsRecord(); 144 | connection.closeConnection(); 145 | connection.prepareStatement(); // with args; 146 | 147 | JdbcUrlBuilder.newBuilder() 148 | .host("host") 149 | .port(3306) 150 | .database("test") 151 | .setAuto_reconnect(true) 152 | .build(); 153 | } 154 | 155 | 156 | } 157 | 158 | ``` 159 | #### Table Example 160 | ```java 161 | 162 | public class Example extends Table { 163 | 164 | 165 | public Example() { 166 | super("example"); 167 | addColumns( 168 | Column.of("id", ColumnType.INT).settings(ColumnSettings.AUTO_INCREMENT, ColumnSettings.UNIQUE), 169 | Column.of("uuid", ColumnType.TEXT).settings(ColumnSettings.NOT_NULL, ColumnSettings.UNIQUE).defaultValue("none"), 170 | Column.of("name", ColumnType.VARCHAR).size(64).settings(ColumnSettings.NOT_NULL, ColumnSettings.UNIQUE).defaultValue("none"), 171 | Column.of("rank", ColumnType.VARCHAR).size(64).settings(ColumnSettings.NOT_NULL).defaultValue("DEFAULT") 172 | ); 173 | setPrimaryKey("id"); 174 | 175 | } 176 | } 177 | ``` 178 | 179 | #### Query examples 180 | ```java 181 | public class Examples { 182 | public void examples() { 183 | 184 | Table table = new Table(); 185 | connection.getTableCommands().createTable(table); 186 | 187 | connection.prepareStatement( 188 | Query.select("test").where("id").and("uuid")) 189 | .setParameter(1, 5) 190 | .setParameter(2, UUID.randomUUID()) 191 | .executeQueryAsync(result -> 192 | result.executeIfPresent(resultSet -> { 193 | resultSet.next(); // or hasNext depending on you 194 | int id = resultSet.getInt("id"); //examples 195 | 196 | }).orElse(exception -> { 197 | if (exception != null) 198 | exception.printStackTrace(); 199 | }).apply() 200 | ); 201 | 202 | //or 203 | 204 | Query selectQuery = Query.select("table").where("uuid").and("id"); 205 | PreparedQuery query = selectQuery.prepareStatement(connection); 206 | query.setParameter(1, UUID.randomUUID()).setParameter(2, 1); 207 | try (ResultSet set = query.executeQuery()) { 208 | set.getInt("id");//etc 209 | } catch (SQLException e) { 210 | e.printStackTrace(); 211 | } 212 | } 213 | 214 | } 215 | 216 | ``` 217 | 218 | 219 | ### Contributing 220 | 221 | Before contributing to this project, please note the following: 222 | 223 | ###### - Test your changes: Ensure that any changes you make to the project have been thoroughly tested before submitting them. 224 | 225 | ###### - Provide documentation: If you are adding new features or functionality, consider providing clear and concise documentation to help other contributors understand how to use them. 226 | 227 | ###### - Follow established standards: Adhere to established coding standards and best practices to ensure that your contributions are consistent with the rest of the project. 228 | 229 | ###### - Submit changes appropriately: Follow the project's preferred method of submitting changes, whether that is through pull requests, commits, or another method specified by the project owner. 230 | 231 | 232 | ####

Thanks for reading & reviewing my project!

233 | #####

Special thanks to @AkramLZ for inspiration!

234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'SQLava' 2 | 3 | -------------------------------------------------------------------------------- /sql_lava_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobeine/SQLava/53596c99339ab0dd6dc6cc70356f698a837015fe/sql_lava_logo.png -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/Callback.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection; 2 | 3 | import me.cobeine.sqlava.connection.database.query.QueryHandler; 4 | 5 | /** 6 | * @author Cobeine 7 | */ 8 | 9 | public interface Callback{ 10 | void onCall(QueryHandler result); 11 | 12 | default void call(V r, T t) { 13 | try { 14 | onCall(QueryHandler.of(r, t)); 15 | } catch (Exception e) { 16 | e.printStackTrace(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/Connection.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | 6 | /** 7 | * @Author Cobeine 8 | */ 9 | 10 | public interface Connection { 11 | 12 | C getConnection(); 13 | 14 | ConnectionResult connect(); 15 | 16 | default void closeConnection() { 17 | if (getConnection() instanceof Closeable){ 18 | try { 19 | ((Closeable) getConnection()).close(); 20 | } catch (IOException e) { 21 | throw new RuntimeException(e); 22 | } 23 | return; 24 | } else if (getConnection() instanceof AutoCloseable) { 25 | try { 26 | ((AutoCloseable) getConnection()).close(); 27 | } catch (Exception e) { 28 | throw new RuntimeException(e); 29 | } 30 | return; 31 | } 32 | throw new UnsupportedOperationException("Cannot close a non-closable connection!"); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/ConnectionResult.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection; 2 | 3 | /** 4 | * The enum Connection result. 5 | * 6 | * @Author Cobeine 7 | */ 8 | public enum ConnectionResult { 9 | 10 | /** 11 | * Success connection result. 12 | */ 13 | SUCCESS, 14 | /** 15 | * Fail connection result. 16 | */ 17 | FAIL 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/auth/AuthenticatedConnection.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.auth; 2 | 3 | import me.cobeine.sqlava.connection.Connection; 4 | 5 | /** 6 | * @Author Cobeine 7 | */ 8 | 9 | public interface AuthenticatedConnection extends Connection { 10 | 11 | CredentialsHolder getCredentialsHolder(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/auth/BasicMySQLCredentials.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.auth; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author Cobeine 8 | */ 9 | @AllArgsConstructor 10 | @Getter 11 | public enum BasicMySQLCredentials implements CredentialsKey { 12 | HOST("serverName", String.class,true), 13 | PORT("port", Integer.class,true), 14 | DATABASE("databaseName", String.class,true), 15 | USERNAME("user", String.class,true), 16 | PASSWORD("password", String.class,true), 17 | MAX_LIFETIME("maximumLifetime", Integer.class,true), 18 | DATASOURCE_CLASS_NAME("dataSourceClassName", String.class,false), 19 | DRIVER("JdbcDriver", String.class,false), 20 | POOL_SIZE("poolSize", Integer.class,false), 21 | JDBC_URL("jdbcUrl",String.class,false); 22 | 23 | private final String key; 24 | private final Class dataType; 25 | private final boolean property; 26 | 27 | @Override 28 | public CredentialsKey[] array() { 29 | return values(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/auth/CredentialsHolder.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.auth; 2 | 3 | 4 | import java.util.*; 5 | 6 | /** 7 | * @Author Cobeine 8 | */ 9 | 10 | public class CredentialsHolder { 11 | private final Map record; 12 | 13 | public CredentialsHolder() { 14 | record = new HashMap<>(); 15 | } 16 | public T getProperty(CredentialsKey key, Class dataType) { 17 | if (!record.containsKey(key)) { 18 | if (key.equals(BasicMySQLCredentials.JDBC_URL)) { 19 | return null; 20 | } 21 | if (key.equals(BasicMySQLCredentials.MAX_LIFETIME)) { 22 | return null; 23 | } 24 | if (key.isProperty()) { 25 | throw new IllegalStateException("Key not found: " + key.getKey()); 26 | } 27 | } 28 | return dataType.cast(record.get(key)); 29 | } 30 | public Optional get(CredentialsKey key, Class dataType) { 31 | if (!record.containsKey(key)) { 32 | return Optional.empty(); 33 | } 34 | return Optional.of(dataType.cast(record.get(key))); 35 | } 36 | 37 | public static CredentialsRecordBuilder builder() { 38 | return new CredentialsRecordBuilder(); 39 | } 40 | 41 | public List keySet() { 42 | return new ArrayList<>(record.keySet()); 43 | } 44 | 45 | public static class CredentialsRecordBuilder { 46 | 47 | private final CredentialsHolder recorder; 48 | 49 | public CredentialsRecordBuilder() { 50 | this.recorder = new CredentialsHolder(); 51 | } 52 | 53 | public CredentialsRecordBuilder add(CredentialsKey key, Object value) { 54 | recorder.record.put(key, value); 55 | return this; 56 | } 57 | public CredentialsHolder build() { 58 | return recorder; 59 | } 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/auth/CredentialsKey.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.auth; 2 | 3 | /** 4 | * @Author Cobeine 5 | */ 6 | 7 | public interface CredentialsKey { 8 | 9 | 10 | String getKey(); 11 | 12 | boolean isProperty(); 13 | 14 | CredentialsKey[] array(); 15 | 16 | Class getDataType(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/MySQLConnection.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database; 2 | 3 | import com.zaxxer.hikari.HikariConfig; 4 | import com.zaxxer.hikari.HikariDataSource; 5 | import lombok.Getter; 6 | import me.cobeine.sqlava.connection.Callback; 7 | import me.cobeine.sqlava.connection.auth.AuthenticatedConnection; 8 | import me.cobeine.sqlava.connection.auth.BasicMySQLCredentials; 9 | import me.cobeine.sqlava.connection.auth.CredentialsKey; 10 | import me.cobeine.sqlava.connection.auth.CredentialsHolder; 11 | import me.cobeine.sqlava.connection.database.query.PreparedQuery; 12 | import me.cobeine.sqlava.connection.database.query.Query; 13 | import me.cobeine.sqlava.connection.database.table.TableCommands; 14 | import me.cobeine.sqlava.connection.pool.ConnectionPool; 15 | import me.cobeine.sqlava.connection.pool.PooledConnection; 16 | import me.cobeine.sqlava.connection.ConnectionResult; 17 | 18 | import java.sql.Connection; 19 | import java.sql.SQLException; 20 | import java.util.logging.Logger; 21 | 22 | /** 23 | * @Author Cobeine 24 | */ 25 | @Getter 26 | public class MySQLConnection implements AuthenticatedConnection, PooledConnection{ 27 | 28 | private ConnectionPool pool; 29 | private final CredentialsHolder credentialsHolder; 30 | private final Logger logger; 31 | private HikariDataSource dataSource; 32 | private final TableCommands TableCommands; 33 | 34 | public MySQLConnection(CredentialsHolder record) { 35 | this.credentialsHolder = record; 36 | this.TableCommands = new TableCommands(this); 37 | logger = Logger.getLogger(this.getClass().getName()); 38 | } 39 | 40 | public void connect(Callback callback) { 41 | try { 42 | connect(); 43 | callback.call(0,null); 44 | }catch (Exception e){ 45 | callback.call(-1,e); 46 | } 47 | } 48 | @Override 49 | public ConnectionResult connect() { 50 | HikariConfig config = new HikariConfig(); 51 | if (credentialsHolder.getProperty(BasicMySQLCredentials.DATASOURCE_CLASS_NAME,String.class) != null) { 52 | config.setDataSourceClassName(credentialsHolder.getProperty(BasicMySQLCredentials.DATASOURCE_CLASS_NAME, String.class)); 53 | } 54 | if (credentialsHolder.getProperty(BasicMySQLCredentials.DRIVER, String.class) != null) { 55 | config.setDriverClassName(credentialsHolder.getProperty(BasicMySQLCredentials.DRIVER, String.class)); 56 | } 57 | if (credentialsHolder.getProperty(BasicMySQLCredentials.JDBC_URL,String.class) != null) { 58 | config.setJdbcUrl(credentialsHolder.getProperty(BasicMySQLCredentials.JDBC_URL,String.class)); 59 | } 60 | if (credentialsHolder.getProperty(BasicMySQLCredentials.MAX_LIFETIME,Integer.class) != null) { 61 | config.setMaxLifetime(credentialsHolder.getProperty(BasicMySQLCredentials.MAX_LIFETIME,Integer.class)); 62 | } 63 | if (credentialsHolder.getProperty(BasicMySQLCredentials.POOL_SIZE,Integer.class) != null) { 64 | config.setMaximumPoolSize(credentialsHolder.getProperty(BasicMySQLCredentials.POOL_SIZE, Integer.class)); 65 | } 66 | for (CredentialsKey credentialsKey : credentialsHolder.keySet()) { 67 | if (credentialsKey.isProperty()) { 68 | config.addDataSourceProperty(credentialsKey.getKey(), credentialsHolder.getProperty(credentialsKey,credentialsKey.getDataType())); 69 | } 70 | } 71 | 72 | dataSource = new HikariDataSource(config); 73 | this.pool = new ConnectionPool<>(dataSource) { 74 | @Override 75 | public Connection resource() { 76 | try { 77 | return getSource().getConnection(); 78 | } catch (SQLException e) { 79 | e.printStackTrace(); 80 | return null; 81 | } 82 | } 83 | }; 84 | try (Connection autoClosable = getPool().resource()) { 85 | return ConnectionResult.SUCCESS; 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | return ConnectionResult.FAIL; 89 | } 90 | } 91 | 92 | public PreparedQuery prepareStatement(Query query) { 93 | return query.prepareStatement(this); 94 | } 95 | public PreparedQuery prepareStatement(String query) { 96 | return new PreparedQuery(this, query); 97 | } 98 | 99 | @Override 100 | public HikariDataSource getConnection() { 101 | return dataSource; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/PreparedQuery.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query; 2 | 3 | import me.cobeine.sqlava.connection.Callback; 4 | import me.cobeine.sqlava.connection.database.MySQLConnection; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import javax.sql.rowset.CachedRowSet; 8 | import javax.sql.rowset.RowSetProvider; 9 | import java.sql.*; 10 | 11 | /** 12 | * @author Cobeine 13 | */ 14 | 15 | public class PreparedQuery { 16 | private final MySQLConnection sqlConnection; 17 | private Connection connection; 18 | private PreparedStatement statement; 19 | boolean batched; 20 | public PreparedQuery(@NotNull MySQLConnection sqlConnection, @NotNull String buildQuery) { 21 | this.sqlConnection = sqlConnection; 22 | try { 23 | this.connection = sqlConnection.getConnection().getConnection(); 24 | this.statement = connection.prepareStatement(buildQuery); 25 | } catch (SQLException e) { 26 | sqlConnection.getLogger().severe(String.format("Failed to prepare statement of query '%s': %s", buildQuery, e)); 27 | } 28 | } 29 | public PreparedQuery setParameter(int index, Object value) { 30 | 31 | try { 32 | if (statement == null) 33 | return this; 34 | 35 | if (value instanceof String) statement.setString(index, (String) value); 36 | else statement.setObject(index, value); 37 | } catch (Exception ignored) { 38 | } 39 | return this; 40 | } 41 | 42 | public int[] executeBatch() throws SQLException { 43 | try { 44 | return statement.executeBatch(); 45 | } finally { 46 | if (statement != null) { 47 | statement.close(); 48 | } 49 | 50 | if (connection != null) { 51 | connection.commit(); 52 | connection.close(); 53 | } 54 | } 55 | } 56 | 57 | public void executeBatchAsync() { 58 | executeBatchAsync(null); 59 | } 60 | 61 | public void executeBatchAsync(final Callback callback) { 62 | sqlConnection.getPool().submit(() -> { 63 | try { 64 | int[] rowsChanged = executeBatch(); 65 | if (callback != null) { 66 | callback.call(rowsChanged, null); 67 | } 68 | } catch (SQLException e) { 69 | if (callback != null) { 70 | callback.call(null, e); 71 | } 72 | } 73 | }); 74 | } 75 | 76 | public int executeUpdate() throws SQLException { 77 | try { 78 | return statement.executeUpdate(); 79 | 80 | } finally { 81 | 82 | if (statement != null && !statement.isClosed()) 83 | statement.close(); 84 | 85 | if (connection != null) 86 | connection.close(); 87 | 88 | } 89 | } 90 | 91 | public int executeUpdateWithKeys() throws SQLException { 92 | try { 93 | String stm = statement.toString(); 94 | String sql = stm.substring(stm.indexOf("INSERT")); 95 | statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); 96 | ResultSet resultSet = statement.getGeneratedKeys(); 97 | if (resultSet == null || !resultSet.next()) 98 | return 0; 99 | return resultSet.getInt(1); 100 | } finally { 101 | 102 | if (statement != null) 103 | statement.close(); 104 | 105 | if (connection != null) 106 | connection.close(); 107 | 108 | } 109 | } 110 | 111 | public ResultSet executeQuery() throws SQLException { 112 | CachedRowSet rowSet = RowSetProvider.newFactory().createCachedRowSet(); 113 | 114 | try (ResultSet resultSet = statement.executeQuery()) { 115 | 116 | rowSet.populate(resultSet); 117 | 118 | } finally { 119 | 120 | if (statement != null && !statement.isClosed()) 121 | statement.close(); 122 | 123 | if (connection != null) 124 | connection.close(); 125 | 126 | } 127 | return rowSet; 128 | } 129 | 130 | public void executeUpdateAsync(final Callback callback) { 131 | sqlConnection.getPool().submit(() -> { 132 | 133 | try { 134 | int rowsChanged = executeUpdate(); 135 | if (callback != null) 136 | callback.call(rowsChanged, null); 137 | 138 | } catch (SQLException e) { 139 | if (callback != null) 140 | callback.call(0, e); 141 | else 142 | e.printStackTrace(); 143 | } 144 | }); 145 | } 146 | public void addBatch() throws SQLException { 147 | if (!batched) { 148 | if (connection.getAutoCommit()) { 149 | connection.setAutoCommit(false); 150 | } 151 | batched = true; 152 | } 153 | statement.addBatch(); 154 | } 155 | 156 | public void addBatch(String s) throws SQLException { 157 | addBatch(); 158 | statement.addBatch(s); 159 | } 160 | 161 | public void executeUpdateAsyncWithGeneratedKeys( Callback callback) { 162 | sqlConnection.getPool().submit(() -> { 163 | 164 | try { 165 | int id = executeUpdateWithKeys(); 166 | if (callback != null) 167 | callback.call(id, null); 168 | 169 | } catch (SQLException e) { 170 | if (callback != null) 171 | callback.call(0, e); 172 | else 173 | e.printStackTrace(); 174 | } 175 | }); 176 | } 177 | 178 | public void executeUpdateAsync() { 179 | executeUpdateAsync(null); 180 | } 181 | public void executeQueryAsync(final Callback callback) { 182 | sqlConnection.getPool().submit(() -> { 183 | try { 184 | ResultSet rs = executeQuery(); 185 | callback.call(rs, null); 186 | } catch (SQLException e) { 187 | callback.call(null, e); 188 | } 189 | }); 190 | } 191 | @SuppressWarnings("unused") 192 | public void rollback() throws SQLException { 193 | if (connection != null) 194 | connection.rollback(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/Query.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query; 2 | 3 | import me.cobeine.sqlava.connection.database.query.impl.SelectQuery; 4 | import me.cobeine.sqlava.connection.database.MySQLConnection; 5 | import me.cobeine.sqlava.connection.database.query.impl.DeleteQuery; 6 | import me.cobeine.sqlava.connection.database.query.impl.InsertQuery; 7 | import me.cobeine.sqlava.connection.database.query.impl.UpdateQuery; 8 | 9 | import java.util.Collection; 10 | 11 | /** 12 | * @author Cobeine 13 | */ 14 | 15 | public interface Query { 16 | 17 | default PreparedQuery prepareStatement(MySQLConnection sqlConnection) { 18 | return new PreparedQuery(sqlConnection, build()); 19 | } 20 | 21 | String build(); 22 | 23 | default String separate(Collection collection, String separator) { 24 | StringBuilder builder = new StringBuilder(); 25 | String sep = ""; 26 | for (String item : collection) { 27 | builder.append(sep).append(item); 28 | sep = separator; 29 | } 30 | return builder.toString(); 31 | } 32 | default String separate(Collection collection) { 33 | return separate(collection, ","); 34 | } 35 | 36 | 37 | static SelectQuery select(String from) { 38 | return new SelectQuery(from); 39 | } 40 | static DeleteQuery delete(String from) { 41 | return new DeleteQuery(from); 42 | } 43 | static InsertQuery insert(String into) { 44 | return new InsertQuery(into); 45 | } 46 | static UpdateQuery update(String into) { 47 | return new UpdateQuery(into); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/QueryHandler.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | 5 | import java.sql.SQLException; 6 | import java.util.Optional; 7 | 8 | /** 9 | * @author Cobeine 10 | */ 11 | @RequiredArgsConstructor(staticName = "of") 12 | public final class QueryHandler { 13 | 14 | private final V result; 15 | private final T throwable; 16 | private Executor throwableExecutor; 17 | private Executor resultExecutor; 18 | 19 | public Optional getResult() { 20 | return Optional.ofNullable(result); 21 | } 22 | 23 | public Optional getException() { 24 | return Optional.ofNullable(throwable); 25 | } 26 | 27 | public QueryHandler executeIfPresent(Executor executor) { 28 | this.resultExecutor = executor; 29 | return this; 30 | } 31 | 32 | public void apply() { 33 | if (getException().isPresent()) { 34 | applyThrowable(); 35 | return; 36 | } 37 | if (getResult().isPresent()) 38 | applyResult(); 39 | } 40 | 41 | private void applyResult() { 42 | if (resultExecutor == null) return; 43 | try { 44 | if (getResult().isPresent()) { 45 | resultExecutor.execute(getResult().get()); 46 | } 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | public QueryHandler orElse(Executor exception) { 53 | this.throwableExecutor = exception; 54 | return this; 55 | } 56 | 57 | private void applyThrowable() { 58 | if (throwableExecutor == null) return; 59 | try { 60 | if (getException().isPresent()) { 61 | throwableExecutor.execute(getException().get()); 62 | } 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | public interface Executor { 69 | void execute(V v) throws SQLException; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/impl/DeleteQuery.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query.impl; 2 | 3 | import me.cobeine.sqlava.connection.database.query.Query; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Cobeine 10 | */ 11 | 12 | public class DeleteQuery implements Query { 13 | private final String table; 14 | private final List wheres = new ArrayList<>(); 15 | public DeleteQuery(String table) { 16 | this.table = table; 17 | } 18 | 19 | public DeleteQuery where(String expression) { 20 | wheres.add(expression + "=?"); 21 | return this; 22 | } 23 | public DeleteQuery where(String... expression) { 24 | for (String s : expression) { 25 | wheres.add(s + "=?"); 26 | } 27 | return this; 28 | } 29 | public DeleteQuery where(String expression,Object value) { 30 | wheres.add(expression + "=" + (value instanceof String ? "'" + value +"'" : value)); 31 | return this; 32 | } 33 | public DeleteQuery and(String expression) { 34 | where(expression); 35 | return this; 36 | } 37 | public DeleteQuery and(String expression,Object value) { 38 | where(expression,value); 39 | return this; 40 | } 41 | 42 | 43 | @Override 44 | public String build() { 45 | StringBuilder builder = new StringBuilder(); 46 | builder.append("DELETE FROM ").append(table); 47 | 48 | if (wheres.size() > 0) 49 | builder.append(" WHERE ").append(separate(wheres, " AND ")); 50 | 51 | return builder.toString(); 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/impl/InsertQuery.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query.impl; 2 | 3 | import me.cobeine.sqlava.connection.database.query.Query; 4 | 5 | import java.util.LinkedHashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * @author Cobeine 10 | */ 11 | 12 | public class InsertQuery implements Query { 13 | private final String table; 14 | private final LinkedHashMap values = new LinkedHashMap<>(); 15 | private final LinkedHashMap duplicateValues = new LinkedHashMap<>(); 16 | private boolean onDuplicateKey = false; 17 | 18 | public InsertQuery(String table) { 19 | this.table = table; 20 | } 21 | 22 | 23 | public InsertQuery value(String column, String value) { 24 | values.put(column, value); 25 | return this; 26 | } 27 | 28 | 29 | public InsertQuery value(String column) { 30 | value(column, "?"); 31 | return this; 32 | } 33 | public InsertQuery values(String... column) { 34 | for (String s : column) { 35 | values.put(s, "?"); 36 | } 37 | return this; 38 | } 39 | 40 | public InsertQuery onDuplicateKeyUpdate() { 41 | onDuplicateKey = true; 42 | return this; 43 | } 44 | 45 | 46 | public InsertQuery set(String column, String value) { 47 | duplicateValues.put(column, value); 48 | return this; 49 | } 50 | 51 | 52 | public InsertQuery set(String column) { 53 | set(column, "VALUES(" + column + ")"); 54 | return this; 55 | } 56 | 57 | 58 | @Override 59 | public String build() { 60 | StringBuilder builder = new StringBuilder(); 61 | builder.append("INSERT INTO ").append(table).append(" (") 62 | .append(separate(values.keySet())).append(")").append(" VALUES (").append(separate(values.values())).append(")"); 63 | 64 | if (onDuplicateKey) { 65 | builder.append(" ON DUPLICATE KEY UPDATE "); 66 | 67 | String separator = ""; 68 | if (duplicateValues.isEmpty()) { 69 | String sep = ""; 70 | for (String s : values.keySet()) { 71 | builder.append(sep).append(s).append("=").append("VALUES(").append(s).append(")"); 72 | sep = ", "; 73 | } 74 | }else { 75 | for (Map.Entry entry : duplicateValues.entrySet()) { 76 | String column = entry.getKey(); 77 | String value = entry.getValue(); 78 | builder.append(separator).append(column).append("=").append(value); 79 | separator = ","; 80 | } 81 | } 82 | 83 | } 84 | return builder.toString(); 85 | } 86 | 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/impl/SelectQuery.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query.impl; 2 | 3 | import me.cobeine.sqlava.connection.database.query.Query; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Cobeine 11 | */ 12 | 13 | public class SelectQuery implements Query { 14 | private final String table; 15 | private final List columns = new ArrayList<>(); 16 | private final List wheres = new ArrayList<>(); 17 | private String orderBy; 18 | private boolean orderByAscending = false; 19 | private int limitOffset = 0; 20 | private int limitRowCount = 0; 21 | 22 | public SelectQuery(String table) { 23 | this.table = table; 24 | } 25 | 26 | 27 | public SelectQuery column(String column) { 28 | columns.add(column); 29 | return this; 30 | } 31 | public SelectQuery column(String... column) { 32 | columns.addAll(Arrays.asList(column)); 33 | return this; 34 | } 35 | 36 | public SelectQuery where(String expression) { 37 | wheres.add(expression + "=?"); 38 | return this; 39 | } 40 | public SelectQuery where(String... expression) { 41 | for (String s : expression) { 42 | wheres.add(s + "=?"); 43 | } 44 | return this; 45 | } 46 | public SelectQuery where(String expression,Object value) { 47 | wheres.add(expression + "=" + (value instanceof String ? "'" + value +"'" : value)); 48 | return this; 49 | } 50 | public SelectQuery and(String expression) { 51 | where(expression); 52 | return this; 53 | } 54 | public SelectQuery and(String expression,Object value) { 55 | where(expression,value); 56 | return this; 57 | } 58 | 59 | public SelectQuery orderBy(String column, boolean ascending) { 60 | this.orderBy = column; 61 | this.orderByAscending = ascending; 62 | return this; 63 | } 64 | 65 | 66 | public SelectQuery limit(int offset, int rowCount) { 67 | this.limitOffset = offset; 68 | this.limitRowCount = rowCount; 69 | return this; 70 | } 71 | 72 | public SelectQuery limit(int rowCount) { 73 | this.limitOffset = 0; 74 | this.limitRowCount = rowCount; 75 | return this; 76 | } 77 | 78 | @Override 79 | public String build() { 80 | StringBuilder builder = new StringBuilder(); 81 | 82 | if (columns.isEmpty()) builder.append("SELECT *").append(" FROM ").append(table); 83 | 84 | else builder.append("SELECT ").append(separate(columns)).append(" FROM ").append(table); 85 | 86 | if (wheres.size() > 0) 87 | builder.append(" WHERE ").append(separate(wheres, " AND ")); 88 | 89 | if (orderBy != null) 90 | builder.append(" ORDER BY ").append(orderBy).append(orderByAscending ? " ASC" : " DESC"); 91 | 92 | if (limitRowCount > 0) 93 | builder.append(" LIMIT ").append(limitOffset).append(",").append(limitRowCount); 94 | 95 | 96 | return builder.toString(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/query/impl/UpdateQuery.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.query.impl; 2 | 3 | import me.cobeine.sqlava.connection.database.query.Query; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedHashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author Cobeine 12 | */ 13 | 14 | public class UpdateQuery implements Query { 15 | private final String table; 16 | private final LinkedHashMap values = new LinkedHashMap<>(); 17 | private final List wheres = new ArrayList<>(); 18 | 19 | public UpdateQuery(String table) { 20 | this.table = table; 21 | } 22 | 23 | public UpdateQuery setMultiple(String... column) { 24 | for (String s : column) { 25 | set(s, "?"); 26 | } 27 | return this; 28 | } 29 | public UpdateQuery set(String column, String value) { 30 | values.put(column, value); 31 | return this; 32 | } 33 | 34 | public UpdateQuery set(String column) { 35 | set(column, "?"); 36 | return this; 37 | } 38 | public UpdateQuery where(String expression) { 39 | wheres.add(expression + "=?"); 40 | return this; 41 | } 42 | public UpdateQuery where(String... expression) { 43 | for (String s : expression) { 44 | wheres.add(s + "=?"); 45 | } 46 | return this; 47 | } 48 | public UpdateQuery where(String expression,Object value) { 49 | wheres.add(expression + "=" + (value instanceof String ? "'" + value +"'" : value)); 50 | return this; 51 | } 52 | public UpdateQuery and(String expression) { 53 | where(expression); 54 | return this; 55 | } 56 | public UpdateQuery and(String expression,Object value) { 57 | where(expression,value); 58 | return this; 59 | } 60 | 61 | @Override 62 | public String build() { 63 | StringBuilder builder = new StringBuilder(); 64 | builder.append("UPDATE ").append(table).append(" SET "); 65 | 66 | String seperator = ""; 67 | for (Map.Entry entry : values.entrySet()) { 68 | 69 | String column = entry.getKey(); 70 | String value = entry.getValue(); 71 | builder.append(seperator) 72 | .append(column) 73 | .append("=") 74 | .append(value); 75 | seperator = ","; 76 | 77 | } 78 | 79 | if (!wheres.isEmpty()) 80 | builder.append(" WHERE ").append(separate(wheres, " AND ")); 81 | 82 | return builder.toString(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/ForeignKey.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | /** 7 | * @author Cobeine 8 | */ 9 | @RequiredArgsConstructor 10 | public class ForeignKey { 11 | final String foreignKey; 12 | String referencedColumn; 13 | String referencedTable; 14 | OnDelete onDelete; 15 | 16 | 17 | public static ForeignKey foreignKey(String foreignKey) { 18 | return new ForeignKey(foreignKey); 19 | } 20 | 21 | public ForeignKey references(String referencedTable, String referencedColumn) { 22 | this.referencedTable = referencedTable; 23 | this.referencedColumn = referencedColumn; 24 | return this; 25 | } 26 | 27 | public ForeignKey onDelete(OnDelete onDelete) { 28 | this.onDelete = onDelete; 29 | return this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/OnDelete.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table; 2 | 3 | /** 4 | * @author Cobeine 5 | */ 6 | 7 | public enum OnDelete { 8 | CASCADE, SET_NULL, RESTRICT, NO_ACTION, SET_DEFAULT, DO_NOTHING 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/Table.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table; 2 | 3 | import lombok.Getter; 4 | import me.cobeine.sqlava.connection.database.table.column.Column; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | 11 | /** 12 | * @author Cobeine 13 | */ 14 | 15 | public abstract class Table { 16 | 17 | @Getter private final String name; 18 | private final List columns; 19 | private String primaryKey; 20 | private final List foreignKeys; 21 | private final HashMap uniqueKeys; 22 | 23 | public Table(String name) { 24 | this.name = name; 25 | this.columns = new ArrayList<>(); 26 | this.foreignKeys = new ArrayList<>(); 27 | this.uniqueKeys = new HashMap<>(); 28 | } 29 | 30 | public void addColumn(@NotNull Column column) { 31 | this.columns.add(column); 32 | } 33 | 34 | public ForeignKey foreignKey(String key) { 35 | ForeignKey entry = new ForeignKey(key); 36 | foreignKeys.add(entry); 37 | return entry; 38 | } 39 | public void uniqueKey(String key, String... columns) { 40 | uniqueKeys.put(key, columns); 41 | } 42 | 43 | public void addColumns(@NotNull Column... columns) { 44 | for (Column column : columns) { 45 | addColumn(column); 46 | } 47 | } 48 | 49 | public void setPrimaryKey(@NotNull Column primaryKey) { 50 | this.primaryKey = primaryKey.getName(); 51 | } 52 | public void setPrimaryKey(@NotNull String primaryKey) { 53 | this.primaryKey = primaryKey; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | StringBuilder builder = new StringBuilder(); 59 | builder.append("CREATE TABLE IF NOT EXISTS `").append(name).append("` ("); 60 | for (Column column : columns) { 61 | builder.append(column.toString()).append(", "); 62 | } 63 | if (primaryKey != null) { 64 | builder.append("PRIMARY KEY (`").append(primaryKey).append("`)"); 65 | } else { 66 | builder.deleteCharAt(builder.length() - 1); 67 | builder.deleteCharAt(builder.length() - 1); //to remove the last ", " 68 | } 69 | if (!foreignKeys.isEmpty()) { 70 | for (ForeignKey entry : foreignKeys) { 71 | if (entry.referencedColumn != null) { 72 | builder.append(", FOREIGN KEY (`").append(entry.foreignKey).append("`)"); 73 | builder.append(" REFERENCES `").append(entry.referencedTable).append("`(`").append(entry.referencedColumn).append("`)"); 74 | if (entry.onDelete != null) { 75 | builder.append(" ON DELETE ").append(entry.onDelete.name().replace("_"," ")); 76 | } 77 | } 78 | } 79 | } 80 | if (!uniqueKeys.isEmpty()) { 81 | for (String key : uniqueKeys.keySet()) { 82 | String[] columns = uniqueKeys.get(key); 83 | builder.append(", UNIQUE KEY `").append(key).append("` ("); 84 | for (int i = 0; i < columns.length; i++) { 85 | builder.append("`").append(columns[i]).append("`"); 86 | if (i < columns.length - 1) { 87 | builder.append(", "); 88 | } 89 | } 90 | builder.append(")"); 91 | } 92 | } 93 | builder.append(")"); 94 | return builder.toString(); 95 | } 96 | 97 | 98 | } -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/TableCommands.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table; 2 | 3 | import me.cobeine.sqlava.connection.Callback; 4 | import me.cobeine.sqlava.connection.database.MySQLConnection; 5 | import me.cobeine.sqlava.connection.database.query.PreparedQuery; 6 | 7 | import java.sql.SQLException; 8 | 9 | /** 10 | * @Author Cobeine 11 | */ 12 | 13 | public final class TableCommands { 14 | private final MySQLConnection connection; 15 | public TableCommands(MySQLConnection connection) { 16 | this.connection = connection; 17 | } 18 | 19 | public void createTables(Callback callback, Table... tables) throws SQLException { 20 | Table first = tables[0]; 21 | PreparedQuery query = prepareStatement(first.toString()); 22 | for (Table table : tables) { 23 | if (table.equals(first)) continue; 24 | query.addBatch(table.toString()); 25 | } 26 | query.executeBatchAsync(callback); 27 | } 28 | 29 | public void createTables(Table... tables) throws SQLException { 30 | createTables(null, tables); 31 | } 32 | 33 | public void createTable(Table table, Callback callback) { 34 | PreparedQuery query = prepareStatement(table.toString()); 35 | query.executeUpdateAsync(callback); 36 | } 37 | 38 | public void createTable(Table table) { 39 | createTable(table, null); 40 | } 41 | 42 | public void dropTables(Callback callback, Table... tables) throws SQLException { 43 | Table first = tables[0]; 44 | PreparedQuery query = prepareStatement("DROP TABLE " + first.getName()); 45 | for (Table table : tables) { 46 | if (table.equals(first)) continue; 47 | query.addBatch("DROP TABLE " + table.getName()); 48 | } 49 | query.executeBatchAsync(callback); 50 | } 51 | 52 | public void dropTables(Table... tables) throws SQLException { 53 | dropTables(null, tables); 54 | } 55 | 56 | public void dropTable(Table table, Callback callback) { 57 | PreparedQuery query = prepareStatement("DROP TABLE " + table.getName()); 58 | query.executeUpdateAsync(callback); 59 | } 60 | 61 | public void dropTable(Table table) { 62 | dropTable(table, null); 63 | } 64 | 65 | 66 | public void emptyTables(Callback callback, Table... tables) throws SQLException { 67 | Table first = tables[0]; 68 | PreparedQuery query = prepareStatement("TRUNCATE TABLE " + first.getName()); 69 | for (Table table : tables) { 70 | if (table.equals(first)) continue; 71 | query.addBatch("DROP TABLE " + table.getName()); 72 | } 73 | query.executeBatchAsync(callback); 74 | } 75 | 76 | public void emptyTables(Table... tables) throws SQLException { 77 | emptyTables(null, tables); 78 | } 79 | 80 | public void emptyTable(Table table, Callback callback) { 81 | PreparedQuery query = prepareStatement("TRUNCATE TABLE " + table.getName()); 82 | query.executeUpdateAsync(callback); 83 | } 84 | 85 | public void emptyTable(Table table) { 86 | emptyTable(table, null); 87 | } 88 | 89 | public PreparedQuery prepareStatement(String query) { 90 | return new PreparedQuery(connection, query); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/column/Column.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table.column; 2 | 3 | import lombok.Getter; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | /** 11 | * @author Cobeine 12 | */ 13 | 14 | public class Column { 15 | private final @Getter 16 | @NotNull String name; 17 | private final @NotNull ColumnType columnType; 18 | private int size; 19 | private @NotNull List settings; 20 | private Object defaultValue = null; 21 | 22 | 23 | private Column(@NotNull String name, @NotNull ColumnType type) { 24 | this.name = name; 25 | this.columnType = type; 26 | this.size = 0; 27 | this.settings = new ArrayList<>(); 28 | } 29 | 30 | public static Column of(@NotNull String name, @NotNull ColumnType type) { 31 | return new Column(name, type); 32 | } 33 | 34 | public Column size(int size) { 35 | this.size = size; 36 | return this; 37 | } 38 | 39 | public Column defaultValue(Object defaultValue) { 40 | if (defaultValue instanceof String){ 41 | defaultValue = "'" + defaultValue + "'"; 42 | } 43 | this.defaultValue = defaultValue; 44 | return this; 45 | } 46 | 47 | public Column settings(ColumnSettings... settings) { 48 | this.settings = Arrays.asList(settings); 49 | return this; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | StringBuilder builder = new StringBuilder(); 55 | builder.append('`').append(getName()).append("` ").append(columnType.name()); 56 | if (size != 0) { 57 | builder.append("(").append(size).append(")"); 58 | } 59 | if (!settings.isEmpty()) { 60 | builder.append(" "); 61 | for (ColumnSettings setting : settings) { 62 | builder.append(setting.getValue()).append(" "); 63 | } 64 | builder.deleteCharAt(builder.length() - 1); 65 | } 66 | if (defaultValue != null && !settings.contains(ColumnSettings.AUTO_INCREMENT)) { 67 | builder.append(" DEFAULT ").append(defaultValue); 68 | } 69 | return builder.toString(); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/column/ColumnSettings.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table.column; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @author Cobeine 8 | */ 9 | @AllArgsConstructor 10 | public enum ColumnSettings { 11 | 12 | AUTO_INCREMENT("AUTO_INCREMENT"), 13 | NOT_NULL("NOT NULL"), 14 | UNIQUE("UNIQUE "), 15 | ZEROFILL("ZEROFILL"), 16 | UNSIGNED("UNSIGNED"); 17 | 18 | private final @Getter String value; 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/database/table/column/ColumnType.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.database.table.column; 2 | 3 | 4 | /** 5 | * @author Cobeine 6 | */ 7 | 8 | public enum ColumnType { 9 | 10 | //A FIXED length string (can contain letters, numbers, and special characters). The size parameter specifies the column length in characters - can be from 0 to 255. Default is 1 11 | CHAR, 12 | //A VARIABLE length string (can contain letters, numbers, and special characters). The size parameter specifies the maximum column length in characters - can be from 0 to 65535 13 | VARCHAR, 14 | // Equal to CHAR(), but stores binary byte strings. The size parameter specifies the column length in bytes. Default is 1 15 | BINARY, 16 | // Equal to VARCHAR(), but stores binary byte strings. The size parameter specifies the maximum column length in bytes. 17 | VARBINARY, 18 | // For BLOBs (Binary Large Objects). Max length: 255 bytes 19 | TINYBLOB, 20 | // Holds a string with a maximum length of 255 characters 21 | TINYTEXT, 22 | //Holds a string with a maximum length of 65,535 bytes 23 | TEXT, 24 | //For BLOBs (Binary Large Objects). Holds up to 65,535 bytes of data 25 | BLOB, 26 | //Holds a string with a maximum length of 16,777,215 characters 27 | MEDIUMTEXT, 28 | //For BLOBs (Binary Large Objects). Holds up to 16,777,215 bytes of data 29 | MEDIUMBLOB, 30 | //Holds a string with a maximum length of 4,294,967,295 characters 31 | LONGTEXT, 32 | //For BLOBs (Binary Large Objects). Holds up to 4,294,967,295 bytes of data 33 | LONGBLOB, 34 | BIT,//A bit-value type. The number of bits per value is specified in size. The size parameter can hold a value from 1 to 64. The default value for size is 1. 35 | TINYINT,//A very small integer. Signed range is from -128 to 127. Unsigned range is from 0 to 255. The size parameter specifies the maximum display width (which is 255) 36 | BOOLEAN,//Zero is considered as false, nonzero values are considered as true. 37 | SMALLINT,//A small integer. Signed range is from -32768 to 32767. Unsigned range is from 0 to 65535. The size parameter specifies the maximum display width (which is 255) 38 | MEDIUMINT,//A medium integer. Signed range is from -8388608 to 8388607. Unsigned range is from 0 to 16777215. The size parameter specifies the maximum display width (which is 255) 39 | INT,//A medium integer. Signed range is from -2147483648 to 2147483647. Unsigned range is from 0 to 4294967295. The size parameter specifies the maximum display width (which is 255) 40 | BIGINT,//A large integer. Signed range is from -9223372036854775808 to 9223372036854775807. Unsigned range is from 0 to 18446744073709551615. The size parameter specifies the maximum display width (which is 255) 41 | FLOAT,//A floating point number. MySQL uses the p value to determine whether to use FLOAT or DOUBLE for the resulting data type. If p is from 0 to 24, the data type becomes FLOAT(). If p is from 25 to 53, the data type becomes DOUBLE() 42 | DOUBLE,//A normal-size floating point number. The total number of digits is specified in size. The number of digits after the decimal point is specified in the d parameter 43 | DECIMAL,//An exact fixed-point number. The total number of digits is specified in size. The number of digits after the decimal point is specified in the d parameter. The maximum number for size is 65. The maximum number for d is 30. The default value for size is 10. The default value for d is 0. 44 | DATE,//A date. Format: YYYY-MM-DD. The supported range is from '1000-01-01' to '9999-12-31' 45 | DATETIME,//A date and time combination. Format: YYYY-MM-DD hh:mm:ss. The supported range is from '1000-01-01 00:00:00' to '9999-12-31 23:59:59'. Adding DEFAULT and ON UPDATE in the column definition to get automatic initialization and updating to the current date and time 46 | TIMESTAMP,//A timestamp. TIMESTAMP values are stored as the number of seconds since the Unix epoch ('1970-01-01 00:00:00' UTC). Format: YYYY-MM-DD hh:mm:ss. The supported range is from '1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' UTC. Automatic initialization and updating to the current date and time can be specified using DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP in the column definition 47 | TIME,//A time. Format: hh:mm:ss. The supported range is from '-838:59:59' to '838:59:59' 48 | YEAR//A year in four-digit format. Values allowed in four-digit format: 1901 to 2155, and 0000. 49 | 50 | 51 | } -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/pool/ConnectionPool.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.pool; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | 8 | /** 9 | * @Author Cobeine 10 | */ 11 | 12 | public abstract class ConnectionPool { 13 | 14 | private final S source; 15 | private final ExecutorService pool = Executors.newFixedThreadPool(5); 16 | public ConnectionPool(S source) { 17 | this.source = source; 18 | } 19 | 20 | public abstract R resource(); 21 | 22 | public S getSource() { 23 | return source; 24 | } 25 | 26 | public void submit(Runnable o) { 27 | pool.submit(o); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/pool/PooledConnection.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.pool; 2 | 3 | import me.cobeine.sqlava.connection.Connection; 4 | 5 | /** 6 | * @Author Cobeine 7 | */ 8 | 9 | public interface PooledConnection extends Connection { 10 | 11 | 12 | ConnectionPool getPool(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/presets/HikariDataSourcePresets.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.presets; 2 | 3 | /** 4 | * @Author Cobeine 5 | */ 6 | 7 | public interface HikariDataSourcePresets { 8 | 9 | String DEFAULT = ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/presets/MysqlJDBCDriverPresets.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.presets; 2 | 3 | /** 4 | * @Author Cobeine 5 | */ 6 | 7 | public interface MysqlJDBCDriverPresets { 8 | 9 | 10 | String OLD_JDBC = ("com.mysql.jdbc.Driver"); 11 | String NEW_JDBC = ("com.mysql.cj.jdbc.Driver"); 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/cobeine/sqlava/connection/util/JdbcUrlBuilder.java: -------------------------------------------------------------------------------- 1 | package me.cobeine.sqlava.connection.util; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @Author Cobeine 7 | */ 8 | 9 | public final class JdbcUrlBuilder { 10 | 11 | public static final String BASE_URL = "jdbc:mysql://%s:%s/%s"; 12 | private boolean auto_reconnect; 13 | private final HashMap map; 14 | 15 | JdbcUrlBuilder() { 16 | this.map = new HashMap<>(); 17 | } 18 | 19 | public JdbcUrlBuilder host(String host) { 20 | map.put("host", host); 21 | return this; 22 | } 23 | 24 | public JdbcUrlBuilder port(int port) { 25 | map.put("port", port); 26 | return this; 27 | } 28 | 29 | public JdbcUrlBuilder database(String database) { 30 | map.put("database", database); 31 | return this; 32 | } 33 | 34 | public JdbcUrlBuilder setAuto_reconnect(boolean auto_reconnect) { 35 | this.auto_reconnect = auto_reconnect; 36 | return this; 37 | } 38 | 39 | public String build() { 40 | return String.format(BASE_URL, map.get("host"), map.get("port"), map.get("database")) + (auto_reconnect ? "?autoReconnect=true" : ""); 41 | } 42 | 43 | public static JdbcUrlBuilder newBuilder() { 44 | return new JdbcUrlBuilder(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/ExampleTable.java: -------------------------------------------------------------------------------- 1 | import me.cobeine.sqlava.connection.database.table.Table; 2 | import me.cobeine.sqlava.connection.database.table.column.Column; 3 | import me.cobeine.sqlava.connection.database.table.column.ColumnSettings; 4 | import me.cobeine.sqlava.connection.database.table.column.ColumnType; 5 | 6 | /** 7 | * @Author Cobeine 8 | */ 9 | 10 | public class ExampleTable extends Table { 11 | 12 | public ExampleTable() { 13 | super("example"); 14 | addColumns( 15 | Column.of("id", ColumnType.INT).settings(ColumnSettings.AUTO_INCREMENT,ColumnSettings.UNIQUE), 16 | Column.of("uuid", ColumnType.TEXT).settings(ColumnSettings.NOT_NULL,ColumnSettings.UNIQUE).defaultValue("none") 17 | ); 18 | setPrimaryKey("id"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/Examples.java: -------------------------------------------------------------------------------- 1 | import me.cobeine.sqlava.connection.auth.BasicMySQLCredentials; 2 | import me.cobeine.sqlava.connection.auth.CredentialsHolder; 3 | import me.cobeine.sqlava.connection.database.MySQLConnection; 4 | import me.cobeine.sqlava.connection.database.query.PreparedQuery; 5 | import me.cobeine.sqlava.connection.database.query.Query; 6 | import me.cobeine.sqlava.connection.util.JdbcUrlBuilder; 7 | 8 | 9 | /** 10 | * The type Examples. 11 | * 12 | * @Author Cobeine 13 | */ 14 | public class Examples { 15 | private MySQLConnection connection; 16 | public Examples()throws Exception { 17 | var url = JdbcUrlBuilder.newBuilder() 18 | .host("host") 19 | .port(3306) 20 | .setAuto_reconnect(true) 21 | .database("database") 22 | .build(); 23 | CredentialsHolder mysql_creds = CredentialsHolder.builder() 24 | .add(BasicMySQLCredentials.USERNAME,"username") 25 | .add(BasicMySQLCredentials.PASSWORD,"password") 26 | .add(BasicMySQLCredentials.DATABASE,"database") 27 | .add(BasicMySQLCredentials.PORT,3306) 28 | .add(BasicMySQLCredentials.POOL_SIZE,8) 29 | .add(BasicMySQLCredentials.JDBC_URL, url) 30 | .build(); 31 | 32 | connection = new MySQLConnection(mysql_creds); 33 | connection.connect(result -> { 34 | if (result.getException().isEmpty()) { 35 | result.getException().get().printStackTrace(); 36 | return; 37 | } 38 | //successfully connected 39 | connection.getTableCommands().createTable(new ExampleTable()); 40 | connection.getTableCommands().createTable(new ExampleTable(),tableResult -> { 41 | if (tableResult.getException().isPresent()) { 42 | tableResult.getException().get().printStackTrace(); 43 | return; 44 | } 45 | //successfully created table 46 | }); 47 | }); 48 | 49 | PreparedQuery query = connection.prepareStatement("SELECT * FROM example WHERE uuid=test"); 50 | query = connection.prepareStatement(Query.select("example").where("uuid", "test")); 51 | 52 | query.executeQuery(); 53 | query.executeQueryAsync(result -> { 54 | if (result.getException().isPresent()) { 55 | result.getException().get().printStackTrace(); 56 | return; 57 | } 58 | //successfully executed query 59 | result.getResult().ifPresent(resultSet -> { 60 | //... 61 | }); 62 | }); 63 | 64 | Query update = Query.update("example").set("uuid","test").where("id",1).and("uuid","test2"); 65 | 66 | update = Query.update("example").set("uuid").where("id").where("uuid"); 67 | connection.prepareStatement(update) 68 | .setParameter(1,"test") 69 | .setParameter(2,1) 70 | .setParameter(3,"test2").executeUpdateAsync(result -> { 71 | 72 | if (result.getException().isPresent()) { 73 | result.getException().get().printStackTrace(); 74 | return; 75 | } 76 | //successfully executed query 77 | }); 78 | } 79 | 80 | 81 | } 82 | --------------------------------------------------------------------------------