com.jaregu.database.queries.compiling.OptionalNamedParameterFeatureBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of queries Show documentation
Show all versions of queries Show documentation
Java based SQL templating project. Store your queries in *.sql files and build queries for execution. Supports simple expressions and conditional clauses and interface proxying for java-sql bridge.
package com.jaregu.database.queries.compiling;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import com.jaregu.database.queries.building.NamedResolver;
import com.jaregu.database.queries.building.ParameterBinder;
import com.jaregu.database.queries.building.ParametersResolver;
import com.jaregu.database.queries.building.QueryBuildException;
import com.jaregu.database.queries.compiling.expr.Expression;
import com.jaregu.database.queries.compiling.expr.Expression.ExpressionResult;
import com.jaregu.database.queries.compiling.expr.ExpressionParser;
import com.jaregu.database.queries.parsing.CommentType;
import com.jaregu.database.queries.parsing.ParsedQueryPart;
public abstract class OptionalNamedParameterFeatureBase implements QueryCompilerFeature {
private final ExpressionParser expressionParser;
private final ParameterBinder parameterBinder;
protected final Function isSqlWithoutNewLine = (p) -> p.isSimplePart()
&& !p.getContent().contains("\n");
protected final Function isSQL = (p) -> p.isSimplePart();
protected final Function isAnonymousVariable = (p) -> p.isAnonymousVariable();
protected final Function isHyphenCommentExpression = isHyphenCommentExpression();
protected final Function isSlashCommentExpression = isSlashCommentExpression();
OptionalNamedParameterFeatureBase(ExpressionParser expressionParser, ParameterBinder parameterBinder) {
this.expressionParser = expressionParser;
this.parameterBinder = parameterBinder;
}
private Function isHyphenCommentExpression() {
return (p) -> {
return p.isComment() && p.getCommentType() == CommentType.HYPHENS
&& expressionParser.isLikeExpression(p.getCommentContent());
};
}
private Function isSlashCommentExpression() {
return (p) -> {
return p.isComment() && p.getCommentType() == CommentType.SLASH_AND_ASTERISK
&& expressionParser.isLikeExpression(p.getCommentContent());
};
}
protected final boolean isPartsLike(Source source, List> matchers) {
List parts = source.getParts();
boolean matching = true;
if (parts.size() == matchers.size()) {
for (int i = 0; i < matchers.size(); i++) {
Function function = matchers.get(i);
ParsedQueryPart part = parts.get(i);
matching = matching && function.apply(part);
if (!matching) {
break;
}
}
} else {
matching = false;
}
return matching;
}
protected class Builder {
private Source source;
private Optional beforePartIndex;
private boolean replaceLastConstant;
private List afterPartIndex = Collections.emptyList();
private int commentPartIndex;
public Builder(Source source) {
this.source = source;
}
public Builder before(int beforePartIndex) {
return before(beforePartIndex, false);
}
public Builder before(int beforePartIndex, boolean replaceLastConstant) {
this.beforePartIndex = Optional.of(beforePartIndex);
this.replaceLastConstant = replaceLastConstant;
return this;
}
public Builder after(Integer... afterPartIndexes) {
this.afterPartIndex = Arrays.asList(afterPartIndexes);
return this;
}
public Builder comment(int commentPartIndex) {
this.commentPartIndex = commentPartIndex;
return this;
}
public Result build() {
List parts = source.getParts();
StringBuilder beforeSql = new StringBuilder();
StringBuilder afterSql = new StringBuilder();
if (replaceLastConstant) {
ArgumentSplitter.Result splitResult = ArgumentSplitter.of(parts.get(beforePartIndex.get()).getContent())
.split();
beforeSql.append(splitResult.getBeforeSql());
afterSql.append(CommentType.SLASH_AND_ASTERISK.wrap(splitResult.getArgumentSql()))
.append(splitResult.getAfterSql());
} else {
beforePartIndex.map(parts::get).map(ParsedQueryPart::getContent).ifPresent(beforeSql::append);
}
afterPartIndex.stream().map(parts::get).map(ParsedQueryPart::getContent).forEach(afterSql::append);
List expressions = getExpressions();
return new Result() {
@Override
public List getParts() {
return Collections.singletonList(new CompiledQueryOneParameterPart(beforeSql.toString(),
afterSql.toString(), expressions, parameterBinder));
}
};
}
private List getExpressions() {
List expressions = expressionParser
.parse(source.getParts().get(commentPartIndex).getCommentContent());
return expressions;
}
}
private static final class CompiledQueryOneParameterPart implements PreparedQueryPart {
private final String beforeSql;
private final String afterSql;
private final Expression valueExpression;
private final Optional conditionalExpression;
private final ParameterBinder parameterBinder;
public CompiledQueryOneParameterPart(String beforeSql, String afterSql, List expressions,
ParameterBinder parameterBinder) {
this.beforeSql = beforeSql;
this.afterSql = afterSql;
this.valueExpression = expressions.get(0);
this.conditionalExpression = expressions.size() == 1 ? Optional.empty() : Optional.of(expressions.get(1));
this.parameterBinder = parameterBinder;
}
@Override
public Result build(ParametersResolver resolver) {
if (addCriterionLine(resolver)) {
ExpressionResult expressionResult = valueExpression.eval(resolver);
Object value = expressionResult.getReturnValue();
ParameterBinder.Result variableBindingResult = parameterBinder.process(value);
String sql = beforeSql + variableBindingResult.getSql() + afterSql;
List