diff --git a/CHANGELOG.md b/CHANGELOG.md index 86e260063..b0862688c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ For examples of global and statement configuration, see the "Configuration of th 4. Added the ability to configure the library and change some default behaviors. Currently, this is limited to changing the behavior of the library in regard to where clauses that will not render. See the "Configuration of the Library" page for details. ([#515](https://github.com/mybatis/mybatis-dynamic-sql/pull/515)) +5. Added several checks for invalid SQL ([#516](https://github.com/mybatis/mybatis-dynamic-sql/pull/516)) ## Release 1.4.0 - March 3, 2022 diff --git a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java index b6f3e64d3..3891e18ac 100644 --- a/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/AbstractListValueCondition.java @@ -28,6 +28,8 @@ public abstract class AbstractListValueCondition implements VisitableConditio protected final Collection values; /** + * Callback to execute when the list is empty. + * * @deprecated in favor of the statement configuration functions */ @Deprecated @@ -38,9 +40,11 @@ protected AbstractListValueCondition(Collection values) { } /** - * @deprecated in favor of the statement configuration functions + * Construct a new condition with a callback. + * * @param values values * @param emptyCallback empty callback + * @deprecated in favor of the statement configuration functions */ @Deprecated protected AbstractListValueCondition(Collection values, Callback emptyCallback) { @@ -110,9 +114,9 @@ protected > S mapSupport(Function withListEmptyCallback(Callback callback); diff --git a/src/main/java/org/mybatis/dynamic/sql/Callback.java b/src/main/java/org/mybatis/dynamic/sql/Callback.java index 4e38c2864..60b952a03 100644 --- a/src/main/java/org/mybatis/dynamic/sql/Callback.java +++ b/src/main/java/org/mybatis/dynamic/sql/Callback.java @@ -18,6 +18,8 @@ import java.util.function.Function; /** + * Provides a callback function for empty "in" conditions. + * * @deprecated in favor of the new statement configuration functionality */ @Deprecated diff --git a/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java b/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java new file mode 100644 index 000000000..31edcc9e6 --- /dev/null +++ b/src/main/java/org/mybatis/dynamic/sql/exception/InvalidSqlException.java @@ -0,0 +1,22 @@ +/* + * Copyright 2016-2022 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.exception; + +public class InvalidSqlException extends RuntimeException { + public InvalidSqlException(String message) { + super(message); + } +} diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java index 010770b37..907dae563 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/AbstractMultiRowInsertModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -29,7 +29,7 @@ public abstract class AbstractMultiRowInsertModel { private final SqlTable table; private final List records; - private final List columnMappings; + protected final List columnMappings; protected AbstractMultiRowInsertModel(AbstractBuilder builder) { table = Objects.requireNonNull(builder.table); diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java index 5d286854e..85922ffd6 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -18,6 +18,7 @@ import java.util.Collection; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.insert.render.BatchInsert; import org.mybatis.dynamic.sql.insert.render.BatchInsertRenderer; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -26,6 +27,9 @@ public class BatchInsertModel extends AbstractMultiRowInsertModel { private BatchInsertModel(Builder builder) { super(builder); + if (columnMappings.isEmpty()) { + throw new InvalidSqlException("Batch insert statements must have at least one column mapping"); + } } @NotNull diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java index 1db817af5..d5229e008 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.insert.render.GeneralInsertRenderer; import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -35,6 +36,9 @@ public class GeneralInsertModel { private GeneralInsertModel(Builder builder) { table = Objects.requireNonNull(builder.table); + if (builder.insertMappings.isEmpty()) { + throw new InvalidSqlException("General insert statements must have at least one column mapping"); + } insertMappings = builder.insertMappings; } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java index beb77ef78..2ac8b65a2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertColumnListModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -17,15 +17,22 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Stream; import org.mybatis.dynamic.sql.SqlColumn; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; public class InsertColumnListModel { private final List> columns = new ArrayList<>(); private InsertColumnListModel(List> columns) { + Objects.requireNonNull(columns); + if (columns.isEmpty()) { + throw new InvalidSqlException("Insert select statements require at least one column in the column list"); + } + this.columns.addAll(columns); } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java index 6409fa8b6..9090a02b4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 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. @@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.insert.render.InsertRenderer; import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -37,6 +38,9 @@ private InsertModel(Builder builder) { table = Objects.requireNonNull(builder.table); row = Objects.requireNonNull(builder.row); columnMappings = Objects.requireNonNull(builder.columnMappings); + if (columnMappings.isEmpty()) { + throw new InvalidSqlException("Insert statements must have at least one column mapping"); // $NON-NLS-1$ + } } public Stream mapColumnMappings(Function mapper) { diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java index 8c70d8d30..291b92778 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -18,6 +18,7 @@ import java.util.Collection; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.insert.render.MultiRowInsertRenderer; import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; import org.mybatis.dynamic.sql.render.RenderingStrategy; @@ -26,6 +27,9 @@ public class MultiRowInsertModel extends AbstractMultiRowInsertModel { private MultiRowInsertModel(Builder builder) { super(builder); + if (columnMappings.isEmpty()) { + throw new InvalidSqlException("Multi row insert statements must have at least one column mapping"); + } } @NotNull diff --git a/src/main/java/org/mybatis/dynamic/sql/select/GroupByModel.java b/src/main/java/org/mybatis/dynamic/sql/select/GroupByModel.java index 08c212def..5681a3ab3 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/GroupByModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/GroupByModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -18,15 +18,21 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Stream; import org.mybatis.dynamic.sql.BasicColumn; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; public class GroupByModel { private final List columns = new ArrayList<>(); private GroupByModel(Collection columns) { + Objects.requireNonNull(columns); + if (columns.isEmpty()) { + throw new InvalidSqlException("Group by expressions must have at least one column"); + } this.columns.addAll(columns); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/OrderByModel.java b/src/main/java/org/mybatis/dynamic/sql/select/OrderByModel.java index 717cb76b4..85bb2ada1 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/OrderByModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/OrderByModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -18,15 +18,21 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Stream; import org.mybatis.dynamic.sql.SortSpecification; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; public class OrderByModel { private final List columns = new ArrayList<>(); private OrderByModel(Collection columns) { + Objects.requireNonNull(columns); + if (columns.isEmpty()) { + throw new InvalidSqlException("Order by expressions must have at least one column"); + } this.columns.addAll(columns); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java index 8c6a1aad9..37a989daa 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/QueryExpressionModel.java @@ -27,6 +27,7 @@ import org.mybatis.dynamic.sql.BasicColumn; import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.TableExpression; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.select.join.JoinModel; import org.mybatis.dynamic.sql.where.WhereModel; @@ -49,6 +50,10 @@ private QueryExpressionModel(Builder builder) { tableAliases = builder.tableAliases; whereModel = builder.whereModel; groupByModel = builder.groupByModel; + + if (selectList.isEmpty()) { + throw new InvalidSqlException("Query expressions must have at least one column in the select list"); + } } public Optional connector() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java index 147cfc472..6ed630c09 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/SelectModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -23,6 +23,7 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.select.render.SelectRenderer; import org.mybatis.dynamic.sql.select.render.SelectStatementProvider; @@ -34,6 +35,10 @@ public class SelectModel { private SelectModel(Builder builder) { queryExpressions = Objects.requireNonNull(builder.queryExpressions); + if (queryExpressions.isEmpty()) { + throw new InvalidSqlException("Select statements must have at least one query expression"); + } + orderByModel = builder.orderByModel; pagingModel = builder.pagingModel; } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java index c18f61045..282f3e63e 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -15,13 +15,15 @@ */ package org.mybatis.dynamic.sql.select.join; +import java.util.Objects; + import org.mybatis.dynamic.sql.BasicColumn; public abstract class JoinCondition { private final BasicColumn rightColumn; protected JoinCondition(BasicColumn rightColumn) { - this.rightColumn = rightColumn; + this.rightColumn = Objects.requireNonNull(rightColumn); } public BasicColumn rightColumn() { diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java index dc5174e22..5523b6872 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -17,15 +17,22 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Stream; import org.mybatis.dynamic.sql.TableExpression; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; public class JoinModel { private final List joinSpecifications = new ArrayList<>(); private JoinModel(List joinSpecifications) { + Objects.requireNonNull(joinSpecifications); + if (joinSpecifications.isEmpty()) { + throw new InvalidSqlException("Joins must have at least one join specification"); + } + this.joinSpecifications.addAll(joinSpecifications); } diff --git a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java index eee86a7ef..748dddba8 100644 --- a/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java +++ b/src/main/java/org/mybatis/dynamic/sql/select/join/JoinSpecification.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 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. @@ -22,6 +22,7 @@ import java.util.stream.Stream; import org.mybatis.dynamic.sql.TableExpression; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; public class JoinSpecification { @@ -33,6 +34,10 @@ private JoinSpecification(Builder builder) { table = Objects.requireNonNull(builder.table); joinCriteria = Objects.requireNonNull(builder.joinCriteria); joinType = Objects.requireNonNull(builder.joinType); + + if (joinCriteria.isEmpty()) { + throw new InvalidSqlException("Join specifications must have at least one join criterion"); + } } public TableExpression table() { diff --git a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java index 338aecf92..de8604596 100644 --- a/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java +++ b/src/main/java/org/mybatis/dynamic/sql/update/UpdateModel.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlTable; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; import org.mybatis.dynamic.sql.render.RenderingStrategy; import org.mybatis.dynamic.sql.update.render.UpdateRenderer; import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider; @@ -41,6 +42,10 @@ private UpdateModel(Builder builder) { whereModel = builder.whereModel; columnMappings = Objects.requireNonNull(builder.columnMappings); tableAlias = builder.tableAlias; + + if (columnMappings.isEmpty()) { + throw new InvalidSqlException("Update statements must have at least one set phrase"); + } } public SqlTable table() { diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java index c579f57b8..3bb410dc4 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsIn.java @@ -39,8 +39,10 @@ public static IsIn empty() { } /** - * @deprecated in favor of the statement configuration functions + * Build an empty condition. + * * @return a new empty condition + * @deprecated in favor of the statement configuration functions */ @Deprecated private IsIn emptyWithCallBack() { @@ -52,9 +54,11 @@ protected IsIn(Collection values) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new condition with a callback. + * * @param values values * @param emptyCallback empty callback + * @deprecated in favor of the statement configuration functions */ @Deprecated protected IsIn(Collection values, Callback emptyCallback) { @@ -68,9 +72,11 @@ public String renderCondition(String columnName, Stream placeholders) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new condition with a callback. + * * @param callback a callback function - typically throws an exception to block the statement from executing * @return this condition + * @deprecated in favor of the statement configuration functions */ @Deprecated @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java index ddbf948c4..2686be3f5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsInCaseInsensitive.java @@ -35,8 +35,10 @@ public static IsInCaseInsensitive empty() { } /** - * @deprecated in favor of the statement configuration functions + * Build an empty condition. + * * @return a new empty condition + * @deprecated in favor of the statement configuration functions */ @Deprecated private IsInCaseInsensitive emptyWithCallback() { @@ -48,9 +50,11 @@ protected IsInCaseInsensitive(Collection values) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new instance with a callback. + * * @param values values * @param emptyCallback empty callback + * @deprecated in favor of the statement configuration functions */ @Deprecated protected IsInCaseInsensitive(Collection values, Callback emptyCallback) { @@ -65,9 +69,11 @@ public String renderCondition(String columnName, Stream placeholders) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new instance with a callback. + * * @param callback a callback function - typically throws an exception to block the statement from executing * @return this condition + * @deprecated in favor of the statement configuration functions */ @Deprecated @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java index 44102bf9f..7f7afa35f 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotIn.java @@ -39,8 +39,10 @@ public static IsNotIn empty() { } /** - * @deprecated in favor of the statement configuration functions + * Build an empty condition. + * * @return a new empty condition + * @deprecated in favor of the statement configuration functions */ @Deprecated private IsNotIn emptyWithCallback() { @@ -52,9 +54,11 @@ protected IsNotIn(Collection values) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new condition with a callback. + * * @param values values * @param emptyCallback empty callback + * @deprecated in favor of the statement configuration functions */ @Deprecated protected IsNotIn(Collection values, Callback emptyCallback) { @@ -69,10 +73,11 @@ public String renderCondition(String columnName, Stream placeholders) { } /** + * Build a new instance with a callback. * - * @deprecated in favor of the statement configuration functions * @param callback a callback function - typically throws an exception to block the statement from executing * @return this condition + * @deprecated in favor of the statement configuration functions */ @Deprecated @Override diff --git a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java index df1735ed2..216849275 100644 --- a/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java +++ b/src/main/java/org/mybatis/dynamic/sql/where/condition/IsNotInCaseInsensitive.java @@ -35,8 +35,10 @@ public static IsNotInCaseInsensitive empty() { } /** - * @deprecated in favor of the statement configuration functions + * Build an empty condition. + * * @return a new empty condition + * @deprecated in favor of the statement configuration functions */ @Deprecated private IsNotInCaseInsensitive emptyWithCallback() { @@ -48,9 +50,11 @@ protected IsNotInCaseInsensitive(Collection values) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new instance with a callback. + * * @param values values * @param emptyCallback empty callback + * @deprecated in favor of the statement configuration functions */ @Deprecated protected IsNotInCaseInsensitive(Collection values, Callback emptyCallback) { @@ -65,9 +69,11 @@ public String renderCondition(String columnName, Stream placeholders) { } /** - * @deprecated in favor of the statement configuration functions + * Build a new instance with a callback. + * * @param callback a callback function - typically throws an exception to block the statement from executing * @return this condition + * @deprecated in favor of the statement configuration functions */ @Deprecated @Override diff --git a/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java new file mode 100644 index 000000000..e42fc089e --- /dev/null +++ b/src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java @@ -0,0 +1,179 @@ +/* + * Copyright 2016-2022 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 static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.mybatis.dynamic.sql.exception.InvalidSqlException; +import org.mybatis.dynamic.sql.insert.BatchInsertModel; +import org.mybatis.dynamic.sql.insert.GeneralInsertModel; +import org.mybatis.dynamic.sql.insert.InsertColumnListModel; +import org.mybatis.dynamic.sql.insert.InsertModel; +import org.mybatis.dynamic.sql.insert.MultiRowInsertModel; +import org.mybatis.dynamic.sql.select.GroupByModel; +import org.mybatis.dynamic.sql.select.OrderByModel; +import org.mybatis.dynamic.sql.select.QueryExpressionModel; +import org.mybatis.dynamic.sql.select.SelectModel; +import org.mybatis.dynamic.sql.select.join.JoinModel; +import org.mybatis.dynamic.sql.select.join.JoinSpecification; +import org.mybatis.dynamic.sql.select.join.JoinType; +import org.mybatis.dynamic.sql.update.UpdateModel; + +class InvalidSQLTest { + + private static final SqlTable person = new SqlTable("person"); + + @Test + void testInvalidGeneralInsertStatement() { + GeneralInsertModel.Builder builder = new GeneralInsertModel.Builder() + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("General insert statements must have at least one column mapping"); + } + + @Test + void testInvalidInsertStatement() { + InsertModel.Builder builder = new InsertModel.Builder() + .withTable(person) + .withRow("fred"); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Insert statements must have at least one column mapping"); + } + + @Test + void testInvalidMultipleInsertStatementNoRecords() { + MultiRowInsertModel.Builder builder = new MultiRowInsertModel.Builder() + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Multi row insert statements must have at least one column mapping"); + } + + @Test + void testInvalidMultipleInsertStatementNoMappings() { + List records = new ArrayList<>(); + records.add("fred"); + + MultiRowInsertModel.Builder builder = new MultiRowInsertModel.Builder() + .withRecords(records) + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Multi row insert statements must have at least one column mapping"); + } + + @Test + void testInvalidBatchInsertStatementNoRecords() { + BatchInsertModel.Builder builder = new BatchInsertModel.Builder() + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Batch insert statements must have at least one column mapping"); + } + + @Test + void testInvalidBatchInsertStatementNoMappings() { + List records = new ArrayList<>(); + records.add("fred"); + + BatchInsertModel.Builder builder = new BatchInsertModel.Builder() + .withRecords(records) + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Batch insert statements must have at least one column mapping"); + } + + @Test + void testInvalidEmptyInsertColumnList() { + List> list = Collections.emptyList(); + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> InsertColumnListModel.of(list)) + .withMessage("Insert select statements require at least one column in the column list"); + } + + @Test + void testInvalidNullInsertColumnList() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> InsertColumnListModel.of(null)); + } + + @Test + void testInvalidSelectStatementWithoutQueryExpressions() { + SelectModel.Builder builder = new SelectModel.Builder(); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Select statements must have at least one query expression"); + } + + @Test + void testInvalidSelectStatementWithoutColumnList() { + QueryExpressionModel.Builder builder = new QueryExpressionModel.Builder() + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Query expressions must have at least one column in the select list"); + } + + @Test + void testInvalidSelectStatementEmptyJoinModel() { + List list = Collections.emptyList(); + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> JoinModel.of(list)) + .withMessage("Joins must have at least one join specification"); + } + + @Test + void testInvalidSelectStatementNullJoinModel() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> JoinModel.of(null)); + } + + @Test + void testInvalidSelectStatementJoinSpecification() { + JoinSpecification.Builder builder = new JoinSpecification.Builder() + .withJoinTable(person) + .withJoinType(JoinType.LEFT); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Join specifications must have at least one join criterion"); + } + @Test + void testInvalidSelectStatementWithEmptyOrderByList() { + List list = Collections.emptyList(); + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> OrderByModel.of(list)) + .withMessage("Order by expressions must have at least one column"); + } + + @Test + void testInvalidSelectStatementWithEmptyGroupByList() { + List list = Collections.emptyList(); + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> GroupByModel.of(list)) + .withMessage("Group by expressions must have at least one column"); + } + + @Test + void testInvalidUpdateStatement() { + UpdateModel.Builder builder = new UpdateModel.Builder() + .withTable(person); + + assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build) + .withMessage("Update statements must have at least one set phrase"); + } +}