diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CaseQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CaseQueryColumn.java new file mode 100644 index 00000000..199cd774 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CaseQueryColumn.java @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * 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 com.mybatisflex.core.query; + +import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.util.ArrayUtil; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; +import com.mybatisflex.core.util.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +public class CaseQueryColumn extends QueryColumn implements HasParamsColumn{ + + private List whens; + private Object elseValue; + + void addWhen(When when) { + if (whens == null) { + whens = new ArrayList<>(); + } + whens.add(when); + } + + + @Override + String toSelectSql(List queryTables, IDialect dialect) { + StringBuilder sql = new StringBuilder("CASE"); + for (When when : whens) { + sql.append(" WHEN ").append(when.whenCondition.toSql(queryTables, dialect)); + sql.append(" THEN ").append(buildValue(when.thenValue)); + } + if (elseValue != null) { + sql.append(" ELSE ").append(buildValue(elseValue)); + } + sql.append(" END"); + if (StringUtil.isNotBlank(alias)) { + return "(" + sql + ") AS " + dialect.wrap(alias); + } + return sql.toString(); + } + + + @Override + String toConditionSql(List queryTables, IDialect dialect) { + StringBuilder sql = new StringBuilder("CASE"); + for (When when : whens) { + sql.append(" WHEN ").append(when.whenCondition.toSql(queryTables, dialect)); + sql.append(" THEN ").append(buildValue(when.thenValue)); + } + if (elseValue != null) { + sql.append(" ELSE ").append(buildValue(elseValue)); + } + sql.append(" END"); + return "(" + sql + ")"; + } + + @Override + public QueryColumn as(String alias) { + this.alias = alias; + return this; + } + + @Override + public QueryColumn as(LambdaGetter fn) { + return as(LambdaUtil.getFieldName(fn)); + } + + private String buildValue(Object value) { + if (value instanceof Number || value instanceof Boolean) { + return String.valueOf(value); + } else { + return "'" + value + "'"; + } + } + + @Override + public Object[] getParamValues() { + Object[] values = new Object[0]; + for (When when : whens) { + values = ArrayUtil.concat(values, WrapperUtil.getValues(when.whenCondition)); + } + return values; + } + + + public static class When { + private Builder builder; + private QueryCondition whenCondition; + private Object thenValue; + + public When(Builder builder, QueryCondition whenCondition) { + this.builder = builder; + this.whenCondition = whenCondition; + } + + public Builder then(Object thenValue) { + this.thenValue = thenValue; + this.builder.caseQueryColumn.addWhen(this); + return builder; + } + } + + public static class Builder { + + private CaseQueryColumn caseQueryColumn = new CaseQueryColumn(); + + public When when(QueryCondition condition) { + return new When(this, condition); + } + + public Builder else_(Object elseValue) { + caseQueryColumn.elseValue = elseValue; + return this; + } + + public CaseQueryColumn end() { + return caseQueryColumn; + } + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CaseSearchQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CaseSearchQueryColumn.java new file mode 100644 index 00000000..b170b604 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CaseSearchQueryColumn.java @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * 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 com.mybatisflex.core.query; + +import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; +import com.mybatisflex.core.util.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +public class CaseSearchQueryColumn extends QueryColumn { + + private QueryColumn queryColumn; + private List whens; + private Object elseValue; + + @Override + String toSelectSql(List queryTables, IDialect dialect) { + StringBuilder sql = new StringBuilder("CASE "); + sql.append(queryColumn.toSelectSql(queryTables, dialect)); + for (When when : whens) { + sql.append(" WHEN ").append(buildValue(when.searchValue)).append(" THEN ").append(buildValue(when.thenValue)); + } + if (elseValue != null) { + sql.append(" ELSE ").append(buildValue(elseValue)); + } + sql.append(" END"); + if (StringUtil.isNotBlank(alias)) { + return "(" + sql + ") AS " + dialect.wrap(alias); + } + return sql.toString(); + } + + + @Override + String toConditionSql(List queryTables, IDialect dialect) { + StringBuilder sql = new StringBuilder("CASE "); + sql.append(queryColumn.toSelectSql(queryTables, dialect)); + for (When when : whens) { + sql.append(" WHEN ").append(buildValue(when.searchValue)).append(" THEN ").append(buildValue(when.thenValue)); + } + if (elseValue != null) { + sql.append(" ELSE ").append(buildValue(elseValue)); + } + sql.append(" END"); + return "(" + sql + ")"; + } + + + private String buildValue(Object value) { + if (value instanceof Number || value instanceof Boolean) { + return String.valueOf(value); + } else { + return "'" + value + "'"; + } + } + + + void addWhen(When when) { + if (whens == null) { + whens = new ArrayList<>(); + } + whens.add(when); + } + + @Override + public QueryColumn as(String alias) { + this.alias = alias; + return this; + } + + @Override + public QueryColumn as(LambdaGetter fn) { + return as(LambdaUtil.getFieldName(fn)); + } + + public static class When { + private Builder builder; + private Object searchValue; + private Object thenValue; + + public When(Builder builder, Object searchValue) { + this.builder = builder; + this.searchValue = searchValue; + } + + public Builder then(Object thenValue) { + this.thenValue = thenValue; + this.builder.caseQueryColumn.addWhen(this); + return builder; + } + } + + public static class Builder { + + private CaseSearchQueryColumn caseQueryColumn = new CaseSearchQueryColumn(); + + public Builder(QueryColumn queryColumn) { + this.caseQueryColumn.queryColumn = queryColumn; + } + + public When when(Object searchValue) { + return new When(this, searchValue); + } + + public Builder else_(Object elseValue) { + caseQueryColumn.elseValue = elseValue; + return this; + } + + public CaseSearchQueryColumn end() { + return caseQueryColumn; + } + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/HasParamsColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/HasParamsColumn.java new file mode 100644 index 00000000..f4d4fccd --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/HasParamsColumn.java @@ -0,0 +1,6 @@ +package com.mybatisflex.core.query; + +public interface HasParamsColumn { + + Object[] getParamValues(); +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java index db68ba91..2149855a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java @@ -183,8 +183,12 @@ public class QueryCondition implements Serializable { if (effectiveBefore != null) { sql.append(effectiveBefore.connector); } + //列 sql.append(getColumn().toConditionSql(queryTables, dialect)); + //逻辑符号 sql.append(" ").append(logic).append(" "); + + //值(或者问号) if (value instanceof QueryColumn) { sql.append(((QueryColumn) value).toConditionSql(queryTables, dialect)); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryMethods.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryMethods.java index a4d1e81e..5cedb107 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryMethods.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryMethods.java @@ -65,6 +65,14 @@ public class QueryMethods { return new DistinctQueryColumn(columns); } + public static CaseQueryColumn.Builder case_() { + return new CaseQueryColumn.Builder(); + } + + public static CaseSearchQueryColumn.Builder case_(QueryColumn queryColumn) { + return new CaseSearchQueryColumn.Builder(queryColumn); + } + //CONVERT ( data_type [ ( length ) ] , expression [ , style ] ) public static StringFunctionQueryColumn convert(String... params) { return new StringFunctionQueryColumn("CONVERT", params); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java index 4ecdd060..4db61cd0 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java @@ -280,12 +280,12 @@ public class QueryWrapper extends BaseQueryWrapper { return this; } - public QueryWrapper forUpdate(){ + public QueryWrapper forUpdate() { addEndFragment("FOR UPDATE"); return this; } - public QueryWrapper forUpdateNoWait(){ + public QueryWrapper forUpdateNoWait() { addEndFragment("FOR UPDATE NOWAIT"); return this; } @@ -348,7 +348,7 @@ public class QueryWrapper extends BaseQueryWrapper { } public QueryWrapper orderBy(String... orderBys) { - if(orderBys == null || orderBys.length == 0){ + if (orderBys == null || orderBys.length == 0) { //ignore return this; } @@ -395,16 +395,15 @@ public class QueryWrapper extends BaseQueryWrapper { List columnValues = null; List selectColumns = getSelectColumns(); - if (CollectionUtil.isNotEmpty(selectColumns)){ + if (CollectionUtil.isNotEmpty(selectColumns)) { for (QueryColumn selectColumn : selectColumns) { - if (selectColumn instanceof SelectQueryColumn){ - QueryWrapper queryWrapper = ((SelectQueryColumn) selectColumn).getQueryWrapper(); - Object[] valueArray = queryWrapper.getValueArray(); - if (ArrayUtil.isNotEmpty(valueArray)){ - if (columnValues == null){ + if (selectColumn instanceof HasParamsColumn) { + Object[] paramValues = ((HasParamsColumn) selectColumn).getParamValues(); + if (ArrayUtil.isNotEmpty(paramValues)) { + if (columnValues == null) { columnValues = new ArrayList<>(); } - columnValues.addAll(Arrays.asList(valueArray)); + columnValues.addAll(Arrays.asList(paramValues)); } } } @@ -466,7 +465,7 @@ public class QueryWrapper extends BaseQueryWrapper { } Object[] returnValues = columnValues == null ? WrapperUtil.NULL_PARA_ARRAY : columnValues.toArray(); - returnValues = tableValues != null ? ArrayUtil.concat(returnValues,tableValues.toArray()) : returnValues; + returnValues = tableValues != null ? ArrayUtil.concat(returnValues, tableValues.toArray()) : returnValues; returnValues = joinValues != null ? ArrayUtil.concat(returnValues, joinValues.toArray()) : returnValues; returnValues = ArrayUtil.concat(returnValues, paramValues); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/SelectQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/SelectQueryColumn.java index aeb26889..c10d2662 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/SelectQueryColumn.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/SelectQueryColumn.java @@ -17,12 +17,11 @@ package com.mybatisflex.core.query; import com.mybatisflex.core.dialect.IDialect; import com.mybatisflex.core.util.SqlUtil; - import com.mybatisflex.core.util.StringUtil; import java.util.List; -public class SelectQueryColumn extends QueryColumn { +public class SelectQueryColumn extends QueryColumn implements HasParamsColumn { private QueryWrapper queryWrapper; @@ -54,4 +53,9 @@ public class SelectQueryColumn extends QueryColumn { String toConditionSql(List queryTables, IDialect dialect) { return super.toConditionSql(queryTables, dialect); } + + @Override + public Object[] getParamValues() { + return queryWrapper.getValueArray(); + } } diff --git a/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/AccountSqlTester.java b/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/AccountSqlTester.java index 45e2fde4..6e67d2eb 100644 --- a/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/AccountSqlTester.java +++ b/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/AccountSqlTester.java @@ -323,6 +323,43 @@ public class AccountSqlTester { } + @Test + public void testCase1() { + IDialect dialect = new CommonsDialectImpl(); + + QueryWrapper queryWrapper = QueryWrapper.create() + .select(ACCOUNT.ALL_COLUMNS, + case_() + .when(ACCOUNT.ID.eq(100)).then(100) + .when(ACCOUNT.ID.ge(200)).then(200) + .else_(300) + .end().as("result")) + .from(ACCOUNT) + .and(ACCOUNT.USER_NAME.like("michael")); + + String sql = dialect.forSelectByQuery(queryWrapper); + System.out.println(sql); + } + + @Test + public void testCase2() { + IDialect dialect = new CommonsDialectImpl(); + + QueryWrapper queryWrapper = QueryWrapper.create() + .select(ACCOUNT.ALL_COLUMNS, + case_(ACCOUNT.ID) + .when(100).then(100) + .when(200).then(200) + .else_(300) + .end().as("result")) + .from(ACCOUNT) + .and(ACCOUNT.USER_NAME.like("michael")); + + String sql = dialect.forSelectByQuery(queryWrapper); + System.out.println(sql); + } + + @Test public void testLimitOffset() {