C++ SQL语句构建器的实现[与mybatis3使用方式一致]

目录

    • 一:简介
    • 二:实现
    • 三:使用示例

一:简介

1:有时候我们需要动态生成SQL语句,我们当然可以在代码中直接写出那条SQL语句,然而令人头疼的是对于SQL语句的各种换行格式化逗号ANDOR的处理,都是很容易出错的,对此,需要有一个更加智能的方式方便我们编写SQL语句。
2:MyBatis提供了一个好用的工具类帮助我们解决这个问题,其文档地址为:
Mybatis SQL 语句构建器
本文仿造Mybatis,模仿实现了一个基于C++语言版的SQL语句构建器

二:实现

首先需要一个拼接SQL语句的类

SQLStatement.hpp


#include 
#include 
#include 

/**
 * 封装SQL句
 */
class SQLStatement {
    friend class SQLBuilder;

private:
    const std::string AND = ") AND (";
    const std::string OR = ") OR (";

    /**
     * 语句类型:增删改查
     */
    enum class StatementType {
        DELETE, INSERT, SELECT, UPDATE
    } statementType;

    std::vector<std::string> sets;
    std::vector<std::string> select;
    std::vector<std::string> tables;
    std::vector<std::string> join;
    std::vector<std::string> innerJoin;
    std::vector<std::string> outerJoin;
    std::vector<std::string> leftOuterJoin;
    std::vector<std::string> rightOuterJoin;
    std::vector<std::string> where;
    std::vector<std::string> having;
    std::vector<std::string> groupBy;
    std::vector<std::string> orderBy;
    std::vector<std::string> *lastList = nullptr;
    std::vector<std::string> columns;
    std::vector<std::vector<std::string>> valuesList;//插入
    bool distinct = false;
    std::string offset;
    std::string limit;
public:
    SQLStatement() {
        //初始化,插入值有一行
        valuesList.resize(1);
    }

private:
    void sqlClause(std::string &builder, const std::string &keyword, const std::vector<std::string> &parts,
                   const std::string &open, const std::string &close, const std::string &conjunction) {
        if (parts.empty()) {
            return;
        }
        if (!builder.empty()) {
            builder.append(" ");
        }
        builder.append(keyword);
        builder.append(" ");
        builder.append(open);
        std::string last = "";
        for (int i = 0, n = parts.size(); i < n; i++) {
            std::string part = parts.at(i);
            if (i > 0 && part != AND && part != OR && last != AND && last != OR) {
                builder.append(conjunction);
            }
            builder.append(part);
            last = part;
        }
        builder.append(close);
    }

    void deleteSQL(std::string &builder) {
        sqlClause(builder, "DELETE FROM", tables, "", "", "");
        sqlClause(builder, "WHERE", where, "(", ")", " AND ");
        appendLimitClause(builder, "", limit);
    }

    void updateSQL(std::string &builder) {
        sqlClause(builder, "UPDATE", tables, "", "", "");
        joins(builder);
        sqlClause(builder, "SET", sets, "", "", ", ");
        sqlClause(builder, "WHERE", where, "(", ")", " AND ");
        appendLimitClause(builder, "", limit);
    }

    void insertSQL(std::string &builder) {
        sqlClause(builder, "INSERT INTO", tables, "", "", "");
        sqlClause(builder, "", columns, "(", ")", ", ");
        for (int i = 0; i < valuesList.size(); i++) {
            sqlClause(builder, i > 0 ? "," : "VALUES", valuesList.at(i), "(", ")", ", ");
        }
    }

    void joins(std::string &builder) {
        sqlClause(builder, "JOIN", join, "", "", " JOIN ");
        sqlClause(builder, "INNER JOIN", innerJoin, "", "", " INNER JOIN ");
        sqlClause(builder, "OUTER JOIN", outerJoin, "", "", " OUTER JOIN ");
        sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", " LEFT OUTER JOIN ");
        sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", " RIGHT OUTER JOIN ");
    }

    void appendLimitClause(std::string &builder, const std::string &offset, const std::string &limit) {
        if (!limit.empty()) {
            builder.append(" LIMIT ").append(limit);
        }
        if (!offset.empty()) {
            builder.append(" OFFSET ").append(offset);
        }
    }

    void selectSQL(std::string &builder) {
        if (distinct) {
            sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");
        } else {
            sqlClause(builder, "SELECT", select, "", "", ", ");
        }

        sqlClause(builder, "FROM", tables, "", "", ", ");
        joins(builder);
        sqlClause(builder, "WHERE", where, "(", ")", " AND ");
        sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
        sqlClause(builder, "HAVING", having, "(", ")", " AND ");
        sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
        appendLimitClause(builder, offset, limit);
    }

private:
    std::string sql() {
        std::string answer;
        switch (statementType) {
            case StatementType::DELETE:
                deleteSQL(answer);
                break;
            case StatementType::INSERT:
                insertSQL(answer);
                break;
            case StatementType::SELECT:
                selectSQL(answer);
                break;
            case StatementType::UPDATE:
                updateSQL(answer);
                break;
            default:
                answer = "";
        }
        return answer;
    }

};

SQL构建器接口实现

SQLBuilder.hpp


#include 
#include "SQLStatement.hpp"

/**
 * sql语句构建器
 */
