diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java index e88210e85a..0d008249e9 100644 --- a/jOOQ/src/main/java/org/jooq/DSLContext.java +++ b/jOOQ/src/main/java/org/jooq/DSLContext.java @@ -3377,6 +3377,27 @@ public interface DSLContext extends Scope , AutoCloseable { @Support({ FIREBIRD, HSQLDB, POSTGRES }) WithAsStep with(String alias, String... fieldAliases); + + /** + * Create a WITH clause to supply subsequent + * SELECT, UPDATE, INSERT, + * DELETE, and MERGE statements with + * {@link CommonTableExpression}s. + *

+ * The RECURSIVE keyword may be optional or unsupported in some + * databases, in case of which it will not be rendered. For optimal database + * interoperability and readability, however, it is suggested that you use + * {@link #with(String, String...)} for strictly non-recursive CTE and + * {@link #withRecursive(String, String...)} for strictly recursive CTE. + *

+ * This works in a similar way as {@link #with(String, String...)}, except + * that all column names are produced by a function that receives the CTE's + * {@link Select} columns as input. + */ + @Support({ FIREBIRD, HSQLDB, POSTGRES }) + WithAsStep with(String alias, Function, ? extends String> fieldNameFunction); + + // [jooq-tools] START [with] /** @@ -3817,6 +3838,31 @@ public interface DSLContext extends Scope , AutoCloseable { @Support({ FIREBIRD, H2, HSQLDB, POSTGRES }) WithAsStep withRecursive(String alias, String... fieldAliases); + + /** + * Create a WITH clause to supply subsequent + * SELECT, UPDATE, INSERT, + * DELETE, and MERGE statements with + * {@link CommonTableExpression}s. + *

+ * The RECURSIVE keyword may be optional or unsupported in some + * databases, in case of which it will not be rendered. For optimal database + * interoperability and readability, however, it is suggested that you use + * {@link #with(String, String...)} for strictly non-recursive CTE + * and {@link #withRecursive(String, String...)} for strictly + * recursive CTE. + *

+ * Note that the {@link SQLDialect#H2} database only supports single-table, + * RECURSIVE common table expression lists. + *

+ * This works in a similar way as {@link #with(String, String...)}, except + * that all column names are produced by a function that receives the CTE's + * {@link Select} columns as input. + */ + @Support({ FIREBIRD, HSQLDB, POSTGRES }) + WithAsStep withRecursive(String alias, Function, ? extends String> fieldNameFunction); + + // [jooq-tools] START [with-recursive] /** diff --git a/jOOQ/src/main/java/org/jooq/Name.java b/jOOQ/src/main/java/org/jooq/Name.java index 7311a9189a..c8b696d38e 100644 --- a/jOOQ/src/main/java/org/jooq/Name.java +++ b/jOOQ/src/main/java/org/jooq/Name.java @@ -54,6 +54,8 @@ import static org.jooq.SQLDialect.POSTGRES; // ... // ... +import java.util.function.Function; + import javax.annotation.Generated; import org.jooq.conf.Settings; @@ -108,6 +110,23 @@ public interface Name extends QueryPart { @Support({ FIREBIRD, H2, HSQLDB, POSTGRES }) DerivedColumnList fields(String... fieldNames); + + /** + * Add a list of fields to this name to make this name a + * {@link DerivedColumnList}. + *

+ * The DerivedColumnList can then be used along with a + * subselect to form a {@link CommonTableExpression} to be used with + * WITH clauses. + *

+ * This works in a similar way as {@link #fields(String...)}, except + * that all column names are produced by a function that receives the CTE's + * {@link Select} columns as input. + */ + @Support({ FIREBIRD, H2, HSQLDB, POSTGRES }) + DerivedColumnList fields(Function, ? extends String> fieldNameFunction); + + // [jooq-tools] START [fields] /** diff --git a/jOOQ/src/main/java/org/jooq/WithStep.java b/jOOQ/src/main/java/org/jooq/WithStep.java index c12836ac99..8e58b7876d 100644 --- a/jOOQ/src/main/java/org/jooq/WithStep.java +++ b/jOOQ/src/main/java/org/jooq/WithStep.java @@ -51,6 +51,7 @@ import static org.jooq.SQLDialect.POSTGRES; // ... import java.util.Collection; +import java.util.function.Function; import javax.annotation.Generated; @@ -92,6 +93,18 @@ public interface WithStep extends QueryPart { @Support({ FIREBIRD, H2, HSQLDB, POSTGRES }) WithAsStep with(String alias, String... fieldAliases); + + /** + * Add another common table expression to the WITH clause. + *

+ * This works in a similar way as {@link #with(String, String...)}, except + * that all column names are produced by a function that receives the CTE's + * {@link Select} columns as input. + */ + @Support({ FIREBIRD, H2, HSQLDB, POSTGRES }) + WithAsStep with(String alias, Function, ? extends String> fieldNameFunction); + + // [jooq-tools] START [with] /** diff --git a/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionImpl.java b/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionImpl.java index bd92eb69e7..48f5781263 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CommonTableExpressionImpl.java @@ -57,11 +57,11 @@ final class CommonTableExpressionImpl extends AbstractTable /** * Generated UID */ - private static final long serialVersionUID = 2520235151216758958L; + private static final long serialVersionUID = 2520235151216758958L; private final DerivedColumnListImpl name; - private final Select select; - private final Fields fields; + private final Select select; + private final Fields fields; CommonTableExpressionImpl(DerivedColumnListImpl name, Select select) { super(name.name); diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index e4e3696042..41dfa9d875 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -699,6 +699,29 @@ public class DSL { return new WithImpl(null, false).with(alias, fieldAliases); } + + /** + * Create a WITH clause to supply subsequent + * SELECT, UPDATE, INSERT, + * DELETE, and MERGE statements with + * {@link CommonTableExpression}s. + *

+ * The RECURSIVE keyword may be optional or unsupported in some + * databases, in case of which it will not be rendered. For optimal database + * interoperability and readability, however, it is suggested that you use + * {@link #with(String, String...)} for strictly non-recursive CTE and + * {@link #withRecursive(String, String...)} for strictly recursive CTE. + *

+ * This works in a similar way as {@link #with(String, String...)}, except + * that all column names are produced by a function that receives the CTE's + * {@link Select} columns as input. + */ + @Support({ FIREBIRD, HSQLDB, POSTGRES }) + public static WithAsStep with(String alias, Function, ? extends String> fieldNameFunction) { + return new WithImpl(null, false).with(alias, fieldNameFunction); + } + + // [jooq-tools] START [with] /** @@ -1189,6 +1212,33 @@ public class DSL { return new WithImpl(null, true).with(alias, fieldAliases); } + + /** + * Create a WITH clause to supply subsequent + * SELECT, UPDATE, INSERT, + * DELETE, and MERGE statements with + * {@link CommonTableExpression}s. + *

+ * The RECURSIVE keyword may be optional or unsupported in some + * databases, in case of which it will not be rendered. For optimal database + * interoperability and readability, however, it is suggested that you use + * {@link #with(String, String...)} for strictly non-recursive CTE + * and {@link #withRecursive(String, String...)} for strictly + * recursive CTE. + *

+ * Note that the {@link SQLDialect#H2} database only supports single-table, + * RECURSIVE common table expression lists. + *

+ * This works in a similar way as {@link #with(String, String...)}, except + * that all column names are produced by a function that receives the CTE's + * {@link Select} columns as input. + */ + @Support({ FIREBIRD, H2, HSQLDB, POSTGRES }) + public static WithAsStep withRecursive(String alias, Function, ? extends String> fieldNameFunction) { + return new WithImpl(null, true).with(alias, fieldNameFunction); + } + + // [jooq-tools] START [with-recursive] /** diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java index 1ea602e796..e5059a2a77 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java @@ -1387,6 +1387,13 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri return new WithImpl(configuration(), false).with(alias, fieldAliases); } + + @Override + public WithAsStep with(String alias, Function, ? extends String> fieldNameFunction) { + return new WithImpl(configuration(), false).with(alias, fieldNameFunction); + } + + // [jooq-tools] START [with] @Generated("This method was generated using jOOQ-tools") @@ -1538,6 +1545,13 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri return new WithImpl(configuration(), true).with(alias, fieldAliases); } + + @Override + public WithAsStep withRecursive(String alias, Function, ? extends String> fieldNameFunction) { + return new WithImpl(configuration(), true).with(alias, fieldNameFunction); + } + + // [jooq-tools] START [with-recursive] @Generated("This method was generated using jOOQ-tools") diff --git a/jOOQ/src/main/java/org/jooq/impl/DerivedColumnListImpl.java b/jOOQ/src/main/java/org/jooq/impl/DerivedColumnListImpl.java index 8841d59e9b..5782a7383e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DerivedColumnListImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DerivedColumnListImpl.java @@ -42,6 +42,8 @@ package org.jooq.impl; import static org.jooq.impl.DSL.name; +import java.util.function.Function; + import org.jooq.Clause; import org.jooq.CommonTableExpression; import org.jooq.Context; @@ -68,6 +70,7 @@ import org.jooq.DerivedColumnList6; import org.jooq.DerivedColumnList7; import org.jooq.DerivedColumnList8; import org.jooq.DerivedColumnList9; +import org.jooq.Field; import org.jooq.Select; /** @@ -107,20 +110,45 @@ implements /** * Gemerated UID */ - private static final long serialVersionUID = -369633206858851863L; + private static final long serialVersionUID = -369633206858851863L; + + final String name; + final String[] fieldNames; + + final Function, ? extends String> fieldNameFunction; - final String name; - final String[] fieldNames; DerivedColumnListImpl(String name, String[] fieldNames) { this.name = name; this.fieldNames = fieldNames; + + this.fieldNameFunction = null; + } + + DerivedColumnListImpl(String name, Function, ? extends String> fieldNameFunction) { + this.name = name; + this.fieldNames = null; + this.fieldNameFunction = fieldNameFunction; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public final CommonTableExpression as(Select select) { - return new CommonTableExpressionImpl(this, select); + Select s = select; + + + if (fieldNameFunction != null) { + return new CommonTableExpressionImpl( + new DerivedColumnListImpl(name, s.getSelect().stream().map(fieldNameFunction).toArray(String[]::new)), + s + ); + } + + + return new CommonTableExpressionImpl(this, s); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/NameImpl.java b/jOOQ/src/main/java/org/jooq/impl/NameImpl.java index 79cac5b6a8..8e9a3ac8a6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/NameImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/NameImpl.java @@ -41,12 +41,14 @@ package org.jooq.impl; import java.util.Arrays; +import java.util.function.Function; import javax.annotation.Generated; import org.jooq.Clause; import org.jooq.CommonTableExpression; import org.jooq.Context; +import org.jooq.Field; import org.jooq.Name; import org.jooq.Record; import org.jooq.Select; @@ -120,6 +122,15 @@ final class NameImpl extends AbstractQueryPart implements Name { return new DerivedColumnListImpl(qualifiedName[0], fieldNames); } + + + @Override + public final DerivedColumnListImpl fields(Function, ? extends String> fieldNameFunction) { + return new DerivedColumnListImpl(qualifiedName[0], fieldNameFunction); + } + + + // [jooq-tools] START [fields] @Generated("This method was generated using jOOQ-tools") diff --git a/jOOQ/src/main/java/org/jooq/impl/WithImpl.java b/jOOQ/src/main/java/org/jooq/impl/WithImpl.java index 786eff8fde..5961dfc4a1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/WithImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/WithImpl.java @@ -52,6 +52,7 @@ import static org.jooq.impl.DSL.zero; import java.util.Arrays; import java.util.Collection; +import java.util.function.Function; import javax.annotation.Generated; @@ -158,17 +159,20 @@ implements /** * Generated UID */ - private static final long serialVersionUID = -1813359431778402705L; - private static final Clause[] CLAUSES = { WITH }; + private static final long serialVersionUID = -1813359431778402705L; + private static final Clause[] CLAUSES = { WITH }; - private final CommonTableExpressionList cte; - private final boolean recursive; - private Configuration configuration; + private final CommonTableExpressionList cte; + private final boolean recursive; + private Configuration configuration; // Intermediary properties for CTE construction - private String alias; - private String[] fieldAliases; + private String alias; + private String[] fieldAliases; + + private Function, ? extends String> fieldNameFunction; + WithImpl(Configuration configuration, boolean recursive) { this.configuration = configuration; @@ -205,11 +209,20 @@ implements @Override public final WithStep as(Select select) { - cte.add(name(alias).fields(fieldAliases).as(select)); + + + if (fieldNameFunction != null) + cte.add(name(alias).fields(fieldNameFunction).as(select)); + else + + cte.add(name(alias).fields(fieldAliases).as(select)); this.alias = null; this.fieldAliases = null; + this.fieldNameFunction = null; + + return this; } @@ -226,6 +239,16 @@ implements return this; } + + @Override + public final WithAsStep with(String a, Function, ? extends String> f) { + this.alias = a; + this.fieldNameFunction = f; + + return this; + } + + // [jooq-tools] START [with] @Override