From 2f343a324918bdf8350ae7ca03815c12749ffb44 Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Thu, 14 Mar 2019 20:53:58 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/CMakeLists.txt => CMakeLists.txt | 18 +- adapter.hpp | 35 +++ col.hpp | 317 ++++++++++++++++++++++++++ delete_model.hpp | 91 ++++++++ insert_model.hpp | 169 ++++++++++++++ model.hpp | 96 ++++++++ select_model.hpp | 243 ++++++++++++++++++++ sql.h | 283 ++++++----------------- test/test.cpp | 77 +++---- update_model.hpp | 108 +++++++++ 10 files changed, 1175 insertions(+), 262 deletions(-) rename test/CMakeLists.txt => CMakeLists.txt (50%) create mode 100644 adapter.hpp create mode 100644 col.hpp create mode 100644 delete_model.hpp create mode 100644 insert_model.hpp create mode 100644 model.hpp create mode 100644 select_model.hpp create mode 100644 update_model.hpp diff --git a/test/CMakeLists.txt b/CMakeLists.txt similarity index 50% rename from test/CMakeLists.txt rename to CMakeLists.txt index fcbefab..8112617 100644 --- a/test/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,19 +4,27 @@ set(CMAKE_MACOSX_RPATH 0) project(sql-builder) -set(DEBUG_FLAGS "-std=c++11 -g -O1 -Wall -Wextra -pedantic") -set(RELEASE_FLAGS "-std=c++11 -O3 -Wall -Wextra -pedantic") +# set(DEBUG_FLAGS "-std=c++11 -g -O1 -Wall -Wextra -pedantic") +# set(RELEASE_FLAGS "-std=c++11 -O3 -Wall -Wextra -pedantic") set(CMAKE_CXX_FLAGS ${RELEASE_FLAGS}) set(CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS}) set(CMAKE_CONFIGURATION_TYPES Debug Release) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) -include_directories(sql-test "../") +include_directories(.) + +set(SQL_TEST_SRC test/test.cpp + adapter.hpp + col.hpp + insert_model.hpp + delete_model.hpp + model.hpp + select_model.hpp + update_model.hpp) -set(SQL_TEST_SRC test.cpp) add_executable(sql-test ${SQL_TEST_SRC}) add_test(all "sql-test") -enable_testing() +enable_testing() \ No newline at end of file diff --git a/adapter.hpp b/adapter.hpp new file mode 100644 index 0000000..25efa8d --- /dev/null +++ b/adapter.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace boosql { + +class adapter : public std::enable_shared_from_this +{ +public: + virtual std::string quote_value(const std::string & value) = 0; + virtual std::string quote_field(const std::string & field) = 0; + virtual std::string placeholder() = 0; +}; + +class sqlite_adapter : public adapter +{ +public: + std::string quote_value(const std::string & value) override + { + return "'" + value + "'"; + } + + std::string quote_field(const std::string & field) override + { + return "\"" + field + "\""; + } + + std::string placeholder() override + { + return "?"; + } +}; + +} \ No newline at end of file diff --git a/col.hpp b/col.hpp new file mode 100644 index 0000000..05072d1 --- /dev/null +++ b/col.hpp @@ -0,0 +1,317 @@ +#pragma once + +#include +#include +#include "adapter.hpp" + +namespace boosql +{ + +using namespace std; + +class col +{ + typedef enum {field, value, other} witch; + + struct item { + public: + witch type; + string val; + }; + +public: + col(const string & c) + { + if (c != "") { + _items.push_back(item{ field, c }); + } + } + + col(const string & c, bool with_quote_begin) + { + quote_begin(); + if (c != "") { + _items.push_back(item{field, c}); + } + } + + virtual ~col() {} + + col& as(const string& s) + { + _items.push_back(item{other, "AS " + s}); + return *this; + } + + col& is_null() { + _items.push_back(item{other, "IS NULL"}); + return *this; + } + + col& is_not_null() { + _items.push_back(item{other, "IS NOT NULL"}); + return *this; + } + + template + col& in(const vector& args) { + return in_or_not(args, "IN"); + } + + template + col& not_in(const vector& args) { + return in_or_not(args, "NOT IN"); + } + + template + col & in_or_not(const vector& args, string in) + { + size_t size = args.size(); + if(size == 1) { + _items.push_back(item{other, "="}); + ostringstream str; + str << args[0]; + _items.push_back(item{value, str.str()}); + } else { + _items.push_back(item{other, in + " ("}); + for(size_t i = 0; i < size; ++i) { + ostringstream str; + str << args[i]; + _items.push_back(item{value, str.str()}); + if(i < size - 1) { + _items.push_back(item{other, ","}); + } + } + _items.push_back(item{other, ")"}); + } + return *this; + } + + col & and() + { + _items.push_back(item{other, "AND"}); + return *this; + } + + col & or() + { + _items.push_back(item{other, "OR"}); + return *this; + } + + col & quote_begin() + { + _items.push_back(item{other, "("}); + return *this; + } + + col & quote_end() + { + _items.push_back(item{other, ")"}); + return *this; + } + + col& operator ()(const string & any) + { + _items.push_back(item{other, any}); + return *this; + } + + template + col & val(const T& data) + { + ostringstream str; + str << data; + _items.push_back(item{value, str.str()}); + + return *this; + } + + template + col & val(const vector &data) + { + for (auto i = data.begin(); i != data.end(); ++i) { + ostringstream str; + str << *i; + _items.push_back(item{value, str.str()}); + } + + return *this; + } + + col& operator &&(col & condition) + { + and(); + merge(condition); + + return *this; + } + + col& operator ||(col& condition) + { + or (); + merge(condition); + + return *this; + } + + void merge(col & condition) + { + for (auto i = condition._items.begin(); i != condition._items.end(); ++i) { + _items.push_back(*i); + } + } + + col& operator &&(const string& condition) + { + quote_begin(); + _items.push_back(item{other, condition}); + quote_end(); + + return *this; + } + + col& operator ||(const string& condition) { + quote_begin(); + _items.push_back(item{other, condition}); + quote_end(); + + return *this; + } + + col& operator &&(const char* condition) { + return operator &&(string(condition)); + } + + col& operator ||(const char* condition) { + return operator ||(string(condition)); + } + + col& operator [] (const char * data) { + return with_operator(data, "LIKE"); + } + + col& operator [] (const string & data) { + return with_operator(data, "LIKE"); + } + + col & escape(const string & data) { + _items.push_back(item{other, "{ ESCAPE "}); + _items.push_back(item{value, data}); + _items.push_back(item{other, "}"}); + + return *this; + } + + template + col& operator ==(const T& data) { + return with_operator(data, "="); + } + + template + col& operator !=(const T& data) { + return with_operator(data, "!="); + } + + template + col& operator >=(const T& data) { + return with_operator(data, ">="); + } + + template + col& operator <=(const T& data) { + return with_operator(data, "<="); + } + + template + col& operator >(const T& data) { + return with_operator(data, ">"); + } + + template + col& operator <(const T& data) { + return with_operator(data, "<"); + } + + template + col & with_operator(const T & data, const string & oper) + { + ostringstream str; + str << data; + _items.push_back(item{other, oper}); + _items.push_back(item{value, str.str()}); + + return *this; + } + + string str(adapter * adapter) const + { + return str(adapter, ""); + } + + string str(adapter * adapter, vector & params) const + { + return str(adapter, "", params); + } + + string str(adapter * adapter, string table_name) const { + string ret = ""; + string pre_col = ""; + if (table_name != "") { + pre_col = adapter->quote_field(table_name) + "."; + } + for(auto i = _items.begin(); i != _items.end(); ++i) { + auto it = *i; + switch(it.type) { + case field: + ret += pre_col + adapter->quote_field(it.val); + break; + case value: + ret += adapter->quote_value(it.val); + break; + case other: + ret += " " + it.val + " "; + } + } + + return ret; + } + + string str(adapter * adapter, string table_name, vector & params) const + { + string ret = ""; + string pre_col = ""; + if (table_name != "") { + pre_col = adapter->quote_field(table_name) + "."; + } + for(auto i = _items.begin(); i != _items.end(); ++i) { + auto it = *i; + switch(it.type) { + case field: + ret += pre_col + adapter->quote_field(it.val); + break; + case value: + ret += adapter->placeholder(); + params.push_back(it.val); + break; + case other: + ret += " " + it.val + " "; + } + } + + return ret; + } + + static col pre_quote(const string & c) + { + return col(c, true); + } + + operator bool() { + return true; + } +private: + vector _items; +}; + +} \ No newline at end of file diff --git a/delete_model.hpp b/delete_model.hpp new file mode 100644 index 0000000..0c812c0 --- /dev/null +++ b/delete_model.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include "model.hpp" + +#include + +namespace boosql { + +using namespace std; + +class delete_model : public model +{ +public: + delete_model(shared_ptr adapter) : model(adapter) {} + + virtual ~delete_model() {} + + delete_model& from(const std::string& table_name) { + _table_name = table_name; + return *this; + } + + delete_model& and_where(const string & condition) + { + model::and_where(condition); + return *this; + } + + delete_model& and_where(const col & condition) + { + model::and_where(condition); + return *this; + } + + delete_model& or_where(const string & condition) + { + model::or_where(condition); + return *this; + } + + delete_model& or_where(const col & condition) + { + model::or_where(condition); + return *this; + } + + delete_model& quote(std::function callback) + { + model::quote(callback, *this); + return *this; + } + + delete_model& where(const string& condition) { + model::where(condition); + return *this; + } + + delete_model& where(const col& condition) { + model::where(condition); + return *this; + } + + const string & table_name() + { + return _table_name; + } + + virtual const string& str() override { + _sql.clear(); + _sql.append("DELETE FROM "); + _sql.append(_adapter->quote_field(_table_name)); + _sql.append(where_str()); + + return _sql; + } + + delete_model& reset() { + _table_name.clear(); + model::reset(); + return *this; + } + friend inline std::ostream& operator<< (std::ostream& out, delete_model& mod) { + out << mod.str(); + return out; + } + +protected: + std::string _table_name; +}; + +} \ No newline at end of file diff --git a/insert_model.hpp b/insert_model.hpp new file mode 100644 index 0000000..01dcef4 --- /dev/null +++ b/insert_model.hpp @@ -0,0 +1,169 @@ +#pragma once + +#include "model.hpp" + +#include + +namespace boosql +{ + +class insert_model : public model +{ + class row_interface { + public: + virtual const string & fields(adapter *, const string &) = 0; + virtual const string & values(adapter *) = 0; + }; + + class row : public row_interface { + public: + row(insert_model & model): _model(model) {} + + template + row& insert(const std::string& c, const T& data) { + ostringstream str; + str << data; + _data[c] = str.str(); + return *this; + } + + template + row& operator()(const std::string& c, const T& data) { + return insert(c, data); + } + + insert_model & next_row() { + return _model; + } + + const string & fields(adapter * adapter, const string & table_name) override + { + if (_fields != "") { + return _fields; + } + _fields = "("; + auto size = _data.size(); + int count = 0; + for (auto i = _data.begin(); i != _data.end(); ++i) { + count++; + _fields.append(col(i->first).str(adapter, table_name)); + if (count < size) { + _fields.append(", "); + } + } + + _fields.append(")"); + + return _fields; + } + + const string & values(adapter * adapter) override + { + if (_values != "") { + return _values; + } + _values = "("; + auto size = _data.size(); + int count = 0; + for (auto i = _data.begin(); i != _data.end(); ++i) { + count++; + _values.append(adapter->quote_value(i->second)); + if (count < size) { + _values.append(", "); + } + } + + _values.append(")"); + + return _values; + } + + private: + insert_model & _model; + map _data; + string _fields; + string _values; + }; + +public: + insert_model(shared_ptr adapter) : model(adapter) {} + virtual ~insert_model() + { + auto i = _rows.begin(); + while (i != _rows.end()) { + delete *i; + _rows.erase(i); + i = _rows.begin(); + } + } + + row & next_row() { + auto r = new row(*this); + _rows.push_back(r); + return *r; + } + + template + row& operator()(const std::string& c, const T& data) { + return next_row()(c, data); + } + + insert_model& into(const std::string& table_name) { + _table_name = table_name; + return *this; + } + + insert_model& replace(bool var) { + _replace = var; + return *this; + } + + const string & table_name() override + { + return _table_name; + } + + const string& str() override { + _sql.clear(); + if (_replace) { + _sql.append("INSERT INTO OR REPLACE INFO "); + }else { + _sql.append("INSERT INTO "); + } + _sql.append(_adapter->quote_field(_table_name)); + auto size = _rows.size(); + int count = 0; + for (auto i = _rows.begin(); i != _rows.end(); ++i) { + count++; + if (count == 1) { + _sql.append((*i)->fields(_adapter.get(), _table_name)); + _sql.append(" VALUES"); + } + _sql.append((*i)->values(_adapter.get())); + if (count < size) { + _sql.append(", "); + } + } + + return _sql; + } + + insert_model& reset() { + _table_name.clear(); + _rows.clear(); + return *this; + } + + friend inline std::ostream& operator << (std::ostream& out, insert_model& mod) { + out << mod.str(); + return out; + } + +protected: + bool _replace = false; + string _table_name; + + vector _rows; +}; + +} \ No newline at end of file diff --git a/model.hpp b/model.hpp new file mode 100644 index 0000000..fba725e --- /dev/null +++ b/model.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include "adapter.hpp" +#include "col.hpp" + +#include +#include +#include + +namespace boosql +{ + +using namespace std; + +class model +{ +public: + model() { + auto adapter = make_shared(); + _adapter = adapter->shared_from_this(); + } + + model(shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} + + string where_str() + { + string ret; + auto size = _where_condition.size(); + if(size > 0) { + ret.append(" WHERE "); + for(size_t i = 0; i < size; ++i) { + ret.append(_where_condition[i].str(_adapter.get(), table_name())); + } + } + + return ret; + } + + virtual ~model() {} + + virtual const string & table_name() = 0; + virtual const std::string& str() = 0; + +protected: + void and_where(const string & condition) + { + _where_condition.push_back(col("").and()); + where(condition); + } + void and_where(const col & condition) + { + _where_condition.push_back(col("").and()); + where(condition); + } + void or_where(const string & condition) + { + _where_condition.push_back(col("").or()); + where(condition); + } + void or_where(const col & condition) + { + _where_condition.push_back(col("").or()); + where(condition); + } + template + void quote(std::function callback, T& model) + { + _where_condition.push_back(col("").and()); + _where_condition.push_back(col("").quote_begin()); + callback(model); + _where_condition.push_back(col("").quote_end()); + } + void where(const string& condition) { + _where_condition.push_back(col("")(condition)); + } + void where(const col& condition) { + _where_condition.push_back(condition); + } + void reset() + { + _where_condition.clear(); + } + +private: + model(const model& m) = delete; + model& operator =(const model& data) = delete; + +private: + vector _where_condition; + +protected: + std::string _sql; + shared_ptr _adapter; +}; + +} \ No newline at end of file diff --git a/select_model.hpp b/select_model.hpp new file mode 100644 index 0000000..2ecffbe --- /dev/null +++ b/select_model.hpp @@ -0,0 +1,243 @@ +#pragma once + +#include +#include +#include + +#include "col.hpp" +#include "model.hpp" + +namespace boosql { + +using namespace std; + +class select_model : public model +{ +public: + select_model(shared_ptr adapter): model(adapter) {} + virtual ~select_model() {} + + template + select_model& select(const col& c, Args&&... columns) { + _select.push_back(c); + select(columns...); + return *this; + } + + // for recursion + select_model& select() { + return *this; + } + + select_model& from(const string& table_name) { + _table_name = table_name; + return *this; + } + + select_model& and_where(const string & condition) + { + model::and_where(condition); + return *this; + } + + select_model& and_where(const col & condition) + { + model::and_where(condition); + return *this; + } + + select_model& or_where(const string & condition) + { + model::or_where(condition); + return *this; + } + + select_model& or_where(const col & condition) + { + model::or_where(condition); + return *this; + } + + select_model& quote(std::function callback) + { + model::quote(callback, *this); + return *this; + } + + select_model& where(const string& condition) { + model::where(condition); + return *this; + } + + select_model& where(const col& condition) { + model::where(condition); + return *this; + } + + template + select_model& group_by(const col& c, Args&&...columns) { + _groupby_columns.push_back(c); + group_by(columns...); + return *this; + } + + // for recursion + select_model& group_by() { + return *this; + } + + select_model& having(const string& condition) { + _having_condition.push_back(col("")(condition)); + return *this; + } + + select_model& having(const col& condition) { + _having_condition.push_back(condition); + return *this; + } + + select_model& order_by(const col& order_by) { + _order_by.push_back(order_by); + return *this; + } + + template + select_model& limit(const T& limit) { + _limit = to_string(limit); + + return *this; + } + + select_model& page(const int& page, const int& page_size) { + offset((page - 1) * page_size); + limit(page_size); + return *this; + } + + template + select_model& offset(const T& offset) { + _offset = to_string(offset); + return *this; + } + + const string & table_name() + { + return _table_name; + } + + const string& str() override + { + _sql.clear(); + _sql.append("SELECT "); + _sql.append(select_str()); + _sql.append(" FROM "); + _sql.append(_table_name); + _sql.append(where_str()); + _sql.append(group_by_str()); + _sql.append(having_str()); + _sql.append(order_by_str()); + if(!_limit.empty()) { + _sql.append(" LIMIT "); + _sql.append(_limit); + } + if(!_offset.empty()) { + _sql.append(" OFFSET "); + _sql.append(_offset); + } + return _sql; + } + + string order_by_str() + { + string ret; + auto size = _order_by.size(); + if (size > 0) { + ret.append(" ORDER BY "); + for (size_t i = 0; i < size; ++i) { + ret.append(_order_by[i].str(_adapter.get(), _table_name)); + if(i < size - 1) { + _sql.append(", "); + } + } + } + + return ret; + } + + string having_str() + { + string ret; + auto size = _having_condition.size(); + if(size > 0) { + ret.append(" HAVING "); + for(size_t i = 0; i < size; ++i) { + ret.append(_having_condition[i].str(_adapter.get(), _table_name)); + if(i < size - 1) { + _sql.append(" "); + } + } + } + + return ret; + } + + string group_by_str() + { + string ret; + auto size = _groupby_columns.size(); + if(!_groupby_columns.empty()) { + ret.append(" GROUP BY "); + for(size_t i = 0; i < size; ++i) { + ret.append(_groupby_columns[i].str(_adapter.get(), _table_name)); + if(i < size - 1) { + ret.append(", "); + } + } + } + + return ret; + } + + + string select_str() + { + string ret = ""; + int count = 0; + for (auto i = _select.begin(); i != _select.end(); ++i) { + count++; + ret.append((*i).str(_adapter.get(), _table_name)); + if (count < _select.size()) { + ret.append(", "); + } + } + + return ret; + } + + select_model& reset() { + model::reset(); + _table_name.clear(); + _select.clear(); + _groupby_columns.clear(); + _having_condition.clear(); + _order_by.clear(); + _limit.clear(); + _offset.clear(); + return *this; + } + friend inline ostream& operator<< (ostream& out, select_model& mod) { + out< _select; + vector _groupby_columns; + vector _having_condition; + vector _order_by; + string _limit; + string _offset; +}; + +} \ No newline at end of file diff --git a/sql.h b/sql.h index 5a6e7a5..9f35386 100644 --- a/sql.h +++ b/sql.h @@ -1,10 +1,13 @@ #pragma once +#include #include #include #include -namespace sql { +namespace boosql { + + using namespace std; template inline std::string to_value(const T& data) { @@ -48,207 +51,55 @@ static std::string sql::to_value(const time_t& data) { } */ -class column +class sql_model { public: - column(const std::string& column) { - _cond = column; - } - virtual ~column() {} - - column& as(const std::string& s) { - _cond.append(" as "); - _cond.append(s); - return *this; - } - - column& is_null() { - _cond.append(" is null"); - return *this; - } - - column& is_not_null() { - _cond.append(" is not null"); - return *this; - } - - template - column& in(const std::vector& args) { - size_t size = args.size(); - if(size == 1) { - _cond.append(" = "); - _cond.append(to_value(args[0])); - } else { - _cond.append(" in ("); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _cond.append(to_value(args[i])); - _cond.append(", "); - } else { - _cond.append(to_value(args[i])); - } - } - _cond.append(")"); - } - return *this; - } - - template - column& not_in(const std::vector& args) { - size_t size = args.size(); - if(size == 1) { - _cond.append(" != "); - _cond.append(to_value(args[0])); - } else { - _cond.append(" not in ("); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _cond.append(to_value(args[i])); - _cond.append(", "); - } else { - _cond.append(to_value(args[i])); - } - } - _cond.append(")"); - } - return *this; - } - - column& operator &&(column& condition) { - std::string str("("); - str.append(_cond); - str.append(") and ("); - str.append(condition._cond); - str.append(")"); - condition._cond = str; - return condition; - } - - column& operator ||(column& condition) { - std::string str("("); - str.append(_cond); - str.append(") or ("); - str.append(condition._cond); - str.append(")"); - condition._cond = str; - return condition; - } - - column& operator &&(const std::string& condition) { - _cond.append(" and "); - _cond.append(condition); - return *this; - } - - column& operator ||(const std::string& condition) { - _cond.append(" or "); - _cond.append(condition); - return *this; - } - - column& operator &&(const char* condition) { - _cond.append(" and "); - _cond.append(condition); - return *this; - } - - column& operator ||(const char* condition) { - _cond.append(" or "); - _cond.append(condition); - return *this; - } - - template - column& operator ==(const T& data) { - _cond.append(" = "); - _cond.append(to_value(data)); - return *this; - } - - template - column& operator !=(const T& data) { - _cond.append(" != "); - _cond.append(to_value(data)); - return *this; - } - - template - column& operator >=(const T& data) { - _cond.append(" >= "); - _cond.append(to_value(data)); - return *this; + sql_model() { + auto adapter = make_shared(); + _adapter = adapter->shared_from_this(); } + sql_model(shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} - template - column& operator <=(const T& data) { - _cond.append(" <= "); - _cond.append(to_value(data)); - return *this; - } - - template - column& operator >(const T& data) { - _cond.append(" > "); - _cond.append(to_value(data)); - return *this; - } - - template - column& operator <(const T& data) { - _cond.append(" < "); - _cond.append(to_value(data)); - return *this; + column col(const string & col) + { + return column(_adapter->quote_field(col)); } - const std::string& str() const { - return _cond; - } - - operator bool() { - return true; - } -private: - std::string _cond; -}; - - -class SqlModel -{ -public: - SqlModel() {} - virtual ~SqlModel() {} + virtual ~sql_model() {} virtual const std::string& str() = 0; const std::string& last_sql() { return _sql; } private: - SqlModel(const SqlModel& m) = delete; - SqlModel& operator =(const SqlModel& data) = delete; + sql_model(const sql_model& m) = delete; + sql_model& operator =(const sql_model& data) = delete; + shared_ptr _adapter; + protected: std::string _sql; }; -class SelectModel : public SqlModel +class select_model : public sql_model { public: - SelectModel() {} - virtual ~SelectModel() {} + select_model() {} + virtual ~select_model() {} template - SelectModel& select(const std::string& str, Args&&... columns) { + select_model& select(const std::string& str, Args&&... columns) { _select_columns.push_back(str); select(columns...); return *this; } // for recursion - SelectModel& select() { + select_model& select() { return *this; } template - SelectModel& from(const std::string& table_name, Args&&... tables) { + select_model& from(const std::string& table_name, Args&&... tables) { if(_table_name.empty()) { _table_name = table_name; } else { @@ -260,60 +111,60 @@ class SelectModel : public SqlModel } // for recursion - SelectModel& from() { + select_model& from() { return *this; } - SelectModel& where(const std::string& condition) { + select_model& where(const std::string& condition) { _where_condition.push_back(condition); return *this; } - SelectModel& where(column& condition) { + select_model& where(column& condition) { _where_condition.push_back(condition.str()); return *this; } template - SelectModel& group_by(const std::string& str, Args&&...columns) { + select_model& group_by(const std::string& str, Args&&...columns) { _groupby_columns.push_back(str); group_by(columns...); return *this; } // for recursion - SelectModel& group_by() { + select_model& group_by() { return *this; } - SelectModel& having(const std::string& condition) { + select_model& having(const std::string& condition) { _having_condition.push_back(condition); return *this; } - SelectModel& having(column& condition) { + select_model& having(column& condition) { _having_condition.push_back(condition.str()); return *this; } - SelectModel& order_by(const std::string& order_by) { + select_model& order_by(const std::string& order_by) { _order_by = order_by; return *this; } template - SelectModel& limit(const T& limit) { + select_model& limit(const T& limit) { _limit = std::to_string(limit); return *this; } template - SelectModel& limit(const T& offset, const T& limit) { + select_model& limit(const T& offset, const T& limit) { _offset = std::to_string(offset); _limit = std::to_string(limit); return *this; } template - SelectModel& offset(const T& offset) { + select_model& offset(const T& offset) { _offset = std::to_string(offset); return *this; } @@ -383,7 +234,7 @@ class SelectModel : public SqlModel return _sql; } - SelectModel& reset() { + select_model& reset() { _table_name.clear(); _select_columns.clear(); _groupby_columns.clear(); @@ -394,7 +245,7 @@ class SelectModel : public SqlModel _offset.clear(); return *this; } - friend inline std::ostream& operator<< (std::ostream& out, SelectModel& mod) { + friend inline std::ostream& operator<< (std::ostream& out, select_model& mod) { out< - InsertModel& insert(const std::string& c, const T& data) { + insert_model& insert(const std::string& c, const T& data) { _columns.push_back(c); _values.push_back(to_value(data)); return *this; } template - InsertModel& operator()(const std::string& c, const T& data) { + insert_model& operator()(const std::string& c, const T& data) { return insert(c, data); } - InsertModel& into(const std::string& table_name) { + insert_model& into(const std::string& table_name) { _table_name = table_name; return *this; } - InsertModel& replace(bool var) { + insert_model& replace(bool var) { _replace = var; return *this; } @@ -471,14 +322,14 @@ class InsertModel : public SqlModel return _sql; } - InsertModel& reset() { + insert_model& reset() { _table_name.clear(); _columns.clear(); _values.clear(); return *this; } - friend inline std::ostream& operator<< (std::ostream& out, InsertModel& mod) { + friend inline std::ostream& operator<< (std::ostream& out, insert_model& mod) { out< -inline InsertModel& InsertModel::insert(const std::string& c, const std::nullptr_t&) { +inline insert_model& insert_model::insert(const std::string& c, const std::nullptr_t&) { _columns.push_back(c); _values.push_back("null"); return *this; } -class UpdateModel : public SqlModel +class update_model : public sql_model { public: - UpdateModel() {} - virtual ~UpdateModel() {} + update_model() {} + virtual ~update_model() {} - UpdateModel& update(const std::string& table_name) { + update_model& update(const std::string& table_name) { _table_name = table_name; return *this; } template - UpdateModel& set(const std::string& c, const T& data) { + update_model& set(const std::string& c, const T& data) { std::string str(c); str.append(" = "); str.append(to_value(data)); @@ -519,16 +370,16 @@ class UpdateModel : public SqlModel } template - UpdateModel& operator()(const std::string& c, const T& data) { + update_model& operator()(const std::string& c, const T& data) { return set(c, data); } - UpdateModel& where(const std::string& condition) { + update_model& where(const std::string& condition) { _where_condition.push_back(condition); return *this; } - UpdateModel& where(column& condition) { + update_model& where(column& condition) { _where_condition.push_back(condition.str()); return *this; } @@ -562,13 +413,13 @@ class UpdateModel : public SqlModel return _sql; } - UpdateModel& reset() { + update_model& reset() { _table_name.clear(); _set_columns.clear(); _where_condition.clear(); return *this; } - friend inline std::ostream& operator<< (std::ostream& out, UpdateModel& mod) { + friend inline std::ostream& operator<< (std::ostream& out, update_model& mod) { out< -inline UpdateModel& UpdateModel::set(const std::string& c, const std::nullptr_t&) { +inline update_model& update_model::set(const std::string& c, const std::nullptr_t&) { std::string str(c); str.append(" = null"); _set_columns.push_back(str); @@ -588,18 +439,18 @@ inline UpdateModel& UpdateModel::set(const std::string& c, const std::nullptr_t& } -class DeleteModel : public SqlModel +class delete_model : public sql_model { public: - DeleteModel() {} - virtual ~DeleteModel() {} + delete_model() {} + virtual ~delete_model() {} - DeleteModel& _delete() { + delete_model& _delete() { return *this; } template - DeleteModel& from(const std::string& table_name, Args&&... tables) { + delete_model& from(const std::string& table_name, Args&&... tables) { if(_table_name.empty()) { _table_name = table_name; } else { @@ -611,16 +462,16 @@ class DeleteModel : public SqlModel } // for recursion - DeleteModel& from() { + delete_model& from() { return *this; } - DeleteModel& where(const std::string& condition) { + delete_model& where(const std::string& condition) { _where_condition.push_back(condition); return *this; } - DeleteModel& where(column& condition) { + delete_model& where(column& condition) { _where_condition.push_back(condition.str()); return *this; } @@ -644,12 +495,12 @@ class DeleteModel : public SqlModel return _sql; } - DeleteModel& reset() { + delete_model& reset() { _table_name.clear(); _where_condition.clear(); return *this; } - friend inline std::ostream& operator<< (std::ostream& out, DeleteModel& mod) { + friend inline std::ostream& operator<< (std::ostream& out, delete_model& mod) { out< #include -#include "sql.h" +#include "col.hpp" +#include "select_model.hpp" +#include "update_model.hpp" +#include "delete_model.hpp" +#include "insert_model.hpp" +#include "adapter.hpp" /* @@ -17,49 +22,39 @@ create table if not exists user ( */ -using namespace sql; +using namespace boosql; int main() { - InsertModel i; - i.insert("score", 100) - ("name", std::string("six")) - ("age", (unsigned char)20) - ("address", "beijing") - ("create_time", nullptr) - .into("user"); - std::cout< 60 and (column("age") >= 20 or column("address").is_not_null())) - .group_by("age") - .having(column("age") > 10) - .order_by("age desc") - .limit(10) - .offset(1); - std::cout< 60) and ((age >= 20) or (address is not null)) group by age having age > 10 order by age desc limit 10 offset 1 - - std::vector a = {1, 2, 3}; - UpdateModel u; - u.update("user") - .set("name", "ddc") - ("age", 18) - ("score", nullptr) - ("address", "beijing") - .where(column("id").in(a)); - std::cout< a = make_shared(); + + select_model selector(a); + selector.from("users") + .select(col("*")) + .where(boosql::col("hello")["%hello"]) // like + .quote([](select_model & model) { + model.where(col("id") != 1).or_where(col("id") != 2); + }); + selector.group_by(col("hello")).order_by(col("hello")("DESC")); + cout << selector.str() << endl; + + update_model updater(a); + updater.update("users")("hello", "hello")("world", "world").where(col("id") == 2); + cout << updater.str() << endl; + + delete_model deleter(a); + deleter.from("users").where(col("id") == 1).or_where(col("name")["%hello"]); + cout << deleter.str() << endl; + + insert_model insert(a); + insert.into("users") + ("id", 1) + ("name", "hello") + .next_row() + ("id", 2) + ("name", "world"); + + cout << insert.str() << endl; return 0; } diff --git a/update_model.hpp b/update_model.hpp new file mode 100644 index 0000000..6c15215 --- /dev/null +++ b/update_model.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include "model.hpp" +#include +#include "col.hpp" +#include + +namespace boosql { + +class update_model : public model +{ +public: + update_model(shared_ptr adapter) : model(adapter) {} + update_model& update(const std::string& table_name) { + _table_name = table_name; + return *this; + } + + template + update_model& set(const std::string& c, const T& data) { + _columns.push_back(col(c)("=").val(data)); + return *this; + } + + template + update_model& operator()(const std::string& c, const T& data) { + return set(c, data); + } + + update_model& and_where(const string & condition) + { + model::and_where(condition); + return *this; + } + + update_model& and_where(const col & condition) + { + model::and_where(condition); + return *this; + } + + update_model& or_where(const string & condition) + { + model::or_where(condition); + return *this; + } + + update_model& or_where(const col & condition) + { + model::or_where(condition); + return *this; + } + + update_model& quote(std::function callback) + { + model::quote(callback, *this); + return *this; + } + + update_model& where(const string& condition) { + model::where(condition); + return *this; + } + + update_model& where(const col& condition) { + model::where(condition); + return *this; + } + + virtual const string & table_name() + { + return _table_name; + } + + virtual const string& str() override { + _sql.clear(); + _sql.append("UPDATE "); + _sql.append(_adapter->quote_field(_table_name)); + _sql.append(" SET "); + size_t size = _columns.size(); + for(size_t i = 0; i < size; ++i) { + _sql.append(_columns[i].str(_adapter.get(), table_name())); + if(i < size - 1) { + _sql.append(", "); + } + } + _sql.append(where_str()); + + return _sql; + } + + update_model& reset() { + model::reset(); + _table_name.clear(); + _columns.clear(); + return *this; + } + friend inline std::ostream& operator << (std::ostream& out, update_model& mod) { + out << mod.str(); + return out; + } + +protected: + vector _columns; + string _table_name; +}; + +} \ No newline at end of file From 600b6753818b80e471d7f454d8410df80cca3813 Mon Sep 17 00:00:00 2001 From: yang-zhong <37243458+yang-zzhong@users.noreply.github.com> Date: Thu, 14 Mar 2019 20:56:13 +0800 Subject: [PATCH 02/12] Update README.md --- README.md | 99 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 6acfce7..566a517 100644 --- a/README.md +++ b/README.md @@ -7,45 +7,62 @@ ## Examples: ``` c++ - using namespace sql; - - InsertModel i; - i.insert("score", 100) - ("name", std::string("six")) - ("age", (unsigned char)20) - ("address", "beijing") - ("create_time", nullptr) - .into("user"); - std::cout< 60 and (column("age") >= 20 or column("address").is_not_null())) - .group_by("age") - .having(column("age") > 10) - .order_by("age desc") - .limit(10) - .offset(1); - std::cout< 60) and ((age >= 20) or (address is not null)) group by age having age > 10 order by age desc limit 10 offset 1 - - std::vector a = {1, 2, 3}; - UpdateModel u; - u.update("user") - .set("name", "ddc") - ("age", 18) - ("score", nullptr) - ("address", "beijing") - .where(column("id").in(a)); - std::cout< +#include + +#include "col.hpp" +#include "select_model.hpp" +#include "update_model.hpp" +#include "delete_model.hpp" +#include "insert_model.hpp" +#include "adapter.hpp" + +/* +create table if not exists user ( + `id` int(10) unsigned not null auto_increment, + `age` tinyint(8) unsigned, + `score` int(10) unsigned not null default 0, + `name` varchar(128) not null default '', + `address` varchar(256), + `create_time` datetime not null, + primary key(`id`) +) +*/ + +using namespace boosql; + +int main() +{ + shared_ptr a = make_shared(); + + select_model selector(a); + selector.from("users") + .select(col("*")) + .where(boosql::col("hello")["%hello"]) // like + .quote([](select_model & model) { + model.where(col("id") != 1).or_where(col("id") != 2); + }); + selector.group_by(col("hello")).order_by(col("hello")("DESC")); + cout << selector.str() << endl; + + update_model updater(a); + updater.update("users")("hello", "hello")("world", "world").where(col("id") == 2); + cout << updater.str() << endl; + + delete_model deleter(a); + deleter.from("users").where(col("id") == 1).or_where(col("name")["%hello"]); + cout << deleter.str() << endl; + + insert_model insert(a); + insert.into("users") + ("id", 1) + ("name", "hello") + .next_row() + ("id", 2) + ("name", "world"); + + cout << insert.str() << endl; + + return 0; +} ``` From 0a2a8533b2cde0592da8aecc1dd1226413a23be7 Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Fri, 15 Mar 2019 11:38:54 +0800 Subject: [PATCH 03/12] add join --- col.hpp | 34 ++++++++--- delete_model.hpp | 13 +++- insert_model.hpp | 57 ++++++++++++++++-- model.hpp | 40 +++++++++--- select_model.hpp | 154 ++++++++++++++++++++++++++++++++++++++++++++++- test/test.cpp | 6 ++ update_model.hpp | 23 ++++++- 7 files changed, 303 insertions(+), 24 deletions(-) diff --git a/col.hpp b/col.hpp index 05072d1..7e98c5e 100644 --- a/col.hpp +++ b/col.hpp @@ -20,22 +20,35 @@ class col }; public: + col() {} + + col(const string & c) { - if (c != "") { - _items.push_back(item{ field, c }); - } + name(c); } - col(const string & c, bool with_quote_begin) + col(const string & c, const string & tn) + { + name(c); + table_name(tn); + } + + virtual ~col() {} + + col & name(const string & c) { - quote_begin(); if (c != "") { - _items.push_back(item{field, c}); + _items.push_back(item{ field, c }); } + return *this; } - virtual ~col() {} + col & table_name(const string & tn) + { + _table_name = tn; + return *this; + } col& as(const string& s) { @@ -259,6 +272,8 @@ class col string pre_col = ""; if (table_name != "") { pre_col = adapter->quote_field(table_name) + "."; + } else if (_table_name != "") { + pre_col = adapter->quote_field(_table_name) + "."; } for(auto i = _items.begin(); i != _items.end(); ++i) { auto it = *i; @@ -283,6 +298,8 @@ class col string pre_col = ""; if (table_name != "") { pre_col = adapter->quote_field(table_name) + "."; + } else if (_table_name != "") { + pre_col = adapter->quote_field(_table_name) + "."; } for(auto i = _items.begin(); i != _items.end(); ++i) { auto it = *i; @@ -304,7 +321,7 @@ class col static col pre_quote(const string & c) { - return col(c, true); + return col().quote_begin().name(c); } operator bool() { @@ -312,6 +329,7 @@ class col } private: vector _items; + string _table_name = ""; }; } \ No newline at end of file diff --git a/delete_model.hpp b/delete_model.hpp index 0c812c0..97cc656 100644 --- a/delete_model.hpp +++ b/delete_model.hpp @@ -65,11 +65,20 @@ class delete_model : public model return _table_name; } - virtual const string& str() override { + const string& str() override { _sql.clear(); _sql.append("DELETE FROM "); _sql.append(_adapter->quote_field(_table_name)); - _sql.append(where_str()); + append_where(); + + return _sql; + } + + const string& str(vector & params) override { + _sql.clear(); + _sql.append("DELETE FROM "); + _sql.append(_adapter->quote_field(_table_name)); + append_where(params); return _sql; } diff --git a/insert_model.hpp b/insert_model.hpp index 01dcef4..fcb2be4 100644 --- a/insert_model.hpp +++ b/insert_model.hpp @@ -11,8 +11,9 @@ class insert_model : public model { class row_interface { public: - virtual const string & fields(adapter *, const string &) = 0; + virtual const string & fields(adapter *) = 0; virtual const string & values(adapter *) = 0; + virtual const string & values(adapter *, vector &) = 0; }; class row : public row_interface { @@ -36,7 +37,7 @@ class insert_model : public model return _model; } - const string & fields(adapter * adapter, const string & table_name) override + const string & fields(adapter * adapter) override { if (_fields != "") { return _fields; @@ -46,7 +47,7 @@ class insert_model : public model int count = 0; for (auto i = _data.begin(); i != _data.end(); ++i) { count++; - _fields.append(col(i->first).str(adapter, table_name)); + _fields.append(col(i->first).str(adapter)); if (count < size) { _fields.append(", "); } @@ -78,6 +79,28 @@ class insert_model : public model return _values; } + const string & values(adapter * adapter, vector & params) override + { + if (_values != "") { + return _values; + } + _values = "("; + auto size = _data.size(); + int count = 0; + for (auto i = _data.begin(); i != _data.end(); ++i) { + count++; + _values.append(adapter->placeholder()); + params.push_back(i->second); + if (count < size) { + _values.append(", "); + } + } + + _values.append(")"); + + return _values; + } + private: insert_model & _model; map _data; @@ -136,7 +159,7 @@ class insert_model : public model for (auto i = _rows.begin(); i != _rows.end(); ++i) { count++; if (count == 1) { - _sql.append((*i)->fields(_adapter.get(), _table_name)); + _sql.append((*i)->fields(_adapter.get())); _sql.append(" VALUES"); } _sql.append((*i)->values(_adapter.get())); @@ -148,6 +171,32 @@ class insert_model : public model return _sql; } + const string &str(vector ¶ms) override + { + _sql.clear(); + if (_replace) { + _sql.append("INSERT INTO OR REPLACE INFO "); + }else { + _sql.append("INSERT INTO "); + } + _sql.append(_adapter->quote_field(_table_name)); + auto size = _rows.size(); + int count = 0; + for (auto i = _rows.begin(); i != _rows.end(); ++i) { + count++; + if (count == 1) { + _sql.append((*i)->fields(_adapter.get())); + _sql.append(" VALUES"); + } + _sql.append((*i)->values(_adapter.get(), params)); + if (count < size) { + _sql.append(", "); + } + } + + return _sql; + } + insert_model& reset() { _table_name.clear(); _rows.clear(); diff --git a/model.hpp b/model.hpp index fba725e..9d10343 100644 --- a/model.hpp +++ b/model.hpp @@ -22,15 +22,21 @@ class model model(shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} - string where_str() + virtual string where_str() { string ret; - auto size = _where_condition.size(); - if(size > 0) { - ret.append(" WHERE "); - for(size_t i = 0; i < size; ++i) { - ret.append(_where_condition[i].str(_adapter.get(), table_name())); - } + for(auto i = _where_condition.begin(); i != _where_condition.end(); ++i) { + ret.append((*i).str(_adapter.get(), table_name())); + } + + return ret; + } + + virtual string where_str(vector & params) + { + string ret; + for(auto i = _where_condition.begin(); i != _where_condition.end(); ++i) { + ret.append((*i).str(_adapter.get(), table_name(), params)); } return ret; @@ -40,8 +46,28 @@ class model virtual const string & table_name() = 0; virtual const std::string& str() = 0; + virtual const std::string& str(vector &) = 0; protected: + + void append_where() + { + string w = where_str(); + if (w.length() > 0) { + _sql.append( " WHERE " ); + _sql.append(w); + } + } + + void append_where(vector & params) + { + string w = where_str(params); + if (w.length() > 0) { + _sql.append( " WHERE " ); + _sql.append(w); + } + } + void and_where(const string & condition) { _where_condition.push_back(col("").and()); diff --git a/select_model.hpp b/select_model.hpp index 2ecffbe..1fe0406 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -13,6 +13,49 @@ using namespace std; class select_model : public model { + typedef enum {left, right, inner} join_type; + + class join_t { + public: + join_t(select_model & selector, select_model & model) : _selector(selector), model(model) {} + + join_t & on(string main) + { + if (ons.size() > 0) { + ons.push_back(col().and()); + } + ons.push_back(col(main, _selector.table_name())); + + return *this; + } + join_t & operator () (string oper, col second) + { + ons.push_back(col()(oper)); + ons.push_back(second.table_name(model.table_name())); + + return *this; + } + + join_t & or_on(string main) + { + ons.push_back(col().or()); + ons.push_back(col(main, _selector.table_name())); + + return *this; + } + + select_model & end() + { + return _selector; + } + + public: + join_type type; + select_model & model; + vector ons; + private: + select_model & _selector; + }; public: select_model(shared_ptr adapter): model(adapter) {} virtual ~select_model() {} @@ -74,6 +117,18 @@ class select_model : public model return *this; } + join_t & left_join(select_model & m) { + return join(m, left); + } + + join_t & right_join(select_model &m) { + return join(m, right); + } + + join_t & inner_join(select_model &m) { + return join(m, inner); + } + template select_model& group_by(const col& c, Args&&...columns) { _groupby_columns.push_back(c); @@ -132,7 +187,31 @@ class select_model : public model _sql.append(select_str()); _sql.append(" FROM "); _sql.append(_table_name); - _sql.append(where_str()); + _sql.append(join_str()); + append_where(); + _sql.append(group_by_str()); + _sql.append(having_str()); + _sql.append(order_by_str()); + if(!_limit.empty()) { + _sql.append(" LIMIT "); + _sql.append(_limit); + } + if(!_offset.empty()) { + _sql.append(" OFFSET "); + _sql.append(_offset); + } + return _sql; + } + + const string & str(vector ¶ms) override + { + _sql.clear(); + _sql.append("SELECT "); + _sql.append(select_str()); + _sql.append(" FROM "); + _sql.append(_table_name); + _sql.append(join_str()); + append_where(params); _sql.append(group_by_str()); _sql.append(having_str()); _sql.append(order_by_str()); @@ -164,6 +243,64 @@ class select_model : public model return ret; } + string join_str() + { + string ret; + for (auto i = _joins.begin(); i != _joins.end(); ++i) { + switch ((*i).type) { + case left: + ret.append(" LEFT"); + break; + case right: + ret.append(" RIGHT"); + break; + case inner: + ret.append(" INNER"); + break; + } + ret.append(" JOIN " + (*i).model.table_name()); + ret.append(" ON "); + auto ons = (*i).ons; + for (auto j = ons.begin(); j != ons.end(); ++j) { + ret.append((*j).str(_adapter.get())); + } + } + + return ret; + } + + string where_str() + { + string ret = model::where_str(); + for (auto i = _joins.begin(); i != _joins.end(); ++i) { + if (ret.length() > 0) { + ret.append(" AND "); + } + auto s = (*i).model.where_str(); + if (s.length() > 0) { + ret.append("(" + s + ")"); + } + } + + return ret; + } + + string where_str(vector & params) + { + string ret = model::where_str(params); + for (auto i = _joins.begin(); i != _joins.end(); ++i) { + if (ret.length() > 0) { + ret.append(" AND "); + } + auto s = (*i).model.where_str(params); + if (s.length() > 0) { + ret.append("(" + s + ")"); + } + } + + return ret; + } + string having_str() { string ret; @@ -210,6 +347,10 @@ class select_model : public model ret.append(", "); } } + for (auto i = _joins.begin(); i != _joins.end(); ++i) { + ret.append(", "); + ret.append((*i).model.select_str()); + } return ret; } @@ -230,8 +371,19 @@ class select_model : public model return out; } + private: + + join_t & join(select_model & m, join_type type) { + join_t j(*this, m); + j.type = type; + _joins.push_back(j); + + return _joins.back(); + } + private: string _table_name; + vector _joins; vector _select; vector _groupby_columns; vector _having_condition; diff --git a/test/test.cpp b/test/test.cpp index d490531..58d1842 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -35,6 +35,12 @@ int main() .quote([](select_model & model) { model.where(col("id") != 1).or_where(col("id") != 2); }); + select_model group(a); + + group.from("group").select(col("a"), col("b"), col("c")).where(col("a") == 2); + + selector.left_join(group).on("hello")("=", col("a")).or_on("id")("=", col("b")).end(); + selector.group_by(col("hello")).order_by(col("hello")("DESC")); cout << selector.str() << endl; diff --git a/update_model.hpp b/update_model.hpp index 6c15215..dcf9aad 100644 --- a/update_model.hpp +++ b/update_model.hpp @@ -72,7 +72,8 @@ class update_model : public model return _table_name; } - virtual const string& str() override { + const string& str() override + { _sql.clear(); _sql.append("UPDATE "); _sql.append(_adapter->quote_field(_table_name)); @@ -84,7 +85,25 @@ class update_model : public model _sql.append(", "); } } - _sql.append(where_str()); + append_where(); + + return _sql; + } + + const string& str(vector & params) override + { + _sql.clear(); + _sql.append("UPDATE "); + _sql.append(_adapter->quote_field(_table_name)); + _sql.append(" SET "); + size_t size = _columns.size(); + for(size_t i = 0; i < size; ++i) { + _sql.append(_columns[i].str(_adapter.get(), table_name(), params)); + if(i < size - 1) { + _sql.append(", "); + } + } + append_where(); return _sql; } From 0b95a9535894a37b4f58a80cf413d14bc4dc0a4c Mon Sep 17 00:00:00 2001 From: yang-zhong <37243458+yang-zzhong@users.noreply.github.com> Date: Fri, 15 Mar 2019 11:43:31 +0800 Subject: [PATCH 04/12] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 566a517..067c330 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Examples: ``` c++ - #include +#include #include #include "col.hpp" @@ -42,6 +42,12 @@ int main() .quote([](select_model & model) { model.where(col("id") != 1).or_where(col("id") != 2); }); + select_model group(a); + + group.from("group").select(col("a"), col("b"), col("c")).where(col("a") == 2); + + selector.left_join(group).on("hello")("=", col("a")).or_on("id")("=", col("b")).end(); + selector.group_by(col("hello")).order_by(col("hello")("DESC")); cout << selector.str() << endl; From dd628c72c2b8eeb4eea6372cf36d8d948122377b Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Fri, 15 Mar 2019 12:15:25 +0800 Subject: [PATCH 05/12] fixed --- col.hpp | 72 ++++--- delete_model.hpp | 16 +- insert_model.hpp | 33 ++- model.hpp | 50 +++-- select_model.hpp | 79 ++++---- sql.h | 513 ----------------------------------------------- test/test.cpp | 10 +- update_model.hpp | 18 +- 8 files changed, 135 insertions(+), 656 deletions(-) delete mode 100644 sql.h diff --git a/col.hpp b/col.hpp index 7e98c5e..d85c575 100644 --- a/col.hpp +++ b/col.hpp @@ -7,8 +7,6 @@ namespace boosql { -using namespace std; - class col { typedef enum {field, value, other} witch; @@ -16,19 +14,19 @@ class col struct item { public: witch type; - string val; + std::string val; }; public: col() {} - col(const string & c) + col(const std::string & c) { name(c); } - col(const string & c, const string & tn) + col(const std::string & c, const std::string & tn) { name(c); table_name(tn); @@ -36,7 +34,7 @@ class col virtual ~col() {} - col & name(const string & c) + col & name(const std::string & c) { if (c != "") { _items.push_back(item{ field, c }); @@ -44,13 +42,13 @@ class col return *this; } - col & table_name(const string & tn) + col & table_name(const std::string & tn) { _table_name = tn; return *this; } - col& as(const string& s) + col& as(const std::string& s) { _items.push_back(item{other, "AS " + s}); return *this; @@ -67,26 +65,26 @@ class col } template - col& in(const vector& args) { + col& in(const std::vector& args) { return in_or_not(args, "IN"); } template - col& not_in(const vector& args) { + col& not_in(const std::vector& args) { return in_or_not(args, "NOT IN"); } template - col & in_or_not(const vector& args, string in) + col & in_or_not(const std::vector& args, std::string in) { size_t size = args.size(); if(size == 1) { - _items.push_back(item{other, "="}); + _items.push_back(item{other, "="}); ostringstream str; str << args[0]; - _items.push_back(item{value, str.str()}); + _items.push_back(item{value, str.str()}); } else { - _items.push_back(item{other, in + " ("}); + _items.push_back(item{other, in + " ("}); for(size_t i = 0; i < size; ++i) { ostringstream str; str << args[i]; @@ -124,7 +122,7 @@ class col return *this; } - col& operator ()(const string & any) + col& operator ()(const std::string & any) { _items.push_back(item{other, any}); return *this; @@ -133,7 +131,7 @@ class col template col & val(const T& data) { - ostringstream str; + std::ostringstream str; str << data; _items.push_back(item{value, str.str()}); @@ -141,10 +139,10 @@ class col } template - col & val(const vector &data) + col & val(const std::vector &data) { for (auto i = data.begin(); i != data.end(); ++i) { - ostringstream str; + std::ostringstream str; str << *i; _items.push_back(item{value, str.str()}); } @@ -175,7 +173,7 @@ class col } } - col& operator &&(const string& condition) + col& operator &&(const std::string& condition) { quote_begin(); _items.push_back(item{other, condition}); @@ -184,7 +182,7 @@ class col return *this; } - col& operator ||(const string& condition) { + col& operator ||(const std::string& condition) { quote_begin(); _items.push_back(item{other, condition}); quote_end(); @@ -193,22 +191,22 @@ class col } col& operator &&(const char* condition) { - return operator &&(string(condition)); + return operator &&(std::string(condition)); } col& operator ||(const char* condition) { - return operator ||(string(condition)); + return operator ||(std::string(condition)); } col& operator [] (const char * data) { return with_operator(data, "LIKE"); } - col& operator [] (const string & data) { + col& operator [] (const std::string & data) { return with_operator(data, "LIKE"); } - col & escape(const string & data) { + col & escape(const std::string & data) { _items.push_back(item{other, "{ ESCAPE "}); _items.push_back(item{value, data}); _items.push_back(item{other, "}"}); @@ -247,9 +245,9 @@ class col } template - col & with_operator(const T & data, const string & oper) + col & with_operator(const T & data, const std::string & oper) { - ostringstream str; + std::ostringstream str; str << data; _items.push_back(item{other, oper}); _items.push_back(item{value, str.str()}); @@ -257,19 +255,19 @@ class col return *this; } - string str(adapter * adapter) const + std::string str(adapter * adapter) const { return str(adapter, ""); } - string str(adapter * adapter, vector & params) const + std::string str(adapter * adapter, std::vector & params) const { return str(adapter, "", params); } - string str(adapter * adapter, string table_name) const { - string ret = ""; - string pre_col = ""; + std::string str(adapter * adapter, std::string table_name) const { + std::string ret = ""; + std::string pre_col = ""; if (table_name != "") { pre_col = adapter->quote_field(table_name) + "."; } else if (_table_name != "") { @@ -292,10 +290,10 @@ class col return ret; } - string str(adapter * adapter, string table_name, vector & params) const + std::string str(adapter * adapter, std::string table_name, std::vector & params) const { - string ret = ""; - string pre_col = ""; + std::string ret = ""; + std::string pre_col = ""; if (table_name != "") { pre_col = adapter->quote_field(table_name) + "."; } else if (_table_name != "") { @@ -319,7 +317,7 @@ class col return ret; } - static col pre_quote(const string & c) + static col pre_quote(const std::string & c) { return col().quote_begin().name(c); } @@ -328,8 +326,8 @@ class col return true; } private: - vector _items; - string _table_name = ""; + std::vector _items; + std::string _table_name = ""; }; } \ No newline at end of file diff --git a/delete_model.hpp b/delete_model.hpp index 97cc656..27c3362 100644 --- a/delete_model.hpp +++ b/delete_model.hpp @@ -6,12 +6,10 @@ namespace boosql { -using namespace std; - class delete_model : public model { public: - delete_model(shared_ptr adapter) : model(adapter) {} + delete_model(std::shared_ptr adapter) : model(adapter) {} virtual ~delete_model() {} @@ -20,7 +18,7 @@ class delete_model : public model return *this; } - delete_model& and_where(const string & condition) + delete_model& and_where(const std::string & condition) { model::and_where(condition); return *this; @@ -32,7 +30,7 @@ class delete_model : public model return *this; } - delete_model& or_where(const string & condition) + delete_model& or_where(const std::string & condition) { model::or_where(condition); return *this; @@ -50,7 +48,7 @@ class delete_model : public model return *this; } - delete_model& where(const string& condition) { + delete_model& where(const std::string& condition) { model::where(condition); return *this; } @@ -60,12 +58,12 @@ class delete_model : public model return *this; } - const string & table_name() + const std::string & table_name() { return _table_name; } - const string& str() override { + const std::string& str() override { _sql.clear(); _sql.append("DELETE FROM "); _sql.append(_adapter->quote_field(_table_name)); @@ -74,7 +72,7 @@ class delete_model : public model return _sql; } - const string& str(vector & params) override { + const std::string& str(std::vector & params) override { _sql.clear(); _sql.append("DELETE FROM "); _sql.append(_adapter->quote_field(_table_name)); diff --git a/insert_model.hpp b/insert_model.hpp index fcb2be4..5322866 100644 --- a/insert_model.hpp +++ b/insert_model.hpp @@ -11,9 +11,9 @@ class insert_model : public model { class row_interface { public: - virtual const string & fields(adapter *) = 0; - virtual const string & values(adapter *) = 0; - virtual const string & values(adapter *, vector &) = 0; + virtual const std::string & fields(adapter *) = 0; + virtual const std::string & values(adapter *) = 0; + virtual const std::string & values(adapter *, std::vector &) = 0; }; class row : public row_interface { @@ -22,7 +22,7 @@ class insert_model : public model template row& insert(const std::string& c, const T& data) { - ostringstream str; + std::ostringstream str; str << data; _data[c] = str.str(); return *this; @@ -37,7 +37,7 @@ class insert_model : public model return _model; } - const string & fields(adapter * adapter) override + const std::string & fields(adapter * adapter) override { if (_fields != "") { return _fields; @@ -58,7 +58,7 @@ class insert_model : public model return _fields; } - const string & values(adapter * adapter) override + const std::string & values(adapter * adapter) override { if (_values != "") { return _values; @@ -79,7 +79,7 @@ class insert_model : public model return _values; } - const string & values(adapter * adapter, vector & params) override + const std::string & values(adapter * adapter, std::vector & params) override { if (_values != "") { return _values; @@ -103,13 +103,13 @@ class insert_model : public model private: insert_model & _model; - map _data; - string _fields; - string _values; + std::map _data; + std::string _fields; + std::string _values; }; public: - insert_model(shared_ptr adapter) : model(adapter) {} + insert_model(std::shared_ptr adapter) : model(adapter) {} virtual ~insert_model() { auto i = _rows.begin(); @@ -141,12 +141,12 @@ class insert_model : public model return *this; } - const string & table_name() override + const std::string & table_name() override { return _table_name; } - const string& str() override { + const std::string& str() override { _sql.clear(); if (_replace) { _sql.append("INSERT INTO OR REPLACE INFO "); @@ -171,7 +171,7 @@ class insert_model : public model return _sql; } - const string &str(vector ¶ms) override + const std::string &str(std::vector ¶ms) override { _sql.clear(); if (_replace) { @@ -210,9 +210,8 @@ class insert_model : public model protected: bool _replace = false; - string _table_name; - - vector _rows; + std::string _table_name; + std::vector _rows; }; } \ No newline at end of file diff --git a/model.hpp b/model.hpp index 9d10343..93ce0e0 100644 --- a/model.hpp +++ b/model.hpp @@ -10,21 +10,19 @@ namespace boosql { -using namespace std; - class model { public: model() { - auto adapter = make_shared(); + auto adapter = std::make_shared(); _adapter = adapter->shared_from_this(); } - model(shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} + model(std::shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} - virtual string where_str() + virtual std::string where_str() { - string ret; + std::string ret; for(auto i = _where_condition.begin(); i != _where_condition.end(); ++i) { ret.append((*i).str(_adapter.get(), table_name())); } @@ -32,9 +30,9 @@ class model return ret; } - virtual string where_str(vector & params) + virtual std::string where_str(std::vector & params) { - string ret; + std::string ret; for(auto i = _where_condition.begin(); i != _where_condition.end(); ++i) { ret.append((*i).str(_adapter.get(), table_name(), params)); } @@ -44,60 +42,60 @@ class model virtual ~model() {} - virtual const string & table_name() = 0; + virtual const std::string & table_name() = 0; virtual const std::string& str() = 0; - virtual const std::string& str(vector &) = 0; + virtual const std::string& str(std::vector &) = 0; protected: void append_where() { - string w = where_str(); + std::string w = where_str(); if (w.length() > 0) { _sql.append( " WHERE " ); _sql.append(w); } } - void append_where(vector & params) + void append_where(std::vector & params) { - string w = where_str(params); + std::string w = where_str(params); if (w.length() > 0) { _sql.append( " WHERE " ); _sql.append(w); } } - void and_where(const string & condition) + void and_where(const std::string & condition) { - _where_condition.push_back(col("").and()); + _where_condition.push_back(col().and()); where(condition); } void and_where(const col & condition) { - _where_condition.push_back(col("").and()); + _where_condition.push_back(col().and()); where(condition); } - void or_where(const string & condition) + void or_where(const std::string & condition) { - _where_condition.push_back(col("").or()); + _where_condition.push_back(col().or()); where(condition); } void or_where(const col & condition) { - _where_condition.push_back(col("").or()); + _where_condition.push_back(col().or()); where(condition); } template void quote(std::function callback, T& model) { - _where_condition.push_back(col("").and()); - _where_condition.push_back(col("").quote_begin()); + _where_condition.push_back(col().and()); + _where_condition.push_back(col().quote_begin()); callback(model); - _where_condition.push_back(col("").quote_end()); + _where_condition.push_back(col().quote_end()); } - void where(const string& condition) { - _where_condition.push_back(col("")(condition)); + void where(const std::string& condition) { + _where_condition.push_back(col()(condition)); } void where(const col& condition) { _where_condition.push_back(condition); @@ -112,11 +110,11 @@ class model model& operator =(const model& data) = delete; private: - vector _where_condition; + std::vector _where_condition; protected: std::string _sql; - shared_ptr _adapter; + std::shared_ptr _adapter; }; } \ No newline at end of file diff --git a/select_model.hpp b/select_model.hpp index 1fe0406..d9b895f 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -9,7 +9,6 @@ namespace boosql { -using namespace std; class select_model : public model { @@ -19,7 +18,7 @@ class select_model : public model public: join_t(select_model & selector, select_model & model) : _selector(selector), model(model) {} - join_t & on(string main) + join_t & on(std::string main) { if (ons.size() > 0) { ons.push_back(col().and()); @@ -28,7 +27,7 @@ class select_model : public model return *this; } - join_t & operator () (string oper, col second) + join_t & operator () (std::string oper, col second) { ons.push_back(col()(oper)); ons.push_back(second.table_name(model.table_name())); @@ -36,7 +35,7 @@ class select_model : public model return *this; } - join_t & or_on(string main) + join_t & or_on(std::string main) { ons.push_back(col().or()); ons.push_back(col(main, _selector.table_name())); @@ -52,12 +51,12 @@ class select_model : public model public: join_type type; select_model & model; - vector ons; + std::vector ons; private: select_model & _selector; }; public: - select_model(shared_ptr adapter): model(adapter) {} + select_model(std::shared_ptr adapter): model(adapter) {} virtual ~select_model() {} template @@ -72,12 +71,12 @@ class select_model : public model return *this; } - select_model& from(const string& table_name) { + select_model& from(const std::string& table_name) { _table_name = table_name; return *this; } - select_model& and_where(const string & condition) + select_model& and_where(const std::string & condition) { model::and_where(condition); return *this; @@ -89,7 +88,7 @@ class select_model : public model return *this; } - select_model& or_where(const string & condition) + select_model& or_where(const std::string & condition) { model::or_where(condition); return *this; @@ -107,7 +106,7 @@ class select_model : public model return *this; } - select_model& where(const string& condition) { + select_model& where(const std::string& condition) { model::where(condition); return *this; } @@ -141,7 +140,7 @@ class select_model : public model return *this; } - select_model& having(const string& condition) { + select_model& having(const std::string& condition) { _having_condition.push_back(col("")(condition)); return *this; } @@ -158,7 +157,7 @@ class select_model : public model template select_model& limit(const T& limit) { - _limit = to_string(limit); + _limit = std::to_string(limit); return *this; } @@ -171,16 +170,16 @@ class select_model : public model template select_model& offset(const T& offset) { - _offset = to_string(offset); + _offset = std::to_string(offset); return *this; } - const string & table_name() + const std::string & table_name() { return _table_name; } - const string& str() override + const std::string& str() override { _sql.clear(); _sql.append("SELECT "); @@ -203,7 +202,7 @@ class select_model : public model return _sql; } - const string & str(vector ¶ms) override + const std::string & str(std::vector ¶ms) override { _sql.clear(); _sql.append("SELECT "); @@ -226,9 +225,9 @@ class select_model : public model return _sql; } - string order_by_str() + std::string order_by_str() { - string ret; + std::string ret; auto size = _order_by.size(); if (size > 0) { ret.append(" ORDER BY "); @@ -243,9 +242,9 @@ class select_model : public model return ret; } - string join_str() + std::string join_str() { - string ret; + std::string ret; for (auto i = _joins.begin(); i != _joins.end(); ++i) { switch ((*i).type) { case left: @@ -269,9 +268,9 @@ class select_model : public model return ret; } - string where_str() + std::string where_str() { - string ret = model::where_str(); + std::string ret = model::where_str(); for (auto i = _joins.begin(); i != _joins.end(); ++i) { if (ret.length() > 0) { ret.append(" AND "); @@ -285,9 +284,9 @@ class select_model : public model return ret; } - string where_str(vector & params) + std::string where_str(std::vector & params) { - string ret = model::where_str(params); + std::string ret = model::where_str(params); for (auto i = _joins.begin(); i != _joins.end(); ++i) { if (ret.length() > 0) { ret.append(" AND "); @@ -301,9 +300,9 @@ class select_model : public model return ret; } - string having_str() + std::string having_str() { - string ret; + std::string ret; auto size = _having_condition.size(); if(size > 0) { ret.append(" HAVING "); @@ -318,9 +317,9 @@ class select_model : public model return ret; } - string group_by_str() + std::string group_by_str() { - string ret; + std::string ret; auto size = _groupby_columns.size(); if(!_groupby_columns.empty()) { ret.append(" GROUP BY "); @@ -336,9 +335,9 @@ class select_model : public model } - string select_str() + std::string select_str() { - string ret = ""; + std::string ret = ""; int count = 0; for (auto i = _select.begin(); i != _select.end(); ++i) { count++; @@ -366,8 +365,8 @@ class select_model : public model _offset.clear(); return *this; } - friend inline ostream& operator<< (ostream& out, select_model& mod) { - out< _joins; - vector _select; - vector _groupby_columns; - vector _having_condition; - vector _order_by; - string _limit; - string _offset; + std::string _table_name; + std::vector _joins; + std::vector _select; + std::vector _groupby_columns; + std::vector _having_condition; + std::vector _order_by; + std::string _limit; + std::string _offset; }; } \ No newline at end of file diff --git a/sql.h b/sql.h deleted file mode 100644 index 9f35386..0000000 --- a/sql.h +++ /dev/null @@ -1,513 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace boosql { - - using namespace std; - -template -inline std::string to_value(const T& data) { - return std::to_string(data); -} - -template -inline std::string to_value(char const(&data)[N]) { - std::string str("'"); - str.append(data); - str.append("'"); - return str; -} - -template <> -inline std::string to_value(const std::string& data) { - std::string str("'"); - str.append(data); - str.append("'"); - return str; -} - -template <> -inline std::string to_value(const char* const& data) { - std::string str("'"); - str.append(data); - str.append("'"); - return str; -} - -/* -template <> -static std::string sql::to_value(const time_t& data) { - char buff[128] = {0}; - struct tm* ttime = localtime(&data); - strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", ttime); - std::string str("'"); - str.append(buff); - str.append("'"); - return str; -} -*/ - -class sql_model -{ -public: - sql_model() { - auto adapter = make_shared(); - _adapter = adapter->shared_from_this(); - } - sql_model(shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} - - column col(const string & col) - { - return column(_adapter->quote_field(col)); - } - - virtual ~sql_model() {} - - virtual const std::string& str() = 0; - const std::string& last_sql() { - return _sql; - } -private: - sql_model(const sql_model& m) = delete; - sql_model& operator =(const sql_model& data) = delete; - shared_ptr _adapter; - -protected: - std::string _sql; -}; - -class select_model : public sql_model -{ -public: - select_model() {} - virtual ~select_model() {} - - template - select_model& select(const std::string& str, Args&&... columns) { - _select_columns.push_back(str); - select(columns...); - return *this; - } - - // for recursion - select_model& select() { - return *this; - } - - template - select_model& from(const std::string& table_name, Args&&... tables) { - if(_table_name.empty()) { - _table_name = table_name; - } else { - _table_name.append(", "); - _table_name.append(table_name); - } - from(tables...); - return *this; - } - - // for recursion - select_model& from() { - return *this; - } - - select_model& where(const std::string& condition) { - _where_condition.push_back(condition); - return *this; - } - - select_model& where(column& condition) { - _where_condition.push_back(condition.str()); - return *this; - } - - template - select_model& group_by(const std::string& str, Args&&...columns) { - _groupby_columns.push_back(str); - group_by(columns...); - return *this; - } - - // for recursion - select_model& group_by() { - return *this; - } - - select_model& having(const std::string& condition) { - _having_condition.push_back(condition); - return *this; - } - - select_model& having(column& condition) { - _having_condition.push_back(condition.str()); - return *this; - } - - select_model& order_by(const std::string& order_by) { - _order_by = order_by; - return *this; - } - - template - select_model& limit(const T& limit) { - _limit = std::to_string(limit); - return *this; - } - template - select_model& limit(const T& offset, const T& limit) { - _offset = std::to_string(offset); - _limit = std::to_string(limit); - return *this; - } - template - select_model& offset(const T& offset) { - _offset = std::to_string(offset); - return *this; - } - - virtual const std::string& str() override { - _sql.clear(); - _sql.append("select "); - size_t size = _select_columns.size(); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_select_columns[i]); - _sql.append(", "); - } else { - _sql.append(_select_columns[i]); - } - } - _sql.append(" from "); - _sql.append(_table_name); - size = _where_condition.size(); - if(size > 0) { - _sql.append(" where "); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_where_condition[i]); - _sql.append(" "); - } else { - _sql.append(_where_condition[i]); - } - } - } - size = _groupby_columns.size(); - if(!_groupby_columns.empty()) { - _sql.append(" group by "); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_groupby_columns[i]); - _sql.append(", "); - } else { - _sql.append(_groupby_columns[i]); - } - } - } - size = _having_condition.size(); - if(size > 0) { - _sql.append(" having "); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_having_condition[i]); - _sql.append(" "); - } else { - _sql.append(_having_condition[i]); - } - } - } - if(!_order_by.empty()) { - _sql.append(" order by "); - _sql.append(_order_by); - } - if(!_limit.empty()) { - _sql.append(" limit "); - _sql.append(_limit); - } - if(!_offset.empty()) { - _sql.append(" offset "); - _sql.append(_offset); - } - return _sql; - } - - select_model& reset() { - _table_name.clear(); - _select_columns.clear(); - _groupby_columns.clear(); - _where_condition.clear(); - _having_condition.clear(); - _order_by.clear(); - _limit.clear(); - _offset.clear(); - return *this; - } - friend inline std::ostream& operator<< (std::ostream& out, select_model& mod) { - out< _select_columns; - std::vector _groupby_columns; - std::string _table_name; - std::vector _where_condition; - std::vector _having_condition; - std::string _order_by; - std::string _limit; - std::string _offset; -}; - - - -class insert_model : public sql_model -{ -public: - insert_model() {} - virtual ~insert_model() {} - - template - insert_model& insert(const std::string& c, const T& data) { - _columns.push_back(c); - _values.push_back(to_value(data)); - return *this; - } - - template - insert_model& operator()(const std::string& c, const T& data) { - return insert(c, data); - } - - insert_model& into(const std::string& table_name) { - _table_name = table_name; - return *this; - } - - insert_model& replace(bool var) { - _replace = var; - return *this; - } - - virtual const std::string& str() override { - _sql.clear(); - std::string v_ss; - - if (_replace) { - _sql.append("insert or replace into "); - }else { - _sql.append("insert into "); - } - - _sql.append(_table_name); - _sql.append("("); - v_ss.append(" values("); - size_t size = _columns.size(); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_columns[i]); - _sql.append(", "); - v_ss.append(_values[i]); - v_ss.append(", "); - } else { - _sql.append(_columns[i]); - _sql.append(")"); - v_ss.append(_values[i]); - v_ss.append(")"); - } - } - _sql.append(v_ss); - return _sql; - } - - insert_model& reset() { - _table_name.clear(); - _columns.clear(); - _values.clear(); - return *this; - } - - friend inline std::ostream& operator<< (std::ostream& out, insert_model& mod) { - out< _columns; - std::vector _values; -}; - -template <> -inline insert_model& insert_model::insert(const std::string& c, const std::nullptr_t&) { - _columns.push_back(c); - _values.push_back("null"); - return *this; -} - - -class update_model : public sql_model -{ -public: - update_model() {} - virtual ~update_model() {} - - update_model& update(const std::string& table_name) { - _table_name = table_name; - return *this; - } - - template - update_model& set(const std::string& c, const T& data) { - std::string str(c); - str.append(" = "); - str.append(to_value(data)); - _set_columns.push_back(str); - return *this; - } - - template - update_model& operator()(const std::string& c, const T& data) { - return set(c, data); - } - - update_model& where(const std::string& condition) { - _where_condition.push_back(condition); - return *this; - } - - update_model& where(column& condition) { - _where_condition.push_back(condition.str()); - return *this; - } - - virtual const std::string& str() override { - _sql.clear(); - _sql.append("update "); - _sql.append(_table_name); - _sql.append(" set "); - size_t size = _set_columns.size(); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_set_columns[i]); - _sql.append(", "); - } else { - _sql.append(_set_columns[i]); - } - } - size = _where_condition.size(); - if(size > 0) { - _sql.append(" where "); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_where_condition[i]); - _sql.append(" "); - } else { - _sql.append(_where_condition[i]); - } - } - } - return _sql; - } - - update_model& reset() { - _table_name.clear(); - _set_columns.clear(); - _where_condition.clear(); - return *this; - } - friend inline std::ostream& operator<< (std::ostream& out, update_model& mod) { - out< _set_columns; - std::string _table_name; - std::vector _where_condition; -}; - -template <> -inline update_model& update_model::set(const std::string& c, const std::nullptr_t&) { - std::string str(c); - str.append(" = null"); - _set_columns.push_back(str); - return *this; -} - - -class delete_model : public sql_model -{ -public: - delete_model() {} - virtual ~delete_model() {} - - delete_model& _delete() { - return *this; - } - - template - delete_model& from(const std::string& table_name, Args&&... tables) { - if(_table_name.empty()) { - _table_name = table_name; - } else { - _table_name.append(", "); - _table_name.append(table_name); - } - from(tables...); - return *this; - } - - // for recursion - delete_model& from() { - return *this; - } - - delete_model& where(const std::string& condition) { - _where_condition.push_back(condition); - return *this; - } - - delete_model& where(column& condition) { - _where_condition.push_back(condition.str()); - return *this; - } - - virtual const std::string& str() override { - _sql.clear(); - _sql.append("delete from "); - _sql.append(_table_name); - size_t size = _where_condition.size(); - if(size > 0) { - _sql.append(" where "); - for(size_t i = 0; i < size; ++i) { - if(i < size - 1) { - _sql.append(_where_condition[i]); - _sql.append(" "); - } else { - _sql.append(_where_condition[i]); - } - } - } - return _sql; - } - - delete_model& reset() { - _table_name.clear(); - _where_condition.clear(); - return *this; - } - friend inline std::ostream& operator<< (std::ostream& out, delete_model& mod) { - out< _where_condition; -}; - -} diff --git a/test/test.cpp b/test/test.cpp index 58d1842..a111c08 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -26,7 +26,7 @@ using namespace boosql; int main() { - shared_ptr a = make_shared(); + std::shared_ptr a = std::make_shared(); select_model selector(a); selector.from("users") @@ -42,15 +42,15 @@ int main() selector.left_join(group).on("hello")("=", col("a")).or_on("id")("=", col("b")).end(); selector.group_by(col("hello")).order_by(col("hello")("DESC")); - cout << selector.str() << endl; + std::cout << selector.str() << std::endl; update_model updater(a); updater.update("users")("hello", "hello")("world", "world").where(col("id") == 2); - cout << updater.str() << endl; + std::cout << updater.str() << std::endl; delete_model deleter(a); deleter.from("users").where(col("id") == 1).or_where(col("name")["%hello"]); - cout << deleter.str() << endl; + std::cout << deleter.str() << std::endl; insert_model insert(a); insert.into("users") @@ -60,7 +60,7 @@ int main() ("id", 2) ("name", "world"); - cout << insert.str() << endl; + std::cout << insert.str() << std::endl; return 0; } diff --git a/update_model.hpp b/update_model.hpp index dcf9aad..212b645 100644 --- a/update_model.hpp +++ b/update_model.hpp @@ -10,7 +10,7 @@ namespace boosql { class update_model : public model { public: - update_model(shared_ptr adapter) : model(adapter) {} + update_model(std::shared_ptr a) : model(a) {} update_model& update(const std::string& table_name) { _table_name = table_name; return *this; @@ -27,7 +27,7 @@ class update_model : public model return set(c, data); } - update_model& and_where(const string & condition) + update_model& and_where(const std::string & condition) { model::and_where(condition); return *this; @@ -39,7 +39,7 @@ class update_model : public model return *this; } - update_model& or_where(const string & condition) + update_model& or_where(const std::string & condition) { model::or_where(condition); return *this; @@ -57,7 +57,7 @@ class update_model : public model return *this; } - update_model& where(const string& condition) { + update_model& where(const std::string& condition) { model::where(condition); return *this; } @@ -67,12 +67,12 @@ class update_model : public model return *this; } - virtual const string & table_name() + virtual const std::string & table_name() { return _table_name; } - const string& str() override + const std::string& str() override { _sql.clear(); _sql.append("UPDATE "); @@ -90,7 +90,7 @@ class update_model : public model return _sql; } - const string& str(vector & params) override + const std::string& str(std::vector & params) override { _sql.clear(); _sql.append("UPDATE "); @@ -120,8 +120,8 @@ class update_model : public model } protected: - vector _columns; - string _table_name; + std::vector _columns; + std::string _table_name; }; } \ No newline at end of file From 1d0189f109c3a17042dd9b6c42c20d9eea559189 Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Fri, 15 Mar 2019 12:30:00 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- delete_model.hpp | 1 + insert_model.hpp | 1 + select_model.hpp | 1 + test/test.cpp | 3 ++- update_model.hpp | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/delete_model.hpp b/delete_model.hpp index 27c3362..b28106a 100644 --- a/delete_model.hpp +++ b/delete_model.hpp @@ -9,6 +9,7 @@ namespace boosql { class delete_model : public model { public: + delete_model() {} delete_model(std::shared_ptr adapter) : model(adapter) {} virtual ~delete_model() {} diff --git a/insert_model.hpp b/insert_model.hpp index 5322866..f21c706 100644 --- a/insert_model.hpp +++ b/insert_model.hpp @@ -109,6 +109,7 @@ class insert_model : public model }; public: + insert_model() {} insert_model(std::shared_ptr adapter) : model(adapter) {} virtual ~insert_model() { diff --git a/select_model.hpp b/select_model.hpp index d9b895f..e3bd722 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -56,6 +56,7 @@ class select_model : public model select_model & _selector; }; public: + select_model() {} select_model(std::shared_ptr adapter): model(adapter) {} virtual ~select_model() {} diff --git a/test/test.cpp b/test/test.cpp index a111c08..6fba624 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -48,7 +48,8 @@ int main() updater.update("users")("hello", "hello")("world", "world").where(col("id") == 2); std::cout << updater.str() << std::endl; - delete_model deleter(a); + delete_model deleter; + // delete_model deleter(a); deleter.from("users").where(col("id") == 1).or_where(col("name")["%hello"]); std::cout << deleter.str() << std::endl; diff --git a/update_model.hpp b/update_model.hpp index 212b645..0b9546a 100644 --- a/update_model.hpp +++ b/update_model.hpp @@ -10,6 +10,7 @@ namespace boosql { class update_model : public model { public: + update_model() {} update_model(std::shared_ptr a) : model(a) {} update_model& update(const std::string& table_name) { _table_name = table_name; From 56a00056c4f1481503e2ba2053569df5435b4ab4 Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Mon, 18 Mar 2019 16:26:10 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- col.hpp | 6 ++++++ delete_model.hpp | 4 ++++ insert_model.hpp | 22 ++++++++++++++++++++++ model.hpp | 16 +++++++++------- select_model.hpp | 24 ++++++++++++++++++++++-- test/test.cpp | 10 ++++++++++ update_model.hpp | 6 ++++++ 7 files changed, 79 insertions(+), 9 deletions(-) diff --git a/col.hpp b/col.hpp index d85c575..5d7141d 100644 --- a/col.hpp +++ b/col.hpp @@ -32,6 +32,12 @@ class col table_name(tn); } + col(const col & c) + { + _items = c._items; + _table_name = c._table_name; + } + virtual ~col() {} col & name(const std::string & c) diff --git a/delete_model.hpp b/delete_model.hpp index b28106a..d9e5b61 100644 --- a/delete_model.hpp +++ b/delete_model.hpp @@ -11,6 +11,10 @@ class delete_model : public model public: delete_model() {} delete_model(std::shared_ptr adapter) : model(adapter) {} + delete_model(const delete_model & m) : model(m) + { + _table_name = m._table_name; + } virtual ~delete_model() {} diff --git a/insert_model.hpp b/insert_model.hpp index f21c706..7e3dce2 100644 --- a/insert_model.hpp +++ b/insert_model.hpp @@ -3,6 +3,7 @@ #include "model.hpp" #include +#include namespace boosql { @@ -11,6 +12,7 @@ class insert_model : public model { class row_interface { public: + virtual void each(std::function) = 0; virtual const std::string & fields(adapter *) = 0; virtual const std::string & values(adapter *) = 0; virtual const std::string & values(adapter *, std::vector &) = 0; @@ -33,6 +35,13 @@ class insert_model : public model return insert(c, data); } + void each(std::function handle) + { + for (auto i = _data.begin(); i != _data.end(); ++i) { + handle(i->first, i->second); + } + } + insert_model & next_row() { return _model; } @@ -111,6 +120,19 @@ class insert_model : public model public: insert_model() {} insert_model(std::shared_ptr adapter) : model(adapter) {} + insert_model(const insert_model & m) : model(m) + { + _replace = m._replace; + _table_name = m._table_name; + for (auto i = m._rows.begin(); i != m._rows.end(); ++i) { + row * r = new row(*this); + (*i)->each([&r](std::string field, std::string val) { + r->insert(field, val); + }); + _rows.push_back(r); + } + } + virtual ~insert_model() { auto i = _rows.begin(); diff --git a/model.hpp b/model.hpp index 93ce0e0..9f16b5e 100644 --- a/model.hpp +++ b/model.hpp @@ -18,6 +18,12 @@ class model _adapter = adapter->shared_from_this(); } + model(const model & m) + { + _adapter = m._adapter->shared_from_this(); + _where_condition = m._where_condition; + } + model(std::shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} virtual std::string where_str() @@ -105,16 +111,12 @@ class model _where_condition.clear(); } -private: - model(const model& m) = delete; - model& operator =(const model& data) = delete; - -private: - std::vector _where_condition; - protected: std::string _sql; std::shared_ptr _adapter; + +private: + std::vector _where_condition; }; } \ No newline at end of file diff --git a/select_model.hpp b/select_model.hpp index e3bd722..963fad6 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -58,8 +58,28 @@ class select_model : public model public: select_model() {} select_model(std::shared_ptr adapter): model(adapter) {} + select_model(const select_model & m) : model(m) + { + _table_name = m._table_name; + for (auto i = m._joins.begin(); i != m._joins.end(); ++i) { + join_t join(*this, (*i).model); + join.ons = (*i).ons; + _joins.push_back(join); + } + _select = m._select; + _groupby_columns = m._groupby_columns; + _having_condition = m._having_condition; + _order_by = m._order_by; + _limit = m._limit; + _offset = m._offset; + } + virtual ~select_model() {} + void copy_select(const select_model & m) + { + } + template select_model& select(const col& c, Args&&... columns) { _select.push_back(c); @@ -235,7 +255,7 @@ class select_model : public model for (size_t i = 0; i < size; ++i) { ret.append(_order_by[i].str(_adapter.get(), _table_name)); if(i < size - 1) { - _sql.append(", "); + ret.append(", "); } } } @@ -322,7 +342,7 @@ class select_model : public model { std::string ret; auto size = _groupby_columns.size(); - if(!_groupby_columns.empty()) { + if(size > 0) { ret.append(" GROUP BY "); for(size_t i = 0; i < size; ++i) { ret.append(_groupby_columns[i].str(_adapter.get(), _table_name)); diff --git a/test/test.cpp b/test/test.cpp index 6fba624..32264f9 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -42,11 +42,21 @@ int main() selector.left_join(group).on("hello")("=", col("a")).or_on("id")("=", col("b")).end(); selector.group_by(col("hello")).order_by(col("hello")("DESC")); + + select_model another(selector); + + another.order_by(col("hello")("ASC")); + std::cout << selector.str() << std::endl; + std::cout << another.str() << std::endl; update_model updater(a); updater.update("users")("hello", "hello")("world", "world").where(col("id") == 2); + update_model au(updater); + au("helloworld", "helloworld"); + std::cout << updater.str() << std::endl; + std::cout << au.str() << std::endl; delete_model deleter; // delete_model deleter(a); diff --git a/update_model.hpp b/update_model.hpp index 0b9546a..a8a5aa7 100644 --- a/update_model.hpp +++ b/update_model.hpp @@ -12,6 +12,12 @@ class update_model : public model public: update_model() {} update_model(std::shared_ptr a) : model(a) {} + update_model(const update_model & m) : model(m) + { + _columns = m._columns; + _table_name = m._table_name; + } + update_model& update(const std::string& table_name) { _table_name = table_name; return *this; From 7700949a034f9e7fffd0fa332fd786051fc1adfc Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Mon, 18 Mar 2019 19:53:20 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E8=B0=83=E6=95=B4col?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- col.hpp | 21 ++++++++++----------- model.hpp | 13 +++++++------ select_model.hpp | 6 +++--- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/col.hpp b/col.hpp index 5d7141d..70d9561 100644 --- a/col.hpp +++ b/col.hpp @@ -20,7 +20,6 @@ class col public: col() {} - col(const std::string & c) { name(c); @@ -85,14 +84,14 @@ class col { size_t size = args.size(); if(size == 1) { - _items.push_back(item{other, "="}); - ostringstream str; + _items.push_back(item{other, "="}); + std::ostringstream str; str << args[0]; - _items.push_back(item{value, str.str()}); + _items.push_back(item{value, str.str()}); } else { - _items.push_back(item{other, in + " ("}); + _items.push_back(item{other, in + " ("}); for(size_t i = 0; i < size; ++i) { - ostringstream str; + std::ostringstream str; str << args[i]; _items.push_back(item{value, str.str()}); if(i < size - 1) { @@ -104,13 +103,13 @@ class col return *this; } - col & and() + col & o_and() { _items.push_back(item{other, "AND"}); return *this; } - col & or() + col & o_or() { _items.push_back(item{other, "OR"}); return *this; @@ -158,7 +157,7 @@ class col col& operator &&(col & condition) { - and(); + o_and(); merge(condition); return *this; @@ -166,7 +165,7 @@ class col col& operator ||(col& condition) { - or (); + o_or(); merge(condition); return *this; @@ -336,4 +335,4 @@ class col std::string _table_name = ""; }; -} \ No newline at end of file +} diff --git a/model.hpp b/model.hpp index 9f16b5e..27aa444 100644 --- a/model.hpp +++ b/model.hpp @@ -7,6 +7,7 @@ #include #include + namespace boosql { @@ -74,28 +75,28 @@ class model void and_where(const std::string & condition) { - _where_condition.push_back(col().and()); + _where_condition.push_back(col().o_and()); where(condition); } void and_where(const col & condition) { - _where_condition.push_back(col().and()); + _where_condition.push_back(col().o_and()); where(condition); } void or_where(const std::string & condition) { - _where_condition.push_back(col().or()); + _where_condition.push_back(col().o_or()); where(condition); } void or_where(const col & condition) { - _where_condition.push_back(col().or()); + _where_condition.push_back(col().o_or()); where(condition); } template void quote(std::function callback, T& model) { - _where_condition.push_back(col().and()); + _where_condition.push_back(col().o_and()); _where_condition.push_back(col().quote_begin()); callback(model); _where_condition.push_back(col().quote_end()); @@ -119,4 +120,4 @@ class model std::vector _where_condition; }; -} \ No newline at end of file +} diff --git a/select_model.hpp b/select_model.hpp index 963fad6..8e4b896 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -21,7 +21,7 @@ class select_model : public model join_t & on(std::string main) { if (ons.size() > 0) { - ons.push_back(col().and()); + ons.push_back(col().o_and()); } ons.push_back(col(main, _selector.table_name())); @@ -37,7 +37,7 @@ class select_model : public model join_t & or_on(std::string main) { - ons.push_back(col().or()); + ons.push_back(col().o_or()); ons.push_back(col(main, _selector.table_name())); return *this; @@ -412,4 +412,4 @@ class select_model : public model std::string _offset; }; -} \ No newline at end of file +} From 5beb6f822265160f34526cf4a130be7b3609b8de Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Tue, 19 Mar 2019 12:39:55 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9join=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- select_model.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/select_model.hpp b/select_model.hpp index 8e4b896..6bb6487 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -293,11 +293,10 @@ class select_model : public model { std::string ret = model::where_str(); for (auto i = _joins.begin(); i != _joins.end(); ++i) { - if (ret.length() > 0) { - ret.append(" AND "); - } auto s = (*i).model.where_str(); - if (s.length() > 0) { + if (ret.length() > 0 && s.length() > 0) { + ret.append(" AND (" + s + ")"); + } else if (s.length() > 0) { ret.append("(" + s + ")"); } } From f55124bafd37751b3488d997108f738aa0ceeea3 Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Tue, 19 Mar 2019 14:47:21 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adapter.hpp | 6 ++++++ delete_model.hpp | 15 ++++++++++----- insert_model.hpp | 23 ++++++++++++----------- model.hpp | 47 +++++++++++++++++++++++++++++++++++++---------- select_model.hpp | 26 +++++++++++++------------- test/test.cpp | 24 ++++++++++++------------ update_model.hpp | 18 +++++++++--------- 7 files changed, 99 insertions(+), 60 deletions(-) diff --git a/adapter.hpp b/adapter.hpp index 25efa8d..a9bc19e 100644 --- a/adapter.hpp +++ b/adapter.hpp @@ -11,6 +11,7 @@ class adapter : public std::enable_shared_from_this virtual std::string quote_value(const std::string & value) = 0; virtual std::string quote_field(const std::string & field) = 0; virtual std::string placeholder() = 0; + virtual adapter * clone() = 0; }; class sqlite_adapter : public adapter @@ -30,6 +31,11 @@ class sqlite_adapter : public adapter { return "?"; } + + adapter * clone() override + { + return new sqlite_adapter(); + } }; } \ No newline at end of file diff --git a/delete_model.hpp b/delete_model.hpp index d9e5b61..5a6999d 100644 --- a/delete_model.hpp +++ b/delete_model.hpp @@ -10,12 +10,20 @@ class delete_model : public model { public: delete_model() {} - delete_model(std::shared_ptr adapter) : model(adapter) {} + delete_model(adapter * a) : model(a) {} delete_model(const delete_model & m) : model(m) { _table_name = m._table_name; } + delete_model(adapter * a, const std::string & table_name) + : model(a, table_name) + {} + + delete_model(const std::string & table_name) + : model(table_name) + {} + virtual ~delete_model() {} delete_model& from(const std::string& table_name) { @@ -87,17 +95,14 @@ class delete_model : public model } delete_model& reset() { - _table_name.clear(); model::reset(); return *this; } + friend inline std::ostream& operator<< (std::ostream& out, delete_model& mod) { out << mod.str(); return out; } - -protected: - std::string _table_name; }; } \ No newline at end of file diff --git a/insert_model.hpp b/insert_model.hpp index 7e3dce2..21e4136 100644 --- a/insert_model.hpp +++ b/insert_model.hpp @@ -119,7 +119,7 @@ class insert_model : public model public: insert_model() {} - insert_model(std::shared_ptr adapter) : model(adapter) {} + insert_model(adapter * a) : model(a) {} insert_model(const insert_model & m) : model(m) { _replace = m._replace; @@ -132,6 +132,13 @@ class insert_model : public model _rows.push_back(r); } } + insert_model(adapter * a, const std::string & table_name) + : model(a, table_name) + {} + + insert_model(const std::string & table_name) + : model(table_name) + {} virtual ~insert_model() { @@ -164,11 +171,6 @@ class insert_model : public model return *this; } - const std::string & table_name() override - { - return _table_name; - } - const std::string& str() override { _sql.clear(); if (_replace) { @@ -182,10 +184,10 @@ class insert_model : public model for (auto i = _rows.begin(); i != _rows.end(); ++i) { count++; if (count == 1) { - _sql.append((*i)->fields(_adapter.get())); + _sql.append((*i)->fields(_adapter)); _sql.append(" VALUES"); } - _sql.append((*i)->values(_adapter.get())); + _sql.append((*i)->values(_adapter)); if (count < size) { _sql.append(", "); } @@ -208,10 +210,10 @@ class insert_model : public model for (auto i = _rows.begin(); i != _rows.end(); ++i) { count++; if (count == 1) { - _sql.append((*i)->fields(_adapter.get())); + _sql.append((*i)->fields(_adapter)); _sql.append(" VALUES"); } - _sql.append((*i)->values(_adapter.get(), params)); + _sql.append((*i)->values(_adapter, params)); if (count < size) { _sql.append(", "); } @@ -233,7 +235,6 @@ class insert_model : public model protected: bool _replace = false; - std::string _table_name; std::vector _rows; }; diff --git a/model.hpp b/model.hpp index 27aa444..e74c8a4 100644 --- a/model.hpp +++ b/model.hpp @@ -14,24 +14,44 @@ namespace boosql class model { public: - model() { - auto adapter = std::make_shared(); - _adapter = adapter->shared_from_this(); + const std::string & table_name() + { + return _table_name; + } + + model() + { + _adapter = new sqlite_adapter(); + _auto_delete_adapter = true; } model(const model & m) { - _adapter = m._adapter->shared_from_this(); + _adapter = m._adapter->clone(); + _auto_delete_adapter = true; + _where_condition = m._where_condition; } - model(std::shared_ptr adapter) : _adapter(adapter->shared_from_this()) {} + model(adapter * adapter) : _adapter(adapter) {} + + model(adapter * adapter, const std::string & table_name) + : _adapter(adapter), _table_name(table_name) + { + } + + model(const std::string & table_name) + { + _adapter = new sqlite_adapter(); + _auto_delete_adapter = true; + _table_name = table_name; + } virtual std::string where_str() { std::string ret; for(auto i = _where_condition.begin(); i != _where_condition.end(); ++i) { - ret.append((*i).str(_adapter.get(), table_name())); + ret.append((*i).str(_adapter, table_name())); } return ret; @@ -41,15 +61,19 @@ class model { std::string ret; for(auto i = _where_condition.begin(); i != _where_condition.end(); ++i) { - ret.append((*i).str(_adapter.get(), table_name(), params)); + ret.append((*i).str(_adapter, table_name(), params)); } return ret; } - virtual ~model() {} + virtual ~model() + { + if (_auto_delete_adapter) { + delete _adapter; + } + } - virtual const std::string & table_name() = 0; virtual const std::string& str() = 0; virtual const std::string& str(std::vector &) = 0; @@ -109,12 +133,15 @@ class model } void reset() { + _table_name.clear(); _where_condition.clear(); } protected: std::string _sql; - std::shared_ptr _adapter; + adapter * _adapter; + bool _auto_delete_adapter = false; + std::string _table_name; private: std::vector _where_condition; diff --git a/select_model.hpp b/select_model.hpp index 6bb6487..43ae262 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -57,7 +57,7 @@ class select_model : public model }; public: select_model() {} - select_model(std::shared_ptr adapter): model(adapter) {} + select_model(adapter * adapter): model(adapter) {} select_model(const select_model & m) : model(m) { _table_name = m._table_name; @@ -73,6 +73,12 @@ class select_model : public model _limit = m._limit; _offset = m._offset; } + select_model(adapter * adapter, const std::string & table_name) + : model(adapter, table_name) + {} + + select_model(const std::string & table_name) : model(table_name) + {} virtual ~select_model() {} @@ -195,11 +201,6 @@ class select_model : public model return *this; } - const std::string & table_name() - { - return _table_name; - } - const std::string& str() override { _sql.clear(); @@ -253,7 +254,7 @@ class select_model : public model if (size > 0) { ret.append(" ORDER BY "); for (size_t i = 0; i < size; ++i) { - ret.append(_order_by[i].str(_adapter.get(), _table_name)); + ret.append(_order_by[i].str(_adapter, _table_name)); if(i < size - 1) { ret.append(", "); } @@ -282,7 +283,7 @@ class select_model : public model ret.append(" ON "); auto ons = (*i).ons; for (auto j = ons.begin(); j != ons.end(); ++j) { - ret.append((*j).str(_adapter.get())); + ret.append((*j).str(_adapter)); } } @@ -327,7 +328,7 @@ class select_model : public model if(size > 0) { ret.append(" HAVING "); for(size_t i = 0; i < size; ++i) { - ret.append(_having_condition[i].str(_adapter.get(), _table_name)); + ret.append(_having_condition[i].str(_adapter, _table_name)); if(i < size - 1) { _sql.append(" "); } @@ -344,7 +345,7 @@ class select_model : public model if(size > 0) { ret.append(" GROUP BY "); for(size_t i = 0; i < size; ++i) { - ret.append(_groupby_columns[i].str(_adapter.get(), _table_name)); + ret.append(_groupby_columns[i].str(_adapter, _table_name)); if(i < size - 1) { ret.append(", "); } @@ -361,7 +362,7 @@ class select_model : public model int count = 0; for (auto i = _select.begin(); i != _select.end(); ++i) { count++; - ret.append((*i).str(_adapter.get(), _table_name)); + ret.append((*i).str(_adapter, _table_name)); if (count < _select.size()) { ret.append(", "); } @@ -376,7 +377,6 @@ class select_model : public model select_model& reset() { model::reset(); - _table_name.clear(); _select.clear(); _groupby_columns.clear(); _having_condition.clear(); @@ -385,6 +385,7 @@ class select_model : public model _offset.clear(); return *this; } + friend inline std::ostream& operator<< (std::ostream& out, select_model& mod) { out << mod.str(); return out; @@ -401,7 +402,6 @@ class select_model : public model } private: - std::string _table_name; std::vector _joins; std::vector _select; std::vector _groupby_columns; diff --git a/test/test.cpp b/test/test.cpp index 32264f9..96fa370 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -26,18 +26,18 @@ using namespace boosql; int main() { - std::shared_ptr a = std::make_shared(); + sqlite_adapter a; - select_model selector(a); - selector.from("users") - .select(col("*")) + select_model selector(&a, "users"); + + selector .select(col("*")) .where(boosql::col("hello")["%hello"]) // like .quote([](select_model & model) { model.where(col("id") != 1).or_where(col("id") != 2); }); - select_model group(a); + select_model group(&a, "group"); - group.from("group").select(col("a"), col("b"), col("c")).where(col("a") == 2); + group.select(col("a"), col("b"), col("c")).where(col("a") == 2); selector.left_join(group).on("hello")("=", col("a")).or_on("id")("=", col("b")).end(); @@ -50,21 +50,21 @@ int main() std::cout << selector.str() << std::endl; std::cout << another.str() << std::endl; - update_model updater(a); - updater.update("users")("hello", "hello")("world", "world").where(col("id") == 2); + update_model updater(&a, "users"); + updater("hello", "hello")("world", "world").where(col("id") == 2); update_model au(updater); au("helloworld", "helloworld"); std::cout << updater.str() << std::endl; std::cout << au.str() << std::endl; - delete_model deleter; + delete_model deleter(&a, "users"); // delete_model deleter(a); - deleter.from("users").where(col("id") == 1).or_where(col("name")["%hello"]); + deleter.where(col("id") == 1).or_where(col("name")["%hello"]); std::cout << deleter.str() << std::endl; - insert_model insert(a); - insert.into("users") + insert_model insert(&a, "users"); + insert ("id", 1) ("name", "hello") .next_row() diff --git a/update_model.hpp b/update_model.hpp index a8a5aa7..e95c078 100644 --- a/update_model.hpp +++ b/update_model.hpp @@ -11,12 +11,18 @@ class update_model : public model { public: update_model() {} - update_model(std::shared_ptr a) : model(a) {} + update_model(adapter * a) : model(a) {} update_model(const update_model & m) : model(m) { _columns = m._columns; _table_name = m._table_name; } + update_model(adapter * a, const std::string & table_name) + : model(a, table_name) + {} + update_model(const std::string & table_name) + : model(table_name) + {} update_model& update(const std::string& table_name) { _table_name = table_name; @@ -74,11 +80,6 @@ class update_model : public model return *this; } - virtual const std::string & table_name() - { - return _table_name; - } - const std::string& str() override { _sql.clear(); @@ -87,7 +88,7 @@ class update_model : public model _sql.append(" SET "); size_t size = _columns.size(); for(size_t i = 0; i < size; ++i) { - _sql.append(_columns[i].str(_adapter.get(), table_name())); + _sql.append(_columns[i].str(_adapter, table_name())); if(i < size - 1) { _sql.append(", "); } @@ -105,7 +106,7 @@ class update_model : public model _sql.append(" SET "); size_t size = _columns.size(); for(size_t i = 0; i < size; ++i) { - _sql.append(_columns[i].str(_adapter.get(), table_name(), params)); + _sql.append(_columns[i].str(_adapter, table_name(), params)); if(i < size - 1) { _sql.append(", "); } @@ -117,7 +118,6 @@ class update_model : public model update_model& reset() { model::reset(); - _table_name.clear(); _columns.clear(); return *this; } From a94eac78dffe7ba4432af7ee571c07f57125802c Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Wed, 10 Apr 2019 12:56:40 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- col.hpp | 15 ++++++++++++--- model.hpp | 23 ++++++++++++++++++----- select_model.hpp | 3 +-- test/test.cpp | 35 ++++++++++++++++++++++++++++++++--- 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/col.hpp b/col.hpp index 70d9561..5fb235a 100644 --- a/col.hpp +++ b/col.hpp @@ -9,15 +9,14 @@ namespace boosql class col { - typedef enum {field, value, other} witch; - +public: + enum witch {field, value, other}; struct item { public: witch type; std::string val; }; -public: col() {} col(const std::string & c) @@ -178,6 +177,16 @@ class col } } + bool empty() + { + return _items.empty(); + } + + const item & last() + { + return _items.back(); + } + col& operator &&(const std::string& condition) { quote_begin(); diff --git a/model.hpp b/model.hpp index e74c8a4..00d0655 100644 --- a/model.hpp +++ b/model.hpp @@ -30,6 +30,7 @@ class model _adapter = m._adapter->clone(); _auto_delete_adapter = true; + _table_name = m._table_name; _where_condition = m._where_condition; } @@ -100,35 +101,47 @@ class model void and_where(const std::string & condition) { _where_condition.push_back(col().o_and()); - where(condition); + _where_condition.push_back(col()(condition)); } void and_where(const col & condition) { _where_condition.push_back(col().o_and()); - where(condition); + _where_condition.push_back(condition); } void or_where(const std::string & condition) { _where_condition.push_back(col().o_or()); - where(condition); + _where_condition.push_back(col()(condition)); } void or_where(const col & condition) { _where_condition.push_back(col().o_or()); - where(condition); + _where_condition.push_back(condition); } template void quote(std::function callback, T& model) { - _where_condition.push_back(col().o_and()); + if (_where_condition.size() > 0) { + _where_condition.push_back(col().o_and()); + } _where_condition.push_back(col().quote_begin()); callback(model); _where_condition.push_back(col().quote_end()); } void where(const std::string& condition) { + if (_where_condition.size() > 0) { + _where_condition.push_back(col().o_and()); + } _where_condition.push_back(col()(condition)); } void where(const col& condition) { + int s = _where_condition.size(); + if (s > 0) { + col last = _where_condition.back(); + if (!last.empty() && last.last().val != "(") { + _where_condition.push_back(col().o_and()); + } + } _where_condition.push_back(condition); } void reset() diff --git a/select_model.hpp b/select_model.hpp index 43ae262..741b410 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -60,7 +60,6 @@ class select_model : public model select_model(adapter * adapter): model(adapter) {} select_model(const select_model & m) : model(m) { - _table_name = m._table_name; for (auto i = m._joins.begin(); i != m._joins.end(); ++i) { join_t join(*this, (*i).model); join.ons = (*i).ons; @@ -279,7 +278,7 @@ class select_model : public model ret.append(" INNER"); break; } - ret.append(" JOIN " + (*i).model.table_name()); + ret.append(" JOIN " + _adapter->quote_field((*i).model.table_name())); ret.append(" ON "); auto ons = (*i).ons; for (auto j = ons.begin(); j != ons.end(); ++j) { diff --git a/test/test.cpp b/test/test.cpp index 96fa370..36037d0 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -24,12 +24,10 @@ create table if not exists user ( using namespace boosql; -int main() +void test_select_join() { sqlite_adapter a; - select_model selector(&a, "users"); - selector .select(col("*")) .where(boosql::col("hello")["%hello"]) // like .quote([](select_model & model) { @@ -49,7 +47,26 @@ int main() std::cout << selector.str() << std::endl; std::cout << another.str() << std::endl; +} + +void test_select_where() +{ + sqlite_adapter a; + select_model s(&a, "users"); + s.select(col()("*")) + .where(col("hello") == "hello") + .where(col("world") == "world") + .or_where(col("hw") == "hw") + .quote([](select_model & s) { + s.where(col("a") != "1") + .or_where(col("b") == "1"); + }); + std::cout << s.str() << std::endl; +} +void test_update() +{ + sqlite_adapter a; update_model updater(&a, "users"); updater("hello", "hello")("world", "world").where(col("id") == 2); update_model au(updater); @@ -57,12 +74,20 @@ int main() std::cout << updater.str() << std::endl; std::cout << au.str() << std::endl; +} +void test_delete() +{ + sqlite_adapter a; delete_model deleter(&a, "users"); // delete_model deleter(a); deleter.where(col("id") == 1).or_where(col("name")["%hello"]); std::cout << deleter.str() << std::endl; +} +void test_insert() +{ + sqlite_adapter a; insert_model insert(&a, "users"); insert ("id", 1) @@ -72,6 +97,10 @@ int main() ("name", "world"); std::cout << insert.str() << std::endl; +} +int main() +{ + test_select_where(); return 0; } From 6fbf1c5435698a4c5c67e8e24ad271964473b827 Mon Sep 17 00:00:00 2001 From: yang-zhong Date: Fri, 12 Apr 2019 12:59:05 +0800 Subject: [PATCH 12/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- insert_model.hpp | 10 +++---- makefile | 6 ---- model.hpp | 1 + select_model.hpp | 74 ++++++++++++++++++++++++++++++++++++++++-------- test/test.cpp | 17 ++++++++++- 6 files changed, 85 insertions(+), 25 deletions(-) delete mode 100644 makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index 8112617..10d3108 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) include_directories(.) set(SQL_TEST_SRC test/test.cpp - adapter.hpp + adapter.hpp col.hpp insert_model.hpp delete_model.hpp diff --git a/insert_model.hpp b/insert_model.hpp index 21e4136..00865bd 100644 --- a/insert_model.hpp +++ b/insert_model.hpp @@ -53,7 +53,7 @@ class insert_model : public model } _fields = "("; auto size = _data.size(); - int count = 0; + unsigned count = 0; for (auto i = _data.begin(); i != _data.end(); ++i) { count++; _fields.append(col(i->first).str(adapter)); @@ -74,7 +74,7 @@ class insert_model : public model } _values = "("; auto size = _data.size(); - int count = 0; + unsigned count = 0; for (auto i = _data.begin(); i != _data.end(); ++i) { count++; _values.append(adapter->quote_value(i->second)); @@ -95,7 +95,7 @@ class insert_model : public model } _values = "("; auto size = _data.size(); - int count = 0; + unsigned count = 0; for (auto i = _data.begin(); i != _data.end(); ++i) { count++; _values.append(adapter->placeholder()); @@ -180,7 +180,7 @@ class insert_model : public model } _sql.append(_adapter->quote_field(_table_name)); auto size = _rows.size(); - int count = 0; + unsigned count = 0; for (auto i = _rows.begin(); i != _rows.end(); ++i) { count++; if (count == 1) { @@ -206,7 +206,7 @@ class insert_model : public model } _sql.append(_adapter->quote_field(_table_name)); auto size = _rows.size(); - int count = 0; + unsigned count = 0; for (auto i = _rows.begin(); i != _rows.end(); ++i) { count++; if (count == 1) { diff --git a/makefile b/makefile deleted file mode 100644 index eeca4a6..0000000 --- a/makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: - cd test && mkdir -p build && cd build && cmake .. && make && ctest -test: all - cd test/build && ./sql-test -clean: - rm -rf test/build diff --git a/model.hpp b/model.hpp index 00d0655..325d8a3 100644 --- a/model.hpp +++ b/model.hpp @@ -144,6 +144,7 @@ class model } _where_condition.push_back(condition); } + void reset() { _table_name.clear(); diff --git a/select_model.hpp b/select_model.hpp index 741b410..0df9a07 100644 --- a/select_model.hpp +++ b/select_model.hpp @@ -19,26 +19,38 @@ class select_model : public model join_t(select_model & selector, select_model & model) : _selector(selector), model(model) {} join_t & on(std::string main) + { + return on(main, _selector.table_ref()); + } + + join_t & on(std::string main, std::string table_name) { if (ons.size() > 0) { ons.push_back(col().o_and()); } - ons.push_back(col(main, _selector.table_name())); + + ons.push_back(col(main, table_name)); return *this; } + join_t & operator () (std::string oper, col second) { ons.push_back(col()(oper)); - ons.push_back(second.table_name(model.table_name())); + ons.push_back(second.table_name(model.table_ref())); return *this; } join_t & or_on(std::string main) + { + return or_on(main, _selector.table_ref()); + } + + join_t & or_on(std::string main, std::string table_name) { ons.push_back(col().o_or()); - ons.push_back(col(main, _selector.table_name())); + ons.push_back(col(main, table_name)); return *this; } @@ -97,11 +109,19 @@ class select_model : public model return *this; } - select_model& from(const std::string& table_name) { + select_model& from(const std::string& table_name) + { _table_name = table_name; return *this; } + select_model & from(select_model & m) + { + _from_model = &m; + _is_from_model = true; + return *this; + } + select_model& and_where(const std::string & condition) { model::and_where(condition); @@ -200,13 +220,38 @@ class select_model : public model return *this; } + std::string table_str() + { + if (_is_from_model) { + return "(" + _from_model->str() + ") __m__"; + } + return _table_name; + } + + std::string table_ref() + { + if (_is_from_model) { + return "__m__"; + } + + return _table_name; + } + + std::string table_str(std::vector & p) + { + if (_is_from_model) { + return "(" + _from_model->str(p) + ") __m__"; + } + return _table_name; + } + const std::string& str() override { _sql.clear(); _sql.append("SELECT "); _sql.append(select_str()); _sql.append(" FROM "); - _sql.append(_table_name); + _sql.append(table_str()); _sql.append(join_str()); append_where(); _sql.append(group_by_str()); @@ -229,7 +274,7 @@ class select_model : public model _sql.append("SELECT "); _sql.append(select_str()); _sql.append(" FROM "); - _sql.append(_table_name); + _sql.append(table_str(params)); _sql.append(join_str()); append_where(params); _sql.append(group_by_str()); @@ -253,7 +298,7 @@ class select_model : public model if (size > 0) { ret.append(" ORDER BY "); for (size_t i = 0; i < size; ++i) { - ret.append(_order_by[i].str(_adapter, _table_name)); + ret.append(_order_by[i].str(_adapter, table_ref())); if(i < size - 1) { ret.append(", "); } @@ -327,7 +372,7 @@ class select_model : public model if(size > 0) { ret.append(" HAVING "); for(size_t i = 0; i < size; ++i) { - ret.append(_having_condition[i].str(_adapter, _table_name)); + ret.append(_having_condition[i].str(_adapter, table_ref())); if(i < size - 1) { _sql.append(" "); } @@ -344,7 +389,7 @@ class select_model : public model if(size > 0) { ret.append(" GROUP BY "); for(size_t i = 0; i < size; ++i) { - ret.append(_groupby_columns[i].str(_adapter, _table_name)); + ret.append(_groupby_columns[i].str(_adapter, table_ref())); if(i < size - 1) { ret.append(", "); } @@ -358,16 +403,18 @@ class select_model : public model std::string select_str() { std::string ret = ""; - int count = 0; + unsigned count = 0; for (auto i = _select.begin(); i != _select.end(); ++i) { count++; - ret.append((*i).str(_adapter, _table_name)); + ret.append((*i).str(_adapter, table_ref())); if (count < _select.size()) { ret.append(", "); } } for (auto i = _joins.begin(); i != _joins.end(); ++i) { - ret.append(", "); + if (ret.length() > 0) { + ret.append(", "); + } ret.append((*i).model.select_str()); } @@ -408,6 +455,9 @@ class select_model : public model std::vector _order_by; std::string _limit; std::string _offset; + bool _is_from_model = false; + + select_model * _from_model; }; } diff --git a/test/test.cpp b/test/test.cpp index 36037d0..cf07944 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -64,6 +64,21 @@ void test_select_where() std::cout << s.str() << std::endl; } +void test_select_from_select() +{ + sqlite_adapter a; + select_model from(&a, "users"); + from.select(col("a"), col("b")) + .where(col("a") == 0) + .order_by(col("b")("ASC")); + + select_model s(&a); + s.from(from) + .select(col("a"), col("b")); + + std::cout << s.str() << std::endl; +} + void test_update() { sqlite_adapter a; @@ -101,6 +116,6 @@ void test_insert() int main() { - test_select_where(); + test_select_from_select(); return 0; }