From 4a7fc7f00d8421f842362fa3ee8e19bfa32fbefa Mon Sep 17 00:00:00 2001 From: fnc12 Date: Sat, 6 Oct 2018 09:27:04 +0300 Subject: [PATCH 01/63] added asterisk without type and added move constructor to iterator --- dev/aggregate_functions.h | 9 +++++++-- dev/column_result.h | 5 +++++ dev/storage.h | 12 ++++++++++++ include/sqlite_orm/sqlite_orm.h | 26 ++++++++++++++++++++++++-- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/dev/aggregate_functions.h b/dev/aggregate_functions.h index e63aff3c3..d5003bb8e 100644 --- a/dev/aggregate_functions.h +++ b/dev/aggregate_functions.h @@ -34,7 +34,12 @@ namespace sqlite_orm { operator std::string() const { return "COUNT"; } - + }; + + struct count_asterisk_without_type { + operator std::string() const { + return "COUNT"; + } }; template @@ -104,7 +109,7 @@ namespace sqlite_orm { return {t}; } - inline aggregate_functions::count_asterisk_t count() { + inline aggregate_functions::count_asterisk_without_type count() { return {}; } diff --git a/dev/column_result.h b/dev/column_result.h index 22e978772..1df797697 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -171,6 +171,11 @@ namespace sqlite_orm { using type = std::shared_ptr::type>; }; + template<> + struct column_result_t { + using type = int; + }; + template struct column_result_t, void> { using type = typename column_result_t::type; diff --git a/dev/storage.h b/dev/storage.h index 37a1dd23c..99277b6fb 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -109,6 +109,10 @@ namespace sqlite_orm { this->operator++(); } + iterator_t(iterator_t&&) = default; + + iterator_t& operator=(iterator_t&&) = default; + ~iterator_t() { if(this->stmt){ statement_finalizer f{*this->stmt}; @@ -600,6 +604,10 @@ namespace sqlite_orm { template std::string string_from_expression(const aggregate_functions::count_asterisk_t &f, bool /*noTableName*/ = false, bool /*escape*/ = false) { + return this->string_from_expression(aggregate_functions::count_asterisk_without_type{}); + } + + std::string string_from_expression(const aggregate_functions::count_asterisk_without_type &f, bool /*noTableName*/ = false, bool /*escape*/ = false) { std::stringstream ss; ss << static_cast(f) << "(*) "; return ss.str(); @@ -1699,6 +1707,10 @@ namespace sqlite_orm { } } + std::set> parse_table_name(const aggregate_functions::count_asterisk_without_type &c) { + return {}; + } + template std::set> parse_table_name(const asterisk_t &ast) { auto tableName = this->impl.template find_table_name(); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9c56fb6dc..94bc67b45 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3010,7 +3010,12 @@ namespace sqlite_orm { operator std::string() const { return "COUNT"; } - + }; + + struct count_asterisk_without_type { + operator std::string() const { + return "COUNT"; + } }; template @@ -3080,7 +3085,7 @@ namespace sqlite_orm { return {t}; } - inline aggregate_functions::count_asterisk_t count() { + inline aggregate_functions::count_asterisk_without_type count() { return {}; } @@ -4431,6 +4436,11 @@ namespace sqlite_orm { using type = std::shared_ptr::type>; }; + template<> + struct column_result_t { + using type = int; + }; + template struct column_result_t, void> { using type = typename column_result_t::type; @@ -6034,6 +6044,10 @@ namespace sqlite_orm { this->operator++(); } + iterator_t(iterator_t&&) = default; + + iterator_t& operator=(iterator_t&&) = default; + ~iterator_t() { if(this->stmt){ statement_finalizer f{*this->stmt}; @@ -6525,6 +6539,10 @@ namespace sqlite_orm { template std::string string_from_expression(const aggregate_functions::count_asterisk_t &f, bool /*noTableName*/ = false, bool /*escape*/ = false) { + return this->string_from_expression(aggregate_functions::count_asterisk_without_type{}); + } + + std::string string_from_expression(const aggregate_functions::count_asterisk_without_type &f, bool /*noTableName*/ = false, bool /*escape*/ = false) { std::stringstream ss; ss << static_cast(f) << "(*) "; return ss.str(); @@ -7624,6 +7642,10 @@ namespace sqlite_orm { } } + std::set> parse_table_name(const aggregate_functions::count_asterisk_without_type &c) { + return {}; + } + template std::set> parse_table_name(const asterisk_t &ast) { auto tableName = this->impl.template find_table_name(); From dbecb57c781218525443c8d7556e5cf778e74984 Mon Sep 17 00:00:00 2001 From: fnc12 Date: Sat, 6 Oct 2018 09:45:13 +0300 Subject: [PATCH 02/63] added copy ctor to iterator --- dev/storage.h | 4 ++++ include/sqlite_orm/sqlite_orm.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/dev/storage.h b/dev/storage.h index 99277b6fb..7e1216abf 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -109,10 +109,14 @@ namespace sqlite_orm { this->operator++(); } + iterator_t(const iterator_t &) = default; + iterator_t(iterator_t&&) = default; iterator_t& operator=(iterator_t&&) = default; + iterator_t& operator=(const iterator_t&) = default; + ~iterator_t() { if(this->stmt){ statement_finalizer f{*this->stmt}; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 94bc67b45..9257dc5f3 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -6044,10 +6044,14 @@ namespace sqlite_orm { this->operator++(); } + iterator_t(const iterator_t &) = default; + iterator_t(iterator_t&&) = default; iterator_t& operator=(iterator_t&&) = default; + iterator_t& operator=(const iterator_t&) = default; + ~iterator_t() { if(this->stmt){ statement_finalizer f{*this->stmt}; From 3007eb6f6de7bef2201e26433c37d6e578951b6d Mon Sep 17 00:00:00 2001 From: fnc12 Date: Mon, 8 Oct 2018 12:55:45 +0300 Subject: [PATCH 03/63] started except --- dev/select_constraints.h | 39 +++++++++++++++++-- dev/storage.h | 2 +- examples/except.cpp | 69 +++++++++++++++++++++++++++++++++ include/sqlite_orm/sqlite_orm.h | 41 ++++++++++++++++++-- 4 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 examples/except.cpp diff --git a/dev/select_constraints.h b/dev/select_constraints.h index 8d38c189d..ddb565f6d 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -120,18 +120,31 @@ namespace sqlite_orm { }; /** - * Union object type. + * Base for UNION, UNION ALL, EXCEPT and INTERSECT */ template - struct union_t { + struct compound_operator { using left_type = L; using right_type = R; left_type left; right_type right; + + compound_operator(left_type l, right_type r): left(std::move(l)), right(std::move(r)) {} + }; + + /** + * Union object type. + */ + template + struct union_t : public compound_operator { + using super = compound_operator; + using left_type = typename super::left_type; + using right_type = typename super::right_type; + bool all = false; - union_t(left_type l, right_type r, decltype(all) all_): left(std::move(l)), right(std::move(r)), all(all_) { + union_t(left_type l, right_type r, decltype(all) all_): super(std::move(l), std::move(r)), all(all_) { this->left.highest_level = true; this->right.highest_level = true; } @@ -147,6 +160,21 @@ namespace sqlite_orm { } }; + template + struct except_t { + using left_type = L; + using right_type = R; + + left_type left; + right_type right; + + except_t(left_type l, right_type r): left(std::move(l)), right(std::move(r)) {} + + operator std::string() const { + return "EXCEPT"; + } + }; + /** * Generic way to get DISTINCT value from any type. */ @@ -224,6 +252,11 @@ namespace sqlite_orm { return {std::move(lhs), std::move(rhs)}; } + template + internal::except_t except(L lhs, R rhs) { + return {std::move(lhs), std::move(rhs)}; + } + /** * Public function for UNION ALL operator. * lhs and rhs are subselect objects. diff --git a/dev/storage.h b/dev/storage.h index 7e1216abf..00f556f2d 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -2324,7 +2324,7 @@ namespace sqlite_orm { class R, class ...Args, class Ret = typename internal::column_result_t>::type> - std::vector select(union_t op, Args ...args) { + std::vector select(const union_t &op, Args ...args) { std::stringstream ss; ss << this->string_from_expression(op.left) << " "; ss << static_cast(op) << " "; diff --git a/examples/except.cpp b/examples/except.cpp new file mode 100644 index 000000000..d1b327d37 --- /dev/null +++ b/examples/except.cpp @@ -0,0 +1,69 @@ +/** + * Example is implemented from here https://www.tutlane.com/tutorial/sqlite/sqlite-except-operator + */ +#include +#include +#include + +using std::cout; +using std::endl; + +struct DeptMaster { + int deptId = 0; + std::string deptName; +}; + +struct EmpMaster { + int empId = 0; + std::string firstName; + std::string lastName; + long salary; + decltype(DeptMaster::deptId) deptId; +}; + +int main() { + using namespace sqlite_orm; + + auto storage = make_storage("", + make_table("dept_master", + make_column("dept_id", &DeptMaster::deptId, autoincrement(), primary_key()), + make_column("dept_name", &DeptMaster::deptName)), + make_table("emp_master", + make_column("emp_id", &EmpMaster::empId, autoincrement(), primary_key()), + make_column("first_name", &EmpMaster::firstName), + make_column("last_name", &EmpMaster::lastName), + make_column("salary", &EmpMaster::salary), + make_column("dept_id", &EmpMaster::deptId), + foreign_key(&EmpMaster::deptId).references(&DeptMaster::deptId))); + storage.sync_schema(); + storage.remove_all(); + storage.remove_all(); + { + auto valuesToInsert = { + DeptMaster{0, "Admin"}, + DeptMaster{0, "Sales"}, + DeptMaster{0, "Quality Control"}, + DeptMaster{0, "Marketing"}, + }; + storage.insert_range(valuesToInsert.begin(), valuesToInsert.end()); + } + { + auto valuesToInsert = { + EmpMaster{1, "Honey", "Patel", 10100, 1}, + EmpMaster{2, "Shweta", "Jariwala", 19300, 2}, + EmpMaster{3, "Vinay", "Jariwala", 35100, 3}, + EmpMaster{4, "Jagruti", "Viras", 9500, 4}, + }; + storage.replace_range(valuesToInsert.begin(), valuesToInsert.end()); + } + { + // SELECT dept_id + // FROM dept_master + // EXCEPT + // SELECT dept_id + // FROM emp_master + auto rows = storage.select(<#T m#>, <#Args args...#>) + } + + return 0; +} diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9257dc5f3..8a156867f 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3275,18 +3275,31 @@ namespace sqlite_orm { }; /** - * Union object type. + * Base for UNION, UNION ALL, EXCEPT and INTERSECT */ template - struct union_t { + struct compound_operator { using left_type = L; using right_type = R; left_type left; right_type right; + + compound_operator(left_type l, right_type r): left(std::move(l)), right(std::move(r)) {} + }; + + /** + * Union object type. + */ + template + struct union_t : public compound_operator { + using super = compound_operator; + using left_type = typename super::left_type; + using right_type = typename super::right_type; + bool all = false; - union_t(left_type l, right_type r, decltype(all) all_): left(std::move(l)), right(std::move(r)), all(all_) { + union_t(left_type l, right_type r, decltype(all) all_): super(std::move(l), std::move(r)), all(all_) { this->left.highest_level = true; this->right.highest_level = true; } @@ -3302,6 +3315,21 @@ namespace sqlite_orm { } }; + template + struct except_t { + using left_type = L; + using right_type = R; + + left_type left; + right_type right; + + except_t(left_type l, right_type r): left(std::move(l)), right(std::move(r)) {} + + operator std::string() const { + return "EXCEPT"; + } + }; + /** * Generic way to get DISTINCT value from any type. */ @@ -3379,6 +3407,11 @@ namespace sqlite_orm { return {std::move(lhs), std::move(rhs)}; } + template + internal::except_t except(L lhs, R rhs) { + return {std::move(lhs), std::move(rhs)}; + } + /** * Public function for UNION ALL operator. * lhs and rhs are subselect objects. @@ -8259,7 +8292,7 @@ namespace sqlite_orm { class R, class ...Args, class Ret = typename internal::column_result_t>::type> - std::vector select(union_t op, Args ...args) { + std::vector select(const union_t &op, Args ...args) { std::stringstream ss; ss << this->string_from_expression(op.left) << " "; ss << static_cast(op) << " "; From 32cc01bf4b5506f5aa09cc6849fd1690ad8c2d5c Mon Sep 17 00:00:00 2001 From: fnc12 Date: Mon, 8 Oct 2018 13:35:09 +0300 Subject: [PATCH 04/63] added except feature and refactored union and except as compound operator derived classes --- .travis.yml | 2 ++ dev/column_result.h | 8 ++++++ dev/select_constraints.h | 31 ++++++++++++-------- dev/storage.h | 11 ++++---- examples/except.cpp | 12 +++++--- include/sqlite_orm/sqlite_orm.h | 50 ++++++++++++++++++++++----------- tests/static_tests.cpp | 6 ++++ 7 files changed, 82 insertions(+), 38 deletions(-) diff --git a/.travis.yml b/.travis.yml index 89e3eca57..69db23f80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,3 +75,5 @@ script: - ./a.out - clang++ -std=c++1y examples/exists.cpp sqlite.static -I include/ -I sqlite_amalgamation/ -ldl -lpthread -o a.out - ./a.out + - clang++ -std=c++1y examples/except.cpp sqlite.static -I include/ -I sqlite_amalgamation/ -ldl -lpthread -o a.out + - ./a.out diff --git a/dev/column_result.h b/dev/column_result.h index 1df797697..d2c77bdd0 100644 --- a/dev/column_result.h +++ b/dev/column_result.h @@ -269,5 +269,13 @@ namespace sqlite_orm { static_assert(std::is_same::value, "Union subselect queries must return same types"); using type = left_type; }; + + template + struct column_result_t, void> { + using left_type = typename column_result_t::type; + using right_type = typename column_result_t::type; + static_assert(std::is_same::value, "Except subselect queries must return same types"); + using type = left_type; + }; } } diff --git a/dev/select_constraints.h b/dev/select_constraints.h index ddb565f6d..5776d3f20 100644 --- a/dev/select_constraints.h +++ b/dev/select_constraints.h @@ -6,6 +6,15 @@ namespace sqlite_orm { namespace internal { + template