mirror of
https://github.com/getml/sqlgen.git
synced 2026-02-17 22:28:34 -06:00
Added drop
This commit is contained in:
12
README.md
12
README.md
@@ -12,7 +12,7 @@ sqlgen is closely integrated with our sister project [reflect-cpp](https://githu
|
||||
|
||||
## Documentation
|
||||
|
||||
Click [here](docs/README.md).
|
||||
Click [here](docs).
|
||||
|
||||
## Inserting data
|
||||
|
||||
@@ -141,6 +141,16 @@ Without `AlphaNumeric` validation, this code would be vulnerable to SQL injectio
|
||||
get_people(conn, "Homer' OR '1'='1"); // Attempt to bypass filtering
|
||||
```
|
||||
|
||||
## Dropping a table
|
||||
|
||||
```cpp
|
||||
using namespace sqlgen;
|
||||
|
||||
const auto query = drop<People> | if_exists;
|
||||
|
||||
query(conn).value();
|
||||
```
|
||||
|
||||
## Deleting data
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -74,7 +74,11 @@ using namespace sqlgen;
|
||||
const auto query = delete_from<Person> |
|
||||
where("age"_c >= 18 and "last_name"_c == "Simpson");
|
||||
|
||||
const auto result = query(conn).value();
|
||||
const auto result = query(conn);
|
||||
|
||||
if (!result) {
|
||||
// Error handling
|
||||
}
|
||||
```
|
||||
|
||||
This generates the following SQL:
|
||||
@@ -91,12 +95,12 @@ if you do not want to do that, you can rewrite the example above as follows:
|
||||
const auto query = sqlgen::delete_from<Person> |
|
||||
sqlgen::where(sqlgen::col<"age"> >= 18 and sqlgen::col<"last_name"> == "Simpson");
|
||||
|
||||
const auto result = query(conn).value();
|
||||
const auto result = query(conn);
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The `where` clause is optional - if omitted, all records will be deleted
|
||||
- The `Result<Nothing>` type provides error handling; use `.value()` to extract the result (will throw an exception if there's an error) or refer to the documentation on results for other forms of error handling.
|
||||
- The `Result<Nothing>` type provides error handling; use `.value()` to extract the result (will throw an exception if there's an error) or handle errors as needed or refer to the documentation on `sqlgen::Result<...>` for other forms of error handling.
|
||||
- `"..."_c` refers to the name of the column
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "sqlgen/Varchar.hpp"
|
||||
#include "sqlgen/col.hpp"
|
||||
#include "sqlgen/delete_from.hpp"
|
||||
#include "sqlgen/drop.hpp"
|
||||
#include "sqlgen/if_exists.hpp"
|
||||
#include "sqlgen/limit.hpp"
|
||||
#include "sqlgen/order_by.hpp"
|
||||
#include "sqlgen/patterns.hpp"
|
||||
|
||||
45
include/sqlgen/drop.hpp
Normal file
45
include/sqlgen/drop.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef SQLGEN_DROP_HPP_
|
||||
#define SQLGEN_DROP_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "Connection.hpp"
|
||||
#include "Ref.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "transpilation/to_drop.hpp"
|
||||
|
||||
namespace sqlgen {
|
||||
|
||||
template <class ValueType>
|
||||
Result<Nothing> drop_impl(const Ref<Connection>& _conn, const bool _if_exists) {
|
||||
const auto query = transpilation::to_drop<ValueType>(_if_exists);
|
||||
return _conn->execute(_conn->to_sql(query));
|
||||
}
|
||||
|
||||
template <class ValueType>
|
||||
Result<Nothing> drop_impl(const Result<Ref<Connection>>& _res,
|
||||
const bool _if_exists) {
|
||||
return _res.and_then([&](const auto& _conn) {
|
||||
return drop_impl<ValueType>(_conn, _if_exists);
|
||||
});
|
||||
}
|
||||
|
||||
template <class ValueType>
|
||||
struct Drop {
|
||||
Result<Nothing> operator()(const auto& _conn) const noexcept {
|
||||
try {
|
||||
return drop_impl<ValueType>(_conn, if_exists_);
|
||||
} catch (std::exception& e) {
|
||||
return error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool if_exists_ = false;
|
||||
};
|
||||
|
||||
template <class ContainerType>
|
||||
const auto drop = Drop<ContainerType>{};
|
||||
|
||||
} // namespace sqlgen
|
||||
|
||||
#endif
|
||||
17
include/sqlgen/dynamic/Drop.hpp
Normal file
17
include/sqlgen/dynamic/Drop.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef SQLGEN_DYNAMIC_DROP_HPP_
|
||||
#define SQLGEN_DYNAMIC_DROP_HPP_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "Table.hpp"
|
||||
|
||||
namespace sqlgen::dynamic {
|
||||
|
||||
struct Drop {
|
||||
bool if_exists = true;
|
||||
Table table;
|
||||
};
|
||||
|
||||
} // namespace sqlgen::dynamic
|
||||
|
||||
#endif
|
||||
@@ -5,13 +5,14 @@
|
||||
|
||||
#include "CreateTable.hpp"
|
||||
#include "DeleteFrom.hpp"
|
||||
#include "Drop.hpp"
|
||||
#include "Insert.hpp"
|
||||
#include "SelectFrom.hpp"
|
||||
|
||||
namespace sqlgen::dynamic {
|
||||
|
||||
using Statement =
|
||||
rfl::TaggedUnion<"stmt", CreateTable, DeleteFrom, Insert, SelectFrom>;
|
||||
rfl::TaggedUnion<"stmt", CreateTable, DeleteFrom, Drop, Insert, SelectFrom>;
|
||||
|
||||
} // namespace sqlgen::dynamic
|
||||
|
||||
|
||||
21
include/sqlgen/if_exists.hpp
Normal file
21
include/sqlgen/if_exists.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef SQLGEN_IF_EXISTS_HPP_
|
||||
#define SQLGEN_IF_EXISTS_HPP_
|
||||
|
||||
#include "drop.hpp"
|
||||
|
||||
namespace sqlgen {
|
||||
|
||||
struct IfExists {};
|
||||
|
||||
template <class OtherType>
|
||||
auto operator|(const OtherType& _o, const IfExists&) {
|
||||
auto o = _o;
|
||||
o.if_exists_ = true;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline const auto if_exists = IfExists{};
|
||||
|
||||
} // namespace sqlgen
|
||||
|
||||
#endif
|
||||
29
include/sqlgen/transpilation/to_drop.hpp
Normal file
29
include/sqlgen/transpilation/to_drop.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef SQLGEN_TRANSPILATION_TO_DROP_HPP_
|
||||
#define SQLGEN_TRANSPILATION_TO_DROP_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../Result.hpp"
|
||||
#include "../dynamic/Drop.hpp"
|
||||
#include "../dynamic/Table.hpp"
|
||||
#include "get_schema.hpp"
|
||||
#include "get_tablename.hpp"
|
||||
#include "to_condition.hpp"
|
||||
|
||||
namespace sqlgen::transpilation {
|
||||
|
||||
template <class T>
|
||||
requires std::is_class_v<std::remove_cvref_t<T>> &&
|
||||
std::is_aggregate_v<std::remove_cvref_t<T>>
|
||||
dynamic::Drop to_drop(const bool _if_exists) {
|
||||
return dynamic::Drop{.if_exists = _if_exists,
|
||||
.table = dynamic::Table{.name = get_tablename<T>(),
|
||||
.schema = get_schema<T>()}};
|
||||
}
|
||||
|
||||
} // namespace sqlgen::transpilation
|
||||
|
||||
#endif
|
||||
@@ -6,10 +6,12 @@
|
||||
#include "../CreateTable.hpp"
|
||||
#include "../Insert.hpp"
|
||||
#include "../delete_from.hpp"
|
||||
#include "../drop.hpp"
|
||||
#include "../dynamic/Statement.hpp"
|
||||
#include "../read.hpp"
|
||||
#include "to_create_table.hpp"
|
||||
#include "to_delete_from.hpp"
|
||||
#include "to_drop.hpp"
|
||||
#include "to_insert.hpp"
|
||||
#include "to_select_from.hpp"
|
||||
#include "value_t.hpp"
|
||||
@@ -33,6 +35,13 @@ struct ToSQL<DeleteFrom<T, WhereType>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ToSQL<Drop<T>> {
|
||||
dynamic::Statement operator()(const auto& _drop) const {
|
||||
return to_drop<T>(_drop.if_exists_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ToSQL<Insert<T>> {
|
||||
dynamic::Statement operator()(const auto&) const { return to_insert<T>(); }
|
||||
|
||||
@@ -26,6 +26,8 @@ std::string create_table_to_sql(const dynamic::CreateTable& _stmt) noexcept;
|
||||
|
||||
std::string delete_from_to_sql(const dynamic::DeleteFrom& _stmt) noexcept;
|
||||
|
||||
std::string drop_to_sql(const dynamic::Drop& _stmt) noexcept;
|
||||
|
||||
std::vector<std::string> get_primary_keys(
|
||||
const dynamic::CreateTable& _stmt) noexcept;
|
||||
|
||||
@@ -180,6 +182,25 @@ std::string delete_from_to_sql(const dynamic::DeleteFrom& _stmt) noexcept {
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string drop_to_sql(const dynamic::Drop& _stmt) noexcept {
|
||||
std::stringstream stream;
|
||||
|
||||
stream << "DROP TABLE ";
|
||||
|
||||
if (_stmt.if_exists) {
|
||||
stream << "IF EXISTS ";
|
||||
}
|
||||
|
||||
if (_stmt.table.schema) {
|
||||
stream << wrap_in_quotes(*_stmt.table.schema) << ".";
|
||||
}
|
||||
stream << wrap_in_quotes(_stmt.table.name);
|
||||
|
||||
stream << ";";
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::vector<std::string> get_primary_keys(
|
||||
const dynamic::CreateTable& _stmt) noexcept {
|
||||
using namespace std::ranges::views;
|
||||
@@ -253,6 +274,9 @@ std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept {
|
||||
} else if constexpr (std::is_same_v<S, dynamic::DeleteFrom>) {
|
||||
return delete_from_to_sql(_s);
|
||||
|
||||
} else if constexpr (std::is_same_v<S, dynamic::Drop>) {
|
||||
return drop_to_sql(_s);
|
||||
|
||||
} else if constexpr (std::is_same_v<S, dynamic::Insert>) {
|
||||
return insert_to_sql(_s);
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ std::string create_table_to_sql(const dynamic::CreateTable& _stmt) noexcept;
|
||||
|
||||
std::string delete_from_to_sql(const dynamic::DeleteFrom& _stmt) noexcept;
|
||||
|
||||
std::string drop_to_sql(const dynamic::Drop& _stmt) noexcept;
|
||||
|
||||
std::string insert_to_sql(const dynamic::Insert& _stmt) noexcept;
|
||||
|
||||
std::string properties_to_sql(const dynamic::types::Properties& _p) noexcept;
|
||||
@@ -152,6 +154,25 @@ std::string delete_from_to_sql(const dynamic::DeleteFrom& _stmt) noexcept {
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string drop_to_sql(const dynamic::Drop& _stmt) noexcept {
|
||||
std::stringstream stream;
|
||||
|
||||
stream << "DROP TABLE ";
|
||||
|
||||
if (_stmt.if_exists) {
|
||||
stream << "IF EXISTS ";
|
||||
}
|
||||
|
||||
if (_stmt.table.schema) {
|
||||
stream << "\"" << *_stmt.table.schema << "\".";
|
||||
}
|
||||
stream << "\"" << _stmt.table.name << "\"";
|
||||
|
||||
stream << ";";
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string insert_to_sql(const dynamic::Insert& _stmt) noexcept {
|
||||
using namespace std::ranges::views;
|
||||
|
||||
@@ -240,6 +261,9 @@ std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept {
|
||||
} else if constexpr (std::is_same_v<S, dynamic::DeleteFrom>) {
|
||||
return delete_from_to_sql(_s);
|
||||
|
||||
} else if constexpr (std::is_same_v<S, dynamic::Drop>) {
|
||||
return drop_to_sql(_s);
|
||||
|
||||
} else if constexpr (std::is_same_v<S, dynamic::Insert>) {
|
||||
return insert_to_sql(_s);
|
||||
|
||||
|
||||
25
tests/postgres/test_drop_dry.cpp
Normal file
25
tests/postgres/test_drop_dry.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <sqlgen/transpilation/to_select_from.hpp>
|
||||
|
||||
namespace test_drop_dry {
|
||||
|
||||
struct TestTable {
|
||||
std::string field1;
|
||||
int32_t field2;
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::optional<std::string> nullable;
|
||||
};
|
||||
|
||||
TEST(postgres, test_drop_dry) {
|
||||
using namespace sqlgen;
|
||||
|
||||
const auto query = drop<TestTable> | if_exists;
|
||||
|
||||
const auto expected = R"(DROP TABLE IF EXISTS "TestTable";)";
|
||||
|
||||
EXPECT_EQ(sqlgen::postgres::to_sql(query), expected);
|
||||
}
|
||||
} // namespace test_drop_dry
|
||||
40
tests/sqlite/test_drop.cpp
Normal file
40
tests/sqlite/test_drop.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/sqlite.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_drop {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(sqlite, test_drop) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto conn = sqlgen::sqlite::connect();
|
||||
|
||||
sqlgen::write(conn, people1);
|
||||
|
||||
using namespace sqlgen;
|
||||
|
||||
const auto query = drop<Person> | if_exists;
|
||||
|
||||
query(conn).value();
|
||||
}
|
||||
|
||||
} // namespace test_drop
|
||||
Reference in New Issue
Block a user