001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.query; 017 018import com.mybatisflex.core.FlexConsts; 019import com.mybatisflex.core.constant.SqlConsts; 020import com.mybatisflex.core.dialect.IDialect; 021import com.mybatisflex.core.util.CollectionUtil; 022import com.mybatisflex.core.util.SqlUtil; 023import com.mybatisflex.core.util.StringUtil; 024 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.List; 028import java.util.Objects; 029import java.util.stream.Collectors; 030 031/** 032 * 数据库 聚合函数,例如 count(id) ,max(account.age) 等等 033 */ 034public class FunctionQueryColumn extends QueryColumn implements HasParamsColumn { 035 036 protected String fnName; 037 protected List<QueryColumn> columns; 038 039 public FunctionQueryColumn(String fnName) { 040 SqlUtil.keepColumnSafely(fnName); 041 this.fnName = fnName; 042 this.columns = new ArrayList<>(); 043 } 044 045 public FunctionQueryColumn(String fnName, String... columns) { 046 this(fnName); 047 for (String column : columns) { 048 // SqlUtil.keepColumnSafely(column) 049 this.columns.add(new QueryColumn(column)); 050 } 051 } 052 053 public FunctionQueryColumn(String fnName, QueryColumn... columns) { 054 this(fnName); 055 this.columns.addAll(Arrays.asList(columns)); 056 } 057 058 public String getFnName() { 059 return fnName; 060 } 061 062 public void setFnName(String fnName) { 063 this.fnName = fnName; 064 } 065 066 public List<QueryColumn> getColumns() { 067 return columns; 068 } 069 070 public void setColumns(List<QueryColumn> columns) { 071 this.columns = columns; 072 } 073 074 @Override 075 public Object[] getParamValues() { 076 if (CollectionUtil.isEmpty(columns)) { 077 return FlexConsts.EMPTY_ARRAY; 078 } 079 080 List<Object> params = new ArrayList<>(); 081 082 for (QueryColumn queryColumn : columns) { 083 if (queryColumn instanceof HasParamsColumn) { 084 Object[] paramValues = ((HasParamsColumn) queryColumn).getParamValues(); 085 params.addAll(Arrays.asList(paramValues)); 086 } 087 } 088 089 return params.toArray(); 090 } 091 092 @Override 093 public String toSelectSql(List<QueryTable> queryTables, IDialect dialect) { 094 String sql = getSql(queryTables, dialect); 095 if (StringUtil.isBlank(alias)) { 096 return fnName + WrapperUtil.withBracket(sql); 097 } 098 return fnName + WrapperUtil.withAlias(sql, alias, dialect); 099 } 100 101 @Override 102 String toConditionSql(List<QueryTable> queryTables, IDialect dialect) { 103 String sql = getSql(queryTables, dialect); 104 return fnName + WrapperUtil.withBracket(sql); 105 } 106 107 /** 108 * <p>获取函数括号里面的 SQL 内容。 109 * 110 * <p>如果函数括号里面没有内容,就返回空字符串,这样构建出来就是函数名加括号。 111 * 112 * <p>例如,NOW() 函数的构建: 113 * <pre>{@code 114 * FunctionQueryColumn c1 = new FunctionQueryColumn("NOW"); 115 * FunctionQueryColumn c2 = new FunctionQueryColumn("NOW", new StringQueryColumn("")); 116 * }</pre> 117 */ 118 private String getSql(List<QueryTable> queryTables, IDialect dialect) { 119 if (CollectionUtil.isEmpty(columns)) { 120 return SqlConsts.EMPTY; 121 } 122 123 String sql = columns.stream() 124 .filter(Objects::nonNull) 125 .map(c -> c.toSelectSql(queryTables, dialect)) 126 .collect(Collectors.joining(SqlConsts.DELIMITER)); 127 128 if (StringUtil.isBlank(sql)) { 129 return SqlConsts.EMPTY; 130 } 131 132 return sql; 133 } 134 135 136 @Override 137 public String toString() { 138 return "FunctionQueryColumn{" + 139 "fnName='" + fnName + '\'' + 140 ", columns=" + columns + 141 '}'; 142 } 143 144 @Override 145 public FunctionQueryColumn clone() { 146 FunctionQueryColumn clone = (FunctionQueryColumn) super.clone(); 147 // deep clone ... 148 clone.columns = CollectionUtil.cloneArrayList(this.columns); 149 return clone; 150 } 151 152 153}