diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d2df732a..4f5c74bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,12 @@ GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=miles The major themes of this release include the following: -1. Add support for subqueries in select statements - both in a from clause and a join clause +1. Add support for subqueries in select statements - both in a from clause and a join clause. +1. Add support for the "exists" and "not exists" operator. This will work in "where" clauses anywhere + they are supported. 1. Continue to refine the Kotlin DSL. Most changes to the Kotlin DSL are internal and should be source code compatible with existing code. There is one breaking change detailed below. -1. Remove deprecated code from prior releases +1. Remove deprecated code from prior releases. ### Breaking Change for Kotlin @@ -37,16 +39,17 @@ The new code looks like this: } ``` -This change makes the Kotlin DSL a bit more consistent and also makes it easier to implement sub-query support in the +This change makes the Kotlin DSL a bit more consistent and also makes it easier to implement subquery support in the Kotlin DSL. ### Added - Added a new sort specification that is useful in selects with joins ([#269](https://github.com/mybatis/mybatis-dynamic-sql/pull/269)) - Added the capability to generate a camel cased alias for a column ([#272](https://github.com/mybatis/mybatis-dynamic-sql/issues/272)) -- Added sub-query support for "from" clauses in a select statement ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) +- Added subquery support for "from" clauses in a select statement ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) - Added Kotlin DSL updates to support sub-queries in select statements, where clauses, and insert statements ([#282](https://github.com/mybatis/mybatis-dynamic-sql/pull/282)) -- Added sub-query support for "join" clauses in a select statement ([#293](https://github.com/mybatis/mybatis-dynamic-sql/pull/293)) +- Added subquery support for "join" clauses in a select statement ([#293](https://github.com/mybatis/mybatis-dynamic-sql/pull/293)) +- Added support for the "exists" and "not exists" operator in where clauses ([#296](https://github.com/mybatis/mybatis-dynamic-sql/pull/296)) ## Release 1.2.1 - September 29, 2020 diff --git a/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java b/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java new file mode 100644 index 000000000..b496d7c3a --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/ColumnAndConditionCriterion.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2020 the original author or authors. + * + * 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 + * + * http://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. + */ +package org.mybatis.dynamic.sql; + +import java.util.Objects; + +public class ColumnAndConditionCriterion extends SqlCriterion { + private final BindableColumn column; + private final VisitableCondition condition; + + private ColumnAndConditionCriterion(Builder builder) { + super(builder); + column = Objects.requireNonNull(builder.column); + condition = Objects.requireNonNull(builder.condition); + } + + public BindableColumn column() { + return column; + } + + public VisitableCondition condition() { + return condition; + } + + @Override + public R accept(SqlCriterionVisitor visitor) { + return visitor.visit(this); + } + + public static Builder withColumn(BindableColumn column) { + return new Builder().withColumn(column); + } + + public static class Builder extends AbstractBuilder> { + private BindableColumn column; + private VisitableCondition condition; + + public Builder withColumn(BindableColumn column) { + this.column = column; + return this; + } + + public Builder withCondition(VisitableCondition condition) { + this.condition = condition; + return this; + } + + @Override + protected Builder getThis() { + return this; + } + + public ColumnAndConditionCriterion build() { + return new ColumnAndConditionCriterion<>(this); + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java b/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java new file mode 100644 index 000000000..cff4875bb --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/ExistsCriterion.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016-2020 the original author or authors. + * + * 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 + * + * http://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. + */ +package org.mybatis.dynamic.sql; + +import java.util.Objects; + +public class ExistsCriterion extends SqlCriterion { + private final ExistsPredicate existsPredicate; + + private ExistsCriterion(Builder builder) { + super(builder); + this.existsPredicate = Objects.requireNonNull(builder.existsPredicate); + } + + public ExistsPredicate existsPredicate() { + return existsPredicate; + } + + @Override + public R accept(SqlCriterionVisitor visitor) { + return visitor.visit(this); + } + + public static class Builder extends AbstractBuilder { + private ExistsPredicate existsPredicate; + + public Builder withExistsPredicate(ExistsPredicate existsPredicate) { + this.existsPredicate = existsPredicate; + return this; + } + + public ExistsCriterion build() { + return new ExistsCriterion(this); + } + + @Override + protected Builder getThis() { + return this; + } + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java b/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java new file mode 100644 index 000000000..db518ce57 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/ExistsPredicate.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016-2020 the original author or authors. + * + * 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 + * + * http://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. + */ +package org.mybatis.dynamic.sql; + +import java.util.Objects; + +import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.util.Buildable; + +public class ExistsPredicate { + private final Buildable selectModelBuilder; + private final String operator; + + private ExistsPredicate(String operator, Buildable selectModelBuilder) { + this.selectModelBuilder = Objects.requireNonNull(selectModelBuilder); + this.operator = Objects.requireNonNull(operator); + } + + public String operator() { + return operator; + } + + public Buildable selectModelBuilder() { + return selectModelBuilder; + } + + @NotNull + public static ExistsPredicate exists(Buildable selectModelBuilder) { + return new ExistsPredicate("exists", selectModelBuilder); //$NON-NLS-1$ + } + + @NotNull + public static ExistsPredicate notExists(Buildable selectModelBuilder) { + return new ExistsPredicate("not exists", selectModelBuilder); //$NON-NLS-1$ + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java index ee67fe139..71b66e042 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java @@ -235,43 +235,81 @@ static WhereDSL where(BindableColumn column, VisitableCondition condit } static WhereDSL where(BindableColumn column, VisitableCondition condition, - SqlCriterion... subCriteria) { + SqlCriterion... subCriteria) { return WhereDSL.where().where(column, condition, subCriteria); } + static WhereDSL where(ExistsPredicate existsPredicate) { + return WhereDSL.where().where(existsPredicate); + } + + static WhereDSL where(ExistsPredicate existsPredicate, SqlCriterion... subCriteria) { + return WhereDSL.where().where(existsPredicate, subCriteria); + } + // where condition connectors - static SqlCriterion or(BindableColumn column, VisitableCondition condition) { - return SqlCriterion.withColumn(column) + static SqlCriterion or(BindableColumn column, VisitableCondition condition) { + return ColumnAndConditionCriterion.withColumn(column) .withConnector("or") //$NON-NLS-1$ .withCondition(condition) .build(); } - static SqlCriterion or(BindableColumn column, VisitableCondition condition, - SqlCriterion...subCriteria) { - return SqlCriterion.withColumn(column) + static SqlCriterion or(BindableColumn column, VisitableCondition condition, + SqlCriterion...subCriteria) { + return ColumnAndConditionCriterion.withColumn(column) .withConnector("or") //$NON-NLS-1$ .withCondition(condition) .withSubCriteria(Arrays.asList(subCriteria)) .build(); } - static SqlCriterion and(BindableColumn column, VisitableCondition condition) { - return SqlCriterion.withColumn(column) + static SqlCriterion or(ExistsPredicate existsPredicate) { + return new ExistsCriterion.Builder() + .withConnector("or") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .build(); + } + + static SqlCriterion or(ExistsPredicate existsPredicate, SqlCriterion...subCriteria) { + return new ExistsCriterion.Builder() + .withConnector("or") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .withSubCriteria(Arrays.asList(subCriteria)) + .build(); + } + + static SqlCriterion and(BindableColumn column, VisitableCondition condition) { + return ColumnAndConditionCriterion.withColumn(column) .withConnector("and") //$NON-NLS-1$ .withCondition(condition) .build(); } - static SqlCriterion and(BindableColumn column, VisitableCondition condition, - SqlCriterion...subCriteria) { - return SqlCriterion.withColumn(column) + static SqlCriterion and(BindableColumn column, VisitableCondition condition, + SqlCriterion...subCriteria) { + return ColumnAndConditionCriterion.withColumn(column) .withConnector("and") //$NON-NLS-1$ .withCondition(condition) .withSubCriteria(Arrays.asList(subCriteria)) .build(); } + static SqlCriterion and(ExistsPredicate existsPredicate) { + return new ExistsCriterion.Builder() + .withConnector("and") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .build(); + } + + static SqlCriterion and(ExistsPredicate existsPredicate, SqlCriterion...subCriteria) { + return new ExistsCriterion.Builder() + .withConnector("and") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .withSubCriteria(Arrays.asList(subCriteria)) + .build(); + } + // join support static JoinCriterion and(BasicColumn joinColumn, JoinCondition joinCondition) { return new JoinCriterion.Builder() @@ -375,6 +413,14 @@ static Upper upper(BindableColumn column) { } // conditions for all data types + static ExistsPredicate exists(Buildable selectModelBuilder) { + return ExistsPredicate.exists(selectModelBuilder); + } + + static ExistsPredicate notExists(Buildable selectModelBuilder) { + return ExistsPredicate.notExists(selectModelBuilder); + } + static IsNull isNull() { return new IsNull<>(); } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlCriterion.java b/src/main/java/org/mybatis/dynamic/sql/SqlCriterion.java index 1092dc8b3..987be84ef 100644 --- a/src/main/java/org/mybatis/dynamic/sql/SqlCriterion.java +++ b/src/main/java/org/mybatis/dynamic/sql/SqlCriterion.java @@ -22,17 +22,13 @@ import java.util.function.Function; import java.util.stream.Stream; -public class SqlCriterion { +public abstract class SqlCriterion { - private final BindableColumn column; - private final VisitableCondition condition; private final String connector; - private final List> subCriteria; + private final List subCriteria; - private SqlCriterion(Builder builder) { + protected SqlCriterion(AbstractBuilder builder) { connector = builder.connector; - column = Objects.requireNonNull(builder.column); - condition = Objects.requireNonNull(builder.condition); subCriteria = Objects.requireNonNull(builder.subCriteria); } @@ -40,50 +36,26 @@ public Optional connector() { return Optional.ofNullable(connector); } - public BindableColumn column() { - return column; - } - - public VisitableCondition condition() { - return condition; - } - - public Stream mapSubCriteria(Function, R> mapper) { + public Stream mapSubCriteria(Function mapper) { return subCriteria.stream().map(mapper); } - public static Builder withColumn(BindableColumn column) { - return new Builder().withColumn(column); - } + public abstract R accept(SqlCriterionVisitor visitor); - public static class Builder { + protected abstract static class AbstractBuilder> { private String connector; - private BindableColumn column; - private VisitableCondition condition; - private final List> subCriteria = new ArrayList<>(); + private final List subCriteria = new ArrayList<>(); - public Builder withConnector(String connector) { + public T withConnector(String connector) { this.connector = connector; - return this; + return getThis(); } - public Builder withColumn(BindableColumn column) { - this.column = column; - return this; - } - - public Builder withCondition(VisitableCondition condition) { - this.condition = condition; - return this; - } - - public Builder withSubCriteria(List> subCriteria) { + public T withSubCriteria(List subCriteria) { this.subCriteria.addAll(subCriteria); - return this; + return getThis(); } - public SqlCriterion build() { - return new SqlCriterion<>(this); - } + protected abstract T getThis(); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlCriterionVisitor.java b/src/main/java/org/mybatis/dynamic/sql/SqlCriterionVisitor.java new file mode 100644 index 000000000..40bcdbbd9 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/SqlCriterionVisitor.java @@ -0,0 +1,22 @@ +/* + * Copyright 2016-2020 the original author or authors. + * + * 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 + * + * http://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. + */ +package org.mybatis.dynamic.sql; + +public interface SqlCriterionVisitor { + R visit(ColumnAndConditionCriterion criterion); + + R visit(ExistsCriterion criterion); +} diff --git a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java index a767e285e..3ff81b73b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java @@ -66,9 +66,7 @@ public static DeleteDSL deleteFrom(SqlTable table) { public class DeleteWhereBuilder extends AbstractWhereDSL implements Buildable { - private DeleteWhereBuilder() { - super(); - } + private DeleteWhereBuilder() {} @NotNull @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java index 2d891b654..5b66ed46b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionDSL.java @@ -240,8 +240,7 @@ public FromGatherer build() { public class QueryExpressionWhereBuilder extends AbstractWhereDSL implements Buildable { - private QueryExpressionWhereBuilder() { - } + private QueryExpressionWhereBuilder() {} public UnionBuilder union() { return QueryExpressionDSL.this.union(); diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java index 70d8eb451..9daee27c7 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java @@ -138,9 +138,7 @@ public UpdateDSL equalToWhenPresent(Supplier valueSupplier) { public class UpdateWhereBuilder extends AbstractWhereDSL implements Buildable { - public UpdateWhereBuilder() { - super(); - } + private UpdateWhereBuilder() {} @NotNull @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereDSL.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereDSL.java index d31f8d2ae..dc066f275 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereDSL.java @@ -21,31 +21,56 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; +import org.mybatis.dynamic.sql.ExistsCriterion; +import org.mybatis.dynamic.sql.ExistsPredicate; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.VisitableCondition; public abstract class AbstractWhereDSL> { - private final List> criteria = new ArrayList<>(); + private final List criteria = new ArrayList<>(); - protected AbstractWhereDSL() { - super(); + @NotNull + public T where(BindableColumn column, VisitableCondition condition) { + criteria.add(ColumnAndConditionCriterion.withColumn(column) + .withCondition(condition) + .build()); + return getThis(); } @NotNull - public T where(BindableColumn column, VisitableCondition condition) { - addCriterion(column, condition); + public T where(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { + return where(column, condition, Arrays.asList(subCriteria)); + } + + @NotNull + public T where(BindableColumn column, VisitableCondition condition, List subCriteria) { + criteria.add(ColumnAndConditionCriterion.withColumn(column) + .withCondition(condition) + .withSubCriteria(subCriteria) + .build()); return getThis(); } @NotNull - public T where(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { - addCriterion(column, condition, Arrays.asList(subCriteria)); + public T where(ExistsPredicate existsPredicate) { + criteria.add(new ExistsCriterion.Builder() + .withExistsPredicate(existsPredicate) + .build()); return getThis(); } @NotNull - public T where(BindableColumn column, VisitableCondition condition, List> subCriteria) { - addCriterion(column, condition, subCriteria); + public T where(ExistsPredicate existsPredicate, SqlCriterion...subCriteria) { + return where(existsPredicate, Arrays.asList(subCriteria)); + } + + @NotNull + public T where(ExistsPredicate existsPredicate, List subCriteria) { + criteria.add(new ExistsCriterion.Builder() + .withExistsPredicate(existsPredicate) + .withSubCriteria(subCriteria) + .build()); return getThis(); } @@ -57,72 +82,98 @@ public T applyWhere(WhereApplier whereApplier) { @NotNull public T and(BindableColumn column, VisitableCondition condition) { - addCriterion("and", column, condition); //$NON-NLS-1$ + criteria.add(ColumnAndConditionCriterion.withColumn(column) + .withConnector("and") //$NON-NLS-1$ + .withCondition(condition) + .build()); return getThis(); } @NotNull - public T and(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { - addCriterion("and", column, condition, Arrays.asList(subCriteria)); //$NON-NLS-1$ - return getThis(); + public T and(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { + return and(column, condition, Arrays.asList(subCriteria)); } @NotNull - public T and(BindableColumn column, VisitableCondition condition, List> subCriteria) { - addCriterion("and", column, condition, subCriteria); //$NON-NLS-1$ + public T and(BindableColumn column, VisitableCondition condition, List subCriteria) { + criteria.add(ColumnAndConditionCriterion.withColumn(column) + .withConnector("and") //$NON-NLS-1$ + .withCondition(condition) + .withSubCriteria(subCriteria) + .build()); return getThis(); } @NotNull - public T or(BindableColumn column, VisitableCondition condition) { - addCriterion("or", column, condition); //$NON-NLS-1$ + public T and(ExistsPredicate existsPredicate) { + criteria.add(new ExistsCriterion.Builder() + .withConnector("and") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .build()); return getThis(); } @NotNull - public T or(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { - addCriterion("or", column, condition, Arrays.asList(subCriteria)); //$NON-NLS-1$ - return getThis(); + public T and(ExistsPredicate existsPredicate, SqlCriterion...subCriteria) { + return and(existsPredicate, Arrays.asList(subCriteria)); } @NotNull - public T or(BindableColumn column, VisitableCondition condition, List> subCriteria) { - addCriterion("or", column, condition, subCriteria); //$NON-NLS-1$ + public T and(ExistsPredicate existsPredicate, List subCriteria) { + criteria.add(new ExistsCriterion.Builder() + .withConnector("and") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .withSubCriteria(subCriteria) + .build()); return getThis(); } - private void addCriterion(BindableColumn column, VisitableCondition condition) { - SqlCriterion criterion = SqlCriterion.withColumn(column) + @NotNull + public T or(BindableColumn column, VisitableCondition condition) { + criteria.add(ColumnAndConditionCriterion.withColumn(column) + .withConnector("or") //$NON-NLS-1$ .withCondition(condition) - .build(); - criteria.add(criterion); + .build()); + return getThis(); } - private void addCriterion(String connector, BindableColumn column, VisitableCondition condition) { - SqlCriterion criterion = SqlCriterion.withColumn(column) - .withConnector(connector) - .withCondition(condition) - .build(); - criteria.add(criterion); + @NotNull + public T or(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { + return or(column, condition, Arrays.asList(subCriteria)); } - private void addCriterion(BindableColumn column, VisitableCondition condition, - List> subCriteria) { - SqlCriterion criterion = SqlCriterion.withColumn(column) + @NotNull + public T or(BindableColumn column, VisitableCondition condition, List subCriteria) { + criteria.add(ColumnAndConditionCriterion.withColumn(column) + .withConnector("or") //$NON-NLS-1$ .withCondition(condition) .withSubCriteria(subCriteria) - .build(); - criteria.add(criterion); + .build()); + return getThis(); } - private void addCriterion(String connector, BindableColumn column, VisitableCondition condition, - List> subCriteria) { - SqlCriterion criterion = SqlCriterion.withColumn(column) - .withConnector(connector) - .withCondition(condition) + @NotNull + public T or(ExistsPredicate existsPredicate) { + criteria.add(new ExistsCriterion.Builder() + .withConnector("or") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) + .build()); + return getThis(); + } + + @NotNull + public T or(ExistsPredicate existsPredicate, SqlCriterion...subCriteria) { + return or(existsPredicate, Arrays.asList(subCriteria)); + } + + @NotNull + public T or(ExistsPredicate existsPredicate, List subCriteria) { + criteria.add(new ExistsCriterion.Builder() + .withConnector("or") //$NON-NLS-1$ + .withExistsPredicate(existsPredicate) .withSubCriteria(subCriteria) - .build(); - criteria.add(criterion); + .build()); + return getThis(); } protected WhereModel internalBuild() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereSupport.java b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereSupport.java index a46b9fade..caa8dc760 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereSupport.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/AbstractWhereSupport.java @@ -20,6 +20,7 @@ import java.util.function.Consumer; import org.mybatis.dynamic.sql.BindableColumn; +import org.mybatis.dynamic.sql.ExistsPredicate; import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.VisitableCondition; @@ -35,14 +36,22 @@ public abstract class AbstractWhereSupport> { public abstract W where(); - public W where(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { + public W where(BindableColumn column, VisitableCondition condition, SqlCriterion...subCriteria) { return where(column, condition, Arrays.asList(subCriteria)); } - public W where(BindableColumn column, VisitableCondition condition, List> subCriteria) { + public W where(BindableColumn column, VisitableCondition condition, List subCriteria) { return apply(w -> w.where(column, condition, subCriteria)); } + public W where(ExistsPredicate existsPredicate) { + return apply(w -> w.where(existsPredicate)); + } + + public W where(ExistsPredicate existsPredicate, SqlCriterion...subCriteria) { + return apply(w -> w.where(existsPredicate, subCriteria)); + } + public W applyWhere(WhereApplier whereApplier) { return apply(w -> w.applyWhere(whereApplier)); } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java index 66425430c..a5eb3332b 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereDSL.java @@ -17,9 +17,7 @@ public class WhereDSL extends AbstractWhereDSL { - private WhereDSL() { - super(); - } + private WhereDSL() {} @Override protected WhereDSL getThis() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java index e491c6f6d..50fba9462 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/WhereModel.java @@ -31,13 +31,13 @@ public class WhereModel { private static final WhereClauseProvider EMPTY_WHERE_CLAUSE = new WhereClauseProvider.Builder().withWhereClause("").build(); //$NON-NLS-1$ - private final List> criteria = new ArrayList<>(); + private final List criteria = new ArrayList<>(); - private WhereModel(List> criteria) { + private WhereModel(List criteria) { this.criteria.addAll(criteria); } - public Stream mapCriteria(Function, R> mapper) { + public Stream mapCriteria(Function mapper) { return criteria.stream().map(mapper); } @@ -92,7 +92,7 @@ public WhereClauseProvider render(RenderingStrategy renderingStrategy, .orElse(EMPTY_WHERE_CLAUSE); } - public static WhereModel of(List> criteria) { + public static WhereModel of(List criteria) { return new WhereModel(criteria); } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java index 41b03a099..4ec4e05ef 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java @@ -21,9 +21,15 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; +import org.mybatis.dynamic.sql.ExistsCriterion; +import org.mybatis.dynamic.sql.ExistsPredicate; import org.mybatis.dynamic.sql.SqlCriterion; +import org.mybatis.dynamic.sql.SqlCriterionVisitor; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.render.TableAliasCalculator; +import org.mybatis.dynamic.sql.select.render.SelectRenderer; +import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; import org.mybatis.dynamic.sql.util.FragmentAndParameters; import org.mybatis.dynamic.sql.util.FragmentCollector; @@ -44,94 +50,108 @@ * rendering. * * @author Jeff Butler - * @param the type of column to render. Not used during rendering. */ -public class CriterionRenderer { - private final SqlCriterion sqlCriterion; +public class CriterionRenderer implements SqlCriterionVisitor> { private final AtomicInteger sequence; private final RenderingStrategy renderingStrategy; private final TableAliasCalculator tableAliasCalculator; private final String parameterName; - private CriterionRenderer(Builder builder) { - sqlCriterion = Objects.requireNonNull(builder.sqlCriterion); + private CriterionRenderer(Builder builder) { sequence = Objects.requireNonNull(builder.sequence); renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator); parameterName = builder.parameterName; } - public Optional render() { - RenderedCriterion rc; - if (sqlCriterion.condition().shouldRender()) { - rc = renderWithInitialCondition(renderCondition(), renderSubCriteria()); + @Override + public Optional visit(ColumnAndConditionCriterion criterion) { + if (criterion.condition().shouldRender()) { + return renderWithInitialCondition(renderCondition(criterion), criterion); } else { - rc = renderWithoutInitialCondition(renderSubCriteria()); + return renderWithoutInitialCondition(criterion); } - return Optional.ofNullable(rc); } - private FragmentAndParameters renderCondition() { - WhereConditionVisitor visitor = WhereConditionVisitor.withColumn(sqlCriterion.column()) + @Override + public Optional visit(ExistsCriterion criterion) { + ExistsPredicate existsPredicate = criterion.existsPredicate(); + + SelectStatementProvider selectStatement = SelectRenderer + .withSelectModel(existsPredicate.selectModelBuilder().build()) + .withRenderingStrategy(renderingStrategy) + .withSequence(sequence) + .build() + .render(); + + String fragment = existsPredicate.operator() + " (" //$NON-NLS-1$ + + selectStatement.getSelectStatement() + ")"; //$NON-NLS-1$ + + FragmentAndParameters initialCondition = FragmentAndParameters + .withFragment(fragment) + .withParameters(selectStatement.getParameters()) + .build(); + + return renderWithInitialCondition(initialCondition, criterion); + } + + private FragmentAndParameters renderCondition(ColumnAndConditionCriterion criterion) { + WhereConditionVisitor visitor = WhereConditionVisitor.withColumn(criterion.column()) .withRenderingStrategy(renderingStrategy) .withSequence(sequence) .withTableAliasCalculator(tableAliasCalculator) .withParameterName(parameterName) .build(); - return sqlCriterion.condition().accept(visitor); + return criterion.condition().accept(visitor); } - private List renderSubCriteria() { - return sqlCriterion.mapSubCriteria(this::renderSubCriterion) + private List renderSubCriteria(SqlCriterion criterion) { + return criterion.mapSubCriteria(c -> c.accept(this)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); } - private Optional renderSubCriterion(SqlCriterion subCriterion) { - return CriterionRenderer.withCriterion(subCriterion) - .withSequence(sequence) - .withRenderingStrategy(renderingStrategy) - .withTableAliasCalculator(tableAliasCalculator) - .withParameterName(parameterName) - .build() - .render(); - } - - private RenderedCriterion renderWithoutInitialCondition(List subCriteria) { + private Optional renderWithoutInitialCondition(SqlCriterion criterion) { + List subCriteria = renderSubCriteria(criterion); if (subCriteria.isEmpty()) { - return null; + return Optional.empty(); } - return calculateRenderedCriterion(subCriteria); + return calculateRenderedCriterion(subCriteria, criterion); } - private RenderedCriterion renderWithInitialCondition(FragmentAndParameters initialCondition, - List subCriteria) { + private Optional renderWithInitialCondition(FragmentAndParameters initialCondition, + SqlCriterion criterion) { + List subCriteria = renderSubCriteria(criterion); if (subCriteria.isEmpty()) { - return calculateRenderedCriterion(initialCondition); + return calculateRenderedCriterion(initialCondition, criterion); } - return calculateRenderedCriterion(initialCondition, subCriteria); + return calculateRenderedCriterion(initialCondition, criterion, subCriteria); } - private RenderedCriterion calculateRenderedCriterion(FragmentAndParameters initialCondition) { - return fromFragmentAndParameters(initialCondition); + private Optional calculateRenderedCriterion(FragmentAndParameters initialCondition, + SqlCriterion criterion) { + return fromFragmentAndParameters(initialCondition, criterion); } - private RenderedCriterion calculateRenderedCriterion(List subCriteria) { + private Optional calculateRenderedCriterion(List subCriteria, + SqlCriterion criterion) { return calculateRenderedCriterion(subCriteria.get(0).fragmentAndParameters(), + criterion, subCriteria.subList(1, subCriteria.size())); } - private RenderedCriterion calculateRenderedCriterion(FragmentAndParameters initialCondition, + private Optional calculateRenderedCriterion(FragmentAndParameters initialCondition, + SqlCriterion criterion, List subCriteria) { FragmentCollector fc = subCriteria.stream() .map(RenderedCriterion::fragmentAndParametersWithConnector) .collect(FragmentCollector.collect(initialCondition)); return fromFragmentAndParameters(FragmentAndParameters.withFragment(calculateFragment(fc)) .withParameters(fc.parameters()) - .build()); + .build(), criterion); } private String calculateFragment(FragmentCollector collector) { @@ -143,53 +163,44 @@ private String calculateFragment(FragmentCollector collector) { } } - private RenderedCriterion fromFragmentAndParameters(FragmentAndParameters fragmentAndParameters) { + private Optional fromFragmentAndParameters(FragmentAndParameters fragmentAndParameters, + SqlCriterion criterion) { RenderedCriterion.Builder builder = new RenderedCriterion.Builder() .withFragmentAndParameters(fragmentAndParameters); - sqlCriterion.connector().ifPresent(builder::withConnector); - - return builder.build(); - } + criterion.connector().ifPresent(builder::withConnector); - public static Builder withCriterion(SqlCriterion sqlCriterion) { - return new Builder().withCriterion(sqlCriterion); + return Optional.of(builder.build()); } - public static class Builder { - private SqlCriterion sqlCriterion; + public static class Builder { private AtomicInteger sequence; private RenderingStrategy renderingStrategy; private TableAliasCalculator tableAliasCalculator; private String parameterName; - public Builder withCriterion(SqlCriterion sqlCriterion) { - this.sqlCriterion = sqlCriterion; - return this; - } - - public Builder withSequence(AtomicInteger sequence) { + public Builder withSequence(AtomicInteger sequence) { this.sequence = sequence; return this; } - public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { + public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; return this; } - public Builder withTableAliasCalculator(TableAliasCalculator tableAliasCalculator) { + public Builder withTableAliasCalculator(TableAliasCalculator tableAliasCalculator) { this.tableAliasCalculator = tableAliasCalculator; return this; } - public Builder withParameterName(String parameterName) { + public Builder withParameterName(String parameterName) { this.parameterName = parameterName; return this; } - public CriterionRenderer build() { - return new CriterionRenderer<>(this); + public CriterionRenderer build() { + return new CriterionRenderer(this); } } } diff --git a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java index 24311f546..6a1160fa1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java @@ -30,17 +30,17 @@ public class WhereRenderer { private final WhereModel whereModel; - private final AtomicInteger sequence; - private final RenderingStrategy renderingStrategy; - private final TableAliasCalculator tableAliasCalculator; - private final String parameterName; + private final CriterionRenderer criterionRenderer; private WhereRenderer(Builder builder) { whereModel = Objects.requireNonNull(builder.whereModel); - sequence = Objects.requireNonNull(builder.sequence); - renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); - tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator); - parameterName = builder.parameterName; + + criterionRenderer = new CriterionRenderer.Builder() + .withSequence(builder.sequence) + .withRenderingStrategy(builder.renderingStrategy) + .withTableAliasCalculator(builder.tableAliasCalculator) + .withParameterName(builder.parameterName) + .build(); } public Optional render() { @@ -68,14 +68,8 @@ public Optional render() { return Optional.of(wcp); } - private Optional render(SqlCriterion criterion) { - return CriterionRenderer.withCriterion(criterion) - .withSequence(sequence) - .withRenderingStrategy(renderingStrategy) - .withTableAliasCalculator(tableAliasCalculator) - .withParameterName(parameterName) - .build() - .render(); + private Optional render(SqlCriterion criterion) { + return criterion.accept(criterionRenderer); } private String calculateWhereClause(FragmentCollector collector) { diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt index 294d49266..3acd03558 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/CriteriaCollector.kt @@ -16,6 +16,9 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.BindableColumn +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion +import org.mybatis.dynamic.sql.ExistsCriterion +import org.mybatis.dynamic.sql.ExistsPredicate import org.mybatis.dynamic.sql.SqlCriterion import org.mybatis.dynamic.sql.VisitableCondition @@ -23,12 +26,12 @@ typealias CriteriaReceiver = CriteriaCollector.() -> Unit @MyBatisDslMarker class CriteriaCollector { - val criteria = mutableListOf>() + val criteria = mutableListOf() fun and(column: BindableColumn, condition: VisitableCondition) = apply { criteria.add( - SqlCriterion.withColumn(column) + ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .withConnector("and") .build() @@ -42,7 +45,7 @@ class CriteriaCollector { ) = apply { criteria.add( - SqlCriterion.withColumn(column) + ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria) .withConnector("and") @@ -50,10 +53,31 @@ class CriteriaCollector { ) } + fun and(existsPredicate: ExistsPredicate) = + apply { + criteria.add( + ExistsCriterion.Builder() + .withConnector("and") + .withExistsPredicate(existsPredicate) + .build() + ) + } + + fun and(existsPredicate: ExistsPredicate, criteriaReceiver: CriteriaReceiver) = + apply { + criteria.add( + ExistsCriterion.Builder() + .withConnector("and") + .withExistsPredicate(existsPredicate) + .withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria) + .build() + ) + } + fun or(column: BindableColumn, condition: VisitableCondition) = apply { criteria.add( - SqlCriterion.withColumn(column) + ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .withConnector("or") .build() @@ -67,11 +91,32 @@ class CriteriaCollector { ) = apply { criteria.add( - SqlCriterion.withColumn(column) + ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria) .withConnector("or") .build() ) } + + fun or(existsPredicate: ExistsPredicate) = + apply { + criteria.add( + ExistsCriterion.Builder() + .withConnector("or") + .withExistsPredicate(existsPredicate) + .build() + ) + } + + fun or(existsPredicate: ExistsPredicate, criteriaReceiver: CriteriaReceiver) = + apply { + criteria.add( + ExistsCriterion.Builder() + .withConnector("or") + .withExistsPredicate(existsPredicate) + .withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria) + .build() + ) + } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt index cdb6052e4..79f0cd5e7 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt @@ -16,6 +16,7 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.BindableColumn +import org.mybatis.dynamic.sql.ExistsPredicate import org.mybatis.dynamic.sql.SqlCriterion import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.VisitableCondition @@ -31,7 +32,7 @@ typealias WhereApplier = AbstractWhereDSL<*>.() -> Unit @MyBatisDslMarker @Suppress("TooManyFunctions") -abstract class KotlinBaseBuilder, B: KotlinBaseBuilder> { +abstract class KotlinBaseBuilder, B : KotlinBaseBuilder> { fun where(column: BindableColumn, condition: VisitableCondition) = applyToWhere { where(column, condition) @@ -42,6 +43,16 @@ abstract class KotlinBaseBuilder, B: KotlinBaseBuilde where(column, condition, sc) } + fun where(existsPredicate: ExistsPredicate) = + applyToWhere { + where(existsPredicate) + } + + fun where(existsPredicate: ExistsPredicate, subCriteria: CriteriaReceiver) = + applyToWhere(subCriteria) { sc -> + where(existsPredicate, sc) + } + fun applyWhere(whereApplier: WhereApplier) = applyToWhere { applyWhere(whereApplier) @@ -57,6 +68,16 @@ abstract class KotlinBaseBuilder, B: KotlinBaseBuilde and(column, condition, sc) } + fun and(existsPredicate: ExistsPredicate) = + applyToWhere { + and(existsPredicate) + } + + fun and(existsPredicate: ExistsPredicate, subCriteria: CriteriaReceiver) = + applyToWhere(subCriteria) { sc -> + and(existsPredicate, sc) + } + fun or(column: BindableColumn, condition: VisitableCondition) = applyToWhere { or(column, condition) @@ -67,16 +88,26 @@ abstract class KotlinBaseBuilder, B: KotlinBaseBuilde or(column, condition, sc) } + fun or(existsPredicate: ExistsPredicate) = + applyToWhere { + or(existsPredicate) + } + + fun or(existsPredicate: ExistsPredicate, subCriteria: CriteriaReceiver) = + applyToWhere(subCriteria) { sc -> + or(existsPredicate, sc) + } + fun allRows() = self() private fun applyToWhere(block: AbstractWhereDSL<*>.() -> Unit) = - self().also{ + self().also { getDsl().where().apply(block) } private fun applyToWhere( subCriteria: CriteriaReceiver, - block: AbstractWhereDSL<*>.(List>) -> Unit + block: AbstractWhereDSL<*>.(List) -> Unit ) = self().also { getDsl().where().block(CriteriaCollector().apply(subCriteria).criteria) @@ -88,8 +119,8 @@ abstract class KotlinBaseBuilder, B: KotlinBaseBuilde } @Suppress("TooManyFunctions") -abstract class KotlinBaseJoiningBuilder, B: KotlinBaseJoiningBuilder> - : KotlinBaseBuilder() { +abstract class KotlinBaseJoiningBuilder, B : KotlinBaseJoiningBuilder> : + KotlinBaseBuilder() { fun join(table: SqlTable, joinCriteria: JoinReceiver) = applyToDsl(joinCriteria) { jc -> diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt index a44b8efb8..e3f4cf840 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinConditions.kt @@ -15,6 +15,7 @@ */ package org.mybatis.dynamic.sql.util.kotlin +import org.mybatis.dynamic.sql.ExistsPredicate import org.mybatis.dynamic.sql.where.condition.IsEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsGreaterThanOrEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsGreaterThanWithSubselect @@ -24,6 +25,12 @@ import org.mybatis.dynamic.sql.where.condition.IsLessThanWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotEqualToWithSubselect import org.mybatis.dynamic.sql.where.condition.IsNotInWithSubselect +fun exists(subQuery: KotlinSubQueryBuilder.() -> Unit) = + ExistsPredicate.exists(KotlinSubQueryBuilder().apply(subQuery)) + +fun notExists(subQuery: KotlinSubQueryBuilder.() -> Unit) = + ExistsPredicate.notExists(KotlinSubQueryBuilder().apply(subQuery)) + fun isEqualTo(subQuery: KotlinSubQueryBuilder.() -> Unit) = IsEqualToWithSubselect.of(KotlinSubQueryBuilder().apply(subQuery)) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index a5654a8fa..5e7af194b 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -49,11 +49,11 @@ sealed class KotlinBaseSubQueryBuilder> : Build protected abstract fun self(): T } -class KotlinSubQueryBuilder: KotlinBaseSubQueryBuilder() { +class KotlinSubQueryBuilder : KotlinBaseSubQueryBuilder() { override fun self() = this } -class KotlinQualifiedSubQueryBuilder: KotlinBaseSubQueryBuilder() { +class KotlinQualifiedSubQueryBuilder : KotlinBaseSubQueryBuilder() { var correlationName: String? = null operator fun String.unaryPlus(): KotlinQualifiedSubQueryBuilder { @@ -65,12 +65,12 @@ class KotlinQualifiedSubQueryBuilder: KotlinBaseSubQueryBuilder() { - lateinit var columnList : List> + lateinit var columnList: List> - fun columns(vararg columnList : SqlColumn<*>) = + fun columns(vararg columnList: SqlColumn<*>) = columns(columnList.asList()) - fun columns(columnList : List>) = + fun columns(columnList: List>) = apply { this.columnList = columnList } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt index f5c2de65d..d3219cc31 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt @@ -114,4 +114,3 @@ fun selectOne( fun update(mapper: (UpdateStatementProvider) -> Int, table: SqlTable, completer: UpdateCompleter) = mapper(update(table, completer)) - diff --git a/src/site/markdown/docs/subQueries.md b/src/site/markdown/docs/subQueries.md index cd8398d35..bac43ad55 100644 --- a/src/site/markdown/docs/subQueries.md +++ b/src/site/markdown/docs/subQueries.md @@ -1,7 +1,7 @@ # Subquery Support The library currently supports subqueries in the following areas: -1. In certain where conditions +1. In where clauses - both with the "exists" operator and with column-based conditions 1. In certain insert statements 1. In update statements 1. In the "from" clause of a select statement @@ -116,6 +116,8 @@ where rownum() < #{parameters.p2} ## Subqueries in Where Conditions The library support subqueries in the following where conditions: +- exists +- notExists - isEqualTo - isNotEqualTo - isIn @@ -125,7 +127,25 @@ The library support subqueries in the following where conditions: - isLessThan - isLessThanOrEqualTo -A Java example is as follows: +An example of an exists subquery is as follows: + +```java +SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + )) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); +``` + +Note that we have to apply the qualifier for the outer query ("im") to the inner query. The qualifier +for the inner query ("ol") is automatically applied. + +An example of a column based subquery is as follows: ```java SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight) @@ -142,8 +162,23 @@ SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, bra ### Kotlin Support The library includes Kotlin versions of the where conditions that allow use of the Kotlin subquery builder. The Kotlin -where conditions are in the `org.mybatis.dynamic.sql.util.kotlin` package. An example is as follows: +where conditions are in the `org.mybatis.dynamic.sql.util.kotlin` package. + +An example of an exists subquery is as follows: +```kotlin +val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + orderBy(ItemMaster.itemId) +} +``` +An example of a column based subquery is as follows: ```kotlin val selectStatement = select(id, firstName, lastName, birthDate, employed, occupation, addressId) { from(Person) diff --git a/src/test/java/examples/joins/ExistsTest.java b/src/test/java/examples/joins/ExistsTest.java new file mode 100644 index 000000000..0028750d9 --- /dev/null +++ b/src/test/java/examples/joins/ExistsTest.java @@ -0,0 +1,352 @@ +/* + * Copyright 2016-2020 the original author or authors. + * + * 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 + * + * http://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. + */ +package examples.joins; + +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; +import org.apache.ibatis.jdbc.ScriptRunner; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.render.RenderingStrategies; +import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; +import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.List; +import java.util.Map; + +import static examples.joins.ItemMasterDynamicSQLSupport.itemMaster; +import static examples.joins.OrderLineDynamicSQLSupport.orderLine; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mybatis.dynamic.sql.SqlBuilder.*; + +class ExistsTest { + + private static final String JDBC_URL = "jdbc:hsqldb:mem:aname"; + private static final String JDBC_DRIVER = "org.hsqldb.jdbcDriver"; + + private SqlSessionFactory sqlSessionFactory; + + @BeforeEach + void setup() throws Exception { + Class.forName(JDBC_DRIVER); + InputStream is = getClass().getResourceAsStream("/examples/joins/CreateJoinDB.sql"); + try (Connection connection = DriverManager.getConnection(JDBC_URL, "sa", "")) { + ScriptRunner sr = new ScriptRunner(connection); + sr.setLogWriter(null); + sr.runScript(new InputStreamReader(is)); + } + + UnpooledDataSource ds = new UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", ""); + Environment environment = new Environment("test", new JdbcTransactionFactory(), ds); + Configuration config = new Configuration(environment); + config.addMapper(JoinMapper.class); + config.addMapper(CommonSelectMapper.class); + sqlSessionFactory = new SqlSessionFactoryBuilder().build(config); + } + + @Test + void testExists() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + )) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(3); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + + row = rows.get(1); + assertThat(row).containsEntry("ITEM_ID", 33); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + + row = rows.get(2); + assertThat(row).containsEntry("ITEM_ID", 44); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + } + } + + @Test + void testNotExists() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(notExists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + )) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where not exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(1); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 55); + assertThat(row).containsEntry("DESCRIPTION", "Catcher Glove"); + } + } + + @Test + void testAndExists() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(itemMaster.itemId, isEqualTo(22)) + .and(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + )) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " and exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(1); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + } + } + + @Test + void testAndExistsAnd() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(itemMaster.itemId, isEqualTo(22)) + .and(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + ), and(itemMaster.itemId, isGreaterThan(2))) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " and (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER})" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(1); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + } + } + + @Test + void testOrExists() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(itemMaster.itemId, isEqualTo(22)) + .or(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + )) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " or exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(3); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + + row = rows.get(1); + assertThat(row).containsEntry("ITEM_ID", 33); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + + row = rows.get(2); + assertThat(row).containsEntry("ITEM_ID", 44); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + } + } + + @Test + void testOrExistsAnd() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(itemMaster.itemId, isEqualTo(22)) + .or(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + ), and(itemMaster.itemId, isGreaterThan(2))) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " or (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER})" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(3); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + + row = rows.get(1); + assertThat(row).containsEntry("ITEM_ID", 33); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + + row = rows.get(2); + assertThat(row).containsEntry("ITEM_ID", 44); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + } + } + + @Test + void testWhereExistsOr() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + ), or(itemMaster.itemId, isEqualTo(22))) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " or im.item_id = #{parameters.p1,jdbcType=INTEGER})" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(3); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + + row = rows.get(1); + assertThat(row).containsEntry("ITEM_ID", 33); + assertThat(row).containsEntry("DESCRIPTION", "First Base Glove"); + + row = rows.get(2); + assertThat(row).containsEntry("ITEM_ID", 44); + assertThat(row).containsEntry("DESCRIPTION", "Outfield Glove"); + } + } + + @Test + void testWhereExistsAnd() { + try (SqlSession session = sqlSessionFactory.openSession()) { + CommonSelectMapper mapper = session.getMapper(CommonSelectMapper.class); + + SelectStatementProvider selectStatement = select(itemMaster.allColumns()) + .from(itemMaster, "im") + .where(exists( + select(orderLine.allColumns()) + .from(orderLine, "ol") + .where(orderLine.itemId, isEqualTo(itemMaster.itemId.qualifiedWith("im"))) + ), and(itemMaster.itemId, isEqualTo(22))) + .orderBy(itemMaster.itemId) + .build() + .render(RenderingStrategies.MYBATIS3); + + String expectedStatement = "select im.* from ItemMaster im" + + " where (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id = #{parameters.p1,jdbcType=INTEGER})" + + " order by item_id"; + assertThat(selectStatement.getSelectStatement()).isEqualTo(expectedStatement); + + List> rows = mapper.selectManyMappedRows(selectStatement); + + assertThat(rows).hasSize(1); + Map row = rows.get(0); + assertThat(row).containsEntry("ITEM_ID", 22); + assertThat(row).containsEntry("DESCRIPTION", "Helmet"); + } + } +} diff --git a/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java b/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java index 9dfc504cf..dbcc484ea 100644 --- a/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/mybatis3/CriterionRendererTest.java @@ -16,7 +16,6 @@ package org.mybatis.dynamic.sql.mybatis3; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; import java.sql.JDBCType; import java.util.Date; @@ -25,8 +24,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.SqlColumn; -import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.render.TableAliasCalculator; @@ -41,23 +40,22 @@ void testAliasWithIgnore() { SqlColumn column = table.column("id", JDBCType.INTEGER); IsEqualTo condition = IsEqualTo.of(() -> 3); - SqlCriterion criterion = SqlCriterion.withColumn(column) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .build(); AtomicInteger sequence = new AtomicInteger(1); - FragmentAndParameters fp = CriterionRenderer.withCriterion(criterion) + + CriterionRenderer renderer = new CriterionRenderer.Builder() .withSequence(sequence) .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.empty()) - .build() - .render() - .get() - .fragmentAndParametersWithConnector(); - - assertAll( - () -> assertThat(fp.fragment()).isEqualTo("id = #{parameters.p1,jdbcType=INTEGER}"), - () -> assertThat(fp.parameters()).hasSize(1) - ); + .build(); + + assertThat(criterion.accept(renderer)).hasValueSatisfying(rc -> { + FragmentAndParameters fp = rc.fragmentAndParametersWithConnector(); + assertThat(fp.fragment()).isEqualTo("id = #{parameters.p1,jdbcType=INTEGER}"); + assertThat(fp.parameters()).hasSize(1); + }); } @Test @@ -65,25 +63,24 @@ void testAliasWithoutIgnore() { SqlTable table = SqlTable.of("foo"); SqlColumn column = table.column("id", JDBCType.INTEGER); IsEqualTo condition = IsEqualTo.of(() -> 3); - SqlCriterion criterion = SqlCriterion.withColumn(column) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .build(); AtomicInteger sequence = new AtomicInteger(1); Map tableAliases = new HashMap<>(); tableAliases.put(table, "a"); - FragmentAndParameters fp = CriterionRenderer.withCriterion(criterion) + + CriterionRenderer renderer = new CriterionRenderer.Builder() .withSequence(sequence) .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.of(tableAliases)) - .build() - .render() - .get() - .fragmentAndParametersWithConnector(); - - assertAll( - () -> assertThat(fp.fragment()).isEqualTo("a.id = #{parameters.p1,jdbcType=INTEGER}"), - () -> assertThat(fp.parameters()).hasSize(1) - ); + .build(); + + assertThat(criterion.accept(renderer)).hasValueSatisfying(rc -> { + FragmentAndParameters fp = rc.fragmentAndParametersWithConnector(); + assertThat(fp.fragment()).isEqualTo("a.id = #{parameters.p1,jdbcType=INTEGER}"); + assertThat(fp.parameters()).hasSize(1); + }); } @Test @@ -96,23 +93,22 @@ void testTypeHandler() { .withTypeHandler("foo.Bar") .build(); IsEqualTo condition = IsEqualTo.of(Date::new); - SqlCriterion criterion = SqlCriterion.withColumn(column) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .build(); AtomicInteger sequence = new AtomicInteger(1); - FragmentAndParameters fp = CriterionRenderer.withCriterion(criterion) + + CriterionRenderer renderer = new CriterionRenderer.Builder() .withSequence(sequence) .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.empty()) - .build() - .render() - .get() - .fragmentAndParametersWithConnector(); - - assertAll( - () -> assertThat(fp.fragment()).isEqualTo("id = #{parameters.p1,jdbcType=DATE,typeHandler=foo.Bar}"), - () -> assertThat(fp.parameters()).hasSize(1) - ); + .build(); + + assertThat(criterion.accept(renderer)).hasValueSatisfying(rc -> { + FragmentAndParameters fp = rc.fragmentAndParametersWithConnector(); + assertThat(fp.fragment()).isEqualTo("id = #{parameters.p1,jdbcType=DATE,typeHandler=foo.Bar}"); + assertThat(fp.parameters()).hasSize(1); + }); } @Test @@ -120,25 +116,23 @@ void testTypeHandlerAndAlias() { SqlTable table = SqlTable.of("foo"); SqlColumn column = table.column("id", JDBCType.INTEGER, "foo.Bar"); IsEqualTo condition = IsEqualTo.of(() -> 3); - SqlCriterion criterion = SqlCriterion.withColumn(column) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .build(); AtomicInteger sequence = new AtomicInteger(1); Map tableAliases = new HashMap<>(); tableAliases.put(table, "a"); - FragmentAndParameters fp = CriterionRenderer.withCriterion(criterion) + CriterionRenderer renderer = new CriterionRenderer.Builder() .withSequence(sequence) .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.of(tableAliases)) - .build() - .render() - .get() - .fragmentAndParametersWithConnector(); - - assertAll( - () -> assertThat(fp.fragment()).isEqualTo("a.id = #{parameters.p1,jdbcType=INTEGER,typeHandler=foo.Bar}"), - () -> assertThat(fp.parameters()).hasSize(1) - ); + .build(); + + assertThat(criterion.accept(renderer)).hasValueSatisfying(rc -> { + FragmentAndParameters fp = rc.fragmentAndParametersWithConnector(); + assertThat(fp.fragment()).isEqualTo("a.id = #{parameters.p1,jdbcType=INTEGER,typeHandler=foo.Bar}"); + assertThat(fp.parameters()).hasSize(1); + }); } } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java b/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java index 74b45b87f..b317287a7 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/render/CriterionRendererTest.java @@ -24,8 +24,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.ColumnAndConditionCriterion; import org.mybatis.dynamic.sql.SqlColumn; -import org.mybatis.dynamic.sql.SqlCriterion; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.render.RenderingStrategies; import org.mybatis.dynamic.sql.render.TableAliasCalculator; @@ -40,21 +40,22 @@ void testAliasWithIgnore() { SqlColumn column = table.column("id", JDBCType.INTEGER); IsEqualTo condition = IsEqualTo.of(() -> 3); - SqlCriterion criterion = SqlCriterion.withColumn(column) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .build(); AtomicInteger sequence = new AtomicInteger(1); - FragmentAndParameters fp = CriterionRenderer.withCriterion(criterion) + + CriterionRenderer renderer = new CriterionRenderer.Builder() .withSequence(sequence) .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.empty()) - .build() - .render() - .get() - .fragmentAndParametersWithConnector(); + .build(); - assertThat(fp.fragment()).isEqualTo("id = #{parameters.p1,jdbcType=INTEGER}"); - assertThat(fp.parameters()).containsExactly(entry("p1", 3)); + assertThat(criterion.accept(renderer)).hasValueSatisfying(rc -> { + FragmentAndParameters fp = rc.fragmentAndParameters(); + assertThat(fp.fragment()).isEqualTo("id = #{parameters.p1,jdbcType=INTEGER}"); + assertThat(fp.parameters()).containsExactly(entry("p1", 3)); + }); } @Test @@ -62,7 +63,7 @@ void testAliasWithoutIgnore() { SqlTable table = SqlTable.of("foo"); SqlColumn column = table.column("id", JDBCType.INTEGER); IsEqualTo condition = IsEqualTo.of(() -> 3); - SqlCriterion criterion = SqlCriterion.withColumn(column) + ColumnAndConditionCriterion criterion = ColumnAndConditionCriterion.withColumn(column) .withCondition(condition) .build(); AtomicInteger sequence = new AtomicInteger(1); @@ -70,16 +71,16 @@ void testAliasWithoutIgnore() { Map tableAliases = new HashMap<>(); tableAliases.put(table, "a"); - FragmentAndParameters fp = CriterionRenderer.withCriterion(criterion) + CriterionRenderer renderer = new CriterionRenderer.Builder() .withSequence(sequence) .withRenderingStrategy(RenderingStrategies.MYBATIS3) .withTableAliasCalculator(TableAliasCalculator.of(tableAliases)) - .build() - .render() - .get() - .fragmentAndParametersWithConnector(); + .build(); - assertThat(fp.fragment()).isEqualTo("a.id = #{parameters.p1,jdbcType=INTEGER}"); - assertThat(fp.parameters()).containsExactly(entry("p1", 3)); + assertThat(criterion.accept(renderer)).hasValueSatisfying(rc -> { + FragmentAndParameters fp = rc.fragmentAndParameters(); + assertThat(fp.fragment()).isEqualTo("a.id = #{parameters.p1,jdbcType=INTEGER}"); + assertThat(fp.parameters()).containsExactly(entry("p1", 3)); + }); } } diff --git a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java index 211c392e2..14537813a 100644 --- a/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java +++ b/src/test/java/org/mybatis/dynamic/sql/where/render/OptionalCriterionRenderTest.java @@ -180,4 +180,125 @@ void testOverrideFirstConnector() { () -> assertThat(whereClause.getWhereClause()).isEqualTo("where (first_name = :p1 or last_name = :p2)") ); } + + @Test + void testWhereExists() { + WhereClauseProvider whereClause = where( + exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(3)) + )) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + assertThat(whereClause.getParameters()).containsExactly(entry("p1", 3)); + assertThat(whereClause.getWhereClause()).isEqualTo("where exists (select * from person where id = :p1)"); + } + + @Test + void testWhereExistsOr() { + WhereClauseProvider whereClause = where( + exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(3)) + ), + or(exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(4)) + ))) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + String expected = "where (exists (select * from person where id = :p1) " + + "or exists (select * from person where id = :p2))"; + + assertThat(whereClause.getParameters()).containsExactly(entry("p1", 3), entry("p2", 4)); + assertThat(whereClause.getWhereClause()).isEqualTo(expected); + } + + @Test + void testWhereExistsOrOr() { + WhereClauseProvider whereClause = where( + exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(3)) + ), + or(exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(4)) + ), or(exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(5)) + + ) + ))) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + String expected = "where (exists (select * from person where id = :p1) " + + "or (exists (select * from person where id = :p2) " + + "or exists (select * from person where id = :p3)))"; + + assertThat(whereClause.getParameters()).containsExactly(entry("p1", 3), entry("p2", 4), entry("p3", 5)); + assertThat(whereClause.getWhereClause()).isEqualTo(expected); + } + + @Test + void testWhereExistsAnd() { + WhereClauseProvider whereClause = where( + exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(3)) + ), + and(exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(4)) + ))) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + String expected = "where (exists (select * from person where id = :p1) " + + "and exists (select * from person where id = :p2))"; + + assertThat(whereClause.getParameters()).containsExactly(entry("p1", 3), entry("p2", 4)); + assertThat(whereClause.getWhereClause()).isEqualTo(expected); + } + + @Test + void testWhereExistsAndAnd() { + WhereClauseProvider whereClause = where( + exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(3)) + ), + and(exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(4)) + ), and(exists( + select(person.allColumns()) + .from(person) + .where(id, isEqualTo(5)) + + ) + ))) + .build() + .render(RenderingStrategies.SPRING_NAMED_PARAMETER); + + String expected = "where (exists (select * from person where id = :p1) " + + "and (exists (select * from person where id = :p2) " + + "and exists (select * from person where id = :p3)))"; + + assertThat(whereClause.getParameters()).containsExactly(entry("p1", 3), entry("p2", 4), entry("p3", 5)); + assertThat(whereClause.getWhereClause()).isEqualTo(expected); + } } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonDynamicSqlSupport.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonDynamicSqlSupport.kt index e1ed83ab9..1ffd1bf11 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonDynamicSqlSupport.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonDynamicSqlSupport.kt @@ -17,7 +17,7 @@ package examples.kotlin.mybatis3.canonical import org.mybatis.dynamic.sql.SqlTable import java.sql.JDBCType -import java.util.* +import java.util.Date object PersonDynamicSqlSupport { object Person : SqlTable("Person") { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt index 7974473e0..775248753 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt @@ -25,8 +25,25 @@ import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.Person.lastNam import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.Person.occupation import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo -import org.mybatis.dynamic.sql.util.kotlin.* -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.* +import org.mybatis.dynamic.sql.util.kotlin.CountCompleter +import org.mybatis.dynamic.sql.util.kotlin.DeleteCompleter +import org.mybatis.dynamic.sql.util.kotlin.GeneralInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.InsertSelectCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinUpdateBuilder +import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter +import org.mybatis.dynamic.sql.util.kotlin.UpdateCompleter +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.count +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.countDistinct +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.countFrom +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.deleteFrom +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insert +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertInto +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertMultiple +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertSelect +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectDistinct +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectList +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectOne +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.update fun PersonMapper.count(column: BasicColumn, completer: CountCompleter) = count(this::count, column, Person, completer) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt index d857ae1e7..93db1b72e 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperTest.kt @@ -32,10 +32,20 @@ import org.apache.ibatis.session.SqlSessionFactoryBuilder import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -import org.mybatis.dynamic.sql.SqlBuilder.* +import org.mybatis.dynamic.sql.SqlBuilder.add +import org.mybatis.dynamic.sql.SqlBuilder.constant +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isFalse +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThan +import org.mybatis.dynamic.sql.SqlBuilder.isIn +import org.mybatis.dynamic.sql.SqlBuilder.isLessThan +import org.mybatis.dynamic.sql.SqlBuilder.isLike +import org.mybatis.dynamic.sql.SqlBuilder.isNotLike +import org.mybatis.dynamic.sql.SqlBuilder.isNull +import org.mybatis.dynamic.sql.SqlBuilder.isTrue import java.io.InputStreamReader import java.sql.DriverManager -import java.util.* +import java.util.Date class PersonMapperTest { private fun newSession(): SqlSession { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonRecord.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonRecord.kt index f254bcb64..d54667472 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonRecord.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonRecord.kt @@ -15,7 +15,7 @@ */ package examples.kotlin.mybatis3.canonical -import java.util.* +import java.util.Date data class PersonRecord( var id: Int? = null, diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddress.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddress.kt index d31b002a0..ee743b2d4 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddress.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddress.kt @@ -15,7 +15,7 @@ */ package examples.kotlin.mybatis3.canonical -import java.util.* +import java.util.Date data class PersonWithAddress( var id: Int? = null, diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt index fac87a795..fd1afacdd 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonWithAddressMapperExtensions.kt @@ -23,11 +23,14 @@ import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.Person.firstNa import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.Person.id import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.Person.lastName import examples.kotlin.mybatis3.canonical.PersonDynamicSqlSupport.Person.occupation -import org.mybatis.dynamic.sql.SqlBuilder.* +import org.mybatis.dynamic.sql.SqlBuilder.equalTo +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.select +import org.mybatis.dynamic.sql.SqlBuilder.selectDistinct import org.mybatis.dynamic.sql.util.kotlin.KotlinSelectBuilder import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectOne import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectList +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectOne fun PersonWithAddressMapper.selectOne(completer: SelectCompleter): PersonWithAddress? { val start = KotlinSelectBuilder(select(id.`as`("A_ID"), firstName, lastName, birthDate, diff --git a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt index 63805b1f0..52e07408b 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt @@ -41,18 +41,26 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test -import org.mybatis.dynamic.sql.SqlBuilder.* +import org.mybatis.dynamic.sql.SqlBuilder.count +import org.mybatis.dynamic.sql.SqlBuilder.equalTo +import org.mybatis.dynamic.sql.SqlBuilder.insert +import org.mybatis.dynamic.sql.SqlBuilder.insertMultiple +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThan +import org.mybatis.dynamic.sql.SqlBuilder.isLessThan +import org.mybatis.dynamic.sql.SqlBuilder.isNotEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isNotNull +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.count +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.countDistinct import org.mybatis.dynamic.sql.util.kotlin.mybatis3.countFrom import org.mybatis.dynamic.sql.util.kotlin.mybatis3.deleteFrom import org.mybatis.dynamic.sql.util.kotlin.mybatis3.into +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectDistinct import org.mybatis.dynamic.sql.util.kotlin.mybatis3.update import java.io.InputStreamReader import java.sql.DriverManager -import java.util.* -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.count -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.countDistinct -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.selectDistinct +import java.util.Date @Suppress("MaxLineLength", "LargeClass") class GeneralKotlinTest { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/Domain.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/Domain.kt index bfd69a4c2..109afbb93 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/Domain.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/Domain.kt @@ -15,7 +15,7 @@ */ package examples.kotlin.mybatis3.joins -import java.util.* +import java.util.Date data class OrderDetail( var orderId: Int? = null, diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/ExistsTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/ExistsTest.kt new file mode 100644 index 000000000..2a034658c --- /dev/null +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/ExistsTest.kt @@ -0,0 +1,541 @@ +/* + * Copyright 2016-2020 the original author or authors. + * + * 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 + * + * http://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. + */ +package examples.kotlin.mybatis3.joins + +import examples.kotlin.mybatis3.joins.ItemMasterDynamicSQLSupport.ItemMaster +import examples.kotlin.mybatis3.joins.OrderLineDynamicSQLSupport.OrderLine +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource +import org.apache.ibatis.jdbc.ScriptRunner +import org.apache.ibatis.mapping.Environment +import org.apache.ibatis.session.Configuration +import org.apache.ibatis.session.SqlSession +import org.apache.ibatis.session.SqlSessionFactoryBuilder +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThan +import org.mybatis.dynamic.sql.util.kotlin.exists +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select +import org.mybatis.dynamic.sql.util.kotlin.notExists +import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper +import java.io.InputStreamReader +import java.sql.DriverManager + +class ExistsTest { + + private fun newSession(): SqlSession { + Class.forName(JDBC_DRIVER) + val script = javaClass.getResourceAsStream("/examples/kotlin/mybatis3/joins/CreateJoinDB.sql") + + DriverManager.getConnection(JDBC_URL, "sa", "").use { connection -> + val sr = ScriptRunner(connection) + sr.setLogWriter(null) + sr.runScript(InputStreamReader(script)) + } + + val ds = UnpooledDataSource(JDBC_DRIVER, JDBC_URL, "sa", "") + val environment = Environment("test", JdbcTransactionFactory(), ds) + val config = Configuration(environment) + config.addMapper(CommonSelectMapper::class.java) + return SqlSessionFactoryBuilder().build(config).openSession() + } + + @Test + fun testExists() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + orderBy(ItemMaster.itemId) + } + + val expectedStatement: String = "select im.* from ItemMaster im" + + " where exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(3) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + + with(rows[1]) { + assertThat(this).containsEntry("ITEM_ID", 33) + assertThat(this).containsEntry("DESCRIPTION", "First Base Glove") + } + + with(rows[2]) { + assertThat(this).containsEntry("ITEM_ID", 44) + assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove") + } + } + } + + @Test + fun testNotExists() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(notExists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + orderBy(ItemMaster.itemId) + } + + val expectedStatement: String = "select im.* from ItemMaster im" + + " where not exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 55) + assertThat(this).containsEntry("DESCRIPTION", "Catcher Glove") + } + } + } + + @Test + fun testAndExists() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) + and(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " and exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id" + + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + } + } + + @Test + fun testAndExistsAnd() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) + and(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) { + and(ItemMaster.itemId, isGreaterThan(2)) + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " and (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER})" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + } + } + + @Test + fun testAndExistsAnd2() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) { + and(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + and(ItemMaster.itemId, isGreaterThan(2)) + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " and exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER})" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + } + } + + @Test + fun testAndExistsAnd3() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) { + and(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) { + and(ItemMaster.itemId, isGreaterThan(2)) + } + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " and (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER}))" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + } + } + + @Test + fun testOrExists() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) + or(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " or exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(3) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + + with(rows[1]) { + assertThat(this).containsEntry("ITEM_ID", 33) + assertThat(this).containsEntry("DESCRIPTION", "First Base Glove") + } + + with(rows[2]) { + assertThat(this).containsEntry("ITEM_ID", 44) + assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove") + } + } + } + + @Test + fun testOrExistsAnd() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) + or(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where( + OrderLine.itemId, + isEqualTo( + ItemMaster.itemId.qualifiedWith("im") + ) + ) + } + }) { + and(ItemMaster.itemId, isGreaterThan(2)) + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " or (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER})" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(3) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + + with(rows[1]) { + assertThat(this).containsEntry("ITEM_ID", 33) + assertThat(this).containsEntry("DESCRIPTION", "First Base Glove") + } + + with(rows[2]) { + assertThat(this).containsEntry("ITEM_ID", 44) + assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove") + } + } + } + + @Test + fun testOrExistsAnd2() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) { + or(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) + and(ItemMaster.itemId, isGreaterThan(2)) + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " or exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER})" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(3) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + + with(rows[1]) { + assertThat(this).containsEntry("ITEM_ID", 33) + assertThat(this).containsEntry("DESCRIPTION", "First Base Glove") + } + + with(rows[2]) { + assertThat(this).containsEntry("ITEM_ID", 44) + assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove") + } + } + } + + @Test + fun testOrExistsAnd3() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(ItemMaster.itemId, isEqualTo(22)) { + or(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) { + and(ItemMaster.itemId, isGreaterThan(2)) + } + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" + + " or (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id > #{parameters.p2,jdbcType=INTEGER}))" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(3) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + + with(rows[1]) { + assertThat(this).containsEntry("ITEM_ID", 33) + assertThat(this).containsEntry("DESCRIPTION", "First Base Glove") + } + + with(rows[2]) { + assertThat(this).containsEntry("ITEM_ID", 44) + assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove") + } + } + } + + @Test + fun testWhereExistsOr() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) { + or(ItemMaster.itemId, isEqualTo(22)) + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " or im.item_id = #{parameters.p1,jdbcType=INTEGER})" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(3) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + + with(rows[1]) { + assertThat(this).containsEntry("ITEM_ID", 33) + assertThat(this).containsEntry("DESCRIPTION", "First Base Glove") + } + + with(rows[2]) { + assertThat(this).containsEntry("ITEM_ID", 44) + assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove") + } + } + } + + @Test + fun testWhereExistsAnd() { + newSession().use { session -> + val mapper = session.getMapper(CommonSelectMapper::class.java) + + val selectStatement = select(ItemMaster.allColumns()) { + from(ItemMaster, "im") + where(exists { + select(OrderLine.allColumns()) { + from(OrderLine, "ol") + where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im"))) + } + }) { + and(ItemMaster.itemId, isEqualTo(22)) + } + orderBy(ItemMaster.itemId) + } + + val expectedStatement = "select im.* from ItemMaster im" + + " where (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" + + " and im.item_id = #{parameters.p1,jdbcType=INTEGER})" + + " order by item_id" + assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement) + + val rows = mapper.selectManyMappedRows(selectStatement) + assertThat(rows).hasSize(1) + + with(rows[0]) { + assertThat(this).containsEntry("ITEM_ID", 22) + assertThat(this).containsEntry("DESCRIPTION", "Helmet") + } + } + } + + companion object { + const val JDBC_URL = "jdbc:hsqldb:mem:aname" + const val JDBC_DRIVER = "org.hsqldb.jdbcDriver" + } +} diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/ItemMasterDynamicSQLSupport.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/ItemMasterDynamicSQLSupport.kt index d0851ed3f..d9b40951a 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/ItemMasterDynamicSQLSupport.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/ItemMasterDynamicSQLSupport.kt @@ -17,7 +17,7 @@ package examples.kotlin.mybatis3.joins import org.mybatis.dynamic.sql.SqlTable import java.sql.JDBCType -import java.util.* +import java.util.Date object ItemMasterDynamicSQLSupport { object ItemMaster : SqlTable("ItemMaster") { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt index dd4f80a70..73e3b58c9 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt @@ -29,10 +29,11 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.entry import org.junit.jupiter.api.Test -import org.mybatis.dynamic.sql.SqlBuilder.* +import org.mybatis.dynamic.sql.SqlBuilder.equalTo +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select import java.io.InputStreamReader import java.sql.DriverManager -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select class JoinMapperTest { @@ -535,7 +536,7 @@ class JoinMapperTest { join(OrderLine, "ol") { on(OrderMaster.orderId, equalTo(OrderLine.orderId)) } - rightJoin ({ + rightJoin({ select(ItemMaster.allColumns()) { from(ItemMaster) } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/OrderMasterDynamicSQLSupport.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/OrderMasterDynamicSQLSupport.kt index 9918d15fc..9404fb9e2 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/OrderMasterDynamicSQLSupport.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/OrderMasterDynamicSQLSupport.kt @@ -17,7 +17,7 @@ package examples.kotlin.mybatis3.joins import org.mybatis.dynamic.sql.SqlTable import java.sql.JDBCType -import java.util.* +import java.util.Date object OrderMasterDynamicSQLSupport { object OrderMaster : SqlTable("OrderMaster") { diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt index a86316cd2..a65183afb 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt @@ -28,13 +28,33 @@ import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.Person.occupatio import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.mybatis.dynamic.sql.SqlBuilder.* -import org.mybatis.dynamic.sql.util.kotlin.spring.* +import org.mybatis.dynamic.sql.SqlBuilder.add +import org.mybatis.dynamic.sql.SqlBuilder.constant +import org.mybatis.dynamic.sql.SqlBuilder.equalTo +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThan +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThanOrEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isLessThan +import org.mybatis.dynamic.sql.SqlBuilder.isNotNull +import org.mybatis.dynamic.sql.util.kotlin.spring.count +import org.mybatis.dynamic.sql.util.kotlin.spring.countDistinct +import org.mybatis.dynamic.sql.util.kotlin.spring.countFrom +import org.mybatis.dynamic.sql.util.kotlin.spring.deleteFrom +import org.mybatis.dynamic.sql.util.kotlin.spring.insert +import org.mybatis.dynamic.sql.util.kotlin.spring.insertBatch +import org.mybatis.dynamic.sql.util.kotlin.spring.insertInto +import org.mybatis.dynamic.sql.util.kotlin.spring.insertMultiple +import org.mybatis.dynamic.sql.util.kotlin.spring.insertSelect +import org.mybatis.dynamic.sql.util.kotlin.spring.select +import org.mybatis.dynamic.sql.util.kotlin.spring.selectDistinct +import org.mybatis.dynamic.sql.util.kotlin.spring.selectOne +import org.mybatis.dynamic.sql.util.kotlin.spring.update +import org.mybatis.dynamic.sql.util.kotlin.spring.withKeyHolder import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType import org.springframework.jdbc.support.GeneratedKeyHolder -import java.util.* +import java.util.Date class CanonicalSpringKotlinTemplateDirectTest { private lateinit var template: NamedParameterJdbcTemplate diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt index c64a0e99f..155e72aff 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt @@ -28,13 +28,42 @@ import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.Person.occupatio import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.mybatis.dynamic.sql.SqlBuilder.* -import org.mybatis.dynamic.sql.util.kotlin.spring.* +import org.mybatis.dynamic.sql.SqlBuilder.add +import org.mybatis.dynamic.sql.SqlBuilder.constant +import org.mybatis.dynamic.sql.SqlBuilder.equalTo +import org.mybatis.dynamic.sql.SqlBuilder.insert +import org.mybatis.dynamic.sql.SqlBuilder.insertBatch +import org.mybatis.dynamic.sql.SqlBuilder.insertMultiple +import org.mybatis.dynamic.sql.SqlBuilder.isEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThan +import org.mybatis.dynamic.sql.SqlBuilder.isGreaterThanOrEqualTo +import org.mybatis.dynamic.sql.SqlBuilder.isLessThan +import org.mybatis.dynamic.sql.SqlBuilder.isNotNull +import org.mybatis.dynamic.sql.SqlBuilder.isNull +import org.mybatis.dynamic.sql.SqlBuilder.max +import org.mybatis.dynamic.sql.SqlBuilder.sortColumn +import org.mybatis.dynamic.sql.util.kotlin.spring.count +import org.mybatis.dynamic.sql.util.kotlin.spring.countDistinct +import org.mybatis.dynamic.sql.util.kotlin.spring.countFrom +import org.mybatis.dynamic.sql.util.kotlin.spring.delete +import org.mybatis.dynamic.sql.util.kotlin.spring.deleteFrom +import org.mybatis.dynamic.sql.util.kotlin.spring.generalInsert +import org.mybatis.dynamic.sql.util.kotlin.spring.insert +import org.mybatis.dynamic.sql.util.kotlin.spring.insertBatch +import org.mybatis.dynamic.sql.util.kotlin.spring.insertInto +import org.mybatis.dynamic.sql.util.kotlin.spring.insertMultiple +import org.mybatis.dynamic.sql.util.kotlin.spring.insertSelect +import org.mybatis.dynamic.sql.util.kotlin.spring.into +import org.mybatis.dynamic.sql.util.kotlin.spring.select +import org.mybatis.dynamic.sql.util.kotlin.spring.selectDistinct +import org.mybatis.dynamic.sql.util.kotlin.spring.selectList +import org.mybatis.dynamic.sql.util.kotlin.spring.selectOne +import org.mybatis.dynamic.sql.util.kotlin.spring.update import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType import org.springframework.jdbc.support.GeneratedKeyHolder -import java.util.* +import java.util.Date @Suppress("LargeClass", "MaxLineLength") class CanonicalSpringKotlinTest { @@ -602,7 +631,8 @@ class CanonicalSpringKotlinTest { "from Person " + "where id = :p2 " + "union " + - "select p.id as A_ID, p.first_name, p.last_name, p.birth_date, p.employed, p.occupation, p.address_id " + + "select p.id as A_ID, p.first_name, p.last_name, p.birth_date, p.employed, p.occupation, " + + "p.address_id " + "from Person p " + "where p.id = :p3" @@ -665,7 +695,8 @@ class CanonicalSpringKotlinTest { "from Person " + "where id = :p2 " + "union " + - "select distinct p.id as A_ID, p.first_name, p.last_name, p.birth_date, p.employed, p.occupation, p.address_id " + + "select distinct p.id as A_ID, p.first_name, p.last_name, p.birth_date, p.employed, p.occupation, " + + "p.address_id " + "from Person p " + "where p.id = :p3" @@ -730,7 +761,8 @@ class CanonicalSpringKotlinTest { "from Person " + "where id = :p2 " + "union all " + - "select distinct p.id as A_ID, p.first_name, p.last_name, p.birth_date, p.employed, p.occupation, p.address_id " + + "select distinct p.id as A_ID, p.first_name, p.last_name, p.birth_date, p.employed, p.occupation, " + + "p.address_id " + "from Person p " + "order by A_ID" @@ -1175,7 +1207,6 @@ class CanonicalSpringKotlinTest { assertThat(returnedRecord!!.addressId).isEqualTo(3) } - @Test fun testUpdateSetEqualToWhenPresent() { val updateStatement = update(Person) { diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/DomainAndConverters.kt b/src/test/kotlin/examples/kotlin/spring/canonical/DomainAndConverters.kt index 7e9ca39f9..07a9ee288 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/DomainAndConverters.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/DomainAndConverters.kt @@ -15,7 +15,7 @@ */ package examples.kotlin.spring.canonical -import java.util.* +import java.util.Date data class LastName(val name: String) diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/PersonDynamicSqlSupport.kt b/src/test/kotlin/examples/kotlin/spring/canonical/PersonDynamicSqlSupport.kt index 12dcb5f6f..506e85004 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/PersonDynamicSqlSupport.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/PersonDynamicSqlSupport.kt @@ -17,7 +17,7 @@ package examples.kotlin.spring.canonical import org.mybatis.dynamic.sql.SqlTable import java.sql.JDBCType -import java.util.* +import java.util.Date object PersonDynamicSqlSupport { object Person : SqlTable("Person") { diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt index 6cb21e5df..6bd2a2748 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/SpringKotlinSubQueryTest.kt @@ -22,12 +22,13 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mybatis.dynamic.sql.DerivedColumn -import org.mybatis.dynamic.sql.SqlBuilder.* +import org.mybatis.dynamic.sql.SqlBuilder.isLessThan +import org.mybatis.dynamic.sql.SqlBuilder.isLike +import org.mybatis.dynamic.sql.util.kotlin.spring.select import org.mybatis.dynamic.sql.util.kotlin.spring.selectList import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType -import org.mybatis.dynamic.sql.util.kotlin.spring.select class SpringKotlinSubQueryTest { private lateinit var template: NamedParameterJdbcTemplate