CustomFuntionExpression.java
package com.github.mygreen.sqlmapper.metamodel.expression;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import com.github.mygreen.sqlmapper.metamodel.operation.BooleanOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.LocalDateOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.LocalDateTimeOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.LocalTimeOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.NumberOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.SqlDateOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.SqlTimeOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.SqlTimestampOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.StringOperation;
import com.github.mygreen.sqlmapper.metamodel.operation.UtilDateOperation;
import com.github.mygreen.sqlmapper.metamodel.operator.FunctionOp;
import com.github.mygreen.sqlmapper.metamodel.support.SqlFunctionParser;
import com.github.mygreen.sqlmapper.metamodel.support.SqlFunctionParser.Token;
import com.github.mygreen.sqlmapper.metamodel.support.SqlFunctionTokenizer.TokenType;
import lombok.Getter;
/**
* 任意の関数式を表現します。
*
* @since 0.3
* @author T.TSUCHIE
*
*/
public abstract class CustomFuntionExpression<T> implements Expression<T> {
protected final Expression<?> mixin;
/**
* 関数のクエリ
*/
@Getter
protected final String query;
/**
* 関数の引数
*/
@Getter
protected final List<Expression<?>> args;
/**
* SQL関数をパースしてトークンに分解した結果
*/
@Getter
protected final List<Token> tokens;
public CustomFuntionExpression(Expression<?> mixin, String query, Object... args) {
if(query == null || query.isEmpty()) {
throw new IllegalArgumentException("query should be not empty.");
}
/*
* クエリ中のプレースホルダーと引数の個数を比較する。
* プレースホルダーをカウントするときには、文字列句('abc')などを考慮する必要があるが、
* そこまで複雑なことはしないと思うので実施しない。
*/
List<Token> tokens = new SqlFunctionParser().parse(query);
int countPlaceHolder = (int) tokens.stream()
.filter(t -> t.type == TokenType.BIND_VARIABLE)
.count();
int sizeArgs = (args == null ? 0 : args.length);
if(countPlaceHolder != sizeArgs) {
throw new IllegalArgumentException(String.format("'%s' is not match place holder count '%d'. ", query, countPlaceHolder));
}
this.mixin = mixin;
this.query = query;
this.tokens = tokens;
if(sizeArgs == 0) {
this.args = Collections.emptyList();
} else {
this.args = Arrays.stream(args)
.map(this::convertExpression)
.collect(Collectors.toList());
}
}
/**
* 値を式オブジェクトに変換する。
* @param value 値
* @return 変換した値
*/
@SuppressWarnings("rawtypes")
private Expression<?> convertExpression(Object value) {
if(value instanceof Expression) {
return (Expression)value;
} else if(value instanceof Collection) {
return Constant.createCollection((Collection)value);
} else {
return Constant.create(value);
}
}
/**
* 関数の戻り値の型を返します。
* @return ブーリアン型を返します。
*/
public BooleanExpression returnBoolean() {
return new BooleanOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return 文字列型を返します。
*/
public StringExpression returnString() {
return new StringOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @param type 数値の具象クラスを指定します。
* @return 数値型を返します。
*/
public <R extends Number & Comparable<R>> NumberExpression<R> returnNumber(Class<R> type) {
return new NumberOperation<R>(type, FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link LocalDate}型を返します。
*/
public LocalDateExpression returnLocalDate() {
return new LocalDateOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link LocalTime}型を返します。
*/
public LocalTimeExpression returnLocalTime() {
return new LocalTimeOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link LocalDateTime}型を返します。
*/
public LocalDateTimeExpression returnLocalDateTime() {
return new LocalDateTimeOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link Date}型を返します。
*/
public SqlDateExpression returnSqlDate() {
return new SqlDateOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link Time}型を返します。
*/
public SqlTimeExpression returnSqlTime() {
return new SqlTimeOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link Timestamp}型を返します。
*/
public SqlTimestampExpression returnSqlTimeStamp() {
return new SqlTimestampOperation(FunctionOp.CUSTOM, mixin, this);
}
/**
* 関数の戻り値の型を返します。
* @return {@link java.util.Date}型を返します。
*/
public UtilDateExpression returnUtilDate() {
return new UtilDateOperation(FunctionOp.CUSTOM, mixin, this);
}
// /**
// * 関数の戻り値の型を返します。
// * @return 列挙型を返します。
// */
// public <R extends Enum<R>> EnumExpression<R> returnEnum(Class<R> type) {
// return new EnumOperation<R>(type, FunctionOp.CUSTOM, mixin, this);
// }
}