mirror of
https://github.com/getml/sqlgen.git
synced 2026-05-05 06:31:22 -05:00
committed by
GitHub
parent
1424d29c5d
commit
3f8c5556d2
@@ -12,7 +12,7 @@ using Type =
|
||||
rfl::TaggedUnion<"type", types::Unknown, types::Boolean, types::Float32,
|
||||
types::Float64, types::Int8, types::Int16, types::Int32,
|
||||
types::Int64, types::UInt8, types::UInt16, types::UInt32,
|
||||
types::UInt64, types::Text, types::Timestamp,
|
||||
types::UInt64, types::Text, types::Date, types::Timestamp,
|
||||
types::TimestampWithTZ, types::VarChar>;
|
||||
|
||||
} // namespace sqlgen::dynamic
|
||||
|
||||
@@ -65,6 +65,11 @@ struct Text {
|
||||
Properties properties;
|
||||
};
|
||||
|
||||
struct Date {
|
||||
std::string tz;
|
||||
Properties properties;
|
||||
};
|
||||
|
||||
struct Timestamp {
|
||||
std::string tz;
|
||||
Properties properties;
|
||||
|
||||
@@ -23,6 +23,15 @@ std::string replace_all(const std::string& _str, const std::string& _from,
|
||||
std::vector<std::string> split(const std::string& _str,
|
||||
const std::string& _delimiter);
|
||||
|
||||
std::string ltrim(const std::string& _str, const std::string& _chars = " ");
|
||||
|
||||
std::string rtrim(const std::string& _str, const std::string& _chars = " ");
|
||||
|
||||
inline std::string trim(const std::string& _str,
|
||||
const std::string& _chars = " ") {
|
||||
return ltrim(rtrim(_str, _chars), _chars);
|
||||
}
|
||||
|
||||
} // namespace sqlgen::internal::strings
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef SQLGEN_MYSQL_HPP_
|
||||
#define SQLGEN_MYSQL_HPP_
|
||||
|
||||
#include "../sqlgen.hpp"
|
||||
#include "mysql/Credentials.hpp"
|
||||
#include "mysql/connect.hpp"
|
||||
#include "mysql/to_sql.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef SQLGEN_MYSQL_CONNECTION_HPP_
|
||||
#define SQLGEN_MYSQL_CONNECTION_HPP_
|
||||
|
||||
#include <mysql.h>
|
||||
|
||||
#include <memory>
|
||||
#include <rfl.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "../IteratorBase.hpp"
|
||||
#include "../Ref.hpp"
|
||||
#include "../Result.hpp"
|
||||
#include "../Transaction.hpp"
|
||||
#include "../dynamic/Column.hpp"
|
||||
#include "../dynamic/Statement.hpp"
|
||||
#include "../dynamic/Write.hpp"
|
||||
#include "../is_connection.hpp"
|
||||
#include "Credentials.hpp"
|
||||
#include "exec.hpp"
|
||||
#include "to_sql.hpp"
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
class Connection {
|
||||
using ConnPtr = Ref<MYSQL>;
|
||||
using StmtPtr = std::shared_ptr<MYSQL_STMT>;
|
||||
|
||||
public:
|
||||
Connection(const Credentials& _credentials)
|
||||
: conn_(make_conn(_credentials)) {}
|
||||
|
||||
static rfl::Result<Ref<Connection>> make(
|
||||
const Credentials& _credentials) noexcept;
|
||||
|
||||
~Connection() = default;
|
||||
|
||||
Result<Nothing> begin_transaction() noexcept {
|
||||
return execute("START TRANSACTION;");
|
||||
}
|
||||
|
||||
Result<Nothing> commit() noexcept { return execute("COMMIT;"); }
|
||||
|
||||
Result<Nothing> execute(const std::string& _sql) noexcept {
|
||||
return exec(conn_, _sql);
|
||||
}
|
||||
|
||||
Result<Nothing> insert(
|
||||
const dynamic::Insert& _stmt,
|
||||
const std::vector<std::vector<std::optional<std::string>>>&
|
||||
_data) noexcept;
|
||||
|
||||
Result<Ref<IteratorBase>> read(const dynamic::SelectFrom& _query);
|
||||
|
||||
Result<Nothing> rollback() noexcept { return execute("ROLLBACK;"); }
|
||||
|
||||
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
|
||||
return to_sql_impl(_stmt);
|
||||
}
|
||||
|
||||
Result<Nothing> start_write(const dynamic::Write& _stmt);
|
||||
|
||||
Result<Nothing> write(
|
||||
const std::vector<std::vector<std::optional<std::string>>>& _data);
|
||||
|
||||
Result<Nothing> end_write();
|
||||
|
||||
private:
|
||||
/// Actually inserts data based on a prepared statement -
|
||||
/// used by both .insert(...) and .write(...).
|
||||
Result<Nothing> actual_insert(
|
||||
const std::vector<std::vector<std::optional<std::string>>>& _data,
|
||||
MYSQL_STMT* _stmt) const noexcept;
|
||||
|
||||
static ConnPtr make_conn(const Credentials& _credentials);
|
||||
|
||||
Result<StmtPtr> prepare_statement(
|
||||
const std::variant<dynamic::Insert, dynamic::Write>& _stmt)
|
||||
const noexcept;
|
||||
|
||||
private:
|
||||
/// A prepared statement - needed for the read and write operations. Note that
|
||||
/// we have declared it before conn_, meaning it will be destroyed first.
|
||||
StmtPtr stmt_;
|
||||
|
||||
/// The underlying connection.
|
||||
ConnPtr conn_;
|
||||
};
|
||||
|
||||
static_assert(is_connection<Connection>,
|
||||
"Must fulfill the is_connection concept.");
|
||||
static_assert(is_connection<Transaction<Connection>>,
|
||||
"Must fulfill the is_connection concept.");
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SQLGEN_MYSQL_CREDENTIALS_HPP_
|
||||
#define SQLGEN_MYSQL_CREDENTIALS_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
struct Credentials {
|
||||
std::string host;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string dbname = "mysql";
|
||||
int port = 3306;
|
||||
std::string unix_socket = "/var/run/mysqld/mysqld.sock";
|
||||
};
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef SQLGEN_MYSQL_ITERATOR_HPP_
|
||||
#define SQLGEN_MYSQL_ITERATOR_HPP_
|
||||
|
||||
#include <mysql.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../IteratorBase.hpp"
|
||||
#include "../Ref.hpp"
|
||||
#include "../Result.hpp"
|
||||
#include "Connection.hpp"
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
class Iterator : public sqlgen::IteratorBase {
|
||||
using ConnPtr = Ref<MYSQL>;
|
||||
using ResPtr = Ref<MYSQL_RES>;
|
||||
|
||||
public:
|
||||
Iterator(const ResPtr& _res, const ConnPtr& _conn);
|
||||
|
||||
~Iterator();
|
||||
|
||||
/// Whether the end of the available data has been reached.
|
||||
bool end() const final { return end_; }
|
||||
|
||||
/// Returns the next batch of rows.
|
||||
/// If _batch_size is greater than the number of rows left, returns all
|
||||
/// of the rows left.
|
||||
Result<std::vector<std::vector<std::optional<std::string>>>> next(
|
||||
const size_t _batch_size) final;
|
||||
|
||||
private:
|
||||
/// The underlying mysql result.
|
||||
ResPtr res_;
|
||||
|
||||
/// The underlying mysql connection. We have this in here to prevent its
|
||||
/// destruction for the lifetime of the iterator.
|
||||
ConnPtr conn_;
|
||||
|
||||
/// Whether the end is reached.
|
||||
bool end_;
|
||||
};
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef SQLGEN_MYSQL_CONNECT_HPP_
|
||||
#define SQLGEN_MYSQL_CONNECT_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Connection.hpp"
|
||||
#include "Credentials.hpp"
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
inline auto connect(const Credentials& _credentials) {
|
||||
return Connection::make(_credentials);
|
||||
}
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef SQLGEN_MYSQL_EXEC_HPP_
|
||||
#define SQLGEN_MYSQL_EXEC_HPP_
|
||||
|
||||
#include <mysql.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../Ref.hpp"
|
||||
#include "../Result.hpp"
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
Result<Nothing> exec(const Ref<MYSQL>& _conn, const std::string& _sql) noexcept;
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef SQLGEN_MYSQL_MAKE_ERROR_HPP_
|
||||
#define SQLGEN_MYSQL_MAKE_ERROR_HPP_
|
||||
|
||||
#include <mysql.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "../Ref.hpp"
|
||||
#include "../Result.hpp"
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
inline rfl::Unexpected<Error> make_error(const Ref<MYSQL>& _conn) noexcept {
|
||||
return error("MySQL error (" + std::to_string(mysql_errno(_conn.get())) +
|
||||
") [" + mysql_sqlstate(_conn.get()) + "] " +
|
||||
mysql_error(_conn.get()));
|
||||
}
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef SQLGEN_MYSQL_TO_SQL_HPP_
|
||||
#define SQLGEN_MYSQL_TO_SQL_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../dynamic/Statement.hpp"
|
||||
#include "../transpilation/to_sql.hpp"
|
||||
|
||||
namespace sqlgen::mysql {
|
||||
|
||||
/// Transpiles a dynamic general SQL statement to the mysql dialect.
|
||||
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept;
|
||||
|
||||
/// Transpiles any SQL statement to the mysql dialect.
|
||||
template <class T>
|
||||
std::string to_sql(const T& _t) noexcept {
|
||||
if constexpr (std::is_same_v<std::remove_cvref_t<T>, dynamic::Statement>) {
|
||||
return to_sql_impl(_t);
|
||||
} else {
|
||||
return to_sql_impl(transpilation::to_sql(_t));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sqlgen::mysql
|
||||
|
||||
#endif
|
||||
@@ -29,10 +29,16 @@ struct Parser<Timestamp<_format>> {
|
||||
|
||||
static dynamic::Type to_type() noexcept {
|
||||
const std::string format = typename TSType::Format().str();
|
||||
if (format.find("%z") == std::string::npos) {
|
||||
if (format.find("%z") != std::string::npos) {
|
||||
return dynamic::types::TimestampWithTZ{};
|
||||
} else if (format.find("%H") != std::string::npos ||
|
||||
format.find("%M") != std::string::npos ||
|
||||
format.find("%S") != std::string::npos ||
|
||||
format.find("%R") != std::string::npos ||
|
||||
format.find("%T") != std::string::npos) {
|
||||
return dynamic::types::Timestamp{};
|
||||
} else {
|
||||
return dynamic::types::TimestampWithTZ{};
|
||||
return dynamic::types::Date{};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user