diff --git a/jOOQ/src/main/java/org/jooq/impl/DMLQueryAsResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQueryAsResultQuery.java similarity index 93% rename from jOOQ/src/main/java/org/jooq/impl/DMLQueryAsResultQuery.java rename to jOOQ/src/main/java/org/jooq/impl/AbstractDMLQueryAsResultQuery.java index 4c0d5be814..057f1531b3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DMLQueryAsResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQueryAsResultQuery.java @@ -77,22 +77,18 @@ import org.jetbrains.annotations.NotNull; * * @author Lukas Eder */ -final class DMLQueryAsResultQuery> +abstract class AbstractDMLQueryAsResultQuery> extends AbstractQueryPart implements - ResultQueryTrait, - DeleteResultStep, - UpdateResultStep, - InsertResultStep, - UNotYetImplemented + ResultQueryTrait { - private final Q delegate; - private final boolean returningResult; - private Table coerceTable; - private Collection> coerceFields; + final Q delegate; + final boolean returningResult; + Table coerceTable; + Collection> coerceFields; - DMLQueryAsResultQuery(Q delegate, boolean returningResult) { + AbstractDMLQueryAsResultQuery(Q delegate, boolean returningResult) { this.delegate = delegate; this.returningResult = returningResult; } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPartMap.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPartMap.java index a4a00d914a..0c3e7af906 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPartMap.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQueryPartMap.java @@ -37,28 +37,44 @@ */ package org.jooq.impl; +import static org.jooq.impl.QOM.tuple; +import static org.jooq.impl.QOM.unmodifiable; +import static org.jooq.impl.Tools.map; + import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import java.util.function.Function; import org.jooq.Context; import org.jooq.QueryPart; +// ... +// ... +import org.jooq.impl.QOM.Tuple2; +import org.jooq.impl.QOM.UnmodifiableList; /** * @author Lukas Eder */ -abstract class AbstractQueryPartMap +abstract sealed class AbstractQueryPartMap extends AbstractQueryPart implements - Map + QOM.UnmodifiableMap +permits + FieldMapForUpdate, + QueryPartMapView { private final Map map; AbstractQueryPartMap() { - map = new LinkedHashMap<>(); + this(new LinkedHashMap<>()); + } + + AbstractQueryPartMap(Map map) { + this.map = map; } // ------------------------------------------------------------------------- @@ -131,4 +147,42 @@ implements public final Set> entrySet() { return map.entrySet(); } + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + @Override + public final UnmodifiableList> $tuples() { + return unmodifiable(map(entrySet(), e -> tuple(e.getKey(), e.getValue()))); + } + + abstract Function, ? extends AbstractQueryPartMap> $construct(); + + + + + + + + + + + + + + + + + + + + + + + + + + + } diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java index 8073081a91..2fcfdae0d0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java @@ -65,7 +65,7 @@ import org.jooq.Record1; // ... import org.jooq.Select; import org.jooq.impl.QOM.CaseSearched; -import org.jooq.impl.QOM.UTuple2; +import org.jooq.impl.QOM.Tuple2; import org.jooq.impl.QOM.UnmodifiableList; /** @@ -79,7 +79,7 @@ implements QOM.CaseSearched { - private final List>> when; + private final List>> when; private Field else_; CaseConditionStepImpl(DataType type) { @@ -223,7 +223,7 @@ implements ctx.visit(K_CASE) .formatIndentStart(); - for (UTuple2> e : when) { + for (Tuple2> e : when) { Condition c = e.$1(); @@ -263,7 +263,7 @@ implements // ------------------------------------------------------------------------- @Override - public final Function2>>, ? super Field, ? extends CaseSearched> $constructor() { + public final Function2>>, ? super Field, ? extends CaseSearched> $constructor() { return (w, e) -> { CaseConditionStepImpl r = new CaseConditionStepImpl<>(getDataType()); w.forEach(t -> r.when(t.$1(), t.$2())); @@ -273,12 +273,12 @@ implements } @Override - public final UnmodifiableList>> $arg1() { + public final UnmodifiableList>> $arg1() { return QOM.unmodifiable(when); } @Override - public final CaseSearched $arg1(UnmodifiableList>> w) { + public final CaseSearched $arg1(UnmodifiableList>> w) { return $constructor().apply(w, $else()); } diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java index efba407f3f..f792548cf0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java @@ -61,7 +61,7 @@ import org.jooq.Field; import org.jooq.Function3; // ... import org.jooq.impl.QOM.CaseSimple; -import org.jooq.impl.QOM.UTuple2; +import org.jooq.impl.QOM.Tuple2; import org.jooq.impl.QOM.UnmodifiableList; /** @@ -76,7 +76,7 @@ implements { private final Field value; - private final List, Field>> when; + private final List, Field>> when; private Field else_; CaseWhenStepImpl(Field value, Field compareValue, Field result) { @@ -237,7 +237,7 @@ implements private final void acceptSearched(Context ctx) { CaseConditionStep w = null; - for (UTuple2, Field> e : when) + for (Tuple2, Field> e : when) if (w == null) w = DSL.when(value.eq(e.$1()), e.$2()); else @@ -257,7 +257,7 @@ implements .visit(value) .formatIndentStart(); - for (UTuple2, Field> e : when) + for (Tuple2, Field> e : when) ctx.formatSeparator() .visit(K_WHEN).sql(' ') .visit(e.$1()).sql(' ') @@ -282,7 +282,7 @@ implements // ------------------------------------------------------------------------- @Override - public final Function3, ? super UnmodifiableList, Field>>, ? super Field, ? extends CaseSimple> $constructor() { + public final Function3, ? super UnmodifiableList, Field>>, ? super Field, ? extends CaseSimple> $constructor() { return (v, w, e) -> { CaseWhenStepImpl r = new CaseWhenStepImpl<>(v, getDataType()); w.forEach(t -> r.when(t.$1(), t.$2())); @@ -302,12 +302,12 @@ implements } @Override - public final UnmodifiableList, Field>> $arg2() { + public final UnmodifiableList, Field>> $arg2() { return QOM.unmodifiable(when); } @Override - public final CaseSimple $arg2(UnmodifiableList, Field>> w) { + public final CaseSimple $arg2(UnmodifiableList, Field>> w) { return $constructor().apply($value(), w, $else()); } diff --git a/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java b/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java index cb722f486a..38eb75a6c3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java @@ -73,6 +73,15 @@ final class ConditionProviderImpl extends AbstractField implements Cond this.condition = condition; } + static final Condition extractCondition(Condition c) { + + // join(..).on(..).and(..) uses some identity tricks to keep the right + // reference to the mutable ConditionProviderImpl instance, which we + // must take into account here. + return c instanceof ConditionProviderImpl cp ? cp.getWhere() : c; + } + + @Nullable final Condition getWhereOrNull() { return hasWhere() ? condition : null; diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteAsResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/DeleteAsResultQuery.java new file mode 100644 index 0000000000..7dfd1b2dd0 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/DeleteAsResultQuery.java @@ -0,0 +1,116 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import java.util.Collection; + +import org.jooq.DeleteResultStep; +import org.jooq.QueryPart; +import org.jooq.Record; +// ... +import org.jooq.ResultQuery; +import org.jooq.SelectFieldOrAsterisk; +// ... +import org.jooq.impl.QOM.Delete; +import org.jooq.impl.QOM.DeleteReturning; +import org.jooq.impl.QOM.UnmodifiableList; + +/** + * A wrapped {@link Delete} that works like a {@link ResultQuery}. + * + * @author Lukas Eder + */ +final class DeleteAsResultQuery +extends + AbstractDMLQueryAsResultQuery> +implements + DeleteResultStep, + QOM.DeleteReturning +{ + + DeleteAsResultQuery(DeleteQueryImpl delegate, boolean returningResult) { + super(delegate, returningResult); + } + + @Override + public final Delete $delete() { + return getDelegate(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public final DeleteReturning $delete(Delete newDelete) { + return new DeleteAsResultQuery(Tools.deleteQueryImpl(newDelete).copy(d -> d.setReturning($returning())), returningResult); + } + + @Override + public final UnmodifiableList $returning() { + return QOM.unmodifiable(getDelegate().returning); + } + + @Override + public final DeleteReturning $returning(Collection returning) { + return new DeleteAsResultQuery<>(getDelegate().copy(d -> d.setReturning(returning)), returningResult); + } + + + + + + + + + + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteImpl.java index b1c8805c1a..cb9614a049 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeleteImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeleteImpl.java @@ -54,7 +54,6 @@ import org.jooq.Field; import org.jooq.Name; import org.jooq.Operator; import org.jooq.OrderField; -import org.jooq.Param; import org.jooq.QueryPart; import org.jooq.Record; import org.jooq.Record1; @@ -79,24 +78,33 @@ import org.jooq.Record6; import org.jooq.Record7; import org.jooq.Record8; import org.jooq.Record9; +// ... import org.jooq.SQL; import org.jooq.Select; import org.jooq.SelectField; import org.jooq.SelectFieldOrAsterisk; +import org.jooq.SortField; import org.jooq.Table; import org.jooq.TableLike; +// ... +import org.jooq.impl.QOM.Delete; +import org.jooq.impl.QOM.UnmodifiableList; +import org.jooq.impl.QOM.With; /** * @author Lukas Eder */ @SuppressWarnings({ "rawtypes", "unchecked" }) final class DeleteImpl - extends AbstractDelegatingDMLQuery> - implements +extends + AbstractDelegatingDMLQuery> +implements // Cascading interface implementations for Delete behaviour DeleteUsingStep, - DeleteConditionStep { + DeleteConditionStep, + QOM.Delete +{ private boolean returningResult; DeleteImpl(Configuration configuration, WithImpl with, Table table) { @@ -333,33 +341,33 @@ final class DeleteImpl @Override public final DeleteResultStep returning() { getDelegate().setReturning(); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new DeleteAsResultQuery<>(getDelegate(), returningResult); } @Override public final DeleteResultStep returning(SelectFieldOrAsterisk... f) { getDelegate().setReturning(f); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new DeleteAsResultQuery<>(getDelegate(), returningResult); } @Override public final DeleteResultStep returning(Collection f) { getDelegate().setReturning(f); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new DeleteAsResultQuery<>(getDelegate(), returningResult); } @Override public final DeleteResultStep returningResult(SelectFieldOrAsterisk... f) { returningResult = true; getDelegate().setReturning(f); - return new DMLQueryAsResultQuery(getDelegate(), returningResult); + return new DeleteAsResultQuery(getDelegate(), returningResult); } @Override public final DeleteResultStep returningResult(Collection f) { returningResult = true; getDelegate().setReturning(f); - return new DMLQueryAsResultQuery(getDelegate(), returningResult); + return new DeleteAsResultQuery(getDelegate(), returningResult); } @@ -475,4 +483,77 @@ final class DeleteImpl } + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + @Override + public final With $with() { + return getDelegate().$with(); + } + + @Override + public final Table $from() { + return getDelegate().$from(); + } + + @Override + public final Delete $from(Table from) { + return getDelegate().$from(from); + } + + @Override + public final UnmodifiableList> $using() { + return getDelegate().$using(); + } + + @Override + public final Delete $using(Collection> using) { + return getDelegate().$using(using); + } + + @Override + public final Condition $where() { + return getDelegate().$where(); + } + + @Override + public final Delete $where(Condition condition) { + return getDelegate().$where(condition); + } + + @Override + public final UnmodifiableList> $orderBy() { + return getDelegate().$orderBy(); + } + + @Override + public final Delete $orderBy(Collection> orderBy) { + return getDelegate().$orderBy(orderBy); + } + + @Override + public final Field $limit() { + return getDelegate().$limit(); + } + + @Override + public final Delete $limit(Field limit) { + return getDelegate().$limit(limit); + } + + + + + + + + + + + + + + } diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java index de750b27aa..d1df2b501f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java @@ -50,7 +50,6 @@ import static org.jooq.Clause.DELETE_WHERE; // ... import static org.jooq.SQLDialect.CUBRID; // ... -// ... import static org.jooq.SQLDialect.DERBY; // ... import static org.jooq.SQLDialect.FIREBIRD; @@ -75,6 +74,7 @@ import static org.jooq.SQLDialect.SQLITE; // ... import static org.jooq.SQLDialect.YUGABYTEDB; import static org.jooq.conf.SettingsTools.getExecuteDeleteWithoutWhere; +import static org.jooq.impl.ConditionProviderImpl.extractCondition; import static org.jooq.impl.DSL.row; import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.trueCondition; @@ -90,6 +90,7 @@ import static org.jooq.impl.Tools.traverseJoins; import java.util.Arrays; import java.util.Collection; import java.util.Set; +import java.util.function.Consumer; import org.jooq.Clause; import org.jooq.Condition; @@ -99,20 +100,31 @@ import org.jooq.DeleteQuery; import org.jooq.Field; import org.jooq.Operator; import org.jooq.OrderField; -import org.jooq.Param; // ... +import org.jooq.QueryPart; import org.jooq.Record; +// ... import org.jooq.SQLDialect; import org.jooq.Scope; +import org.jooq.SelectFieldOrAsterisk; +import org.jooq.SortField; import org.jooq.Table; import org.jooq.TableLike; +// ... import org.jooq.conf.ParamType; -import org.jooq.impl.QOM.UNotYetImplemented; +import org.jooq.impl.QOM.Delete; +import org.jooq.impl.QOM.UnmodifiableList; /** * @author Lukas Eder */ -final class DeleteQueryImpl extends AbstractDMLQuery implements DeleteQuery, UNotYetImplemented { +final class DeleteQueryImpl +extends + AbstractDMLQuery +implements + DeleteQuery, + QOM.Delete +{ private static final Clause[] CLAUSES = { DELETE }; private static final Set SPECIAL_DELETE_AS_SYNTAX = SQLDialect.supportedBy(MARIADB, MYSQL); @@ -355,6 +367,136 @@ final class DeleteQueryImpl extends AbstractDMLQuery implem return super.isExecutable(); } + + + + + + + + + + + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + final DeleteQueryImpl copy(Consumer> finisher) { + return copy(finisher, table); + } + + final DeleteQueryImpl copy(Consumer> finisher, Table t) { + DeleteQueryImpl r = new DeleteQueryImpl<>(configuration(), with, t); + r.using.addAll(using); + r.condition.addConditions(extractCondition(condition)); + r.orderBy.addAll(orderBy); + r.limit = limit; + r.setReturning(returning); + finisher.accept(r); + return r; + } + + @Override + public final WithImpl $with() { + return with; + } + + @Override + public final Table $from() { + return table; + } + + @Override + public final Delete $from(Table newFrom) { + if ($from() == newFrom) + return this; + else + return copy(d -> {}, newFrom); + } + + @Override + public final UnmodifiableList> $using() { + return QOM.unmodifiable(using); + } + + @Override + public final Delete $using(Collection> using) { + return copy(d -> { + d.using.clear(); + d.using.addAll(using); + }); + } + + @Override + public final Condition $where() { + return condition.getWhereOrNull(); + } + + @Override + public final Delete $where(Condition newWhere) { + if ($where() == newWhere) + return this; + else + return copy(d -> d.condition.setWhere(newWhere)); + } + + @Override + public final UnmodifiableList> $orderBy() { + return QOM.unmodifiable(orderBy); + } + + @Override + public final Delete $orderBy(Collection> newOrderBy) { + return copy(d -> { + d.orderBy.clear(); + d.orderBy.addAll(newOrderBy); + }); + } + + @Override + public final Field $limit() { + return limit; + } + + @Override + public final Delete $limit(Field newLimit) { + if ($limit() == newLimit) + return this; + else + return copy(d -> d.limit = newLimit); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java index 5665eff0b8..ac24c7d923 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java @@ -94,6 +94,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import org.jooq.Clause; import org.jooq.Condition; @@ -115,7 +116,10 @@ import org.jooq.impl.QOM.UNotYetImplemented; /** * @author Lukas Eder */ -final class FieldMapForUpdate extends AbstractQueryPartMap implements UNotYetImplemented { +final class FieldMapForUpdate +extends + AbstractQueryPartMap +{ static final Set CASTS_NEEDED = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB); static final Set NO_SUPPORT_QUALIFY = SQLDialect.supportedBy(POSTGRES, SQLITE, YUGABYTEDB); @@ -510,4 +514,17 @@ final class FieldMapForUpdate extends AbstractQueryPartMap, ? extends AbstractQueryPartMap> $construct() { + return m -> { + FieldMapForUpdate r = new FieldMapForUpdate(table, setClause, assignmentClause); + r.putAll(m); + return r; + }; + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java index 9b2a7c9bb5..2e6694734f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java @@ -117,6 +117,13 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple this.empty = new LinkedHashMap<>(); } + void clear() { + empty.clear(); + values.clear(); + rows = 0; + nextRow = -1; + } + // ------------------------------------------------------------------------- // The QueryPart API // ------------------------------------------------------------------------- diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertAsResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/InsertAsResultQuery.java new file mode 100644 index 0000000000..91d40ea5d6 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/InsertAsResultQuery.java @@ -0,0 +1,119 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import java.util.Collection; + +import org.jooq.DeleteResultStep; +import org.jooq.InsertResultStep; +import org.jooq.QueryPart; +import org.jooq.Record; +// ... +import org.jooq.ResultQuery; +import org.jooq.SelectFieldOrAsterisk; +// ... +import org.jooq.Update; +import org.jooq.impl.QOM.Insert; +import org.jooq.impl.QOM.InsertReturning; +import org.jooq.impl.QOM.UnmodifiableList; + +/** + * A wrapped DML query ({@link Insert}, {@link Update}, {@link Delete}) that + * works like a {@link ResultQuery}. + * + * @author Lukas Eder + */ +final class InsertAsResultQuery +extends + AbstractDMLQueryAsResultQuery> +implements + InsertResultStep, + QOM.InsertReturning +{ + + InsertAsResultQuery(InsertQueryImpl delegate, boolean returningResult) { + super(delegate, returningResult); + } + + @Override + public final Insert $insert() { + return getDelegate(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public final InsertReturning $insert(Insert newInsert) { + return new InsertAsResultQuery(Tools.insertQueryImpl(newInsert).copy(i -> i.setReturning($returning())), returningResult); + } + + @Override + public final UnmodifiableList $returning() { + return QOM.unmodifiable(getDelegate().returning); + } + + @Override + public final InsertReturning $returning(Collection returning) { + return new InsertAsResultQuery<>(getDelegate().copy(i -> i.setReturning(returning)), returningResult); + } + + + + + + + + + + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java index c3c101a422..88954f0fc3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java @@ -54,22 +54,15 @@ import org.jooq.Configuration; import org.jooq.Constraint; import org.jooq.Field; import org.jooq.FieldLike; +import org.jooq.FieldOrRow; +import org.jooq.FieldOrRowOrSelect; import org.jooq.InsertOnConflictConditionStep; import org.jooq.InsertOnConflictWhereIndexPredicateStep; import org.jooq.InsertOnDuplicateSetMoreStep; import org.jooq.InsertResultStep; import org.jooq.InsertSetMoreStep; import org.jooq.InsertSetStep; -import org.jooq.InsertValuesStepN; import org.jooq.InsertValuesStep1; -import org.jooq.InsertValuesStep2; -import org.jooq.InsertValuesStep3; -import org.jooq.InsertValuesStep4; -import org.jooq.InsertValuesStep5; -import org.jooq.InsertValuesStep6; -import org.jooq.InsertValuesStep7; -import org.jooq.InsertValuesStep8; -import org.jooq.InsertValuesStep9; import org.jooq.InsertValuesStep10; import org.jooq.InsertValuesStep11; import org.jooq.InsertValuesStep12; @@ -80,22 +73,23 @@ import org.jooq.InsertValuesStep16; import org.jooq.InsertValuesStep17; import org.jooq.InsertValuesStep18; import org.jooq.InsertValuesStep19; +import org.jooq.InsertValuesStep2; import org.jooq.InsertValuesStep20; import org.jooq.InsertValuesStep21; import org.jooq.InsertValuesStep22; +import org.jooq.InsertValuesStep3; +import org.jooq.InsertValuesStep4; +import org.jooq.InsertValuesStep5; +import org.jooq.InsertValuesStep6; +import org.jooq.InsertValuesStep7; +import org.jooq.InsertValuesStep8; +import org.jooq.InsertValuesStep9; +import org.jooq.InsertValuesStepN; import org.jooq.Name; import org.jooq.Operator; import org.jooq.QueryPart; import org.jooq.Record; import org.jooq.Record1; -import org.jooq.Record2; -import org.jooq.Record3; -import org.jooq.Record4; -import org.jooq.Record5; -import org.jooq.Record6; -import org.jooq.Record7; -import org.jooq.Record8; -import org.jooq.Record9; import org.jooq.Record10; import org.jooq.Record11; import org.jooq.Record12; @@ -106,20 +100,20 @@ import org.jooq.Record16; import org.jooq.Record17; import org.jooq.Record18; import org.jooq.Record19; +import org.jooq.Record2; import org.jooq.Record20; import org.jooq.Record21; import org.jooq.Record22; +import org.jooq.Record3; +import org.jooq.Record4; +import org.jooq.Record5; +import org.jooq.Record6; +import org.jooq.Record7; +import org.jooq.Record8; +import org.jooq.Record9; +// ... import org.jooq.Row; -import org.jooq.RowN; import org.jooq.Row1; -import org.jooq.Row2; -import org.jooq.Row3; -import org.jooq.Row4; -import org.jooq.Row5; -import org.jooq.Row6; -import org.jooq.Row7; -import org.jooq.Row8; -import org.jooq.Row9; import org.jooq.Row10; import org.jooq.Row11; import org.jooq.Row12; @@ -130,15 +124,28 @@ import org.jooq.Row16; import org.jooq.Row17; import org.jooq.Row18; import org.jooq.Row19; +import org.jooq.Row2; import org.jooq.Row20; import org.jooq.Row21; import org.jooq.Row22; +import org.jooq.Row3; +import org.jooq.Row4; +import org.jooq.Row5; +import org.jooq.Row6; +import org.jooq.Row7; +import org.jooq.Row8; +import org.jooq.Row9; +import org.jooq.RowN; import org.jooq.SQL; import org.jooq.Select; import org.jooq.SelectField; import org.jooq.SelectFieldOrAsterisk; import org.jooq.Table; +// ... import org.jooq.UniqueKey; +import org.jooq.impl.QOM.Insert; +import org.jooq.impl.QOM.UnmodifiableList; +import org.jooq.impl.QOM.UnmodifiableMap; /** * @author Lukas Eder @@ -176,7 +183,9 @@ final class InsertImpl, InsertOnDuplicateSetMoreStep, InsertOnConflictWhereIndexPredicateStep, - InsertOnConflictConditionStep { + InsertOnConflictConditionStep, + QOM.Insert +{ private final Table into; private Field[] fields; @@ -1417,33 +1426,33 @@ final class InsertImpl returning() { getDelegate().setReturning(); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new InsertAsResultQuery<>(getDelegate(), returningResult); } @Override public final InsertResultStep returning(SelectFieldOrAsterisk... f) { getDelegate().setReturning(f); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new InsertAsResultQuery<>(getDelegate(), returningResult); } @Override public final InsertResultStep returning(Collection f) { getDelegate().setReturning(f); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new InsertAsResultQuery<>(getDelegate(), returningResult); } @Override public final InsertResultStep returningResult(SelectFieldOrAsterisk... f) { returningResult = true; getDelegate().setReturning(f); - return new DMLQueryAsResultQuery(getDelegate(), returningResult); + return new InsertAsResultQuery(getDelegate(), returningResult); } @Override public final InsertResultStep returningResult(Collection f) { returningResult = true; getDelegate().setReturning(f); - return new DMLQueryAsResultQuery(getDelegate(), returningResult); + return new InsertAsResultQuery(getDelegate(), returningResult); } @Override @@ -1577,4 +1586,138 @@ final class InsertImpl InsertResultStep> returningResult(SelectField field1, SelectField field2, SelectField field3, SelectField field4, SelectField field5, SelectField field6, SelectField field7, SelectField field8, SelectField field9, SelectField field10, SelectField field11, SelectField field12, SelectField field13, SelectField field14, SelectField field15, SelectField field16, SelectField field17, SelectField field18, SelectField field19, SelectField field20, SelectField field21, SelectField field22) { return (InsertResultStep) returningResult(new SelectField[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20, field21, field22 }); } + + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + @Override + public final WithImpl $with() { + return getDelegate().$with(); + } + + @Override + public final Table $into() { + return getDelegate().$into(); + } + + @Override + public final Insert $into(Table newInto) { + return getDelegate().$into(newInto); + } + + @Override + public final UnmodifiableList> $columns() { + return getDelegate().$columns(); + } + + @Override + public final Insert $columns(Collection> columns) { + return getDelegate().$columns(columns); + } + + @Override + public final Select $select() { + return getDelegate().$select(); + } + + @Override + public final Insert $select(Select select) { + return getDelegate().$select(select); + } + + @Override + public final boolean $defaultValues() { + return getDelegate().$defaultValues(); + } + + @Override + public final Insert $defaultValues(boolean defaultValues) { + return getDelegate().$defaultValues(defaultValues); + } + + @Override + public final UnmodifiableList $values() { + return getDelegate().$values(); + } + + @Override + public final Insert $values(Collection values) { + return getDelegate().$values(values); + } + + @Override + public final boolean $onDuplicateKeyIgnore() { + return getDelegate().$onDuplicateKeyIgnore(); + } + + @Override + public final Insert $onDuplicateKeyIgnore(boolean onDuplicateKeyIgnore) { + return getDelegate().$onDuplicateKeyIgnore(onDuplicateKeyIgnore); + } + + @Override + public boolean $onDuplicateKeyUpdate() { + return getDelegate().$onDuplicateKeyUpdate(); + } + + @Override + public final Insert $onDuplicateKeyUpdate(boolean onDuplicateKeyUpdate) { + return getDelegate().$onDuplicateKeyUpdate(onDuplicateKeyUpdate); + } + + @Override + public final UnmodifiableList> $onConflict() { + return getDelegate().$onConflict(); + } + + @Override + public final Insert $onConflict(Collection> onConflictFields) { + return getDelegate().$onConflict(onConflictFields); + } + + @Override + public final Condition $onConflictWhere() { + return getDelegate().$onConflictWhere(); + } + + @Override + public final Insert $onConflictWhere(Condition where) { + return getDelegate().$onConflictWhere(where); + } + + @Override + public final UnmodifiableMap $updateSet() { + return getDelegate().$updateSet(); + } + + @Override + public final Insert $updateSet(Map updateSet) { + return getDelegate().$updateSet(updateSet); + } + + @Override + public final Condition $updateWhere() { + return getDelegate().$updateWhere(); + } + + @Override + public final Insert $updateWhere(Condition where) { + return getDelegate().$updateWhere(where); + } + + + + + + + + + + + + + + } diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index 05bc5a3a2d..16c53b31aa 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -62,6 +62,7 @@ import static org.jooq.SQLDialect.SQLITE; // ... // ... import static org.jooq.conf.ParamType.INLINED; +import static org.jooq.impl.ConditionProviderImpl.extractCondition; import static org.jooq.impl.DSL.constraint; import static org.jooq.impl.DSL.falseCondition; import static org.jooq.impl.DSL.name; @@ -108,6 +109,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.Consumer; import java.util.Set; import org.jooq.Clause; @@ -116,6 +118,8 @@ import org.jooq.Configuration; import org.jooq.Constraint; import org.jooq.Context; import org.jooq.Field; +import org.jooq.FieldOrRow; +import org.jooq.FieldOrRowOrSelect; import org.jooq.GeneratorStatementType; import org.jooq.Identity; import org.jooq.InsertQuery; @@ -126,20 +130,30 @@ import org.jooq.Operator; // ... import org.jooq.QueryPart; import org.jooq.Record; +// ... +import org.jooq.Row; import org.jooq.SQLDialect; import org.jooq.Scope; import org.jooq.Select; import org.jooq.Table; import org.jooq.TableField; +// ... import org.jooq.UniqueKey; import org.jooq.conf.ParamType; import org.jooq.conf.WriteIfReadonly; import org.jooq.impl.FieldMapForUpdate.SetClause; +import org.jooq.impl.QOM.Insert; import org.jooq.impl.QOM.UNotYetImplemented; +import org.jooq.impl.QOM.UnmodifiableList; +import org.jooq.impl.QOM.UnmodifiableMap; +import org.jooq.impl.QOM.With; import org.jooq.impl.Tools.BooleanDataKey; import org.jooq.impl.Tools.ExtendedDataKey; import org.jooq.tools.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + /** * @author Lukas Eder */ @@ -148,7 +162,7 @@ extends AbstractStoreQuery, Field> implements InsertQuery, - UNotYetImplemented + QOM.Insert { static final Clause[] CLAUSES = { INSERT }; @@ -158,7 +172,6 @@ implements static final Set NO_SUPPORT_SUBQUERY_IN_MERGE_USING = SQLDialect.supportedBy(DERBY); static final Set REQUIRE_NEW_MYSQL_EXCLUDED_EMULATION = SQLDialect.supportedBy(MYSQL); - final FieldMapForUpdate updateMap; final FieldMapsForInsert insertMaps; Select select; boolean defaultValues; @@ -168,15 +181,16 @@ implements UniqueKey onConstraintUniqueKey; QueryPartList> onConflict; final ConditionProviderImpl onConflictWhere; - final ConditionProviderImpl condition; + final FieldMapForUpdate updateMap; + final ConditionProviderImpl updateWhere; InsertQueryImpl(Configuration configuration, WithImpl with, Table into) { super(configuration, with, into); - this.updateMap = new FieldMapForUpdate(into, SetClause.INSERT, INSERT_ON_DUPLICATE_KEY_UPDATE_ASSIGNMENT); this.insertMaps = new FieldMapsForInsert(into); this.onConflictWhere = new ConditionProviderImpl(); - this.condition = new ConditionProviderImpl(); + this.updateMap = new FieldMapForUpdate(into, SetClause.INSERT, INSERT_ON_DUPLICATE_KEY_UPDATE_ASSIGNMENT); + this.updateWhere = new ConditionProviderImpl(); } @Override @@ -246,14 +260,31 @@ implements @Override public final void onDuplicateKeyUpdate(boolean flag) { - this.onDuplicateKeyIgnore = false; - this.onDuplicateKeyUpdate = flag; + onDuplicateKeyUpdate = flag; + + if (flag) { + onDuplicateKeyIgnore = false; + clearOnConflict(); + } } @Override public final void onDuplicateKeyIgnore(boolean flag) { - this.onDuplicateKeyUpdate = false; - this.onDuplicateKeyIgnore = flag; + onDuplicateKeyIgnore = flag; + + if (flag) { + onDuplicateKeyUpdate = false; + updateMap.clear(); + updateWhere.setWhere(null); + clearOnConflict(); + } + } + + private final void clearOnConflict() { + onConflict = null; + onConflictWhere.setWhere(null); + onConstraint = null; + onConstraintUniqueKey = null; } @Override @@ -273,37 +304,38 @@ implements @Override public final void addConditions(Condition conditions) { - condition.addConditions(conditions); + updateWhere.addConditions(conditions); } @Override public final void addConditions(Condition... conditions) { - condition.addConditions(conditions); + updateWhere.addConditions(conditions); } @Override public final void addConditions(Collection conditions) { - condition.addConditions(conditions); + updateWhere.addConditions(conditions); } @Override public final void addConditions(Operator operator, Condition conditions) { - condition.addConditions(operator, conditions); + updateWhere.addConditions(operator, conditions); } @Override public final void addConditions(Operator operator, Condition... conditions) { - condition.addConditions(operator, conditions); + updateWhere.addConditions(operator, conditions); } @Override public final void addConditions(Operator operator, Collection conditions) { - condition.addConditions(operator, conditions); + updateWhere.addConditions(operator, conditions); } @Override public final void setDefaultValues() { defaultValues = true; + select = null; } private final boolean defaultValues(Configuration c) { @@ -322,6 +354,8 @@ implements @Override public final void setSelect(Collection> f, Select s) { + defaultValues = false; + insertMaps.clear(); insertMaps.addFields(f); select = s; } @@ -412,11 +446,11 @@ implements .visit(updateMapComputedOnClientStored(ctx)) .formatIndentEnd(); - if (condition.hasWhere()) + if (updateWhere.hasWhere()) ctx.formatSeparator() .visit(K_WHERE) .sql(' ') - .visit(condition); + .visit(updateWhere); ctx.end(INSERT_ON_DUPLICATE_KEY_UPDATE); } @@ -469,8 +503,8 @@ implements .qualify(newQualify); // [#8479] Emulate WHERE clause using CASE - if (condition.hasWhere()) - ctx.data(DATA_ON_DUPLICATE_KEY_WHERE, condition.getWhere()); + if (updateWhere.hasWhere()) + ctx.data(DATA_ON_DUPLICATE_KEY_WHERE, updateWhere.getWhere()); if (requireNewMySQLExcludedEmulation) { um.replaceAll((k, v) -> { @@ -484,7 +518,7 @@ implements ctx.visit(um); - if (condition.hasWhere()) + if (updateWhere.hasWhere()) ctx.data().remove(DATA_ON_DUPLICATE_KEY_WHERE); ctx.qualify(oldQualify) @@ -945,8 +979,8 @@ implements // computed column emulation um = updateMapComputedOnClientStored(ctx, um); - notMatched = condition.hasWhere() - ? on.whenMatchedAnd(condition.getWhere()).thenUpdate().set(um) + notMatched = updateWhere.hasWhere() + ? on.whenMatchedAnd(updateWhere.getWhere()).thenUpdate().set(um) : on.whenMatchedThenUpdate().set(um); } @@ -1070,6 +1104,222 @@ implements + + + + + + + + + + + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + final InsertQueryImpl copy(Consumer> finisher) { + return copy(finisher, table); + } + + final InsertQueryImpl copy(Consumer> finisher, Table t) { + InsertQueryImpl i = new InsertQueryImpl<>(configuration(), with, t); + + if (!returning.isEmpty()) + i.setReturning(returning); + + i.insertMaps.empty.putAll(insertMaps.empty); + i.insertMaps.values.putAll(insertMaps.values); + i.insertMaps.rows = insertMaps.rows; + i.insertMaps.nextRow = insertMaps.nextRow; + i.defaultValues = defaultValues; + i.select = select; + + if (onConflict != null) + i.onConflict(onConflict); + + if (onConflictWhere.hasWhere()) + i.onConflictWhere.setWhere(extractCondition(onConflictWhere)); + + i.onConstraint = onConstraint; + i.onConstraintUniqueKey = (UniqueKey) onConstraintUniqueKey; + i.onDuplicateKeyIgnore = onDuplicateKeyIgnore; + i.onDuplicateKeyUpdate = onDuplicateKeyUpdate; + i.updateWhere.setWhere(updateWhere.getWhere()); + i.updateMap.putAll(updateMap); + finisher.accept(i); + return i; + } + + @Override + public final WithImpl $with() { + return with; + } + + @Override + public final Table $into() { + return table; + } + + @Override + public final Insert $into(Table newInto) { + if ($into() == newInto) + return this; + else + return copy(i -> {}, newInto); + } + + @Override + public final UnmodifiableList> $columns() { + return QOM.unmodifiable(new ArrayList<>(insertMaps.values.keySet())); + } + + @Override + public final Insert $columns(Collection> columns) { + throw new QOM.NotYetImplementedException(); + } + + @Override + public final Select $select() { + return select; + } + + @Override + public final Insert $select(Select newSelect) { + if ($select() == newSelect) + return this; + else + return copy(i -> { + i.setSelect($columns(), newSelect); + }); + } + + @Override + public final boolean $defaultValues() { + return defaultValues; + } + + @Override + public final Insert $defaultValues(boolean newDefaultValues) { + if ($defaultValues() == newDefaultValues) + return this; + else + return copy(i -> { + if (newDefaultValues) + i.setDefaultValues(); + else + i.defaultValues = false; + }); + } + + @Override + public final UnmodifiableList $values() { + return QOM.unmodifiable(new ArrayList<>()); + } + + @Override + public final Insert $values(Collection values) { + throw new QOM.NotYetImplementedException(); + } + + @Override + public final boolean $onDuplicateKeyIgnore() { + return onDuplicateKeyIgnore; + } + + @Override + public final Insert $onDuplicateKeyIgnore(boolean newOnDuplicateKeyIgnore) { + if ($onDuplicateKeyIgnore() == newOnDuplicateKeyIgnore) + return this; + else + return copy(i -> i.onDuplicateKeyIgnore(newOnDuplicateKeyIgnore)); + } + + @Override + public final boolean $onDuplicateKeyUpdate() { + return onDuplicateKeyUpdate; + } + + @Override + public final Insert $onDuplicateKeyUpdate(boolean newOnDuplicateKeyUpdate) { + if ($onDuplicateKeyUpdate() == newOnDuplicateKeyUpdate) + return this; + else + return copy(i -> i.onDuplicateKeyUpdate(newOnDuplicateKeyUpdate)); + } + + @Override + public final UnmodifiableList> $onConflict() { + return QOM.unmodifiable(onConflict == null ? new ArrayList<>() : onConflict); + } + + @Override + public final Insert $onConflict(Collection> newOnConflict) { + if ($onConflict() == newOnConflict) + return this; + else + return copy(i -> i.onConflict(newOnConflict)); + } + + @Override + public final Condition $onConflictWhere() { + return onConflictWhere.getWhereOrNull(); + } + + @Override + public final Insert $onConflictWhere(Condition newWhere) { + if ($onConflictWhere() == newWhere) + return this; + else + return copy(i -> i.onConflictWhere.setWhere(newWhere)); + } + + @Override + public final UnmodifiableMap $updateSet() { + return QOM.unmodifiable(updateMap); + } + + @Override + public final Insert $updateSet(Map newUpdateSet) { + if ($updateSet() == newUpdateSet) + return this; + else + return copy(i -> i.addValuesForUpdate(newUpdateSet)); + } + + @Override + public final Condition $updateWhere() { + return updateWhere.getWhereOrNull(); + } + + @Override + public final Insert $updateWhere(Condition newWhere) { + if ($updateWhere() == newWhere) + return this; + else + return copy(i -> i.updateWhere.setWhere(newWhere)); + } + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/QOM.java b/jOOQ/src/main/java/org/jooq/impl/QOM.java index 0fbc1f31b5..e15f4c9330 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QOM.java +++ b/jOOQ/src/main/java/org/jooq/impl/QOM.java @@ -39,6 +39,7 @@ package org.jooq.impl; import static java.util.Collections.unmodifiableCollection; import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableMap; import static org.jooq.impl.DSL.keyword; import java.math.BigDecimal; @@ -46,7 +47,9 @@ import java.sql.Date; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.function.Predicate; @@ -64,6 +67,7 @@ import org.jooq.DatePart; import org.jooq.Domain; import org.jooq.Field; import org.jooq.FieldOrRow; +import org.jooq.FieldOrRowOrSelect; import org.jooq.Function1; import org.jooq.Function10; import org.jooq.Function11; @@ -115,13 +119,16 @@ import org.jooq.SQL; import org.jooq.SQLDialect; import org.jooq.Schema; import org.jooq.Select; +import org.jooq.SelectFieldOrAsterisk; import org.jooq.Sequence; +import org.jooq.SortField; import org.jooq.Spatial; import org.jooq.Statement; import org.jooq.Table; import org.jooq.TableElement; import org.jooq.TableLike; // ... +import org.jooq.UniqueKey; // ... import org.jooq.WindowDefinition; import org.jooq.WindowSpecification; @@ -221,16 +228,29 @@ public final class QOM { /** * A generic tuple of degree 2 for use in {@link QOM} types. */ - public sealed interface UTuple2 + public sealed interface Tuple2 extends org.jooq.QueryPart permits - UTupleImpl2 + TupleImpl2 { @NotNull Q1 $1(); - @NotNull UTuple2 $1(Q1 newPart1); + @NotNull Tuple2 $1(Q1 newPart1); @NotNull Q2 $2(); - @NotNull UTuple2 $2(Q2 newPart2); + @NotNull Tuple2 $2(Q2 newPart2); + } + + /** + * An unmodifiable {@link Map} of {@link QueryPart} keys and values. + */ + public sealed interface UnmodifiableMap + extends + org.jooq.QueryPart, + java.util.Map + permits + AbstractQueryPartMap + { + @NotNull UnmodifiableList> $tuples(); } /** @@ -335,6 +355,117 @@ public final class QOM { // XXX: Queries // ------------------------------------------------------------------------- + public sealed interface Insert + extends + DMLQuery + permits + InsertImpl, + InsertQueryImpl + { + @Nullable With $with(); + @NotNull Table $into(); + @NotNull Insert $into(Table into); + @NotNull UnmodifiableList> $columns(); + @NotNull Insert $columns(Collection> columns); + @Nullable Select $select(); + @NotNull Insert $select(Select select); + boolean $defaultValues(); + @NotNull Insert $defaultValues(boolean defaultValues); + @NotNull UnmodifiableList $values(); + @NotNull Insert $values(Collection values); + boolean $onDuplicateKeyIgnore(); + @NotNull Insert $onDuplicateKeyIgnore(boolean onDuplicateKeyIgnore); + boolean $onDuplicateKeyUpdate(); + @NotNull Insert $onDuplicateKeyUpdate(boolean onDuplicateKeyUpdate); + @NotNull UnmodifiableList> $onConflict(); + @NotNull Insert $onConflict(Collection> onConflictFields); + // [#13640] TODO: What to do about the CONSTRAINT? Re-design this model? + @Nullable Condition $onConflictWhere(); + @NotNull Insert $onConflictWhere(Condition where); + @NotNull UnmodifiableMap $updateSet(); + @NotNull Insert $updateSet(Map updateSet); + @Nullable Condition $updateWhere(); + @NotNull Insert $updateWhere(Condition where); + } + + public sealed interface InsertReturning + extends + ResultQuery + permits + InsertAsResultQuery + { + @NotNull Insert $insert(); + @NotNull InsertReturning $insert(Insert insert); + @NotNull UnmodifiableList $returning(); + @NotNull InsertReturning $returning(Collection returning); + } + + public sealed interface Update + extends + DMLQuery + permits + UpdateImpl, + UpdateQueryImpl + { + @Nullable With $with(); + @NotNull Table $table(); + @NotNull Update $table(Table table); + @NotNull UnmodifiableList> $from(); + @NotNull Update $from(Collection> from); + @NotNull UnmodifiableMap $set(); + @NotNull Update $set(Map set); + @Nullable Condition $where(); + @NotNull Update $where(Condition condition); + @NotNull UnmodifiableList> $orderBy(); + @NotNull Update $orderBy(Collection> orderBy); + @Nullable Field $limit(); + @NotNull Update $limit(Field limit); + } + + public sealed interface UpdateReturning + extends + ResultQuery + permits + UpdateAsResultQuery + { + @NotNull Update $update(); + @NotNull UpdateReturning $update(Update update); + @NotNull UnmodifiableList $returning(); + @NotNull UpdateReturning $returning(Collection returning); + } + + public sealed interface Delete + extends + DMLQuery + permits + DeleteImpl, + DeleteQueryImpl + { + @Nullable With $with(); + @NotNull Table $from(); + @NotNull Delete $from(Table table); + @NotNull UnmodifiableList> $using(); + @NotNull Delete $using(Collection> using); + @Nullable Condition $where(); + @NotNull Delete $where(Condition condition); + @NotNull UnmodifiableList> $orderBy(); + @NotNull Delete $orderBy(Collection> orderBy); + @Nullable Field $limit(); + @NotNull Delete $limit(Field limit); + } + + public sealed interface DeleteReturning + extends + ResultQuery + permits + DeleteAsResultQuery + { + @NotNull Delete $delete(); + @NotNull DeleteReturning $delete(Delete delete); + @NotNull UnmodifiableList $returning(); + @NotNull DeleteReturning $returning(Collection returning); + } + public /*sealed*/ interface CreateType extends DDLQuery @@ -1040,12 +1171,12 @@ public final class QOM { public /*sealed*/ interface CaseSimple extends Field, - UOperator3, UnmodifiableList, Field>>, Field, CaseSimple> + UOperator3, UnmodifiableList, Field>>, Field, CaseSimple> { @NotNull default Field $value() { return $arg1(); } @NotNull default CaseSimple $value(Field value) { return $arg1(value); } - @NotNull default UnmodifiableList, Field>> $when() { return $arg2(); } - @NotNull default CaseSimple $when(UnmodifiableList, Field>> when) { return $arg2(when); } + @NotNull default UnmodifiableList, Field>> $when() { return $arg2(); } + @NotNull default CaseSimple $when(UnmodifiableList, Field>> when) { return $arg2(when); } @Nullable default Field $else() { return $arg3(); } @NotNull default CaseSimple $else(Field else_) { return $arg3(else_); } } @@ -1053,10 +1184,10 @@ public final class QOM { public /*sealed*/ interface CaseSearched extends Field, - UOperator2>>, Field, CaseSearched> + UOperator2>>, Field, CaseSearched> { - @NotNull default UnmodifiableList>> $when() { return $arg1(); } - @NotNull default CaseSearched $when(UnmodifiableList>> when) { return $arg1(when); } + @NotNull default UnmodifiableList>> $when() { return $arg1(); } + @NotNull default CaseSearched $when(UnmodifiableList>> when) { return $arg1(when); } @Nullable default Field $else() { return $arg2(); } @NotNull default CaseSearched $else(Field else_) { return $arg2(else_); } } @@ -7824,8 +7955,16 @@ public final class QOM { return new QueryPartList<>(unmodifiableCollection(collection)); } + /** + * Turn a {@link Map} into an unmodifiable {@link UnmodifiableMap}. + */ @Internal - public static final UTuple2 tuple(Q1 q1, Q2 q2) { - return new UTupleImpl2<>(q1, q2); + public static final UnmodifiableMap unmodifiable(Map map) { + return new QueryPartMapView<>(unmodifiableMap(map)); + } + + @Internal + public static final Tuple2 tuple(Q1 q1, Q2 q2) { + return new TupleImpl2<>(q1, q2); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/QueryPartMapView.java b/jOOQ/src/main/java/org/jooq/impl/QueryPartMapView.java new file mode 100644 index 0000000000..799219959c --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/QueryPartMapView.java @@ -0,0 +1,79 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import static org.jooq.impl.QueryPartCollectionView.wrap; + +import java.util.Map; +import java.util.function.Function; + +import org.jooq.Context; +import org.jooq.QueryPart; + +/** + * @author Lukas Eder + */ +final class QueryPartMapView +extends + AbstractQueryPartMap +{ + + QueryPartMapView(Map map) { + super(map); + } + + // ------------------------------------------------------------------------- + // The QueryPart API + // ------------------------------------------------------------------------- + + @Override + public final void accept(Context ctx) { + + // This is a placeholder implementation without any real SQL usage + ctx.visit(wrap($tuples())); + } + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + @Override + final Function, ? extends AbstractQueryPartMap> $construct() { + return QueryPartMapView::new; + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index fcdf13e01a..b9ece485e0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -124,6 +124,7 @@ import static org.jooq.impl.CombineOperator.INTERSECT_ALL; import static org.jooq.impl.CombineOperator.UNION; import static org.jooq.impl.CombineOperator.UNION_ALL; import static org.jooq.impl.CommonTableExpressionList.markTopLevelCteAndAccept; +import static org.jooq.impl.ConditionProviderImpl.extractCondition; import static org.jooq.impl.DSL.asterisk; import static org.jooq.impl.DSL.createTable; import static org.jooq.impl.DSL.emptyGroupingSet; @@ -4617,7 +4618,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp @Override public final UnmodifiableList $groupBy() { - return QOM.unmodifiable(groupBy == null ? new GroupFieldList() : groupBy); + return QOM.unmodifiable(groupBy); } @Override @@ -4846,15 +4847,6 @@ final class SelectQueryImpl extends AbstractResultQuery imp - - - - - - - - - diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index ccc02a2631..c5088dd130 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -3873,7 +3873,7 @@ final class Tools { return q; else if (query instanceof AbstractDelegatingDMLQuery q) return abstractDMLQuery(q.getDelegate()); - else if (query instanceof DMLQueryAsResultQuery q) + else if (query instanceof AbstractDMLQueryAsResultQuery q) return q.getDelegate(); else return null; diff --git a/jOOQ/src/main/java/org/jooq/impl/UTupleImpl2.java b/jOOQ/src/main/java/org/jooq/impl/TupleImpl2.java similarity index 89% rename from jOOQ/src/main/java/org/jooq/impl/UTupleImpl2.java rename to jOOQ/src/main/java/org/jooq/impl/TupleImpl2.java index eb45eb8b0b..a04ef49584 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UTupleImpl2.java +++ b/jOOQ/src/main/java/org/jooq/impl/TupleImpl2.java @@ -43,7 +43,7 @@ import org.jooq.Context; import org.jooq.QueryPart; // ... // ... -import org.jooq.impl.QOM.UTuple2; +import org.jooq.impl.QOM.Tuple2; /** * A generic tuple of degree 2, which acts as a {@link QueryPart} for traversal, @@ -51,17 +51,17 @@ import org.jooq.impl.QOM.UTuple2; * * @author Lukas Eder */ -final class UTupleImpl2 +final class TupleImpl2 extends AbstractQueryPart implements - UTuple2 + Tuple2 { private final Q1 part1; private final Q2 part2; - UTupleImpl2(Q1 part1, Q2 part2) { + TupleImpl2(Q1 part1, Q2 part2) { this.part1 = part1; this.part2 = part2; } @@ -92,12 +92,12 @@ implements } @Override - public final UTuple2 $1(Q1 newPart1) { + public final Tuple2 $1(Q1 newPart1) { return tuple(newPart1, part2); } @Override - public final UTuple2 $2(Q2 newPart2) { + public final Tuple2 $2(Q2 newPart2) { return tuple(part1, newPart2); } diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateAsResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/UpdateAsResultQuery.java new file mode 100644 index 0000000000..d0818cf679 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/UpdateAsResultQuery.java @@ -0,0 +1,116 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import java.util.Collection; + +import org.jooq.QueryPart; +import org.jooq.Record; +// ... +import org.jooq.ResultQuery; +import org.jooq.SelectFieldOrAsterisk; +// ... +import org.jooq.UpdateResultStep; +import org.jooq.impl.QOM.UnmodifiableList; +import org.jooq.impl.QOM.Update; +import org.jooq.impl.QOM.UpdateReturning; + +/** + * A wrapped {@link Update} that works like a {@link ResultQuery}. + * + * @author Lukas Eder + */ +final class UpdateAsResultQuery +extends + AbstractDMLQueryAsResultQuery> +implements + UpdateResultStep, + QOM.UpdateReturning +{ + + UpdateAsResultQuery(UpdateQueryImpl delegate, boolean returningResult) { + super(delegate, returningResult); + } + + @Override + public final Update $update() { + return getDelegate(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public final UpdateReturning $update(Update newUpdate) { + return new UpdateAsResultQuery(Tools.updateQueryImpl(newUpdate).copy(d -> d.setReturning($returning())), returningResult); + } + + @Override + public final UnmodifiableList $returning() { + return QOM.unmodifiable(getDelegate().returning); + } + + @Override + public final UpdateReturning $returning(Collection returning) { + return new UpdateAsResultQuery<>(getDelegate().copy(d -> d.setReturning(returning)), returningResult); + } + + + + + + + + + + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdateImpl.java index 57e9931eca..c3e837d590 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UpdateImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/UpdateImpl.java @@ -49,6 +49,8 @@ import java.util.Map; import org.jooq.Condition; import org.jooq.Configuration; import org.jooq.Field; +import org.jooq.FieldOrRow; +import org.jooq.FieldOrRowOrSelect; import org.jooq.Name; import org.jooq.Operator; import org.jooq.OrderField; @@ -76,6 +78,7 @@ import org.jooq.Record6; import org.jooq.Record7; import org.jooq.Record8; import org.jooq.Record9; +// ... import org.jooq.Row1; import org.jooq.Row10; import org.jooq.Row11; @@ -103,8 +106,10 @@ import org.jooq.SQL; import org.jooq.Select; import org.jooq.SelectField; import org.jooq.SelectFieldOrAsterisk; +import org.jooq.SortField; import org.jooq.Table; import org.jooq.TableLike; +// ... import org.jooq.UpdateConditionStep; import org.jooq.UpdateFromStep; import org.jooq.UpdateQuery; @@ -112,6 +117,10 @@ import org.jooq.UpdateResultStep; import org.jooq.UpdateSetFirstStep; import org.jooq.UpdateSetMoreStep; import org.jooq.UpdateWhereStep; +import org.jooq.impl.QOM.UnmodifiableList; +import org.jooq.impl.QOM.UnmodifiableMap; +import org.jooq.impl.QOM.Update; +import org.jooq.impl.QOM.With; /** * A wrapper for an {@link UpdateQuery} @@ -120,13 +129,16 @@ import org.jooq.UpdateWhereStep; */ @SuppressWarnings({ "rawtypes", "unchecked" }) final class UpdateImpl - extends AbstractDelegatingDMLQuery> - implements +extends + AbstractDelegatingDMLQuery> +implements // Cascading interface implementations for Update behaviour UpdateSetFirstStep, UpdateSetMoreStep, - UpdateConditionStep { + UpdateConditionStep, + QOM.Update +{ private boolean returningResult; UpdateImpl(Configuration configuration, WithImpl with, Table table) { @@ -679,33 +691,33 @@ final class UpdateImpl @Override public final UpdateResultStep returning() { getDelegate().setReturning(); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new UpdateAsResultQuery<>(getDelegate(), returningResult); } @Override public final UpdateResultStep returning(SelectFieldOrAsterisk... f) { getDelegate().setReturning(f); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new UpdateAsResultQuery<>(getDelegate(), returningResult); } @Override public final UpdateResultStep returning(Collection f) { getDelegate().setReturning(f); - return new DMLQueryAsResultQuery<>(getDelegate(), returningResult); + return new UpdateAsResultQuery<>(getDelegate(), returningResult); } @Override public final UpdateResultStep returningResult(SelectFieldOrAsterisk... f) { returningResult = true; getDelegate().setReturning(f); - return new DMLQueryAsResultQuery(getDelegate(), returningResult); + return new UpdateAsResultQuery(getDelegate(), returningResult); } @Override public final UpdateResultStep returningResult(Collection f) { returningResult = true; getDelegate().setReturning(f); - return new DMLQueryAsResultQuery(getDelegate(), returningResult); + return new UpdateAsResultQuery(getDelegate(), returningResult); } @@ -821,4 +833,88 @@ final class UpdateImpl } + + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + @Override + public final With $with() { + return getDelegate().$with(); + } + + @Override + public final Table $table() { + return getDelegate().$table(); + } + + @Override + public final Update $table(Table table) { + return getDelegate().$table(table); + } + + @Override + public final UnmodifiableList> $from() { + return getDelegate().$from(); + } + + @Override + public final Update $from(Collection> using) { + return getDelegate().$from(using); + } + + @Override + public final UnmodifiableMap $set() { + return getDelegate().$set(); + } + + @Override + public final Update $set(Map set) { + return getDelegate().$set(set); + } + + @Override + public final Condition $where() { + return getDelegate().$where(); + } + + @Override + public final Update $where(Condition condition) { + return getDelegate().$where(condition); + } + + @Override + public final UnmodifiableList> $orderBy() { + return getDelegate().$orderBy(); + } + + @Override + public final Update $orderBy(Collection> orderBy) { + return getDelegate().$orderBy(orderBy); + } + + @Override + public final Field $limit() { + return getDelegate().$limit(); + } + + @Override + public final Update $limit(Field limit) { + return getDelegate().$limit(limit); + } + + + + + + + + + + + + + + } diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java index 08435ea2d1..70cbf3f0be 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java @@ -77,6 +77,7 @@ import static org.jooq.SQLDialect.SQLITE; // ... import static org.jooq.SQLDialect.YUGABYTEDB; import static org.jooq.conf.SettingsTools.getExecuteUpdateWithoutWhere; +import static org.jooq.impl.ConditionProviderImpl.extractCondition; import static org.jooq.impl.DSL.insertInto; import static org.jooq.impl.DSL.mergeInto; import static org.jooq.impl.DSL.name; @@ -137,6 +138,7 @@ import org.jooq.Record6; import org.jooq.Record7; import org.jooq.Record8; import org.jooq.Record9; +// ... import org.jooq.Row; import org.jooq.Row1; import org.jooq.Row10; @@ -164,12 +166,16 @@ import org.jooq.RowN; import org.jooq.SQLDialect; import org.jooq.Scope; import org.jooq.Select; +import org.jooq.SortField; import org.jooq.Table; import org.jooq.TableField; import org.jooq.TableLike; +// ... import org.jooq.UpdateQuery; import org.jooq.impl.FieldMapForUpdate.SetClause; -import org.jooq.impl.QOM.UNotYetImplemented; +import org.jooq.impl.QOM.UnmodifiableList; +import org.jooq.impl.QOM.UnmodifiableMap; +import org.jooq.impl.QOM.Update; /** * @author Lukas Eder @@ -179,7 +185,7 @@ extends AbstractStoreQuery implements UpdateQuery, - UNotYetImplemented + QOM.Update { private static final Clause[] CLAUSES = { UPDATE }; @@ -636,8 +642,12 @@ implements ctx.visit(mergeInto(table).using(s).on(c).whenMatchedThenUpdate().set(um)); } - private final UpdateQueryImpl copy(Consumer> consumer) { - UpdateQueryImpl u = new UpdateQueryImpl<>(configuration(), with, table); + final UpdateQueryImpl copy(Consumer> finisher) { + return copy(finisher, table); + } + + final UpdateQueryImpl copy(Consumer> finisher, Table t) { + UpdateQueryImpl u = new UpdateQueryImpl<>(configuration(), with, t); if (!returning.isEmpty()) u.setReturning(returning); @@ -647,7 +657,7 @@ implements u.condition.setWhere(condition.getWhere()); u.orderBy.addAll(orderBy); u.limit = limit; - consumer.accept(u); + finisher.accept(u); return u; } @@ -784,6 +794,138 @@ implements return updateMap.size() > 0; } + + + + + + + + + + + + + // ------------------------------------------------------------------------- + // XXX: Query Object Model + // ------------------------------------------------------------------------- + + @Override + public final WithImpl $with() { + return with; + } + + @Override + public final Table $table() { + return table; + } + + @Override + public final Update $table(Table newTable) { + if ($from() == newTable) + return this; + else + return copy(d -> {}, newTable); + } + + @Override + public final UnmodifiableList> $from() { + return QOM.unmodifiable(from); + } + + @Override + public final Update $from(Collection> newFrom) { + return copy(d -> { + d.from.clear(); + d.from.addAll(newFrom); + }); + } + + @Override + public final UnmodifiableMap $set() { + return QOM.unmodifiable(updateMap); + } + + @Override + public final Update $set(Map newSet) { + return copy(u -> { + u.updateMap.clear(); + u.updateMap.putAll(newSet); + }); + } + + @Override + public final Condition $where() { + return condition.getWhereOrNull(); + } + + @Override + public final Update $where(Condition newWhere) { + if ($where() == newWhere) + return this; + else + return copy(u -> u.condition.setWhere(newWhere)); + } + + @Override + public final UnmodifiableList> $orderBy() { + return QOM.unmodifiable(orderBy); + } + + @Override + public final Update $orderBy(Collection> newOrderBy) { + return copy(u -> { + u.orderBy.clear(); + u.orderBy.addAll(newOrderBy); + }); + } + + @Override + public final Field $limit() { + return limit; + } + + @Override + public final Update $limit(Field newLimit) { + if ($limit() == newLimit) + return this; + else + return copy(s -> s.limit = newLimit); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +