diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/core/interceptor/ResultProvider.java b/magic-api/src/main/java/org/ssssssss/magicapi/core/interceptor/ResultProvider.java index 905d4fef969bc3651141c8a45e0f75fe0e8bcdb9..10302d947bda4ce865830c05eb203aab357fc810 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/core/interceptor/ResultProvider.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/core/interceptor/ResultProvider.java @@ -2,9 +2,9 @@ package org.ssssssss.magicapi.core.interceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.ssssssss.magicapi.core.context.RequestEntity; import org.ssssssss.magicapi.modules.db.model.Page; import org.ssssssss.magicapi.modules.db.model.PageResult; -import org.ssssssss.magicapi.core.context.RequestEntity; import org.ssssssss.script.exception.MagicScriptAssertException; import org.ssssssss.script.exception.MagicScriptException; import org.ssssssss.script.functions.ObjectConvertExtension; diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java index 4ee5cc0b0f4a414cc6c35f30b95a1b9dd4bddf0b..83bcf0c68fd041c42b3a05fa05ed159b9a40bced 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/SQLModule.java @@ -17,6 +17,7 @@ import org.ssssssss.magicapi.modules.db.dialect.DialectAdapter; import org.ssssssss.magicapi.modules.db.inteceptor.NamedTableInterceptor; import org.ssssssss.magicapi.modules.db.inteceptor.SQLInterceptor; import org.ssssssss.magicapi.modules.db.model.Page; +import org.ssssssss.magicapi.modules.db.model.PageResultBuilder; import org.ssssssss.magicapi.modules.db.model.SqlTypes; import org.ssssssss.magicapi.modules.db.provider.PageProvider; import org.ssssssss.magicapi.modules.db.table.NamedTable; @@ -555,6 +556,12 @@ public class SQLModule implements DynamicAttribute, Dynami return page(boundSql, page); } + @Transient + public PageResultBuilder> executePage(BoundSql boundSql) { + Page page = pageProvider.getPage(boundSql.getRuntimeContext()); + return executePage(boundSql, page); + } + @Transient public String getDataSourceName() { return this.dataSourceNode == null ? "unknown" : dataSourceNode.getName(); @@ -599,6 +606,11 @@ public class SQLModule implements DynamicAttribute, Dynami } private Object page(int count, BoundSql boundSql, Page page, Dialect dialect) { + return buildPageResult(executePage(count, boundSql, page, dialect)); + } + + @Transient + public PageResultBuilder> executePage(int count, BoundSql boundSql, Page page, Dialect dialect) { List> list = null; if (count > 0) { if (dialect == null) { @@ -607,8 +619,14 @@ public class SQLModule implements DynamicAttribute, Dynami BoundSql pageBoundSql = buildPageBoundSql(dialect, boundSql, page.getOffset(), page.getLimit()); list = pageBoundSql.execute(this.sqlInterceptors, () -> queryForList(pageBoundSql)); } + + return new PageResultBuilder<>(page, count, list); + } + + @Transient + public Object buildPageResult(PageResultBuilder> builder) { RequestEntity requestEntity = RequestContext.getRequestEntity(); - return resultProvider.buildPageResult(requestEntity, page, count, list); + return resultProvider.buildPageResult(requestEntity, builder.getPage(), builder.getTotal(), builder.getList()); } @Transient @@ -620,6 +638,15 @@ public class SQLModule implements DynamicAttribute, Dynami return page(count, boundSql, page, dialect); } + @Transient + public PageResultBuilder> executePage(BoundSql boundSql, Page page) { + assertDatasourceNotNull(); + Dialect dialect = dataSourceNode.getDialect(dialectAdapter); + BoundSql countBoundSql = boundSql.copy(dialect.getCountSql(boundSql.getSql())); + int count = selectInt(countBoundSql); + return executePage(count, boundSql, page, dialect); + } + /** * 查询总条目数 */ @@ -721,7 +748,12 @@ public class SQLModule implements DynamicAttribute, Dynami @Comment("指定table,进行单表操作") public NamedTable table(@Comment(name = "tableName", value = "表名") String tableName) { - return new NamedTable(tableName, this, rowMapColumnMapper, namedTableInterceptors); + return new NamedTable(tableName, null, this, rowMapColumnMapper, namedTableInterceptors); + } + + @Comment("指定table,进行单表操作") + public NamedTable table(@Comment(name = "tableName", value = "表名") String tableName, @Comment(name = "alias", value = "别名") String alias) { + return new NamedTable(tableName, alias, this, rowMapColumnMapper, namedTableInterceptors); } private BoundSql buildPageBoundSql(Dialect dialect, BoundSql boundSql, long offset, long limit) { diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/PageResultBuilder.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/PageResultBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..811d60be227f015525233e7e89ac6db951ec5092 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/model/PageResultBuilder.java @@ -0,0 +1,59 @@ +package org.ssssssss.magicapi.modules.db.model; + +import java.util.List; + +/** + * 分页执行结果 + * + * @author mxd + */ +public class PageResultBuilder { + + /** + * 分页请求参数 + */ + private Page page; + + /** + * 总条数 + */ + private long total; + + /** + * 数据项 + */ + private List list; + + public PageResultBuilder(Page page, long total, List list) { + this.page = page; + this.total = total; + this.list = list; + } + + public PageResultBuilder() { + } + + public Page getPage() { + return page; + } + + public void setPage(Page page) { + this.page = page; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/provider/PascalColumnMapperProvider.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/provider/PascalColumnMapperProvider.java index 76193d034fdf5acef1d9bca3caa9e45cfa59047b..d34effb4cec7fc0f9a10cb03b38f895feebec446 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/provider/PascalColumnMapperProvider.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/provider/PascalColumnMapperProvider.java @@ -37,12 +37,14 @@ public class PascalColumnMapperProvider implements ColumnMapperProvider { @Override public String unmapping(String name) { StringBuilder sb = new StringBuilder(); + boolean isFirst = true; for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); - if (i > 0 && Character.isUpperCase(ch)) { + if (!isFirst && Character.isUpperCase(ch)) { sb.append("_"); } sb.append(Character.toLowerCase(ch)); + isFirst = (ch == '.' || ch == ' '); } return sb.toString(); } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/DbConstant.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/DbConstant.java new file mode 100644 index 0000000000000000000000000000000000000000..f274d72c845d46823c5422a84fb09248c53e6fd9 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/DbConstant.java @@ -0,0 +1,38 @@ +package org.ssssssss.magicapi.modules.db.table; + +/** + * 数据库操作常量 + * @author tangchen + */ +public interface DbConstant { + + String AS = " AS "; + + String JOIN = "JOIN"; + + String LEFT = "LEFT"; + + String RIGHT = "RIGHT"; + + String INNER = "INNER"; + + String SPACE = " "; + + String DOT = "."; + + + /** + * " LEFT JOIN " + */ + String LEFT_JOIN = SPACE + LEFT + SPACE + JOIN + SPACE; + + /** + * " RIGHT JOIN " + */ + String RIGHT_JOIN = SPACE + RIGHT + SPACE + JOIN + SPACE; + + /** + * " INNER JOIN " + */ + String INNER_JOIN = SPACE + INNER + SPACE + JOIN + SPACE; +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/JoinInterface.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/JoinInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..73b2b66d4497830c302c864f067619f4ab163eb8 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/JoinInterface.java @@ -0,0 +1,56 @@ +package org.ssssssss.magicapi.modules.db.table; + +import org.ssssssss.script.annotation.Comment; + +import java.beans.Transient; + +/** + * 关联表操作接口 + * + * @author tom + */ +public interface JoinInterface { + + @Transient + @Comment("拼接join") + JoinedTable join(boolean condition, String joinType, String tableName, String alias); + + @Comment("拼接innerJoin") + default JoinedTable innerJoin(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias) { + return join(condition, DbConstant.INNER_JOIN, tableName, alias); + } + + @Comment("拼接innerJoin") + default JoinedTable innerJoin(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias) { + return join(true, DbConstant.INNER_JOIN, tableName, alias); + } + + @Comment("拼接leftJoin") + default JoinedTable leftJoin(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias) { + return join(condition, DbConstant.LEFT_JOIN, tableName, alias); + } + + @Comment("拼接leftJoin") + default JoinedTable leftJoin(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias) { + return join(true, DbConstant.LEFT_JOIN, tableName, alias); + } + + @Comment("拼接rightJoin") + default JoinedTable rightJoin(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias) { + return join(condition, DbConstant.RIGHT_JOIN, tableName, alias); + } + + @Comment("拼接rightJoin") + default JoinedTable rightJoin(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias) { + return join(true, DbConstant.RIGHT_JOIN, tableName, alias); + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/JoinedTable.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/JoinedTable.java new file mode 100644 index 0000000000000000000000000000000000000000..ecbe11c4da6f147091a80861e86f1be49e20fa79 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/JoinedTable.java @@ -0,0 +1,39 @@ +package org.ssssssss.magicapi.modules.db.table; + +import org.ssssssss.script.annotation.Comment; + +/** + * 连表操作API + * + * @author tom + */ +public class JoinedTable extends TableBase { + + protected final NamedTable namedTable; + + On on = new On(this); + + /** + * Join类型 + */ + String joinType; + + public JoinedTable(NamedTable namedTable, String tableName, String alias) { + super(tableName, alias, namedTable.sqlModule, + namedTable.rowMapColumnMapper, namedTable.namedTableInterceptors); + this.namedTable = namedTable; + } + + @Override + @Comment("克隆") + public JoinedTable clone() { + JoinedTable joinedTable = (JoinedTable) super.clone(); + joinedTable.on = this.on == null ? null : this.on.clone(); + return joinedTable; + } + + @Comment("拼接on") + public On on() { + return on; + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/NamedTable.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/NamedTable.java index 4e481fe69145100d21883d2a3ac37968a9b12ad9..f1872026102707af096d521e4ffbe2cdb46739e5 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/NamedTable.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/NamedTable.java @@ -2,13 +2,13 @@ package org.ssssssss.magicapi.modules.db.table; import org.apache.commons.lang3.StringUtils; import org.ssssssss.magicapi.core.context.RequestContext; -import org.ssssssss.magicapi.core.exception.MagicAPIException; -import org.ssssssss.magicapi.core.model.Attributes; import org.ssssssss.magicapi.core.context.RequestEntity; +import org.ssssssss.magicapi.core.exception.MagicAPIException; import org.ssssssss.magicapi.modules.db.BoundSql; -import org.ssssssss.magicapi.modules.db.inteceptor.NamedTableInterceptor; import org.ssssssss.magicapi.modules.db.SQLModule; +import org.ssssssss.magicapi.modules.db.inteceptor.NamedTableInterceptor; import org.ssssssss.magicapi.modules.db.model.Page; +import org.ssssssss.magicapi.modules.db.model.PageResultBuilder; import org.ssssssss.magicapi.modules.db.model.SqlMode; import org.ssssssss.script.annotation.Comment; import org.ssssssss.script.runtime.RuntimeContext; @@ -25,17 +25,7 @@ import java.util.stream.Collectors; * * @author mxd */ -public class NamedTable extends Attributes { - - String tableName; - - SQLModule sqlModule; - - String primary; - - String logicDeleteColumn; - - Object logicDeleteValue; +public class NamedTable extends TableBase implements JoinInterface { Map columns = new HashMap<>(); @@ -47,38 +37,18 @@ public class NamedTable extends Attributes { Set excludeColumns = new HashSet<>(); - Function rowMapColumnMapper; - Object defaultPrimaryValue; - boolean useLogic = false; + boolean useDistinct = false; boolean withBlank = false; - List namedTableInterceptors; - Where where = new Where(this); - public NamedTable(String tableName, SQLModule sqlModule, Function rowMapColumnMapper, List namedTableInterceptors) { - this.tableName = tableName; - this.sqlModule = sqlModule; - this.rowMapColumnMapper = rowMapColumnMapper; - this.namedTableInterceptors = namedTableInterceptors; - this.logicDeleteColumn = sqlModule.getLogicDeleteColumn(); - String deleteValue = sqlModule.getLogicDeleteValue(); - this.logicDeleteValue = deleteValue; - if (deleteValue != null) { - boolean isString = deleteValue.startsWith("'") || deleteValue.startsWith("\""); - if (isString && deleteValue.length() > 2) { - this.logicDeleteValue = deleteValue.substring(1, deleteValue.length() - 1); - } else { - try { - this.logicDeleteValue = Integer.parseInt(deleteValue); - } catch (NumberFormatException e) { - this.logicDeleteValue = deleteValue; - } - } - } + List joinedTables = new ArrayList<>(); + + public NamedTable(String tableName, String alias, SQLModule sqlModule, Function rowMapColumnMapper, List namedTableInterceptors) { + super(tableName, alias, sqlModule, rowMapColumnMapper, namedTableInterceptors); } private NamedTable() { @@ -87,27 +57,40 @@ public class NamedTable extends Attributes { @Override @Comment("克隆") public NamedTable clone() { - NamedTable namedTable = new NamedTable(); - namedTable.tableName = this.tableName; - namedTable.sqlModule = this.sqlModule; - namedTable.primary = this.primary; - namedTable.logicDeleteValue = this.logicDeleteValue; - namedTable.logicDeleteColumn = this.logicDeleteColumn; + NamedTable namedTable = (NamedTable) super.clone(); namedTable.columns = new HashMap<>(this.columns); namedTable.fields = new ArrayList<>(fields); namedTable.groups = new ArrayList<>(groups); namedTable.orders = new ArrayList<>(orders); + namedTable.joinedTables = new ArrayList<>(joinedTables); namedTable.excludeColumns = new HashSet<>(excludeColumns); namedTable.rowMapColumnMapper = this.rowMapColumnMapper; namedTable.defaultPrimaryValue = this.defaultPrimaryValue; + namedTable.useDistinct = this.useDistinct; namedTable.useLogic = this.useLogic; namedTable.withBlank = this.withBlank; namedTable.where = this.where == null ? null : this.where.clone(); - namedTable.namedTableInterceptors = this.namedTableInterceptors; - namedTable.properties = this.properties; return namedTable; } + @Override + @Transient + @Comment("拼接join") + public JoinedTable join(boolean condition, String joinType, String tableName, String alias) { + JoinedTable join = new JoinedTable(this, tableName, alias); + join.joinType = joinType; + if (condition) { + joinedTables.add(join); + } + return join; + } + + @Comment("使用去重") + public NamedTable distinct() { + this.useDistinct = true; + return this; + } + @Comment("使用逻辑删除") public NamedTable logic() { this.useLogic = true; @@ -204,6 +187,25 @@ public class NamedTable extends Attributes { return this; } + @Comment("设置查询的列,如`column('t', 'a', 'a1')` -> `select t.a as a1`") + public NamedTable columnAs(@Comment(name = "tableAlias", value = "表别名") String tableAlias, + @Comment(name = "property", value = "查询的列") String property, + @Comment(name = "alias", value = "列别名") String alias) { + if (StringUtils.isNotBlank(property)) { + this.fields.add(tableAlias + DbConstant.DOT + this.rowMapColumnMapper.apply(property) + DbConstant.AS + this.rowMapColumnMapper.apply(alias)); + } + return this; + } + + @Comment("设置查询的列,如`column('a', 'a1')` -> `select a as a1`") + public NamedTable columnAs(@Comment(name = "property", value = "查询的列") String property, + @Comment(name = "alias", value = "列别名") String alias) { + if (StringUtils.isNotBlank(property)) { + this.fields.add(this.rowMapColumnMapper.apply(property) + DbConstant.AS + this.rowMapColumnMapper.apply(alias)); + } + return this; + } + @Comment("拼接`order by xxx asc/desc`") public NamedTable orderBy(@Comment(name = "property", value = "要排序的列") String property, @Comment(name = "sort", value = "`asc`或`desc`") String sort) { @@ -260,8 +262,9 @@ public class NamedTable extends Attributes { builder.append(")"); Object value = sqlModule.insert(new BoundSql(runtimeContext, builder.toString(), entries.stream().map(Map.Entry::getValue).collect(Collectors.toList()), sqlModule), this.primary); if(value == null && StringUtils.isNotBlank(this.primary)){ - return this.columns.get(this.primary); + value = this.columns.get(this.primary); } + data.put(this.primary, value); return value; } @@ -373,7 +376,8 @@ public class NamedTable extends Attributes { @Comment("执行分页查询") public Object page(RuntimeContext runtimeContext) { preHandle(SqlMode.PAGE); - return sqlModule.page(buildSelect(runtimeContext)); + PageResultBuilder> pageResultBuilder = sqlModule.executePage(buildSelect(runtimeContext)); + return sqlModule.buildPageResult(pageResultBuilder); } @Comment("执行分页查询,分页条件手动传入") @@ -381,7 +385,8 @@ public class NamedTable extends Attributes { @Comment(name = "limit", value = "限制条数") long limit, @Comment(name = "offset", value = "跳过条数") long offset) { preHandle(SqlMode.PAGE); - return sqlModule.page(buildSelect(runtimeContext), new Page(limit, offset)); + PageResultBuilder> pageResultBuilder = sqlModule.executePage(buildSelect(runtimeContext), new Page(limit, offset)); + return sqlModule.buildPageResult(pageResultBuilder); } @Comment("执行update语句") @@ -441,8 +446,10 @@ public class NamedTable extends Attributes { public int count(RuntimeContext runtimeContext) { preHandle(SqlMode.COUNT); StringBuilder builder = new StringBuilder(); - builder.append("select count(1) from ").append(tableName); - List params = buildWhere(builder); + builder.append("select count(1) from ").append(getAlisName(tableName)); + List params = new ArrayList<>(); + params.addAll(buildJoin(builder)); + params.addAll(buildWhere(builder)); return sqlModule.selectInt(new BoundSql(runtimeContext, builder.toString(), params, sqlModule)); } @@ -477,13 +484,18 @@ public class NamedTable extends Attributes { List fields = this.fields.stream() .filter(it -> !excludeColumns.contains(it)) .collect(Collectors.toList()); + if (this.useDistinct) { + builder.append("distinct "); + } if (fields.isEmpty()) { - builder.append("*"); + builder.append(withAlis("*")); } else { builder.append(StringUtils.join(fields, ",")); } - builder.append(" from ").append(tableName); - List params = buildWhere(builder); + builder.append(" from ").append(getAlisName(tableName)); + List params = new ArrayList<>(); + params.addAll(buildJoin(builder)); + params.addAll(buildWhere(builder)); if (!groups.isEmpty()) { builder.append(" group by "); builder.append(String.join(",", groups)); @@ -497,16 +509,36 @@ public class NamedTable extends Attributes { return boundSql; } + private List buildJoin(StringBuilder builder) { + List params = new ArrayList<>(); + for (JoinedTable sub : joinedTables) { + builder.append(sub.joinType) + .append(sub.getAlisName(sub.tableName)); + On on = sub.on; + if (!on.isEmpty()) { + on.and(); + on.ne(sub.isUseLogic(), sub.withAlis(logicDeleteColumn), logicDeleteValue); + builder.append(on.getSql()); + params.addAll(on.getParams()); + } else if (sub.isUseLogic()) { + on.ne(sub.withAlis(logicDeleteColumn), logicDeleteValue); + builder.append(on.getSql()); + params.addAll(on.getParams()); + } + } + return params; + } + private List buildWhere(StringBuilder builder) { List params = new ArrayList<>(); if (!where.isEmpty()) { where.and(); - where.ne(useLogic, logicDeleteColumn, logicDeleteValue); + where.ne(useLogic, withAlis(logicDeleteColumn), logicDeleteValue); builder.append(where.getSql()); params.addAll(where.getParams()); } else if (useLogic) { - where.ne(logicDeleteColumn, logicDeleteValue); + where.ne(withAlis(logicDeleteColumn), logicDeleteValue); builder.append(where.getSql()); params.addAll(where.getParams()); } @@ -514,58 +546,6 @@ public class NamedTable extends Attributes { } - /** - * 获取查询的表名 - * - * @return 表名 - */ - @Transient - public String getTableName() { - return tableName; - } - - /** - * 设置表名 - * - * @param tableName 表名 - */ - @Transient - public void setTableName(String tableName) { - this.tableName = tableName; - } - - /** - * 获取SQL模块 - */ - @Transient - public SQLModule getSqlModule() { - return sqlModule; - } - - /** - * 获取主键列 - */ - @Transient - public String getPrimary() { - return primary; - } - - /** - * 获取逻辑删除列 - */ - @Transient - public String getLogicDeleteColumn() { - return logicDeleteColumn; - } - - /** - * 获取逻辑删除值 - */ - @Transient - public Object getLogicDeleteValue() { - return logicDeleteValue; - } - /** * 获取设置的columns */ @@ -657,19 +637,19 @@ public class NamedTable extends Attributes { } /** - * 是否设逻辑了逻辑删除 + * 是否使用排他 */ @Transient - public boolean isUseLogic() { - return useLogic; + public boolean isUseDistinct() { + return useDistinct; } /** - * 设置是否使用逻辑删除 + * 设置是否使用排他 */ @Transient - public void setUseLogic(boolean useLogic) { - this.useLogic = useLogic; + public void setUseDistinct(boolean useDistinct) { + this.useDistinct = useDistinct; } /** diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/On.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/On.java new file mode 100644 index 0000000000000000000000000000000000000000..11b809a60fd97b312bb7a5a20d0269f9e1a9ffd7 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/On.java @@ -0,0 +1,532 @@ +package org.ssssssss.magicapi.modules.db.table; + +import org.ssssssss.script.annotation.Comment; + +import java.beans.Transient; +import java.util.function.Function; + +/** + * 连表API的On + * + * @author tom + */ +public class On extends WhereBase implements TableInterface, JoinInterface { + + public On(JoinedTable joinedTable) { + this(joinedTable, true); + } + + public On(JoinedTable joinedTable, boolean needOn) { + super(joinedTable, needOn); + } + + @Override + @Comment("克隆") + public On clone() { + return (On) super.clone(); + } + + @Override + @Transient + public NamedTable getNamedTable() { + return ((JoinedTable) tableBase).namedTable; + } + + @Comment("拼接where") + public Where where() { + return getNamedTable().where(); + } + + @Comment("逻辑过滤") + public On logic() { + super.logic(); + return this; + } + + @Override + @Comment("过滤`null`的参数") + public On notNull() { + return notNull(true); + } + + @Override + @Comment("过滤`blank`的参数") + public On notBlank() { + return notBlank(true); + } + + @Override + @Comment("是否过滤`null`的参数") + public On notNull(boolean flag) { + super.notNull(flag); + return this; + } + + @Override + @Comment("是否过滤`blank`的参数") + public On notBlank(boolean flag) { + super.notBlank(flag); + return this; + } + + @Override + @Comment("等于`=`,如:`eq('name', '老王') ---> name = '老王'`") + public On eq(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return eq(true, column, value); + } + + @Override + @Comment("等于`=`,如:`eq('name', '老王') ---> name = '老王'`") + public On eq(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.eq(condition, column, value); + return this; + } + + @Override + @Comment("等于`=`,如:`eq2('t.userId', 'u.id') ---> t.userId = u.id`") + public On eq2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return eq2(true, column1, column2); + } + + @Override + @Comment("等于`=`,如:`eq2('t.userId', 'u.id') ---> t.userId = u.id`") + public On eq2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.eq2(condition, column1, column2); + return this; + } + + @Override + @Comment("不等于`<>`,如:`ne('name', '老王') ---> name <> '老王'`") + public On ne(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return ne(true, column, value); + } + + @Override + @Comment("不等于`<>`,如:`ne('name', '老王') ---> name <> '老王'`") + public On ne(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.ne(condition, column, value); + return this; + } + + @Override + @Comment("不等于`<>`,如:`ne2('t.name', 'u.name') ---> t.name <> u.name`") + public On ne2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return ne2(true, column1, column2); + } + + @Override + @Comment("不等于`<>`,如:`ne2('t.name', 'u.name') ---> t.name <> u.name`") + public On ne2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.ne2(condition, column1, column2); + return this; + } + + @Override + @Comment("between(true, true, 't.createTime', '2023-01-01', '2023-01-31', true, false) ---> t.create_time >= '2023-01-01' and t.create_time < '2023-01-31'") + public On between( + @Comment(name = "startCon", value = "判断表达式,当为true时拼接条件") boolean startCon, + @Comment(name = "endCon", value = "判断表达式,当为true时拼接条件") boolean endCon, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal, + @Comment(name = "startContain", value = "包含开始值") boolean startContain, + @Comment(name = "endContain", value = "包含结束值") boolean endContain + ) { + super.between(startCon, endCon, column, startVal, endVal, startContain, endContain); + return this; + } + + @Override + @Comment("between('t.createTime', '2023-01-01', '2023-01-31', true, false) ---> t.create_time >= '2023-01-01' and t.create_time < '2023-01-31'") + public On between( + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal, + @Comment(name = "startContain", value = "包含开始值") boolean startContain, + @Comment(name = "endContain", value = "包含结束值") boolean endContain + ) { + return between(true,true,column,startVal,endVal,startContain,endContain); + } + + @Override + @Comment("between(true, true, 't.createTime', '2023-01-01', '2023-01-31') ---> t.create_time >= '2023-01-01' and t.create_time <= '2023-01-31'") + public On between( + @Comment(name = "startCon", value = "判断表达式,当为true时拼接条件") boolean startCon, + @Comment(name = "endCon", value = "判断表达式,当为true时拼接条件") boolean endCon, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal + ) { + return between(startCon,endCon,column,startVal,endVal,true,true); + } + + @Override + @Comment("between('t.createTime', '2023-01-01', '2023-01-31') ---> t.create_time >= '2023-01-01' and t.create_time <= '2023-01-31'") + public On between( + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal + ) { + return between(true,true,column,startVal,endVal,true,true); + } + + @Override + @Comment("等于`=`,如:`notExists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> not exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public On notExists(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + exists(true, condition, tableName, alias, function, useLogic); + return this; + } + + @Override + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public On notExists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return notExists(true, tableName, alias, function, useLogic); + } + + @Override + @Comment("等于`=`,如:`exists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王')) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王'`") + public On notExists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function) { + return notExists(true, tableName, alias, function, false); + } + + @Override + @Comment("等于`=`,如:`exists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public On exists(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + exists(false, condition, tableName, alias, function, useLogic); + return this; + } + + @Override + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public On exists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return exists(true, tableName, alias, function, useLogic); + } + + @Override + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王')) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王'`") + public On exists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function) { + return exists(true, tableName, alias, function, false); + } + + @Override + @Comment("小于`<`,如:`lt('age', 18) ---> age < 18") + public On lt(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return lt(true, column, value); + } + + @Override + @Comment("小于`<`,如:`lt('age', 18) ---> age < 18") + public On lt(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.lt(condition, column, value); + return this; + } + + @Override + @Comment("小于`<`,如:`lt2('t.age', 'u.age') ---> t.age < u.age") + public On lt2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return lt2(true, column1, column2); + } + + @Override + @Comment("小于`<`,如:`lt2('t.age', 'u.age') ---> t.age < u.age") + public On lt2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.lt2(condition, column1, column2); + return this; + } + + @Override + @Comment("小于等于`<=`,如:`lte('age', 18) ---> age <= 18") + public On lte(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return lte(true, column, value); + } + + @Override + @Comment("小于等于`<=`,如:`lte('age', 18) ---> age <= 18") + public On lte(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.lte(condition, column, value); + return this; + } + + @Override + @Comment("小于等于`<=`,如:`lte2('t.age', 'u.age') ---> t.age <= u.age") + public On lte2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return lte2(true, column1, column2); + } + + @Override + @Comment("小于等于`<=`,如:`lte2('t.age', 'u.age') ---> t.age <= u.age") + public On lte2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.lte2(condition, column1, column2); + return this; + } + + @Override + @Comment("大于`>`,如:`get('age', 18) ---> age > 18") + public On gt(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return gt(true, column, value); + } + + @Override + @Comment("大于`>`,如:`get('age', 18) ---> age > 18") + public On gt(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.gt(condition, column, value); + return this; + } + + @Override + @Comment("大于`>`,如:`get('t.age', 't.age') ---> t.age > u.age") + public On gt2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return gt2(true, column1, column2); + } + + @Override + @Comment("大于`>`,如:`get('t.age', 't.age') ---> t.age > u.age") + public On gt2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.gt2(condition, column1, column2); + return this; + } + + @Override + @Comment("大于等于`>=`,如:`get('age', 18) ---> age >= 18") + public On gte(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return gte(true, column, value); + } + + @Override + @Comment("大于等于`>=`,如:`get('age', 18) ---> age >= 18") + public On gte(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.gte(condition, column, value); + return this; + } + + @Override + @Comment("大于等于`>=`,如:`get('t.age', 'u.age') ---> t.age >= u.age") + public On gte2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return gte2(true, column1, column2); + } + + @Override + @Comment("大于等于`>=`,如:`get('t.age', 'u.age') ---> t.age >= u.age") + public On gte2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.gte2(condition, column1, column2); + return this; + } + + @Override + @Comment("`in`,如:`in('age', [1,2,3]) ---> age in (1,2,3)") + public On in(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return in(true, column, value); + } + + @Override + @Comment("`in`,如:`in('age', [1,2,3]) ---> age in (1,2,3)") + public On in(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.in(condition, column, value); + return this; + } + + @Override + @Comment("`not in`,如:`notIn('age', [1,2,3]) ---> age not in (1,2,3)") + public On notIn(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return notIn(true, column, value); + } + + @Override + @Comment("`not in`,如:`notIn('age', [1,2,3]) ---> age not in (1,2,3)") + public On notIn(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.notIn(condition, column, value); + return this; + } + + @Override + @Comment("`like`,如:`like('name', '%王%') ---> name like '%王%'") + public On like(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return like(true, column, value); + } + + @Override + @Comment("`like`,如:`like('name', '%王%') ---> name like '%王%'") + public On like(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.like(condition, column, value); + return this; + } + + @Override + @Comment("`not like`,如:`notLike('name', '%王%') ---> name not like '%王%'") + public On notLike(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return notLike(true, column, value); + } + + @Override + @Comment("`not like` ,如:`notLike('name', '%王%') ---> name not like '%王%'") + public On notLike(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + super.notLike(condition, column, value); + return this; + } + + @Override + @Comment("`is null`,如:`isNull('name') ---> name is null") + public On isNull(@Comment(name = "column", value = "数据库中的列名") String column) { + return isNull(true, column); + } + + @Override + @Comment("`is null`,如:`isNull('name') ---> name is null") + public On isNull(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column) { + super.isNull(condition, column); + return this; + } + + @Override + @Comment("`is not null`,如:`isNotNull('name') ---> name is not null") + public On isNotNull(@Comment(name = "column", value = "数据库中的列名") String column) { + return isNotNull(true, column); + } + + @Override + @Comment("`is not null`,如:`isNotNull('name') ---> name is not null") + public On isNotNull(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column) { + super.isNotNull(condition, column); + return this; + } + + @Override + @Comment("拼接`or`") + public On or() { + super.or(); + return this; + } + + @Override + @Comment("拼接`and`") + public On and() { + super.and(); + return this; + } + + @Override + @Comment("`and`嵌套,如and(it => it.eq('name','李白').ne('status','正常') --> and (name = '李白' and status <> '正常')") + public On and(@Comment(name = "function", value = "回调函数") Function function) { + return and(true, function); + } + + @Override + @Comment("`and`嵌套,如and(it => it.eq('name','李白').ne('status','正常') --> and (name = '李白' and status <> '正常')") + public On and(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "function", value = "回调函数") Function function) { + super.and(condition, function); + return this; + } + + @Override + @Comment("拼接`order by xxx asc/desc`") + public On orderBy(@Comment(name = "column", value = "要排序的列") String column, + @Comment(name = "sort", value = "`asc`或`desc`") String sort) { + + this.getNamedTable().orderBy(column, sort); + return this; + } + + @Override + @Comment("拼接`order by xxx asc`") + public On orderBy(@Comment(name = "column", value = "要排序的列") String column) { + return orderBy(column, "asc"); + } + + @Override + @Comment("拼接`order by xxx desc`") + public On orderByDesc(@Comment(name = "column", value = "要排序的列") String column) { + return orderBy(column, "desc"); + } + + @Override + @Comment("拼接`group by`") + public On groupBy(@Comment("要分组的列") String... columns) { + this.getNamedTable().groupBy(columns); + return this; + } + + @Override + protected String getSql() { + remove(); + if (isEmpty()) { + return ""; + } + return (needWhere ? " on " : "") + String.join(" ", tokens); + } + + @Override + @Transient + @Comment("拼接join") + public JoinedTable join(boolean condition, String joinType, String tableName, String alias) { + return getNamedTable().join(condition, joinType, tableName, alias); + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/TableBase.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/TableBase.java new file mode 100644 index 0000000000000000000000000000000000000000..eabbeed60a498be8690fc6587e9370d4471a0bb9 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/TableBase.java @@ -0,0 +1,177 @@ +package org.ssssssss.magicapi.modules.db.table; + +import org.apache.commons.lang3.StringUtils; +import org.ssssssss.magicapi.core.model.Attributes; +import org.ssssssss.magicapi.modules.db.SQLModule; +import org.ssssssss.magicapi.modules.db.inteceptor.NamedTableInterceptor; +import org.ssssssss.script.annotation.Comment; + +import java.beans.Transient; +import java.util.List; +import java.util.function.Function; + +/** + * 表操作基类 + * + * @author tom + */ +public class TableBase extends Attributes { + + String tableName; + + String alias; + + SQLModule sqlModule; + + String primary; + + String logicDeleteColumn; + + Object logicDeleteValue; + + boolean useLogic = false; + + Function rowMapColumnMapper; + + List namedTableInterceptors; + + public TableBase(String tableName, String alias, SQLModule sqlModule, Function rowMapColumnMapper, + List namedTableInterceptors) { + this.tableName = tableName; + this.alias = alias; + this.sqlModule = sqlModule; + this.rowMapColumnMapper = rowMapColumnMapper; + this.namedTableInterceptors = namedTableInterceptors; + this.logicDeleteColumn = sqlModule.getLogicDeleteColumn(); + String deleteValue = sqlModule.getLogicDeleteValue(); + this.logicDeleteValue = deleteValue; + if (deleteValue != null) { + boolean isString = deleteValue.startsWith("'") || deleteValue.startsWith("\""); + if (isString && deleteValue.length() > 2) { + this.logicDeleteValue = deleteValue.substring(1, deleteValue.length() - 1); + } else { + try { + this.logicDeleteValue = Integer.parseInt(deleteValue); + } catch (NumberFormatException e) { + this.logicDeleteValue = deleteValue; + } + } + } + } + + protected TableBase() { + } + + @Override + @Comment("克隆") + public TableBase clone() { + TableBase tableBase = new TableBase(); + tableBase.tableName = this.tableName; + tableBase.alias = this.alias; + tableBase.sqlModule = this.sqlModule; + tableBase.primary = this.primary; + tableBase.logicDeleteValue = this.logicDeleteValue; + tableBase.logicDeleteColumn = this.logicDeleteColumn; + tableBase.rowMapColumnMapper = this.rowMapColumnMapper; + tableBase.namedTableInterceptors = this.namedTableInterceptors; + tableBase.properties = this.properties; + return tableBase; + } + + + /** + * 获取别名 + * + * @return 名 + */ + @Transient + String getAlisName(String name) { + if (StringUtils.isNotEmpty(alias)) { + return name + DbConstant.AS + alias; + } + return name; + } + + + /** + * 获取别名 + * + * @return 名 + */ + @Transient + String withAlis(String name) { + if (StringUtils.isNotEmpty(alias)) { + return alias + DbConstant.DOT + name; + } + return name; + } + + + /** + * 获取查询的表名 + * + * @return 表名 + */ + @Transient + public String getTableName() { + return tableName; + } + + /** + * 设置表名 + * + * @param tableName 表名 + */ + @Transient + public void setTableName(String tableName) { + this.tableName = tableName; + } + + /** + * 获取SQL模块 + */ + @Transient + public SQLModule getSqlModule() { + return sqlModule; + } + + /** + * 获取主键列 + */ + @Transient + public String getPrimary() { + return primary; + } + + /** + * 获取逻辑删除列 + */ + @Transient + public String getLogicDeleteColumn() { + return logicDeleteColumn; + } + + /** + * 获取逻辑删除值 + */ + @Transient + public Object getLogicDeleteValue() { + return logicDeleteValue; + } + + /** + * 是否设逻辑了逻辑删除 + */ + @Transient + public boolean isUseLogic() { + return useLogic; + } + + /** + * 设置是否使用逻辑删除 + */ + @Transient + public void setUseLogic(boolean useLogic) { + this.useLogic = useLogic; + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/TableInterface.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/TableInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..cea6615b4c47a8a6a665ec6d9f579ab7a06a3b8a --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/TableInterface.java @@ -0,0 +1,74 @@ +package org.ssssssss.magicapi.modules.db.table; + +import org.ssssssss.script.annotation.Comment; +import org.ssssssss.script.runtime.RuntimeContext; + +import java.beans.Transient; +import java.util.List; +import java.util.Map; + +/** + * 表查询操作接口 + * + * @author tom + */ +public interface TableInterface { + + @Transient + NamedTable getNamedTable(); + + @Comment("拼接`order by xxx asc/desc`") + default TableInterface orderBy(@Comment(name = "column", value = "要排序的列") String column, + @Comment(name = "sort", value = "`asc`或`desc`") String sort) { + this.getNamedTable().orderBy(column, sort); + return this; + } + + @Comment("拼接`order by xxx asc`") + default TableInterface orderBy(@Comment(name = "column", value = "要排序的列") String column) { + return orderBy(column, "asc"); + } + + @Comment("拼接`order by xxx desc`") + default TableInterface orderByDesc(@Comment(name = "column", value = "要排序的列") String column) { + return orderBy(column, "desc"); + } + + @Comment("拼接`group by`") + default TableInterface groupBy(@Comment("要分组的列") String... columns) { + this.getNamedTable().groupBy(columns); + return this; + } + + @Comment("执行分页查询") + default Object page(RuntimeContext runtimeContext) { + return getNamedTable().page(runtimeContext); + } + + @Comment("执行分页查询,分页条件手动传入") + default Object page(RuntimeContext runtimeContext, + @Comment(name = "limit", value = "限制条数") long limit, + @Comment(name = "offset", value = "跳过条数") long offset) { + return getNamedTable().page(runtimeContext, limit, offset); + } + + @Comment("执行select查询") + default List> select(RuntimeContext runtimeContext) { + return getNamedTable().select(runtimeContext); + } + + @Comment("执行selectOne查询") + default Map selectOne(RuntimeContext runtimeContext) { + return getNamedTable().selectOne(runtimeContext); + } + + @Comment("查询条数") + default int count(RuntimeContext runtimeContext) { + return getNamedTable().count(runtimeContext); + } + + @Comment("查询是否存在") + default boolean exists(RuntimeContext runtimeContext) { + return getNamedTable().exists(runtimeContext); + } +} diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/Where.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/Where.java index 6b3067bd5e7e79acd0f51604416f432b0eac9951..7b28e8253e2134db0cd15143992e686246f02606 100644 --- a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/Where.java +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/Where.java @@ -1,12 +1,10 @@ package org.ssssssss.magicapi.modules.db.table; -import org.apache.commons.lang3.StringUtils; import org.ssssssss.script.annotation.Comment; -import org.ssssssss.script.functions.StreamExtension; import org.ssssssss.script.runtime.RuntimeContext; import java.beans.Transient; -import java.util.*; +import java.util.Map; import java.util.function.Function; /** @@ -14,485 +12,570 @@ import java.util.function.Function; * * @author mxd */ -public class Where { - - private final List tokens = new ArrayList<>(); - - private final List params = new ArrayList<>(); - - private final NamedTable namedTable; - - private final boolean needWhere; - - private boolean notNull = false; - - private boolean notBlank = false; +public class Where extends WhereBase implements TableInterface { public Where(NamedTable namedTable) { this(namedTable, true); } public Where(NamedTable namedTable, boolean needWhere) { - this.namedTable = namedTable; - this.needWhere = needWhere; + super(namedTable, needWhere); } @Override @Comment("克隆") public Where clone() { - Where where = new Where(this.namedTable, this.needWhere); - where.tokens.addAll(this.tokens); - where.params.addAll(this.params); - where.notNull = this.notNull; - where.notBlank = this.notBlank; - return where; + return (Where) super.clone(); } + @Override + @Transient + public NamedTable getNamedTable() { + return (NamedTable) tableBase; + } + + @Override + @Comment("使用逻辑删除") + public Where logic() { + super.logic(); + return this; + } + + @Override @Comment("过滤`null`的参数") public Where notNull() { return notNull(true); } + @Override @Comment("过滤`blank`的参数") public Where notBlank() { return notBlank(true); } + @Override @Comment("是否过滤`null`的参数") public Where notNull(boolean flag) { - this.notNull = flag; + super.notNull(flag); return this; } + @Override @Comment("是否过滤`blank`的参数") public Where notBlank(boolean flag) { - this.notBlank = flag; + super.notBlank(flag); return this; } + @Override @Comment("等于`=`,如:`eq('name', '老王') ---> name = '老王'`") public Where eq(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return eq(true, column, value); } + @Override @Comment("等于`=`,如:`eq('name', '老王') ---> name = '老王'`") public Where eq(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - if (condition && filterNullAndBlank(value)) { - tokens.add(namedTable.rowMapColumnMapper.apply(column)); - if (value == null) { - append(" is null"); - } else { - params.add(value); - append(" = ?"); - } - appendAnd(); - } + super.eq(condition, column, value); + return this; + } + + @Override + @Comment("等于`=`,如:`eq2('t.userId', 'u.id') ---> t.userId = u.id`") + public Where eq2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return eq2(true, column1, column2); + } + + @Override + @Comment("等于`=`,如:`eq2('t.userId', 'u.id') ---> t.userId = u.id`") + public Where eq2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.eq2(condition, column1, column2); return this; } + @Override @Comment("不等于`<>`,如:`ne('name', '老王') ---> name <> '老王'`") public Where ne(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return ne(true, column, value); } + @Override @Comment("不等于`<>`,如:`ne('name', '老王') ---> name <> '老王'`") public Where ne(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - if (condition && filterNullAndBlank(value)) { - append(namedTable.rowMapColumnMapper.apply(column)); - if (value == null) { - append("is not null"); - } else { - params.add(value); - append("<> ?"); - } - appendAnd(); - } + super.ne(condition, column, value); return this; } + @Override + @Comment("不等于`<>`,如:`ne2('t.name', 'u.name') ---> t.name <> u.name`") + public Where ne2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return ne2(true, column1, column2); + } + + @Override + @Comment("不等于`<>`,如:`ne2('t.name', 'u.name') ---> t.name <> u.name`") + public Where ne2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.ne2(condition, column1, column2); + return this; + } + + @Override @Comment("小于`<`,如:`lt('age', 18) ---> age < 18") public Where lt(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return lt(true, column, value); } + @Override @Comment("小于`<`,如:`lt('age', 18) ---> age < 18") public Where lt(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - return append(condition, column, " < ?", value); + super.lt(condition, column, value); + return this; } + @Override + @Comment("小于`<`,如:`lt2('t.age', 'u.age') ---> t.age < u.age") + public Where lt2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return lt2(true, column1, column2); + } + + @Override + @Comment("小于`<`,如:`lt2('t.age', 'u.age') ---> t.age < u.age") + public Where lt2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.lt2(condition, column1, column2); + return this; + } + + @Override @Comment("小于等于`<=`,如:`lte('age', 18) ---> age <= 18") public Where lte(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return lte(true, column, value); } + @Override @Comment("小于等于`<=`,如:`lte('age', 18) ---> age <= 18") public Where lte(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - return append(condition, column, " <= ?", value); + super.lte(condition, column, value); + return this; + } + + @Override + @Comment("小于等于`<=`,如:`lte2('t.age', 'u.age') ---> t.age <= u.age") + public Where lte2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return lte2(true, column1, column2); + } + + @Override + @Comment("小于等于`<=`,如:`lte2('t.age', 'u.age') ---> t.age <= u.age") + public Where lte2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.lte2(condition, column1, column2); + return this; } + @Override @Comment("大于`>`,如:`get('age', 18) ---> age > 18") public Where gt(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return gt(true, column, value); } + @Override @Comment("大于`>`,如:`get('age', 18) ---> age > 18") public Where gt(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - return append(condition, column, " > ?", value); + super.gt(condition, column, value); + return this; + } + + @Override + @Comment("大于`>`,如:`get('t.age', 't.age') ---> t.age > u.age") + public Where gt2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return gt2(true, column1, column2); } + @Override + @Comment("大于`>`,如:`get('t.age', 't.age') ---> t.age > u.age") + public Where gt2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.gt2(condition, column1, column2); + return this; + } + + @Override @Comment("大于等于`>=`,如:`get('age', 18) ---> age >= 18") public Where gte(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return gte(true, column, value); } + @Override @Comment("大于等于`>=`,如:`get('age', 18) ---> age >= 18") public Where gte(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - return append(condition, column, " >= ?", value); + super.gte(condition, column, value); + return this; + } + + @Override + @Comment("大于等于`>=`,如:`get('t.age', 'u.age') ---> t.age >= u.age") + public Where gte2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return gte2(true, column1, column2); } + @Override + @Comment("大于等于`>=`,如:`get('t.age', 'u.age') ---> t.age >= u.age") + public Where gte2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + super.gte2(condition, column1, column2); + return this; + } + + @Override @Comment("`in`,如:`in('age', [1,2,3]) ---> age in (1,2,3)") public Where in(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return in(true, column, value); } + @Override @Comment("`in`,如:`in('age', [1,2,3]) ---> age in (1,2,3)") public Where in(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - if (condition && value != null) { - List objects = StreamExtension.arrayLikeToList(value); - if (objects.size() > 0) { - append(namedTable.rowMapColumnMapper.apply(column)); - append(" in ("); - append(String.join(",", Collections.nCopies(objects.size(), "?"))); - append(")"); - appendAnd(); - params.addAll(objects); - } - } + super.in(condition, column, value); return this; } + @Override @Comment("`not in`,如:`notIn('age', [1,2,3]) ---> age not in (1,2,3)") public Where notIn(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return notIn(true, column, value); } + @Override @Comment("`not in`,如:`notIn('age', [1,2,3]) ---> age not in (1,2,3)") public Where notIn(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - if (condition && value != null) { - List objects = StreamExtension.arrayLikeToList(value); - if (objects.size() > 0) { - append(namedTable.rowMapColumnMapper.apply(column)); - append("not in ("); - append(String.join(",", Collections.nCopies(objects.size(), "?"))); - append(")"); - appendAnd(); - params.addAll(objects); - } - } + super.notIn(condition, column, value); return this; } + @Override @Comment("`like`,如:`like('name', '%王%') ---> name like '%王%'") public Where like(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return like(true, column, value); } + @Override @Comment("`like`,如:`like('name', '%王%') ---> name like '%王%'") public Where like(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - return append(condition, column, "like ?", value); + super.like(condition, column, value); + return this; } + @Override @Comment("`not like`,如:`notLike('name', '%王%') ---> name not like '%王%'") public Where notLike(@Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { return notLike(true, column, value); } + @Override @Comment("`not like` ,如:`notLike('name', '%王%') ---> name not like '%王%'") public Where notLike(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column, @Comment(name = "value", value = "值") Object value) { - return append(condition, column, "not like ?", value); + super.notLike(condition, column, value); + return this; } + @Override @Comment("`is null`,如:`isNull('name') ---> name is null") public Where isNull(@Comment(name = "column", value = "数据库中的列名") String column) { return isNull(true, column); } + @Override @Comment("`is null`,如:`isNull('name') ---> name is null") public Where isNull(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column) { - if (condition) { - append(namedTable.rowMapColumnMapper.apply(column)); - append("is null"); - appendAnd(); - } + super.isNull(condition, column); return this; } + @Override @Comment("`is not null`,如:`isNotNull('name') ---> name is not null") public Where isNotNull(@Comment(name = "column", value = "数据库中的列名") String column) { return isNotNull(true, column); } + @Override @Comment("`is not null`,如:`isNotNull('name') ---> name is not null") public Where isNotNull(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, @Comment(name = "column", value = "数据库中的列名") String column) { - if (condition) { - append(namedTable.rowMapColumnMapper.apply(column)); - append("is not null"); - appendAnd(); - } + super.isNotNull(condition, column); return this; } + @Override + @Comment("between('t.createTime', '2023-01-01', '2023-01-31', true, false) ---> t.create_time >= '2023-01-01' and t.create_time < '2023-01-31'") + public Where between( + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal, + @Comment(name = "startContain", value = "包含开始值") boolean startContain, + @Comment(name = "endContain", value = "包含结束值") boolean endContain + ) { + return between(true,true,column,startVal,endVal,startContain,endContain); + } + + @Override + @Comment("between(true, true, 't.createTime', '2023-01-01', '2023-01-31') ---> t.create_time >= '2023-01-01' and t.create_time <= '2023-01-31'") + public Where between( + @Comment(name = "startCon", value = "判断表达式,当为true时拼接条件") boolean startCon, + @Comment(name = "endCon", value = "判断表达式,当为true时拼接条件") boolean endCon, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal + ) { + return between(startCon,endCon,column,startVal,endVal,true,true); + } + + @Override + @Comment("between('t.createTime', '2023-01-01', '2023-01-31') ---> t.create_time >= '2023-01-01' and t.create_time <= '2023-01-31'") + public Where between( + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal + ) { + return between(true,true,column,startVal,endVal,true,true); + } + + @Override + @Comment("between(true, true, 't.createTime', '2023-01-01', '2023-01-31', true, false) ---> t.create_time >= '2023-01-01' and t.create_time < '2023-01-31'") + public Where between( + @Comment(name = "startCon", value = "判断表达式,当为true时拼接条件") boolean startCon, + @Comment(name = "endCon", value = "判断表达式,当为true时拼接条件") boolean endCon, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal, + @Comment(name = "startContain", value = "包含开始值") boolean startContain, + @Comment(name = "endContain", value = "包含结束值") boolean endContain + ) { + super.between(startCon, endCon, column, startVal, endVal, startContain, endContain); + return this; + } + + @Override + @Comment("等于`=`,如:`notExists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> not exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public Where notExists(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + exists(true, condition, tableName, alias, function, useLogic); + return this; + } + + @Override + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public Where notExists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return notExists(true, tableName, alias, function, useLogic); + } + + @Override + @Comment("等于`=`,如:`exists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王')) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王'`") + public Where notExists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function) { + return notExists(true, tableName, alias, function, false); + } + + @Override + @Comment("等于`=`,如:`exists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public Where exists(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + super.exists(false, condition, tableName, alias, function, useLogic); + return this; + } + + @Override + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + public Where exists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return exists(true, tableName, alias, function, useLogic); + } + + @Override + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王')) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王'`") + public Where exists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function) { + return exists(true, tableName, alias, function, false); + } + + @Override @Comment("拼接`or`") public Where or() { appendOr(); return this; } + @Override @Comment("拼接`and`") public Where and() { appendAnd(); return this; } + @Override @Comment("`and`嵌套,如and(it => it.eq('name','李白').ne('status','正常') --> and (name = '李白' and status <> '正常')") - public Where and(@Comment(name = "function", value = "回调函数") Function function) { + public Where and(@Comment(name = "function", value = "回调函数") Function function) { return and(true, function); } + @Override @Comment("`and`嵌套,如and(it => it.eq('name','李白').ne('status','正常') --> and (name = '李白' and status <> '正常')") public Where and(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, - @Comment(name = "function", value = "回调函数") Function function) { - if (condition) { - Where expr = function.apply(new Object[]{new Where(this.namedTable, false)}); - this.params.addAll(expr.params); - append("("); - append(expr.getSql()); - append(")"); - appendAnd(); - } + @Comment(name = "function", value = "回调函数") Function function) { + super.and(condition, function); return this; } + @Override @Comment("拼接`order by xxx asc/desc`") public Where orderBy(@Comment(name = "column", value = "要排序的列") String column, @Comment(name = "sort", value = "`asc`或`desc`") String sort) { - this.namedTable.orderBy(column, sort); + + this.getNamedTable().orderBy(column, sort); return this; } + @Override @Comment("拼接`order by xxx asc`") public Where orderBy(@Comment(name = "column", value = "要排序的列") String column) { return orderBy(column, "asc"); } + @Override @Comment("拼接`order by xxx desc`") public Where orderByDesc(@Comment(name = "column", value = "要排序的列") String column) { return orderBy(column, "desc"); } + @Override @Comment("拼接`group by`") public Where groupBy(@Comment("要分组的列") String... columns) { - this.namedTable.groupBy(columns); + this.getNamedTable().groupBy(columns); return this; } @Comment("保存到表中,当主键有值时则修改,否则插入") public Object save(RuntimeContext runtimeContext) { - return namedTable.save(runtimeContext); + return getNamedTable().save(runtimeContext); } @Comment("保存到表中,当主键有值时则修改,否则插入") public Object save(RuntimeContext runtimeContext, @Comment(name = "beforeQuery", value = "是否根据id查询有没有数据") boolean beforeQuery) { - return namedTable.save(runtimeContext, beforeQuery); + return getNamedTable().save(runtimeContext, beforeQuery); } @Comment("保存到表中,当主键有值时则修改,否则插入") public Object save(RuntimeContext runtimeContext, @Comment(name = "data", value = "各项列和值") Map data) { - return namedTable.save(runtimeContext, data); + return getNamedTable().save(runtimeContext, data); } @Comment("保存到表中,当主键有值时则修改,否则插入") public Object save(RuntimeContext runtimeContext, @Comment(name = "data", value = "各项列和值") Map data, @Comment(name = "beforeQuery", value = "是否根据id查询有没有数据") boolean beforeQuery) { - return namedTable.save(runtimeContext, data, beforeQuery); + return getNamedTable().save(runtimeContext, data, beforeQuery); } @Comment("执行插入语句,返回主键") public Object insert(RuntimeContext runtimeContext) { - return namedTable.insert(runtimeContext); + return getNamedTable().insert(runtimeContext); } @Comment("执行插入语句,返回主键") public Object insert(RuntimeContext runtimeContext, @Comment(name = "data", value = "各项列和值") Map data) { - return namedTable.insert(runtimeContext, data); + return getNamedTable().insert(runtimeContext, data); } @Comment("执行update语句") public int update(RuntimeContext runtimeContext) { - return namedTable.update(runtimeContext); + return getNamedTable().update(runtimeContext); } @Comment("执行delete语句") public int delete(RuntimeContext runtimeContext) { - return namedTable.delete(runtimeContext); + return getNamedTable().delete(runtimeContext); } @Comment("执行update语句") public int update(RuntimeContext runtimeContext, @Comment(name = "data", value = "各项列和值") Map data) { - return namedTable.update(runtimeContext, data); + return getNamedTable().update(runtimeContext, data); } @Comment("执行update语句") public int update(RuntimeContext runtimeContext, @Comment(name = "data", value = "各项列和值") Map data, @Comment(name = "isUpdateBlank", value = "是否更新空值字段") boolean isUpdateBlank) { - return namedTable.update(runtimeContext, data, isUpdateBlank); - } - - @Comment("执行分页查询") - public Object page(RuntimeContext runtimeContext) { - return namedTable.page(runtimeContext); - } - - @Comment("执行分页查询,分页条件手动传入") - public Object page(RuntimeContext runtimeContext, - @Comment(name = "limit", value = "限制条数") long limit, - @Comment(name = "offset", value = "跳过条数") long offset) { - return namedTable.page(runtimeContext, limit, offset); - } - - @Comment("执行select查询") - public List> select(RuntimeContext runtimeContext) { - return namedTable.select(runtimeContext); - } - - @Comment("执行selectOne查询") - public Map selectOne(RuntimeContext runtimeContext) { - return namedTable.selectOne(runtimeContext); - } - - @Comment("查询条数") - public int count(RuntimeContext runtimeContext) { - return namedTable.count(runtimeContext); - } - - @Comment("查询是否存在") - public boolean exists(RuntimeContext runtimeContext) { - return namedTable.exists(runtimeContext); - } - - @Transient - public void appendAnd() { - remove(); - tokens.add("and"); - } - - @Transient - public void appendOr() { - remove(); - tokens.add("or"); + return getNamedTable().update(runtimeContext, data, isUpdateBlank); } - List getParams() { - return params; - } - - void remove() { - int size = tokens.size(); - while (size > 0) { - String token = tokens.get(size - 1); - if ("and".equalsIgnoreCase(token) || "or".equalsIgnoreCase(token)) { - tokens.remove(size - 1); - size--; - } else { - break; - } - } - while (size > 0) { - String token = tokens.get(0); - if ("and".equalsIgnoreCase(token) || "or".equalsIgnoreCase(token)) { - tokens.remove(0); - size--; - } else { - break; - } - } - } - - boolean isEmpty() { - return tokens.isEmpty(); - } - - @Transient - public void append(String value) { - tokens.add(value); - } - - @Transient - public void append(String sql, Object value) { - tokens.add(sql); - params.add(value); - } - - String getSql() { + @Override + protected String getSql() { remove(); if (isEmpty()) { return ""; } return (needWhere ? " where " : "") + String.join(" ", tokens); } - - boolean filterNullAndBlank(Object value) { - if (notNull && value == null) { - return false; - } - return !notBlank || !StringUtils.isEmpty(Objects.toString(value, "")); - } - - private Where append(boolean append, String column, String condition, Object value) { - if (append && filterNullAndBlank(value)) { - append(namedTable.rowMapColumnMapper.apply(column)); - append(condition); - appendAnd(); - params.add(value); - } - return this; - } } diff --git a/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/WhereBase.java b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/WhereBase.java new file mode 100644 index 0000000000000000000000000000000000000000..73fa17ba8018c2157bb8b3e0f32870223f40cb94 --- /dev/null +++ b/magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/WhereBase.java @@ -0,0 +1,658 @@ +package org.ssssssss.magicapi.modules.db.table; + +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.StringUtils; +import org.ssssssss.script.annotation.Comment; +import org.ssssssss.script.functions.StreamExtension; + +import java.beans.Transient; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +/** + * 表API的Where基类 + * + * @author tom + */ +public class WhereBase { + + protected final List tokens = new ArrayList<>(); + + protected final List params = new ArrayList<>(); + + protected final TableBase tableBase; + + protected final boolean needWhere; + + protected boolean notNull = false; + + protected boolean notBlank = false; + + public WhereBase(TableBase tableBase) { + this(tableBase, true); + } + + public WhereBase(TableBase tableBase, boolean needWhere) { + this.tableBase = tableBase; + this.needWhere = needWhere; + } + + @Transient + @Comment("克隆") + public WhereBase clone() { + WhereBase whereOrOn = new WhereBase(this.tableBase, this.needWhere); + whereOrOn.tokens.addAll(this.tokens); + whereOrOn.params.addAll(this.params); + whereOrOn.notNull = this.notNull; + whereOrOn.notBlank = this.notBlank; + return whereOrOn; + } + + @Transient + @Comment("过滤`null`的参数") + public WhereBase notNull() { + return notNull(true); + } + + @Comment("过滤`blank`的参数") + public WhereBase notBlank() { + return notBlank(true); + } + + @Transient + @Comment("是否过滤`null`的参数") + WhereBase notNull(boolean flag) { + notNull = flag; + return this; + } + + @Transient + @Comment("是否过滤`blank`的参数") + WhereBase notBlank(boolean flag) { + notBlank = flag; + return this; + } + + @Transient + @Comment("使用逻辑删除") + WhereBase logic() { + tableBase.useLogic = true; + return this; + } + + @Transient + @Comment("等于`=`,如:`eq('name', '老王') ---> name = '老王'`") + WhereBase eq(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return eq(true, column, value); + } + + @Transient + @Comment("等于`=`,如:`eq('name', '老王') ---> name = '老王'`") + WhereBase eq(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + if (condition && filterNullAndBlank(value)) { + tokens.add(tableBase.rowMapColumnMapper.apply(column)); + if (value == null) { + append(" is null"); + } else { + params.add(value); + append(" = ?"); + } + appendAnd(); + } + return this; + } + + @Transient + @Comment("等于`=`,如:`eq2('t.userId', 'u.id') ---> t.userId = u.id`") + WhereBase eq2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return eq2(true, column1, column2); + } + + @Transient + @Comment("等于`=`,如:`eq2('t.userId', 'u.id') ---> t.userId = u.id`") + WhereBase eq2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return append2(condition, column1, " = ", column2); + } + + @Transient + @Comment("不等于`<>`,如:`ne('name', '老王') ---> name <> '老王'`") + WhereBase ne(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return ne(true, column, value); + } + + @Transient + @Comment("不等于`<>`,如:`ne('name', '老王') ---> name <> '老王'`") + WhereBase ne(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + if (condition && filterNullAndBlank(value)) { + append(tableBase.rowMapColumnMapper.apply(column)); + if (value == null) { + append("is not null"); + } else { + params.add(value); + append("<> ?"); + } + appendAnd(); + } + return this; + } + + @Transient + @Comment("不等于`<>`,如:`ne2('t.name', 'u.name') ---> t.name <> u.name`") + WhereBase ne2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return ne2(true, column1, column2); + } + + @Transient + @Comment("不等于`<>`,如:`ne2('t.name', 'u.name') ---> t.name <> u.name`") + WhereBase ne2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return append2(condition, column1, " <> ", column2); + } + + @Transient + @Comment("between('t.createTime', '2023-01-01', '2023-01-31', true, false) ---> t.create_time >= '2023-01-01' and t.create_time < '2023-01-31'") + WhereBase between( + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal, + @Comment(name = "startContain", value = "包含开始值") boolean startContain, + @Comment(name = "endContain", value = "包含结束值") boolean endContain + ) { + return between(true,true,column,startVal,endVal,startContain,endContain); + } + + @Transient + @Comment("between(true, true, 't.createTime', '2023-01-01', '2023-01-31') ---> t.create_time >= '2023-01-01' and t.create_time <= '2023-01-31'") + WhereBase between( + @Comment(name = "startCon", value = "判断表达式,当为true时拼接条件") boolean startCon, + @Comment(name = "endCon", value = "判断表达式,当为true时拼接条件") boolean endCon, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal + ) { + return between(startCon,endCon,column,startVal,endVal,true,true); + } + + @Transient + @Comment("between('t.createTime', '2023-01-01', '2023-01-31') ---> t.create_time >= '2023-01-01' and t.create_time <= '2023-01-31'") + WhereBase between( + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal + ) { + return between(true,true,column,startVal,endVal,true,true); + } + + @Transient + @Comment("between(true, true, 't.createTime', '2023-01-01', '2023-01-31', true, false) ---> t.create_time >= '2023-01-01' and t.create_time < '2023-01-31'") + WhereBase between( + @Comment(name = "startCon", value = "判断表达式,当为true时拼接条件") boolean startCon, + @Comment(name = "endCon", value = "判断表达式,当为true时拼接条件") boolean endCon, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "startVal", value = "开始值") Object startVal, + @Comment(name = "endVal", value = "结束值") Object endVal, + @Comment(name = "startContain", value = "包含开始值") boolean startContain, + @Comment(name = "endContain", value = "包含结束值") boolean endContain + ) { + append(startCon,column,startContain ? ">=" : ">",startVal).append(endCon,column,endContain ? "<=" : "<",endVal); + return this; + } + + @Transient + @Comment("等于`=`,如:`notExists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> not exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + WhereBase notExists(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return exists(true, condition, tableName, alias, function, useLogic); + } + + @Transient + @Comment("等于`=`,如:`notExists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> not exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + WhereBase notExists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return notExists(true, tableName, alias, function, useLogic); + } + + @Transient + @Comment("等于`=`,如:`notExists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王')) ---> not exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王'`") + WhereBase notExists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function) { + return notExists(true, tableName, alias, function, false); + } + + @Transient + @Comment("等于`=`,如:`exists(true, 'table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + WhereBase exists(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return exists(false, condition, tableName, alias, function, useLogic); + } + + @Transient + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王'), true) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王' and tn.del_flag<>1`") + WhereBase exists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function, + @Comment(name = "useLogic", value = "使用逻辑删除") boolean useLogic) { + return exists(true, tableName, alias, function, useLogic); + } + + @Transient + @Comment("等于`=`,如:`exists('table_name', 'tn', namedWhere -> namedWhere.eq2('tn.aId','a.id').eq('tn.name','老王')) ---> exists(select 1 from table_name as tn namedWhere tn.a_id=a.id and tn.user_id='老王'`") + WhereBase exists(@Comment(name = "tableName", value = "表名") String tableName, + @Comment(name = "alias", value = "别名") String alias, + @Comment(name = "function", value = "关联条件") Function function) { + return exists(true, tableName, alias, function, false); + } + + @Comment("存在子查询") + WhereBase exists(boolean notFlag, boolean condition, String tableName, String alias, + Function function, + boolean useLogic) { + if (condition) { + if (notFlag) { + append("not"); + } + append("exists(select 1 from"); + append(tableName); + if (StringUtils.isNotEmpty(alias)) { + append("as"); + append(alias); + } + WhereBase whereBase = new WhereBase(tableBase); + function.apply(whereBase); + if (!whereBase.isEmpty()) { + whereBase.and(); + } + whereBase.ne(useLogic, + (StringUtils.isNotEmpty(alias) ? (alias + ".") : "") + tableBase.logicDeleteColumn, + tableBase.logicDeleteValue); + append(whereBase.getSql()); + params.addAll(whereBase.getParams()); + append(")"); + appendAnd(); + } + return this; + } + + @Transient + @Comment("小于`<`,如:`lt('age', 18) ---> age < 18") + WhereBase lt(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return lt(true, column, value); + } + + @Transient + @Comment("小于`<`,如:`lt('age', 18) ---> age < 18") + WhereBase lt(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return append(condition, column, " < ?", value); + } + + @Transient + @Comment("小于`<`,如:`lt2('t.age', 'u.age') ---> t.age < u.age") + WhereBase lt2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return lt2(true, column1, column2); + } + + @Transient + @Comment("小于`<`,如:`lt2('t.age', 'u.age') ---> t.age < u.age") + WhereBase lt2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return append2(condition, column1, " < ", column2); + } + + @Transient + @Comment("小于等于`<=`,如:`lte('age', 18) ---> age <= 18") + WhereBase lte(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return lte(true, column, value); + } + + @Transient + @Comment("小于等于`<=`,如:`lte('age', 18) ---> age <= 18") + WhereBase lte(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return append(condition, column, " <= ?", value); + } + + @Transient + @Comment("小于等于`<=`,如:`lte2('t.age', 'u.age') ---> t.age <= u.age") + WhereBase lte2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return lte2(true, column1, column2); + } + + @Transient + @Comment("小于等于`<=`,如:`lte2('t.age', 'u.age') ---> t.age <= u.age") + WhereBase lte2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return append2(condition, column1, " <= ", column2); + } + + @Transient + @Comment("大于`>`,如:`get('age', 18) ---> age > 18") + WhereBase gt(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return gt(true, column, value); + } + + @Transient + @Comment("大于`>`,如:`get('age', 18) ---> age > 18") + WhereBase gt(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return append(condition, column, " > ?", value); + } + + @Transient + @Comment("大于`>`,如:`get('t.age', 't.age') ---> t.age > u.age") + WhereBase gt2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return gt2(true, column1, column2); + } + + @Transient + @Comment("大于`>`,如:`get('t.age', 't.age') ---> t.age > u.age") + WhereBase gt2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return append2(condition, column1, " > ", column2); + } + + @Transient + @Comment("大于等于`>=`,如:`get('age', 18) ---> age >= 18") + WhereBase gte(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return gte(true, column, value); + } + + @Transient + @Comment("大于等于`>=`,如:`get('age', 18) ---> age >= 18") + WhereBase gte(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return append(condition, column, " >= ?", value); + } + + @Transient + @Comment("大于等于`>=`,如:`get('t.age', 'u.age') ---> t.age >= u.age") + WhereBase gte2(@Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return gte2(true, column1, column2); + } + + @Transient + @Comment("大于等于`>=`,如:`get('t.age', 'u.age') ---> t.age >= u.age") + WhereBase gte2(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column1", value = "数据库中的列名1") String column1, + @Comment(name = "column2", value = "数据库中的列名2") String column2) { + return append2(condition, column1, " >= ", column2); + } + + @Transient + @Comment("`in`,如:`in('age', [1,2,3]) ---> age in (1,2,3)") + WhereBase in(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return in(true, column, value); + } + + @Transient + @Comment("`in`,如:`in('age', [1,2,3]) ---> age in (1,2,3)") + WhereBase in(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + if (condition && value != null) { + List objects = StreamExtension.arrayLikeToList(value); + if (!objects.isEmpty()) { + append(tableBase.rowMapColumnMapper.apply(column)); + append(" in ("); + append(String.join(",", Collections.nCopies(objects.size(), "?"))); + append(")"); + appendAnd(); + params.addAll(objects); + } + } + return this; + } + + @Transient + @Comment("`not in`,如:`notIn('age', [1,2,3]) ---> age not in (1,2,3)") + WhereBase notIn(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return notIn(true, column, value); + } + + @Transient + @Comment("`not in`,如:`notIn('age', [1,2,3]) ---> age not in (1,2,3)") + WhereBase notIn(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + if (condition && value != null) { + List objects = StreamExtension.arrayLikeToList(value); + if (!objects.isEmpty()) { + append(tableBase.rowMapColumnMapper.apply(column)); + append("not in ("); + append(String.join(",", Collections.nCopies(objects.size(), "?"))); + append(")"); + appendAnd(); + params.addAll(objects); + } + } + return this; + } + + @Transient + @Comment("`like`,如:`like('name', '%王%') ---> name like '%王%'") + WhereBase like(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return like(true, column, value); + } + + @Transient + @Comment("`like`,如:`like('name', '%王%') ---> name like '%王%'") + WhereBase like(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return append(condition, column, "like ?", value); + } + + @Transient + @Comment("`not like`,如:`notLike('name', '%王%') ---> name not like '%王%'") + WhereBase notLike(@Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return notLike(true, column, value); + } + + @Transient + @Comment("`not like` ,如:`notLike('name', '%王%') ---> name not like '%王%'") + WhereBase notLike(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column, + @Comment(name = "value", value = "值") Object value) { + return append(condition, column, "not like ?", value); + } + + @Transient + @Comment("`is null`,如:`isNull('name') ---> name is null") + WhereBase isNull(@Comment(name = "column", value = "数据库中的列名") String column) { + return isNull(true, column); + } + + @Transient + @Comment("`is null`,如:`isNull('name') ---> name is null") + WhereBase isNull(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column) { + if (condition) { + append(tableBase.rowMapColumnMapper.apply(column)); + append("is null"); + appendAnd(); + } + return this; + } + + @Transient + @Comment("`is not null`,如:`isNotNull('name') ---> name is not null") + WhereBase isNotNull(@Comment(name = "column", value = "数据库中的列名") String column) { + return isNotNull(true, column); + } + + @Transient + @Comment("`is not null`,如:`isNotNull('name') ---> name is not null") + WhereBase isNotNull(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "column", value = "数据库中的列名") String column) { + if (condition) { + append(tableBase.rowMapColumnMapper.apply(column)); + append("is not null"); + appendAnd(); + } + return this; + } + + @Transient + @Comment("拼接`or`") + WhereBase or() { + appendOr(); + return this; + } + + @Transient + @Comment("拼接`and`") + WhereBase and() { + appendAnd(); + return this; + } + + @Transient + @Comment("`and`嵌套,如and(it => it.eq('name','李白').ne('status','正常') --> and (name = '李白' and status <> '正常')") + WhereBase and(@Comment(name = "function", value = "回调函数") Function function) { + return and(true, function); + } + + @Transient + @Comment("`and`嵌套,如and(it => it.eq('name','李白').ne('status','正常') --> and (name = '李白' and status <> '正常')") + WhereBase and(@Comment(name = "condition", value = "判断表达式,当为true时拼接条件") boolean condition, + @Comment(name = "function", value = "回调函数") Function function) { + if (condition) { + WhereBase expr = function.apply(new Object[]{new WhereBase(this.tableBase, false)}); + this.params.addAll(expr.params); + String sql = expr.getSql(); + if (StringUtils.isNotBlank(sql)) { + append("("); + append(sql); + append(")"); + appendAnd(); + } + } + return this; + } + + @Transient + void appendAnd() { + remove(); + tokens.add("and"); + } + + @Transient + void appendOr() { + remove(); + tokens.add("or"); + } + + List getParams() { + return params; + } + + void remove() { + int size = tokens.size(); + while (size > 0) { + String token = tokens.get(size - 1); + if ("and".equalsIgnoreCase(token) || "or".equalsIgnoreCase(token)) { + tokens.remove(size - 1); + size--; + } else { + break; + } + } + while (size > 0) { + String token = tokens.get(0); + if ("and".equalsIgnoreCase(token) || "or".equalsIgnoreCase(token)) { + tokens.remove(0); + size--; + } else { + break; + } + } + } + + boolean isEmpty() { + return tokens.isEmpty(); + } + + @Transient + void append(String value) { + tokens.add(value); + } + + @Transient + void append(String sql, Object value) { + tokens.add(sql); + params.add(value); + } + + protected String getSql() { + throw new NotImplementedException("获取sql方法未实现!"); + } + + boolean filterNullAndBlank(Object value) { + if (notNull && value == null) { + return false; + } + return !notBlank || !StringUtils.isEmpty(Objects.toString(value, "")); + } + + WhereBase append(boolean append, String column, String condition, Object value) { + if (append && filterNullAndBlank(value)) { + append(tableBase.rowMapColumnMapper.apply(column)); + append(condition); + appendAnd(); + params.add(value); + } + return this; + } + + WhereBase append2(boolean append, String column1, String condition, String column2) { + if (append) { + append(tableBase.rowMapColumnMapper.apply(column1)); + append(condition); + append(tableBase.rowMapColumnMapper.apply(column2)); + appendAnd(); + } + return this; + } +}