From d29d1d5bbebfcf0ed584386e3efda5f41cf30e95 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Tue, 27 Jan 2026 10:39:10 +0700 Subject: [PATCH 01/23] Up version to 0.2.0 --- src.wsjcpp/CMakeLists.txt | 4 ++-- wsjcpp.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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" From 83582a99b6a8ab7c61c6b7abd70217244b2f372e Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Tue, 27 Jan 2026 10:49:52 +0700 Subject: [PATCH 02/23] Start new class WsjcppSqlBuilder2 --- src/wsjcpp_sql_builder.cpp | 28 ++++++++++++++++++++++++++++ src/wsjcpp_sql_builder.h | 14 +++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index f94f12c..cafa75e 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -27,6 +27,34 @@ #include "wsjcpp_sql_builder.h" +// --------------------------------------------------------------------- +// WsjcppSqlBuilder2 + + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeSelect(const std::string &sSqlTable) { + m_sTableName = sSqlTable; + m_nSqlType = WsjcppSqlBuilderType::SELECT; + return *this; +} + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeInsert(const std::string &sSqlTable) { + m_sTableName = sSqlTable; + m_nSqlType = WsjcppSqlBuilderType::INSERT; + return *this; +} + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeUpdate(const std::string &sSqlTable) { + m_sTableName = sSqlTable; + m_nSqlType = WsjcppSqlBuilderType::UPDATE; + return *this; +} + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeDelete(const std::string &sSqlTable) { + m_sTableName = sSqlTable; + m_nSqlType = WsjcppSqlBuilderType::DELETE; + return *this; +} + // --------------------------------------------------------------------- // WsjcppSqlBuilder diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 1a5f804..22cdd60 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -30,7 +30,19 @@ #include #include -enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE }; +enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE, DELETE }; + +class WsjcppSqlBuilder2 { +public: + WsjcppSqlBuilder2 &makeSelect(const std::string &sSqlTable); + WsjcppSqlBuilder2 &makeInsert(const std::string &sSqlTable); + WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); + WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); + +private: + std::string m_sTableName; + WsjcppSqlBuilderType m_nSqlType; +}; class WsjcppSqlBuilder { public: From ec3c9f241c9bc81077bfcc3fd10909fd15f93221 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Wed, 28 Jan 2026 10:42:16 +0700 Subject: [PATCH 03/23] Prepare class select --- src/tests/test_select.cpp | 42 +++++++++++++ src/wsjcpp_sql_builder.cpp | 123 +++++++++++++++++++++++-------------- src/wsjcpp_sql_builder.h | 62 ++++++++++++++----- 3 files changed, 166 insertions(+), 61 deletions(-) create mode 100644 src/tests/test_select.cpp diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp new file mode 100644 index 0000000..5fb0352 --- /dev/null +++ b/src/tests/test_select.cpp @@ -0,0 +1,42 @@ +/********************************************************************************** + * 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() { + WsjcppSqlBuilder2 builder; + builder.selectFrom("TABLE_NAME") + .colum("COL1") + .colum("COL2") + .colum("COL3") + ; + builder.hasErrors(); + // builder.sql(); + + return 0; +} \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index cafa75e..99a5ec4 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -26,39 +26,12 @@ ***********************************************************************************/ #include "wsjcpp_sql_builder.h" +#include // --------------------------------------------------------------------- -// WsjcppSqlBuilder2 - - -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeSelect(const std::string &sSqlTable) { - m_sTableName = sSqlTable; - m_nSqlType = WsjcppSqlBuilderType::SELECT; - return *this; -} - -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeInsert(const std::string &sSqlTable) { - m_sTableName = sSqlTable; - m_nSqlType = WsjcppSqlBuilderType::INSERT; - return *this; -} - -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeUpdate(const std::string &sSqlTable) { - m_sTableName = sSqlTable; - m_nSqlType = WsjcppSqlBuilderType::UPDATE; - return *this; -} +// WsjcppSqlQuery -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeDelete(const std::string &sSqlTable) { - m_sTableName = sSqlTable; - m_nSqlType = WsjcppSqlBuilderType::DELETE; - return *this; -} - -// --------------------------------------------------------------------- -// WsjcppSqlBuilder - -WsjcppSqlBuilder::WsjcppSqlBuilder(WsjcppSqlBuilderType nSqlType, +WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlBuilderType nSqlType, const std::string &sSqlTable) { m_nSqlType = nSqlType; m_sSqlTable = sSqlTable; @@ -80,7 +53,7 @@ WsjcppSqlBuilder::WsjcppSqlBuilder(WsjcppSqlBuilderType nSqlType, } } -bool WsjcppSqlBuilder::sel(const std::string &sColumnName) { +bool WsjcppSqlQuery::sel(const std::string &sColumnName) { if (!checkName(sColumnName)) { return false; } @@ -88,7 +61,7 @@ bool WsjcppSqlBuilder::sel(const std::string &sColumnName) { return true; } -bool WsjcppSqlBuilder::add(const std::string &sColumnName, +bool WsjcppSqlQuery::add(const std::string &sColumnName, const std::string &sValue) { if (!checkName(sColumnName)) { return false; @@ -123,7 +96,7 @@ bool WsjcppSqlBuilder::add(const std::string &sColumnName, return true; } -bool WsjcppSqlBuilder::add(const std::string &sColumnName, int nValue) { +bool WsjcppSqlQuery::add(const std::string &sColumnName, int nValue) { if (!checkName(sColumnName)) { return false; } @@ -141,7 +114,7 @@ bool WsjcppSqlBuilder::add(const std::string &sColumnName, int nValue) { return true; } -bool WsjcppSqlBuilder::add(const std::string &sColumnName, long nValue) { +bool WsjcppSqlQuery::add(const std::string &sColumnName, long nValue) { if (!checkName(sColumnName)) { return false; } @@ -159,7 +132,7 @@ bool WsjcppSqlBuilder::add(const std::string &sColumnName, long nValue) { return true; } -bool WsjcppSqlBuilder::where(const std::string &sColumnName, +bool WsjcppSqlQuery::where(const std::string &sColumnName, const std::string &sValue) { if (!checkName(sColumnName)) { return false; @@ -176,7 +149,7 @@ bool WsjcppSqlBuilder::where(const std::string &sColumnName, return true; } -bool WsjcppSqlBuilder::where(const std::string &sColumnName, int nValue) { +bool WsjcppSqlQuery::where(const std::string &sColumnName, int nValue) { if (!checkName(sColumnName)) { return false; } @@ -191,7 +164,7 @@ bool WsjcppSqlBuilder::where(const std::string &sColumnName, int nValue) { return true; } -bool WsjcppSqlBuilder::where(const std::string &sColumnName, long nValue) { +bool WsjcppSqlQuery::where(const std::string &sColumnName, long nValue) { if (!checkName(sColumnName)) { return false; } @@ -206,7 +179,7 @@ bool WsjcppSqlBuilder::where(const std::string &sColumnName, long nValue) { return true; } -std::string WsjcppSqlBuilder::getTextQuery() { +std::string WsjcppSqlQuery::getTextQuery() { std::string sSqlQuery = ""; size_t size0 = m_sSqlQuery0.size(); size_t size1 = m_sSqlQuery1.size(); @@ -239,11 +212,11 @@ std::string WsjcppSqlBuilder::getTextQuery() { return sSqlQuery; } -bool WsjcppSqlBuilder::isValid() { return m_bValid; } +bool WsjcppSqlQuery::isValid() { return m_bValid; } -std::string WsjcppSqlBuilder::getErrorMessage() { return m_sErrorMessage; } +std::string WsjcppSqlQuery::getErrorMessage() { return m_sErrorMessage; } -bool WsjcppSqlBuilder::checkName(const std::string &sColumnName) { +bool WsjcppSqlQuery::checkName(const std::string &sColumnName) { if (sColumnName.size() < 2) { m_sErrorMessage = "Parameter '" + sColumnName + "' must more than 2 characters"; @@ -266,7 +239,7 @@ bool WsjcppSqlBuilder::checkName(const std::string &sColumnName) { return true; } -std::string WsjcppSqlBuilder::prepareStringValue(const std::string &sValue) { +std::string WsjcppSqlQuery::prepareStringValue(const std::string &sValue) { // escaping simbols NUL (ASCII 0), \n, \r, \, ', ", и Control-Z. std::string sResult; sResult.reserve(sValue.size() * 2); @@ -300,16 +273,76 @@ std::string WsjcppSqlBuilder::prepareStringValue(const std::string &sValue) { // WsjcppSqlBuilderSelect WsjcppSqlBuilderSelect::WsjcppSqlBuilderSelect(const std::string &sSqlTable) - : WsjcppSqlBuilder(WsjcppSqlBuilderType::SELECT, sSqlTable) {} + : WsjcppSqlQuery(WsjcppSqlBuilderType::SELECT, sSqlTable) {} // --------------------------------------------------------------------- // WsjcppSqlBuilderInsert WsjcppSqlBuilderInsert::WsjcppSqlBuilderInsert(const std::string &sSqlTable) - : WsjcppSqlBuilder(WsjcppSqlBuilderType::INSERT, sSqlTable) {} + : WsjcppSqlQuery(WsjcppSqlBuilderType::INSERT, sSqlTable) {} // --------------------------------------------------------------------- // WsjcppSqlBuilderUpdate WsjcppSqlBuilderUpdate::WsjcppSqlBuilderUpdate(const std::string &sSqlTable) - : WsjcppSqlBuilder(WsjcppSqlBuilderType::UPDATE, sSqlTable) {} + : WsjcppSqlQuery(WsjcppSqlBuilderType::UPDATE, sSqlTable) {} + + +// --------------------------------------------------------------------- +// WsjcppSqlBuilderUpdate + +WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder) +: WsjcppSqlQuery(WsjcppSqlBuilderType::SELECT, tableName) { + m_tableName = tableName; + m_builder = builder; +} + +WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col) { + auto it = std::find(m_columns.begin(), m_columns.end(), col); + if (it != m_columns.end()) { + m_builder->addError("Column '" + col + "' already added to select"); + } else { + m_columns.push_back(col); + } + return *this; +} + +WsjcppSqlBuilder2 &WsjcppSqlSelect::compile() { + return *m_builder; +} + +// --------------------------------------------------------------------- +// WsjcppSqlBuilder2 + +WsjcppSqlSelect &WsjcppSqlBuilder2::selectFrom(const std::string &tableName) { + m_tableName = tableName; + m_nSqlType = WsjcppSqlBuilderType::SELECT; + m_queries.push_back(std::make_shared(m_tableName, this)); + return *(WsjcppSqlSelect *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeInsert(const std::string &tableName) { + m_tableName = tableName; + m_nSqlType = WsjcppSqlBuilderType::INSERT; + return *this; +} + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeUpdate(const std::string &tableName) { + m_tableName = tableName; + m_nSqlType = WsjcppSqlBuilderType::UPDATE; + return *this; +} + +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeDelete(const std::string &tableName) { + m_tableName = tableName; + m_nSqlType = WsjcppSqlBuilderType::DELETE; + return *this; +} + +bool WsjcppSqlBuilder2::hasErrors() { + return m_errors.size() > 0; +} + +void WsjcppSqlBuilder2::addError(const std::string &err) { + m_errors.push_back(err); +} \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 22cdd60..ccc2979 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -29,24 +29,16 @@ #include #include +#include +#include -enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE, DELETE }; -class WsjcppSqlBuilder2 { -public: - WsjcppSqlBuilder2 &makeSelect(const std::string &sSqlTable); - WsjcppSqlBuilder2 &makeInsert(const std::string &sSqlTable); - WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); - WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); -private: - std::string m_sTableName; - WsjcppSqlBuilderType m_nSqlType; -}; +enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE, DELETE }; -class WsjcppSqlBuilder { +class WsjcppSqlQuery { public: - WsjcppSqlBuilder(WsjcppSqlBuilderType nSqlType, const std::string &sSqlTable); + WsjcppSqlQuery(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); @@ -74,17 +66,55 @@ class WsjcppSqlBuilder { std::map m_mapFields; }; -class WsjcppSqlBuilderSelect : public WsjcppSqlBuilder { +class WsjcppSqlBuilderSelect : public WsjcppSqlQuery { public: WsjcppSqlBuilderSelect(const std::string &sSqlTable); }; -class WsjcppSqlBuilderInsert : public WsjcppSqlBuilder { +class WsjcppSqlBuilderInsert : public WsjcppSqlQuery { public: WsjcppSqlBuilderInsert(const std::string &sSqlTable); }; -class WsjcppSqlBuilderUpdate : public WsjcppSqlBuilder { +class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { public: WsjcppSqlBuilderUpdate(const std::string &sSqlTable); }; + +class WsjcppSqlBuilder2; + +class WsjcppSqlSelect : public WsjcppSqlQuery { +public: + WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder); + WsjcppSqlSelect &colum(const std::string &col); + // TODO where + // TODO group by + // TODO order by + WsjcppSqlBuilder2 &compile(); + std::string getSql(); + +private: + std::string m_tableName; + WsjcppSqlBuilder2 *m_builder; + std::vector m_columns; +}; + +class WsjcppSqlBuilder2 { +public: + WsjcppSqlSelect &selectFrom(const std::string &sSqlTable); + WsjcppSqlBuilder2 &makeInsert(const std::string &sSqlTable); + WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); + WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); + + bool hasErrors(); + +protected: + friend WsjcppSqlSelect; + void addError(const std::string &err); + +private: + std::vector m_errors; + std::string m_tableName; + WsjcppSqlBuilderType m_nSqlType; + std::vector> m_queries; +}; \ No newline at end of file From a7e180198a2f4ea3480efd36a4bffa2d40525dfa Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Wed, 28 Jan 2026 20:42:42 +0700 Subject: [PATCH 04/23] Added sql() method for compile query --- src/tests/test_select.cpp | 20 ++++++++++++++++++-- src/wsjcpp_sql_builder.cpp | 35 +++++++++++++++++++++++++++++++++++ src/wsjcpp_sql_builder.h | 13 ++++++++++++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index 5fb0352..ce1cb6e 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -35,8 +35,24 @@ int main() { .colum("COL2") .colum("COL3") ; - builder.hasErrors(); - // builder.sql(); + if (builder.hasErrors()) { + return -1; + } + std::string sqlQuery = builder.sql(); + std::string sqlQueryExpected = "SELECT COL1, COL2, COL3 FROM TABLE_NAME"; + if (sqlQuery != sqlQueryExpected) { + std::cerr + << "Expected:" << std::endl + << " " << sqlQueryExpected << std::endl + << ", but got:" << std::endl + << " " << sqlQuery << std::endl + ; + return -1; + } + + builder.clear(); + + return 0; } \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 99a5ec4..693eb6e 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -311,6 +311,26 @@ WsjcppSqlBuilder2 &WsjcppSqlSelect::compile() { return *m_builder; } +std::string WsjcppSqlSelect::sql() { + std::string ret = "SELECT "; + // TODO TOP OR LINIT for different databases + bool first = true; + for (auto col : m_columns) { + // TODO and 'AS' + if (!first) { + ret += ", "; + } + ret += col; + first = false; + } + ret += " FROM "; + ret += m_tableName; + // TODO where + // TODO group by + // TODO order by + return ret; +} + // --------------------------------------------------------------------- // WsjcppSqlBuilder2 @@ -345,4 +365,19 @@ bool WsjcppSqlBuilder2::hasErrors() { void WsjcppSqlBuilder2::addError(const std::string &err) { m_errors.push_back(err); +} + +std::string WsjcppSqlBuilder2::sql() { + std::string ret = ""; + for (auto query : m_queries) { + if (ret.size() > 0) { + ret += "\n"; + } + ret += query->sql(); + } + return ret; +} + +void WsjcppSqlBuilder2::clear() { + m_queries.clear(); } \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index ccc2979..22a4fcd 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -51,6 +51,8 @@ class WsjcppSqlQuery { bool isValid(); std::string getErrorMessage(); + virtual std::string sql() { return ""; }; // TODO = 0; + private: std::string prepareStringValue(const std::string &sValue); bool checkName(const std::string &sColumnName); @@ -83,6 +85,13 @@ class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { class WsjcppSqlBuilder2; +// class WsjcppSqlWhere { +// public: +// WsjcppSqlWhere(); + +// }; + + class WsjcppSqlSelect : public WsjcppSqlQuery { public: WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder); @@ -91,7 +100,7 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { // TODO group by // TODO order by WsjcppSqlBuilder2 &compile(); - std::string getSql(); + virtual std::string sql() override; private: std::string m_tableName; @@ -107,6 +116,8 @@ class WsjcppSqlBuilder2 { WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); bool hasErrors(); + std::string sql(); + void clear(); protected: friend WsjcppSqlSelect; From 2637d63063e5be5a43d93a18314a564a8be97ad9 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Wed, 28 Jan 2026 20:46:59 +0700 Subject: [PATCH 05/23] Added columns 'AS' to select --- src/tests/test_select.cpp | 12 ++++++------ src/wsjcpp_sql_builder.cpp | 9 ++++++--- src/wsjcpp_sql_builder.h | 13 ++++++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index ce1cb6e..e1faca7 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -30,16 +30,16 @@ int main() { WsjcppSqlBuilder2 builder; - builder.selectFrom("TABLE_NAME") - .colum("COL1") - .colum("COL2") - .colum("COL3") + builder.selectFrom("table1") + .colum("col1") + .colum("col2", "c3") + .colum("col3") ; if (builder.hasErrors()) { return -1; } std::string sqlQuery = builder.sql(); - std::string sqlQueryExpected = "SELECT COL1, COL2, COL3 FROM TABLE_NAME"; + std::string sqlQueryExpected = "SELECT col1, col2 AS c3, col3 FROM table1"; if (sqlQuery != sqlQueryExpected) { std::cerr << "Expected:" << std::endl @@ -52,7 +52,7 @@ int main() { builder.clear(); - + return 0; } \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 693eb6e..9ada687 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -297,12 +297,13 @@ WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 m_builder = builder; } -WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col) { +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()) { m_builder->addError("Column '" + col + "' already added to select"); } else { m_columns.push_back(col); + m_columns_as[col] = col_as; } return *this; } @@ -313,14 +314,16 @@ WsjcppSqlBuilder2 &WsjcppSqlSelect::compile() { std::string WsjcppSqlSelect::sql() { std::string ret = "SELECT "; - // TODO TOP OR LINIT for different databases + // TODO TOP OR LIMIT for different databases bool first = true; for (auto col : m_columns) { - // TODO and 'AS' if (!first) { ret += ", "; } ret += col; + if (m_columns_as[col] != "") { + ret += " AS " + m_columns_as[col]; + } first = false; } ret += " FROM "; diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 22a4fcd..33ec1d5 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -85,17 +85,19 @@ class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { class WsjcppSqlBuilder2; -// class WsjcppSqlWhere { -// public: -// WsjcppSqlWhere(); +class WsjcppSqlWhere { +public: + WsjcppSqlWhere(); +private: -// }; +}; class WsjcppSqlSelect : public WsjcppSqlQuery { public: WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder); - WsjcppSqlSelect &colum(const std::string &col); + WsjcppSqlSelect &colum(const std::string &col, const std::string &col_as = ""); + // TODO where // TODO group by // TODO order by @@ -106,6 +108,7 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { std::string m_tableName; WsjcppSqlBuilder2 *m_builder; std::vector m_columns; + std::map m_columns_as; }; class WsjcppSqlBuilder2 { From 56b738b6fb408b6c99a5a393a8752fee24bb94d7 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 12:10:46 +0700 Subject: [PATCH 06/23] First implement where for select --- src/tests/test_select.cpp | 18 +++- src/wsjcpp_sql_builder.cpp | 200 +++++++++++++++++++++++++++++++++++-- src/wsjcpp_sql_builder.h | 72 ++++++++++++- 3 files changed, 273 insertions(+), 17 deletions(-) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index e1faca7..3829f6e 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -34,12 +34,18 @@ int main() { .colum("col1") .colum("col2", "c3") .colum("col3") + .where() + .equal("col1", "1") + .or_() + .notEqual("col2", "2") + .endWhere() + // .groupBy() ; if (builder.hasErrors()) { return -1; } std::string sqlQuery = builder.sql(); - std::string sqlQueryExpected = "SELECT col1, col2 AS c3, col3 FROM table1"; + std::string sqlQueryExpected = "SELECT col1, col2 AS c3, col3 FROM table1 WHERE col1 = \"1\" OR col2 <> \"2\""; if (sqlQuery != sqlQueryExpected) { std::cerr << "Expected:" << std::endl @@ -51,8 +57,14 @@ int main() { } 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/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 9ada687..da7f79e 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -288,11 +288,168 @@ WsjcppSqlBuilderUpdate::WsjcppSqlBuilderUpdate(const std::string &sSqlTable) : WsjcppSqlQuery(WsjcppSqlBuilderType::UPDATE, sSqlTable) {} +// --------------------------------------------------------------------- +// WsjcppSqlWhereBase + +WsjcppSqlWhereBase::WsjcppSqlWhereBase(WsjcppSqlWhereType type) : m_type(type) { + +}; + +WsjcppSqlWhereType WsjcppSqlWhereBase::type() { + return m_type; +} + +// --------------------------------------------------------------------- +// WsjcppSqlWhereOr + +WsjcppSqlWhereOr::WsjcppSqlWhereOr() : WsjcppSqlWhereBase(WsjcppSqlWhereType::OR) { } +std::string WsjcppSqlWhereOr::sql() { return " OR "; }; + +// --------------------------------------------------------------------- +// WsjcppSqlWhereAnd + +WsjcppSqlWhereAnd::WsjcppSqlWhereAnd() : WsjcppSqlWhereBase(WsjcppSqlWhereType::AND) { } +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), m_value(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 + "\""; // TODO validate and escaping + return ret; +} + +// --------------------------------------------------------------------- +// WsjcppSqlWhere + +WsjcppSqlWhere &WsjcppSqlWhere::cond(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &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; +} + +WsjcppSqlWhere &WsjcppSqlWhere::notEqual(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::NOT_EQUAL, value); + return *this; +} + +WsjcppSqlWhere &WsjcppSqlWhere::equal(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::EQUAL, value); + return *this; +} + +WsjcppSqlWhere &WsjcppSqlWhere::moreThen(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::MORE_THEN, value); + return *this; +} + +WsjcppSqlWhere &WsjcppSqlWhere::lessThen(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::LESS_THEN, value); + return *this; +} + +WsjcppSqlWhere &WsjcppSqlWhere::like(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::LIKE, value); + return *this; +} + + +WsjcppSqlWhere &WsjcppSqlWhere::or_() { + if ( + m_conditions.size() > 0 + && ( + m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::OR + || m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::AND + ) + ) { + // TODO add to builder errors; + // std::cerr << "[WARNING] WsjcppSqlWhere. Last item alredy defined 'or' or 'and'. current will be skipped." << std::endl; + return *this; + } + + m_conditions.push_back(std::make_shared()); + return *this; +} + +WsjcppSqlWhere &WsjcppSqlWhere::and_() { + if ( + m_conditions.size() > 0 + && ( + m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::OR + || m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::AND + ) + ) { + // TODO add to builder errors; + // std::cerr << "[WARNING] WsjcppSqlWhere. Last item alredy defined 'or' or 'and'. current will be skipped." << std::endl; + return *this; + } + m_conditions.push_back(std::make_shared()); + return *this; +} + +std::string WsjcppSqlWhere::sql() { + std::string ret = ""; + for (auto item : m_conditions) { + ret += item->sql(); + } + return ret; +}; + // --------------------------------------------------------------------- // WsjcppSqlBuilderUpdate WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder) : WsjcppSqlQuery(WsjcppSqlBuilderType::SELECT, tableName) { + // TODO multitype table names with AS m_tableName = tableName; m_builder = builder; } @@ -308,6 +465,16 @@ WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col, const std::strin return *this; } +// WsjcppSqlWhere &WsjcppSqlSelect::where() { +WsjcppSqlWhere &WsjcppSqlSelect::where() { + if (!m_where) { + // m_where = std::make_shared>(); + m_where = std::make_shared(m_builder, this); + } + + return *(m_where.get()); +} + WsjcppSqlBuilder2 &WsjcppSqlSelect::compile() { return *m_builder; } @@ -315,19 +482,29 @@ WsjcppSqlBuilder2 &WsjcppSqlSelect::compile() { std::string WsjcppSqlSelect::sql() { std::string ret = "SELECT "; // TODO TOP OR LIMIT for different databases - bool first = true; - for (auto col : m_columns) { - if (!first) { - ret += ", "; - } - ret += col; - if (m_columns_as[col] != "") { - ret += " AS " + m_columns_as[col]; + + if (m_columns.size() == 0) { + ret += "*"; + } else { + 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; } - first = false; + ret += " FROM "; + ret += m_tableName; + } + + if (m_where) { + ret += " WHERE " + m_where->sql(); } - ret += " FROM "; - ret += m_tableName; + // TODO where // TODO group by // TODO order by @@ -341,6 +518,7 @@ WsjcppSqlSelect &WsjcppSqlBuilder2::selectFrom(const std::string &tableName) { m_tableName = tableName; m_nSqlType = WsjcppSqlBuilderType::SELECT; m_queries.push_back(std::make_shared(m_tableName, this)); + // TODO check must be select last one; return *(WsjcppSqlSelect *)(m_queries[m_queries.size() -1].get()); } diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 33ec1d5..7d35be6 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -85,20 +85,83 @@ class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { class WsjcppSqlBuilder2; -class WsjcppSqlWhere { + +enum class WsjcppSqlWhereType { OR, AND, CONDITION, SUB }; + +class WsjcppSqlWhereBase { public: - WsjcppSqlWhere(); + 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; +}; + +enum class WsjcppSqlWhereConditionType { NOT_EQUAL, EQUAL, MORE_THEN, LESS_THEN, LIKE }; +class WsjcppSqlWhereCondition : public WsjcppSqlWhereBase { +public: + WsjcppSqlWhereCondition(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &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(WsjcppSqlBuilder2 *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB), m_builder(builder), m_query(query) { } + WsjcppSqlWhere(WsjcppSqlBuilder2 *builder, WsjcppSqlSelect *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB), m_builder(builder), m_query(query) { } + WsjcppSqlWhere ¬Equal(const std::string &name, const std::string &value); + WsjcppSqlWhere &equal(const std::string &name, const std::string &value); + WsjcppSqlWhere &moreThen(const std::string &name, const std::string &value); + WsjcppSqlWhere &lessThen(const std::string &name, const std::string &value); + WsjcppSqlWhere &like(const std::string &name, const std::string &value); + + WsjcppSqlWhere &or_(); + WsjcppSqlWhere &and_(); + // T &endWhere() { + WsjcppSqlSelect &endWhere() { + return *m_query; + } + + virtual std::string sql() override; + +private: + WsjcppSqlWhere &cond(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &value); + + WsjcppSqlBuilder2 *m_builder; + // T *m_query; + WsjcppSqlSelect *m_query; + std::vector> m_conditions; +}; class WsjcppSqlSelect : public WsjcppSqlQuery { public: WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder); WsjcppSqlSelect &colum(const std::string &col, const std::string &col_as = ""); - // TODO where + WsjcppSqlWhere &where(); // TODO group by // TODO order by WsjcppSqlBuilder2 &compile(); @@ -107,12 +170,15 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { private: std::string m_tableName; WsjcppSqlBuilder2 *m_builder; + std::shared_ptr m_where; std::vector m_columns; std::map m_columns_as; }; class WsjcppSqlBuilder2 { public: + // TODO begin / end transaction can be added here + WsjcppSqlSelect &selectFrom(const std::string &sSqlTable); WsjcppSqlBuilder2 &makeInsert(const std::string &sSqlTable); WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); From d7b4414616f9e9b879435e73b90f29a690ccaaac Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 12:24:14 +0700 Subject: [PATCH 07/23] redesign where to template (because it's will be reused for DELETE and for UPDATE queries) --- src/tests/test_select.cpp | 2 +- src/wsjcpp_sql_builder.cpp | 90 ++-------------------------------- src/wsjcpp_sql_builder.h | 98 ++++++++++++++++++++++++++++++-------- 3 files changed, 83 insertions(+), 107 deletions(-) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index 3829f6e..78d2f8b 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -38,7 +38,7 @@ int main() { .equal("col1", "1") .or_() .notEqual("col2", "2") - .endWhere() + .endWhere() // .groupBy() ; if (builder.hasErrors()) { diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index da7f79e..1c423d0 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -302,13 +302,13 @@ WsjcppSqlWhereType WsjcppSqlWhereBase::type() { // --------------------------------------------------------------------- // WsjcppSqlWhereOr -WsjcppSqlWhereOr::WsjcppSqlWhereOr() : WsjcppSqlWhereBase(WsjcppSqlWhereType::OR) { } +WsjcppSqlWhereOr::WsjcppSqlWhereOr() : WsjcppSqlWhereBase(WsjcppSqlWhereType::LOGICAL_OPERATOR) { } std::string WsjcppSqlWhereOr::sql() { return " OR "; }; // --------------------------------------------------------------------- // WsjcppSqlWhereAnd -WsjcppSqlWhereAnd::WsjcppSqlWhereAnd() : WsjcppSqlWhereBase(WsjcppSqlWhereType::AND) { } +WsjcppSqlWhereAnd::WsjcppSqlWhereAnd() : WsjcppSqlWhereBase(WsjcppSqlWhereType::LOGICAL_OPERATOR) { } std::string WsjcppSqlWhereAnd::sql() { return " AND "; }; // --------------------------------------------------------------------- @@ -362,87 +362,7 @@ std::string WsjcppSqlWhereCondition::sql() { return ret; } -// --------------------------------------------------------------------- -// WsjcppSqlWhere - -WsjcppSqlWhere &WsjcppSqlWhere::cond(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &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; -} - -WsjcppSqlWhere &WsjcppSqlWhere::notEqual(const std::string &name, const std::string &value) { - cond(name, WsjcppSqlWhereConditionType::NOT_EQUAL, value); - return *this; -} - -WsjcppSqlWhere &WsjcppSqlWhere::equal(const std::string &name, const std::string &value) { - cond(name, WsjcppSqlWhereConditionType::EQUAL, value); - return *this; -} - -WsjcppSqlWhere &WsjcppSqlWhere::moreThen(const std::string &name, const std::string &value) { - cond(name, WsjcppSqlWhereConditionType::MORE_THEN, value); - return *this; -} - -WsjcppSqlWhere &WsjcppSqlWhere::lessThen(const std::string &name, const std::string &value) { - cond(name, WsjcppSqlWhereConditionType::LESS_THEN, value); - return *this; -} -WsjcppSqlWhere &WsjcppSqlWhere::like(const std::string &name, const std::string &value) { - cond(name, WsjcppSqlWhereConditionType::LIKE, value); - return *this; -} - - -WsjcppSqlWhere &WsjcppSqlWhere::or_() { - if ( - m_conditions.size() > 0 - && ( - m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::OR - || m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::AND - ) - ) { - // TODO add to builder errors; - // std::cerr << "[WARNING] WsjcppSqlWhere. Last item alredy defined 'or' or 'and'. current will be skipped." << std::endl; - return *this; - } - - m_conditions.push_back(std::make_shared()); - return *this; -} - -WsjcppSqlWhere &WsjcppSqlWhere::and_() { - if ( - m_conditions.size() > 0 - && ( - m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::OR - || m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::AND - ) - ) { - // TODO add to builder errors; - // std::cerr << "[WARNING] WsjcppSqlWhere. Last item alredy defined 'or' or 'and'. current will be skipped." << std::endl; - return *this; - } - m_conditions.push_back(std::make_shared()); - return *this; -} - -std::string WsjcppSqlWhere::sql() { - std::string ret = ""; - for (auto item : m_conditions) { - ret += item->sql(); - } - return ret; -}; // --------------------------------------------------------------------- // WsjcppSqlBuilderUpdate @@ -465,11 +385,9 @@ WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col, const std::strin return *this; } -// WsjcppSqlWhere &WsjcppSqlSelect::where() { -WsjcppSqlWhere &WsjcppSqlSelect::where() { +WsjcppSqlWhere &WsjcppSqlSelect::where() { if (!m_where) { - // m_where = std::make_shared>(); - m_where = std::make_shared(m_builder, this); + m_where = std::make_shared>(m_builder, this); } return *(m_where.get()); diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 7d35be6..6c1d753 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -86,7 +86,7 @@ class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { class WsjcppSqlBuilder2; -enum class WsjcppSqlWhereType { OR, AND, CONDITION, SUB }; +enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB }; class WsjcppSqlWhereBase { public: @@ -127,32 +127,89 @@ class WsjcppSqlWhereCondition : public WsjcppSqlWhereBase { class WsjcppSqlSelect; -// template +template class WsjcppSqlWhere : public WsjcppSqlWhereBase { public: - // WsjcppSqlWhere(WsjcppSqlBuilder2 *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB), m_builder(builder), m_query(query) { } - WsjcppSqlWhere(WsjcppSqlBuilder2 *builder, WsjcppSqlSelect *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB), m_builder(builder), m_query(query) { } - WsjcppSqlWhere ¬Equal(const std::string &name, const std::string &value); - WsjcppSqlWhere &equal(const std::string &name, const std::string &value); - WsjcppSqlWhere &moreThen(const std::string &name, const std::string &value); - WsjcppSqlWhere &lessThen(const std::string &name, const std::string &value); - WsjcppSqlWhere &like(const std::string &name, const std::string &value); - - WsjcppSqlWhere &or_(); - WsjcppSqlWhere &and_(); - // T &endWhere() { - WsjcppSqlSelect &endWhere() { + WsjcppSqlWhere(WsjcppSqlBuilder2 *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB), m_builder(builder), m_query(query) { } + + WsjcppSqlWhere ¬Equal(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::NOT_EQUAL, value); + return *this; + } + + WsjcppSqlWhere &equal(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::EQUAL, value); + return *this; + } + + WsjcppSqlWhere &moreThen(const std::string &name, const std::string &value) { + cond(name, WsjcppSqlWhereConditionType::MORE_THEN, value); + return *this; + } + + WsjcppSqlWhere &lessThen(const std::string &name, const std::string &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 + ) { + // TODO + // m_builder->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 + ) { + // TODO + // m_builder->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; + } + + T &endWhere() { return *m_query; } - virtual std::string sql() override; + virtual std::string sql() override { + std::string ret = ""; + for (auto item : m_conditions) { + ret += item->sql(); + } + return ret; + } private: - WsjcppSqlWhere &cond(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &value); + WsjcppSqlWhere &cond(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &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; + } WsjcppSqlBuilder2 *m_builder; - // T *m_query; - WsjcppSqlSelect *m_query; + T *m_query; std::vector> m_conditions; }; @@ -161,7 +218,7 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder); WsjcppSqlSelect &colum(const std::string &col, const std::string &col_as = ""); - WsjcppSqlWhere &where(); + WsjcppSqlWhere &where(); // TODO group by // TODO order by WsjcppSqlBuilder2 &compile(); @@ -170,7 +227,7 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { private: std::string m_tableName; WsjcppSqlBuilder2 *m_builder; - std::shared_ptr m_where; + std::shared_ptr> m_where; std::vector m_columns; std::map m_columns_as; }; @@ -190,6 +247,7 @@ class WsjcppSqlBuilder2 { protected: friend WsjcppSqlSelect; + friend WsjcppSqlWhere; void addError(const std::string &err); private: From aee4fda990286c2375a8e06e0315f4517b5a65b2 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 12:40:49 +0700 Subject: [PATCH 08/23] Implemented subCondition --- src/tests/test_select.cpp | 17 ++++++++++++++--- src/wsjcpp_sql_builder.cpp | 2 +- src/wsjcpp_sql_builder.h | 34 +++++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index 78d2f8b..afe8895 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -34,18 +34,29 @@ int main() { .colum("col1") .colum("col2", "c3") .colum("col3") + .colum("col4") .where() .equal("col1", "1") .or_() .notEqual("col2", "2") - .endWhere() - // .groupBy() + .or_() + .subCondition() + .equal("c3", "4") + // .and_() // be default must be added and + .equal("col2", "5") + .finishSubCondition() + .or_() + .lessThen("col4", "...") + .endWhere() // need only for groupBy havingBy and etc ; if (builder.hasErrors()) { return -1; } std::string sqlQuery = builder.sql(); - std::string sqlQueryExpected = "SELECT col1, col2 AS c3, col3 FROM table1 WHERE col1 = \"1\" OR col2 <> \"2\""; + 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 < \"...\""; if (sqlQuery != sqlQueryExpected) { std::cerr << "Expected:" << std::endl diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 1c423d0..cad9cd9 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -387,7 +387,7 @@ WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col, const std::strin WsjcppSqlWhere &WsjcppSqlSelect::where() { if (!m_where) { - m_where = std::make_shared>(m_builder, this); + m_where = std::make_shared>(nullptr, m_builder, this); } return *(m_where.get()); diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 6c1d753..4e179af 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -86,7 +86,7 @@ class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { class WsjcppSqlBuilder2; -enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB }; +enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB_CONDITION }; class WsjcppSqlWhereBase { public: @@ -130,7 +130,8 @@ class WsjcppSqlSelect; template class WsjcppSqlWhere : public WsjcppSqlWhereBase { public: - WsjcppSqlWhere(WsjcppSqlBuilder2 *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB), m_builder(builder), m_query(query) { } + WsjcppSqlWhere(WsjcppSqlWhere *parent, WsjcppSqlBuilder2 *builder, T *query) + : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB_CONDITION), m_parent(parent), m_builder(builder), m_query(query) { } WsjcppSqlWhere ¬Equal(const std::string &name, const std::string &value) { cond(name, WsjcppSqlWhereConditionType::NOT_EQUAL, value); @@ -184,6 +185,28 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { 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; } @@ -191,7 +214,11 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { virtual std::string sql() override { std::string ret = ""; for (auto item : m_conditions) { - ret += item->sql(); + if (item->type() == WsjcppSqlWhereType::SUB_CONDITION) { + ret += "(" + item->sql() + ")"; + } else { + ret += item->sql(); + } } return ret; } @@ -210,6 +237,7 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { WsjcppSqlBuilder2 *m_builder; T *m_query; + WsjcppSqlWhere *m_parent; std::vector> m_conditions; }; From 303bf8319a548380f77974aff22ea5efeec5fe90 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 12:56:25 +0700 Subject: [PATCH 09/23] Added support different data types for where conditions --- src/tests/test_select.cpp | 4 +- src/wsjcpp_sql_builder.cpp | 102 +++++++++++++++++++++++-------------- src/wsjcpp_sql_builder.h | 24 ++++++--- 3 files changed, 85 insertions(+), 45 deletions(-) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index afe8895..c8d8732 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -46,7 +46,7 @@ int main() { .equal("col2", "5") .finishSubCondition() .or_() - .lessThen("col4", "...") + .lessThen("col4", 111) .endWhere() // need only for groupBy havingBy and etc ; if (builder.hasErrors()) { @@ -56,7 +56,7 @@ int main() { 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 < \"...\""; + "WHERE col1 = '1' OR col2 <> '2' OR (c3 = '4' AND col2 = '5') OR col4 < 111"; if (sqlQuery != sqlQueryExpected) { std::cerr << "Expected:" << std::endl diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index cad9cd9..55f9260 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -28,6 +28,40 @@ #include "wsjcpp_sql_builder.h" #include + +// --------------------------------------------------------------------- +// 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 @@ -71,9 +105,9 @@ bool WsjcppSqlQuery::add(const std::string &sColumnName, m_bValid = false; } else if (m_nSqlType == WsjcppSqlBuilderType::INSERT) { m_sSqlQuery0 += sColumnName + ", "; - m_sSqlQuery1 += prepareStringValue(sValue) + ", "; + m_sSqlQuery1 += WsjcppSqlBuilderHelpers::escapingStringValue(sValue) + ", "; } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery0 += sColumnName + " = " + prepareStringValue(sValue); + m_sSqlQuery0 += sColumnName + " = " + WsjcppSqlBuilderHelpers::escapingStringValue(sValue); } else { m_sErrorMessage = "Unknown sql type"; m_bValid = false; @@ -138,12 +172,12 @@ bool WsjcppSqlQuery::where(const std::string &sColumnName, return false; } if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sSqlQuery2 += sColumnName + " = " + prepareStringValue(sValue); + m_sSqlQuery2 += sColumnName + " = " + WsjcppSqlBuilderHelpers::escapingStringValue(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); + m_sSqlQuery1 += sColumnName + " = " + WsjcppSqlBuilderHelpers::escapingStringValue(sValue); } return true; @@ -239,36 +273,6 @@ bool WsjcppSqlQuery::checkName(const std::string &sColumnName) { return true; } -std::string WsjcppSqlQuery::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); - } - } - sResult.push_back('\''); - return sResult; -} - // --------------------------------------------------------------------- // WsjcppSqlBuilderSelect @@ -318,9 +322,33 @@ WsjcppSqlWhereCondition::WsjcppSqlWhereCondition( const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &value -) - : WsjcppSqlWhereBase(WsjcppSqlWhereType::CONDITION), m_name(name), m_comparator(comparator), m_value(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() { @@ -358,7 +386,7 @@ std::string WsjcppSqlWhereCondition::sql() { ret += " unknwon_operator "; break; } - ret += "\"" + m_value + "\""; // TODO validate and escaping + ret += m_value; return ret; } diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 4e179af..31fd2b1 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -32,6 +32,11 @@ #include #include +class WsjcppSqlBuilderHelpers { +public: + static std::string escapingStringValue(const std::string &sValue); +}; + enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE, DELETE }; @@ -54,7 +59,6 @@ class WsjcppSqlQuery { virtual std::string sql() { return ""; }; // TODO = 0; private: - std::string prepareStringValue(const std::string &sValue); bool checkName(const std::string &sColumnName); WsjcppSqlBuilderType m_nSqlType; std::string m_sSqlTable; @@ -115,6 +119,9 @@ enum class WsjcppSqlWhereConditionType { NOT_EQUAL, EQUAL, MORE_THEN, LESS_THEN, 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(); @@ -133,22 +140,26 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { WsjcppSqlWhere(WsjcppSqlWhere *parent, WsjcppSqlBuilder2 *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB_CONDITION), m_parent(parent), m_builder(builder), m_query(query) { } - WsjcppSqlWhere ¬Equal(const std::string &name, const std::string &value) { + template + WsjcppSqlWhere ¬Equal(const std::string &name, TVal value) { cond(name, WsjcppSqlWhereConditionType::NOT_EQUAL, value); return *this; } - WsjcppSqlWhere &equal(const std::string &name, const std::string &value) { + template + WsjcppSqlWhere &equal(const std::string &name, TVal value) { cond(name, WsjcppSqlWhereConditionType::EQUAL, value); return *this; } - WsjcppSqlWhere &moreThen(const std::string &name, const std::string &value) { + template + WsjcppSqlWhere &moreThen(const std::string &name, TVal value) { cond(name, WsjcppSqlWhereConditionType::MORE_THEN, value); return *this; } - WsjcppSqlWhere &lessThen(const std::string &name, const std::string &value) { + template + WsjcppSqlWhere &lessThen(const std::string &name, TVal value) { cond(name, WsjcppSqlWhereConditionType::LESS_THEN, value); return *this; } @@ -224,7 +235,8 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { } private: - WsjcppSqlWhere &cond(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &value) { + 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 From dc7a0c9c7b10b42d39f4bd6b78beac85ce65b24c Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 13:06:24 +0700 Subject: [PATCH 10/23] Removed old builder --- src/main.cpp | 28 ++--- src/tests/test_insert.cpp | 25 ++-- src/tests/test_select.cpp | 1 + src/wsjcpp_sql_builder.cpp | 252 +++---------------------------------- src/wsjcpp_sql_builder.h | 57 ++------- 5 files changed, 58 insertions(+), 305 deletions(-) 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_insert.cpp b/src/tests/test_insert.cpp index d0a750e..e1706dc 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -29,16 +29,23 @@ #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);") { + WsjcppSqlBuilder2 builder; + builder.insertInto("table1"); + + if (builder.hasErrors()) { + std::cerr << "Select builder has some errors" << std::endl; return -1; } + // std::string sqlQuery = builder.sql(); + // std::string sqlQueryExpected = "INSERT INTO TABLE_NAME(COL1, COL2) VALUES ('val1', 1);"; + // 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 index c8d8732..89f910d 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -50,6 +50,7 @@ int main() { .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(); diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 55f9260..7f3277c 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -62,236 +62,20 @@ std::string WsjcppSqlBuilderHelpers::escapingStringValue(const std::string &sVal return sResult; } -// --------------------------------------------------------------------- -// WsjcppSqlQuery - -WsjcppSqlQuery::WsjcppSqlQuery(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; - } -} -bool WsjcppSqlQuery::sel(const std::string &sColumnName) { - if (!checkName(sColumnName)) { - return false; - } - m_sSqlQuery0 += sColumnName + ", "; - return true; -} +WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlBuilderType sqlType, const std::string &tableName) + : m_sqlType(sqlType), m_tableName(tableName) { -bool WsjcppSqlQuery::add(const std::string &sColumnName, - const std::string &sValue) { - if (!checkName(sColumnName)) { - return false; - } - 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 += WsjcppSqlBuilderHelpers::escapingStringValue(sValue) + ", "; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - m_sSqlQuery0 += sColumnName + " = " + WsjcppSqlBuilderHelpers::escapingStringValue(sValue); - } else { - m_sErrorMessage = "Unknown sql type"; - m_bValid = false; - } - - // m_sSqlQuery = sBefore + sEscapedValue + sAfter; - - // while (true) { - // /* Locate the substring to replace. */ - // index = str.find(sName, index); - // if (index == std::string::npos) - // return false; - - // /* Make the replacement. */ - // str.replace(index, 3, "def"); - - // /* Advance index forward so the next iteration doesn't pick it up as - // well. */ index += 3; - // } - return true; } -bool WsjcppSqlQuery::add(const std::string &sColumnName, int nValue) { - if (!checkName(sColumnName)) { - return false; - } - - 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); - } - - return true; +WsjcppSqlBuilderType WsjcppSqlQuery::sqlType() { + return m_sqlType; } -bool WsjcppSqlQuery::add(const std::string &sColumnName, long nValue) { - if (!checkName(sColumnName)) { - return false; - } - - 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); - } - - return true; -} - -bool WsjcppSqlQuery::where(const std::string &sColumnName, - const std::string &sValue) { - if (!checkName(sColumnName)) { - return false; - } - if (m_nSqlType == WsjcppSqlBuilderType::SELECT) { - m_sSqlQuery2 += sColumnName + " = " + WsjcppSqlBuilderHelpers::escapingStringValue(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 + " = " + WsjcppSqlBuilderHelpers::escapingStringValue(sValue); - } - - return true; -} - -bool WsjcppSqlQuery::where(const std::string &sColumnName, int nValue) { - if (!checkName(sColumnName)) { - return 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); - } - return true; +const std::string &WsjcppSqlQuery::tableName() { + return m_tableName; } -bool WsjcppSqlQuery::where(const std::string &sColumnName, long nValue) { - if (!checkName(sColumnName)) { - return 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); - } - return true; -} - -std::string WsjcppSqlQuery::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); - } - sSqlQuery += m_sSqlQuery2; - } else if (m_nSqlType == WsjcppSqlBuilderType::UPDATE) { - sSqlQuery = m_sSqlQuery0 + m_sSqlQuery1 + m_sSqlQuery2; - } - return sSqlQuery; -} - -bool WsjcppSqlQuery::isValid() { return m_bValid; } - -std::string WsjcppSqlQuery::getErrorMessage() { return m_sErrorMessage; } - -bool WsjcppSqlQuery::checkName(const std::string &sColumnName) { - if (sColumnName.size() < 2) { - m_sErrorMessage = - "Parameter '" + sColumnName + "' must more than 2 characters"; - m_bValid = false; - return false; - } - // 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; -} - -// --------------------------------------------------------------------- -// WsjcppSqlBuilderSelect - -WsjcppSqlBuilderSelect::WsjcppSqlBuilderSelect(const std::string &sSqlTable) - : WsjcppSqlQuery(WsjcppSqlBuilderType::SELECT, sSqlTable) {} - -// --------------------------------------------------------------------- -// WsjcppSqlBuilderInsert - -WsjcppSqlBuilderInsert::WsjcppSqlBuilderInsert(const std::string &sSqlTable) - : WsjcppSqlQuery(WsjcppSqlBuilderType::INSERT, sSqlTable) {} - -// --------------------------------------------------------------------- -// WsjcppSqlBuilderUpdate - -WsjcppSqlBuilderUpdate::WsjcppSqlBuilderUpdate(const std::string &sSqlTable) - : WsjcppSqlQuery(WsjcppSqlBuilderType::UPDATE, sSqlTable) {} - - // --------------------------------------------------------------------- // WsjcppSqlWhereBase @@ -390,8 +174,6 @@ std::string WsjcppSqlWhereCondition::sql() { return ret; } - - // --------------------------------------------------------------------- // WsjcppSqlBuilderUpdate @@ -468,23 +250,23 @@ WsjcppSqlSelect &WsjcppSqlBuilder2::selectFrom(const std::string &tableName) { return *(WsjcppSqlSelect *)(m_queries[m_queries.size() -1].get()); } -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeInsert(const std::string &tableName) { +WsjcppSqlBuilder2 &WsjcppSqlBuilder2::insertInto(const std::string &tableName) { m_tableName = tableName; m_nSqlType = WsjcppSqlBuilderType::INSERT; return *this; } -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeUpdate(const std::string &tableName) { - m_tableName = tableName; - m_nSqlType = WsjcppSqlBuilderType::UPDATE; - return *this; -} +// WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeUpdate(const std::string &tableName) { +// m_tableName = tableName; +// m_nSqlType = WsjcppSqlBuilderType::UPDATE; +// return *this; +// } -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeDelete(const std::string &tableName) { - m_tableName = tableName; - m_nSqlType = WsjcppSqlBuilderType::DELETE; - return *this; -} +// WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeDelete(const std::string &tableName) { +// m_tableName = tableName; +// m_nSqlType = WsjcppSqlBuilderType::DELETE; +// return *this; +// } bool WsjcppSqlBuilder2::hasErrors() { return m_errors.size() > 0; diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 31fd2b1..96ac996 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -37,59 +37,22 @@ class WsjcppSqlBuilderHelpers { static std::string escapingStringValue(const std::string &sValue); }; - - enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE, DELETE }; class WsjcppSqlQuery { public: - WsjcppSqlQuery(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(); - - virtual std::string sql() { return ""; }; // TODO = 0; + WsjcppSqlQuery(WsjcppSqlBuilderType sqlType, const std::string &tableName); + WsjcppSqlBuilderType sqlType(); + const std::string &tableName(); + virtual std::string sql() = 0; private: - bool checkName(const std::string &sColumnName); - WsjcppSqlBuilderType m_nSqlType; - std::string m_sSqlTable; - std::string m_sErrorMessage; - bool m_bValid; - - // query parts - std::string m_sSqlQuery0; - std::string m_sSqlQuery1; - std::string m_sSqlQuery2; - std::map m_mapFields; -}; - -class WsjcppSqlBuilderSelect : public WsjcppSqlQuery { -public: - WsjcppSqlBuilderSelect(const std::string &sSqlTable); -}; - -class WsjcppSqlBuilderInsert : public WsjcppSqlQuery { -public: - WsjcppSqlBuilderInsert(const std::string &sSqlTable); -}; - -class WsjcppSqlBuilderUpdate : public WsjcppSqlQuery { -public: - WsjcppSqlBuilderUpdate(const std::string &sSqlTable); + WsjcppSqlBuilderType m_sqlType; + std::string m_tableName; }; class WsjcppSqlBuilder2; - enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB_CONDITION }; class WsjcppSqlWhereBase { @@ -276,10 +239,10 @@ class WsjcppSqlBuilder2 { public: // TODO begin / end transaction can be added here - WsjcppSqlSelect &selectFrom(const std::string &sSqlTable); - WsjcppSqlBuilder2 &makeInsert(const std::string &sSqlTable); - WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); - WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); + WsjcppSqlSelect &selectFrom(const std::string &tableName); + WsjcppSqlBuilder2 &insertInto(const std::string &tableName); + // WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); + // WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); bool hasErrors(); std::string sql(); From 58ebc11321deb561d3b63c578d6bfa90171c03fd Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 13:08:40 +0700 Subject: [PATCH 11/23] Updated README.md --- README.md | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7b2d3a3..7429a97 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; + WsjcppSqlBuilder2 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 From b76578514030feb504d4d3bce7f502ac79a831fa Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 13:11:01 +0700 Subject: [PATCH 12/23] Renamed WsjcppSqlBuilder2 to WsjcppSqlBuilder --- README.md | 2 +- src/tests/test_insert.cpp | 2 +- src/tests/test_select.cpp | 2 +- src/wsjcpp_sql_builder.cpp | 22 ++++++++++----------- src/wsjcpp_sql_builder.h | 40 ++++++++++++++++++++++++++++---------- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 7429a97..59928e7 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Example main func: #include int main(int argc, const char* argv[]) { - WsjcppSqlBuilder2 builder; + WsjcppSqlBuilder builder; builder.selectFrom("table1") .colum("col1") .colum("col2", "c3") diff --git a/src/tests/test_insert.cpp b/src/tests/test_insert.cpp index e1706dc..24c562d 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -29,7 +29,7 @@ #include int main() { - WsjcppSqlBuilder2 builder; + WsjcppSqlBuilder builder; builder.insertInto("table1"); if (builder.hasErrors()) { diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index 89f910d..9be10c2 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -29,7 +29,7 @@ #include int main() { - WsjcppSqlBuilder2 builder; + WsjcppSqlBuilder builder; builder.selectFrom("table1") .colum("col1") .colum("col2", "c3") diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 7f3277c..0535bc3 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -177,7 +177,7 @@ std::string WsjcppSqlWhereCondition::sql() { // --------------------------------------------------------------------- // WsjcppSqlBuilderUpdate -WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder) +WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder *builder) : WsjcppSqlQuery(WsjcppSqlBuilderType::SELECT, tableName) { // TODO multitype table names with AS m_tableName = tableName; @@ -203,7 +203,7 @@ WsjcppSqlWhere &WsjcppSqlSelect::where() { return *(m_where.get()); } -WsjcppSqlBuilder2 &WsjcppSqlSelect::compile() { +WsjcppSqlBuilder &WsjcppSqlSelect::compile() { return *m_builder; } @@ -240,9 +240,9 @@ std::string WsjcppSqlSelect::sql() { } // --------------------------------------------------------------------- -// WsjcppSqlBuilder2 +// WsjcppSqlBuilder -WsjcppSqlSelect &WsjcppSqlBuilder2::selectFrom(const std::string &tableName) { +WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { m_tableName = tableName; m_nSqlType = WsjcppSqlBuilderType::SELECT; m_queries.push_back(std::make_shared(m_tableName, this)); @@ -250,33 +250,33 @@ WsjcppSqlSelect &WsjcppSqlBuilder2::selectFrom(const std::string &tableName) { return *(WsjcppSqlSelect *)(m_queries[m_queries.size() -1].get()); } -WsjcppSqlBuilder2 &WsjcppSqlBuilder2::insertInto(const std::string &tableName) { +WsjcppSqlBuilder &WsjcppSqlBuilder::insertInto(const std::string &tableName) { m_tableName = tableName; m_nSqlType = WsjcppSqlBuilderType::INSERT; return *this; } -// WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeUpdate(const std::string &tableName) { +// WsjcppSqlBuilder &WsjcppSqlBuilder::makeUpdate(const std::string &tableName) { // m_tableName = tableName; // m_nSqlType = WsjcppSqlBuilderType::UPDATE; // return *this; // } -// WsjcppSqlBuilder2 &WsjcppSqlBuilder2::makeDelete(const std::string &tableName) { +// WsjcppSqlBuilder &WsjcppSqlBuilder::makeDelete(const std::string &tableName) { // m_tableName = tableName; // m_nSqlType = WsjcppSqlBuilderType::DELETE; // return *this; // } -bool WsjcppSqlBuilder2::hasErrors() { +bool WsjcppSqlBuilder::hasErrors() { return m_errors.size() > 0; } -void WsjcppSqlBuilder2::addError(const std::string &err) { +void WsjcppSqlBuilder::addError(const std::string &err) { m_errors.push_back(err); } -std::string WsjcppSqlBuilder2::sql() { +std::string WsjcppSqlBuilder::sql() { std::string ret = ""; for (auto query : m_queries) { if (ret.size() > 0) { @@ -287,6 +287,6 @@ std::string WsjcppSqlBuilder2::sql() { return ret; } -void WsjcppSqlBuilder2::clear() { +void WsjcppSqlBuilder::clear() { m_queries.clear(); } \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 96ac996..f474c52 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -51,7 +51,7 @@ class WsjcppSqlQuery { std::string m_tableName; }; -class WsjcppSqlBuilder2; +class WsjcppSqlBuilder; enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB_CONDITION }; @@ -100,7 +100,7 @@ class WsjcppSqlSelect; template class WsjcppSqlWhere : public WsjcppSqlWhereBase { public: - WsjcppSqlWhere(WsjcppSqlWhere *parent, WsjcppSqlBuilder2 *builder, T *query) + WsjcppSqlWhere(WsjcppSqlWhere *parent, WsjcppSqlBuilder *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB_CONDITION), m_parent(parent), m_builder(builder), m_query(query) { } template @@ -210,7 +210,7 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { return *this; } - WsjcppSqlBuilder2 *m_builder; + WsjcppSqlBuilder *m_builder; T *m_query; WsjcppSqlWhere *m_parent; std::vector> m_conditions; @@ -218,31 +218,51 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { class WsjcppSqlSelect : public WsjcppSqlQuery { public: - WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder2 *builder); + WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder *builder); WsjcppSqlSelect &colum(const std::string &col, const std::string &col_as = ""); WsjcppSqlWhere &where(); // TODO group by // TODO order by - WsjcppSqlBuilder2 &compile(); + WsjcppSqlBuilder &compile(); virtual std::string sql() override; private: std::string m_tableName; - WsjcppSqlBuilder2 *m_builder; + WsjcppSqlBuilder *m_builder; std::shared_ptr> m_where; std::vector m_columns; std::map m_columns_as; }; -class WsjcppSqlBuilder2 { + +// class WsjcppSqlInsert : public WsjcppSqlQuery { +// public: +// WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder); +// WsjcppSqlInsert &colum(const std::string &col, const std::string &col_as = ""); + +// WsjcppSqlWhere &where(); +// // TODO group by +// // TODO order by +// WsjcppSqlBuilder &compile(); +// virtual std::string sql() override; + +// private: +// std::string m_tableName; +// WsjcppSqlBuilder *m_builder; +// std::shared_ptr> m_where; +// std::vector m_columns; +// std::map m_columns_as; +// }; + +class WsjcppSqlBuilder { public: // TODO begin / end transaction can be added here WsjcppSqlSelect &selectFrom(const std::string &tableName); - WsjcppSqlBuilder2 &insertInto(const std::string &tableName); - // WsjcppSqlBuilder2 &makeUpdate(const std::string &sSqlTable); - // WsjcppSqlBuilder2 &makeDelete(const std::string &sSqlTable); + WsjcppSqlBuilder &insertInto(const std::string &tableName); + // WsjcppSqlBuilder &makeUpdate(const std::string &sSqlTable); + // WsjcppSqlBuilder &makeDelete(const std::string &sSqlTable); bool hasErrors(); std::string sql(); From dfd5d03d7c5ad9543d83ad2c999af90b8a11961a Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 13:23:10 +0700 Subject: [PATCH 13/23] Renamed WsjcppSqlBuilderType to WsjcppSqlQueryType, redesign WsjcppSqlQuery, preparing Insert --- src/wsjcpp_sql_builder.cpp | 54 ++++++++++++++++++++++++-------------- src/wsjcpp_sql_builder.h | 50 ++++++++++++++++------------------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 0535bc3..e26cb4f 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -63,15 +63,23 @@ std::string WsjcppSqlBuilderHelpers::escapingStringValue(const std::string &sVal } -WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlBuilderType sqlType, const std::string &tableName) - : m_sqlType(sqlType), m_tableName(tableName) { +WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlQueryType sqlType, WsjcppSqlBuilder *builder, const std::string &tableName) + : m_sqlType(sqlType), m_builder(builder), m_tableName(tableName) { } -WsjcppSqlBuilderType WsjcppSqlQuery::sqlType() { +WsjcppSqlQueryType WsjcppSqlQuery::sqlType() { return m_sqlType; } +WsjcppSqlBuilder &WsjcppSqlQuery::builder() { + return *m_builder; +} + +WsjcppSqlBuilder *WsjcppSqlQuery::builderRawPtr() { + return m_builder; +} + const std::string &WsjcppSqlQuery::tableName() { return m_tableName; } @@ -175,19 +183,17 @@ std::string WsjcppSqlWhereCondition::sql() { } // --------------------------------------------------------------------- -// WsjcppSqlBuilderUpdate +// WsjcppSqlSelect WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder *builder) -: WsjcppSqlQuery(WsjcppSqlBuilderType::SELECT, tableName) { +: WsjcppSqlQuery(WsjcppSqlQueryType::SELECT, builder, tableName) { // TODO multitype table names with AS - m_tableName = tableName; - m_builder = builder; } 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()) { - m_builder->addError("Column '" + col + "' already added to select"); + builder().addError("Column '" + col + "' already added to select"); } else { m_columns.push_back(col); m_columns_as[col] = col_as; @@ -197,16 +203,12 @@ WsjcppSqlSelect &WsjcppSqlSelect::colum(const std::string &col, const std::strin WsjcppSqlWhere &WsjcppSqlSelect::where() { if (!m_where) { - m_where = std::make_shared>(nullptr, m_builder, this); + m_where = std::make_shared>(nullptr, builderRawPtr(), this); } return *(m_where.get()); } -WsjcppSqlBuilder &WsjcppSqlSelect::compile() { - return *m_builder; -} - std::string WsjcppSqlSelect::sql() { std::string ret = "SELECT "; // TODO TOP OR LIMIT for different databases @@ -226,25 +228,39 @@ std::string WsjcppSqlSelect::sql() { first = false; } ret += " FROM "; - ret += m_tableName; + ret += tableName(); } if (m_where) { ret += " WHERE " + m_where->sql(); } - // TODO where // TODO group by // TODO order by return ret; } +// --------------------------------------------------------------------- +// WsjcppSqlInsert + +WsjcppSqlInsert::WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder) +: WsjcppSqlQuery(WsjcppSqlQueryType::INSERT, builder, tableName) { + +} + + +std::string WsjcppSqlInsert::sql() { + std::string ret = "INSERT INTO " + tableName(); + + return ret; +}; + // --------------------------------------------------------------------- // WsjcppSqlBuilder WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { m_tableName = tableName; - m_nSqlType = WsjcppSqlBuilderType::SELECT; + m_nSqlType = WsjcppSqlQueryType::SELECT; m_queries.push_back(std::make_shared(m_tableName, this)); // TODO check must be select last one; return *(WsjcppSqlSelect *)(m_queries[m_queries.size() -1].get()); @@ -252,19 +268,19 @@ WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { WsjcppSqlBuilder &WsjcppSqlBuilder::insertInto(const std::string &tableName) { m_tableName = tableName; - m_nSqlType = WsjcppSqlBuilderType::INSERT; + m_nSqlType = WsjcppSqlQueryType::INSERT; return *this; } // WsjcppSqlBuilder &WsjcppSqlBuilder::makeUpdate(const std::string &tableName) { // m_tableName = tableName; -// m_nSqlType = WsjcppSqlBuilderType::UPDATE; +// m_nSqlType = WsjcppSqlQueryType::UPDATE; // return *this; // } // WsjcppSqlBuilder &WsjcppSqlBuilder::makeDelete(const std::string &tableName) { // m_tableName = tableName; -// m_nSqlType = WsjcppSqlBuilderType::DELETE; +// m_nSqlType = WsjcppSqlQueryType::DELETE; // return *this; // } diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index f474c52..dffe6dd 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -37,22 +37,25 @@ class WsjcppSqlBuilderHelpers { static std::string escapingStringValue(const std::string &sValue); }; -enum class WsjcppSqlBuilderType { SELECT, INSERT, UPDATE, DELETE }; +enum class WsjcppSqlQueryType { SELECT, INSERT, UPDATE, DELETE }; + +class WsjcppSqlBuilder; class WsjcppSqlQuery { public: - WsjcppSqlQuery(WsjcppSqlBuilderType sqlType, const std::string &tableName); - WsjcppSqlBuilderType sqlType(); + WsjcppSqlQuery(WsjcppSqlQueryType sqlType, WsjcppSqlBuilder *builder, const std::string &tableName); + WsjcppSqlQueryType sqlType(); + WsjcppSqlBuilder &builder(); + WsjcppSqlBuilder *builderRawPtr(); const std::string &tableName(); virtual std::string sql() = 0; private: - WsjcppSqlBuilderType m_sqlType; + WsjcppSqlQueryType m_sqlType; std::string m_tableName; + WsjcppSqlBuilder *m_builder; }; -class WsjcppSqlBuilder; - enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB_CONDITION }; class WsjcppSqlWhereBase { @@ -224,36 +227,27 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { WsjcppSqlWhere &where(); // TODO group by // TODO order by - WsjcppSqlBuilder &compile(); virtual std::string sql() override; private: - std::string m_tableName; - WsjcppSqlBuilder *m_builder; std::shared_ptr> m_where; std::vector m_columns; std::map m_columns_as; }; -// class WsjcppSqlInsert : public WsjcppSqlQuery { -// public: -// WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder); -// WsjcppSqlInsert &colum(const std::string &col, const std::string &col_as = ""); +class WsjcppSqlInsert : public WsjcppSqlQuery { +public: + WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder); + // WsjcppSqlInsert &colum(const std::string &col); -// WsjcppSqlWhere &where(); -// // TODO group by -// // TODO order by -// WsjcppSqlBuilder &compile(); -// virtual std::string sql() override; + WsjcppSqlBuilder &builder(); + virtual std::string sql() override; -// private: -// std::string m_tableName; -// WsjcppSqlBuilder *m_builder; -// std::shared_ptr> m_where; -// std::vector m_columns; -// std::map m_columns_as; -// }; +private: + std::vector m_columns; + std::map m_columns_as; +}; class WsjcppSqlBuilder { public: @@ -261,8 +255,8 @@ class WsjcppSqlBuilder { WsjcppSqlSelect &selectFrom(const std::string &tableName); WsjcppSqlBuilder &insertInto(const std::string &tableName); - // WsjcppSqlBuilder &makeUpdate(const std::string &sSqlTable); - // WsjcppSqlBuilder &makeDelete(const std::string &sSqlTable); + // WsjcppSqlBuilder &update(const std::string &sSqlTable); + // WsjcppSqlBuilder &deleteFrom(const std::string &sSqlTable); bool hasErrors(); std::string sql(); @@ -276,6 +270,6 @@ class WsjcppSqlBuilder { private: std::vector m_errors; std::string m_tableName; - WsjcppSqlBuilderType m_nSqlType; + WsjcppSqlQueryType m_nSqlType; std::vector> m_queries; }; \ No newline at end of file From d1b8c555882ea96537ad54ccd39355e5054ffdcc Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 13:38:31 +0700 Subject: [PATCH 14/23] Implemented first insert version --- src/tests/test_insert.cpp | 30 +++++++++++------- src/wsjcpp_sql_builder.cpp | 65 ++++++++++++++++++++++++++++++++++---- src/wsjcpp_sql_builder.h | 14 +++++--- 3 files changed, 85 insertions(+), 24 deletions(-) diff --git a/src/tests/test_insert.cpp b/src/tests/test_insert.cpp index 24c562d..2120145 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -30,22 +30,28 @@ int main() { WsjcppSqlBuilder builder; - builder.insertInto("table1"); + 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 TABLE_NAME(COL1, COL2) VALUES ('val1', 1);"; - // if (sqlQuery != sqlQueryExpected) { - // std::cerr - // << "Expected:" << std::endl - // << " " << sqlQueryExpected << std::endl - // << ", but got:" << std::endl - // << " " << sqlQuery << 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; + } return 0; } \ No newline at end of file diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index e26cb4f..ff058cc 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -248,10 +248,64 @@ WsjcppSqlInsert::WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder } +WsjcppSqlInsert &WsjcppSqlInsert::colum(const std::string &col) { + m_columns.push_back(col); + return *this; +} + +WsjcppSqlInsert &WsjcppSqlInsert::addColums(const std::vector &cols) { + for (auto col : cols) { + m_columns.push_back(col); + } + return *this; +} + +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 += ")"; + + ret += " VALUES("; + first = true; + for (auto val : m_values) { + if (!first) { + ret += ", "; + } + ret += val; + first = false; + } + ret += ")"; + return ret; }; @@ -259,17 +313,14 @@ std::string WsjcppSqlInsert::sql() { // WsjcppSqlBuilder WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { - m_tableName = tableName; - m_nSqlType = WsjcppSqlQueryType::SELECT; - m_queries.push_back(std::make_shared(m_tableName, this)); + 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()); } -WsjcppSqlBuilder &WsjcppSqlBuilder::insertInto(const std::string &tableName) { - m_tableName = tableName; - m_nSqlType = WsjcppSqlQueryType::INSERT; - return *this; +WsjcppSqlInsert &WsjcppSqlBuilder::insertInto(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + return *(WsjcppSqlInsert *)(m_queries[m_queries.size() -1].get());; } // WsjcppSqlBuilder &WsjcppSqlBuilder::makeUpdate(const std::string &tableName) { diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index dffe6dd..74bceb2 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -239,14 +239,20 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { class WsjcppSqlInsert : public WsjcppSqlQuery { public: WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder); - // WsjcppSqlInsert &colum(const std::string &col); + WsjcppSqlInsert &colum(const std::string &col); + WsjcppSqlInsert &addColums(const std::vector &cols); + + WsjcppSqlInsert &val(const std::string &col); + WsjcppSqlInsert &val(int col); + WsjcppSqlInsert &val(float col); + WsjcppSqlInsert &val(double col); WsjcppSqlBuilder &builder(); virtual std::string sql() override; private: std::vector m_columns; - std::map m_columns_as; + std::vector m_values; }; class WsjcppSqlBuilder { @@ -254,7 +260,7 @@ class WsjcppSqlBuilder { // TODO begin / end transaction can be added here WsjcppSqlSelect &selectFrom(const std::string &tableName); - WsjcppSqlBuilder &insertInto(const std::string &tableName); + WsjcppSqlInsert &insertInto(const std::string &tableName); // WsjcppSqlBuilder &update(const std::string &sSqlTable); // WsjcppSqlBuilder &deleteFrom(const std::string &sSqlTable); @@ -269,7 +275,5 @@ class WsjcppSqlBuilder { private: std::vector m_errors; - std::string m_tableName; - WsjcppSqlQueryType m_nSqlType; std::vector> m_queries; }; \ No newline at end of file From afebee9c6591d7b2e39bc9a035d37ae55dca65a3 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 13:51:38 +0700 Subject: [PATCH 15/23] Added reuse Insert with clearValues() --- src/tests/test_insert.cpp | 20 ++++++++++++++++++++ src/wsjcpp_sql_builder.cpp | 16 +++++++++++++++- src/wsjcpp_sql_builder.h | 2 ++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/tests/test_insert.cpp b/src/tests/test_insert.cpp index 2120145..dd2fe7d 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -53,5 +53,25 @@ int main() { ; 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/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index ff058cc..c46f339 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -260,6 +260,11 @@ WsjcppSqlInsert &WsjcppSqlInsert::addColums(const std::vector &cols return *this; } +WsjcppSqlInsert &WsjcppSqlInsert::clearValues() { + m_values.clear(); + return *this; +} + WsjcppSqlInsert &WsjcppSqlInsert::val(const std::string &val) { m_values.push_back(WsjcppSqlBuilderHelpers::escapingStringValue(val)); return *this; @@ -320,7 +325,16 @@ WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { WsjcppSqlInsert &WsjcppSqlBuilder::insertInto(const std::string &tableName) { m_queries.push_back(std::make_shared(tableName, this)); - return *(WsjcppSqlInsert *)(m_queries[m_queries.size() -1].get());; + return *(WsjcppSqlInsert *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlInsert &WsjcppSqlBuilder::findInsertOrCreate(const std::string &tableName) { + for (auto query : m_queries) { + if (query->sqlType() == WsjcppSqlQueryType::INSERT && query->tableName() == tableName) { + return *(WsjcppSqlInsert *)(query.get()); + } + } + return insertInto(tableName); } // WsjcppSqlBuilder &WsjcppSqlBuilder::makeUpdate(const std::string &tableName) { diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 74bceb2..a4bc433 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -241,6 +241,7 @@ class WsjcppSqlInsert : public WsjcppSqlQuery { WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder); WsjcppSqlInsert &colum(const std::string &col); WsjcppSqlInsert &addColums(const std::vector &cols); + WsjcppSqlInsert &clearValues(); WsjcppSqlInsert &val(const std::string &col); WsjcppSqlInsert &val(int col); @@ -261,6 +262,7 @@ class WsjcppSqlBuilder { WsjcppSqlSelect &selectFrom(const std::string &tableName); WsjcppSqlInsert &insertInto(const std::string &tableName); + WsjcppSqlInsert &findInsertOrCreate(const std::string &tableName); // WsjcppSqlBuilder &update(const std::string &sSqlTable); // WsjcppSqlBuilder &deleteFrom(const std::string &sSqlTable); From 4979e441a2be9409551ae61ca537c49e407e6ab7 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Thu, 29 Jan 2026 14:25:11 +0700 Subject: [PATCH 16/23] Prepare update query --- src/tests/test_update.cpp | 68 +++++++++++++++++++++++++++++++ src/wsjcpp_sql_builder.cpp | 83 +++++++++++++++++++++++++++++++++++--- src/wsjcpp_sql_builder.h | 35 +++++++++++++--- 3 files changed, 174 insertions(+), 12 deletions(-) create mode 100644 src/tests/test_update.cpp diff --git a/src/tests/test_update.cpp b/src/tests/test_update.cpp new file mode 100644 index 0000000..745de3f --- /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() { + WsjcppSqlBuilder 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 c46f339..2ba453e 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -205,7 +205,6 @@ WsjcppSqlWhere &WsjcppSqlSelect::where() { if (!m_where) { m_where = std::make_shared>(nullptr, builderRawPtr(), this); } - return *(m_where.get()); } @@ -314,6 +313,70 @@ std::string WsjcppSqlInsert::sql() { return ret; }; +// --------------------------------------------------------------------- +// WsjcppSqlUpdate + +WsjcppSqlUpdate::WsjcppSqlUpdate(const std::string &tableName, WsjcppSqlBuilder *builder) + : WsjcppSqlQuery(WsjcppSqlQueryType::INSERT, builder, tableName) { + +} + +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; +} + +WsjcppSqlWhere &WsjcppSqlUpdate::where() { + if (!m_where) { + m_where = std::make_shared>(nullptr, builderRawPtr(), this); + } + return *(m_where.get()); +} + +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_where) { + ret += " WHERE " + m_where->sql(); + } + + return ret; +}; + + // --------------------------------------------------------------------- // WsjcppSqlBuilder @@ -337,11 +400,19 @@ WsjcppSqlInsert &WsjcppSqlBuilder::findInsertOrCreate(const std::string &tableNa return insertInto(tableName); } -// WsjcppSqlBuilder &WsjcppSqlBuilder::makeUpdate(const std::string &tableName) { -// m_tableName = tableName; -// m_nSqlType = WsjcppSqlQueryType::UPDATE; -// return *this; -// } +WsjcppSqlUpdate &WsjcppSqlBuilder::update(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + return *(WsjcppSqlUpdate *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlUpdate &WsjcppSqlBuilder::findUpdateOrCreate(const std::string &tableName) { + for (auto query : m_queries) { + if (query->sqlType() == WsjcppSqlQueryType::UPDATE && query->tableName() == tableName) { + return *(WsjcppSqlUpdate *)(query.get()); + } + } + return update(tableName); +} // WsjcppSqlBuilder &WsjcppSqlBuilder::makeDelete(const std::string &tableName) { // m_tableName = tableName; diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index a4bc433..d77b3ba 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -243,12 +243,11 @@ class WsjcppSqlInsert : public WsjcppSqlQuery { WsjcppSqlInsert &addColums(const std::vector &cols); WsjcppSqlInsert &clearValues(); - WsjcppSqlInsert &val(const std::string &col); - WsjcppSqlInsert &val(int col); - WsjcppSqlInsert &val(float col); - WsjcppSqlInsert &val(double col); + WsjcppSqlInsert &val(const std::string &val); + WsjcppSqlInsert &val(int val); + WsjcppSqlInsert &val(float val); + WsjcppSqlInsert &val(double val); - WsjcppSqlBuilder &builder(); virtual std::string sql() override; private: @@ -256,6 +255,27 @@ class WsjcppSqlInsert : public WsjcppSqlQuery { std::vector m_values; }; +class WsjcppSqlUpdate : public WsjcppSqlQuery { +public: + WsjcppSqlUpdate(const std::string &tableName, WsjcppSqlBuilder *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 WsjcppSqlBuilder { public: // TODO begin / end transaction can be added here @@ -263,7 +283,8 @@ class WsjcppSqlBuilder { WsjcppSqlSelect &selectFrom(const std::string &tableName); WsjcppSqlInsert &insertInto(const std::string &tableName); WsjcppSqlInsert &findInsertOrCreate(const std::string &tableName); - // WsjcppSqlBuilder &update(const std::string &sSqlTable); + WsjcppSqlUpdate &update(const std::string &tableName); + WsjcppSqlUpdate &findUpdateOrCreate(const std::string &tableName); // WsjcppSqlBuilder &deleteFrom(const std::string &sSqlTable); bool hasErrors(); @@ -272,6 +293,8 @@ class WsjcppSqlBuilder { protected: friend WsjcppSqlSelect; + friend WsjcppSqlInsert; + friend WsjcppSqlUpdate; friend WsjcppSqlWhere; void addError(const std::string &err); From ebb24e6363a972e1e723f0635d8cdb7ddf030814 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Fri, 30 Jan 2026 11:27:22 +0700 Subject: [PATCH 17/23] Fix formatting --- src/tests/test_insert.cpp | 80 +++++++++++++++++++-------------------- src/tests/test_update.cpp | 68 ++++++++++++++++----------------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/tests/test_insert.cpp b/src/tests/test_insert.cpp index dd2fe7d..ef4febb 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -29,49 +29,49 @@ #include int main() { - WsjcppSqlBuilder builder; - builder.insertInto("table2") - .colum("col1") - .addColums({"col2", "col3"}) - .val("val1") - .val(1) - .val(2.0) + WsjcppSqlBuilder 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; + } - 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) + ; - 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; + } - 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; + return 0; } \ No newline at end of file diff --git a/src/tests/test_update.cpp b/src/tests/test_update.cpp index 745de3f..f836964 100644 --- a/src/tests/test_update.cpp +++ b/src/tests/test_update.cpp @@ -29,40 +29,40 @@ #include int main() { - WsjcppSqlBuilder 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) - ; + WsjcppSqlBuilder 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; - } + 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; + return 0; } \ No newline at end of file From 95f87da52b1a34d91dec8aad6eb71ffab8dde472 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Fri, 30 Jan 2026 11:29:30 +0700 Subject: [PATCH 18/23] Preapred delete query --- src/tests/test_delete.cpp | 65 ++++++++++++++++++++++++++++++++++++++ src/wsjcpp_sql_builder.cpp | 45 ++++++++++++++++++++++---- src/wsjcpp_sql_builder.h | 15 ++++++++- 3 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 src/tests/test_delete.cpp diff --git a/src/tests/test_delete.cpp b/src/tests/test_delete.cpp new file mode 100644 index 0000000..64fd26d --- /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() { + WsjcppSqlBuilder 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/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 2ba453e..753b255 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -317,7 +317,7 @@ std::string WsjcppSqlInsert::sql() { // WsjcppSqlUpdate WsjcppSqlUpdate::WsjcppSqlUpdate(const std::string &tableName, WsjcppSqlBuilder *builder) - : WsjcppSqlQuery(WsjcppSqlQueryType::INSERT, builder, tableName) { + : WsjcppSqlQuery(WsjcppSqlQueryType::UPDATE, builder, tableName) { } @@ -377,6 +377,31 @@ std::string WsjcppSqlUpdate::sql() { }; +// --------------------------------------------------------------------- +// WsjcppSqlDelete + +WsjcppSqlDelete::WsjcppSqlDelete(const std::string &tableName, WsjcppSqlBuilder *builder) + : WsjcppSqlQuery(WsjcppSqlQueryType::DELETE, builder, tableName) { + +} + +WsjcppSqlWhere &WsjcppSqlDelete::where() { + if (!m_where) { + m_where = std::make_shared>(nullptr, builderRawPtr(), this); + } + return *(m_where.get()); +} + +std::string WsjcppSqlDelete::sql() { + std::string ret = "DELETE FROM " + tableName(); + + if (m_where) { + ret += " WHERE " + m_where->sql(); + } + + return ret; +}; + // --------------------------------------------------------------------- // WsjcppSqlBuilder @@ -414,11 +439,19 @@ WsjcppSqlUpdate &WsjcppSqlBuilder::findUpdateOrCreate(const std::string &tableNa return update(tableName); } -// WsjcppSqlBuilder &WsjcppSqlBuilder::makeDelete(const std::string &tableName) { -// m_tableName = tableName; -// m_nSqlType = WsjcppSqlQueryType::DELETE; -// return *this; -// } +WsjcppSqlDelete &WsjcppSqlBuilder::deleteFrom(const std::string &tableName) { + m_queries.push_back(std::make_shared(tableName, this)); + return *(WsjcppSqlDelete *)(m_queries[m_queries.size() -1].get()); +} + +WsjcppSqlDelete &WsjcppSqlBuilder::findDeleteOrCreate(const std::string &tableName) { + for (auto query : m_queries) { + if (query->sqlType() == WsjcppSqlQueryType::DELETE && query->tableName() == tableName) { + return *(WsjcppSqlDelete *)(query.get()); + } + } + return deleteFrom(tableName); +} bool WsjcppSqlBuilder::hasErrors() { return m_errors.size() > 0; diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index d77b3ba..786c6e2 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -276,6 +276,18 @@ class WsjcppSqlUpdate : public WsjcppSqlQuery { std::map m_values; }; +class WsjcppSqlDelete : public WsjcppSqlQuery { +public: + WsjcppSqlDelete(const std::string &tableName, WsjcppSqlBuilder *builder); + + WsjcppSqlWhere &where(); + + virtual std::string sql() override; + +private: + std::shared_ptr> m_where; +}; + class WsjcppSqlBuilder { public: // TODO begin / end transaction can be added here @@ -285,7 +297,8 @@ class WsjcppSqlBuilder { WsjcppSqlInsert &findInsertOrCreate(const std::string &tableName); WsjcppSqlUpdate &update(const std::string &tableName); WsjcppSqlUpdate &findUpdateOrCreate(const std::string &tableName); - // WsjcppSqlBuilder &deleteFrom(const std::string &sSqlTable); + WsjcppSqlDelete &deleteFrom(const std::string &sSqlTable); + WsjcppSqlDelete &findDeleteOrCreate(const std::string &tableName); bool hasErrors(); std::string sql(); From 29e54dad9c404e964b253547accd42129b0638ee Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Fri, 30 Jan 2026 11:31:30 +0700 Subject: [PATCH 19/23] Fix formatting --- src/tests/test_delete.cpp | 62 +++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/tests/test_delete.cpp b/src/tests/test_delete.cpp index 64fd26d..d5d4c0b 100644 --- a/src/tests/test_delete.cpp +++ b/src/tests/test_delete.cpp @@ -29,37 +29,37 @@ #include int main() { - WsjcppSqlBuilder 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) - ; + WsjcppSqlBuilder 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; - } + 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; + return 0; } \ No newline at end of file From 1ba154c5c4ce7bf8a6e0fd609f1ea7a2502a0f00 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Fri, 30 Jan 2026 12:28:32 +0700 Subject: [PATCH 20/23] Fix TODOs for addError (via protected block) --- src/wsjcpp_sql_builder.h | 46 ++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index 786c6e2..bf02092 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -39,6 +39,30 @@ class WsjcppSqlBuilderHelpers { enum class WsjcppSqlQueryType { SELECT, INSERT, UPDATE, DELETE }; + +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; + +protected: + friend WsjcppSqlWhere; + friend WsjcppSqlWhere; + friend WsjcppSqlWhere; + friend WsjcppSqlWhere; + friend WsjcppSqlQuery; + virtual void addError(const std::string &err) = 0; +}; + class WsjcppSqlBuilder; class WsjcppSqlQuery { @@ -140,8 +164,7 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { m_conditions.size() > 0 && m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::LOGICAL_OPERATOR ) { - // TODO - // m_builder->addError("[WARNING] WsjcppSqlWhere. Last item alredy defined as logical_operator. current will be skipped."); + addError("[WARNING] WsjcppSqlWhere. Last item alredy defined as logical_operator. current will be skipped."); return *this; } @@ -154,8 +177,7 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { m_conditions.size() > 0 && m_conditions[m_conditions.size()-1]->type() == WsjcppSqlWhereType::LOGICAL_OPERATOR ) { - // TODO - // m_builder->addError("[WARNING] WsjcppSqlWhere. Last item alredy defined as logical_operator. current will be skipped."); + addError("[WARNING] WsjcppSqlWhere. Last item alredy defined as logical_operator. current will be skipped."); return *this; } m_conditions.push_back(std::make_shared()); @@ -213,6 +235,10 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { return *this; } + void addError(const std::string &err) { + ((IWsjcppSqlBuilder *)m_builder)->addError(err); + } + WsjcppSqlBuilder *m_builder; T *m_query; WsjcppSqlWhere *m_parent; @@ -279,16 +305,13 @@ class WsjcppSqlUpdate : public WsjcppSqlQuery { class WsjcppSqlDelete : public WsjcppSqlQuery { public: WsjcppSqlDelete(const std::string &tableName, WsjcppSqlBuilder *builder); - WsjcppSqlWhere &where(); - virtual std::string sql() override; - private: std::shared_ptr> m_where; }; -class WsjcppSqlBuilder { +class WsjcppSqlBuilder : public IWsjcppSqlBuilder { public: // TODO begin / end transaction can be added here @@ -300,16 +323,17 @@ class WsjcppSqlBuilder { WsjcppSqlDelete &deleteFrom(const std::string &sSqlTable); WsjcppSqlDelete &findDeleteOrCreate(const std::string &tableName); - bool hasErrors(); - std::string sql(); void clear(); + virtual bool hasErrors() override; + virtual std::string sql() override; + protected: friend WsjcppSqlSelect; friend WsjcppSqlInsert; friend WsjcppSqlUpdate; friend WsjcppSqlWhere; - void addError(const std::string &err); + virtual void addError(const std::string &err) override; private: std::vector m_errors; From 56df29b01f6d794e35f81c40a92f1c6cc28939b0 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Fri, 30 Jan 2026 12:35:01 +0700 Subject: [PATCH 21/23] Refactor and prepare dbType --- src/wsjcpp_sql_builder.cpp | 20 ++++++++++++++--- src/wsjcpp_sql_builder.h | 44 ++++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 753b255..7785c86 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -405,6 +405,10 @@ std::string WsjcppSqlDelete::sql() { // --------------------------------------------------------------------- // WsjcppSqlBuilder +WsjcppSqlBuilder::WsjcppSqlBuilder(WsjcppSqlBuilderForDatabase dbType) : m_dbType(dbType) { + +} + WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { m_queries.push_back(std::make_shared(tableName, this)); // TODO check must be select last one; @@ -453,6 +457,10 @@ WsjcppSqlDelete &WsjcppSqlBuilder::findDeleteOrCreate(const std::string &tableNa return deleteFrom(tableName); } +void WsjcppSqlBuilder::clear() { + m_queries.clear(); +} + bool WsjcppSqlBuilder::hasErrors() { return m_errors.size() > 0; } @@ -472,6 +480,12 @@ std::string WsjcppSqlBuilder::sql() { return ret; } -void WsjcppSqlBuilder::clear() { - m_queries.clear(); -} \ No newline at end of file + +void WsjcppSqlBuilder::setDatabaseType(WsjcppSqlBuilderForDatabase dbType) { + m_dbType = dbType; +} + +WsjcppSqlBuilderForDatabase WsjcppSqlBuilder::databaseType() { + return m_dbType; +} + diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index bf02092..e6ebfb2 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -32,14 +32,37 @@ #include #include +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); }; -enum class WsjcppSqlQueryType { SELECT, INSERT, UPDATE, DELETE }; - - +class WsjcppSqlBuilder; class WsjcppSqlQuery; class WsjcppSqlInsert; class WsjcppSqlUpdate; @@ -47,12 +70,13 @@ 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; @@ -63,7 +87,7 @@ class IWsjcppSqlBuilder { virtual void addError(const std::string &err) = 0; }; -class WsjcppSqlBuilder; + class WsjcppSqlQuery { public: @@ -80,8 +104,6 @@ class WsjcppSqlQuery { WsjcppSqlBuilder *m_builder; }; -enum class WsjcppSqlWhereType { LOGICAL_OPERATOR, CONDITION, SUB_CONDITION }; - class WsjcppSqlWhereBase { public: WsjcppSqlWhereBase(WsjcppSqlWhereType type); @@ -104,8 +126,6 @@ class WsjcppSqlWhereAnd : public WsjcppSqlWhereBase { virtual std::string sql() override; }; -enum class WsjcppSqlWhereConditionType { NOT_EQUAL, EQUAL, MORE_THEN, LESS_THEN, LIKE }; - class WsjcppSqlWhereCondition : public WsjcppSqlWhereBase { public: WsjcppSqlWhereCondition(const std::string &name, WsjcppSqlWhereConditionType comparator, const std::string &value); @@ -313,6 +333,8 @@ class WsjcppSqlDelete : public WsjcppSqlQuery { class WsjcppSqlBuilder : public IWsjcppSqlBuilder { public: + WsjcppSqlBuilder(WsjcppSqlBuilderForDatabase dbType = WsjcppSqlBuilderForDatabase::SQLITE3); + // TODO begin / end transaction can be added here WsjcppSqlSelect &selectFrom(const std::string &tableName); @@ -328,6 +350,9 @@ class WsjcppSqlBuilder : public IWsjcppSqlBuilder { virtual bool hasErrors() override; virtual std::string sql() override; + virtual void setDatabaseType(WsjcppSqlBuilderForDatabase dbType) override; + virtual WsjcppSqlBuilderForDatabase databaseType() override; + protected: friend WsjcppSqlSelect; friend WsjcppSqlInsert; @@ -338,4 +363,5 @@ class WsjcppSqlBuilder : public IWsjcppSqlBuilder { private: std::vector m_errors; std::vector> m_queries; + WsjcppSqlBuilderForDatabase m_dbType; }; \ No newline at end of file From d2d935bd7619d8c27c707c7e68626c71783c7423 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Sat, 31 Jan 2026 13:13:17 +0700 Subject: [PATCH 22/23] Preapered namespece wsjcpp --- README.md | 2 +- src/tests/test_delete.cpp | 2 +- src/tests/test_insert.cpp | 2 +- src/tests/test_select.cpp | 2 +- src/tests/test_update.cpp | 2 +- src/wsjcpp_sql_builder.cpp | 47 ++++++++++++++++++++------------------ src/wsjcpp_sql_builder.h | 32 ++++++++++++++------------ 7 files changed, 48 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 59928e7..462151a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Example main func: #include int main(int argc, const char* argv[]) { - WsjcppSqlBuilder builder; + wsjcpp::SqlBuilder builder; builder.selectFrom("table1") .colum("col1") .colum("col2", "c3") diff --git a/src/tests/test_delete.cpp b/src/tests/test_delete.cpp index d5d4c0b..f5d3ac9 100644 --- a/src/tests/test_delete.cpp +++ b/src/tests/test_delete.cpp @@ -29,7 +29,7 @@ #include int main() { - WsjcppSqlBuilder builder; + wsjcpp::SqlBuilder builder; builder.deleteFrom("table4") .where() .equal("col1", "1") diff --git a/src/tests/test_insert.cpp b/src/tests/test_insert.cpp index ef4febb..8ac6ecf 100644 --- a/src/tests/test_insert.cpp +++ b/src/tests/test_insert.cpp @@ -29,7 +29,7 @@ #include int main() { - WsjcppSqlBuilder builder; + wsjcpp::SqlBuilder builder; builder.insertInto("table2") .colum("col1") .addColums({"col2", "col3"}) diff --git a/src/tests/test_select.cpp b/src/tests/test_select.cpp index 9be10c2..ccafea5 100644 --- a/src/tests/test_select.cpp +++ b/src/tests/test_select.cpp @@ -29,7 +29,7 @@ #include int main() { - WsjcppSqlBuilder builder; + wsjcpp::SqlBuilder builder; builder.selectFrom("table1") .colum("col1") .colum("col2", "c3") diff --git a/src/tests/test_update.cpp b/src/tests/test_update.cpp index f836964..bdbfe77 100644 --- a/src/tests/test_update.cpp +++ b/src/tests/test_update.cpp @@ -29,7 +29,7 @@ #include int main() { - WsjcppSqlBuilder builder; + wsjcpp::SqlBuilder builder; builder.update("table3") .set("col1", "val uuu") .set("col2", 1) diff --git a/src/wsjcpp_sql_builder.cpp b/src/wsjcpp_sql_builder.cpp index 7785c86..85d6b97 100644 --- a/src/wsjcpp_sql_builder.cpp +++ b/src/wsjcpp_sql_builder.cpp @@ -29,6 +29,8 @@ #include +namespace wsjcpp { + // --------------------------------------------------------------------- // WsjcppSqlBuilderHelpers @@ -63,7 +65,7 @@ std::string WsjcppSqlBuilderHelpers::escapingStringValue(const std::string &sVal } -WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlQueryType sqlType, WsjcppSqlBuilder *builder, const std::string &tableName) +WsjcppSqlQuery::WsjcppSqlQuery(WsjcppSqlQueryType sqlType, SqlBuilder *builder, const std::string &tableName) : m_sqlType(sqlType), m_builder(builder), m_tableName(tableName) { } @@ -72,11 +74,11 @@ WsjcppSqlQueryType WsjcppSqlQuery::sqlType() { return m_sqlType; } -WsjcppSqlBuilder &WsjcppSqlQuery::builder() { +SqlBuilder &WsjcppSqlQuery::builder() { return *m_builder; } -WsjcppSqlBuilder *WsjcppSqlQuery::builderRawPtr() { +SqlBuilder *WsjcppSqlQuery::builderRawPtr() { return m_builder; } @@ -185,7 +187,7 @@ std::string WsjcppSqlWhereCondition::sql() { // --------------------------------------------------------------------- // WsjcppSqlSelect -WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder *builder) +WsjcppSqlSelect::WsjcppSqlSelect(const std::string &tableName, SqlBuilder *builder) : WsjcppSqlQuery(WsjcppSqlQueryType::SELECT, builder, tableName) { // TODO multitype table names with AS } @@ -242,7 +244,7 @@ std::string WsjcppSqlSelect::sql() { // --------------------------------------------------------------------- // WsjcppSqlInsert -WsjcppSqlInsert::WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder) +WsjcppSqlInsert::WsjcppSqlInsert(const std::string &tableName, SqlBuilder *builder) : WsjcppSqlQuery(WsjcppSqlQueryType::INSERT, builder, tableName) { } @@ -316,7 +318,7 @@ std::string WsjcppSqlInsert::sql() { // --------------------------------------------------------------------- // WsjcppSqlUpdate -WsjcppSqlUpdate::WsjcppSqlUpdate(const std::string &tableName, WsjcppSqlBuilder *builder) +WsjcppSqlUpdate::WsjcppSqlUpdate(const std::string &tableName, SqlBuilder *builder) : WsjcppSqlQuery(WsjcppSqlQueryType::UPDATE, builder, tableName) { } @@ -380,7 +382,7 @@ std::string WsjcppSqlUpdate::sql() { // --------------------------------------------------------------------- // WsjcppSqlDelete -WsjcppSqlDelete::WsjcppSqlDelete(const std::string &tableName, WsjcppSqlBuilder *builder) +WsjcppSqlDelete::WsjcppSqlDelete(const std::string &tableName, SqlBuilder *builder) : WsjcppSqlQuery(WsjcppSqlQueryType::DELETE, builder, tableName) { } @@ -403,24 +405,24 @@ std::string WsjcppSqlDelete::sql() { }; // --------------------------------------------------------------------- -// WsjcppSqlBuilder +// SqlBuilder -WsjcppSqlBuilder::WsjcppSqlBuilder(WsjcppSqlBuilderForDatabase dbType) : m_dbType(dbType) { +SqlBuilder::SqlBuilder(WsjcppSqlBuilderForDatabase dbType) : m_dbType(dbType) { } -WsjcppSqlSelect &WsjcppSqlBuilder::selectFrom(const std::string &tableName) { +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 &WsjcppSqlBuilder::insertInto(const std::string &tableName) { +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 &WsjcppSqlBuilder::findInsertOrCreate(const std::string &tableName) { +WsjcppSqlInsert &SqlBuilder::findInsertOrCreate(const std::string &tableName) { for (auto query : m_queries) { if (query->sqlType() == WsjcppSqlQueryType::INSERT && query->tableName() == tableName) { return *(WsjcppSqlInsert *)(query.get()); @@ -429,12 +431,12 @@ WsjcppSqlInsert &WsjcppSqlBuilder::findInsertOrCreate(const std::string &tableNa return insertInto(tableName); } -WsjcppSqlUpdate &WsjcppSqlBuilder::update(const std::string &tableName) { +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()); } -WsjcppSqlUpdate &WsjcppSqlBuilder::findUpdateOrCreate(const std::string &tableName) { +WsjcppSqlUpdate &SqlBuilder::findUpdateOrCreate(const std::string &tableName) { for (auto query : m_queries) { if (query->sqlType() == WsjcppSqlQueryType::UPDATE && query->tableName() == tableName) { return *(WsjcppSqlUpdate *)(query.get()); @@ -443,12 +445,12 @@ WsjcppSqlUpdate &WsjcppSqlBuilder::findUpdateOrCreate(const std::string &tableNa return update(tableName); } -WsjcppSqlDelete &WsjcppSqlBuilder::deleteFrom(const std::string &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 &WsjcppSqlBuilder::findDeleteOrCreate(const std::string &tableName) { +WsjcppSqlDelete &SqlBuilder::findDeleteOrCreate(const std::string &tableName) { for (auto query : m_queries) { if (query->sqlType() == WsjcppSqlQueryType::DELETE && query->tableName() == tableName) { return *(WsjcppSqlDelete *)(query.get()); @@ -457,19 +459,19 @@ WsjcppSqlDelete &WsjcppSqlBuilder::findDeleteOrCreate(const std::string &tableNa return deleteFrom(tableName); } -void WsjcppSqlBuilder::clear() { +void SqlBuilder::clear() { m_queries.clear(); } -bool WsjcppSqlBuilder::hasErrors() { +bool SqlBuilder::hasErrors() { return m_errors.size() > 0; } -void WsjcppSqlBuilder::addError(const std::string &err) { +void SqlBuilder::addError(const std::string &err) { m_errors.push_back(err); } -std::string WsjcppSqlBuilder::sql() { +std::string SqlBuilder::sql() { std::string ret = ""; for (auto query : m_queries) { if (ret.size() > 0) { @@ -481,11 +483,12 @@ std::string WsjcppSqlBuilder::sql() { } -void WsjcppSqlBuilder::setDatabaseType(WsjcppSqlBuilderForDatabase dbType) { +void SqlBuilder::setDatabaseType(WsjcppSqlBuilderForDatabase dbType) { m_dbType = dbType; } -WsjcppSqlBuilderForDatabase WsjcppSqlBuilder::databaseType() { +WsjcppSqlBuilderForDatabase SqlBuilder::databaseType() { return m_dbType; } +} // namespace wsjcpp diff --git a/src/wsjcpp_sql_builder.h b/src/wsjcpp_sql_builder.h index e6ebfb2..48f2add 100644 --- a/src/wsjcpp_sql_builder.h +++ b/src/wsjcpp_sql_builder.h @@ -32,6 +32,8 @@ #include #include +namespace wsjcpp { + enum class WsjcppSqlQueryType { SELECT, INSERT, @@ -62,7 +64,7 @@ class WsjcppSqlBuilderHelpers { static std::string escapingStringValue(const std::string &sValue); }; -class WsjcppSqlBuilder; +class SqlBuilder; class WsjcppSqlQuery; class WsjcppSqlInsert; class WsjcppSqlUpdate; @@ -91,17 +93,17 @@ class IWsjcppSqlBuilder { class WsjcppSqlQuery { public: - WsjcppSqlQuery(WsjcppSqlQueryType sqlType, WsjcppSqlBuilder *builder, const std::string &tableName); + WsjcppSqlQuery(WsjcppSqlQueryType sqlType, SqlBuilder *builder, const std::string &tableName); WsjcppSqlQueryType sqlType(); - WsjcppSqlBuilder &builder(); - WsjcppSqlBuilder *builderRawPtr(); + SqlBuilder &builder(); + SqlBuilder *builderRawPtr(); const std::string &tableName(); virtual std::string sql() = 0; private: WsjcppSqlQueryType m_sqlType; std::string m_tableName; - WsjcppSqlBuilder *m_builder; + SqlBuilder *m_builder; }; class WsjcppSqlWhereBase { @@ -147,7 +149,7 @@ class WsjcppSqlSelect; template class WsjcppSqlWhere : public WsjcppSqlWhereBase { public: - WsjcppSqlWhere(WsjcppSqlWhere *parent, WsjcppSqlBuilder *builder, T *query) + WsjcppSqlWhere(WsjcppSqlWhere *parent, SqlBuilder *builder, T *query) : WsjcppSqlWhereBase(WsjcppSqlWhereType::SUB_CONDITION), m_parent(parent), m_builder(builder), m_query(query) { } template @@ -259,7 +261,7 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { ((IWsjcppSqlBuilder *)m_builder)->addError(err); } - WsjcppSqlBuilder *m_builder; + SqlBuilder *m_builder; T *m_query; WsjcppSqlWhere *m_parent; std::vector> m_conditions; @@ -267,7 +269,7 @@ class WsjcppSqlWhere : public WsjcppSqlWhereBase { class WsjcppSqlSelect : public WsjcppSqlQuery { public: - WsjcppSqlSelect(const std::string &tableName, WsjcppSqlBuilder *builder); + WsjcppSqlSelect(const std::string &tableName, SqlBuilder *builder); WsjcppSqlSelect &colum(const std::string &col, const std::string &col_as = ""); WsjcppSqlWhere &where(); @@ -284,7 +286,7 @@ class WsjcppSqlSelect : public WsjcppSqlQuery { class WsjcppSqlInsert : public WsjcppSqlQuery { public: - WsjcppSqlInsert(const std::string &tableName, WsjcppSqlBuilder *builder); + WsjcppSqlInsert(const std::string &tableName, SqlBuilder *builder); WsjcppSqlInsert &colum(const std::string &col); WsjcppSqlInsert &addColums(const std::vector &cols); WsjcppSqlInsert &clearValues(); @@ -303,7 +305,7 @@ class WsjcppSqlInsert : public WsjcppSqlQuery { class WsjcppSqlUpdate : public WsjcppSqlQuery { public: - WsjcppSqlUpdate(const std::string &tableName, WsjcppSqlBuilder *builder); + 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); @@ -324,16 +326,16 @@ class WsjcppSqlUpdate : public WsjcppSqlQuery { class WsjcppSqlDelete : public WsjcppSqlQuery { public: - WsjcppSqlDelete(const std::string &tableName, WsjcppSqlBuilder *builder); + WsjcppSqlDelete(const std::string &tableName, SqlBuilder *builder); WsjcppSqlWhere &where(); virtual std::string sql() override; private: std::shared_ptr> m_where; }; -class WsjcppSqlBuilder : public IWsjcppSqlBuilder { +class SqlBuilder : public IWsjcppSqlBuilder { public: - WsjcppSqlBuilder(WsjcppSqlBuilderForDatabase dbType = WsjcppSqlBuilderForDatabase::SQLITE3); + SqlBuilder(WsjcppSqlBuilderForDatabase dbType = WsjcppSqlBuilderForDatabase::SQLITE3); // TODO begin / end transaction can be added here @@ -364,4 +366,6 @@ class WsjcppSqlBuilder : public IWsjcppSqlBuilder { std::vector m_errors; std::vector> m_queries; WsjcppSqlBuilderForDatabase m_dbType; -}; \ No newline at end of file +}; + +} // namespace wsjcpp \ No newline at end of file From e8fd1f47b85f376684e3df4578896fa1d6f3d4f0 Mon Sep 17 00:00:00 2001 From: Evgenii Sopov Date: Sat, 31 Jan 2026 13:15:11 +0700 Subject: [PATCH 23/23] Updated CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) 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