diff --git a/CHANGELOG.md b/CHANGELOG.md index e2bd9a0..3dadad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # wsjcpp-sql-builder Changelog +## [v0.2.0] - 2026-01-31 (2026 Jan 31) + +- Implemented a select, update, insert, delete with chain concept + ## [v0.1.0] - 2025-08-10 (2025 Aug 10) - Added first implementation from fhq-server diff --git a/README.md b/README.md index 7b2d3a3..462151a 100644 --- a/README.md +++ b/README.md @@ -23,21 +23,32 @@ Example main func: #include int main(int argc, const char* argv[]) { - WsjcppSqlBuilderInsert sql("TABLE_NAME"); - sql.add("COL1", "val1"); // will be escaped - sql.add("COL2", 1); - // sql.add("COL3", 1.1); - if (!sql.isValid()) { - std::cerr << "Something wrong with query: " << sql.getErrorMessage() << std::endl; - return -1; - } - std::cout << sql.getTextQuery() << std::endl; - return 0; + wsjcpp::SqlBuilder builder; + builder.selectFrom("table1") + .colum("col1") + .colum("col2", "c3") + .colum("col3") + .colum("col4") + .where() + .equal("col1", "1") + .or_() + .notEqual("col2", "2") + .or_() + .subCondition() + .equal("c3", "4") + // .and_() // be default must be added and + .equal("col2", "5") + .finishSubCondition() + .or_() + .lessThen("col4", 111) + .endWhere() // need only for groupBy havingBy and etc + ; + std::cout << builder.sql() << std::endl; } ``` Example output: ``` $ ./wsjcpp-sql-builder -INSERT INTO TABLE_NAME(COL1, COL2) VALUES ('val1', 1); +SELECT col1, col2 AS c3, col3, col4 FROM table1 WHERE col1 = '1' OR col2 <> '2' OR (c3 = '4' AND col2 = '5') OR col4 < 111 ``` \ No newline at end of file diff --git a/src.wsjcpp/CMakeLists.txt b/src.wsjcpp/CMakeLists.txt index c2e2bc6..21689d4 100644 --- a/src.wsjcpp/CMakeLists.txt +++ b/src.wsjcpp/CMakeLists.txt @@ -1,7 +1,7 @@ -# Automaticly generated by wsjcpp@v0.2.5 +# Automaticly generated by wsjcpp@v0.2.7 cmake_minimum_required(VERSION 3.0) -add_definitions(-DWSJCPP_APP_VERSION="v0.1.0") +add_definitions(-DWSJCPP_APP_VERSION="v0.2.0") add_definitions(-DWSJCPP_APP_NAME="wsjcpp-sql-builder") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/src/main.cpp b/src/main.cpp index 906955c..606d8b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,21 +2,21 @@ #include int main(int argc, const char* argv[]) { - WsjcppSqlBuilderInsert sql("TABLE_NAME"); - sql.add("COL1", "val1"); // will be escaped - sql.add("COL2", 1); - // sql.add("COL3", 1.1); - if (!sql.isValid()) { - std::cerr << "Something wrong with query: " << sql.getErrorMessage() << std::endl; - return -1; - } + // WsjcppSqlBuilderInsert sql("TABLE_NAME"); + // sql.add("COL1", "val1"); // will be escaped + // sql.add("COL2", 1); + // // sql.add("COL3", 1.1); + // if (!sql.isValid()) { + // std::cerr << "Something wrong with query: " << sql.getErrorMessage() << std::endl; + // return -1; + // } - std::string expectedIns = "INSERT INTO TABLE_NAME(COL1, COL2) VALUES ('val1', 1);"; - if (expectedIns != sql.getTextQuery()) { - std::cerr << "Expeceted sql: " << expectedIns << ", but got " << sql.getTextQuery() << std::endl; - return -1; - } - std::cout << sql.getTextQuery() << std::endl; + // std::string expectedIns = "INSERT INTO TABLE_NAME(COL1, COL2) VALUES ('val1', 1);"; + // if (expectedIns != sql.getTextQuery()) { + // std::cerr << "Expeceted sql: " << expectedIns << ", but got " << sql.getTextQuery() << std::endl; + // return -1; + // } + // std::cout << sql.getTextQuery() << std::endl; return 0; } diff --git a/src/tests/test_delete.cpp b/src/tests/test_delete.cpp new file mode 100644 index 0000000..f5d3ac9 --- /dev/null +++ b/src/tests/test_delete.cpp @@ -0,0 +1,65 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2025-2026 Evgenii Sopov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + *all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Official Source Code: https://github.com/wsjcpp/wsjcpp-sql-builder + * + ***********************************************************************************/ + +#include +#include + +int main() { + wsjcpp::SqlBuilder builder; + builder.deleteFrom("table4") + .where() + .equal("col1", "1") + .or_() + .notEqual("col2", "2") + .or_() + .subCondition() + .equal("c3", "4") + // .and_() // be default must be added and + .equal("col2", "5") + .finishSubCondition() + .or_() + .lessThen("col4", 111) + ; + + if (builder.hasErrors()) { + std::cerr << "Select builder has some errors" << std::endl; + return -1; + } + std::string sqlQuery = builder.sql(); + std::string sqlQueryExpected = "DELETE FROM table4 WHERE col1 = '1' OR col2 <> '2' OR (c3 = '4' AND col2 = '5') OR col4 < 111"; + if (sqlQuery != sqlQueryExpected) { + std::cerr + << "Expected:" << std::endl + << " {" << sqlQueryExpected << "}" << std::endl + << ", but got:" << std::endl + << " {" << sqlQuery << "}" << std::endl + ; + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/src/tests/test_insert.cpp b/src/tests/test_insert.cpp index d0a750e..8ac6ecf 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -29,16 +29,49 @@ #include int main() { - WsjcppSqlBuilderInsert sql("TABLE_NAME"); - sql.add("COL1", "val1"); // will be escaped - sql.add("COL2", 1); - // sql.add("COL3", 1.1); - if (!sql.isValid()) { - std::cerr << "Something wrong with query: " << sql.getErrorMessage() << std::endl; - return -1; - } - if (sql.getTextQuery() != "INSERT INTO TABLE_NAME(COL1, COL2) VALUES ('val1', 1);") { - return -1; - } - return 0; + wsjcpp::SqlBuilder builder; + builder.insertInto("table2") + .colum("col1") + .addColums({"col2", "col3"}) + .val("val1") + .val(1) + .val(2.0) + ; + + if (builder.hasErrors()) { + std::cerr << "Select builder has some errors" << std::endl; + return -1; + } + std::string sqlQuery = builder.sql(); + std::string sqlQueryExpected = "INSERT INTO table2(col1, col2, col3) VALUES('val1', 1, 2.000000)"; + if (sqlQuery != sqlQueryExpected) { + std::cerr + << "Expected:" << std::endl + << " {" << sqlQueryExpected << "}" << std::endl + << ", but got:" << std::endl + << " {" << sqlQuery << "}" << std::endl + ; + return -1; + } + + builder.findInsertOrCreate("table2") + .clearValues() + .val("val2") + .val(2) + .val(10.0) + ; + + sqlQuery = builder.sql(); + sqlQueryExpected = "INSERT INTO table2(col1, col2, col3) VALUES('val2', 2, 10.000000)"; + if (sqlQuery != sqlQueryExpected) { + std::cerr + << "Expected:" << std::endl + << " {" << sqlQueryExpected << "}" << std::endl + << ", but got:" << std::endl + << " {" << sqlQuery << "}" << std::endl + ; + return -1; + } + + return 0; } \ No newline at end of file diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp new file mode 100644 index 0000000..ccafea5 --- /dev/null +++ b/src/tests/test_select.cpp @@ -0,0 +1,82 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2025-2026 Evgenii Sopov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + *all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Official Source Code: https://github.com/wsjcpp/wsjcpp-sql-builder + * + ***********************************************************************************/ + +#include +#include + +int main() { + wsjcpp::SqlBuilder builder; + builder.selectFrom("table1") + .colum("col1") + .colum("col2", "c3") + .colum("col3") + .colum("col4") + .where() + .equal("col1", "1") + .or_() + .notEqual("col2", "2") + .or_() + .subCondition() + .equal("c3", "4") + // .and_() // be default must be added and + .equal("col2", "5") + .finishSubCondition() + .or_() + .lessThen("col4", 111) + .endWhere() // need only for groupBy havingBy and etc + ; + if (builder.hasErrors()) { + std::cerr << "Select builder has some errors" << std::endl; + return -1; + } + std::string sqlQuery = builder.sql(); + std::string sqlQueryExpected = + "SELECT col1, col2 AS c3, col3, col4 " + "FROM table1 " + "WHERE col1 = '1' OR col2 <> '2' OR (c3 = '4' AND col2 = '5') OR col4 < 111"; + if (sqlQuery != sqlQueryExpected) { + std::cerr + << "Expected:" << std::endl + << " " << sqlQueryExpected << std::endl + << ", but got:" << std::endl + << " " << sqlQuery << std::endl + ; + return -1; + } + + builder.clear(); + sqlQuery = builder.sql(); + if (sqlQuery != "") { + std::cerr + << "Expected empty, but got: " << std::endl + << " " << sqlQuery << std::endl + ; + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/src/tests/test_update.cpp b/src/tests/test_update.cpp new file mode 100644 index 0000000..bdbfe77 --- /dev/null +++ b/src/tests/test_update.cpp @@ -0,0 +1,68 @@ +/********************************************************************************** + * MIT License + * + * Copyright (c) 2025-2026 Evgenii Sopov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + *all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Official Source Code: https://github.com/wsjcpp/wsjcpp-sql-builder + * + ***********************************************************************************/ + +#include +#include + +int main() { + wsjcpp::SqlBuilder builder; + builder.update("table3") + .set("col1", "val uuu") + .set("col2", 1) + .set("col3", 1.000) + .where() + .equal("col1", "1") + .or_() + .notEqual("col2", "2") + .or_() + .subCondition() + .equal("c3", "4") + // .and_() // be default must be added and + .equal("col2", "5") + .finishSubCondition() + .or_() + .lessThen("col4", 111) + ; + + if (builder.hasErrors()) { + std::cerr << "Select builder has some errors" << std::endl; + return -1; + } + std::string sqlQuery = builder.sql(); + std::string sqlQueryExpected = "UPDATE table3 SET col1 = 'val uuu', col2 = 1, col3 = 1.000000 WHERE col1 = '1' OR col2 <> '2' OR (c3 = '4' AND col2 = '5') OR col4 < 111"; + if (sqlQuery != sqlQueryExpected) { + std::cerr + << "Expected:" << std::endl + << " {" << sqlQueryExpected << "}" << std::endl + << ", but got:" << std::endl + << " {" << sqlQuery << "}" << std::endl + ; + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index f94f12c..85d6b97 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -26,262 +26,469 @@ ***********************************************************************************/ #include "wsjcpp_sql_builder.h" +#include + + +namespace wsjcpp { // --------------------------------------------------------------------- -// WsjcppSqlBuilder - -WsjcppSqlBuilder::WsjcppSqlBuilder(WsjcppSqlBuilderType nSqlType, - const std::string &sSqlTable) { - m_nSqlType = nSqlType; - m_sSqlTable = sSqlTable; - m_bValid = true; - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sSqlQuery0 = "SELECT "; - m_sSqlQuery1 = " FROM " + sSqlTable; - m_sSqlQuery2 = ""; - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sSqlQuery0 = "INSERT INTO " + sSqlTable + "("; - m_sSqlQuery1 = ") VALUES ("; - m_sSqlQuery2 = ");"; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery0 = "UPDATE " + sSqlTable + " SET "; - m_sSqlQuery1 = " WHERE "; - } else { - m_sErrorMessage = "Unknown sql type"; - m_bValid = false; +// WsjcppSqlBuilderHelpers + +std::string WsjcppSqlBuilderHelpers::escapingStringValue(const std::string &sValue) { + // escaping simbols NUL (ASCII 0), \n, \r, \, ', ", и Control-Z. + std::string sResult; + sResult.reserve(sValue.size() * 2); + sResult.push_back('\''); + for (int i = 0; i < sValue.size(); i++) { + char c = sValue[i]; + if (c == '\n') { + sResult.push_back('\\'); + sResult.push_back('n'); + } else if (c == '\r') { + sResult.push_back('\\'); + sResult.push_back('r'); + } else if (c == '\\' || c == '"') { + sResult.push_back('\\'); + sResult.push_back(c); + } else if (c == '\'') { + sResult.push_back('\''); + sResult.push_back(c); + } else if (c == 0) { + sResult.push_back('\\'); + sResult.push_back('0'); + } else { + sResult.push_back(c); + } + } + sResult.push_back('\''); + return sResult; +} + + +WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlQueryType sqlType, SqlBuilder *builder, const std::string &tableName) + : m_sqlType(sqlType), m_builder(builder), m_tableName(tableName) { + +} + +WsjcppSqlQueryType WsjcppSqlQuery::sqlType() { + return m_sqlType; +} + +SqlBuilder &WsjcppSqlQuery::builder() { + return *m_builder; +} + +SqlBuilder *WsjcppSqlQuery::builderRawPtr() { + return m_builder; +} + +const std::string &WsjcppSqlQuery::tableName() { + return m_tableName; +} + +// --------------------------------------------------------------------- +// WsjcppSqlWhereBase + +WsjcppSqlWhereBase::WsjcppSqlWhereBase(WsjcppSqlWhereType type) : m_type(type) { + +}; + +WsjcppSqlWhereType WsjcppSqlWhereBase::type() { + return m_type; +} + +// --------------------------------------------------------------------- +// WsjcppSqlWhereOr + +WsjcppSqlWhereOr::WsjcppSqlWhereOr() : WsjcppSqlWhereBase(WsjcppSqlWhereType::LOGICAL_OPERATOR) { } +std::string WsjcppSqlWhereOr::sql() { return " OR "; }; + +// --------------------------------------------------------------------- +// WsjcppSqlWhereAnd + +WsjcppSqlWhereAnd::WsjcppSqlWhereAnd() : WsjcppSqlWhereBase(WsjcppSqlWhereType::LOGICAL_OPERATOR) { } +std::string WsjcppSqlWhereAnd::sql() { return " AND "; }; + +// --------------------------------------------------------------------- +// WsjcppSqlWhereCondition + +WsjcppSqlWhereCondition::WsjcppSqlWhereCondition( + const std::string &name, + WsjcppSqlWhereConditionType comparator, + const std::string &value +) : WsjcppSqlWhereBase(WsjcppSqlWhereType::CONDITION), m_name(name), m_comparator(comparator) { + // TODO in different databases different quotes, mssql have a column names in double quotes + m_value = WsjcppSqlBuilderHelpers::escapingStringValue(value); +} + +WsjcppSqlWhereCondition::WsjcppSqlWhereCondition( + const std::string &name, + WsjcppSqlWhereConditionType comparator, + int value +) : WsjcppSqlWhereBase(WsjcppSqlWhereType::CONDITION), m_name(name), m_comparator(comparator) { + m_value = std::to_string(value); +} + +WsjcppSqlWhereCondition::WsjcppSqlWhereCondition( + const std::string &name, + WsjcppSqlWhereConditionType comparator, + double value +) : WsjcppSqlWhereBase(WsjcppSqlWhereType::CONDITION), m_name(name), m_comparator(comparator) { + m_value = std::to_string(value); +} + +WsjcppSqlWhereCondition::WsjcppSqlWhereCondition( + const std::string &name, + WsjcppSqlWhereConditionType comparator, + float value +) : WsjcppSqlWhereBase(WsjcppSqlWhereType::CONDITION), m_name(name), m_comparator(comparator) { + m_value = std::to_string(value); +} + +const std::string &WsjcppSqlWhereCondition::name() { + return m_name; +} + +WsjcppSqlWhereConditionType WsjcppSqlWhereCondition::comparator() { + return m_comparator; +} + +const std::string &WsjcppSqlWhereCondition::value() { + return m_value; +} + +std::string WsjcppSqlWhereCondition::sql() { + std::string ret; + ret += m_name; // TODO validate and escaping + switch (m_comparator) { + case WsjcppSqlWhereConditionType::NOT_EQUAL: + ret += " <> "; + break; + case WsjcppSqlWhereConditionType::EQUAL: + ret += " = "; + break; + case WsjcppSqlWhereConditionType::MORE_THEN: + ret += " > "; + break; + case WsjcppSqlWhereConditionType::LESS_THEN: + ret += " < "; + break; + case WsjcppSqlWhereConditionType::LIKE: + ret += " LIKE "; + break; + default: + ret += " unknwon_operator "; + break; } + ret += m_value; + return ret; +} + +// --------------------------------------------------------------------- +// WsjcppSqlSelect + +WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, SqlBuilder *builder) +: WsjcppSqlQuery(WsjcppSqlQueryType::SELECT, builder, tableName) { + // TODO multitype table names with AS } -bool WsjcppSqlBuilder::sel(const std::string &sColumnName) { - if (!checkName(sColumnName)) { - return false; +WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col, const std::string &col_as) { + auto it = std::find(m_columns.begin(), m_columns.end(), col); + if (it != m_columns.end()) { + builder().addError("Column '" + col + "' already added to select"); + } else { + m_columns.push_back(col); + m_columns_as[col] = col_as; } - m_sSqlQuery0 += sColumnName + ", "; - return true; + return *this; } -bool WsjcppSqlBuilder::add(const std::string &sColumnName, - const std::string &sValue) { - if (!checkName(sColumnName)) { - return false; +WsjcppSqlWhere &WsjcppSqlSelect::where() { + if (!m_where) { + m_where = std::make_shared>(nullptr, builderRawPtr(), this); } - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sErrorMessage = "For select you could not use 'add'"; - m_bValid = false; - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sSqlQuery0 += sColumnName + ", "; - m_sSqlQuery1 += prepareStringValue(sValue) + ", "; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery0 += sColumnName + " = " + prepareStringValue(sValue); + return *(m_where.get()); +} + +std::string WsjcppSqlSelect::sql() { + std::string ret = "SELECT "; + // TODO TOP OR LIMIT for different databases + + if (m_columns.size() == 0) { + ret += "*"; } else { - m_sErrorMessage = "Unknown sql type"; - m_bValid = false; + bool first = true; + for (auto col : m_columns) { + if (!first) { + ret += ", "; + } + ret += col; + if (m_columns_as[col] != "") { + ret += " AS " + m_columns_as[col]; + } + first = false; + } + ret += " FROM "; + ret += tableName(); } - // m_sSqlQuery = sBefore + sEscapedValue + sAfter; + if (m_where) { + ret += " WHERE " + m_where->sql(); + } - // while (true) { - // /* Locate the substring to replace. */ - // index = str.find(sName, index); - // if (index == std::string::npos) - // return false; + // TODO group by + // TODO order by + return ret; +} + +// --------------------------------------------------------------------- +// WsjcppSqlInsert - // /* Make the replacement. */ - // str.replace(index, 3, "def"); +WsjcppSqlInsert::WsjcppSqlInsert(const std::string &tableName, SqlBuilder *builder) +: WsjcppSqlQuery(WsjcppSqlQueryType::INSERT, builder, tableName) { - // /* Advance index forward so the next iteration doesn't pick it up as - // well. */ index += 3; - // } - return true; } -bool WsjcppSqlBuilder::add(const std::string &sColumnName, int nValue) { - if (!checkName(sColumnName)) { - return false; - } +WsjcppSqlInsert &WsjcppSqlInsert::colum(const std::string &col) { + m_columns.push_back(col); + return *this; +} - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sErrorMessage = "For select you could not use 'add'"; - m_bValid = false; - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sSqlQuery0 += sColumnName + ", "; - m_sSqlQuery1 += std::to_string(nValue) + ", "; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery0 += sColumnName + " = " + std::to_string(nValue); +WsjcppSqlInsert &WsjcppSqlInsert::addColums(const std::vector &cols) { + for (auto col : cols) { + m_columns.push_back(col); } + return *this; +} - return true; +WsjcppSqlInsert &WsjcppSqlInsert::clearValues() { + m_values.clear(); + return *this; } -bool WsjcppSqlBuilder::add(const std::string &sColumnName, long nValue) { - if (!checkName(sColumnName)) { - return false; +WsjcppSqlInsert &WsjcppSqlInsert::val(const std::string &val) { + m_values.push_back(WsjcppSqlBuilderHelpers::escapingStringValue(val)); + return *this; +} + +WsjcppSqlInsert &WsjcppSqlInsert::val(int val) { + m_values.push_back(std::to_string(val)); + return *this; +} + +WsjcppSqlInsert &WsjcppSqlInsert::val(float val) { + m_values.push_back(std::to_string(val)); + return *this; +} + +WsjcppSqlInsert &WsjcppSqlInsert::val(double val) { + m_values.push_back(std::to_string(val)); + return *this; +} + +std::string WsjcppSqlInsert::sql() { + std::string ret = "INSERT INTO " + tableName(); + + // TODO if columns is empty + ret += "("; + bool first = true; + for (auto col : m_columns) { + if (!first) { + ret += ", "; + } + ret += col; + first = false; } + ret += ")"; - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sErrorMessage = "For select you could not use 'add'"; - m_bValid = false; - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sSqlQuery0 += sColumnName + ", "; - m_sSqlQuery1 += std::to_string(nValue) + ", "; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery0 += sColumnName + " = " + std::to_string(nValue); + ret += " VALUES("; + first = true; + for (auto val : m_values) { + if (!first) { + ret += ", "; + } + ret += val; + first = false; } + ret += ")"; + + return ret; +}; + +// --------------------------------------------------------------------- +// WsjcppSqlUpdate + +WsjcppSqlUpdate::WsjcppSqlUpdate(const std::string &tableName, SqlBuilder *builder) + : WsjcppSqlQuery(WsjcppSqlQueryType::UPDATE, builder, tableName) { - return true; } -bool WsjcppSqlBuilder::where(const std::string &sColumnName, - const std::string &sValue) { - if (!checkName(sColumnName)) { - return false; - } - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sSqlQuery2 += sColumnName + " = " + prepareStringValue(sValue); - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sErrorMessage = "where can be in insert"; - return false; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery1 += sColumnName + " = " + prepareStringValue(sValue); +WsjcppSqlUpdate &WsjcppSqlUpdate::set(const std::string &name, const std::string &val) { + return setValue(name, WsjcppSqlBuilderHelpers::escapingStringValue(val)); +} + +WsjcppSqlUpdate &WsjcppSqlUpdate::set(const std::string &name, int val) { + return setValue(name, std::to_string(val)); +} + +WsjcppSqlUpdate &WsjcppSqlUpdate::set(const std::string &name, float val) { + return setValue(name, std::to_string(val)); +} + +WsjcppSqlUpdate &WsjcppSqlUpdate::set(const std::string &name, double val) { + return setValue(name, std::to_string(val)); +} + +WsjcppSqlUpdate &WsjcppSqlUpdate::setValue(const std::string &name, const std::string &val) { + auto it = std::find(m_columns.begin(), m_columns.end(), name); + if (it != m_columns.end()) { + m_values[name] = val; + // builder().addError("Column '" + name + "' already added to select"); + } else { + m_columns.push_back(name); + m_values[name] = val; } + return *this; +} - return true; +WsjcppSqlWhere &WsjcppSqlUpdate::where() { + if (!m_where) { + m_where = std::make_shared>(nullptr, builderRawPtr(), this); + } + return *(m_where.get()); } -bool WsjcppSqlBuilder::where(const std::string &sColumnName, int nValue) { - if (!checkName(sColumnName)) { - return false; +std::string WsjcppSqlUpdate::sql() { + std::string ret = "UPDATE " + tableName() + " SET "; + + // TODO if columns is empty + bool first = true; + for (auto col : m_columns) { + if (!first) { + ret += ", "; + } + ret += col + " = " + m_values[col]; + first = false; } - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sSqlQuery2 += sColumnName + " = " + std::to_string(nValue); - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sErrorMessage = "where can be in insert"; - return false; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery1 += sColumnName + " = " + std::to_string(nValue); + + if (m_where) { + ret += " WHERE " + m_where->sql(); } - return true; + + return ret; +}; + + +// --------------------------------------------------------------------- +// WsjcppSqlDelete + +WsjcppSqlDelete::WsjcppSqlDelete(const std::string &tableName, SqlBuilder *builder) + : WsjcppSqlQuery(WsjcppSqlQueryType::DELETE, builder, tableName) { + } -bool WsjcppSqlBuilder::where(const std::string &sColumnName, long nValue) { - if (!checkName(sColumnName)) { - return false; +WsjcppSqlWhere &WsjcppSqlDelete::where() { + if (!m_where) { + m_where = std::make_shared>(nullptr, builderRawPtr(), this); } - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sSqlQuery2 += sColumnName + " = " + std::to_string(nValue); - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - m_sErrorMessage = "where can be in insert"; - return false; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery1 += sColumnName + " = " + std::to_string(nValue); + return *(m_where.get()); +} + +std::string WsjcppSqlDelete::sql() { + std::string ret = "DELETE FROM " + tableName(); + + if (m_where) { + ret += " WHERE " + m_where->sql(); } - return true; -} - -std::string WsjcppSqlBuilder::getTextQuery() { - std::string sSqlQuery = ""; - size_t size0 = m_sSqlQuery0.size(); - size_t size1 = m_sSqlQuery1.size(); - size_t size2 = m_sSqlQuery2.size(); - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - // TODO refactor this to vector and join - sSqlQuery = m_sSqlQuery0; - if (size0 > 2 && m_sSqlQuery0[size0 - 1] == ' ' && - m_sSqlQuery0[size0 - 2] == ',') { - sSqlQuery += m_sSqlQuery0.substr(0, size0 - 2); - } - sSqlQuery += m_sSqlQuery1; - if (size2 > 2 && m_sSqlQuery2[size2 - 1] == ' ' && - m_sSqlQuery2[size2 - 2] == ',') { - sSqlQuery += m_sSqlQuery2.substr(0, size2 - 2); - } - } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { - if (size0 > 2 && m_sSqlQuery0[size0 - 1] == ' ' && - m_sSqlQuery0[size0 - 2] == ',') { - sSqlQuery += m_sSqlQuery0.substr(0, size0 - 2); - } - if (size1 > 2 && m_sSqlQuery1[size1 - 1] == ' ' && - m_sSqlQuery1[size1 - 2] == ',') { - sSqlQuery += m_sSqlQuery1.substr(0, size1 - 2); + + return ret; +}; + +// --------------------------------------------------------------------- +// SqlBuilder + +SqlBuilder::SqlBuilder(WsjcppSqlBuilderForDatabase dbType) : m_dbType(dbType) { + +} + +WsjcppSqlSelect &SqlBuilder::selectFrom(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + // TODO check must be select last one; + return *(WsjcppSqlSelect *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlInsert &SqlBuilder::insertInto(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + return *(WsjcppSqlInsert *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlInsert &SqlBuilder::findInsertOrCreate(const std::string &tableName) { + for (auto query : m_queries) { + if (query->sqlType() == WsjcppSqlQueryType::INSERT && query->tableName() == tableName) { + return *(WsjcppSqlInsert *)(query.get()); } - sSqlQuery += m_sSqlQuery2; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - sSqlQuery = m_sSqlQuery0 + m_sSqlQuery1 + m_sSqlQuery2; } - return sSqlQuery; + return insertInto(tableName); } -bool WsjcppSqlBuilder::isValid() { return m_bValid; } - -std::string WsjcppSqlBuilder::getErrorMessage() { return m_sErrorMessage; } +WsjcppSqlUpdate &SqlBuilder::update(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + return *(WsjcppSqlUpdate *)(m_queries[m_queries.size() -1].get()); +} -bool WsjcppSqlBuilder::checkName(const std::string &sColumnName) { - if (sColumnName.size() < 2) { - m_sErrorMessage = - "Parameter '" + sColumnName + "' must more than 2 characters"; - m_bValid = false; - return false; +WsjcppSqlUpdate &SqlBuilder::findUpdateOrCreate(const std::string &tableName) { + for (auto query : m_queries) { + if (query->sqlType() == WsjcppSqlQueryType::UPDATE && query->tableName() == tableName) { + return *(WsjcppSqlUpdate *)(query.get()); + } } - // TODO check alphabet - - // if (sName[0] != ':') { - // m_sErrorMessage = "Parameter '" + sName + "' must starts with ':'"; - // m_bValid = false; - // return false; - // } - // nIndex = m_sSqlQuery.find(sName, 0); - // if (nIndex == std::string::npos) { - // m_sErrorMessage = "Not found '" + sName + "' in " + m_sSqlQuery; - // m_bValid = false; - // return false; - // } - return true; -} - -std::string WsjcppSqlBuilder::prepareStringValue(const std::string &sValue) { - // escaping simbols NUL (ASCII 0), \n, \r, \, ', ", и Control-Z. - std::string sResult; - sResult.reserve(sValue.size() * 2); - sResult.push_back('\''); - for (int i = 0; i < sValue.size(); i++) { - char c = sValue[i]; - if (c == '\n') { - sResult.push_back('\\'); - sResult.push_back('n'); - } else if (c == '\r') { - sResult.push_back('\\'); - sResult.push_back('r'); - } else if (c == '\\' || c == '"') { - sResult.push_back('\\'); - sResult.push_back(c); - } else if (c == '\'') { - sResult.push_back('\''); - sResult.push_back(c); - } else if (c == 0) { - sResult.push_back('\\'); - sResult.push_back('0'); - } else { - sResult.push_back(c); + return update(tableName); +} + +WsjcppSqlDelete &SqlBuilder::deleteFrom(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + return *(WsjcppSqlDelete *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlDelete &SqlBuilder::findDeleteOrCreate(const std::string &tableName) { + for (auto query : m_queries) { + if (query->sqlType() == WsjcppSqlQueryType::DELETE && query->tableName() == tableName) { + return *(WsjcppSqlDelete *)(query.get()); } } - sResult.push_back('\''); - return sResult; + return deleteFrom(tableName); } -// --------------------------------------------------------------------- -// WsjcppSqlBuilderSelect +void SqlBuilder::clear() { + m_queries.clear(); +} -WsjcppSqlBuilderSelect::WsjcppSqlBuilderSelect(const std::string &sSqlTable) - : WsjcppSqlBuilder(WsjcppSqlBuilderType::SELECT, sSqlTable) {} +bool SqlBuilder::hasErrors() { + return m_errors.size() > 0; +} -// --------------------------------------------------------------------- -// WsjcppSqlBuilderInsert +void SqlBuilder::addError(const std::string &err) { + m_errors.push_back(err); +} -WsjcppSqlBuilderInsert::WsjcppSqlBuilderInsert(const std::string &sSqlTable) - : WsjcppSqlBuilder(WsjcppSqlBuilderType::INSERT, sSqlTable) {} +std::string SqlBuilder::sql() { + std::string ret = ""; + for (auto query : m_queries) { + if (ret.size() > 0) { + ret += "\n"; + } + ret += query->sql(); + } + return ret; +} -// --------------------------------------------------------------------- -// WsjcppSqlBuilderUpdate -WsjcppSqlBuilderUpdate::WsjcppSqlBuilderUpdate(const std::string &sSqlTable) - : WsjcppSqlBuilder(WsjcppSqlBuilderType::UPDATE, sSqlTable) {} +void SqlBuilder::setDatabaseType(WsjcppSqlBuilderForDatabase dbType) { + m_dbType = dbType; +} + +WsjcppSqlBuilderForDatabase SqlBuilder::databaseType() { + return m_dbType; +} + +} // namespace wsjcpp diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 1a5f804..48f2add 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -29,50 +29,343 @@ #include #include +#include +#include -enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE }; +namespace wsjcpp { -class WsjcppSqlBuilder { +enum class WsjcppSqlQueryType { + SELECT, + INSERT, + UPDATE, + DELETE, +}; + +enum class WsjcppSqlWhereType { + LOGICAL_OPERATOR, + CONDITION, + SUB_CONDITION, +}; + +enum class WsjcppSqlWhereConditionType { + NOT_EQUAL, + EQUAL, + MORE_THEN, + LESS_THEN, + LIKE, +}; + +enum class WsjcppSqlBuilderForDatabase { + SQLITE3, +}; + +class WsjcppSqlBuilderHelpers { +public: + static std::string escapingStringValue(const std::string &sValue); +}; + +class SqlBuilder; +class WsjcppSqlQuery; +class WsjcppSqlInsert; +class WsjcppSqlUpdate; +class WsjcppSqlSelect; +class WsjcppSqlDelete; +template class WsjcppSqlWhere; + +class IWsjcppSqlBuilder { +public: + + virtual bool hasErrors() = 0; + virtual std::string sql() = 0; + virtual void setDatabaseType(WsjcppSqlBuilderForDatabase dbType) = 0; + virtual WsjcppSqlBuilderForDatabase databaseType() = 0; + +protected: + friend WsjcppSqlWhere; + friend WsjcppSqlWhere; + friend WsjcppSqlWhere; + friend WsjcppSqlWhere; + friend WsjcppSqlQuery; + virtual void addError(const std::string &err) = 0; +}; + + + +class WsjcppSqlQuery { +public: + WsjcppSqlQuery(WsjcppSqlQueryType sqlType, SqlBuilder *builder, const std::string &tableName); + WsjcppSqlQueryType sqlType(); + SqlBuilder &builder(); + SqlBuilder *builderRawPtr(); + const std::string &tableName(); + virtual std::string sql() = 0; + +private: + WsjcppSqlQueryType m_sqlType; + std::string m_tableName; + SqlBuilder *m_builder; +}; + +class WsjcppSqlWhereBase { +public: + WsjcppSqlWhereBase(WsjcppSqlWhereType type); + WsjcppSqlWhereType type(); + virtual std::string sql() = 0; + +private: + WsjcppSqlWhereType m_type; +}; + +class WsjcppSqlWhereOr : public WsjcppSqlWhereBase { +public: + WsjcppSqlWhereOr(); + virtual std::string sql() override; +}; + +class WsjcppSqlWhereAnd : public WsjcppSqlWhereBase { +public: + WsjcppSqlWhereAnd(); + virtual std::string sql() override; +}; + +class WsjcppSqlWhereCondition : public WsjcppSqlWhereBase { +public: + WsjcppSqlWhereCondition(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &value); + WsjcppSqlWhereCondition(const std::string &name, WsjcppSqlWhereConditionType comparator, int value); + WsjcppSqlWhereCondition(const std::string &name, WsjcppSqlWhereConditionType comparator, double value); + WsjcppSqlWhereCondition(const std::string &name, WsjcppSqlWhereConditionType comparator, float value); + const std::string &name(); + WsjcppSqlWhereConditionType comparator(); + const std::string &value(); + virtual std::string sql() override; +private: + std::string m_name; + std::string m_value; + WsjcppSqlWhereConditionType m_comparator; +}; + +class WsjcppSqlSelect; + +template +class WsjcppSqlWhere : public WsjcppSqlWhereBase { +public: + WsjcppSqlWhere(WsjcppSqlWhere *parent, SqlBuilder *builder, T *query) + : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB_CONDITION), m_parent(parent), m_builder(builder), m_query(query) { } + + template + WsjcppSqlWhere ¬Equal(const std::string &name, TVal value) { + cond(name, WsjcppSqlWhereConditionType::NOT_EQUAL, value); + return *this; + } + + template + WsjcppSqlWhere &equal(const std::string &name, TVal value) { + cond(name, WsjcppSqlWhereConditionType::EQUAL, value); + return *this; + } + + template + WsjcppSqlWhere &moreThen(const std::string &name, TVal value) { + cond(name, WsjcppSqlWhereConditionType::MORE_THEN, value); + return *this; + } + + template + WsjcppSqlWhere &lessThen(const std::string &name, TVal value) { + cond(name, WsjcppSqlWhereConditionType::LESS_THEN, value); + return *this; + } + + WsjcppSqlWhere &like(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::LIKE, value); + return *this; + } + + WsjcppSqlWhere &or_() { + if ( + m_conditions.size() > 0 + && m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::LOGICAL_OPERATOR + ) { + addError("[WARNING] WsjcppSqlWhere. Last item alredy defined as logical_operator. current will be skipped."); + return *this; + } + + m_conditions.push_back(std::make_shared()); + return *this; + } + + WsjcppSqlWhere &and_() { + if ( + m_conditions.size() > 0 + && m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::LOGICAL_OPERATOR + ) { + addError("[WARNING] WsjcppSqlWhere. Last item alredy defined as logical_operator. current will be skipped."); + return *this; + } + m_conditions.push_back(std::make_shared()); + return *this; + } + + WsjcppSqlWhere &subCondition() { + if ( + m_conditions.size() > 0 + && m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::CONDITION + ) { + and_(); // default add and_ + } + auto sub_cond = std::make_shared>(this, m_builder, m_query); + m_conditions.push_back(sub_cond); + return *(sub_cond.get()); + } + + WsjcppSqlWhere &finishSubCondition() { + // TODO return parent + if (m_parent != nullptr) { + return *m_parent; + } + // default return current where + // TODO warning to builder + return *this; + } + + T &endWhere() { + return *m_query; + } + + virtual std::string sql() override { + std::string ret = ""; + for (auto item : m_conditions) { + if (item->type() == WsjcppSqlWhereType::SUB_CONDITION) { + ret += "(" + item->sql() + ")"; + } else { + ret += item->sql(); + } + } + return ret; + } + +private: + template + WsjcppSqlWhere &cond(const std::string &name, WsjcppSqlWhereConditionType comparator, TVal value) { + if ( + m_conditions.size() > 0 + && m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::CONDITION + ) { + and_(); // default add and_ + } + m_conditions.push_back(std::make_shared(name, comparator, value)); + return *this; + } + + void addError(const std::string &err) { + ((IWsjcppSqlBuilder *)m_builder)->addError(err); + } + + SqlBuilder *m_builder; + T *m_query; + WsjcppSqlWhere *m_parent; + std::vector> m_conditions; +}; + +class WsjcppSqlSelect : public WsjcppSqlQuery { public: - WsjcppSqlBuilder(WsjcppSqlBuilderType nSqlType, const std::string &sSqlTable); - bool sel(const std::string &sColumnName); - bool add(const std::string &sColumnName, const std::string &sValue); - bool add(const std::string &sColumnName, int nValue); - bool add(const std::string &sColumnName, long nValue); - bool where(const std::string &sColumnName, const std::string &sValue); - bool where(const std::string &sColumnName, int nValue); - bool where(const std::string &sColumnName, long nValue); - - std::string getTextQuery(); - bool isValid(); - std::string getErrorMessage(); + WsjcppSqlSelect(const std::string &tableName, SqlBuilder *builder); + WsjcppSqlSelect &colum(const std::string &col, const std::string &col_as = ""); + + WsjcppSqlWhere &where(); + // TODO group by + // TODO order by + virtual std::string sql() override; private: - std::string prepareStringValue(const std::string &sValue); - bool checkName(const std::string &sColumnName); - WsjcppSqlBuilderType m_nSqlType; - std::string m_sSqlTable; - std::string m_sErrorMessage; - bool m_bValid; + std::shared_ptr> m_where; + std::vector m_columns; + std::map m_columns_as; +}; + - // query parts - std::string m_sSqlQuery0; - std::string m_sSqlQuery1; - std::string m_sSqlQuery2; - std::map m_mapFields; +class WsjcppSqlInsert : public WsjcppSqlQuery { +public: + WsjcppSqlInsert(const std::string &tableName, SqlBuilder *builder); + WsjcppSqlInsert &colum(const std::string &col); + WsjcppSqlInsert &addColums(const std::vector &cols); + WsjcppSqlInsert &clearValues(); + + WsjcppSqlInsert &val(const std::string &val); + WsjcppSqlInsert &val(int val); + WsjcppSqlInsert &val(float val); + WsjcppSqlInsert &val(double val); + + virtual std::string sql() override; + +private: + std::vector m_columns; + std::vector m_values; }; -class WsjcppSqlBuilderSelect : public WsjcppSqlBuilder { +class WsjcppSqlUpdate : public WsjcppSqlQuery { public: - WsjcppSqlBuilderSelect(const std::string &sSqlTable); + WsjcppSqlUpdate(const std::string &tableName, SqlBuilder *builder); + + WsjcppSqlUpdate &set(const std::string &name, const std::string &val); + WsjcppSqlUpdate &set(const std::string &name, int val); + WsjcppSqlUpdate &set(const std::string &name, float val); + WsjcppSqlUpdate &set(const std::string &name, double val); + + WsjcppSqlWhere &where(); + + virtual std::string sql() override; + +private: + WsjcppSqlUpdate &setValue(const std::string &name, const std::string &val); + + std::shared_ptr> m_where; + std::vector m_columns; + std::map m_values; }; -class WsjcppSqlBuilderInsert : public WsjcppSqlBuilder { +class WsjcppSqlDelete : public WsjcppSqlQuery { public: - WsjcppSqlBuilderInsert(const std::string &sSqlTable); + WsjcppSqlDelete(const std::string &tableName, SqlBuilder *builder); + WsjcppSqlWhere &where(); + virtual std::string sql() override; +private: + std::shared_ptr> m_where; }; -class WsjcppSqlBuilderUpdate : public WsjcppSqlBuilder { +class SqlBuilder : public IWsjcppSqlBuilder { public: - WsjcppSqlBuilderUpdate(const std::string &sSqlTable); + SqlBuilder(WsjcppSqlBuilderForDatabase dbType = WsjcppSqlBuilderForDatabase::SQLITE3); + + // TODO begin / end transaction can be added here + + WsjcppSqlSelect &selectFrom(const std::string &tableName); + WsjcppSqlInsert &insertInto(const std::string &tableName); + WsjcppSqlInsert &findInsertOrCreate(const std::string &tableName); + WsjcppSqlUpdate &update(const std::string &tableName); + WsjcppSqlUpdate &findUpdateOrCreate(const std::string &tableName); + WsjcppSqlDelete &deleteFrom(const std::string &sSqlTable); + WsjcppSqlDelete &findDeleteOrCreate(const std::string &tableName); + + void clear(); + + virtual bool hasErrors() override; + virtual std::string sql() override; + + virtual void setDatabaseType(WsjcppSqlBuilderForDatabase dbType) override; + virtual WsjcppSqlBuilderForDatabase databaseType() override; + +protected: + friend WsjcppSqlSelect; + friend WsjcppSqlInsert; + friend WsjcppSqlUpdate; + friend WsjcppSqlWhere; + virtual void addError(const std::string &err) override; + +private: + std::vector m_errors; + std::vector> m_queries; + WsjcppSqlBuilderForDatabase m_dbType; }; + +} // namespace wsjcpp \ No newline at end of file diff --git a/wsjcpp.yml b/wsjcpp.yml index 901099c..726f288 100644 --- a/wsjcpp.yml +++ b/wsjcpp.yml @@ -1,5 +1,5 @@ name: "wsjcpp-sql-builder" -version: v0.1.0 +version: v0.2.0 cmake_minimum_required: "3.0" cmake_cxx_standard: "17" description: "C++ Class-helper for build SQL queries"