feat: add sql case grammar support

This commit is contained in:
开源海哥 2023-05-25 16:38:23 +08:00
parent e6c896f14a
commit 8af72a24e6
8 changed files with 336 additions and 13 deletions

View File

@ -0,0 +1,135 @@
/**
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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<When> whens;
private Object elseValue;
void addWhen(When when) {
if (whens == null) {
whens = new ArrayList<>();
}
whens.add(when);
}
@Override
String toSelectSql(List<QueryTable> 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<QueryTable> 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 <T> QueryColumn as(LambdaGetter<T> 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;
}
}
}

View File

@ -0,0 +1,130 @@
/**
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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<When> whens;
private Object elseValue;
@Override
String toSelectSql(List<QueryTable> 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<QueryTable> 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 <T> QueryColumn as(LambdaGetter<T> 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;
}
}
}

View File

@ -0,0 +1,6 @@
package com.mybatisflex.core.query;
public interface HasParamsColumn {
Object[] getParamValues();
}

View File

@ -183,8 +183,12 @@ public class QueryCondition implements Serializable {
if (effectiveBefore != null) { if (effectiveBefore != null) {
sql.append(effectiveBefore.connector); sql.append(effectiveBefore.connector);
} }
//
sql.append(getColumn().toConditionSql(queryTables, dialect)); sql.append(getColumn().toConditionSql(queryTables, dialect));
//逻辑符号
sql.append(" ").append(logic).append(" "); sql.append(" ").append(logic).append(" ");
//或者问号
if (value instanceof QueryColumn) { if (value instanceof QueryColumn) {
sql.append(((QueryColumn) value).toConditionSql(queryTables, dialect)); sql.append(((QueryColumn) value).toConditionSql(queryTables, dialect));
} }

View File

@ -65,6 +65,14 @@ public class QueryMethods {
return new DistinctQueryColumn(columns); 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 ] ) //CONVERT ( data_type [ ( length ) ] , expression [ , style ] )
public static StringFunctionQueryColumn convert(String... params) { public static StringFunctionQueryColumn convert(String... params) {
return new StringFunctionQueryColumn("CONVERT", params); return new StringFunctionQueryColumn("CONVERT", params);

View File

@ -280,12 +280,12 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
return this; return this;
} }
public QueryWrapper forUpdate(){ public QueryWrapper forUpdate() {
addEndFragment("FOR UPDATE"); addEndFragment("FOR UPDATE");
return this; return this;
} }
public QueryWrapper forUpdateNoWait(){ public QueryWrapper forUpdateNoWait() {
addEndFragment("FOR UPDATE NOWAIT"); addEndFragment("FOR UPDATE NOWAIT");
return this; return this;
} }
@ -348,7 +348,7 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
} }
public QueryWrapper orderBy(String... orderBys) { public QueryWrapper orderBy(String... orderBys) {
if(orderBys == null || orderBys.length == 0){ if (orderBys == null || orderBys.length == 0) {
//ignore //ignore
return this; return this;
} }
@ -395,16 +395,15 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
List<Object> columnValues = null; List<Object> columnValues = null;
List<QueryColumn> selectColumns = getSelectColumns(); List<QueryColumn> selectColumns = getSelectColumns();
if (CollectionUtil.isNotEmpty(selectColumns)){ if (CollectionUtil.isNotEmpty(selectColumns)) {
for (QueryColumn selectColumn : selectColumns) { for (QueryColumn selectColumn : selectColumns) {
if (selectColumn instanceof SelectQueryColumn){ if (selectColumn instanceof HasParamsColumn) {
QueryWrapper queryWrapper = ((SelectQueryColumn) selectColumn).getQueryWrapper(); Object[] paramValues = ((HasParamsColumn) selectColumn).getParamValues();
Object[] valueArray = queryWrapper.getValueArray(); if (ArrayUtil.isNotEmpty(paramValues)) {
if (ArrayUtil.isNotEmpty(valueArray)){ if (columnValues == null) {
if (columnValues == null){
columnValues = new ArrayList<>(); columnValues = new ArrayList<>();
} }
columnValues.addAll(Arrays.asList(valueArray)); columnValues.addAll(Arrays.asList(paramValues));
} }
} }
} }
@ -466,7 +465,7 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
} }
Object[] returnValues = columnValues == null ? WrapperUtil.NULL_PARA_ARRAY : columnValues.toArray(); 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 = joinValues != null ? ArrayUtil.concat(returnValues, joinValues.toArray()) : returnValues;
returnValues = ArrayUtil.concat(returnValues, paramValues); returnValues = ArrayUtil.concat(returnValues, paramValues);

View File

@ -17,12 +17,11 @@ package com.mybatisflex.core.query;
import com.mybatisflex.core.dialect.IDialect; import com.mybatisflex.core.dialect.IDialect;
import com.mybatisflex.core.util.SqlUtil; import com.mybatisflex.core.util.SqlUtil;
import com.mybatisflex.core.util.StringUtil; import com.mybatisflex.core.util.StringUtil;
import java.util.List; import java.util.List;
public class SelectQueryColumn extends QueryColumn { public class SelectQueryColumn extends QueryColumn implements HasParamsColumn {
private QueryWrapper queryWrapper; private QueryWrapper queryWrapper;
@ -54,4 +53,9 @@ public class SelectQueryColumn extends QueryColumn {
String toConditionSql(List<QueryTable> queryTables, IDialect dialect) { String toConditionSql(List<QueryTable> queryTables, IDialect dialect) {
return super.toConditionSql(queryTables, dialect); return super.toConditionSql(queryTables, dialect);
} }
@Override
public Object[] getParamValues() {
return queryWrapper.getValueArray();
}
} }

View File

@ -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 @Test
public void testLimitOffset() { public void testLimitOffset() {