├── .all-contributorsrc ├── .github ├── CODEOWNERS ├── dependabot.yml ├── project.yml └── workflows │ ├── build.yml │ ├── pre-release.yml │ ├── quarkus-snapshot.yaml │ ├── release-perform.yml │ └── release-prepare.yml ├── .gitignore ├── LICENSE ├── README.md ├── deployment ├── pom.xml └── src │ ├── main │ └── java │ │ └── io │ │ └── quarkiverse │ │ └── jooq │ │ └── deployment │ │ ├── JooqInitializedBuildItem.java │ │ └── JooqProcessor.java │ └── test │ ├── java │ └── io │ │ └── quarkiverse │ │ └── jooq │ │ ├── Demo.java │ │ ├── InjectTest.java │ │ ├── JooqTest.java │ │ ├── Keys.java │ │ ├── MyCustomConfiguration1.java │ │ ├── MyCustomConfigurationFactory.java │ │ ├── Public.java │ │ ├── QDemo.java │ │ └── RDemo.java │ └── resources │ └── application.properties ├── docs ├── antora.yml ├── modules │ └── ROOT │ │ ├── assets │ │ └── images │ │ │ └── .keepme │ │ ├── examples │ │ └── .keepme │ │ ├── nav.adoc │ │ └── pages │ │ ├── includes │ │ ├── attributes.adoc │ │ ├── quarkus-jooq.adoc │ │ └── quarkus-jooq_quarkus.jooq.adoc │ │ └── index.adoc ├── pom.xml └── templates │ └── includes │ └── attributes.adoc ├── integration-tests ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── quarkiverse │ │ │ └── jooq │ │ │ └── it │ │ │ ├── Demo.java │ │ │ ├── JooqResource.java │ │ │ ├── Keys.java │ │ │ ├── MyCustomConfiguration1.java │ │ │ ├── MyCustomConfigurationFactory.java │ │ │ ├── Public.java │ │ │ ├── QDemo.java │ │ │ └── RDemo.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── io │ └── quarkiverse │ └── jooq │ └── it │ ├── JooqResourceIT.java │ └── JooqResourceTest.java ├── pom.xml ├── quarkus-jooq-pro ├── deployment │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── quarkiverse │ │ └── jooq │ │ └── pro │ │ └── deployment │ │ └── JooqProProcessor.java ├── pom.xml └── runtime │ ├── pom.xml │ └── src │ └── main │ └── java │ └── io │ └── quarkiverse │ └── jooq │ └── pro │ └── runtime │ ├── AbstractDslContextProducer.java │ └── DslContextFactory.java └── runtime ├── pom.xml └── src └── main └── java └── io └── quarkiverse └── jooq ├── runtime ├── AbstractDslContextProducer.java ├── ConnectionProvider.java ├── DslContextFactory.java ├── JooqConfig.java ├── JooqCustomContext.java ├── JooqItemConfig.java ├── JooqRecorder.java └── SQLDataTypeExt.java └── sql └── SqlLoggerListener.java /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "angrymango", 10 | "name": "Tim King", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/343859?v=4", 12 | "profile": "http://hakt.com.au", 13 | "contributions": [ 14 | "code", 15 | "maintenance" 16 | ] 17 | }, 18 | { 19 | "login": "Sirz3chs", 20 | "name": "Bois Pierre-Antoine", 21 | "avatar_url": "https://avatars.githubusercontent.com/u/23245718?v=4", 22 | "profile": "https://github.com/Sirz3chs", 23 | "contributions": [ 24 | "code", 25 | "maintenance" 26 | ] 27 | }, 28 | { 29 | "login": "ranjanashish", 30 | "name": "Ashish Ranjan", 31 | "avatar_url": "https://avatars.githubusercontent.com/u/113700?v=4", 32 | "profile": "https://github.com/ranjanashish", 33 | "contributions": [ 34 | "code", 35 | "maintenance" 36 | ] 37 | } 38 | ], 39 | "contributorsPerLine": 7, 40 | "projectName": "quarkus-jooq", 41 | "projectOwner": "quarkiverse", 42 | "repoType": "github", 43 | "repoHost": "https://github.com", 44 | "skipCi": true, 45 | "commitConvention": "angular" 46 | } 47 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 5 | 6 | # The '*' pattern is global owners. 7 | 8 | # Order is important. The last matching pattern has the most precedence. 9 | # The folders are ordered as follows: 10 | 11 | # In each subsection folders are ordered first by depth, then alphabetically. 12 | # This should make it easy to add new rules without breaking existing ones. 13 | 14 | * @quarkiverse/quarkiverse-jooq 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | ignore: 13 | - dependency-name: "org.apache.maven.plugins:maven-compiler-plugin" 14 | -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Extension 2 | release: 3 | current-version: "2.1.0" 4 | next-version: "999-SNAPSHOT" 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | paths-ignore: 8 | - '.gitignore' 9 | - 'CODEOWNERS' 10 | - 'LICENSE' 11 | - '*.md' 12 | - '*.adoc' 13 | - '*.txt' 14 | - '.all-contributorsrc' 15 | pull_request: 16 | paths-ignore: 17 | - '.gitignore' 18 | - 'CODEOWNERS' 19 | - 'LICENSE' 20 | - '*.md' 21 | - '*.adoc' 22 | - '*.txt' 23 | - '.all-contributorsrc' 24 | 25 | concurrency: 26 | group: ${{ github.workflow }}-${{ github.ref }} 27 | cancel-in-progress: true 28 | 29 | defaults: 30 | run: 31 | shell: bash 32 | 33 | jobs: 34 | build: 35 | name: Build on ${{ matrix.os }} 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | # os: [windows-latest, macos-latest, ubuntu-latest] 40 | os: [ubuntu-latest] 41 | runs-on: ${{ matrix.os }} 42 | steps: 43 | - name: Prepare git 44 | run: git config --global core.autocrlf false 45 | if: startsWith(matrix.os, 'windows') 46 | 47 | - uses: actions/checkout@v3 48 | - name: Set up JDK 17 49 | uses: actions/setup-java@v3 50 | with: 51 | distribution: temurin 52 | java-version: 17 53 | cache: 'maven' 54 | 55 | - name: Build with Maven 56 | run: mvn -B clean install -Dno-format 57 | 58 | - name: Build with Maven (Native) 59 | run: mvn -B install -Dnative -Dquarkus.native.container-build -Dnative.surefire.skip -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Pre Release 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/project.yml' 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | pre-release: 14 | name: Pre-Release 15 | uses: quarkiverse/.github/.github/workflows/pre-release.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/quarkus-snapshot.yaml: -------------------------------------------------------------------------------- 1 | name: "Quarkus ecosystem CI" 2 | on: 3 | workflow_dispatch: 4 | watch: 5 | types: [started] 6 | 7 | # For this CI to work, ECOSYSTEM_CI_TOKEN needs to contain a GitHub with rights to close the Quarkus issue that the user/bot has opened, 8 | # while 'ECOSYSTEM_CI_REPO_PATH' needs to be set to the corresponding path in the 'quarkusio/quarkus-ecosystem-ci' repository 9 | 10 | env: 11 | ECOSYSTEM_CI_REPO: quarkusio/quarkus-ecosystem-ci 12 | ECOSYSTEM_CI_REPO_FILE: context.yaml 13 | JAVA_VERSION: 17 14 | 15 | ######################### 16 | # Repo specific setting # 17 | ######################### 18 | 19 | ECOSYSTEM_CI_REPO_PATH: quarkiverse-jooq 20 | 21 | jobs: 22 | build: 23 | name: "Build against latest Quarkus snapshot" 24 | runs-on: ubuntu-latest 25 | # Allow to manually launch the ecosystem CI in addition to the bots 26 | if: github.actor == 'quarkusbot' || github.actor == 'quarkiversebot' || github.actor == '' 27 | 28 | steps: 29 | - name: Install yq 30 | uses: dcarbone/install-yq-action@v1.0.1 31 | 32 | - name: Set up Java 33 | uses: actions/setup-java@v3 34 | with: 35 | distribution: temurin 36 | java-version: ${{ env.JAVA_VERSION }} 37 | 38 | - name: Checkout repo 39 | uses: actions/checkout@v3 40 | with: 41 | path: current-repo 42 | 43 | - name: Checkout Ecosystem 44 | uses: actions/checkout@v3 45 | with: 46 | repository: ${{ env.ECOSYSTEM_CI_REPO }} 47 | path: ecosystem-ci 48 | 49 | - name: Setup and Run Tests 50 | run: ./ecosystem-ci/setup-and-test 51 | env: 52 | ECOSYSTEM_CI_TOKEN: ${{ secrets.ECOSYSTEM_CI_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/release-perform.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Perform Release 2 | run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: 'Tag to release' 11 | required: true 12 | 13 | permissions: 14 | attestations: write 15 | id-token: write 16 | contents: read 17 | 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | perform-release: 24 | name: Perform Release 25 | uses: quarkiverse/.github/.github/workflows/perform-release.yml@main 26 | secrets: inherit 27 | with: 28 | version: ${{github.event.inputs.tag || github.ref_name}} 29 | -------------------------------------------------------------------------------- /.github/workflows/release-prepare.yml: -------------------------------------------------------------------------------- 1 | name: Quarkiverse Prepare Release 2 | 3 | on: 4 | pull_request: 5 | types: [ closed ] 6 | paths: 7 | - '.github/project.yml' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | prepare-release: 15 | name: Prepare Release 16 | if: ${{ github.event.pull_request.merged == true}} 17 | uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main 18 | secrets: inherit 19 | with: 20 | skip_tests: true 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Eclipse 26 | .project 27 | .classpath 28 | .settings/ 29 | bin/ 30 | 31 | # IntelliJ 32 | .idea 33 | *.ipr 34 | *.iml 35 | *.iws 36 | 37 | # NetBeans 38 | nb-configuration.xml 39 | 40 | # Visual Studio Code 41 | .vscode 42 | .factorypath 43 | 44 | # OSX 45 | .DS_Store 46 | 47 | # Vim 48 | *.swp 49 | *.swo 50 | 51 | # patch 52 | *.orig 53 | *.rej 54 | 55 | # Gradle 56 | .gradle/ 57 | build/ 58 | 59 | # Maven 60 | target/ 61 | pom.xml.tag 62 | pom.xml.releaseBackup 63 | pom.xml.versionsBackup 64 | release.properties 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jOOQ Extension for Quarkus 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-) 4 | 5 | 6 | [![Build](https://github.com/quarkiverse/quarkus-jooq/workflows/Build/badge.svg)](https://github.com/quarkiverse/quarkus-jooq/actions?query=workflow%3ABuild) 7 | [![Maven Central](https://img.shields.io/maven-central/v/io.quarkiverse.jooq/quarkus-jooq.svg?label=Maven%20Central)](https://search.maven.org/artifact/io.quarkiverse.jooq/quarkus-jooq) 8 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 9 | 10 | jOOQ generates Java code from your database and lets you build type safe SQL queries through its fluent API. 11 | 12 | This extension allows you to develop applications that interact with the [supported databases](https://www.jooq.org/download/support-matrix) using [jOOQ](https://github.com/jOOQ/jOOQ). 13 | 14 | - [Contributors](#contributors) 15 | - [Configuration](#configuration) 16 | - [Usage](#usage) 17 | - [Native Mode Support](#native-mode-support) 18 | - [jOOQ Commercial Distributions](#jooq-commercial-distributions) 19 | 20 | ## Contributors ✨ 21 | 22 | The is extension is based on the prior work by [@leotu](https://github.com/leotu) - [quarkus-ext-jooq](https://github.com/leotu/quarkus-ext-jooq) 23 | 24 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
Tim King
Tim King

💻 🚧
Bois Pierre-Antoine
Bois Pierre-Antoine

💻 🚧
Ashish Ranjan
Ashish Ranjan