class SQLBuilder {
private:
    SQLStatement sql;

public:
    SQLBuilder &UPDATE(const std::string &table) {
        sql.statementType = SQLStatement::StatementType::UPDATE;
        sql.tables.emplace_back(table);
        return *this;
    }

    SQLBuilder &SET(const std::string &sets) {
        sql.sets.emplace_back(sets);
        return *this;
    }

    SQLBuilder &INSERT_INTO(const std::string &tableName) {
        sql.statementType = SQLStatement::StatementType::INSERT;
        sql.tables.emplace_back(tableName);
        return *this;
    }

    SQLBuilder &VALUES(const std::string &columns, const std::string &values) {
        INTO_COLUMNS(columns);
        INTO_VALUES(values);
        return *this;
    }

    SQLBuilder &INTO_COLUMNS(const std::string &columns) {
        sql.columns.emplace_back(columns);
        return *this;
    }

    SQLBuilder &INTO_VALUES(const std::string &values) {
        sql.valuesList.back().emplace_back(values);
        return *this;
    }

    SQLBuilder &SELECT(const std::string &columns) {
        sql.statementType = SQLStatement::StatementType::SELECT;
        sql.select.emplace_back(columns);
        return *this;
    }

    SQLBuilder &SELECT_DISTINCT(const std::string &columns) {
        sql.distinct = true;
        return SELECT(columns);
    }

    SQLBuilder &DELETE_FROM(const std::string &table) {
        sql.statementType = SQLStatement::StatementType::DELETE;
        sql.tables.emplace_back(table);
        return *this;
    }

    SQLBuilder &FROM(const std::string &table) {
        sql.tables.emplace_back(table);
        return *this;
    }

    SQLBuilder &JOIN(const std::string &join) {
        sql.join.emplace_back(join);
        return *this;
    }

    SQLBuilder &INNER_JOIN(const std::string &join) {
        sql.innerJoin.emplace_back(join);
        return *this;
    }

    SQLBuilder &LEFT_OUTER_JOIN(const std::string &join) {
        sql.leftOuterJoin.emplace_back(join);
        return *this;
    }

    SQLBuilder &RIGHT_OUTER_JOIN(const std::string &join) {
        sql.rightOuterJoin.emplace_back(join);
        return *this;
    }

    SQLBuilder &OUTER_JOIN(const std::string &join) {
        sql.outerJoin.emplace_back(join);
        return *this;
    }

    SQLBuilder &WHERE(const std::string &conditions) {
        sql.where.emplace_back(conditions);
        sql.lastList = &sql.where;
        return *this;
    }

    SQLBuilder &OR() {
        sql.lastList->emplace_back(sql.OR);
        return *this;
    }

    SQLBuilder &AND() {
        sql.lastList->emplace_back(sql.AND);
        return *this;
    }

    SQLBuilder &GROUP_BY(const std::string &columns) {
        sql.groupBy.emplace_back(columns);
        return *this;
    }

    SQLBuilder &HAVING(const std::string &conditions) {
        sql.having.emplace_back(conditions);
        sql.lastList = &sql.having;
        return *this;
    }

    SQLBuilder &ORDER_BY(const std::string &columns) {
        sql.orderBy.emplace_back(columns);
        return *this;
    }

    SQLBuilder &LIMIT(const std::string &variable, const std::string &offset) {
        sql.limit = variable;
        sql.offset = offset;
        return *this;
    }

    SQLBuilder &LIMIT(const std::string &variable) {
        sql.limit = variable;
        sql.offset = std::to_string(0);
        return *this;
    }

    /**
     * 批量插入时,多插入一行
     * @return
     */
    SQLBuilder &ADD_ROW() {
        sql.valuesList.resize(sql.valuesList.size() + 1);
        return *this;
    }

    std::string toString() {
        return sql.sql();
    }

};

三:使用示例

#include "SQLBuilder.hpp"

int main() {
    auto sql1 = SQLBuilder()
            .SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME")
            .SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON")
            .FROM("PERSON P")
            .FROM("ACCOUNT A")
            .INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID")
            .INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID")
            .WHERE("P.ID = A.ID")
            .WHERE("P.FIRST_NAME like ?")
            .OR()
            .WHERE("P.LAST_NAME like ?")
            .GROUP_BY("P.ID")
            .HAVING("P.LAST_NAME like ?")
            .OR()
            .HAVING("P.FIRST_NAME like ?")
            .ORDER_BY("P.ID")
            .ORDER_BY("P.FULL_NAME")
            .LIMIT("?", "?")
            .toString();

    auto sql2 = SQLBuilder()
            .INSERT_INTO("PERSON")
            .VALUES("ID, FIRST_NAME", "?, ?")
            .VALUES("LAST_NAME", "?")
            .toString();

    auto sql3 = SQLBuilder()
            .INSERT_INTO("TABLE_A")
            .INTO_COLUMNS("a,b,c,d")
            .INTO_VALUES("1,2,3,4")
            .ADD_ROW()
            .INTO_VALUES("5,6")
            .INTO_VALUES("7,8")
            .toString();

    auto sql4 = SQLBuilder()
            .DELETE_FROM("PERSON")
            .WHERE("id=?")
            .LIMIT("20")
            .toString();
    auto sql5 = SQLBuilder()
            .UPDATE("PERSON")
            .SET("name=?")
            .WHERE("id=10")
            .toString();
   return 0;
}

你可能感兴趣的:(C++,Java)