先说结论

SQL查询的WHERE语句是可以通过对象生成的


接着论证

  • 先定义这样一个对象, 假设作如下赋值
@Getter
@Setter
@Table(name = "t_user")
public class UserQuery {
     private Integer pageNumber;                // 3
     private Integer pageSize;                  // 10
     private String sort;                       // id,desc;create_time,asc

     private String usernameOrEmailOrMobile;    // admin
     private String nicknameLike;               // 管理员
     private Boolean valid;                     // true
 }
  • 对于usernameOrEmailOrMobile,按Or拆开后分别接上" = ?",再用" OR "拼接,得到
username = ? OR email = ? OR mobile = ?
  • 对于nicknameLike,去掉后缀Like,拼接" LIKE ?",得到
nickame LIKE ?
  • 对于valid,字段名加上"= ?"得到
valid = ?
  • 将上述3条语句用" AND "拼接,含OR的语句加括号,再在前面加上"WHERE",得到
WHERE (username = ? OR email = ? OR mobile = ?) AND nickname LIKE ? AND valid = ?
  • 对于sort字段,逗号替换为空格,分号替换为逗号,前面加上"ORDER BY ",得到
ORDER BY id DESC, createTime ASC
  • 将pageNumber和pageSize的值代入LIMIT ${pageSize} OFFSET ${(pageNumber - 1) * pageSize},得到
LIMIT 10 OFFSET 20
  • 将上述SELECT, WHERE, ORDER BY, LIMIT语句合并,得到
WHERE (username = ? OR email = ? OR mobile = ?) AND nickname LIKE ? AND valid = ?
ORDER BY id DESC, createTime ASC
LIMIT 10 OFFSET 20
  • 同时得到对应的参数列表
["admin", "admin", "admin", "%管理员%", true]

其中WHERE语句的过滤条件根据对应字段是否赋值来决定是否拼接

  • 再从@Table注解里得到表名,代入SELECT * FROM [TABLE],得到
SELECT * FROM t_user
  • 再同上述WHERE语句拼接,即可得到一条完整的查询语句
SELECT * FROM t_user
WHERE (username = ? OR email = ? OR mobile = ?) AND nickname LIKE ? AND valid = ?
ORDER BY id DESC, createTime ASC
LIMIT 10 OFFSET 20

证毕。


扩展

每条SELECT语句都需要支持分页和排序,所以可以将pageNumber,pageSize,sort提取为父类

public class PageQuery {
    private Integer pageNumber;
    private Integer pageSize;
    private String sort;
}

@Table(name = "t_user")
public class UserQuery extends PageQuery {
    private String usernameOrEmailOrMobile;
    private String nicknameLike;
    private Boolean valid;
}

查询构造器QueryBuilder

基于上述分析,我们就可以编写出测试用例,通过测试用例驱动出一个自动化的查询语句构造器


单元测试用例

    @Test
    public void buildSelect() {
        TestQuery testQuery = TestQuery.builder().build();
        assertEquals("SELECT * FROM user", testQueryBuilder.buildSelectAndArgs(testQuery, argList));
    }
    @Test
    public void buildSelectWithWhere() {
        TestQuery testQuery = TestQuery.builder().username("test").build();
        assertEquals("SELECT * FROM user WHERE username = ?", testQueryBuilder.buildSelectAndArgs(testQuery, argList));
    }
    @Test
    public void buildSelectWithWhereAndPage() {
        TestQuery testQuery = TestQuery.builder().username("test").build();
        testQuery.setPageNumber(3).setPageSize(10);
        assertEquals("SELECT * FROM user WHERE username = ? LIMIT 10 OFFSET 30",
                     testQueryBuilder.buildSelectAndArgs(testQuery, argList));
    }
    @Test
    public void buildSelectWithArgs() {
        argList = new ArrayList<>();
        TestQuery testQuery = TestQuery.builder().username("test").build();
        assertEquals("SELECT * FROM user WHERE username = ?",
                     testQueryBuilder.buildSelectAndArgs(testQuery, argList));
        assertEquals(1, argList.size());
        assertEquals("test", argList.get(0));
    }

Github地址

doyto-query