💻 🚧
38 | 39 | 40 | 41 | 42 | 43 | 44 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 45 | 46 | ## Configuration 47 | 48 | After configuring `quarkus BOM`: 49 | 50 | ```xml 51 | 52 | 53 | 54 | io.quarkus 55 | quarkus-bom 56 | ${insert.newest.quarkus.version.here} 57 | pom 58 | import 59 | 60 | 61 | 62 | ``` 63 | 64 | You can just configure the `quarkus-jooq` extension by adding the following dependency: 65 | 66 | ```xml 67 | 68 | io.quarkiverse.jooq 69 | quarkus-jooq 70 | ${latest.release.version} 71 | 72 | ``` 73 | 76 | 77 | ## Usage 78 | 79 | The default DSL context can then be injected with: 80 | 81 | ```yaml 82 | # default datasource 83 | quarkus.datasource.db-kind=h2 84 | quarkus.datasource.username=username-default 85 | quarkus.datasource.password=username-default 86 | quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:default;DATABASE_TO_UPPER=FALSE; 87 | quarkus.datasource.jdbc.min-size=1 88 | quarkus.datasource.jdbc.max-size=2 89 | 90 | # default jOOQ datasource 91 | quarkus.jooq.dialect=H2 92 | ``` 93 | 94 | The default ```org.jooq.DSLContext``` can then be injected: 95 | 96 | ```java 97 | @Inject 98 | DSLContext dsl; // default 99 | ``` 100 | 101 | ### Custom Configuration 102 | 103 | Update the configuration with a reference to a named dependency to inject: 104 | 105 | ```yaml 106 | # Using custom jOOQ configuration injection 107 | quarkus.jooq.configuration-inject=myCustomConfiguration 108 | ``` 109 | 110 | Then provide the custom configuration in the apply method. 111 | 112 | ```java 113 | @ApplicationScoped 114 | public class MyCustomConfigurationFactory { 115 | private static final Logger LOGGER = Logger.getLogger(MyCustomConfigurationFactory.class); 116 | 117 | @ApplicationScoped 118 | @Produces 119 | @Named("myCustomConfiguration") 120 | public JooqCustomContext create() { 121 | LOGGER.debug("MyCustomConfigurationFactory: create"); 122 | return new JooqCustomContext() { 123 | @Override 124 | public void apply(Configuration configuration) { 125 | // Custom configuration here... 126 | } 127 | }; 128 | } 129 | } 130 | ``` 131 | 132 | Alternatively, using a qualified class that implements ```io.quarkiverse.jooq.runtime.JooqCustomContext```: 133 | 134 | ```yaml 135 | # Using custom jOOQ configuration 136 | quarkus.jooq.configuration=io.quarkiverse.jooq.MyCustomConfiguration 137 | ``` 138 | 139 | Then provide the custom configuration in the apply method. 140 | 141 | ```java 142 | public class MyCustomConfiguration implements JooqCustomContext { 143 | @Override 144 | public void apply(Configuration configuration) { 145 | // Custom configuration here... 146 | } 147 | } 148 | ``` 149 | 150 | ### Multiple Datasources 151 | 152 | Multiple data sources can be configured using named data sources as follows: 153 | 154 | ```yaml 155 | # named data source 156 | quarkus.datasource.datasource1.db-kind=h2 157 | quarkus.datasource.datasource1.username=username1 158 | quarkus.datasource.datasource1.password=username1 159 | quarkus.datasource.datasource1.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:datasource1;DATABASE_TO_UPPER=FALSE; 160 | quarkus.datasource.datasource1.jdbc.min-size=1 161 | quarkus.datasource.datasource1.jdbc.max-size=2 162 | 163 | # jOOQ configuration referencing the named data source 164 | quarkus.jooq.dsl1.dialect=H2 165 | quarkus.jooq.dsl1.datasource=datasource1 166 | quarkus.jooq.dsl1.configuration=io.quarkiverse.jooq.MyCustomConfiguration1 167 | ``` 168 | 169 | ## Native Mode Support 170 | 171 | Native compilation is supported in the standard Quarkus way using: 172 | 173 | ```shell 174 | ./mvnw package -Pnative 175 | ``` 176 | 177 | ## jOOQ Commercial Distributions 178 | 179 | Only the Open Source version of jOOQ is supported as an automated build target at this time because of the lack of access to the pro jars at build time. 180 | 181 | In order to build use the jOOQ commercial features the extension must be built by the license holder. This can be done by: 182 | 183 | * Adding the commercial jOOQ jars to a private maven repository 184 | * Configuring settings.xml with the access details, for example: 185 | ```xml 186 | 187 | 188 | 189 | jooq-pro 190 | 191 | 192 | [REPO_ID] 193 | [REPO_NAME] 194 | [REPO_URL] 195 | 196 | 197 | 198 | 199 | 200 | 201 | [REPO_ID] 202 | [USERNAME] 203 | [PASSWORD] 204 | 205 | 206 | 207 | ``` 208 | * Building the extension: 209 | ```shell 210 | cd [EXTENSION_HOME]/quarkus-jooq-pro 211 | mvn clean install -Pjooq-pro 212 | ``` 213 | * Optionally release the artifacts to the private maven repository for use elsewhere and import into your project: 214 | ```xml 215 | 216 | io.quarkiverse.jooq.pro 217 | quarkus-jooq 218 | ${quarkus-jooq-pro.version} 219 | 220 | ``` -------------------------------------------------------------------------------- /deployment/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.jooq 6 | quarkus-jooq-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-jooq-deployment 12 | Quarkus jOOQ - Deployment 13 | 14 | 15 | 16 | io.quarkus 17 | quarkus-agroal-deployment 18 | 19 | 20 | io.quarkus 21 | quarkus-arc-deployment 22 | 23 | 24 | io.quarkus 25 | quarkus-narayana-jta-deployment 26 | 27 | 28 | 29 | io.quarkiverse.jooq 30 | quarkus-jooq 31 | ${project.version} 32 | 33 | 34 | 35 | 36 | io.quarkus 37 | quarkus-junit5 38 | test 39 | 40 | 41 | io.quarkus 42 | quarkus-jdbc-h2 43 | test 44 | 45 | 46 | io.quarkus 47 | quarkus-test-h2 48 | test 49 | 50 | 51 | io.quarkus 52 | quarkus-jdbc-postgresql 53 | test 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.apache.maven.plugins 61 | maven-compiler-plugin 62 | 63 | 64 | 65 | io.quarkus 66 | quarkus-extension-processor 67 | ${quarkus.version} 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/jooq/deployment/JooqInitializedBuildItem.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.deployment; 2 | 3 | import io.quarkus.builder.item.SimpleBuildItem; 4 | 5 | /** 6 | * Marker build item indicating the QuerySQL has been fully initialized. 7 | */ 8 | public final class JooqInitializedBuildItem extends SimpleBuildItem { 9 | 10 | public JooqInitializedBuildItem() { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /deployment/src/main/java/io/quarkiverse/jooq/deployment/JooqProcessor.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.deployment; 2 | 3 | import java.util.List; 4 | import java.util.Map.Entry; 5 | import java.util.Optional; 6 | import java.util.function.BooleanSupplier; 7 | import java.util.regex.Pattern; 8 | 9 | import jakarta.enterprise.context.ApplicationScoped; 10 | import jakarta.enterprise.inject.Default; 11 | import jakarta.enterprise.inject.Produces; 12 | import jakarta.inject.Inject; 13 | import jakarta.inject.Singleton; 14 | 15 | import org.jboss.jandex.AnnotationInstance; 16 | import org.jboss.jandex.AnnotationValue; 17 | import org.jboss.jandex.DotName; 18 | import org.jboss.logging.Logger; 19 | import org.jooq.*; 20 | import org.jooq.tools.LoggerListener; 21 | import org.objectweb.asm.Opcodes; 22 | 23 | import io.agroal.api.AgroalDataSource; 24 | import io.quarkiverse.jooq.runtime.*; 25 | import io.quarkus.agroal.spi.JdbcDataSourceBuildItem; 26 | import io.quarkus.arc.deployment.GeneratedBeanBuildItem; 27 | import io.quarkus.arc.deployment.UnremovableBeanBuildItem; 28 | import io.quarkus.arc.deployment.UnremovableBeanBuildItem.BeanClassNameExclusion; 29 | import io.quarkus.arc.processor.DotNames; 30 | import io.quarkus.datasource.common.runtime.DataSourceUtil; 31 | import io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig; 32 | import io.quarkus.deployment.annotations.BuildProducer; 33 | import io.quarkus.deployment.annotations.BuildStep; 34 | import io.quarkus.deployment.annotations.ExecutionTime; 35 | import io.quarkus.deployment.annotations.Record; 36 | import io.quarkus.deployment.builditem.CombinedIndexBuildItem; 37 | import io.quarkus.deployment.builditem.FeatureBuildItem; 38 | import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; 39 | import io.quarkus.deployment.pkg.steps.NativeBuild; 40 | import io.quarkus.deployment.recording.RecorderContext; 41 | import io.quarkus.gizmo.*; 42 | import io.quarkus.runtime.util.HashUtil; 43 | 44 | public class JooqProcessor { 45 | 46 | private static final String FEATURE = "jooq"; 47 | 48 | private static final Logger log = Logger.getLogger(JooqProcessor.class); 49 | 50 | private static final DotName DSL_CONTEXT_QUALIFIER = DotName 51 | .createSimple(AbstractDslContextProducer.DslContextQualifier.class.getName()); 52 | 53 | private final String dslContextProducerClassName = AbstractDslContextProducer.class.getPackage().getName() + "." 54 | + "DslContextProducer"; 55 | 56 | /** 57 | * Register a extension capability and feature 58 | * 59 | * @return jOOQ feature build item 60 | */ 61 | @Record(ExecutionTime.STATIC_INIT) 62 | FeatureBuildItem featureBuildItem() { 63 | return new FeatureBuildItem(FEATURE); 64 | } 65 | 66 | @BuildStep(onlyIf = { NativeBuild.class, RegisterClassesForReflectionEnabled.class }) 67 | public void registerReflections(CombinedIndexBuildItem indexBuildItem, 68 | BuildProducer reflectiveClass, 69 | JooqConfig jooqConfig) { 70 | Pattern jooqDBReflectClasses = Pattern.compile(jooqConfig.generatedClassesPattern()); 71 | indexBuildItem.getIndex() 72 | .getKnownClasses() 73 | .stream() 74 | .filter(o -> jooqDBReflectClasses.matcher(o.name().toString()).matches()) 75 | .forEach(clazz -> reflectiveClass.produce(new ReflectiveClassBuildItem(true, true, clazz.name().toString()))); 76 | } 77 | 78 | @SuppressWarnings("unchecked") 79 | @Record(ExecutionTime.STATIC_INIT) 80 | @BuildStep 81 | protected void build(RecorderContext recorder, JooqRecorder template, 82 | BuildProducer reflectiveClass, 83 | BuildProducer unremovableBeans, 84 | JooqConfig jooqConfig, 85 | BuildProducer generatedBean, 86 | DataSourcesBuildTimeConfig dataSourceConfig, 87 | List jdbcDataSourcesBuildItem) { 88 | if (isUnconfigured(jooqConfig)) { 89 | return; 90 | } 91 | 92 | reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, AbstractDslContextProducer.class)); 93 | reflectiveClass.produce(new ReflectiveClassBuildItem(false, true, LoggerListener.class)); 94 | 95 | if (!isPresentDialect(jooqConfig.defaultConfig())) { 96 | log.warn("No default sql-dialect been defined"); 97 | } 98 | 99 | createDslContextProducerBean(generatedBean, unremovableBeans, jooqConfig, dataSourceConfig, jdbcDataSourcesBuildItem, 100 | AbstractDslContextProducer.class); 101 | } 102 | 103 | @Record(ExecutionTime.RUNTIME_INIT) 104 | @BuildStep 105 | void configureDataSource(JooqRecorder template, 106 | BuildProducer jooqInitialized, JooqConfig jooqConfig) { 107 | if (isUnconfigured(jooqConfig)) { 108 | return; 109 | } 110 | jooqInitialized.produce(new JooqInitializedBuildItem()); 111 | } 112 | 113 | protected boolean isUnconfigured(JooqConfig jooqConfig) { 114 | if (!isPresentDialect(jooqConfig.defaultConfig()) && jooqConfig.namedConfig().isEmpty()) { 115 | // No jOOQ has been configured so bail out 116 | log.debug("No jOOQ has been configured"); 117 | return true; 118 | } else { 119 | return false; 120 | } 121 | } 122 | 123 | protected void createDslContextProducerBean(BuildProducer generatedBean, 124 | BuildProducer unremovableBeans, 125 | JooqConfig jooqConfig, 126 | DataSourcesBuildTimeConfig dataSourceConfig, 127 | List jdbcDataSourcesBuildItem, Class producerClass) { 128 | ClassOutput classOutput = (name, data) -> generatedBean.produce(new GeneratedBeanBuildItem(name, data)); 129 | unremovableBeans.produce(new UnremovableBeanBuildItem(new BeanClassNameExclusion(dslContextProducerClassName))); 130 | 131 | ClassCreator classCreator = ClassCreator.builder().classOutput(classOutput).className(dslContextProducerClassName) 132 | .superClass(producerClass).build(); 133 | classCreator.addAnnotation(ApplicationScoped.class); 134 | 135 | JooqItemConfig defaultConfig = jooqConfig.defaultConfig(); 136 | if (isPresentDialect(defaultConfig)) { 137 | Optional defaultJdbcDataSourceBuildItem = jdbcDataSourcesBuildItem.stream() 138 | .filter(JdbcDataSourceBuildItem::isDefault) 139 | .findFirst(); 140 | 141 | if (!defaultJdbcDataSourceBuildItem.isPresent()) { //dataSourceConfig.defaultDataSource.dbKind 142 | log.warn("Default dataSource not found"); 143 | System.err.println(">>> Default dataSource not found"); 144 | } 145 | if (defaultConfig.datasource().isPresent() 146 | && !DataSourceUtil.DEFAULT_DATASOURCE_NAME.equals(defaultConfig.datasource().get())) { 147 | log.warn("Skip default dataSource name: " + defaultConfig.datasource().get()); 148 | } 149 | String dsVarName = "defaultDataSource"; 150 | 151 | FieldCreator defaultDataSourceCreator = classCreator.getFieldCreator(dsVarName, AgroalDataSource.class) 152 | .setModifiers(Opcodes.ACC_MODULE); 153 | 154 | defaultDataSourceCreator.addAnnotation(Default.class); 155 | defaultDataSourceCreator.addAnnotation(Inject.class); 156 | 157 | // 158 | String dialect = defaultConfig.dialect(); 159 | MethodCreator defaultDslContextMethodCreator = classCreator.getMethodCreator("createDefaultDslContext", 160 | DSLContext.class); 161 | 162 | defaultDslContextMethodCreator.addAnnotation(Singleton.class); 163 | defaultDslContextMethodCreator.addAnnotation(Produces.class); 164 | defaultDslContextMethodCreator.addAnnotation(Default.class); 165 | 166 | ResultHandle dialectRH = defaultDslContextMethodCreator.load(dialect); 167 | 168 | ResultHandle dataSourceRH = defaultDslContextMethodCreator.readInstanceField( 169 | FieldDescriptor.of(classCreator.getClassName(), dsVarName, AgroalDataSource.class.getName()), 170 | defaultDslContextMethodCreator.getThis()); 171 | 172 | if (defaultConfig.configurationInject().isPresent()) { 173 | String configurationInjectName = defaultConfig.configurationInject().get(); 174 | String injectVarName = "configuration_" + HashUtil.sha1(configurationInjectName); 175 | 176 | FieldCreator configurationCreator = classCreator.getFieldCreator(injectVarName, JooqCustomContext.class) 177 | .setModifiers(Opcodes.ACC_MODULE); 178 | 179 | configurationCreator.addAnnotation(Inject.class); 180 | configurationCreator.addAnnotation(AnnotationInstance.create(DotNames.NAMED, null, 181 | new AnnotationValue[] { AnnotationValue.createStringValue("value", configurationInjectName) })); 182 | 183 | ResultHandle configurationRH = defaultDslContextMethodCreator.readInstanceField( 184 | FieldDescriptor.of(classCreator.getClassName(), injectVarName, JooqCustomContext.class.getName()), 185 | defaultDslContextMethodCreator.getThis()); 186 | 187 | defaultDslContextMethodCreator.returnValue( // 188 | defaultDslContextMethodCreator.invokeVirtualMethod( 189 | MethodDescriptor.ofMethod(producerClass, "createDslContext", 190 | DSLContext.class, String.class, AgroalDataSource.class, 191 | JooqCustomContext.class), 192 | defaultDslContextMethodCreator.getThis(), dialectRH, dataSourceRH, configurationRH)); 193 | } else { 194 | ResultHandle configurationRH = defaultConfig.configuration().isPresent() 195 | ? defaultDslContextMethodCreator.load(defaultConfig.configuration().get()) 196 | : defaultDslContextMethodCreator.loadNull(); 197 | 198 | defaultConfig.configuration() 199 | .ifPresent(s -> unremovableBeans.produce(new UnremovableBeanBuildItem(new BeanClassNameExclusion(s)))); 200 | 201 | defaultDslContextMethodCreator.returnValue(defaultDslContextMethodCreator.invokeVirtualMethod( 202 | MethodDescriptor.ofMethod(producerClass, "createDslContext", DSLContext.class, 203 | String.class, AgroalDataSource.class, String.class), 204 | defaultDslContextMethodCreator.getThis(), dialectRH, dataSourceRH, configurationRH)); 205 | } 206 | } 207 | 208 | for (Entry configEntry : jooqConfig.namedConfig().entrySet()) { 209 | String named = configEntry.getKey(); 210 | JooqItemConfig namedConfig = configEntry.getValue(); 211 | if (!isPresentDialect(namedConfig)) { 212 | log.warnv("!isPresentDialect(namedConfig), named: {0}, namedConfig: {1}", named, namedConfig); 213 | continue; 214 | } 215 | if (!namedConfig.datasource().isPresent()) { 216 | log.warnv("(!config.datasource.isPresent()), named: {0}, namedConfig: {1}", named, namedConfig); 217 | continue; 218 | } 219 | 220 | String dataSourceName = namedConfig.datasource().get(); 221 | Optional namedJdbcDataSourceBuildItem = jdbcDataSourcesBuildItem.stream() 222 | .filter(j -> j.getName().equals(dataSourceName)) 223 | .findFirst(); 224 | 225 | if (!namedJdbcDataSourceBuildItem.isPresent()) { 226 | log.warnv("Named: '{0}' dataSource not found", dataSourceName); 227 | System.err.println(">>> Named: '" + dataSourceName + "' dataSource not found"); 228 | } 229 | 230 | String suffix = HashUtil.sha1(named); 231 | String dsVarName = "dataSource_" + suffix; 232 | 233 | FieldCreator dataSourceCreator = classCreator.getFieldCreator(dsVarName, AgroalDataSource.class) 234 | .setModifiers(Opcodes.ACC_MODULE); 235 | dataSourceCreator.addAnnotation(Inject.class); 236 | dataSourceCreator.addAnnotation(AnnotationInstance.create(DotNames.NAMED, null, 237 | new AnnotationValue[] { AnnotationValue.createStringValue("value", dataSourceName) })); 238 | 239 | MethodCreator namedDslContextMethodCreator = classCreator.getMethodCreator("createNamedDslContext_" + suffix, 240 | DSLContext.class.getName()); 241 | 242 | namedDslContextMethodCreator.addAnnotation(ApplicationScoped.class); 243 | namedDslContextMethodCreator.addAnnotation(Produces.class); 244 | namedDslContextMethodCreator.addAnnotation(AnnotationInstance.create(DotNames.NAMED, null, 245 | new AnnotationValue[] { AnnotationValue.createStringValue("value", named) })); 246 | namedDslContextMethodCreator.addAnnotation(AnnotationInstance.create(DSL_CONTEXT_QUALIFIER, null, 247 | new AnnotationValue[] { AnnotationValue.createStringValue("value", named) })); 248 | 249 | ResultHandle dialectRH = namedDslContextMethodCreator.load(namedConfig.dialect()); 250 | 251 | ResultHandle dataSourceRH = namedDslContextMethodCreator.readInstanceField( 252 | FieldDescriptor.of(classCreator.getClassName(), dsVarName, AgroalDataSource.class.getName()), 253 | namedDslContextMethodCreator.getThis()); 254 | 255 | if (namedConfig.configurationInject().isPresent()) { 256 | String configurationInjectName = namedConfig.configurationInject().get(); 257 | String injectVarName = "configurationInjectName" + HashUtil.sha1(configurationInjectName); 258 | 259 | FieldCreator configurationCreator = classCreator.getFieldCreator(injectVarName, JooqCustomContext.class) 260 | .setModifiers(Opcodes.ACC_MODULE); 261 | 262 | configurationCreator.addAnnotation(Inject.class); 263 | configurationCreator.addAnnotation(AnnotationInstance.create(DotNames.NAMED, null, 264 | new AnnotationValue[] { AnnotationValue.createStringValue("value", configurationInjectName) })); 265 | 266 | ResultHandle configurationRH = namedDslContextMethodCreator.readInstanceField(FieldDescriptor 267 | .of(classCreator.getClassName(), injectVarName, JooqCustomContext.class.getName()), 268 | namedDslContextMethodCreator.getThis()); 269 | 270 | namedDslContextMethodCreator.returnValue(namedDslContextMethodCreator.invokeVirtualMethod( 271 | MethodDescriptor.ofMethod(producerClass, "createDslContext", 272 | DSLContext.class, String.class, AgroalDataSource.class, JooqCustomContext.class), 273 | namedDslContextMethodCreator.getThis(), dialectRH, dataSourceRH, configurationRH)); 274 | } else { 275 | ResultHandle configurationRH = namedConfig.configuration().isPresent() 276 | ? namedDslContextMethodCreator.load(namedConfig.configuration().get()) 277 | : namedDslContextMethodCreator.loadNull(); 278 | 279 | namedConfig.configuration() 280 | .ifPresent(s -> unremovableBeans.produce(new UnremovableBeanBuildItem(new BeanClassNameExclusion(s)))); 281 | 282 | namedDslContextMethodCreator.returnValue(namedDslContextMethodCreator.invokeVirtualMethod( 283 | MethodDescriptor.ofMethod(producerClass, "createDslContext", DSLContext.class, 284 | String.class, AgroalDataSource.class, String.class), 285 | namedDslContextMethodCreator.getThis(), dialectRH, dataSourceRH, configurationRH)); 286 | } 287 | } 288 | 289 | classCreator.close(); 290 | } 291 | 292 | protected boolean isPresentDialect(JooqItemConfig itemConfig) { 293 | return itemConfig.dialect() != null && !itemConfig.dialect().isEmpty(); 294 | } 295 | 296 | static class RegisterClassesForReflectionEnabled implements BooleanSupplier { 297 | JooqConfig jooqConfig; 298 | 299 | public boolean getAsBoolean() { 300 | return jooqConfig.registerGeneratedClassesForReflection(); 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/Demo.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigDecimal; 5 | import java.util.Date; 6 | 7 | import io.quarkus.runtime.annotations.RegisterForReflection; 8 | 9 | /** 10 | * 11 | * @author Leo Tu 12 | */ 13 | @SuppressWarnings("serial") 14 | @RegisterForReflection 15 | public class Demo implements Serializable { 16 | 17 | private String id; 18 | private String name; 19 | private BigDecimal amount; 20 | private Date createdAt; 21 | 22 | public String getId() { 23 | return id; 24 | } 25 | 26 | public void setId(String id) { 27 | this.id = id; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public void setName(String name) { 35 | this.name = name; 36 | } 37 | 38 | public BigDecimal getAmount() { 39 | return amount; 40 | } 41 | 42 | public void setAmount(BigDecimal amount) { 43 | this.amount = amount; 44 | } 45 | 46 | public Date getCreatedAt() { 47 | return createdAt; 48 | } 49 | 50 | public void setCreatedAt(Date createdAt) { 51 | this.createdAt = createdAt; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return super.toString() + "[id=" + id + ", name=" + name + ", amount=" + amount + ", createdAt=" + createdAt 57 | + "]"; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/InjectTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import jakarta.enterprise.context.ApplicationScoped; 10 | import jakarta.enterprise.inject.Default; 11 | import jakarta.enterprise.inject.Instance; 12 | import jakarta.enterprise.inject.Produces; 13 | import jakarta.inject.Inject; 14 | import jakarta.inject.Named; 15 | import jakarta.inject.Provider; 16 | import jakarta.inject.Qualifier; 17 | import jakarta.inject.Singleton; 18 | 19 | import org.jboss.logging.Logger; 20 | import org.junit.jupiter.api.Order; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import io.quarkus.test.junit.QuarkusTest; 24 | 25 | /** 26 | * 27 | * @author Leo Tu 28 | */ 29 | //@Disabled 30 | @QuarkusTest 31 | public class InjectTest { 32 | private static final Logger LOGGER = Logger.getLogger(InjectTest.class); 33 | 34 | @Inject 35 | TestServiceBean testBean; 36 | 37 | @Order(1) 38 | @Test 39 | public void test1() throws Exception { 40 | try { 41 | testBean.action(); 42 | } catch (Exception e) { 43 | LOGGER.error("", e); 44 | throw e; 45 | } 46 | } 47 | 48 | @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE }) 49 | @Retention(RetentionPolicy.RUNTIME) 50 | @Documented 51 | @Qualifier 52 | static public @interface ServiceType { 53 | 54 | String value(); 55 | } 56 | 57 | @ApplicationScoped 58 | static public class ServiceBeanProducer { 59 | 60 | @Singleton 61 | @Produces 62 | @Default 63 | public ServiceInterface createDefault() { 64 | LOGGER.debug("createDefault"); 65 | return new ServiceImpl("my-default"); 66 | } 67 | 68 | @ApplicationScoped 69 | @Produces 70 | @Named("name1") 71 | @ServiceType("name1") 72 | public ServiceInterface createNamed1() { 73 | LOGGER.debug("createNamed1"); 74 | return new ServiceImpl("my-name-1"); 75 | } 76 | 77 | @ApplicationScoped 78 | @Produces 79 | @Named("name2") 80 | @ServiceType("name2") 81 | public ServiceInterface createNamed2() { 82 | LOGGER.debug("createNamed2"); 83 | return new ServiceImpl("my-name-2"); 84 | } 85 | 86 | @ApplicationScoped 87 | @Produces 88 | @Named("name3") 89 | @ServiceType("name3") 90 | public ServiceInterface createNamed3() { 91 | LOGGER.debug("createNamed3"); 92 | return new ServiceImpl("my-name-3"); 93 | } 94 | } 95 | 96 | static public interface ServiceInterface { 97 | 98 | public String getMyName(); 99 | } 100 | 101 | static public class ServiceImpl implements ServiceInterface { 102 | private final String name; 103 | 104 | public ServiceImpl(String name) { 105 | this.name = name; 106 | } 107 | 108 | @Override 109 | public String getMyName() { 110 | LOGGER.debug("name:" + name); 111 | return name; 112 | } 113 | } 114 | 115 | @ApplicationScoped 116 | static public class TestServiceBean { 117 | 118 | @Inject 119 | // ServiceInterface defaultService; 120 | Instance defaultService; 121 | 122 | @Inject 123 | @Named("name1") 124 | ServiceInterface service1; 125 | 126 | @Inject 127 | @Named("name2") 128 | Provider service2; 129 | 130 | @Inject 131 | @Named("name3") 132 | Instance service3; 133 | 134 | void action() throws Exception { 135 | LOGGER.debug(">> defaultService=" + defaultService.get().getMyName()); 136 | LOGGER.debug(">> service1=" + service1.getMyName()); 137 | LOGGER.debug(">> service2=" + service2.get().getMyName()); 138 | LOGGER.debug(">> service3=" + service3.get().getMyName()); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/JooqTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import java.math.BigDecimal; 4 | import java.sql.Connection; 5 | import java.sql.DatabaseMetaData; 6 | import java.sql.ResultSet; 7 | import java.sql.Statement; 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.UUID; 11 | import java.util.concurrent.ThreadLocalRandom; 12 | 13 | import jakarta.annotation.PostConstruct; 14 | import jakarta.enterprise.context.ApplicationScoped; 15 | import jakarta.enterprise.event.Observes; 16 | import jakarta.inject.Inject; 17 | import jakarta.inject.Named; 18 | import jakarta.transaction.Transactional; 19 | import jakarta.transaction.Transactional.TxType; 20 | 21 | import org.h2.tools.Server; 22 | import org.jboss.logging.Logger; 23 | import org.jooq.DSLContext; 24 | import org.jooq.impl.DSL; 25 | import org.junit.jupiter.api.*; 26 | 27 | import io.quarkus.runtime.ShutdownEvent; 28 | import io.quarkus.runtime.StartupEvent; 29 | import io.quarkus.test.junit.QuarkusTest; 30 | 31 | /** 32 | * 33 | * @author Leo Tu 34 | */ 35 | //@Disabled 36 | @QuarkusTest 37 | public class JooqTest { 38 | private static final Logger LOGGER = Logger.getLogger(JooqTest.class); 39 | 40 | /** 41 | * http://www.h2database.com/html/main.html 42 | */ 43 | static private Server server; 44 | 45 | @Order(1) 46 | @BeforeAll 47 | static public void startDatabase() { 48 | LOGGER.debug("Start H2 server..." + server); 49 | try { 50 | server = Server 51 | .createTcpServer(new String[] { "-ifNotExists", "-trace", "-tcp", "-tcpAllowOthers", "-tcpPort", "19092" }) 52 | .start(); 53 | Thread.sleep(1000 * 1); // waiting for database to be ready 54 | } catch (Exception e) { 55 | LOGGER.error("Start H2 server failed", e); 56 | throw new RuntimeException(e); 57 | } 58 | } 59 | 60 | @AfterAll 61 | static public void stopDatabase() { 62 | LOGGER.debug("Stop H2 server..." + server); 63 | if (server != null) { 64 | server.stop(); 65 | server = null; 66 | } 67 | // while (true) { // only for GUI tool to view data 68 | // try { 69 | // Thread.sleep(100); 70 | // } catch (InterruptedException e) { 71 | // e.printStackTrace(); 72 | // } 73 | // } 74 | } 75 | 76 | @Inject 77 | TestBean testBean; 78 | 79 | // @BeforeEach 80 | // public void setUp() throws Exception { 81 | // LOGGER.debug("setUp..."); 82 | // } 83 | // 84 | // @AfterEach 85 | // public void tearDown() throws Exception { 86 | // LOGGER.debug("tearDown..."); 87 | // } 88 | 89 | @Test 90 | public void test1() throws Exception { 91 | LOGGER.info("BEGIN test1..."); 92 | try { 93 | testBean.testConnection(); 94 | // 95 | testBean.testDDL(); 96 | testBean.testAll(); 97 | 98 | // testBean.testInsert(); 99 | // testBean.testUpdate(); 100 | // testBean.testQuery(); 101 | // testBean.testDelete(); // get connection failed if max<=2 102 | // testBean.testCount(); 103 | 104 | testBean.testDDL1(); 105 | testBean.testAllService1(); 106 | } catch (Exception e) { 107 | LOGGER.error("", e); 108 | throw e; 109 | } finally { 110 | LOGGER.info("END test1."); 111 | } 112 | } 113 | 114 | @ApplicationScoped 115 | static class TestBean { 116 | 117 | @Inject 118 | DSLContext dsl; // default 119 | 120 | @Inject 121 | @Named("dsl1") 122 | DSLContext dsl1; 123 | 124 | @Inject 125 | @Named("dsl2") 126 | DSLContext dsl2; 127 | 128 | private ServiceAction action; 129 | private ServiceAction action1; 130 | 131 | @PostConstruct 132 | void onPostConstruct() { 133 | LOGGER.debug("onPostConstruct"); 134 | } 135 | 136 | /** 137 | * Called when the runtime has started 138 | * 139 | * @param event 140 | */ 141 | void onStart(@Observes StartupEvent event) { 142 | LOGGER.debug("onStart, event=" + event); 143 | action = new ServiceAction(dsl, "name00", 10); 144 | action1 = new ServiceAction(dsl1, "name11", 15); 145 | } 146 | 147 | void onStop(@Observes ShutdownEvent event) { 148 | LOGGER.debug("onStop, event=" + event); 149 | } 150 | 151 | // https://github.com/quarkusio/quarkus/issues/2224 152 | // public void onTxSuccessEvent(@Observes(during = 153 | // TransactionPhase.AFTER_SUCCESS) String msg) { 154 | // LOGGER.debug("onTxSuccessEvent, msg=" + msg); 155 | // } 156 | // 157 | // public void onTxFailureEvent(@Observes(during = 158 | // TransactionPhase.AFTER_FAILURE) String msg) { 159 | // LOGGER.debug("onTxFailureEvent, msg=" + msg); 160 | // } 161 | // 162 | // public void onTxCompletionEvent(@Observes(during = 163 | // TransactionPhase.AFTER_COMPLETION) String msg) { 164 | // LOGGER.debug("onTxCompletionEvent, msg=" + msg); 165 | // } 166 | 167 | void testConnection() throws Exception { 168 | // (default) 169 | try (Connection conn = dsl.parsingConnection()) { 170 | DatabaseMetaData dmd = conn.getMetaData(); 171 | LOGGER.debugv("dsl, databaseProductName: {0}, databaseProductVersion: {1}", 172 | dmd.getDatabaseProductName(), dmd.getDatabaseProductVersion()); 173 | } catch (Exception e) { 174 | LOGGER.error("dsl.getConnection", e); 175 | throw e; 176 | } 177 | 178 | // (1) 179 | try (Connection conn = dsl1.parsingConnection()) { 180 | DatabaseMetaData dmd = conn.getMetaData(); 181 | LOGGER.debugv("dsl1, databaseProductName: {0}, databaseProductVersion: {1}", 182 | dmd.getDatabaseProductName(), dmd.getDatabaseProductVersion()); 183 | } catch (Exception e) { 184 | LOGGER.error("dsl1.getConnection", e); 185 | throw e; 186 | } 187 | 188 | // (2) 189 | try (Connection conn = dsl2.parsingConnection()) { 190 | DatabaseMetaData dmd = conn.getMetaData(); 191 | LOGGER.debugv("dsl2, databaseProductName: {0}, databaseProductVersion: {1}", 192 | dmd.getDatabaseProductName(), dmd.getDatabaseProductVersion()); 193 | } catch (Exception e) { 194 | LOGGER.error("dsl2.getConnection", e); 195 | throw e; 196 | } 197 | } 198 | 199 | // === (default) 200 | void testDDL() throws Exception { 201 | action.createDDL(); 202 | } 203 | 204 | @Transactional 205 | void testInsert() throws Exception { 206 | action.insertData(); 207 | } 208 | 209 | @Transactional 210 | void testUpdate() throws Exception { 211 | action.updateData(); 212 | } 213 | 214 | @Transactional(TxType.SUPPORTS) 215 | void testQuery() throws Exception { 216 | action.queryData(); 217 | } 218 | 219 | @Transactional(TxType.REQUIRED) 220 | void testDelete() throws Exception { 221 | action.deleteData(); 222 | } 223 | 224 | @Transactional(TxType.SUPPORTS) 225 | void testCount() throws Exception { 226 | action.countData(); 227 | } 228 | 229 | @Transactional(TxType.REQUIRED) 230 | void testAllService() throws Exception { 231 | action.insertData(); 232 | action.updateData(); 233 | action.queryData(); 234 | action.deleteData(); 235 | action.countData(); 236 | } 237 | 238 | @Transactional(TxType.REQUIRED) 239 | void testAll() throws Exception { 240 | testInsert(); 241 | testUpdate(); 242 | testQuery(); 243 | testDelete(); 244 | testCount(); 245 | } 246 | 247 | // === (1) 248 | void testDDL1() throws Exception { 249 | action1.createDDL(); 250 | } 251 | 252 | @Transactional 253 | void testInsert1() throws Exception { 254 | action1.insertData(); 255 | } 256 | 257 | @Transactional 258 | void testUpdate1() throws Exception { 259 | action1.updateData(); 260 | } 261 | 262 | @Transactional(TxType.SUPPORTS) 263 | void testQuery1() throws Exception { 264 | action1.queryData(); 265 | } 266 | 267 | @Transactional(TxType.REQUIRED) 268 | void testDelete1() throws Exception { 269 | action1.deleteData(); 270 | } 271 | 272 | @Transactional(TxType.SUPPORTS) 273 | void testCount1() throws Exception { 274 | action1.countData(); 275 | } 276 | 277 | @Transactional(TxType.REQUIRED) 278 | void testAllService1() throws Exception { 279 | action1.insertData(); 280 | action1.updateData(); 281 | action1.queryData(); 282 | action1.deleteData(); 283 | action1.countData(); 284 | } 285 | 286 | @Transactional(TxType.REQUIRED) 287 | void testAll1() throws Exception { 288 | testInsert1(); 289 | testUpdate1(); 290 | testQuery1(); 291 | testDelete1(); 292 | testCount1(); 293 | } 294 | 295 | } 296 | 297 | static class ServiceAction { 298 | 299 | final private DSLContext dsl; 300 | final private int loop; 301 | final private String prefix; 302 | 303 | public ServiceAction(DSLContext dsl, String prefix, int loop) { 304 | this.dsl = dsl; 305 | this.prefix = prefix; 306 | this.loop = loop; 307 | } 308 | 309 | public ServiceAction(DSLContext dsl) { 310 | this.dsl = dsl; 311 | this.prefix = null; 312 | this.loop = -1; 313 | } 314 | 315 | void createDDL() throws Exception { 316 | String table = QDemo.$.getName(); 317 | String ddl = "" + // 318 | "CREATE TABLE " + table + "(" + // 319 | " id char(32) NOT NULL," + // 320 | " name varchar(128) NOT NULL," + // 321 | " amount decimal(12,3) ," + // 322 | " created_at timestamp NOT NULL," + // 323 | " PRIMARY KEY (id)" + // 324 | ")"; 325 | 326 | try (Connection conn = dsl.parsingConnection()) { 327 | Statement stmt = conn.createStatement(); 328 | stmt.execute(ddl); 329 | stmt.close(); 330 | // listTableTypes(conn); 331 | ResultSet rs = conn.getMetaData().getTables(null, null, table.toUpperCase(), new String[] { "TABLE" }); 332 | boolean tableExists = false; 333 | while (rs.next()) { 334 | String tableType = rs.getString("TABLE_TYPE"); 335 | String tableCatalog = rs.getString("TABLE_CAT"); 336 | String tableSchema = rs.getString("TABLE_SCHEM"); 337 | String tableName = rs.getString("TABLE_NAME"); 338 | // tableType:TABLE, tableCatalog:DEFAULT, tableSchema:PUBLIC, table:demo 339 | LOGGER.debugv("tableType:{0}, tableCatalog:{1}, tableSchema:{2}, table:{3}", tableType, 340 | tableCatalog, tableSchema, table); 341 | if (table.equalsIgnoreCase(tableName)) { 342 | tableExists = true; 343 | } 344 | } 345 | 346 | LOGGER.debugv("createDDL table: {0} success: {1}", table, tableExists); 347 | rs.close(); 348 | Assertions.assertTrue(tableExists); 349 | } 350 | } 351 | 352 | @SuppressWarnings("unused") 353 | private void listTableTypes(Connection conn) throws Exception { 354 | DatabaseMetaData dmd = conn.getMetaData(); 355 | ResultSet ttRs = dmd.getTableTypes(); 356 | int columnCount = ttRs.getMetaData().getColumnCount(); 357 | while (ttRs.next()) { 358 | for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) { 359 | String tableType = ttRs.getString(columnIndex); 360 | // tableType: "EXTERNAL","SYSTEM TABLE","TABLE","TABLE LINK","VIEW" 361 | LOGGER.debugv("tableType: {0}", tableType); 362 | } 363 | } 364 | ttRs.close(); 365 | } 366 | 367 | void insertData() throws Exception { 368 | for (int i = 0; i < loop; i++) { 369 | String id = UUID.randomUUID().toString().replaceAll("-", ""); 370 | int randomNum = ThreadLocalRandom.current().nextInt(0, 9); 371 | long row = dsl.insertInto(QDemo.$) // 372 | .set(QDemo.$.id, id) // 373 | .set(QDemo.$.name, prefix + "-" + i) // 374 | .set(QDemo.$.amount, new BigDecimal(12.1 + randomNum)) // 375 | .set(QDemo.$.createdAt, new Date()) // 376 | .execute(); 377 | LOGGER.debugv("insertData prefix: {0}, i: {1}, row: {2}", prefix, i, row); 378 | Assertions.assertEquals(1, row); 379 | } 380 | } 381 | 382 | void updateData() throws Exception { 383 | long row = dsl.update(QDemo.$) // 384 | .set(QDemo.$.name, prefix + "-" + "5U") // 385 | .set(QDemo.$.createdAt, new Date()) // 386 | .where(QDemo.$.name.eq(prefix + "-" + 5)) // 387 | .execute(); 388 | LOGGER.debugv("updateData prefix: {0}, row: {1}", prefix, row); 389 | Assertions.assertEquals(1, row); 390 | } 391 | 392 | void queryData() throws Exception { 393 | List dataList = dsl.select() // 394 | .from(QDemo.$) // 395 | .fetchInto(Demo.class); 396 | 397 | LOGGER.debugv("queryData prefix: {0}, dataList.size: {1}", prefix, dataList.size()); 398 | Assertions.assertTrue(dataList.size() == loop); 399 | 400 | Demo data = dsl.select() // 401 | .from(QDemo.$) // 402 | .where(QDemo.$.name.eq(prefix + "-" + "5U")) // 403 | .fetchOneInto(Demo.class); 404 | LOGGER.debugv("queryData prefix: {0}, data: {1}", prefix, data); 405 | Assertions.assertTrue(data != null); 406 | } 407 | 408 | void deleteData() throws Exception { 409 | LOGGER.debug("deleteData..."); 410 | long row = dsl.delete(QDemo.$) // 411 | .execute(); 412 | LOGGER.debugv("deleteData prefix: {0}, row: {1}", prefix, row); 413 | Assertions.assertTrue(row == loop); 414 | } 415 | 416 | void countData() throws Exception { 417 | LOGGER.debug("countData..."); 418 | long total = dsl.select(DSL.count()).from(QDemo.$).fetchOneInto(long.class); 419 | // long total = dsl.selectCount().from(QDemo.$).fetchOne(0, long.class); 420 | LOGGER.debugv("countData prefix: {0}, total: {1}", prefix, total); 421 | Assertions.assertTrue(total == 0); 422 | } 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/Keys.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import org.jooq.UniqueKey; 4 | import org.jooq.impl.DSL; 5 | import org.jooq.impl.Internal; 6 | 7 | /** 8 | * A class modelling foreign key relationships and constraints of tables of the 9 | * schema. 10 | */ 11 | @SuppressWarnings({ "all", "unchecked", "rawtypes" }) 12 | public class Keys { 13 | 14 | // ------------------------------------------------------------------------- 15 | // IDENTITY definitions 16 | // ------------------------------------------------------------------------- 17 | 18 | // ------------------------------------------------------------------------- 19 | // UNIQUE and PRIMARY KEY definitions 20 | // ------------------------------------------------------------------------- 21 | 22 | public static final UniqueKey DEMO_PKEY = UniqueKeys0.DEMO_PKEY; 23 | 24 | // ------------------------------------------------------------------------- 25 | // FOREIGN KEY definitions 26 | // ------------------------------------------------------------------------- 27 | 28 | // ------------------------------------------------------------------------- 29 | // [#1459] distribute members to avoid static initialisers > 64kb 30 | // ------------------------------------------------------------------------- 31 | 32 | private static class UniqueKeys0 { 33 | 34 | public static final UniqueKey DEMO_PKEY = Internal.createUniqueKey(QDemo.$, DSL.name("demo_pkey"), QDemo.$.id); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/MyCustomConfiguration1.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import io.quarkiverse.jooq.runtime.JooqCustomContext; 4 | 5 | /** 6 | * 7 | * @author Leo Tu 8 | */ 9 | public class MyCustomConfiguration1 implements JooqCustomContext { 10 | } 11 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/MyCustomConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import jakarta.annotation.PostConstruct; 4 | import jakarta.enterprise.context.ApplicationScoped; 5 | import jakarta.enterprise.inject.Produces; 6 | import jakarta.inject.Named; 7 | import jakarta.inject.Singleton; 8 | 9 | import org.jboss.logging.Logger; 10 | 11 | import io.quarkiverse.jooq.runtime.JooqCustomContext; 12 | 13 | /** 14 | * 15 | * @author Leo Tu 16 | */ 17 | //@ApplicationScoped 18 | @Singleton 19 | public class MyCustomConfigurationFactory { 20 | private static final Logger LOGGER = Logger.getLogger(MyCustomConfigurationFactory.class); 21 | 22 | @PostConstruct 23 | void onPostConstruct() { 24 | LOGGER.debug("MyCustomConfigurationFactory: onPostConstruct"); 25 | } 26 | 27 | @ApplicationScoped 28 | @Produces 29 | @Named("myCustomConfiguration2") 30 | public JooqCustomContext create() { 31 | LOGGER.debug("MyCustomConfigurationFactory: create"); 32 | return new JooqCustomContext() { 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/Public.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import org.jooq.impl.SchemaImpl; 4 | 5 | @SuppressWarnings({ "all", "unchecked", "rawtypes" }) 6 | public class Public extends SchemaImpl { 7 | 8 | /** 9 | * The reference instance of PUBLIC 10 | */ 11 | public static final Public PUBLIC = new Public(); 12 | 13 | /** 14 | * The table PUBLIC.BOOK. 15 | */ 16 | public final QDemo DEMO = QDemo.$; 17 | 18 | /** 19 | * No further instances allowed 20 | */ 21 | private Public() { 22 | super("PUBLIC", null); 23 | } 24 | 25 | // /** 26 | // * {@inheritDoc} 27 | // */ 28 | // @Override 29 | // public Catalog getCatalog() { 30 | // return DefaultCatalog.DEFAULT_CATALOG; 31 | // } 32 | // 33 | // @Override 34 | // public final List> getTables() { 35 | // List result = new ArrayList(); 36 | // result.addAll(getTables0()); 37 | // return result; 38 | // } 39 | // 40 | // private final List> getTables0() { 41 | // return Arrays.>asList( 42 | // Author.AUTHOR, 43 | // Book.BOOK, 44 | // BookStore.BOOK_STORE, 45 | // BookToBookStore.BOOK_TO_BOOK_STORE); 46 | // } 47 | } 48 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/QDemo.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Arrays; 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | import org.jooq.Field; 9 | import org.jooq.Name; 10 | import org.jooq.Schema; 11 | import org.jooq.Table; 12 | import org.jooq.TableField; 13 | import org.jooq.UniqueKey; 14 | import org.jooq.impl.DSL; 15 | import org.jooq.impl.SQLDataType; 16 | import org.jooq.impl.TableImpl; 17 | 18 | import io.quarkiverse.jooq.runtime.SQLDataTypeExt; 19 | 20 | /** 21 | * 22 | * @author Leo Tu 23 | */ 24 | @SuppressWarnings("serial") 25 | public class QDemo extends TableImpl { 26 | 27 | public static final QDemo $ = new QDemo(); 28 | 29 | /** 30 | * The class holding records for this type 31 | */ 32 | @Override 33 | public Class getRecordType() { 34 | return RDemo.class; 35 | } 36 | 37 | public final TableField id = createField(DSL.name("id"), SQLDataType.CHAR(22).nullable(false).identity(true), 38 | this, 39 | "The PK"); 40 | public final TableField name = createField(DSL.name("name"), SQLDataType.VARCHAR(128).nullable(false), this, 41 | "The Name"); 42 | public final TableField amount = createField(DSL.name("amount"), SQLDataType.NUMERIC(12, 3), this, 43 | "Amount Value"); 44 | public final TableField createdAt = createField(DSL.name("created_at"), 45 | SQLDataTypeExt.UTILDATE.nullable(false), 46 | this, "Created At"); 47 | 48 | public QDemo() { 49 | this(DSL.name("demo"), null); 50 | } 51 | 52 | public QDemo(String alias) { 53 | this(DSL.name(alias), $); 54 | } 55 | 56 | private QDemo(Name alias, Table aliased) { 57 | this(alias, aliased, null); 58 | } 59 | 60 | private QDemo(Name alias, Table aliased, Field[] parameters) { 61 | super(alias, null, aliased, parameters, DSL.comment("Demo Table")); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public Schema getSchema() { 69 | return Public.PUBLIC; 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | public UniqueKey getPrimaryKey() { 77 | return Keys.DEMO_PKEY; 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | */ 83 | @Override 84 | public List> getKeys() { 85 | return Arrays.> asList(Keys.DEMO_PKEY); 86 | } 87 | 88 | /** 89 | * {@inheritDoc} 90 | */ 91 | @Override 92 | public QDemo as(String alias) { 93 | return new QDemo(DSL.name(alias), this); 94 | } 95 | 96 | /** 97 | * {@inheritDoc} 98 | */ 99 | @Override 100 | public QDemo as(Name alias) { 101 | return new QDemo(alias, this); 102 | } 103 | 104 | /** 105 | * Rename this table 106 | */ 107 | @Override 108 | public QDemo rename(String name) { 109 | return new QDemo(DSL.name(name), null); 110 | } 111 | 112 | /** 113 | * Rename this table 114 | */ 115 | @Override 116 | public QDemo rename(Name name) { 117 | return new QDemo(name, null); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /deployment/src/test/java/io/quarkiverse/jooq/RDemo.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Date; 5 | 6 | import org.jooq.impl.UpdatableRecordImpl; 7 | 8 | import io.quarkus.runtime.annotations.RegisterForReflection; 9 | 10 | /** 11 | * 12 | * @author Leo Tu 13 | */ 14 | @SuppressWarnings("serial") 15 | @RegisterForReflection 16 | public class RDemo extends UpdatableRecordImpl { 17 | 18 | private String id; 19 | private String name; 20 | private BigDecimal amount; 21 | private Date createdAt; 22 | 23 | /** 24 | * Create a detached RCompany 25 | */ 26 | public RDemo() { 27 | super(QDemo.$); 28 | } 29 | 30 | public String getId() { 31 | return (String) get(0); 32 | } 33 | 34 | public RDemo setId(String id) { 35 | set(0, id); 36 | return this; 37 | } 38 | 39 | public String getName() { 40 | return (String) get(1); 41 | } 42 | 43 | public RDemo setName(String name) { 44 | set(1, name); 45 | return this; 46 | } 47 | 48 | public BigDecimal getAmount() { 49 | return (BigDecimal) get(2); 50 | } 51 | 52 | public RDemo setAmount(BigDecimal amount) { 53 | set(2, amount); 54 | return this; 55 | } 56 | 57 | public Date getCreatedAt() { 58 | return (Date) get(3); 59 | } 60 | 61 | public RDemo setCreatedAt(Date createdAt) { 62 | set(3, createdAt); 63 | return this; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return super.toString() + "[id=" + id + ", name=" + name + ", amount=" + amount + ", createdAt=" + createdAt 69 | + "]"; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /deployment/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | # https://quarkus.io/guides/logging-guide 2 | 3 | quarkus.log.level = INFO 4 | quarkus.log.file.enable=false 5 | 6 | quarkus.log.console.enable = true 7 | #quarkus.log.console.format = %d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n 8 | quarkus.log.console.format = %d{HH:mm:ss.SSS} %-5p [%t] [%C:%L,%M\(\)] %s%e%n 9 | quarkus.log.console.level = DEBUG 10 | quarkus.log.console.color = false 11 | 12 | quarkus.log.category."io.quarkiverse.jooq".level = DEBUG 13 | quarkus.log.category."io.quarkiverse.jooq.sql".level = DEBUG 14 | #quarkus.log.category."io.quarkus.agroal.runtime".level = DEBUG 15 | 16 | # default datasource 17 | quarkus.jooq.dialect=H2 18 | quarkus.jooq.configuration-inject=myCustomConfiguration2 19 | 20 | quarkus.jooq.dsl1.dialect=H2 21 | quarkus.jooq.dsl1.datasource=datasource1 22 | quarkus.jooq.dsl1.configuration=io.quarkiverse.jooq.MyCustomConfiguration1 23 | 24 | quarkus.jooq.dsl2.dialect=H2 25 | quarkus.jooq.dsl2.datasource=datasource2 26 | quarkus.jooq.dsl2.configuration-inject=myCustomConfiguration2 27 | 28 | # 29 | quarkus.datasource.db-kind=h2 30 | quarkus.datasource.username=username-default 31 | quarkus.datasource.password=username-default 32 | quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:default;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE; 33 | quarkus.datasource.jdbc.min-size=1 34 | quarkus.datasource.jdbc.max-size=2 35 | 36 | quarkus.datasource.datasource1.db-kind=h2 37 | quarkus.datasource.datasource1.username=username1 38 | quarkus.datasource.datasource1.password=username1 39 | quarkus.datasource.datasource1.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:datasource1;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE; 40 | quarkus.datasource.datasource1.jdbc.min-size=1 41 | quarkus.datasource.datasource1.jdbc.max-size=2 42 | 43 | quarkus.datasource.datasource2.db-kind=h2 44 | quarkus.datasource.datasource2.username=username2 45 | quarkus.datasource.datasource2.password=username2 46 | quarkus.datasource.datasource2.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:datasource2;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE; 47 | quarkus.datasource.datasource2.jdbc.min-size=1 48 | quarkus.datasource.datasource2.jdbc.max-size=2 -------------------------------------------------------------------------------- /docs/antora.yml: -------------------------------------------------------------------------------- 1 | name: quarkus-jooq 2 | title: jOOQ 3 | version: dev 4 | nav: 5 | - modules/ROOT/nav.adoc 6 | -------------------------------------------------------------------------------- /docs/modules/ROOT/assets/images/.keepme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-jooq/a86b0e8a7bb01bfec34aa6104dc1087b6b87e6cb/docs/modules/ROOT/assets/images/.keepme -------------------------------------------------------------------------------- /docs/modules/ROOT/examples/.keepme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quarkiverse/quarkus-jooq/a86b0e8a7bb01bfec34aa6104dc1087b6b87e6cb/docs/modules/ROOT/examples/.keepme -------------------------------------------------------------------------------- /docs/modules/ROOT/nav.adoc: -------------------------------------------------------------------------------- 1 | * xref:index.adoc[Quarkus jOOQ] 2 | -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :project-version: 2.1.0 2 | 3 | :examples-dir: ./../examples/ -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/includes/quarkus-jooq.adoc: -------------------------------------------------------------------------------- 1 | :summaryTableId: quarkus-jooq_quarkus-jooq 2 | [.configuration-legend] 3 | icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime 4 | [.configuration-reference.searchable, cols="80,.^10,.^10"] 5 | |=== 6 | 7 | h|[.header-title]##Configuration property## 8 | h|Type 9 | h|Default 10 | 11 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-dialect]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-dialect[`quarkus.jooq.dialect`]## 12 | 13 | [.description] 14 | -- 15 | The jOOQ dialect 16 | 17 | 18 | ifdef::add-copy-button-to-env-var[] 19 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_DIALECT+++[] 20 | endif::add-copy-button-to-env-var[] 21 | ifndef::add-copy-button-to-env-var[] 22 | Environment variable: `+++QUARKUS_JOOQ_DIALECT+++` 23 | endif::add-copy-button-to-env-var[] 24 | -- 25 | |string 26 | |required icon:exclamation-circle[title=Configuration property is required] 27 | 28 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-datasource]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-datasource[`quarkus.jooq.datasource`]## 29 | 30 | [.description] 31 | -- 32 | The jOOQ dataSource 33 | 34 | 35 | ifdef::add-copy-button-to-env-var[] 36 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_DATASOURCE+++[] 37 | endif::add-copy-button-to-env-var[] 38 | ifndef::add-copy-button-to-env-var[] 39 | Environment variable: `+++QUARKUS_JOOQ_DATASOURCE+++` 40 | endif::add-copy-button-to-env-var[] 41 | -- 42 | |string 43 | | 44 | 45 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-configuration]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-configuration[`quarkus.jooq.configuration`]## 46 | 47 | [.description] 48 | -- 49 | The jOOQ configuration 50 | 51 | 52 | ifdef::add-copy-button-to-env-var[] 53 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_CONFIGURATION+++[] 54 | endif::add-copy-button-to-env-var[] 55 | ifndef::add-copy-button-to-env-var[] 56 | Environment variable: `+++QUARKUS_JOOQ_CONFIGURATION+++` 57 | endif::add-copy-button-to-env-var[] 58 | -- 59 | |string 60 | | 61 | 62 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-configuration-inject]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-configuration-inject[`quarkus.jooq.configuration-inject`]## 63 | 64 | [.description] 65 | -- 66 | The jOOQ configuration by inject named 67 | 68 | 69 | ifdef::add-copy-button-to-env-var[] 70 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_CONFIGURATION_INJECT+++[] 71 | endif::add-copy-button-to-env-var[] 72 | ifndef::add-copy-button-to-env-var[] 73 | Environment variable: `+++QUARKUS_JOOQ_CONFIGURATION_INJECT+++` 74 | endif::add-copy-button-to-env-var[] 75 | -- 76 | |string 77 | | 78 | 79 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-register-generated-classes-for-reflection]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-register-generated-classes-for-reflection[`quarkus.jooq.register-generated-classes-for-reflection`]## 80 | 81 | [.description] 82 | -- 83 | Whether to automatically register jOOQ records/POJOs for reflection. 84 | 85 | 86 | ifdef::add-copy-button-to-env-var[] 87 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_REGISTER_GENERATED_CLASSES_FOR_REFLECTION+++[] 88 | endif::add-copy-button-to-env-var[] 89 | ifndef::add-copy-button-to-env-var[] 90 | Environment variable: `+++QUARKUS_JOOQ_REGISTER_GENERATED_CLASSES_FOR_REFLECTION+++` 91 | endif::add-copy-button-to-env-var[] 92 | -- 93 | |boolean 94 | |`true` 95 | 96 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-generated-classes-pattern]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-generated-classes-pattern[`quarkus.jooq.generated-classes-pattern`]## 97 | 98 | [.description] 99 | -- 100 | Regex used to determine classes to be registered for reflection. 101 | 102 | 103 | ifdef::add-copy-button-to-env-var[] 104 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_GENERATED_CLASSES_PATTERN+++[] 105 | endif::add-copy-button-to-env-var[] 106 | ifndef::add-copy-button-to-env-var[] 107 | Environment variable: `+++QUARKUS_JOOQ_GENERATED_CLASSES_PATTERN+++` 108 | endif::add-copy-button-to-env-var[] 109 | -- 110 | |string 111 | |`.+\.tables\.(pojos\|records)\..+` 112 | 113 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-dialect]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-dialect[`quarkus.jooq."named-config".dialect`]## 114 | 115 | [.description] 116 | -- 117 | The jOOQ dialect 118 | 119 | 120 | ifdef::add-copy-button-to-env-var[] 121 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__DIALECT+++[] 122 | endif::add-copy-button-to-env-var[] 123 | ifndef::add-copy-button-to-env-var[] 124 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__DIALECT+++` 125 | endif::add-copy-button-to-env-var[] 126 | -- 127 | |string 128 | |required icon:exclamation-circle[title=Configuration property is required] 129 | 130 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-datasource]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-datasource[`quarkus.jooq."named-config".datasource`]## 131 | 132 | [.description] 133 | -- 134 | The jOOQ dataSource 135 | 136 | 137 | ifdef::add-copy-button-to-env-var[] 138 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__DATASOURCE+++[] 139 | endif::add-copy-button-to-env-var[] 140 | ifndef::add-copy-button-to-env-var[] 141 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__DATASOURCE+++` 142 | endif::add-copy-button-to-env-var[] 143 | -- 144 | |string 145 | | 146 | 147 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-configuration]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-configuration[`quarkus.jooq."named-config".configuration`]## 148 | 149 | [.description] 150 | -- 151 | The jOOQ configuration 152 | 153 | 154 | ifdef::add-copy-button-to-env-var[] 155 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION+++[] 156 | endif::add-copy-button-to-env-var[] 157 | ifndef::add-copy-button-to-env-var[] 158 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION+++` 159 | endif::add-copy-button-to-env-var[] 160 | -- 161 | |string 162 | | 163 | 164 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-configuration-inject]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-configuration-inject[`quarkus.jooq."named-config".configuration-inject`]## 165 | 166 | [.description] 167 | -- 168 | The jOOQ configuration by inject named 169 | 170 | 171 | ifdef::add-copy-button-to-env-var[] 172 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION_INJECT+++[] 173 | endif::add-copy-button-to-env-var[] 174 | ifndef::add-copy-button-to-env-var[] 175 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION_INJECT+++` 176 | endif::add-copy-button-to-env-var[] 177 | -- 178 | |string 179 | | 180 | 181 | |=== 182 | 183 | 184 | :!summaryTableId: -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/includes/quarkus-jooq_quarkus.jooq.adoc: -------------------------------------------------------------------------------- 1 | :summaryTableId: quarkus-jooq_quarkus-jooq 2 | [.configuration-legend] 3 | icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime 4 | [.configuration-reference.searchable, cols="80,.^10,.^10"] 5 | |=== 6 | 7 | h|[.header-title]##Configuration property## 8 | h|Type 9 | h|Default 10 | 11 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-dialect]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-dialect[`quarkus.jooq.dialect`]## 12 | 13 | [.description] 14 | -- 15 | The jOOQ dialect 16 | 17 | 18 | ifdef::add-copy-button-to-env-var[] 19 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_DIALECT+++[] 20 | endif::add-copy-button-to-env-var[] 21 | ifndef::add-copy-button-to-env-var[] 22 | Environment variable: `+++QUARKUS_JOOQ_DIALECT+++` 23 | endif::add-copy-button-to-env-var[] 24 | -- 25 | |string 26 | |required icon:exclamation-circle[title=Configuration property is required] 27 | 28 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-datasource]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-datasource[`quarkus.jooq.datasource`]## 29 | 30 | [.description] 31 | -- 32 | The jOOQ dataSource 33 | 34 | 35 | ifdef::add-copy-button-to-env-var[] 36 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_DATASOURCE+++[] 37 | endif::add-copy-button-to-env-var[] 38 | ifndef::add-copy-button-to-env-var[] 39 | Environment variable: `+++QUARKUS_JOOQ_DATASOURCE+++` 40 | endif::add-copy-button-to-env-var[] 41 | -- 42 | |string 43 | | 44 | 45 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-configuration]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-configuration[`quarkus.jooq.configuration`]## 46 | 47 | [.description] 48 | -- 49 | The jOOQ configuration 50 | 51 | 52 | ifdef::add-copy-button-to-env-var[] 53 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_CONFIGURATION+++[] 54 | endif::add-copy-button-to-env-var[] 55 | ifndef::add-copy-button-to-env-var[] 56 | Environment variable: `+++QUARKUS_JOOQ_CONFIGURATION+++` 57 | endif::add-copy-button-to-env-var[] 58 | -- 59 | |string 60 | | 61 | 62 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-configuration-inject]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-configuration-inject[`quarkus.jooq.configuration-inject`]## 63 | 64 | [.description] 65 | -- 66 | The jOOQ configuration by inject named 67 | 68 | 69 | ifdef::add-copy-button-to-env-var[] 70 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_CONFIGURATION_INJECT+++[] 71 | endif::add-copy-button-to-env-var[] 72 | ifndef::add-copy-button-to-env-var[] 73 | Environment variable: `+++QUARKUS_JOOQ_CONFIGURATION_INJECT+++` 74 | endif::add-copy-button-to-env-var[] 75 | -- 76 | |string 77 | | 78 | 79 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-register-generated-classes-for-reflection]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-register-generated-classes-for-reflection[`quarkus.jooq.register-generated-classes-for-reflection`]## 80 | 81 | [.description] 82 | -- 83 | Whether to automatically register jOOQ records/POJOs for reflection. 84 | 85 | 86 | ifdef::add-copy-button-to-env-var[] 87 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_REGISTER_GENERATED_CLASSES_FOR_REFLECTION+++[] 88 | endif::add-copy-button-to-env-var[] 89 | ifndef::add-copy-button-to-env-var[] 90 | Environment variable: `+++QUARKUS_JOOQ_REGISTER_GENERATED_CLASSES_FOR_REFLECTION+++` 91 | endif::add-copy-button-to-env-var[] 92 | -- 93 | |boolean 94 | |`true` 95 | 96 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-generated-classes-pattern]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-generated-classes-pattern[`quarkus.jooq.generated-classes-pattern`]## 97 | 98 | [.description] 99 | -- 100 | Regex used to determine classes to be registered for reflection. 101 | 102 | 103 | ifdef::add-copy-button-to-env-var[] 104 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ_GENERATED_CLASSES_PATTERN+++[] 105 | endif::add-copy-button-to-env-var[] 106 | ifndef::add-copy-button-to-env-var[] 107 | Environment variable: `+++QUARKUS_JOOQ_GENERATED_CLASSES_PATTERN+++` 108 | endif::add-copy-button-to-env-var[] 109 | -- 110 | |string 111 | |`.+\.tables\.(pojos\|records)\..+` 112 | 113 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-dialect]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-dialect[`quarkus.jooq."named-config".dialect`]## 114 | 115 | [.description] 116 | -- 117 | The jOOQ dialect 118 | 119 | 120 | ifdef::add-copy-button-to-env-var[] 121 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__DIALECT+++[] 122 | endif::add-copy-button-to-env-var[] 123 | ifndef::add-copy-button-to-env-var[] 124 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__DIALECT+++` 125 | endif::add-copy-button-to-env-var[] 126 | -- 127 | |string 128 | |required icon:exclamation-circle[title=Configuration property is required] 129 | 130 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-datasource]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-datasource[`quarkus.jooq."named-config".datasource`]## 131 | 132 | [.description] 133 | -- 134 | The jOOQ dataSource 135 | 136 | 137 | ifdef::add-copy-button-to-env-var[] 138 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__DATASOURCE+++[] 139 | endif::add-copy-button-to-env-var[] 140 | ifndef::add-copy-button-to-env-var[] 141 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__DATASOURCE+++` 142 | endif::add-copy-button-to-env-var[] 143 | -- 144 | |string 145 | | 146 | 147 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-configuration]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-configuration[`quarkus.jooq."named-config".configuration`]## 148 | 149 | [.description] 150 | -- 151 | The jOOQ configuration 152 | 153 | 154 | ifdef::add-copy-button-to-env-var[] 155 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION+++[] 156 | endif::add-copy-button-to-env-var[] 157 | ifndef::add-copy-button-to-env-var[] 158 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION+++` 159 | endif::add-copy-button-to-env-var[] 160 | -- 161 | |string 162 | | 163 | 164 | a|icon:lock[title=Fixed at build time] [[quarkus-jooq_quarkus-jooq-named-config-configuration-inject]] [.property-path]##link:#quarkus-jooq_quarkus-jooq-named-config-configuration-inject[`quarkus.jooq."named-config".configuration-inject`]## 165 | 166 | [.description] 167 | -- 168 | The jOOQ configuration by inject named 169 | 170 | 171 | ifdef::add-copy-button-to-env-var[] 172 | Environment variable: env_var_with_copy_button:+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION_INJECT+++[] 173 | endif::add-copy-button-to-env-var[] 174 | ifndef::add-copy-button-to-env-var[] 175 | Environment variable: `+++QUARKUS_JOOQ__NAMED_CONFIG__CONFIGURATION_INJECT+++` 176 | endif::add-copy-button-to-env-var[] 177 | -- 178 | |string 179 | | 180 | 181 | |=== 182 | 183 | 184 | :!summaryTableId: -------------------------------------------------------------------------------- /docs/modules/ROOT/pages/index.adoc: -------------------------------------------------------------------------------- 1 | = Your Quarkiverse Extension 2 | :extension-status: preview 3 | 4 | Describe what the extension does here. 5 | 6 | == Installation 7 | 8 | If you want to use this extension, you need to add the `quarkiverse-jooq` extension first. 9 | In your `pom.xml` file, add: 10 | 11 | [source,xml] 12 | ---- 13 | 14 | io.quarkiverse.jooq 15 | quarkiverse-jooq 16 | {project-version} 17 | 18 | ---- 19 | 20 | [[extension-configuration-reference]] 21 | == Extension Configuration Reference 22 | 23 | include::includes/quarkus-jooq.adoc[leveloffset=+1, opts=optional] 24 | -------------------------------------------------------------------------------- /docs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.jooq 6 | quarkus-jooq-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-jooq-docs 12 | Quarkus jOOQ - Documentation 13 | 14 | 15 | 16 | 17 | io.quarkiverse.jooq 18 | quarkus-jooq-deployment 19 | ${project.version} 20 | 21 | 22 | 23 | 24 | modules/ROOT/examples 25 | 26 | 27 | it.ozimov 28 | yaml-properties-maven-plugin 29 | 30 | 31 | initialize 32 | 33 | read-project-properties 34 | 35 | 36 | 37 | ${project.basedir}/../.github/project.yml 38 | 39 | 40 | 41 | 42 | 43 | 44 | io.quarkus 45 | quarkus-config-doc-maven-plugin 46 | true 47 | 48 | ${project.basedir}/modules/ROOT/pages/includes/ 49 | 50 | 51 | 52 | maven-resources-plugin 53 | 54 | 55 | copy-resources 56 | generate-resources 57 | 58 | copy-resources 59 | 60 | 61 | ${project.basedir}/modules/ROOT/pages/includes/ 62 | 63 | 64 | ${project.basedir}/templates/includes 65 | attributes.adoc 66 | true 67 | 68 | 69 | 70 | 71 | 72 | copy-images 73 | prepare-package 74 | 75 | copy-resources 76 | 77 | 78 | ${project.build.directory}/generated-docs/_images/ 79 | 80 | 81 | ${project.basedir}/modules/ROOT/assets/images/ 82 | false 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | org.asciidoctor 91 | asciidoctor-maven-plugin 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /docs/templates/includes/attributes.adoc: -------------------------------------------------------------------------------- 1 | :project-version: ${release.current-version} 2 | 3 | :examples-dir: ./../examples/ -------------------------------------------------------------------------------- /integration-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.quarkiverse.jooq 7 | quarkus-jooq-parent 8 | 999-SNAPSHOT 9 | 10 | quarkus-jooq-integration-tests 11 | Quarkus jOOQ - Integration Tests 12 | 13 | 14 | true 15 | 16 | 17 | 18 | 19 | io.quarkus 20 | quarkus-rest 21 | 22 | 23 | io.quarkus 24 | quarkus-jdbc-h2 25 | 26 | 27 | io.quarkiverse.jooq 28 | quarkus-jooq 29 | ${project.version} 30 | 31 | 32 | io.quarkus 33 | quarkus-junit5 34 | test 35 | 36 | 37 | io.quarkus 38 | quarkus-test-h2 39 | test 40 | 41 | 42 | io.rest-assured 43 | rest-assured 44 | test 45 | 46 | 47 | 48 | 49 | 50 | 51 | io.quarkus 52 | quarkus-maven-plugin 53 | 54 | 55 | 56 | build 57 | 58 | 59 | 60 | 61 | 62 | maven-failsafe-plugin 63 | 64 | 65 | 66 | integration-test 67 | verify 68 | 69 | 70 | 71 | 72 | 73 | ${project.build.directory}/${project.build.finalName}-runner 74 | org.jboss.logmanager.LogManager 75 | ${maven.home} 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | native-image 85 | 86 | 87 | native 88 | 89 | 90 | 91 | 92 | 93 | maven-surefire-plugin 94 | 95 | ${native.surefire.skip} 96 | 97 | 98 | 99 | 100 | 101 | false 102 | true 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/Demo.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigDecimal; 5 | import java.util.Date; 6 | 7 | import io.quarkus.runtime.annotations.RegisterForReflection; 8 | 9 | /** 10 | * 11 | * @author Leo Tu 12 | */ 13 | @SuppressWarnings("serial") 14 | @RegisterForReflection 15 | public class Demo implements Serializable { 16 | 17 | private String id; 18 | private String name; 19 | private BigDecimal amount; 20 | private Date createdAt; 21 | 22 | public String getId() { 23 | return id; 24 | } 25 | 26 | public void setId(String id) { 27 | this.id = id; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public void setName(String name) { 35 | this.name = name; 36 | } 37 | 38 | public BigDecimal getAmount() { 39 | return amount; 40 | } 41 | 42 | public void setAmount(BigDecimal amount) { 43 | this.amount = amount; 44 | } 45 | 46 | public Date getCreatedAt() { 47 | return createdAt; 48 | } 49 | 50 | public void setCreatedAt(Date createdAt) { 51 | this.createdAt = createdAt; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return super.toString() + "[id=" + id + ", name=" + name + ", amount=" + amount + ", createdAt=" + createdAt 57 | + "]"; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/JooqResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.quarkiverse.jooq.it; 18 | 19 | import java.math.BigDecimal; 20 | import java.sql.Connection; 21 | import java.sql.DatabaseMetaData; 22 | import java.sql.ResultSet; 23 | import java.sql.Statement; 24 | import java.util.Date; 25 | import java.util.List; 26 | import java.util.UUID; 27 | import java.util.concurrent.ThreadLocalRandom; 28 | 29 | import jakarta.annotation.PostConstruct; 30 | import jakarta.enterprise.context.ApplicationScoped; 31 | import jakarta.enterprise.event.Observes; 32 | import jakarta.inject.Inject; 33 | import jakarta.inject.Named; 34 | import jakarta.transaction.Transactional; 35 | import jakarta.transaction.Transactional.TxType; 36 | import jakarta.ws.rs.GET; 37 | import jakarta.ws.rs.Path; 38 | 39 | import org.jboss.logging.Logger; 40 | import org.jooq.DSLContext; 41 | import org.jooq.impl.DSL; 42 | 43 | import io.quarkus.runtime.ShutdownEvent; 44 | import io.quarkus.runtime.StartupEvent; 45 | 46 | @Path("/jooq") 47 | @ApplicationScoped 48 | public class JooqResource { 49 | 50 | private static final Logger LOGGER = Logger.getLogger(JooqResource.class); 51 | 52 | @GET 53 | public String hello() { 54 | return "Hello jooq"; 55 | } 56 | 57 | @ApplicationScoped 58 | static class TestBean { 59 | 60 | @Inject 61 | DSLContext dsl; // default 62 | 63 | @Inject 64 | @Named("dsl1") 65 | DSLContext dsl1; 66 | 67 | @Inject 68 | @Named("dsl2") 69 | DSLContext dsl2; 70 | 71 | private ServiceAction action; 72 | private ServiceAction action1; 73 | 74 | @PostConstruct 75 | void onPostConstruct() { 76 | LOGGER.debug("onPostConstruct"); 77 | } 78 | 79 | /** 80 | * Called when the runtime has started 81 | * 82 | * @param event 83 | */ 84 | void onStart(@Observes StartupEvent event) { 85 | LOGGER.debug("onStart, event=" + event); 86 | action = new ServiceAction(dsl, "name00", 10); 87 | action1 = new ServiceAction(dsl1, "name11", 15); 88 | } 89 | 90 | void onStop(@Observes ShutdownEvent event) { 91 | LOGGER.debug("onStop, event=" + event); 92 | } 93 | 94 | // https://github.com/quarkusio/quarkus/issues/2224 95 | // public void onTxSuccessEvent(@Observes(during = 96 | // TransactionPhase.AFTER_SUCCESS) String msg) { 97 | // LOGGER.debug("onTxSuccessEvent, msg=" + msg); 98 | // } 99 | // 100 | // public void onTxFailureEvent(@Observes(during = 101 | // TransactionPhase.AFTER_FAILURE) String msg) { 102 | // LOGGER.debug("onTxFailureEvent, msg=" + msg); 103 | // } 104 | // 105 | // public void onTxCompletionEvent(@Observes(during = 106 | // TransactionPhase.AFTER_COMPLETION) String msg) { 107 | // LOGGER.debug("onTxCompletionEvent, msg=" + msg); 108 | // } 109 | 110 | void testConnection() throws Exception { 111 | // (default) 112 | try (Connection conn = dsl.parsingConnection()) { 113 | DatabaseMetaData dmd = conn.getMetaData(); 114 | LOGGER.debugv("dsl, databaseProductName: {0}, databaseProductVersion: {1}", 115 | dmd.getDatabaseProductName(), dmd.getDatabaseProductVersion()); 116 | } catch (Exception e) { 117 | LOGGER.error("dsl.getConnection", e); 118 | throw e; 119 | } 120 | 121 | // (1) 122 | try (Connection conn = dsl1.parsingConnection()) { 123 | DatabaseMetaData dmd = conn.getMetaData(); 124 | LOGGER.debugv("dsl1, databaseProductName: {0}, databaseProductVersion: {1}", 125 | dmd.getDatabaseProductName(), dmd.getDatabaseProductVersion()); 126 | } catch (Exception e) { 127 | LOGGER.error("dsl1.getConnection", e); 128 | throw e; 129 | } 130 | 131 | // (2) 132 | try (Connection conn = dsl2.parsingConnection()) { 133 | DatabaseMetaData dmd = conn.getMetaData(); 134 | LOGGER.debugv("dsl2, databaseProductName: {0}, databaseProductVersion: {1}", 135 | dmd.getDatabaseProductName(), dmd.getDatabaseProductVersion()); 136 | } catch (Exception e) { 137 | LOGGER.error("dsl2.getConnection", e); 138 | throw e; 139 | } 140 | } 141 | 142 | // === (default) 143 | void testDDL() throws Exception { 144 | action.createDDL(); 145 | } 146 | 147 | @Transactional 148 | void testInsert() throws Exception { 149 | action.insertData(); 150 | } 151 | 152 | @Transactional 153 | void testUpdate() throws Exception { 154 | action.updateData(); 155 | } 156 | 157 | @Transactional(TxType.SUPPORTS) 158 | void testQuery() throws Exception { 159 | action.queryData(); 160 | } 161 | 162 | @Transactional(TxType.REQUIRED) 163 | void testDelete() throws Exception { 164 | action.deleteData(); 165 | } 166 | 167 | @Transactional(TxType.SUPPORTS) 168 | void testCount() throws Exception { 169 | action.countData(); 170 | } 171 | 172 | @Transactional(TxType.REQUIRED) 173 | void testAllService() throws Exception { 174 | action.insertData(); 175 | action.updateData(); 176 | action.queryData(); 177 | action.deleteData(); 178 | action.countData(); 179 | } 180 | 181 | @Transactional(TxType.REQUIRED) 182 | void testAll() throws Exception { 183 | testInsert(); 184 | testUpdate(); 185 | testQuery(); 186 | testDelete(); 187 | testCount(); 188 | } 189 | 190 | // === (1) 191 | void testDDL1() throws Exception { 192 | action1.createDDL(); 193 | } 194 | 195 | @Transactional 196 | void testInsert1() throws Exception { 197 | action1.insertData(); 198 | } 199 | 200 | @Transactional 201 | void testUpdate1() throws Exception { 202 | action1.updateData(); 203 | } 204 | 205 | @Transactional(TxType.SUPPORTS) 206 | void testQuery1() throws Exception { 207 | action1.queryData(); 208 | } 209 | 210 | @Transactional(TxType.REQUIRED) 211 | void testDelete1() throws Exception { 212 | action1.deleteData(); 213 | } 214 | 215 | @Transactional(TxType.SUPPORTS) 216 | void testCount1() throws Exception { 217 | action1.countData(); 218 | } 219 | 220 | @Transactional(TxType.REQUIRED) 221 | void testAllService1() throws Exception { 222 | action1.insertData(); 223 | action1.updateData(); 224 | action1.queryData(); 225 | action1.deleteData(); 226 | action1.countData(); 227 | } 228 | 229 | @Transactional(TxType.REQUIRED) 230 | void testAll1() throws Exception { 231 | testInsert1(); 232 | testUpdate1(); 233 | testQuery1(); 234 | testDelete1(); 235 | testCount1(); 236 | } 237 | 238 | } 239 | 240 | static class ServiceAction { 241 | 242 | final private DSLContext dsl; 243 | final private int loop; 244 | final private String prefix; 245 | 246 | public ServiceAction(DSLContext dsl, String prefix, int loop) { 247 | this.dsl = dsl; 248 | this.prefix = prefix; 249 | this.loop = loop; 250 | } 251 | 252 | public ServiceAction(DSLContext dsl) { 253 | this.dsl = dsl; 254 | this.prefix = null; 255 | this.loop = -1; 256 | } 257 | 258 | void createDDL() throws Exception { 259 | String table = QDemo.$.getName(); 260 | String ddl = "" + // 261 | "CREATE TABLE " + table + "(" + // 262 | " id char(32) NOT NULL," + // 263 | " name varchar(128) NOT NULL," + // 264 | " amount decimal(12,3) ," + // 265 | " created_at timestamp NOT NULL," + // 266 | " PRIMARY KEY (id)" + // 267 | ")"; 268 | 269 | try (Connection conn = dsl.parsingConnection()) { 270 | Statement stmt = conn.createStatement(); 271 | stmt.execute(ddl); 272 | stmt.close(); 273 | // listTableTypes(conn); 274 | ResultSet rs = conn.getMetaData().getTables(null, null, table.toUpperCase(), new String[] { "TABLE" }); 275 | boolean tableExists = false; 276 | while (rs.next()) { 277 | String tableType = rs.getString("TABLE_TYPE"); 278 | String tableCatalog = rs.getString("TABLE_CAT"); 279 | String tableSchema = rs.getString("TABLE_SCHEM"); 280 | String tableName = rs.getString("TABLE_NAME"); 281 | // tableType:TABLE, tableCatalog:DEFAULT, tableSchema:PUBLIC, table:demo 282 | LOGGER.debugv("tableType:{0}, tableCatalog:{1}, tableSchema:{2}, table:{3}", tableType, 283 | tableCatalog, tableSchema, table); 284 | if (table.equalsIgnoreCase(tableName)) { 285 | tableExists = true; 286 | } 287 | } 288 | 289 | LOGGER.debugv("createDDL table: {0} success: {1}", table, tableExists); 290 | rs.close(); 291 | 292 | if (!tableExists) { 293 | throw new IllegalStateException("Table does not exist"); 294 | } 295 | } 296 | } 297 | 298 | @SuppressWarnings("unused") 299 | private void listTableTypes(Connection conn) throws Exception { 300 | DatabaseMetaData dmd = conn.getMetaData(); 301 | ResultSet ttRs = dmd.getTableTypes(); 302 | int columnCount = ttRs.getMetaData().getColumnCount(); 303 | while (ttRs.next()) { 304 | for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) { 305 | String tableType = ttRs.getString(columnIndex); 306 | // tableType: "EXTERNAL","SYSTEM TABLE","TABLE","TABLE LINK","VIEW" 307 | LOGGER.debugv("tableType: {0}", tableType); 308 | } 309 | } 310 | ttRs.close(); 311 | } 312 | 313 | void insertData() throws Exception { 314 | for (int i = 0; i < loop; i++) { 315 | String id = UUID.randomUUID().toString().replaceAll("-", ""); 316 | int randomNum = ThreadLocalRandom.current().nextInt(0, 9); 317 | long row = dsl.insertInto(QDemo.$) // 318 | .set(QDemo.$.id, id) // 319 | .set(QDemo.$.name, prefix + "-" + i) // 320 | .set(QDemo.$.amount, new BigDecimal(12.1 + randomNum)) // 321 | .set(QDemo.$.createdAt, new Date()) // 322 | .execute(); 323 | LOGGER.debugv("insertData prefix: {0}, i: {1}, row: {2}", prefix, i, row); 324 | if (row != 1L) { 325 | throw new IllegalStateException("row is not equal to 1"); 326 | } 327 | } 328 | } 329 | 330 | void updateData() throws Exception { 331 | long row = dsl.update(QDemo.$) // 332 | .set(QDemo.$.name, prefix + "-" + "5U") // 333 | .set(QDemo.$.createdAt, new Date()) // 334 | .where(QDemo.$.name.eq(prefix + "-" + 5)) // 335 | .execute(); 336 | LOGGER.debugv("updateData prefix: {0}, row: {1}", prefix, row); 337 | if (row != 1L) { 338 | throw new IllegalStateException("row is not equal to 1"); 339 | } 340 | } 341 | 342 | void queryData() throws Exception { 343 | List dataList = dsl.select() // 344 | .from(QDemo.$) // 345 | .fetchInto(Demo.class); 346 | 347 | LOGGER.debugv("queryData prefix: {0}, dataList.size: {1}", prefix, dataList.size()); 348 | if (dataList.size() != loop) { 349 | throw new IllegalStateException("dataList.size() != loop"); 350 | } 351 | 352 | Demo data = dsl.select() // 353 | .from(QDemo.$) // 354 | .where(QDemo.$.name.eq(prefix + "-" + "5U")) // 355 | .fetchOneInto(Demo.class); 356 | LOGGER.debugv("queryData prefix: {0}, data: {1}", prefix, data); 357 | if (data == null) { 358 | throw new IllegalStateException("data == null"); 359 | } 360 | } 361 | 362 | void deleteData() throws Exception { 363 | LOGGER.debug("deleteData..."); 364 | long row = dsl.delete(QDemo.$) // 365 | .execute(); 366 | LOGGER.debugv("deleteData prefix: {0}, row: {1}", prefix, row); 367 | if (row != loop) { 368 | throw new IllegalStateException("row != loop"); 369 | } 370 | } 371 | 372 | void countData() throws Exception { 373 | LOGGER.debug("countData..."); 374 | long total = dsl.select(DSL.count()).from(QDemo.$).fetchOneInto(long.class); 375 | // long total = dsl.selectCount().from(QDemo.$).fetchOne(0, long.class); 376 | LOGGER.debugv("countData prefix: {0}, total: {1}", prefix, total); 377 | if (total != 0) { 378 | throw new IllegalStateException("total != 0"); 379 | } 380 | } 381 | } 382 | } 383 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/Keys.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import org.jooq.UniqueKey; 4 | import org.jooq.impl.DSL; 5 | import org.jooq.impl.Internal; 6 | 7 | /** 8 | * A class modelling foreign key relationships and constraints of tables of the 9 | * schema. 10 | */ 11 | @SuppressWarnings({ "all", "unchecked", "rawtypes" }) 12 | public class Keys { 13 | 14 | // ------------------------------------------------------------------------- 15 | // IDENTITY definitions 16 | // ------------------------------------------------------------------------- 17 | 18 | // ------------------------------------------------------------------------- 19 | // UNIQUE and PRIMARY KEY definitions 20 | // ------------------------------------------------------------------------- 21 | 22 | public static final UniqueKey DEMO_PKEY = UniqueKeys0.DEMO_PKEY; 23 | 24 | // ------------------------------------------------------------------------- 25 | // FOREIGN KEY definitions 26 | // ------------------------------------------------------------------------- 27 | 28 | // ------------------------------------------------------------------------- 29 | // [#1459] distribute members to avoid static initialisers > 64kb 30 | // ------------------------------------------------------------------------- 31 | 32 | private static class UniqueKeys0 { 33 | 34 | public static final UniqueKey DEMO_PKEY = Internal.createUniqueKey(QDemo.$, DSL.name("demo_pkey"), QDemo.$.id); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/MyCustomConfiguration1.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import io.quarkiverse.jooq.runtime.JooqCustomContext; 4 | 5 | /** 6 | * 7 | * @author Leo Tu 8 | */ 9 | public class MyCustomConfiguration1 implements JooqCustomContext { 10 | } 11 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/MyCustomConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import jakarta.annotation.PostConstruct; 4 | import jakarta.enterprise.context.ApplicationScoped; 5 | import jakarta.enterprise.inject.Produces; 6 | import jakarta.inject.Named; 7 | import jakarta.inject.Singleton; 8 | 9 | import org.jboss.logging.Logger; 10 | 11 | import io.quarkiverse.jooq.runtime.JooqCustomContext; 12 | 13 | /** 14 | * 15 | * @author Leo Tu 16 | */ 17 | //@ApplicationScoped 18 | @Singleton 19 | public class MyCustomConfigurationFactory { 20 | private static final Logger LOGGER = Logger.getLogger(MyCustomConfigurationFactory.class); 21 | 22 | @PostConstruct 23 | void onPostConstruct() { 24 | LOGGER.debug("MyCustomConfigurationFactory: onPostConstruct"); 25 | } 26 | 27 | @ApplicationScoped 28 | @Produces 29 | @Named("myCustomConfiguration2") 30 | public JooqCustomContext create() { 31 | LOGGER.debug("MyCustomConfigurationFactory: create"); 32 | return new JooqCustomContext() { 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/Public.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import org.jooq.impl.SchemaImpl; 4 | 5 | @SuppressWarnings({ "all", "unchecked", "rawtypes" }) 6 | public class Public extends SchemaImpl { 7 | 8 | /** 9 | * The reference instance of PUBLIC 10 | */ 11 | public static final Public PUBLIC = new Public(); 12 | 13 | /** 14 | * The table PUBLIC.BOOK. 15 | */ 16 | public final QDemo DEMO = QDemo.$; 17 | 18 | /** 19 | * No further instances allowed 20 | */ 21 | private Public() { 22 | super("PUBLIC", null); 23 | } 24 | 25 | // /** 26 | // * {@inheritDoc} 27 | // */ 28 | // @Override 29 | // public Catalog getCatalog() { 30 | // return DefaultCatalog.DEFAULT_CATALOG; 31 | // } 32 | // 33 | // @Override 34 | // public final List> getTables() { 35 | // List result = new ArrayList(); 36 | // result.addAll(getTables0()); 37 | // return result; 38 | // } 39 | // 40 | // private final List> getTables0() { 41 | // return Arrays.>asList( 42 | // Author.AUTHOR, 43 | // Book.BOOK, 44 | // BookStore.BOOK_STORE, 45 | // BookToBookStore.BOOK_TO_BOOK_STORE); 46 | // } 47 | } 48 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/QDemo.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Arrays; 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | import org.jooq.Field; 9 | import org.jooq.Name; 10 | import org.jooq.Schema; 11 | import org.jooq.Table; 12 | import org.jooq.TableField; 13 | import org.jooq.UniqueKey; 14 | import org.jooq.impl.DSL; 15 | import org.jooq.impl.SQLDataType; 16 | import org.jooq.impl.TableImpl; 17 | 18 | import io.quarkiverse.jooq.runtime.SQLDataTypeExt; 19 | 20 | /** 21 | * 22 | * @author Leo Tu 23 | */ 24 | @SuppressWarnings("serial") 25 | public class QDemo extends TableImpl { 26 | 27 | public static final QDemo $ = new QDemo(); 28 | 29 | /** 30 | * The class holding records for this type 31 | */ 32 | @Override 33 | public Class getRecordType() { 34 | return RDemo.class; 35 | } 36 | 37 | public final TableField id = createField(DSL.name("id"), SQLDataType.CHAR(22).nullable(false).identity(true), 38 | this, 39 | "The PK"); 40 | public final TableField name = createField(DSL.name("name"), SQLDataType.VARCHAR(128).nullable(false), this, 41 | "The Name"); 42 | public final TableField amount = createField(DSL.name("amount"), SQLDataType.NUMERIC(12, 3), this, 43 | "Amount Value"); 44 | public final TableField createdAt = createField(DSL.name("created_at"), 45 | SQLDataTypeExt.UTILDATE.nullable(false), 46 | this, "Created At"); 47 | 48 | public QDemo() { 49 | this(DSL.name("demo"), null); 50 | } 51 | 52 | public QDemo(String alias) { 53 | this(DSL.name(alias), $); 54 | } 55 | 56 | private QDemo(Name alias, Table aliased) { 57 | this(alias, aliased, null); 58 | } 59 | 60 | private QDemo(Name alias, Table aliased, Field[] parameters) { 61 | super(alias, null, aliased, parameters, DSL.comment("Demo Table")); 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | public Schema getSchema() { 69 | return Public.PUBLIC; 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | public UniqueKey getPrimaryKey() { 77 | return Keys.DEMO_PKEY; 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | */ 83 | @Override 84 | public List> getKeys() { 85 | return Arrays.> asList(Keys.DEMO_PKEY); 86 | } 87 | 88 | /** 89 | * {@inheritDoc} 90 | */ 91 | @Override 92 | public QDemo as(String alias) { 93 | return new QDemo(DSL.name(alias), this); 94 | } 95 | 96 | /** 97 | * {@inheritDoc} 98 | */ 99 | @Override 100 | public QDemo as(Name alias) { 101 | return new QDemo(alias, this); 102 | } 103 | 104 | /** 105 | * Rename this table 106 | */ 107 | @Override 108 | public QDemo rename(String name) { 109 | return new QDemo(DSL.name(name), null); 110 | } 111 | 112 | /** 113 | * Rename this table 114 | */ 115 | @Override 116 | public QDemo rename(Name name) { 117 | return new QDemo(name, null); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /integration-tests/src/main/java/io/quarkiverse/jooq/it/RDemo.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Date; 5 | 6 | import org.jooq.impl.UpdatableRecordImpl; 7 | 8 | import io.quarkus.runtime.annotations.RegisterForReflection; 9 | 10 | /** 11 | * 12 | * @author Leo Tu 13 | */ 14 | @SuppressWarnings("serial") 15 | @RegisterForReflection 16 | public class RDemo extends UpdatableRecordImpl { 17 | 18 | private String id; 19 | private String name; 20 | private BigDecimal amount; 21 | private Date createdAt; 22 | 23 | /** 24 | * Create a detached RCompany 25 | */ 26 | public RDemo() { 27 | super(QDemo.$); 28 | } 29 | 30 | public String getId() { 31 | return (String) get(0); 32 | } 33 | 34 | public RDemo setId(String id) { 35 | set(0, id); 36 | return this; 37 | } 38 | 39 | public String getName() { 40 | return (String) get(1); 41 | } 42 | 43 | public RDemo setName(String name) { 44 | set(1, name); 45 | return this; 46 | } 47 | 48 | public BigDecimal getAmount() { 49 | return (BigDecimal) get(2); 50 | } 51 | 52 | public RDemo setAmount(BigDecimal amount) { 53 | set(2, amount); 54 | return this; 55 | } 56 | 57 | public Date getCreatedAt() { 58 | return (Date) get(3); 59 | } 60 | 61 | public RDemo setCreatedAt(Date createdAt) { 62 | set(3, createdAt); 63 | return this; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return super.toString() + "[id=" + id + ", name=" + name + ", amount=" + amount + ", createdAt=" + createdAt 69 | + "]"; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /integration-tests/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # https://quarkus.io/guides/logging-guide 2 | 3 | quarkus.log.level = INFO 4 | quarkus.log.file.enable=false 5 | 6 | quarkus.log.console.enable = true 7 | #quarkus.log.console.format = %d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n 8 | quarkus.log.console.format = %d{HH:mm:ss.SSS} %-5p [%t] [%C:%L,%M\(\)] %s%e%n 9 | quarkus.log.console.level = DEBUG 10 | quarkus.log.console.color = false 11 | 12 | quarkus.log.category."io.quarkiverse.jooq".level = DEBUG 13 | quarkus.log.category."io.quarkiverse.jooq.sql".level = DEBUG 14 | #quarkus.log.category."io.quarkus.agroal.runtime".level = DEBUG 15 | 16 | # default datasource 17 | quarkus.jooq.dialect=H2 18 | quarkus.jooq.configuration-inject=myCustomConfiguration2 19 | 20 | quarkus.jooq.dsl1.dialect=H2 21 | quarkus.jooq.dsl1.datasource=datasource1 22 | quarkus.jooq.dsl1.configuration=io.quarkiverse.jooq.MyCustomConfiguration1 23 | 24 | quarkus.jooq.dsl2.dialect=H2 25 | quarkus.jooq.dsl2.datasource=datasource2 26 | quarkus.jooq.dsl2.configuration-inject=myCustomConfiguration2 27 | 28 | # 29 | quarkus.datasource.db-kind=h2 30 | quarkus.datasource.username=username-default 31 | quarkus.datasource.password=username-default 32 | quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:default;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE; 33 | quarkus.datasource.jdbc.min-size=1 34 | quarkus.datasource.jdbc.max-size=2 35 | 36 | quarkus.datasource.datasource1.db-kind=h2 37 | quarkus.datasource.datasource1.username=username1 38 | quarkus.datasource.datasource1.password=username1 39 | quarkus.datasource.datasource1.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:datasource1;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE; 40 | quarkus.datasource.datasource1.jdbc.min-size=1 41 | quarkus.datasource.datasource1.jdbc.max-size=2 42 | 43 | quarkus.datasource.datasource2.db-kind=h2 44 | quarkus.datasource.datasource2.username=username2 45 | quarkus.datasource.datasource2.password=username2 46 | quarkus.datasource.datasource2.jdbc.url=jdbc:h2:tcp://localhost:19092/mem:datasource2;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE; 47 | quarkus.datasource.datasource2.jdbc.min-size=1 48 | quarkus.datasource.datasource2.jdbc.max-size=2 -------------------------------------------------------------------------------- /integration-tests/src/test/java/io/quarkiverse/jooq/it/JooqResourceIT.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import io.quarkus.test.junit.QuarkusIntegrationTest; 4 | 5 | @QuarkusIntegrationTest 6 | public class JooqResourceIT extends JooqResourceTest { 7 | } 8 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/io/quarkiverse/jooq/it/JooqResourceTest.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.it; 2 | 3 | import static io.restassured.RestAssured.given; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | import io.quarkus.test.common.WithTestResource; 8 | import io.quarkus.test.h2.H2DatabaseTestResource; 9 | import io.quarkus.test.junit.QuarkusTest; 10 | 11 | @QuarkusTest 12 | @WithTestResource(H2DatabaseTestResource.class) 13 | public class JooqResourceTest { 14 | 15 | @Test 16 | public void testHelloEndpoint() { 17 | given() 18 | .when().get("/jooq") 19 | .then() 20 | .statusCode(200); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.quarkiverse 7 | quarkiverse-parent 8 | 20 9 | 10 | 11 | io.quarkiverse.jooq 12 | quarkus-jooq-parent 13 | 999-SNAPSHOT 14 | Quarkus jOOQ - Parent 15 | 16 | pom 17 | 18 | 19 | 3.14.0 20 | true 21 | 17 22 | 17 23 | UTF-8 24 | UTF-8 25 | 26 | 3.15.3 27 | 3.20.3 28 | 29 | 30 | 31 | https://github.com/quarkiverse/quarkus-jooq 32 | scm:git:https://github.com/quarkiverse/quarkus-jooq.git 33 | scm:git:git@github.com/quarkiverse/quarkus-jooq.git 34 | HEAD 35 | 36 | 37 | 38 | 39 | angrymango 40 | Tim King 41 | 42 | 43 | 44 | 45 | GitHub 46 | https://github.com/quarkiverse/quarkus-jooq/issues 47 | 48 | 49 | 50 | 51 | The Apache License, Version 2.0 52 | http://www.apache.org/licenses/LICENSE-2.0.txt 53 | repo 54 | 55 | 56 | 57 | 58 | deployment 59 | runtime 60 | 61 | 62 | 63 | 64 | 65 | io.quarkus 66 | quarkus-bom 67 | ${quarkus.version} 68 | pom 69 | import 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | io.quarkus 79 | quarkus-maven-plugin 80 | ${quarkus.version} 81 | 82 | 83 | io.quarkus 84 | quarkus-extension-maven-plugin 85 | ${quarkus.version} 86 | 87 | 88 | io.quarkus 89 | quarkus-config-doc-maven-plugin 90 | ${quarkus.version} 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | docs 99 | 100 | 101 | performRelease 102 | !true 103 | 104 | 105 | 106 | docs 107 | 108 | 109 | 110 | 111 | it 112 | 113 | 114 | performRelease 115 | !true 116 | 117 | 118 | 119 | integration-tests 120 | 121 | 122 | 123 | 124 | jooq-pro 125 | 126 | 127 | jooq-pro 128 | true 129 | 130 | 131 | 132 | 133 | 134 | maven-enforcer-plugin 135 | 136 | true 137 | 138 | 139 | 140 | 141 | 142 | 143 | quarkus-jooq-pro 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /quarkus-jooq-pro/deployment/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.quarkiverse.jooq.pro 8 | quarkus-jooq-parent 9 | 999-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | quarkus-jooq-deployment 14 | Quarkus jOOQ Pro - Deployment 15 | 16 | 17 | 18 | io.quarkus 19 | quarkus-agroal-deployment 20 | 21 | 22 | 23 | io.quarkiverse.jooq 24 | quarkus-jooq 25 | ${project.version} 26 | 27 | 28 | io.quarkiverse.jooq.pro 29 | quarkus-jooq 30 | ${project.version} 31 | 32 | 33 | io.quarkiverse.jooq 34 | quarkus-jooq-deployment 35 | ${project.version} 36 | 37 | 38 | -------------------------------------------------------------------------------- /quarkus-jooq-pro/deployment/src/main/java/io/quarkiverse/jooq/pro/deployment/JooqProProcessor.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.pro.deployment; 2 | 3 | import java.util.List; 4 | 5 | import org.jboss.logging.Logger; 6 | import org.jooq.tools.LoggerListener; 7 | 8 | import io.quarkiverse.jooq.deployment.JooqProcessor; 9 | import io.quarkiverse.jooq.pro.runtime.AbstractDslContextProducer; 10 | import io.quarkiverse.jooq.runtime.JooqConfig; 11 | import io.quarkiverse.jooq.runtime.JooqRecorder; 12 | import io.quarkus.agroal.spi.JdbcDataSourceBuildItem; 13 | import io.quarkus.arc.deployment.GeneratedBeanBuildItem; 14 | import io.quarkus.arc.deployment.UnremovableBeanBuildItem; 15 | import io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig; 16 | import io.quarkus.deployment.annotations.BuildProducer; 17 | import io.quarkus.deployment.annotations.BuildStep; 18 | import io.quarkus.deployment.annotations.ExecutionTime; 19 | import io.quarkus.deployment.annotations.Record; 20 | import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; 21 | import io.quarkus.deployment.recording.RecorderContext; 22 | 23 | class JooqProProcessor extends JooqProcessor { 24 | 25 | private static final Logger log = Logger.getLogger(JooqProProcessor.class); 26 | 27 | @SuppressWarnings("unchecked") 28 | @Record(ExecutionTime.STATIC_INIT) 29 | @BuildStep 30 | @Override 31 | protected void build(RecorderContext recorder, JooqRecorder template, 32 | BuildProducer reflectiveClass, 33 | BuildProducer unremovableBeans, 34 | JooqConfig jooqConfig, 35 | BuildProducer generatedBean, 36 | DataSourcesBuildTimeConfig dataSourceConfig, 37 | List jdbcDataSourcesBuildItem) { 38 | if (isUnconfigured(jooqConfig)) { 39 | return; 40 | } 41 | 42 | reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, AbstractDslContextProducer.class)); 43 | reflectiveClass.produce(new ReflectiveClassBuildItem(false, true, LoggerListener.class)); 44 | 45 | if (!isPresentDialect(jooqConfig.defaultConfig())) { 46 | log.warn("No default sql-dialect been defined"); 47 | } 48 | 49 | createDslContextProducerBean(generatedBean, unremovableBeans, jooqConfig, dataSourceConfig, jdbcDataSourcesBuildItem, 50 | AbstractDslContextProducer.class); 51 | } 52 | } -------------------------------------------------------------------------------- /quarkus-jooq-pro/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.quarkiverse.jooq 9 | quarkus-jooq-parent 10 | 999-SNAPSHOT 11 | ../pom.xml 12 | 13 | 14 | io.quarkiverse.jooq.pro 15 | quarkus-jooq-parent 16 | Quarkus jOOQ Pro - Parent 17 | 18 | pom 19 | 20 | 21 | deployment 22 | runtime 23 | 24 | 25 | 26 | org.jooq.pro-java-17 27 | 28 | 29 | -------------------------------------------------------------------------------- /quarkus-jooq-pro/runtime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.quarkiverse.jooq.pro 8 | quarkus-jooq-parent 9 | 999-SNAPSHOT 10 | ../pom.xml 11 | 12 | 13 | quarkus-jooq 14 | Quarkus jOOQ Pro - Runtime 15 | 16 | 17 | 18 | io.quarkus 19 | quarkus-agroal 20 | 21 | 22 | io.quarkus 23 | quarkus-narayana-jta 24 | 25 | 26 | io.quarkus 27 | quarkus-arc 28 | 29 | 30 | org.graalvm.sdk 31 | graal-sdk 32 | 33 | 34 | 35 | 36 | ${jooq.groupId} 37 | jooq 38 | ${org.jooq.version} 39 | 40 | 41 | 42 | io.quarkiverse.jooq 43 | quarkus-jooq 44 | ${project.version} 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /quarkus-jooq-pro/runtime/src/main/java/io/quarkiverse/jooq/pro/runtime/AbstractDslContextProducer.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.pro.runtime; 2 | 3 | import java.util.Objects; 4 | 5 | import org.jboss.logging.Logger; 6 | import org.jooq.DSLContext; 7 | 8 | import io.agroal.api.AgroalDataSource; 9 | import io.quarkiverse.jooq.runtime.JooqCustomContext; 10 | 11 | /** 12 | * Produces DSLContext 13 | * 14 | * @author Tim King 15 | */ 16 | public abstract class AbstractDslContextProducer { 17 | private static final Logger log = Logger.getLogger(AbstractDslContextProducer.class); 18 | 19 | public DSLContext createDslContext(String sqlDialect, AgroalDataSource dataSource, String customConfiguration) { 20 | Objects.requireNonNull(sqlDialect, "sqlDialect"); 21 | Objects.requireNonNull(dataSource, "dataSource"); 22 | 23 | if (customConfiguration == null || customConfiguration.isEmpty()) { 24 | return createDslContext(sqlDialect, dataSource, new JooqCustomContext() { 25 | }); 26 | } else { 27 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 28 | if (cl == null) 29 | cl = JooqCustomContext.class.getClassLoader(); 30 | try { 31 | Class clazz = cl.loadClass(customConfiguration); 32 | JooqCustomContext instance = (JooqCustomContext) clazz.getDeclaredConstructor().newInstance(); 33 | return createDslContext(sqlDialect, dataSource, instance); 34 | } catch (Exception e) { 35 | log.error(customConfiguration, e); 36 | throw new RuntimeException(e); 37 | } 38 | } 39 | } 40 | 41 | public DSLContext createDslContext(String sqlDialect, AgroalDataSource dataSource, JooqCustomContext customConfiguration) { 42 | Objects.requireNonNull(sqlDialect, "sqlDialect"); 43 | Objects.requireNonNull(dataSource, "dataSource"); 44 | Objects.requireNonNull(customConfiguration, "customConfiguration"); 45 | return DslContextFactory.create(sqlDialect, dataSource, customConfiguration); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /quarkus-jooq-pro/runtime/src/main/java/io/quarkiverse/jooq/pro/runtime/DslContextFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.pro.runtime; 2 | 3 | import org.jboss.logging.Logger; 4 | import org.jooq.DSLContext; 5 | import org.jooq.SQLDialect; 6 | import org.jooq.impl.DSL; 7 | 8 | import io.agroal.api.AgroalDataSource; 9 | import io.quarkiverse.jooq.runtime.JooqCustomContext; 10 | 11 | public class DslContextFactory { 12 | private static final Logger log = Logger.getLogger(DslContextFactory.class); 13 | 14 | static { 15 | System.setProperty("org.jooq.no-logo", String.valueOf(true)); 16 | } 17 | 18 | static public DSLContext create(String sqlDialect, AgroalDataSource ds, JooqCustomContext customContext) { 19 | DSLContext context; 20 | if ("PostgreSQL".equalsIgnoreCase(sqlDialect) || "Postgres".equalsIgnoreCase(sqlDialect)) { 21 | context = DSL.using(ds, SQLDialect.POSTGRES); 22 | } else if ("PostgreSQL12".equalsIgnoreCase(sqlDialect) || "Postgres12".equalsIgnoreCase(sqlDialect)) { 23 | context = DSL.using(ds, SQLDialect.POSTGRES_12); 24 | } else if ("PostgreSQL11".equalsIgnoreCase(sqlDialect) || "Postgres11".equalsIgnoreCase(sqlDialect)) { 25 | context = DSL.using(ds, SQLDialect.POSTGRES_11); 26 | } else if ("PostgreSQL10".equalsIgnoreCase(sqlDialect) || "Postgres10".equalsIgnoreCase(sqlDialect)) { 27 | context = DSL.using(ds, SQLDialect.POSTGRES_10); 28 | } else if ("PostgreSQL93".equalsIgnoreCase(sqlDialect) || "Postgres93".equalsIgnoreCase(sqlDialect) 29 | || "PostgreSQL9.3".equalsIgnoreCase(sqlDialect) || "Postgres9.3".equalsIgnoreCase(sqlDialect)) { 30 | context = DSL.using(ds, SQLDialect.POSTGRES_9_3); 31 | } else if ("PostgreSQL94".equalsIgnoreCase(sqlDialect) || "Postgres94".equalsIgnoreCase(sqlDialect) 32 | || "PostgreSQL9.4".equalsIgnoreCase(sqlDialect) || "Postgres9.4".equalsIgnoreCase(sqlDialect)) { 33 | context = DSL.using(ds, SQLDialect.POSTGRES_9_4); 34 | } else if ("PostgreSQL95".equalsIgnoreCase(sqlDialect) || "Postgres95".equalsIgnoreCase(sqlDialect) 35 | || "PostgreSQL9.5".equalsIgnoreCase(sqlDialect) || "Postgres9.5".equalsIgnoreCase(sqlDialect)) { 36 | context = DSL.using(ds, SQLDialect.POSTGRES_9_5); 37 | } else if ("MySQL".equalsIgnoreCase(sqlDialect)) { 38 | context = DSL.using(ds, SQLDialect.MYSQL); 39 | } else if ("MySQL57".equalsIgnoreCase(sqlDialect) || "MySQL5.7".equalsIgnoreCase(sqlDialect)) { 40 | context = DSL.using(ds, SQLDialect.MYSQL_5_7); 41 | } else if ("MySQL80".equalsIgnoreCase(sqlDialect) || "MySQL8.0".equalsIgnoreCase(sqlDialect) 42 | || "MySQL8".equalsIgnoreCase(sqlDialect)) { 43 | context = DSL.using(ds, SQLDialect.MYSQL_8_0); 44 | } else if ("MySQL8019".equalsIgnoreCase(sqlDialect) || "MySQL8.0.19".equalsIgnoreCase(sqlDialect)) { 45 | context = DSL.using(ds, SQLDialect.MYSQL_8_0_19); 46 | } else if ("MARIADB".equalsIgnoreCase(sqlDialect)) { 47 | context = DSL.using(ds, SQLDialect.MARIADB); 48 | } else if ("MARIADB10".equalsIgnoreCase(sqlDialect) || "MARIADB10.0".equalsIgnoreCase(sqlDialect)) { 49 | context = DSL.using(ds, SQLDialect.MARIADB); 50 | } else if ("MARIADB10.1".equalsIgnoreCase(sqlDialect)) { 51 | context = DSL.using(ds, SQLDialect.MARIADB_10_1); 52 | } else if ("MARIADB10.2".equalsIgnoreCase(sqlDialect)) { 53 | context = DSL.using(ds, SQLDialect.MARIADB_10_2); 54 | } else if ("MARIADB10.3".equalsIgnoreCase(sqlDialect)) { 55 | context = DSL.using(ds, SQLDialect.MARIADB_10_3); 56 | } else if ("MARIADB10.4".equalsIgnoreCase(sqlDialect)) { 57 | context = DSL.using(ds, SQLDialect.MARIADB_10_4); 58 | } else if ("MARIADB10.5".equalsIgnoreCase(sqlDialect)) { 59 | context = DSL.using(ds, SQLDialect.MARIADB_10_5); 60 | } else if ("Oracle".equalsIgnoreCase(sqlDialect)) { 61 | context = DSL.using(ds, SQLDialect.DEFAULT); 62 | } else if ("ORACLE10G".equalsIgnoreCase(sqlDialect)) { 63 | context = DSL.using(ds, SQLDialect.ORACLE10G); 64 | } else if ("ORACLE11G".equalsIgnoreCase(sqlDialect)) { 65 | context = DSL.using(ds, SQLDialect.ORACLE11G); 66 | } else if ("ORACLE12C".equalsIgnoreCase(sqlDialect)) { 67 | context = DSL.using(ds, SQLDialect.ORACLE12C); 68 | } else if ("ORACLE18C".equalsIgnoreCase(sqlDialect)) { 69 | context = DSL.using(ds, SQLDialect.ORACLE18C); 70 | } else if ("ORACLE20C".equalsIgnoreCase(sqlDialect)) { 71 | context = DSL.using(ds, SQLDialect.ORACLE20C); 72 | } else if ("SQLServer".equalsIgnoreCase(sqlDialect)) { 73 | context = DSL.using(ds, SQLDialect.DEFAULT); 74 | } else if ("SQLSERVER2008".equalsIgnoreCase(sqlDialect)) { 75 | context = DSL.using(ds, SQLDialect.SQLSERVER2008); 76 | } else if ("SQLSERVER2012".equalsIgnoreCase(sqlDialect)) { 77 | context = DSL.using(ds, SQLDialect.SQLSERVER2012); 78 | } else if ("SQLSERVER2014".equalsIgnoreCase(sqlDialect)) { 79 | context = DSL.using(ds, SQLDialect.SQLSERVER2014); 80 | } else if ("SQLSERVER2016".equalsIgnoreCase(sqlDialect)) { 81 | context = DSL.using(ds, SQLDialect.SQLSERVER2016); 82 | } else if ("SQLSERVER2017".equalsIgnoreCase(sqlDialect)) { 83 | context = DSL.using(ds, SQLDialect.SQLSERVER2017); 84 | } else if ("Derby".equalsIgnoreCase(sqlDialect)) { 85 | context = DSL.using(ds, SQLDialect.DERBY); 86 | } else if ("HSQLDB".equalsIgnoreCase(sqlDialect)) { 87 | context = DSL.using(ds, SQLDialect.HSQLDB); 88 | } else if ("H2".equalsIgnoreCase(sqlDialect)) { 89 | context = DSL.using(ds, SQLDialect.H2); 90 | } else if ("Firebird".equalsIgnoreCase(sqlDialect)) { 91 | context = DSL.using(ds, SQLDialect.FIREBIRD); 92 | } else if ("Firebird25".equalsIgnoreCase(sqlDialect) || "Firebird2.5".equalsIgnoreCase(sqlDialect)) { 93 | context = DSL.using(ds, SQLDialect.FIREBIRD_2_5); 94 | } else if ("Firebird30".equalsIgnoreCase(sqlDialect) || "Firebird3.0".equalsIgnoreCase(sqlDialect) 95 | || "Firebird3".equalsIgnoreCase(sqlDialect)) { 96 | context = DSL.using(ds, SQLDialect.FIREBIRD_3_0); 97 | } else if ("SQLite".equalsIgnoreCase(sqlDialect)) { 98 | context = DSL.using(ds, SQLDialect.SQLITE); 99 | } else if ("SQLite325".equalsIgnoreCase(sqlDialect) || "SQLite3.25".equalsIgnoreCase(sqlDialect)) { 100 | context = DSL.using(ds, SQLDialect.SQLITE_3_25); 101 | } else if ("SQLite328".equalsIgnoreCase(sqlDialect) || "SQLite3.28".equalsIgnoreCase(sqlDialect)) { 102 | context = DSL.using(ds, SQLDialect.SQLITE_3_28); 103 | } else if ("SQLite330".equalsIgnoreCase(sqlDialect) || "SQLite3.30".equalsIgnoreCase(sqlDialect)) { 104 | context = DSL.using(ds, SQLDialect.SQLITE_3_30); 105 | } else if ("ACCESS".equalsIgnoreCase(sqlDialect)) { 106 | context = DSL.using(ds, SQLDialect.ACCESS); 107 | } else if ("ACCESS2013".equalsIgnoreCase(sqlDialect)) { 108 | context = DSL.using(ds, SQLDialect.ACCESS2013); 109 | } else if ("ASE".equalsIgnoreCase(sqlDialect)) { 110 | context = DSL.using(ds, SQLDialect.ASE); 111 | } else if ("ASE125".equalsIgnoreCase(sqlDialect) || "ASE12.5".equalsIgnoreCase(sqlDialect)) { 112 | context = DSL.using(ds, SQLDialect.ASE_12_5); 113 | } else if ("ASE155".equalsIgnoreCase(sqlDialect) || "ASE15.5".equalsIgnoreCase(sqlDialect)) { 114 | context = DSL.using(ds, SQLDialect.ASE_15_5); 115 | } else if ("ASE157".equalsIgnoreCase(sqlDialect) || "ASE15.7".equalsIgnoreCase(sqlDialect)) { 116 | context = DSL.using(ds, SQLDialect.ASE_15_7); 117 | } else if ("ASE160".equalsIgnoreCase(sqlDialect) || "ASE16.0".equalsIgnoreCase(sqlDialect)) { 118 | context = DSL.using(ds, SQLDialect.ASE_16_0); 119 | } else if ("AURORAMYSQL".equalsIgnoreCase(sqlDialect)) { 120 | context = DSL.using(ds, SQLDialect.AURORA_MYSQL); 121 | } else if ("AURORAPOSTGRES".equalsIgnoreCase(sqlDialect)) { 122 | context = DSL.using(ds, SQLDialect.AURORA_POSTGRES); 123 | } else if ("COCKROACHDB".equalsIgnoreCase(sqlDialect)) { 124 | context = DSL.using(ds, SQLDialect.COCKROACHDB); 125 | } else if ("DB2".equalsIgnoreCase(sqlDialect)) { 126 | context = DSL.using(ds, SQLDialect.DB2); 127 | } else if ("DB29".equalsIgnoreCase(sqlDialect)) { 128 | context = DSL.using(ds, SQLDialect.DB2_9); 129 | } else if ("DB210".equalsIgnoreCase(sqlDialect)) { 130 | context = DSL.using(ds, SQLDialect.DB2_10); 131 | } else if ("DB211".equalsIgnoreCase(sqlDialect)) { 132 | context = DSL.using(ds, SQLDialect.DB2_11); 133 | } else if ("HANA".equalsIgnoreCase(sqlDialect)) { 134 | context = DSL.using(ds, SQLDialect.HANA); 135 | } else if ("INFORMIX".equalsIgnoreCase(sqlDialect)) { 136 | context = DSL.using(ds, SQLDialect.INFORMIX); 137 | } else if ("INGRES".equalsIgnoreCase(sqlDialect)) { 138 | context = DSL.using(ds, SQLDialect.INGRES); 139 | } else if ("MEMSQL".equalsIgnoreCase(sqlDialect)) { 140 | context = DSL.using(ds, SQLDialect.MEMSQL); 141 | } else if ("REDSHIFT".equalsIgnoreCase(sqlDialect)) { 142 | context = DSL.using(ds, SQLDialect.REDSHIFT); 143 | } else if ("SQLDATAWAREHOUSE".equalsIgnoreCase(sqlDialect)) { 144 | context = DSL.using(ds, SQLDialect.SQLDATAWAREHOUSE); 145 | } else if ("SYBASE".equalsIgnoreCase(sqlDialect)) { 146 | context = DSL.using(ds, SQLDialect.SYBASE); 147 | } else if ("TERADATA".equalsIgnoreCase(sqlDialect)) { 148 | context = DSL.using(ds, SQLDialect.TERADATA); 149 | } else if ("VERTICA".equalsIgnoreCase(sqlDialect)) { 150 | context = DSL.using(ds, SQLDialect.VERTICA); 151 | } else { 152 | log.warnv("Undefined sqlDialect: {0}", sqlDialect); 153 | context = DSL.using(ds, SQLDialect.DEFAULT); 154 | } 155 | customContext.apply(context.configuration()); 156 | return context; 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /runtime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.quarkiverse.jooq 6 | quarkus-jooq-parent 7 | 999-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | quarkus-jooq 12 | Quarkus jOOQ - Runtime 13 | Enables you to develop type safe SQL queries using jOOQ 14 | 15 | 16 | 17 | io.quarkus 18 | quarkus-agroal 19 | 20 | 21 | io.quarkus 22 | quarkus-narayana-jta 23 | 24 | 25 | io.quarkus 26 | quarkus-arc 27 | 28 | 29 | jakarta.persistence 30 | jakarta.persistence-api 31 | 32 | 33 | org.graalvm.sdk 34 | nativeimage 35 | 36 | 37 | 38 | 39 | org.jooq 40 | jooq 41 | ${org.jooq.version} 42 | 43 | 44 | 45 | 46 | 47 | 48 | io.quarkus 49 | quarkus-extension-maven-plugin 50 | 51 | 52 | 53 | extension-descriptor 54 | 55 | compile 56 | 57 | ${project.groupId}:${project.artifactId}-deployment:${project.version} 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-compiler-plugin 66 | 67 | 68 | 69 | io.quarkus 70 | quarkus-extension-processor 71 | ${quarkus.version} 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/AbstractDslContextProducer.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import java.lang.annotation.*; 4 | import java.util.Objects; 5 | 6 | import jakarta.inject.Qualifier; 7 | 8 | import org.jboss.logging.Logger; 9 | import org.jooq.DSLContext; 10 | 11 | import io.agroal.api.AgroalDataSource; 12 | 13 | /** 14 | * Produces DSLContext 15 | * 16 | * @author Leo Tu 17 | */ 18 | public abstract class AbstractDslContextProducer { 19 | private static final Logger log = Logger.getLogger(AbstractDslContextProducer.class); 20 | 21 | public DSLContext createDslContext(String sqlDialect, AgroalDataSource dataSource, String customConfiguration) { 22 | Objects.requireNonNull(sqlDialect, "sqlDialect"); 23 | Objects.requireNonNull(dataSource, "dataSource"); 24 | 25 | if (customConfiguration == null || customConfiguration.isEmpty()) { 26 | return createDslContext(sqlDialect, dataSource, new JooqCustomContext() { 27 | }); 28 | } else { 29 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 30 | if (cl == null) 31 | cl = JooqCustomContext.class.getClassLoader(); 32 | try { 33 | Class clazz = cl.loadClass(customConfiguration); 34 | JooqCustomContext instance = (JooqCustomContext) clazz.getDeclaredConstructor().newInstance(); 35 | return createDslContext(sqlDialect, dataSource, instance); 36 | } catch (Exception e) { 37 | log.error(customConfiguration, e); 38 | throw new RuntimeException(e); 39 | } 40 | } 41 | } 42 | 43 | public DSLContext createDslContext(String sqlDialect, AgroalDataSource dataSource, JooqCustomContext customConfiguration) { 44 | Objects.requireNonNull(sqlDialect, "sqlDialect"); 45 | Objects.requireNonNull(dataSource, "dataSource"); 46 | Objects.requireNonNull(customConfiguration, "customConfiguration"); 47 | return DslContextFactory.create(sqlDialect, dataSource, customConfiguration); 48 | } 49 | 50 | /** 51 | * CDI: Ambiguous dependencies 52 | */ 53 | @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE }) 54 | @Retention(RetentionPolicy.RUNTIME) 55 | @Documented 56 | @Qualifier 57 | public @interface DslContextQualifier { 58 | String value(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/ConnectionProvider.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import java.sql.Connection; 4 | import java.sql.SQLException; 5 | 6 | import jakarta.inject.Provider; 7 | 8 | import org.jboss.logging.Logger; 9 | 10 | import io.agroal.api.AgroalDataSource; 11 | import io.agroal.api.AgroalDataSourceMetrics; 12 | 13 | /** 14 | * Get database connection 15 | * 16 | * @author Leo Tu 17 | */ 18 | public class ConnectionProvider implements Provider { 19 | private static final Logger LOGGER = Logger.getLogger(ConnectionProvider.class); 20 | 21 | final private AgroalDataSource dataSource; 22 | 23 | public ConnectionProvider(AgroalDataSource dataSource) { 24 | this.dataSource = dataSource; 25 | this.dataSource.getConfiguration().setMetricsEnabled(true); 26 | } 27 | 28 | @Override 29 | public Connection get() { 30 | try { 31 | return dataSource.getConnection(); 32 | } catch (SQLException e) { 33 | AgroalDataSourceMetrics metrics = dataSource.getMetrics(); 34 | debugMetrics(metrics, e.getMessage()); 35 | LOGGER.error("Error occurred and metrics: " + dataSource.getMetrics(), e); 36 | throw new RuntimeException(e); 37 | } 38 | } 39 | 40 | private void debugMetrics(AgroalDataSourceMetrics metrics, String prefix) { 41 | long maxUsedCount = metrics.maxUsedCount(); 42 | LOGGER.tracev(prefix + " maxUsedCount: {0}, activeCount: {1}, availableCount: {2}", 43 | maxUsedCount == Long.MIN_VALUE ? -1 : maxUsedCount, metrics.activeCount(), metrics.availableCount()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/DslContextFactory.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import org.jboss.logging.Logger; 4 | import org.jooq.DSLContext; 5 | import org.jooq.SQLDialect; 6 | import org.jooq.impl.DSL; 7 | 8 | import io.agroal.api.AgroalDataSource; 9 | 10 | /** 11 | * 12 | * 13 | * @author Leo Tu 14 | */ 15 | public class DslContextFactory { 16 | private static final Logger log = Logger.getLogger(DslContextFactory.class); 17 | 18 | static { 19 | System.setProperty("org.jooq.no-logo", String.valueOf(true)); // -Dorg.jooq.no-logo=true 20 | } 21 | 22 | static public DSLContext create(String sqlDialect, AgroalDataSource ds, JooqCustomContext customContext) { 23 | DSLContext context; 24 | if ("PostgreSQL".equalsIgnoreCase(sqlDialect) || "Postgres".equalsIgnoreCase(sqlDialect)) { 25 | context = DSL.using(ds, SQLDialect.POSTGRES); 26 | } else if ("MySQL".equalsIgnoreCase(sqlDialect)) { 27 | context = DSL.using(ds, SQLDialect.MYSQL); 28 | } else if ("MARIADB".equalsIgnoreCase(sqlDialect)) { 29 | context = DSL.using(ds, SQLDialect.MARIADB); 30 | } else if ("Oracle".equalsIgnoreCase(sqlDialect)) { 31 | context = DSL.using(ds, SQLDialect.DEFAULT); 32 | } else if ("SQLServer".equalsIgnoreCase(sqlDialect)) { 33 | context = DSL.using(ds, SQLDialect.DEFAULT); 34 | } else if ("DB2".equalsIgnoreCase(sqlDialect)) { 35 | context = DSL.using(ds, SQLDialect.DEFAULT); 36 | } else if ("Derby".equalsIgnoreCase(sqlDialect)) { 37 | context = DSL.using(ds, SQLDialect.DERBY); 38 | } else if ("HSQLDB".equalsIgnoreCase(sqlDialect)) { 39 | context = DSL.using(ds, SQLDialect.HSQLDB); 40 | } else if ("H2".equalsIgnoreCase(sqlDialect)) { 41 | context = DSL.using(ds, SQLDialect.H2); 42 | } else if ("Firebird".equalsIgnoreCase(sqlDialect)) { 43 | context = DSL.using(ds, SQLDialect.FIREBIRD); 44 | } else if ("SQLite".equalsIgnoreCase(sqlDialect)) { 45 | context = DSL.using(ds, SQLDialect.SQLITE); 46 | } else { 47 | log.warnv("Undefined sqlDialect: {0}", sqlDialect); 48 | context = DSL.using(ds, SQLDialect.DEFAULT); 49 | } 50 | customContext.apply(context.configuration()); 51 | return context; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/JooqConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import java.util.Map; 4 | 5 | import io.quarkus.runtime.annotations.ConfigPhase; 6 | import io.quarkus.runtime.annotations.ConfigRoot; 7 | import io.smallrye.config.ConfigMapping; 8 | import io.smallrye.config.WithDefault; 9 | import io.smallrye.config.WithParentName; 10 | 11 | /** 12 | * Read from application.properties file 13 | * 14 | * @author Leo Tu 15 | */ 16 | @ConfigRoot(phase = ConfigPhase.BUILD_TIME) 17 | @ConfigMapping(prefix = "quarkus.jooq") 18 | public interface JooqConfig { 19 | 20 | /** 21 | * The default config. 22 | */ 23 | @WithParentName 24 | JooqItemConfig defaultConfig(); 25 | 26 | /** 27 | * Whether to automatically register jOOQ records/POJOs 28 | * for reflection. 29 | */ 30 | @WithDefault("true") 31 | boolean registerGeneratedClassesForReflection(); 32 | 33 | /** 34 | * Regex used to determine classes to be registered for 35 | * reflection. 36 | */ 37 | @WithDefault(".+\\.tables\\.(pojos|records)\\..+") 38 | String generatedClassesPattern(); 39 | 40 | /** 41 | * Additional configs. 42 | */ 43 | @WithParentName 44 | Map namedConfig(); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/JooqCustomContext.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.stream.Stream; 7 | 8 | import org.jboss.logging.Logger; 9 | import org.jooq.Configuration; 10 | import org.jooq.ExecuteListenerProvider; 11 | import org.jooq.conf.Settings; 12 | import org.jooq.impl.DefaultConfiguration; 13 | 14 | import io.quarkiverse.jooq.sql.SqlLoggerListener; 15 | 16 | /** 17 | * Custom Configuration 18 | * 19 | * @author Leo Tu 20 | */ 21 | public interface JooqCustomContext { 22 | Logger LOGGER = Logger.getLogger(JooqCustomContext.class); 23 | 24 | /** 25 | * File "jooq-settings.xml" 26 | */ 27 | default void apply(Configuration configuration) { 28 | Settings settings = configuration.settings(); 29 | settings.setRenderCatalog(false); 30 | settings.setRenderSchema(false); 31 | settings.setExecuteLogging(SqlLoggerListener.sqlLog.isTraceEnabled()); // LoggerListener 32 | settings.setRenderFormatted(false); 33 | settings.setQueryTimeout(60); // seconds 34 | 35 | if (settings.isExecuteLogging() && configuration instanceof DefaultConfiguration) { 36 | DefaultConfiguration defaultConfig = (DefaultConfiguration) configuration; 37 | if (configuration.executeListenerProviders() != null) { 38 | List providers = new ArrayList<>( 39 | Arrays.asList(configuration.executeListenerProviders())); 40 | providers.add(SqlLoggerListener::new); 41 | defaultConfig.setExecuteListenerProvider(providers.toArray(new ExecuteListenerProvider[0])); 42 | } else { 43 | defaultConfig.setExecuteListenerProvider(SqlLoggerListener::new); 44 | } 45 | 46 | Stream.of(configuration.executeListenerProviders()).forEach(p -> { 47 | LOGGER.debugv("executeListenerProvider: {0}", p); 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/JooqItemConfig.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import java.util.Optional; 4 | 5 | import io.quarkus.runtime.annotations.ConfigGroup; 6 | 7 | /** 8 | * @author Leo Tu 9 | */ 10 | @ConfigGroup 11 | public interface JooqItemConfig { 12 | 13 | /** 14 | * The jOOQ dialect 15 | */ 16 | String dialect(); 17 | 18 | /** 19 | * The jOOQ dataSource 20 | */ 21 | Optional datasource(); 22 | 23 | /** 24 | * The jOOQ configuration 25 | */ 26 | Optional configuration(); 27 | 28 | /** 29 | * The jOOQ configuration by inject named 30 | */ 31 | Optional configurationInject(); 32 | } 33 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/JooqRecorder.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import org.jboss.logging.Logger; 4 | 5 | import io.quarkus.runtime.annotations.Recorder; 6 | 7 | /** 8 | * Quarkus Template class (runtime) 9 | * 10 | * @author Leo Tu 11 | */ 12 | @Recorder 13 | public class JooqRecorder { 14 | private static final Logger log = Logger.getLogger(JooqRecorder.class); 15 | } 16 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/runtime/SQLDataTypeExt.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.runtime; 2 | 3 | import java.sql.Types; 4 | import java.util.Date; 5 | 6 | import org.jooq.DataType; 7 | import org.jooq.impl.DefaultDataType; 8 | 9 | /** 10 | * org.jooq.impl.SQLDataType.TIMESTAMP(XXX) to io.quarkiverse.jooq.UTILDATE(XXX) 11 | * 12 | * @see org.jooq.impl.SQLDataType 13 | * @see java.sql.Types 14 | */ 15 | public final class SQLDataTypeExt { 16 | /** 17 | * The {@link Types#TIMESTAMP} type. 18 | */ 19 | public static final DataType UTILDATE = new DefaultDataType(null, java.util.Date.class, "timestamp"); 20 | 21 | /** 22 | * The {@link Types#TIMESTAMP_WITH_TIMEZONE} type. 23 | */ 24 | public static final DataType UTILDATEWITHTIMEZONE = new DefaultDataType(null, java.util.Date.class, 25 | "timestamptz"); 26 | } 27 | -------------------------------------------------------------------------------- /runtime/src/main/java/io/quarkiverse/jooq/sql/SqlLoggerListener.java: -------------------------------------------------------------------------------- 1 | package io.quarkiverse.jooq.sql; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Modifier; 5 | import java.util.Arrays; 6 | 7 | import org.jboss.logging.Logger; 8 | import org.jooq.Configuration; 9 | import org.jooq.ExecuteContext; 10 | import org.jooq.ExecuteType; 11 | import org.jooq.Param; 12 | import org.jooq.QueryPart; 13 | import org.jooq.VisitContext; 14 | import org.jooq.VisitListener; 15 | import org.jooq.VisitListenerProvider; 16 | import org.jooq.impl.DSL; 17 | import org.jooq.impl.DefaultVisitListener; 18 | import org.jooq.impl.DefaultVisitListenerProvider; 19 | import org.jooq.tools.LoggerListener; 20 | import org.jooq.tools.StringUtils; 21 | 22 | /** 23 | * Logger (package) name is 'io.quarkiverse.jooq.sql' 24 | */ 25 | @SuppressWarnings("serial") 26 | public class SqlLoggerListener extends LoggerListener { 27 | private static final Logger log = Logger.getLogger(SqlLoggerListener.class); 28 | 29 | static public org.jooq.tools.JooqLogger sqlLog = org.jooq.tools.JooqLogger.getLogger(SqlLoggerListener.class); 30 | 31 | static { 32 | log.debug("sqlLog.isTraceEnabled: " + sqlLog.isTraceEnabled()); 33 | if (sqlLog.isTraceEnabled()) { 34 | try { 35 | setStaticFinalField(LoggerListener.class, "log", sqlLog); 36 | } catch (Exception e) { 37 | log.warn(e.toString()); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * Add a {@link VisitListener} that transforms all bind variables by 44 | * abbreviating them. 45 | */ 46 | private final Configuration abbreviateBindVariables(Configuration configuration) { 47 | VisitListenerProvider[] oldProviders = configuration.visitListenerProviders(); 48 | VisitListenerProvider[] newProviders = new VisitListenerProvider[oldProviders.length + 1]; 49 | System.arraycopy(oldProviders, 0, newProviders, 0, oldProviders.length); 50 | newProviders[newProviders.length - 1] = new DefaultVisitListenerProvider(new BindValueAbbreviator()); 51 | 52 | return configuration.derive(newProviders); 53 | } 54 | 55 | @Override 56 | public void renderEnd(ExecuteContext ctx) { 57 | if (log.isDebugEnabled()) { 58 | Configuration configuration = ctx.configuration(); 59 | String newline = Boolean.TRUE.equals(configuration.settings().isRenderFormatted()) ? "\n" : ""; 60 | 61 | // [#2939] Prevent excessive logging of bind variables only in DEBUG mode, not 62 | // in TRACE mode. 63 | if (!log.isTraceEnabled()) 64 | configuration = abbreviateBindVariables(configuration); 65 | 66 | String[] batchSQL = ctx.batchSQL(); 67 | if (ctx.query() != null) { 68 | 69 | // [#1278] DEBUG log also SQL with inlined bind values, if 70 | // that is not the same as the actual SQL passed to JDBC 71 | String inlined = DSL.using(configuration).renderInlined(ctx.query()); 72 | if (!ctx.sql().equals(inlined)) { 73 | sqlLog.debug("<>", newline + inlined); 74 | } else { 75 | // Actual SQL passed to JDBC 76 | sqlLog.debug("<>", newline + ctx.sql()); 77 | } 78 | } 79 | 80 | // [#2987] Log routines 81 | else if (ctx.routine() != null) { 82 | 83 | String inlined = DSL.using(configuration).renderInlined(ctx.routine()); 84 | 85 | if (!ctx.sql().equals(inlined)) { 86 | sqlLog.debug("<>", newline + inlined); 87 | } else { 88 | sqlLog.debug("<>", newline + ctx.sql()); 89 | } 90 | } 91 | 92 | else if (!StringUtils.isBlank(ctx.sql())) { 93 | 94 | // [#1529] Batch queries should be logged specially 95 | if (ctx.type() == ExecuteType.BATCH) 96 | sqlLog.debug("<>", newline + ctx.sql()); 97 | else 98 | sqlLog.debug("<>", newline + ctx.sql()); 99 | } 100 | 101 | // [#2532] Log a complete BatchMultiple query 102 | else if (batchSQL.length > 0) { 103 | if (batchSQL[batchSQL.length - 1] != null) 104 | for (String sql : batchSQL) 105 | sqlLog.debug("<>", newline + sql); 106 | } 107 | } 108 | } 109 | 110 | @Override 111 | public void recordEnd(ExecuteContext ctx) { 112 | // log.debug("..........recordEnd"); 113 | } 114 | 115 | @Override 116 | public void resultEnd(ExecuteContext ctx) { 117 | // log.debug("..........resultEnd"); 118 | } 119 | 120 | @Override 121 | public void executeEnd(ExecuteContext ctx) { 122 | // log.debug("Affected row(s)", ctx.rows()); 123 | } 124 | 125 | private static final int maxLength = 2000; 126 | 127 | private static class BindValueAbbreviator extends DefaultVisitListener { 128 | 129 | private boolean anyAbbreviations = false; 130 | 131 | @Override 132 | public void visitStart(VisitContext context) { 133 | if (context.renderContext() != null) { 134 | QueryPart part = context.queryPart(); 135 | 136 | if (part instanceof Param) { 137 | Param param = (Param) part; 138 | Object value = param.getValue(); 139 | 140 | if (value instanceof String && ((String) value).length() > maxLength) { 141 | anyAbbreviations = true; 142 | context.queryPart(DSL.val(StringUtils.abbreviate((String) value, maxLength))); 143 | } else if (value instanceof byte[] && ((byte[]) value).length > maxLength) { 144 | anyAbbreviations = true; 145 | context.queryPart(DSL.val(Arrays.copyOf((byte[]) value, maxLength))); 146 | } 147 | } 148 | } 149 | } 150 | 151 | @Override 152 | public void visitEnd(VisitContext context) { 153 | if (anyAbbreviations) { 154 | if (context.queryPartsLength() == 1) { 155 | context.renderContext().sql( 156 | " -- Bind values may have been abbreviated for DEBUG logging. Use TRACE logging for very large bind variables."); 157 | } 158 | } 159 | } 160 | } 161 | 162 | // === 163 | static void setStaticFinalField(Class clsObj, String fieldName, Object newValue) { 164 | setFinalField(null, clsObj, fieldName, newValue); 165 | } 166 | 167 | static void setFinalField(Object reflectObj, Class clsObj, String fieldName, Object newValue) { 168 | if (clsObj == null) { 169 | throw new IllegalArgumentException("(clsObj == null)"); 170 | } 171 | if (fieldName == null || fieldName.length() == 0) { 172 | throw new IllegalArgumentException( 173 | "(fieldName == null || fieldName.length() == 0), fieldName=[" + fieldName + "]"); 174 | } 175 | try { 176 | Field field = clsObj.getDeclaredField(fieldName); 177 | boolean keepStatus = field.canAccess(reflectObj); 178 | if (!keepStatus) { 179 | field.setAccessible(true); 180 | } 181 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 182 | modifiersField.setAccessible(true); 183 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 184 | try { 185 | field.set(reflectObj, newValue); 186 | } finally { 187 | field.setAccessible(keepStatus); 188 | modifiersField.setInt(field, field.getModifiers() & Modifier.FINAL); 189 | } 190 | } catch (Exception e) { 191 | String msg = "reflect object class: " + (reflectObj == null ? "" : reflectObj.getClass().getName()) 192 | + ", declared class: " + clsObj.getName() + ", field name: " + fieldName; 193 | log.warn(msg + ", error: " + e.toString()); 194 | throw new RuntimeException(msg, e); 195 | } 196 | } 197 | } 198 | --------------------------------------------------------------------------------