From 9bbce6b459a405c215be889a96cf6b885a6c0efb Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 17 May 2023 17:47:44 +0200 Subject: [PATCH] [jOOQ/jOOQ#8012] Override Table.where(Condition) methods in generated tables --- .../org/jooq/codegen/AbstractGenerator.java | 11 +++ .../java/org/jooq/codegen/GenerationTool.java | 2 + .../main/java/org/jooq/codegen/Generator.java | 14 +++ .../java/org/jooq/codegen/JavaGenerator.java | 25 ++++- .../java/org/jooq/meta/jaxb/Generate.java | 42 +++++++++ .../org/jooq/meta/xsd/jooq-codegen-3.19.0.xsd | 4 + .../java/org/jooq/impl/SelectQueryImpl.java | 93 ++++++++++++++----- .../main/java/org/jooq/impl/TableImpl.java | 32 ++++++- 8 files changed, 197 insertions(+), 26 deletions(-) diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGenerator.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGenerator.java index 1f13251aab..8140adac30 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGenerator.java @@ -172,6 +172,7 @@ abstract class AbstractGenerator implements Generator { String generateIndentation; int generatePrintMarginForBlockComment = 80; GeneratedTextBlocks generateTextBlocks = GeneratedTextBlocks.DETECT_FROM_JDK; + boolean generateWhereMethodOverrides = true; protected GeneratorStrategyWrapper strategy; protected String targetEncoding = "UTF-8"; @@ -1371,6 +1372,16 @@ abstract class AbstractGenerator implements Generator { this.generateTextBlocks = textBlocks; } + @Override + public boolean generateWhereMethodOverrides() { + return generateWhereMethodOverrides; + } + + @Override + public void setGenerateWhereMethodOverrides(boolean whereMethodOverrides) { + this.generateWhereMethodOverrides = whereMethodOverrides; + } + // ---- @Override diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationTool.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationTool.java index 30325f67e7..39ac8dff2b 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationTool.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationTool.java @@ -922,6 +922,8 @@ public class GenerationTool { generator.setGeneratePrintMarginForBlockComment(g.getGenerate().getPrintMarginForBlockComment()); if (g.getGenerate().getTextBlocks() != null) generator.setGenerateTextBlocks(g.getGenerate().getTextBlocks()); + if (g.getGenerate().isWhereMethodOverrides() != null) + generator.setGenerateWhereMethodOverrides(g.getGenerate().isWhereMethodOverrides()); if (!isBlank(d.getSchemaVersionProvider())) diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/Generator.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/Generator.java index 430699db70..0c72e27e99 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/Generator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/Generator.java @@ -41,11 +41,13 @@ package org.jooq.codegen; import java.io.Serializable; import java.util.Locale; +import org.jooq.Condition; import org.jooq.Constants; import org.jooq.JSON; import org.jooq.JSONB; import org.jooq.Path; import org.jooq.Spatial; +import org.jooq.Table; import org.jooq.XML; import org.jooq.impl.DAOImpl; import org.jooq.meta.Database; @@ -1287,6 +1289,18 @@ public interface Generator { */ void setGenerateTextBlocks(GeneratedTextBlocks textBlocks); + /** + * Whether to generate overrides for {@link Table#where(Condition)} and + * related overloads. + */ + boolean generateWhereMethodOverrides(); + + /** + * Whether to generate overrides for {@link Table#where(Condition)} and + * related overloads. + */ + void setGenerateWhereMethodOverrides(boolean whereMethodOverrides); + /** * The target directory */ diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java index 510e38a2ef..649a845d62 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java @@ -59,7 +59,6 @@ import static org.jooq.impl.DSL.name; import static org.jooq.impl.QOM.GenerationOption.STORED; import static org.jooq.impl.QOM.GenerationOption.VIRTUAL; import static org.jooq.meta.AbstractTypedElementDefinition.getDataType; -import static org.jooq.meta.jaxb.VisibilityModifier.PUBLIC; import static org.jooq.tools.StringUtils.isBlank; import java.io.File; @@ -97,6 +96,7 @@ import java.util.stream.Stream; import org.jooq.AggregateFunction; import org.jooq.Catalog; import org.jooq.Check; +import org.jooq.Condition; import org.jooq.Configuration; import org.jooq.Constants; import org.jooq.DSLContext; @@ -6313,7 +6313,7 @@ public class JavaGenerator extends AbstractGenerator { out.println("});"); } else - out.println("this(alias, aliased, null);"); + out.println("this(alias, aliased, (%s[]) null);", Field.class); out.println("}"); @@ -6328,6 +6328,18 @@ public class JavaGenerator extends AbstractGenerator { out.println("super(alias, null, aliased, parameters, %s.comment(\"%s\"), %s.%s());", DSL.class, escapeString(comment(table)), TableOptions.class, tableType); out.println("}"); + + if (!table.isTableValuedFunction()) { + out.println(); + out.println("private %s(%s alias, %s<%s> aliased, %s where) {", className, Name.class, Table.class, recordType, Condition.class); + + if ((generateSourcesOnViews() || table.isSynthetic()) && table.isView() && table.getSource() != null) + out.println("super(alias, null, null, null, null, aliased, null, %s.comment(\"%s\"), %s.%s(%s), where);", DSL.class, escapeString(comment(table)), TableOptions.class, tableType, textBlock(table.getSource())); + else + out.println("super(alias, null, null, null, null, aliased, null, %s.comment(\"%s\"), %s.%s(), where);", DSL.class, escapeString(comment(table)), TableOptions.class, tableType); + + out.println("}"); + } } if (scala) { @@ -7150,6 +7162,15 @@ public class JavaGenerator extends AbstractGenerator { out.println("return new %s(name.getQualifiedName(), null);", className); out.println("}"); + + if (!table.isTableValuedFunction()) { + out.javadoc("Create an inline derived table from this table"); + out.override(); + printNonnullAnnotation(out); + out.println("%s%s where(%s condition) {", visibilityPublic(), className, Condition.class); + out.println("return new %s(getQualifiedName(), aliased() ? this : null, condition);", className); + out.println("}"); + } } diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/Generate.java b/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/Generate.java index 9fc73a5fff..0b2eb3d64a 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/Generate.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/Generate.java @@ -244,6 +244,8 @@ public class Generate implements Serializable, XMLAppendable @XmlElement(defaultValue = "DETECT_FROM_JDK") @XmlSchemaType(name = "string") protected GeneratedTextBlocks textBlocks = GeneratedTextBlocks.DETECT_FROM_JDK; + @XmlElement(defaultValue = "true") + protected Boolean whereMethodOverrides = true; /** * Generate index information. @@ -2695,6 +2697,30 @@ public class Generate implements Serializable, XMLAppendable this.textBlocks = value; } + /** + * Whether to generate overrides for {@link org.jooq.Table#where(org.jooq.Condition)} and related overloads. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isWhereMethodOverrides() { + return whereMethodOverrides; + } + + /** + * Sets the value of the whereMethodOverrides property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setWhereMethodOverrides(Boolean value) { + this.whereMethodOverrides = value; + } + public Generate withIndexes(Boolean value) { setIndexes(value); return this; @@ -3268,6 +3294,11 @@ public class Generate implements Serializable, XMLAppendable return this; } + public Generate withWhereMethodOverrides(Boolean value) { + setWhereMethodOverrides(value); + return this; + } + @Override public final void appendTo(XMLBuilder builder) { builder.append("indexes", indexes); @@ -3374,6 +3405,7 @@ public class Generate implements Serializable, XMLAppendable builder.append("indentation", indentation); builder.append("printMarginForBlockComment", printMarginForBlockComment); builder.append("textBlocks", textBlocks); + builder.append("whereMethodOverrides", whereMethodOverrides); } @Override @@ -4331,6 +4363,15 @@ public class Generate implements Serializable, XMLAppendable return false; } } + if (whereMethodOverrides == null) { + if (other.whereMethodOverrides!= null) { + return false; + } + } else { + if (!whereMethodOverrides.equals(other.whereMethodOverrides)) { + return false; + } + } return true; } @@ -4442,6 +4483,7 @@ public class Generate implements Serializable, XMLAppendable result = ((prime*result)+((indentation == null)? 0 :indentation.hashCode())); result = ((prime*result)+((printMarginForBlockComment == null)? 0 :printMarginForBlockComment.hashCode())); result = ((prime*result)+((textBlocks == null)? 0 :textBlocks.hashCode())); + result = ((prime*result)+((whereMethodOverrides == null)? 0 :whereMethodOverrides.hashCode())); return result; } diff --git a/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.19.0.xsd b/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.19.0.xsd index 671e6a25c8..c9100d6dbd 100644 --- a/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.19.0.xsd +++ b/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.19.0.xsd @@ -2459,6 +2459,10 @@ This flag is ignored in the commercial Java 6 distribution of jOOQ 3.9+ ]]> + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 2dcfed30f9..17a4698694 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -156,6 +156,7 @@ import static org.jooq.impl.DSL.regexpReplaceAll; import static org.jooq.impl.DSL.row; import static org.jooq.impl.DSL.rowNumber; // ... +import static org.jooq.impl.DSL.selectFrom; import static org.jooq.impl.DSL.table; import static org.jooq.impl.DSL.trueCondition; import static org.jooq.impl.DSL.unquotedName; @@ -261,6 +262,7 @@ import java.util.function.Function; import org.jooq.Asterisk; import org.jooq.Clause; +import org.jooq.Comment; import org.jooq.CommonTableExpression; import org.jooq.Comparator; import org.jooq.Condition; @@ -271,6 +273,7 @@ import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.GeneratorStatementType; import org.jooq.GroupField; +import org.jooq.InverseForeignKey; import org.jooq.JSONEntry; import org.jooq.JSONObjectNullStep; import org.jooq.JSONObjectReturningStep; @@ -288,6 +291,7 @@ import org.jooq.Record; import org.jooq.Result; import org.jooq.Row; import org.jooq.SQLDialect; +import org.jooq.Schema; import org.jooq.Scope; import org.jooq.Select; import org.jooq.SelectField; @@ -304,6 +308,7 @@ import org.jooq.TableField; import org.jooq.TableLike; import org.jooq.TableOnStep; import org.jooq.TableOptionalOnStep; +import org.jooq.TableOptions; import org.jooq.TablePartitionByStep; // ... // ... @@ -2708,18 +2713,31 @@ final class SelectQueryImpl extends AbstractResultQuery imp )); } - private final boolean hasInlineDerivedTables(TableList tablelist) { - return anyMatch(tablelist, t -> - t instanceof InlineDerivedTable - || t instanceof JoinTable && hasInlineDerivedTables((JoinTable) t) - ); + private static final Table inlineDerivedTable(Table t) { + if (t instanceof InlineDerivedTable i) { + return i; + } + else if (t instanceof TableImpl i) { + if (i.where != null) + return new InlineDerivedTable<>(removeWhere(i), i.where); + + Table unaliased = Tools.unalias(i); + if (unaliased instanceof TableImpl u) { + if (u.where != null) + return new InlineDerivedTable<>(removeWhere(u), u.where).query().asTable(i); + } + } + + return null; } - private final boolean hasInlineDerivedTables(JoinTable join) { - return join.lhs instanceof InlineDerivedTable - || join.rhs instanceof InlineDerivedTable - || join.lhs instanceof JoinTable && hasInlineDerivedTables((JoinTable) join.lhs) - || join.rhs instanceof JoinTable && hasInlineDerivedTables((JoinTable) join.rhs); + private static final boolean hasInlineDerivedTables(Table t) { + return inlineDerivedTable(t) != null + || t instanceof JoinTable && (hasInlineDerivedTables(((JoinTable) t).lhs) || hasInlineDerivedTables(((JoinTable) t).rhs)); + } + + private static final boolean hasInlineDerivedTables(TableList tablelist) { + return anyMatch(tablelist, t -> hasInlineDerivedTables(t)); } @@ -2755,7 +2773,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp - private final TableList transformInlineDerivedTables(TableList tablelist, ConditionProviderImpl where) { + private static final TableList transformInlineDerivedTables(TableList tablelist, ConditionProviderImpl where) { if (!hasInlineDerivedTables(tablelist)) return tablelist; @@ -2767,10 +2785,35 @@ final class SelectQueryImpl extends AbstractResultQuery imp return result; } - private final void transformInlineDerivedTable0(Table table, TableList result, ConditionProviderImpl where) { - if (table instanceof InlineDerivedTable t) { - result.add(t.table); - where.addConditions(t.condition); + private static final Table removeWhere(Table t) { + if (t instanceof TableImpl i) { + return new TableImpl<>( + i.getQualifiedName(), + i.getSchema(), + i.path, + i.childPath, + i.parentPath, + i.alias != null ? removeWhere(i.alias.wrapped) : null, + i.parameters, + i.getCommentPart(), + i.getOptions(), + null + ); + } + else + return t; + } + + private static final void transformInlineDerivedTable0(Table table, TableList result, ConditionProviderImpl where) { + Table t = inlineDerivedTable(table); + + if (t != null) { + if (t instanceof InlineDerivedTable i) { + result.add(i.table); + where.addConditions(i.condition); + } + else + result.add(t); } else if (table instanceof JoinTable) result.add(transformInlineDerivedTables0(table, where, false)); @@ -2778,15 +2821,21 @@ final class SelectQueryImpl extends AbstractResultQuery imp result.add(table); } - private final Table transformInlineDerivedTables0(Table table, ConditionProviderImpl where, boolean keepDerivedTable) { - if (table instanceof InlineDerivedTable t) { - if (keepDerivedTable) - return t.query().asTable(t.table); + private static final Table transformInlineDerivedTables0(Table table, ConditionProviderImpl where, boolean keepDerivedTable) { + Table t = inlineDerivedTable(table); - where.addConditions(t.condition); - return t.table; + if (t != null) { + if (t instanceof InlineDerivedTable i) { + if (keepDerivedTable) + return i.query().asTable(i.table); + + where.addConditions(i.condition); + return i.table; + } + else + return t; } - else if (table instanceof JoinTable j) { + else if (table instanceof JoinTable j) { Table lhs; Table rhs; diff --git a/jOOQ/src/main/java/org/jooq/impl/TableImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableImpl.java index 3d6bed20da..8a43313c91 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableImpl.java @@ -124,6 +124,7 @@ implements final FieldsImpl fields; final Alias> alias; + final Condition where; protected final Field[] parameters; final Table path; @@ -239,7 +240,10 @@ implements this(name, schema, path, childPath, null, aliased, parameters, comment, options); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + /** + * @deprecated - [#8012] - 3.19.0 - Please re-generate your code. + */ + @Deprecated public TableImpl( Name name, Schema schema, @@ -250,6 +254,22 @@ implements Field[] parameters, Comment comment, TableOptions options + ) { + this(name, schema, path, childPath, parentPath, aliased, parameters, comment, options, null); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TableImpl( + Name name, + Schema schema, + Table path, + ForeignKey childPath, + InverseForeignKey parentPath, + Table aliased, + Field[] parameters, + Comment comment, + TableOptions options, + Condition where ) { super(options, name, schema, comment); @@ -291,6 +311,7 @@ implements this.alias = null; this.parameters = parameters; + this.where = where; } static final Table path(Table t) { @@ -367,7 +388,14 @@ implements @Override final FieldsImpl fields0() { - return fields; + + // [#8012] Implement the same behaviour as InlineDerivedTable to make + // sure we produce the proper qualification of fields also when + // dereferencing a field using Table.field(String), for example + if (where != null) + return new InlineDerivedTable<>(this, where).fields0(); + else + return fields; } // [#8489] this override is necessary due to a Scala compiler bug (versions 2.10 and 2.11)