Go to file
2024-06-12 16:58:47 +02:00
.github/ISSUE_TEMPLATE Remove OS from issue templates 2024-03-12 09:19:22 +01:00
jOOQ [jOOQ/jOOQ#16815] Deprecate internal, protected AbstractRecord.from(Record) method 2024-06-10 13:59:55 +02:00
jOOQ-beans-extensions [jOOQ/jOOQ#16500] Move jakarta.persistence related logic of DefaultRecordMapper into a new jooq-jpa-extensions module 2024-05-27 16:10:13 +02:00
jOOQ-checker [jOOQ/jOOQ#14806] Upgrade checkerframework to 3.19.0 to better support JDK 17 2024-03-22 16:10:15 +01:00
jOOQ-codegen Revert "[jOOQ/jOOQ#16716] Generate MyTable.let(Function<? super MyTable, 2024-05-27 10:43:57 +02:00
jOOQ-codegen-gradle [jOOQ/jOOQ#16318] No need to inject Project into a Task 2024-06-12 16:58:47 +02:00
jOOQ-codegen-maven [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
jOOQ-examples Re-generated code 2024-05-28 05:07:13 +02:00
jOOQ-jackson-extensions Release 3.20.0-SNAPSHOT 2023-12-15 17:16:27 +01:00
jOOQ-jpa-extensions [jOOQ/jOOQ#16500] Fix module name 2024-05-29 13:40:28 +02:00
jOOQ-kotlin [jOOQ/jOOQ#16560] Cannot configure matchers using jOOQ-codegen-gradle plugin 2024-04-22 10:34:43 +02:00
jOOQ-kotlin-coroutines Release 3.20.0-SNAPSHOT 2023-12-15 17:16:27 +01:00
jOOQ-meta Revert "[jOOQ/jOOQ#16716] Generate MyTable.let(Function<? super MyTable, 2024-05-27 10:43:57 +02:00
jOOQ-meta-extensions [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
jOOQ-meta-extensions-hibernate [jOOQ/jOOQ#16500] Move jakarta.persistence related logic of DefaultRecordMapper into a new jooq-jpa-extensions module 2024-05-27 16:10:13 +02:00
jOOQ-meta-extensions-liquibase [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
jOOQ-meta-kotlin [jOOQ/jOOQ#15251] Add support for synthetic DEFAULT expressions 2024-05-17 11:33:52 +02:00
jOOQ-migrations [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
jOOQ-migrations-maven [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
jOOQ-postgres-extensions [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
jOOQ-scala_2.13 Release 3.20.0-SNAPSHOT 2023-12-15 17:16:27 +01:00
jOOQ-xtend [jOOQ/jOOQ#15987] pom.xml files should use https links instead of http links 2023-12-22 14:44:36 +01:00
.gitignore [jOOQ/jOOQ#11700] Add a jOOQ-r2dbc module (ignore for now) 2021-03-23 09:16:39 +01:00
.travis.yml Travis: use Maven 3.6.2 2019-09-22 13:23:21 -07:00
CONTRIBUTING.md Update CONTRIBUTING.md 2023-11-16 11:59:04 +01:00
LICENSE [jOOQ/jOOQ#14110] License header should use HTTPS rather than HTTP 2022-10-19 10:43:58 +02:00
pom.xml [jOOQ/jOOQ#16752] Upgrade testcontainers dependency 2024-06-03 18:06:40 +02:00
README.md Add policies to README 2024-01-15 13:18:28 +01:00
SECURITY.md Create SECURITY.md 2022-04-19 10:53:35 +02:00

jOOQ

jOOQ is an internal DSL and source code generator, modelling the SQL language as a type safe Java API to help you write better SQL.

Its main features include:

Secondary features include:

Examples

Typesafe, embedded SQL

jOOQ's main feature is typesafe, embedded SQL, allowing for IDE auto completion of SQL syntax...

image

... as well as of schema meta data:

image

This allows for preventing errors of various types, including typos of identifiers:

image

Or data type mismatches:

image

The examples are from the code generation blog post.

A more powerful example using nested collections

For many more examples, please have a look at the demo. A key example showing jOOQ's various strengths is from the MULTISET operator announcement blog post:

Given these target DTOs:

record Actor(String firstName, String lastName) {}
record Film(
  String title,
  List<Actor> actors,
  List<String> categories
) {}

You can now write the following query to fetch films, their nested actors and their nested categorise in a single, type safe query:

List<Film> result =
dsl.select(
      FILM.TITLE,
      multiset(
        select(
          FILM.actor().FIRST_NAME, 
          FILM.actor().LAST_NAME)
        .from(FILM.actor())
      ).as("actors").convertFrom(r -> r.map(mapping(Actor::new))),
      multiset(
        select(FILM.category().NAME)
        .from(FILM.category())
      ).as("categories").convertFrom(r -> r.map(Record1::value1))
   )
   .from(FILM)
   .orderBy(FILM.TITLE)
   .fetch(mapping(Film::new));

The query is completely type safe. Change a column type, name, or the target DTO, and it will stop compiling! Trust only your own eyes:

multiset

And here you see the nested result in action from the logs:

execute

How does it work? Look at this annotated example:

List<Film> result =
dsl.select(
      FILM.TITLE,

      // MULTISET is a standard SQL operator that allows for nesting collections
      // directly in SQL. It is either
      // - supported natively
      // - emulated using SQL/JSON or SQL/XML
      multiset(

        // Implicit path based joins allow for simpler navigation of foreign
        // key relationships.
        select(
          FILM.actor().FIRST_NAME, 
          FILM.actor().LAST_NAME)

        // Implicit correlation to outer queries allows for avoiding repetitive
        // writing of predicates.
        .from(FILM.actor())

      // Ad-hoc conversion allows for mapping structural Record2<String, String>
      // types to your custom DTO using constructor references
      ).as("actors").convertFrom(r -> r.map(mapping(Actor::new))),
      multiset(
        select(FILM.category().NAME)
        .from(FILM.category())
      ).as("categories").convertFrom(r -> r.map(Record1::value1))
   )
   .from(FILM)
   .orderBy(FILM.TITLE)
   .fetch(mapping(Film::new));

The generated SQL query might look like this, in PostgreSQL:

select
  film.title,
  (
    select coalesce(
      jsonb_agg(jsonb_build_object(
        'first_name', t.first_name,
        'last_name', t.last_name
      )),
      jsonb_build_array()
    )
    from (
      select
        alias_78509018.first_name, 
        alias_78509018.last_name
      from (
        film_actor
          join actor as alias_78509018
            on film_actor.actor_id = alias_78509018.actor_id
        )
      where film_actor.film_id = film.film_id
    ) as t
  ) as actors,
  (
    select coalesce(
      jsonb_agg(jsonb_build_object('name', t.name)),
      jsonb_build_array()
    )
    from (
      select alias_130639425.name
      from (
        film_category
          join category as alias_130639425
            on film_category.category_id = alias_130639425.category_id
        )
      where film_category.film_id = film.film_id
    ) as t
  ) as categories
from film
order by film.title

This particular example is explained more in detail in the MULTISET operator announcement blog post. For many more examples, please have a look at the demo.