Generate .lib files when building shared on Windows; Bumped to version 0.4.0 (#86)

This commit is contained in:
Dr. Patrick Urbanke (劉自成)
2025-11-03 01:02:00 +01:00
committed by GitHub
parent 86884f388a
commit 5131953c35
34 changed files with 271 additions and 160 deletions

View File

@@ -5,7 +5,6 @@
#include "sqlgen/Flatten.hpp"
#include "sqlgen/ForeignKey.hpp"
#include "sqlgen/Iterator.hpp"
#include "sqlgen/IteratorBase.hpp"
#include "sqlgen/JSON.hpp"
#include "sqlgen/Literal.hpp"
#include "sqlgen/Pattern.hpp"
@@ -44,6 +43,7 @@
#include "sqlgen/read.hpp"
#include "sqlgen/rollback.hpp"
#include "sqlgen/select_from.hpp"
#include "sqlgen/sqlgen_api.hpp"
#include "sqlgen/to.hpp"
#include "sqlgen/update.hpp"
#include "sqlgen/where.hpp"

View File

@@ -5,7 +5,6 @@
#include <memory>
#include <ranges>
#include "IteratorBase.hpp"
#include "Ref.hpp"
#include "Result.hpp"
#include "internal/batch_size.hpp"
@@ -15,23 +14,19 @@
namespace sqlgen {
/// An input_iterator that returns the underlying type.
template <class T>
template <class T, class UnderlyingIteratorT>
class Iterator {
public:
using difference_type = std::ptrdiff_t;
using value_type = Result<T>;
struct End {
bool operator==(const Iterator<T>& _it) const noexcept {
return _it == *this;
}
bool operator==(const Iterator& _it) const noexcept { return _it == *this; }
bool operator!=(const Iterator<T>& _it) const noexcept {
return _it != *this;
}
bool operator!=(const Iterator& _it) const noexcept { return _it != *this; }
};
Iterator(const Ref<IteratorBase>& _it)
Iterator(const Ref<UnderlyingIteratorT>& _it)
: current_batch_(get_next_batch(_it)), it_(_it), ix_(0) {}
~Iterator() = default;
@@ -46,7 +41,7 @@ class Iterator {
bool operator!=(const End& _end) const noexcept { return !(*this == _end); }
Iterator<T>& operator++() noexcept {
Iterator& operator++() noexcept {
++ix_;
if (ix_ >= current_batch_->size() && !it_->end()) {
current_batch_ = get_next_batch(it_);
@@ -59,7 +54,7 @@ class Iterator {
private:
static Ref<std::vector<Result<T>>> get_next_batch(
const Ref<IteratorBase>& _it) noexcept {
const Ref<UnderlyingIteratorT>& _it) noexcept {
using namespace std::ranges::views;
return _it->next(SQLGEN_BATCH_SIZE)
.transform([](auto str_vec) {
@@ -74,7 +69,7 @@ class Iterator {
Ref<std::vector<Result<T>>> current_batch_;
/// The underlying database iterator.
Ref<IteratorBase> it_;
Ref<UnderlyingIteratorT> it_;
/// The current index in the current batch.
size_t ix_;

View File

@@ -1,29 +0,0 @@
#ifndef SQLGEN_ITERATORBASE_HPP_
#define SQLGEN_ITERATORBASE_HPP_
#include <optional>
#include <string>
#include <vector>
#include "Result.hpp"
namespace sqlgen {
/// Abstract base class for an iterator to be returned by Connection::read(...).
struct IteratorBase {
virtual ~IteratorBase() = default;
/// Whether the end of the available data has been reached.
virtual bool end() const = 0;
/// Returns the next batch of rows.
/// If _batch_size is greater than the number of rows left, returns all
/// of the rows left.
virtual Result<std::vector<std::vector<std::optional<std::string>>>> next(
const size_t _batch_size) = 0;
};
} // namespace sqlgen
#endif

View File

@@ -4,7 +4,6 @@
#include <memory>
#include <ranges>
#include "Iterator.hpp"
#include "Result.hpp"
namespace sqlgen {

View File

@@ -6,8 +6,8 @@
#include <optional>
#include <vector>
#include "IteratorBase.hpp"
#include "Ref.hpp"
#include "Result.hpp"
#include "dynamic/Insert.hpp"
#include "dynamic/SelectFrom.hpp"
#include "dynamic/Statement.hpp"

View File

@@ -3,20 +3,29 @@
#include <type_traits>
#include "../Iterator.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
namespace sqlgen::internal {
template <class ValueType, class ConnType>
struct IteratorType;
/// Most database connectors can just use the standard iterator type, but
/// sometimes we need exception, in which case this template can be overridden.
template <class ValueType, class ConnType>
struct IteratorType {
using Type = Iterator<ValueType>;
struct IteratorType<ValueType, Ref<ConnType>> {
using Type =
typename IteratorType<ValueType, std::remove_cvref_t<ConnType>>::Type;
};
template <class ValueType, class ConnType>
struct IteratorType<ValueType, Result<ConnType>> {
using Type =
typename IteratorType<ValueType, std::remove_cvref_t<ConnType>>::Type;
};
// The specific iterator is implemented by each database in (database
// name)/Connection.hpp
template <class T, class ConnType>
using iterator_t = typename IteratorType<std::remove_cvref_t<T>,
std::remove_cvref_t<ConnType>>::Type;

View File

@@ -4,28 +4,33 @@
#include <string>
#include <vector>
#include "../../sqlgen_api.hpp"
namespace sqlgen::internal::strings {
char to_lower(const char ch);
SQLGEN_API char to_lower(const char ch);
std::string to_lower(const std::string& _str);
SQLGEN_API std::string to_lower(const std::string& _str);
char to_upper(const char ch);
SQLGEN_API char to_upper(const char ch);
std::string to_upper(const std::string& _str);
SQLGEN_API std::string to_upper(const std::string& _str);
std::string join(const std::string& _delimiter,
const std::vector<std::string>& _strings);
SQLGEN_API std::string join(const std::string& _delimiter,
const std::vector<std::string>& _strings);
std::string replace_all(const std::string& _str, const std::string& _from,
const std::string& _to);
SQLGEN_API std::string replace_all(const std::string& _str,
const std::string& _from,
const std::string& _to);
std::vector<std::string> split(const std::string& _str,
const std::string& _delimiter);
SQLGEN_API std::vector<std::string> split(const std::string& _str,
const std::string& _delimiter);
std::string ltrim(const std::string& _str, const std::string& _chars = " ");
SQLGEN_API std::string ltrim(const std::string& _str,
const std::string& _chars = " ");
std::string rtrim(const std::string& _str, const std::string& _chars = " ");
SQLGEN_API std::string rtrim(const std::string& _str,
const std::string& _chars = " ");
inline std::string trim(const std::string& _str,
const std::string& _chars = " ") {

View File

@@ -6,7 +6,6 @@
#include <string>
#include <vector>
#include "IteratorBase.hpp"
#include "Ref.hpp"
#include "Result.hpp"
#include "dynamic/SelectFrom.hpp"

View File

@@ -9,7 +9,6 @@
#include <string>
#include "../Iterator.hpp"
#include "../IteratorBase.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../Transaction.hpp"
@@ -19,35 +18,32 @@
#include "../internal/to_container.hpp"
#include "../internal/write_or_insert.hpp"
#include "../is_connection.hpp"
#include "../sqlgen_api.hpp"
#include "../transpilation/value_t.hpp"
#include "Credentials.hpp"
#include "Iterator.hpp"
#include "exec.hpp"
#include "to_sql.hpp"
namespace sqlgen::mysql {
class Connection {
class SQLGEN_API Connection {
using ConnPtr = Ref<MYSQL>;
using StmtPtr = std::shared_ptr<MYSQL_STMT>;
public:
Connection(const Credentials& _credentials)
: conn_(make_conn(_credentials)) {}
Connection(const Credentials& _credentials);
static rfl::Result<Ref<Connection>> make(
const Credentials& _credentials) noexcept;
~Connection() = default;
~Connection();
Result<Nothing> begin_transaction() noexcept {
return execute("START TRANSACTION;");
}
Result<Nothing> begin_transaction() noexcept;
Result<Nothing> commit() noexcept { return execute("COMMIT;"); }
Result<Nothing> commit() noexcept;
Result<Nothing> execute(const std::string& _sql) noexcept {
return exec(conn_, _sql);
}
Result<Nothing> execute(const std::string& _sql) noexcept;
template <class ItBegin, class ItEnd>
Result<Nothing> insert(const dynamic::Insert& _stmt, ItBegin _begin,
@@ -60,15 +56,15 @@ class Connection {
template <class ContainerType>
auto read(const dynamic::SelectFrom& _query) {
using ValueType = transpilation::value_t<ContainerType>;
return internal::to_container<ContainerType>(read_impl(_query).transform(
[](auto&& _it) { return Iterator<ValueType>(std::move(_it)); }));
return internal::to_container<ContainerType>(
read_impl(_query).transform([](auto&& _it) {
return sqlgen::Iterator<ValueType, mysql::Iterator>(std::move(_it));
}));
}
Result<Nothing> rollback() noexcept { return execute("ROLLBACK;"); }
Result<Nothing> rollback() noexcept;
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
return to_sql_impl(_stmt);
}
std::string to_sql(const dynamic::Statement& _stmt) noexcept;
Result<Nothing> start_write(const dynamic::Write& _stmt);
@@ -98,7 +94,7 @@ class Connection {
const std::variant<dynamic::Insert, dynamic::Write>& _stmt)
const noexcept;
Result<Ref<IteratorBase>> read_impl(const dynamic::SelectFrom& _query);
Result<Ref<Iterator>> read_impl(const dynamic::SelectFrom& _query);
Result<Nothing> write_impl(
const std::vector<std::vector<std::optional<std::string>>>& _data);
@@ -119,4 +115,13 @@ static_assert(is_connection<Transaction<Connection>>,
} // namespace sqlgen::mysql
namespace sqlgen::internal {
template <class ValueType>
struct IteratorType<ValueType, mysql::Connection> {
using Type = Iterator<ValueType, mysql::Iterator>;
};
} // namespace sqlgen::internal
#endif

View File

@@ -8,14 +8,13 @@
#include <string>
#include <vector>
#include "../IteratorBase.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "Connection.hpp"
#include "../sqlgen_api.hpp"
namespace sqlgen::mysql {
class Iterator : public sqlgen::IteratorBase {
class SQLGEN_API Iterator {
using ConnPtr = Ref<MYSQL>;
using ResPtr = Ref<MYSQL_RES>;
@@ -25,13 +24,13 @@ class Iterator : public sqlgen::IteratorBase {
~Iterator();
/// Whether the end of the available data has been reached.
bool end() const final { return end_; }
bool end() const;
/// 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;
const size_t _batch_size);
private:
/// The underlying mysql result.

View File

@@ -7,10 +7,12 @@
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../sqlgen_api.hpp"
namespace sqlgen::mysql {
Result<Nothing> exec(const Ref<MYSQL>& _conn, const std::string& _sql) noexcept;
Result<Nothing> SQLGEN_API exec(const Ref<MYSQL>& _conn,
const std::string& _sql) noexcept;
} // namespace sqlgen::mysql

View File

@@ -5,12 +5,13 @@
#include <type_traits>
#include "../dynamic/Statement.hpp"
#include "../sqlgen_api.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;
std::string SQLGEN_API to_sql_impl(const dynamic::Statement& _stmt) noexcept;
/// Transpiles any SQL statement to the mysql dialect.
template <class T>

View File

@@ -8,7 +8,7 @@
#include <stdexcept>
#include <string>
#include "../IteratorBase.hpp"
#include "../Iterator.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../Transaction.hpp"
@@ -18,32 +18,31 @@
#include "../internal/to_container.hpp"
#include "../internal/write_or_insert.hpp"
#include "../is_connection.hpp"
#include "../sqlgen_api.hpp"
#include "../transpilation/value_t.hpp"
#include "Credentials.hpp"
#include "Iterator.hpp"
#include "exec.hpp"
#include "to_sql.hpp"
namespace sqlgen::postgres {
class Connection {
class SQLGEN_API Connection {
using ConnPtr = Ref<PGconn>;
public:
Connection(const Credentials& _credentials)
: conn_(make_conn(_credentials.to_str())), credentials_(_credentials) {}
Connection(const Credentials& _credentials);
static rfl::Result<Ref<Connection>> make(
const Credentials& _credentials) noexcept;
~Connection() = default;
~Connection();
Result<Nothing> begin_transaction() noexcept;
Result<Nothing> commit() noexcept;
Result<Nothing> execute(const std::string& _sql) noexcept {
return exec(conn_, _sql).transform([](auto&&) { return Nothing{}; });
}
Result<Nothing> execute(const std::string& _sql) noexcept;
template <class ItBegin, class ItEnd>
Result<Nothing> insert(const dynamic::Insert& _stmt, ItBegin _begin,
@@ -56,19 +55,18 @@ class Connection {
template <class ContainerType>
auto read(const dynamic::SelectFrom& _query) {
using ValueType = transpilation::value_t<ContainerType>;
return internal::to_container<ContainerType>(read_impl(_query).transform(
[](auto&& _it) { return Iterator<ValueType>(std::move(_it)); }));
return internal::to_container<ContainerType>(
read_impl(_query).transform([](auto&& _it) {
return sqlgen::Iterator<ValueType, postgres::Iterator>(
std::move(_it));
}));
}
Result<Nothing> rollback() noexcept;
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
return postgres::to_sql_impl(_stmt);
}
std::string to_sql(const dynamic::Statement& _stmt) noexcept;
Result<Nothing> start_write(const dynamic::Write& _stmt) {
return execute(postgres::to_sql_impl(_stmt));
}
Result<Nothing> start_write(const dynamic::Write& _stmt);
Result<Nothing> end_write();
@@ -86,7 +84,7 @@ class Connection {
static ConnPtr make_conn(const std::string& _conn_str);
Result<Ref<IteratorBase>> read_impl(const dynamic::SelectFrom& _query);
Result<Ref<Iterator>> read_impl(const dynamic::SelectFrom& _query);
std::string to_buffer(
const std::vector<std::optional<std::string>>& _line) const noexcept;
@@ -107,4 +105,13 @@ static_assert(is_connection<Transaction<Connection>>,
} // namespace sqlgen::postgres
namespace sqlgen::internal {
template <class ValueType>
struct IteratorType<ValueType, postgres::Connection> {
using Type = Iterator<ValueType, postgres::Iterator>;
};
} // namespace sqlgen::internal
#endif

View File

@@ -8,14 +8,13 @@
#include <string>
#include <vector>
#include "../IteratorBase.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "Connection.hpp"
#include "../sqlgen_api.hpp"
namespace sqlgen::postgres {
class Iterator : public sqlgen::IteratorBase {
class SQLGEN_API Iterator {
using ConnPtr = Ref<PGconn>;
public:
@@ -28,13 +27,13 @@ class Iterator : public sqlgen::IteratorBase {
~Iterator();
/// Whether the end of the available data has been reached.
bool end() const final;
bool end() const;
/// 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;
const size_t _batch_size);
Iterator& operator=(const Iterator& _other) = delete;

View File

@@ -8,11 +8,12 @@
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../sqlgen_api.hpp"
namespace sqlgen::postgres {
Result<Ref<PGresult>> exec(const Ref<PGconn>& _conn,
const std::string& _sql) noexcept;
Result<Ref<PGresult>> SQLGEN_API exec(const Ref<PGconn>& _conn,
const std::string& _sql) noexcept;
} // namespace sqlgen::postgres

View File

@@ -5,12 +5,13 @@
#include <type_traits>
#include "../dynamic/Statement.hpp"
#include "../sqlgen_api.hpp"
#include "../transpilation/to_sql.hpp"
namespace sqlgen::postgres {
/// Transpiles a dynamic general SQL statement to the postgres dialect.
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept;
std::string SQLGEN_API to_sql_impl(const dynamic::Statement& _stmt) noexcept;
/// Transpiles any SQL statement to the postgres dialect.
template <class T>

View File

@@ -0,0 +1,14 @@
#ifndef SQLGEN_SQLGEN_API_HPP_
#define SQLGEN_SQLGEN_API_HPP_
#ifdef SQLGEN_BUILD_SHARED
#ifdef _WIN32
#define SQLGEN_API __declspec(dllexport)
#else
#define SQLGEN_API __attribute__((visibility("default")))
#endif
#else
#define SQLGEN_API
#endif
#endif

View File

@@ -9,7 +9,7 @@
#include <stdexcept>
#include <string>
#include "../IteratorBase.hpp"
#include "../Iterator.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../Transaction.hpp"
@@ -17,22 +17,23 @@
#include "../internal/to_container.hpp"
#include "../internal/write_or_insert.hpp"
#include "../is_connection.hpp"
#include "../sqlgen_api.hpp"
#include "../transpilation/value_t.hpp"
#include "Iterator.hpp"
#include "to_sql.hpp"
namespace sqlgen::sqlite {
class Connection {
class SQLGEN_API Connection {
using ConnPtr = Ref<sqlite3>;
using StmtPtr = std::shared_ptr<sqlite3_stmt>;
public:
Connection(const std::string& _fname)
: stmt_(nullptr), conn_(make_conn(_fname)) {}
Connection(const std::string& _fname);
static rfl::Result<Ref<Connection>> make(const std::string& _fname) noexcept;
~Connection() = default;
~Connection();
Result<Nothing> begin_transaction() noexcept;
@@ -51,15 +52,15 @@ class Connection {
template <class ContainerType>
auto read(const dynamic::SelectFrom& _query) {
using ValueType = transpilation::value_t<ContainerType>;
return internal::to_container<ContainerType>(read_impl(_query).transform(
[](auto&& _it) { return Iterator<ValueType>(std::move(_it)); }));
return internal::to_container<ContainerType>(
read_impl(_query).transform([](auto&& _it) {
return sqlgen::Iterator<ValueType, sqlite::Iterator>(std::move(_it));
}));
}
Result<Nothing> rollback() noexcept;
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
return sqlite::to_sql_impl(_stmt);
}
std::string to_sql(const dynamic::Statement& _stmt) noexcept;
Result<Nothing> start_write(const dynamic::Write& _stmt);
@@ -91,7 +92,7 @@ class Connection {
Result<StmtPtr> prepare_statement(const std::string& _sql) const noexcept;
/// Implements the actual read.
Result<Ref<IteratorBase>> read_impl(const dynamic::SelectFrom& _query);
Result<Ref<Iterator>> read_impl(const dynamic::SelectFrom& _query);
/// Implements the actual write
Result<Nothing> write_impl(
@@ -113,4 +114,13 @@ static_assert(is_connection<Transaction<Connection>>,
} // namespace sqlgen::sqlite
namespace sqlgen::internal {
template <class ValueType>
struct IteratorType<ValueType, sqlite::Connection> {
using Type = Iterator<ValueType, sqlite::Iterator>;
};
} // namespace sqlgen::internal
#endif

View File

@@ -7,14 +7,13 @@
#include <string>
#include <vector>
#include "../IteratorBase.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "Connection.hpp"
#include "../sqlgen_api.hpp"
namespace sqlgen::sqlite {
class Iterator : public sqlgen::IteratorBase {
class SQLGEN_API Iterator {
using ConnPtr = Ref<sqlite3>;
using StmtPtr = Ref<sqlite3_stmt>;
@@ -24,13 +23,13 @@ class Iterator : public sqlgen::IteratorBase {
~Iterator();
/// Whether the end of the available data has been reached.
bool end() const final;
bool end() const;
/// 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;
const size_t _batch_size);
private:
void step() { end_ = (sqlite3_step(stmt_.get()) != SQLITE_ROW); }

View File

@@ -4,12 +4,13 @@
#include <string>
#include "../dynamic/Statement.hpp"
#include "../sqlgen_api.hpp"
#include "../transpilation/to_sql.hpp"
namespace sqlgen::sqlite {
/// Transpiles a dynamic general SQL statement to the sqlite dialect.
std::string to_sql_impl(const dynamic::Statement& _stmt) noexcept;
std::string SQLGEN_API to_sql_impl(const dynamic::Statement& _stmt) noexcept;
/// Transpiles any SQL statement to the sqlite dialect.
template <class T>