/*
* Copyright 2014 mango.jfaster.org
*
* The Mango Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.jfaster.mango.parser;
import com.google.common.collect.Lists;
import org.hamcrest.Matchers;
import org.jfaster.mango.binding.*;
import org.jfaster.mango.binding.BoundSql;
import org.jfaster.mango.support.ParserVisitorAdapter;
import org.jfaster.mango.util.jdbc.JdbcType;
import org.jfaster.mango.util.jdbc.SQLType;
import org.jfaster.mango.util.reflect.TypeToken;
import org.jfaster.mango.descriptor.ParameterDescriptor;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
/**
* @author ash
*/
public class ParserTest {
@Test
public void testBase() throws Exception {
String sql = "select #{:1} from user where id in (:2) and name=:3";
ASTRootNode n = new Parser(sql).parse().init();
Type listType = new TypeToken<List<Integer>>() {
}.getType();
ParameterContext ctx = getParameterContext(Lists.newArrayList(String.class, listType, String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "id");
context.addParameter("2", Arrays.asList(9, 5, 2, 7));
context.addParameter("3", "ash");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select id from user where id in (?,?,?,?) and name=?"));
assertThat(boundSql.getArgs(), contains(new Object[]{9, 5, 2, 7, "ash"}));
}
@Test
public void testIf() throws Exception {
String sql = "select where 1=1 #if(:1) and id>:1 #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", 100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id>? "));
assertThat(boundSql.getArgs(), contains(new Object[]{100}));
}
@Test
public void testIf2() throws Exception {
String sql = "select where 1=1 #if(!:1) and id>:1 #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", 100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 "));
assertThat(boundSql.getArgs().size(), equalTo(0));
}
@Test
public void testIfElseIf() throws Exception {
String sql = "select where 1=1" +
"#if(:1>0)" +
" and id>:1" +
"#elseif(:1<0)" +
" and id<:1" +
"#end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", 100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id>?"));
assertThat(boundSql.getArgs(), contains(new Object[]{100}));
}
@Test
public void testIfElseIf2() throws Exception {
String sql = "select where 1=1" +
"#if(:1>0)" +
" and id>:1" +
"#elseif(:1<0)" +
" and id<:1" +
"#end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", -100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id<?"));
assertThat(boundSql.getArgs(), contains(new Object[]{-100}));
}
@Test
public void testIfElseIfElse() throws Exception {
String sql = "select where 1=1" +
"#if(:1>0)" +
" and id>:1" +
"#elseif(:1<0)" +
" and id<:1" +
"#else" +
" and id=:1" +
"#end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", 100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id>?"));
assertThat(boundSql.getArgs(), contains(new Object[]{100}));
}
@Test
public void testIfElseIfElse2() throws Exception {
String sql = "select where 1=1" +
"#if(:1>0)" +
" and id>:1" +
"#elseif(:1<0)" +
" and id<:1" +
"#else" +
" and id=:1" +
"#end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", -100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id<?"));
assertThat(boundSql.getArgs(), contains(new Object[]{-100}));
}
@Test
public void testIfElseIfElse3() throws Exception {
String sql = "select where 1=1" +
"#if(:1>0)" +
" and id>:1" +
"#elseif(:1<0)" +
" and id<:1" +
"#else" +
" and id=:1" +
"#end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", 0);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id=?"));
assertThat(boundSql.getArgs(), contains(new Object[]{0}));
}
@Test
public void testExpression() throws Exception {
String sql = "select where 1=1 #if(:1==false && :2!=null && :3==true) and id>10 #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Boolean.class,
Object.class, Boolean.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", false);
context.addParameter("2", new Object());
context.addParameter("3", true);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("select where 1=1 and id>10 "));
}
@Test
public void testParse() throws Exception {
String sql = "SELECT * from user where id in ( select id from user2 )";
ASTRootNode n = new Parser(sql).parse().init();
InvocationContext context = DefaultInvocationContext.create();
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("SELECT * from user where id in ( select id from user2 )"));
}
@Test
public void testIntegerLiteral() throws Exception {
String sql = "select #if (:1 > 9223372036854775800) ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", Long.MAX_VALUE);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select ok "));
}
@Test
public void testIntegerLiteral2() throws Exception {
String sql = "select #if (:1 > 10) ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", Long.MAX_VALUE);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select ok "));
}
@Test
public void testIntegerLiteral3() throws Exception {
String sql = "select #if (:1 > 9223372036854775800) ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) Integer.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", 100);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select "));
}
@Test
public void testReplace() throws Exception {
String sql = "replace xxx into replace xxx";
ASTRootNode n = new Parser(sql).parse().init();
List<Type> types = Lists.newArrayList();
ParameterContext ctx = getParameterContext(types);
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("replace xxx into replace xxx"));
assertThat(n.getSQLType(), is(SQLType.REPLACE));
}
@Test
public void testMerge() throws Exception {
String sql = "merge xxx into merge xxx";
ASTRootNode n = new Parser(sql).parse().init();
List<Type> types = Lists.newArrayList();
ParameterContext ctx = getParameterContext(types);
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("merge xxx into merge xxx"));
assertThat(n.getSQLType(), is(SQLType.MERGE));
}
@Test
public void testStringLiteral() throws Exception {
String sql = "select #if (:1 == 'hello') ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "hello");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select ok "));
}
@Test
public void testStringLiteral2() throws Exception {
String sql = "select #if (:1 == 'hello') ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "hello2");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select "));
}
@Test
public void testStringLiteral3() throws Exception {
String sql = "select #if ('') ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "hello2");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select "));
}
@Test
public void testStringLiteral4() throws Exception {
String sql = "select #if (!'') ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "hello2");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select ok "));
}
@Test
public void testStringLiteral5() throws Exception {
String sql = "select #if (:1) ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "he");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select ok "));
}
@Test
public void testStringLiteral6() throws Exception {
String sql = "select #if (:1) ok #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList((Type) String.class));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
context.addParameter("1", "");
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select "));
}
@Test
public void testQuote() throws Exception {
String sql = "insert into table ... values(':dd',':xx')";
ASTRootNode n = new Parser(sql).parse().init();
List<Type> types = Lists.newArrayList();
ParameterContext ctx = getParameterContext(types);
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql().toString(), equalTo("insert into table ... values(':dd',':xx')"));
assertThat(boundSql.getArgs(), hasSize(0));
}
@Test
public void testExpressionParameter4In() throws Exception {
String sql = "select #if (:1) id in (:1) #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList(new TypeToken<List<Integer>>(){}.getType()));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
List<Integer> ids = Lists.newArrayList(1, 2, 3);
context.addParameter("1", ids);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select id in (?,?,?) "));
}
@Test
public void testExpressionParameter4InEmpty() throws Exception {
String sql = "select #if (:1) id in (:1) #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList(new TypeToken<List<Integer>>(){}.getType()));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
List<Integer> ids = Lists.newArrayList();
context.addParameter("1", ids);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select "));
}
@Test
public void testExpressionParameter4InNull() throws Exception {
String sql = "select #if (:1) id in (:1) #end";
ASTRootNode n = new Parser(sql).parse().init();
ParameterContext ctx = getParameterContext(Lists.newArrayList(new TypeToken<List<Integer>>(){}.getType()));
n.checkAndBind(ctx);
InvocationContext context = DefaultInvocationContext.create();
List<Integer> ids = null;
context.addParameter("1", ids);
n.render(context);
BoundSql boundSql = context.getBoundSql();
assertThat(boundSql.getSql(), Matchers.equalTo("select "));
}
@Test
public void testJdbcType() throws Exception {
String sql = "insert into table ... values(:1.b.c@blob) a in (:2.x.y@clob)";
ASTRootNode n = new Parser(sql).parse().init();
final AtomicInteger t = new AtomicInteger(0);
n.jjtAccept(new ParserVisitorAdapter() {
@Override
public Object visit(ASTJDBCParameter node, Object data) {
BindingParameter bp = node.getBindingParameter();
assertThat(bp.getParameterName(), equalTo("1"));
assertThat(bp.getPropertyPath(), equalTo("b.c"));
assertThat(bp.getJdbcType(), equalTo(JdbcType.BLOB));
t.incrementAndGet();
return super.visit(node, data);
}
@Override
public Object visit(ASTJDBCIterableParameter node, Object data) {
BindingParameter bp = node.getBindingParameter();
assertThat(bp.getParameterName(), equalTo("2"));
assertThat(bp.getPropertyPath(), equalTo("x.y"));
assertThat(bp.getJdbcType(), equalTo(JdbcType.CLOB));
t.incrementAndGet();
return super.visit(node, data);
}
}, null);
assertThat(t.intValue(), equalTo(2));
}
private ParameterContext getParameterContext(List<Type> types) {
List<Annotation> empty = Collections.emptyList();
List<ParameterDescriptor> pds = Lists.newArrayList();
int pos = 0;
for (Type type : types) {
ParameterDescriptor pd = ParameterDescriptor.create(pos++, type, empty, String.valueOf(pos));
pds.add(pd);
}
ParameterContext ctx = DefaultParameterContext.create(pds);
return ctx;
}
}