SELECT * FROM A
SELECT * FROM A JOIN B ON (A.id = B.id)
SELECT * FROM A JOIN B ON (A.id = B.id)
WHERE A.foo = '1' -- sometimes we look for these foo values
AND B.bar = '2' -- sometimes we look for these bar values
AND A.baz = '3' -- sometimes we look for these baz values
TableOnConditionStep fromClause = table("B")
.join(table("B")).on("A.id = B.id");
if (joinTableC == true){
fromClause = fromClause.join(table("C")).on("B.id = C.d");
}
dsl.select( ... )
.from( fromClause );
SelectOnConditionStep statement = select(Temperatures.VALUE, Temperatures.TIMESTAMP)
.from(Temperatures)
.where(Temperatures.VALUE.greaterOrEqual(0));
if (filter.hasMaxValue())
statement.and(Temperatures.VALUE.lessOrEqual(filter.getMaxValue());
if (filter.hasLocation())
statement.and(Temperatures.LOCATION.equal(filter.getLocation());
// And so on with the rest of filters to end with:
statement.orderBy(Temperature.TIMESTAMP)
.fetch();
TableOnConditionStep fromClause = table("B")
.join(table("B")).on("A.id = B.id");
if (joinTableC == true){
fromClause = fromClause.join(table("C")).on("B.id = C.d");
}
dsl.select( ... )
.from( fromClause );
Table<?> table = table("A")...
Another example
SelectOnConditionStep statement = select(Temperatures.VALUE, Temperatures.TIMESTAMP)
.from(Temperatures)
.where(Temperatures.VALUE.greaterOrEqual(0));
if (filter.hasMaxValue())
statement.and(Temperatures.VALUE.lessOrEqual(filter.getMaxValue());
if (filter.hasLocation())
statement.and(Temperatures.LOCATION.equal(filter.getLocation());
// And so on with the rest of filters to end with:
statement.orderBy(Temperature.TIMESTAMP)
.fetch();
Condition condition = Temperatures.VALUE.ge(0);if (filter.hasMaxValue())condition = condition.and(Temperatures.VALUE.le(filter.getMaxValue());if (filter.hasLocation())condition = condition.and(Temperatures.LOCATION.eq(filter.getLocation());// Only now construct the query:select(Temperatures.VALUE, Temperatures.TIMESTAMP).from(Temperatures).where(condition).orderBy(Temperatures.TIMESTAMP).fetch();
public Condition condition(Filter filter) {Condition condition = Temperatures.VALUE.ge(0);if (filter.hasMaxValue())condition = condition.and(Temperatures.VALUE.le(filter.getMaxValue());if (filter.hasLocation())condition = condition.and(Temperatures.LOCATION.eq(filter.getLocation());return condition;}// Only now construct the query:select(Temperatures.VALUE, Temperatures.TIMESTAMP).from(Temperatures).where(condition(filter)).orderBy(Temperatures.TIMESTAMP).fetch();
The once pretty fluent style becomes chopped up and hard to follow. The blog post here discusses this in more detail and presents an elegant solution. I'd like to hear how other people are handling this... Also wondering if future versions of JOOQ will have this in mind,
Hi Lukas,As always thank you for the prompt and detailed reply. Looking at the JOOQ type system is becomes clear why the need for various local types are not needed (everything is a subtype of Table).
Your example with generating conditions is very similar to how I do it now... However its the JOIN stuff that's giving me grief right now. Joins are more complicated because of the many permutations of tables that can participate in the join, and depending on which tables participate I need to perform the join differently.Let's say for example you have 3 tables Events, Sessions and People. There are 2^3 - 1 = 7 valid combinations of these 3 tables. (minus one for zero tables).Once a table is joined in the query I don't know if there is a good way to get at that information after the fact (getQuery?). For example, if I'm joining Session it would be good to know if Person has already been joined because then I can do Session.personid = Person.id, but if it is only Event that exists in the join then I need to do Event.sessionid = Sessions.id and if no tables exists so far then there is join and I'm simply querying the Session table.
Is there a way to get a list of the tables in the join or do I need to wrap the query generation logic with something that keeps track oft this for me?
I'm trying to avoid building a giant case statement that accounts for all the permutations. I suppose the questions is less of a JOOQ questions and more of a general design question...
/*
Entity is an enum of my tables. This set matches every table to a predicate which returns true when that table is needed
*/
ImmutableSet<Tuple<Entity, Predicate<EventQuery>>> tablePredicates = ImmutableSet.of(
new Tuple<Entity, Predicate<EventQuery>>(EVENT, q -> ... return some boolean based on q .. )
,new Tuple<Entity, Predicate<EventQuery>>(SESSION, q -> ... return some boolean ..)
,new Tuple<Entity, Predicate<EventQuery>>(PERSON, q -> ... return some boolean .. )
,new Tuple<Entity, Predicate<EventQuery>>(ALIAS, q -> ... return some boolean
);
/* Map where a tuple of tables is the keys to for joining the tables. It can be a thought of as a state machine
* where the two tables in the tuple are a transition.
* The function joins the second table in the tuple to the existing join.
*/
ImmutableMap<Tuple<Entity, Entity>, Function<Table<?>,Table<?>>> joinClauses =
ImmutableMap.of(
new Tuple<Entity, Entity>(SESSION, PERSON),
(t) -> t.join( PERSON.getTable()).on("S.person_id = P.id").and( field("P.last_seen", Timestamp.class).between(query.getStartDate(), query.getEndDate()))
, new Tuple<Entity, Entity>(EVENT, SESSION),
(t) -> t.join( SESSION.getTable()).on("O.session_id = S.session_id")
, new Tuple<Entity, Entity>(EVENT, PERSON),
(t) -> t.join( ALIAS.getTable()).on("O.person_alias = A.alias")
.join( PERSON.getTable()).on("A.person_id = P.id").and( field("P.last_seen", Timestamp.class).between(query.getStartDate(), query.getEndDate()))
, new Tuple<Entity, Entity>(EVENT, ALIAS),
(t) -> t.join( tenantSql.jooqTable(ALIAS)).on("O.person_alias = A.alias")
);
ImmutableMap<K,V> myMap = ImmutableMap.of(
"key1", "value1",
"key2", "value2",
etc...
);
/*
* Run through the tablePredicates and get the list of entities that must participate in the join
*/
List<Entity> joinables = tablePredicates.stream().filter(t -> t._2.test(query) )
.map(t -> t._1)
.collect(Collectors.toList());
//Case for a single table (ie no join necessary) and the starting table
Table<?> fromClause = tenantSql.jooqTable( joinables.get(0), requiresView(joinables.get(0), query));
//Build the joining by looking up tuples in the join clause map.
for (int i = 1; i < joinables.size(); i++){
fromClause = joinClauses.get( new Tuple<Entity, Entity>(joinables.get(i-1), joinables.get(i)))
.apply( fromClause, requiresView(joinables.get(i), query) );
}
return fromClause;
--You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.