Skip to content

Commit

Permalink
[#10] Add to-many path examples as well as join path correlation
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaseder committed Jan 9, 2024
1 parent f4f2824 commit f97c9d0
Show file tree
Hide file tree
Showing 42 changed files with 364 additions and 187 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jooq.demo.java;

import org.jooq.*;
import org.jooq.conf.RenderImplicitJoinType;
import org.jooq.demo.AbstractDemo;
import org.jooq.demo.java.db.tables.Actor;
import org.jooq.demo.java.db.tables.FilmActor;
Expand Down Expand Up @@ -185,7 +186,7 @@ public void typeSafetyAliasing() {
}

@Test
public void implicitJoins() {
public void implicitToOneJoins() {
title("No need to spell out trivial to-one joins");
ctx.select(
CUSTOMER.FIRST_NAME,
Expand All @@ -197,6 +198,41 @@ public void implicitJoins() {
.fetch();
}

@Test
public void implicitToManyJoins() {
title("No need to spell out to-many joins either. Either use explicit to-many joins...");
ctx.select(
CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME,
countDistinct(CUSTOMER.rental().inventory().FILM_ID).as("distinct film rentals"))
.from(CUSTOMER)

// Add an explicit path join for the to-many path
.leftJoin(CUSTOMER.rental().inventory())
.groupBy(CUSTOMER.CUSTOMER_ID)
.orderBy(inline(3).desc())
.limit(5)
.fetch();

title("... or enable implicit to-many joins if you are OK with the 'interesting' semantics.");
ctx.configuration()
.deriveSettings(s -> s.withRenderImplicitJoinToManyType(RenderImplicitJoinType.LEFT_JOIN))
.dsl()
.select(
CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME,

// Now, the to-many path can be implicitly joined. Beware that this may produce very unexpected
// cartesian products (just like any JOIN, of course), which may be hard to debug because of the
// implicitness!
countDistinct(CUSTOMER.rental().inventory().FILM_ID).as("distinct film rentals"))
.from(CUSTOMER)
.groupBy(CUSTOMER.CUSTOMER_ID)
.orderBy(inline(3).desc())
.limit(5)
.fetch();
}

// There's a bug here
@Test(expected = Throwable.class)
public void nestedRecords() {
Expand Down Expand Up @@ -261,16 +297,14 @@ public void nestingToManyRelationships() {
FILM.TITLE,
multiset(
select(
FILM_ACTOR.actor().FIRST_NAME,
FILM_ACTOR.actor().LAST_NAME)
.from(FILM_ACTOR)
.where(FILM_ACTOR.FILM_ID.eq(FILM.FILM_ID))
FILM.actor().FIRST_NAME,
FILM.actor().LAST_NAME)

// Implicit path correlation is very powerful!
// https://www.jooq.org/doc/latest/manual/sql-building/sql-statements/select-statement/implicit-path-correlation/
.from(FILM.actor())
),
multiset(
select(FILM_CATEGORY.category().NAME)
.from(FILM_CATEGORY)
.where(FILM_CATEGORY.FILM_ID.eq(FILM.FILM_ID))
)
multiset(select(FILM.category().NAME).from(FILM.category()))
)
.from(FILM)
.orderBy(FILM.TITLE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.jooq.demo.kotlin

import org.jooq.*
import org.jooq.Records.mapping
import org.jooq.conf.RenderImplicitJoinType
import org.jooq.conf.Settings
import org.jooq.demo.AbstractDemo
import org.jooq.demo.kotlin.db.tables.references.*
import org.jooq.impl.DSL.*
Expand Down Expand Up @@ -183,7 +185,7 @@ class Demo01Querying : AbstractDemo() {
}

@Test
fun implicitJoins() {
fun implicitToOneJoins() {
title("No need to spell out trivial to-one joins")
ctx.select(
CUSTOMER.FIRST_NAME,
Expand All @@ -196,6 +198,43 @@ class Demo01Querying : AbstractDemo() {
.fetch()
}

@Test
fun implicitToManyJoins() {
title("No need to spell out to-many joins either. Either use explicit to-many joins...")
ctx.select(
CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME,
countDistinct(CUSTOMER.rental().inventory().FILM_ID).`as`("distinct film rentals")
)
.from(CUSTOMER)

// Add an explicit path join for the to-many path
.leftJoin(CUSTOMER.rental().inventory())
.groupBy(CUSTOMER.CUSTOMER_ID)
.orderBy(inline(3).desc())
.limit(5)
.fetch()

title("... or enable implicit to-many joins if you are OK with the 'interesting' semantics.")
ctx.configuration()
.deriveSettings { s -> s.withRenderImplicitJoinToManyType(RenderImplicitJoinType.LEFT_JOIN) }
.dsl()
.select(
CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME,

// Now, the to-many path can be implicitly joined. Beware that this may produce very unexpected
// cartesian products (just like any JOIN, of course), which may be hard to debug because of the
// implicitness!
countDistinct(CUSTOMER.rental().inventory().FILM_ID).`as`("distinct film rentals")
)
.from(CUSTOMER)
.groupBy(CUSTOMER.CUSTOMER_ID)
.orderBy(inline(3).desc())
.limit(5)
.fetch()
}

@Test
fun nestedRecords() {
title("Need all columns of those active records?")
Expand Down Expand Up @@ -258,17 +297,15 @@ class Demo01Querying : AbstractDemo() {
FILM.TITLE,
multiset(
select(
FILM_ACTOR.actor.FIRST_NAME,
FILM_ACTOR.actor.LAST_UPDATE
FILM.actor.FIRST_NAME,
FILM.actor.LAST_UPDATE
)
.from(FILM_ACTOR)
.where(FILM_ACTOR.FILM_ID.eq(FILM.FILM_ID))

// Implicit path correlation is very powerful!
// https://www.jooq.org/doc/latest/manual/sql-building/sql-statements/select-statement/implicit-path-correlation/
.from(FILM.actor)
),
multiset(
select(FILM_CATEGORY.category().NAME)
.from(FILM_CATEGORY)
.where(FILM_CATEGORY.FILM_ID.eq(FILM.FILM_ID))
)
multiset(select(FILM.category.NAME).from(FILM.category))
)
.from(FILM)
.orderBy(FILM.TITLE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class Demo01Querying extends AbstractDemo {
}

@Test
def implicitJoins(): Unit = {
def implicitToOneJoins(): Unit = {
title("No need to spell out trivial to-one joins")
ctx.select(
CUSTOMER.FIRST_NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jooq.demo.java;

import org.jooq.*;
import org.jooq.conf.RenderImplicitJoinType;
import org.jooq.demo.AbstractDemo;
import org.jooq.demo.java.db.tables.Actor;
import org.jooq.demo.java.db.tables.FilmActor;
Expand Down Expand Up @@ -185,7 +186,7 @@ public void typeSafetyAliasing() {
}

@Test
public void implicitJoins() {
public void implicitToOneJoins() {
title("No need to spell out trivial to-one joins");
ctx.select(
CUSTOMER.FIRST_NAME,
Expand All @@ -197,6 +198,41 @@ public void implicitJoins() {
.fetch();
}

@Test
public void implicitToManyJoins() {
title("No need to spell out to-many joins either. Either use explicit to-many joins...");
ctx.select(
CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME,
countDistinct(CUSTOMER.rental().inventory().FILM_ID).as("distinct film rentals"))
.from(CUSTOMER)

// Add an explicit path join for the to-many path
.leftJoin(CUSTOMER.rental().inventory())
.groupBy(CUSTOMER.CUSTOMER_ID)
.orderBy(inline(3).desc())
.limit(5)
.fetch();

title("... or enable implicit to-many joins if you are OK with the 'interesting' semantics.");
ctx.configuration()
.deriveSettings(s -> s.withRenderImplicitJoinToManyType(RenderImplicitJoinType.LEFT_JOIN))
.dsl()
.select(
CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME,

// Now, the to-many path can be implicitly joined. Beware that this may produce very unexpected
// cartesian products (just like any JOIN, of course), which may be hard to debug because of the
// implicitness!
countDistinct(CUSTOMER.rental().inventory().FILM_ID).as("distinct film rentals"))
.from(CUSTOMER)
.groupBy(CUSTOMER.CUSTOMER_ID)
.orderBy(inline(3).desc())
.limit(5)
.fetch();
}

// There's a bug here
@Test(expected = Throwable.class)
public void nestedRecords() {
Expand Down Expand Up @@ -261,16 +297,14 @@ public void nestingToManyRelationships() {
FILM.TITLE,
multiset(
select(
FILM_ACTOR.actor().FIRST_NAME,
FILM_ACTOR.actor().LAST_NAME)
.from(FILM_ACTOR)
.where(FILM_ACTOR.FILM_ID.eq(FILM.FILM_ID))
FILM.actor().FIRST_NAME,
FILM.actor().LAST_NAME)

// Implicit path correlation is very powerful!
// https://www.jooq.org/doc/latest/manual/sql-building/sql-statements/select-statement/implicit-path-correlation/
.from(FILM.actor())
),
multiset(
select(FILM_CATEGORY.category().NAME)
.from(FILM_CATEGORY)
.where(FILM_CATEGORY.FILM_ID.eq(FILM.FILM_ID))
)
multiset(select(FILM.category().NAME).from(FILM.category()))
)
.from(FILM)
.orderBy(FILM.TITLE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ open class DefaultCatalog : CatalogImpl("") {
)

/**
* A reference to the 3.19 minor release of the code generator. If this
* A reference to the 3.20 minor release of the code generator. If this
* doesn't compile, it's because the runtime library uses an older minor
* release, namely: 3.19. You can turn off the generation of this reference
* release, namely: 3.20. You can turn off the generation of this reference
* by specifying /configuration/generator/generate/jooqVersionReference
*/
private val REQUIRE_RUNTIME_JOOQ_VERSION = Constants.VERSION_3_19
private val REQUIRE_RUNTIME_JOOQ_VERSION = Constants.VERSION_3_20
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,34 @@ open class GetCustomerBalance : AbstractRoutine<BigDecimal>("get_customer_balanc
}

init {
returnParameter = RETURN_VALUE
addInParameter(P_CUSTOMER_ID)
addInParameter(P_EFFECTIVE_DATE)
returnParameter = GetCustomerBalance.RETURN_VALUE
addInParameter(GetCustomerBalance.P_CUSTOMER_ID)
addInParameter(GetCustomerBalance.P_EFFECTIVE_DATE)
}

/**
* Set the <code>p_customer_id</code> parameter IN value to the routine
*/
fun setPCustomerId(value: Long?): Unit = setValue(P_CUSTOMER_ID, value)
fun setPCustomerId(value: Long?): Unit = setValue(GetCustomerBalance.P_CUSTOMER_ID, value)

/**
* Set the <code>p_customer_id</code> parameter to the function to be used
* with a {@link org.jooq.Select} statement
*/
fun setPCustomerId(field: Field<Long?>): Unit {
setField(P_CUSTOMER_ID, field)
setField(GetCustomerBalance.P_CUSTOMER_ID, field)
}

/**
* Set the <code>p_effective_date</code> parameter IN value to the routine
*/
fun setPEffectiveDate(value: LocalDateTime?): Unit = setValue(P_EFFECTIVE_DATE, value)
fun setPEffectiveDate(value: LocalDateTime?): Unit = setValue(GetCustomerBalance.P_EFFECTIVE_DATE, value)

/**
* Set the <code>p_effective_date</code> parameter to the function to be
* used with a {@link org.jooq.Select} statement
*/
fun setPEffectiveDate(field: Field<LocalDateTime?>): Unit {
setField(P_EFFECTIVE_DATE, field)
setField(GetCustomerBalance.P_EFFECTIVE_DATE, field)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ open class GroupConcat : AbstractRoutine<String>("group_concat", Public.PUBLIC,
}

init {
returnParameter = RETURN_VALUE
addInParameter(_1)
returnParameter = GroupConcat.RETURN_VALUE
addInParameter(GroupConcat._1)
}

/**
* Set the <code>_1</code> parameter IN value to the routine
*/
fun set__1(value: String?): Unit = setValue(_1, value)
fun set__1(value: String?): Unit = setValue(GroupConcat._1, value)

/**
* Set the <code>_1</code> parameter to the function to be used with a
* {@link org.jooq.Select} statement
*/
fun set__1(field: Field<String?>): Unit {
setField(_1, field)
setField(GroupConcat._1, field)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ open class InventoryHeldByCustomer : AbstractRoutine<Int>("inventory_held_by_cus
}

init {
returnParameter = RETURN_VALUE
addInParameter(P_INVENTORY_ID)
returnParameter = InventoryHeldByCustomer.RETURN_VALUE
addInParameter(InventoryHeldByCustomer.P_INVENTORY_ID)
}

/**
* Set the <code>p_inventory_id</code> parameter IN value to the routine
*/
fun setPInventoryId(value: Long?): Unit = setValue(P_INVENTORY_ID, value)
fun setPInventoryId(value: Long?): Unit = setValue(InventoryHeldByCustomer.P_INVENTORY_ID, value)

/**
* Set the <code>p_inventory_id</code> parameter to the function to be used
* with a {@link org.jooq.Select} statement
*/
fun setPInventoryId(field: Field<Long?>): Unit {
setField(P_INVENTORY_ID, field)
setField(InventoryHeldByCustomer.P_INVENTORY_ID, field)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ open class InventoryInStock : AbstractRoutine<Boolean>("inventory_in_stock", Pub
}

init {
returnParameter = RETURN_VALUE
addInParameter(P_INVENTORY_ID)
returnParameter = InventoryInStock.RETURN_VALUE
addInParameter(InventoryInStock.P_INVENTORY_ID)
}

/**
* Set the <code>p_inventory_id</code> parameter IN value to the routine
*/
fun setPInventoryId(value: Long?): Unit = setValue(P_INVENTORY_ID, value)
fun setPInventoryId(value: Long?): Unit = setValue(InventoryInStock.P_INVENTORY_ID, value)

/**
* Set the <code>p_inventory_id</code> parameter to the function to be used
* with a {@link org.jooq.Select} statement
*/
fun setPInventoryId(field: Field<Long?>): Unit {
setField(P_INVENTORY_ID, field)
setField(InventoryInStock.P_INVENTORY_ID, field)
}
}
Loading

0 comments on commit f97c9d0

Please sign in to comment.