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

@@ -2,6 +2,7 @@ name: linux-cxx20-conan
on: [push, pull_request]
jobs:
linux:
strategy:
@@ -35,6 +36,9 @@ jobs:
compiler-version: 12
link: "shared"
name: "${{ github.job }} (${{ matrix.compiler }}-${{ matrix.compiler-version }}-${{ matrix.link }})"
concurrency:
group: ci-${{ github.ref }}-${{ github.job }}-${{ matrix.compiler }}-${{ matrix.compiler-version }}-${{ matrix.link }}
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- name: Checkout

View File

@@ -2,6 +2,7 @@ name: linux-cxx20-vcpkg
on: [push, pull_request]
env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
@@ -60,6 +61,9 @@ jobs:
compiler-version: 14
db: mysql
name: "${{ github.job }} (${{ matrix.compiler }}-${{ matrix.compiler-version }}-${{ matrix.db }})"
concurrency:
group: ci-${{ github.ref }}-${{ github.job }}-${{ matrix.compiler }}-${{ matrix.compiler-version }}-${{ matrix.db }}
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- name: Checkout

View File

@@ -2,6 +2,7 @@ name: macos-cxx20-conan
on: [push, pull_request]
jobs:
macos-clang:
strategy:
@@ -17,6 +18,9 @@ jobs:
- os: "macos-13"
link: "shared"
name: "${{ github.job }} (${{ matrix.os }}-${{ matrix.link }})"
concurrency:
group: ci-${{ github.ref }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.link }}
cancel-in-progress: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout

View File

@@ -2,6 +2,7 @@ name: macos-cxx20-vcpkg
on: [push, pull_request]
env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
@@ -24,6 +25,9 @@ jobs:
- os: "macos-13"
db: mysql
name: "${{ github.job }} (${{ matrix.os }}-${{ matrix.db }})"
concurrency:
group: ci-${{ github.ref }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.db }}
cancel-in-progress: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout

View File

@@ -14,7 +14,11 @@ jobs:
- db: postgres
- db: sqlite
- db: mysql
- db: headers
name: "(windows-${{ matrix.db }})"
concurrency:
group: ci-${{ github.ref }}-windows-${{ matrix.db }}
cancel-in-progress: true
runs-on: windows-latest
steps:
- name: Checkout
@@ -30,21 +34,27 @@ jobs:
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- uses: ilammy/msvc-dev-cmd@v1
- uses: lukka/run-vcpkg@v11
- name: Compile
if: matrix.db == 'headers'
run: |
cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DSQLGEN_CHECK_HEADERS=ON
cmake --build build --config Release -j4
- name: Compile
if: matrix.db == 'postgres'
run: |
cmake -S . -B build -G Ninja -DCMAKE_CXX_STANDARD=20 -DSQLGEN_BUILD_TESTS=ON -DSQLGEN_SQLITE3=OFF -DSQLGEN_BUILD_DRY_TESTS_ONLY=ON
cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Release -DSQLGEN_BUILD_TESTS=ON -DSQLGEN_SQLITE3=OFF -DSQLGEN_BUILD_DRY_TESTS_ONLY=ON -DBUILD_SHARED_LIBS=ON -DVCPKG_TARGET_TRIPLET=x64-windows-release
cmake --build build --config Release -j4
- name: Compile
if: matrix.db == 'sqlite'
run: |
cmake -S . -B build -G Ninja -DCMAKE_CXX_STANDARD=20 -DSQLGEN_BUILD_TESTS=ON -DSQLGEN_POSTGRES=OFF -DSQLGEN_CHECK_HEADERS=ON
cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Release -DSQLGEN_BUILD_TESTS=ON -DSQLGEN_POSTGRES=OFF -DBUILD_SHARED_LIBS=ON -DVCPKG_TARGET_TRIPLET=x64-windows-release
cmake --build build --config Release -j4
- name: Compile
if: matrix.db == 'mysql'
run: |
cmake -S . -B build -G Ninja -DCMAKE_CXX_STANDARD=20 -DSQLGEN_BUILD_TESTS=ON -DSQLGEN_MYSQL=ON -DSQLGEN_POSTGRES=OFF -DSQLGEN_SQLITE3=OFF -DSQLGEN_BUILD_DRY_TESTS_ONLY=ON
cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Release -DSQLGEN_BUILD_TESTS=ON -DSQLGEN_MYSQL=ON -DSQLGEN_POSTGRES=OFF -DSQLGEN_SQLITE3=OFF -DSQLGEN_BUILD_DRY_TESTS_ONLY=ON -DBUILD_SHARED_LIBS=ON -DVCPKG_TARGET_TRIPLET=x64-windows-release
cmake --build build --config Release -j4
- name: Run tests
if: matrix.db != 'headers'
run: |
ctest --test-dir build --output-on-failure

1
.gitignore vendored
View File

@@ -31,6 +31,7 @@
*.out
*.app
.cache/
build/
vcpkg_installed/
CMakeUserPresets.json

View File

@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.23)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
option(SQLGEN_BUILD_SHARED "Build shared library" ${BUILD_SHARED_LIBS})
option(SQLGEN_MYSQL "Enable MySQL support" OFF)
@@ -43,7 +45,7 @@ if (SQLGEN_USE_VCPKG)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE STRING "Vcpkg toolchain file")
endif ()
project(sqlgen VERSION 0.3.0 LANGUAGES CXX)
project(sqlgen VERSION 0.4.0 LANGUAGES CXX)
if (SQLGEN_BUILD_SHARED)
add_library(sqlgen SHARED)
@@ -52,10 +54,30 @@ else()
add_library(sqlgen STATIC)
endif()
add_library(sqlgen::sqlgen ALIAS sqlgen)
if (MSVC)
target_compile_options(sqlgen PRIVATE $<$<CONFIG:Debug>:-Wall>)
target_compile_options(sqlgen PRIVATE
$<$<CONFIG:Debug>:
-Wall
>
$<$<CONFIG:Release>:
-DNDEBUG
>
)
else()
target_compile_options(sqlgen PRIVATE $<$<CONFIG:Debug>:-Wall -Wextra>)
target_compile_options(sqlgen PRIVATE
$<$<CONFIG:Debug>:
-Wall -Wextra -Wpedantic -Wshadow -Wconversion
>
$<$<CONFIG:Release>:
-DNDEBUG
>
)
endif()
if (SQLGEN_BUILD_SHARED)
target_compile_definitions(sqlgen PUBLIC SQLGEN_BUILD_SHARED)
endif()
set(SQLGEN_SOURCES
@@ -114,9 +136,11 @@ set_target_properties(sqlgen PROPERTIES LINKER_LANGUAGE CXX)
target_sources(sqlgen PRIVATE ${SQLGEN_SOURCES})
if (SQLGEN_BUILD_TESTS)
add_library(sqlgen_tests_crt INTERFACE)
target_link_libraries(sqlgen_tests_crt INTERFACE sqlgen GTest::gtest_main)
enable_testing()
find_package(GTest CONFIG REQUIRED)
set(SQLGEN_GTEST_LIB sqlgen GTest::gtest_main)
add_subdirectory(tests)
endif ()

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>

View File

@@ -14,6 +14,11 @@
namespace sqlgen::mysql {
Connection::Connection(const Credentials& _credentials)
: conn_(make_conn(_credentials)) {}
Connection::~Connection() = default;
Result<Nothing> Connection::actual_insert(
const std::vector<std::vector<std::optional<std::string>>>& _data,
MYSQL_STMT* _stmt) const noexcept {
@@ -70,6 +75,16 @@ Result<Nothing> Connection::actual_insert(
return Nothing{};
}
Result<Nothing> Connection::begin_transaction() noexcept {
return execute("START TRANSACTION;");
}
Result<Nothing> Connection::commit() noexcept { return execute("COMMIT;"); }
Result<Nothing> Connection::execute(const std::string& _sql) noexcept {
return exec(conn_, _sql);
}
Result<Nothing> Connection::insert_impl(
const dynamic::Insert& _stmt,
const std::vector<std::vector<std::optional<std::string>>>&
@@ -122,8 +137,7 @@ Result<Connection::StmtPtr> Connection::prepare_statement(
return stmt_ptr;
}
Result<Ref<IteratorBase>> Connection::read_impl(
const dynamic::SelectFrom& _query) {
Result<Ref<Iterator>> Connection::read_impl(const dynamic::SelectFrom& _query) {
const auto sql = mysql::to_sql_impl(_query);
const auto err =
mysql_real_query(conn_.get(), sql.c_str(), static_cast<int>(sql.size()));
@@ -139,6 +153,8 @@ Result<Ref<IteratorBase>> Connection::read_impl(
.transform([&](auto&& _res) { return Ref<Iterator>::make(_res, conn_); });
}
Result<Nothing> Connection::rollback() noexcept { return execute("ROLLBACK;"); }
Result<Nothing> Connection::start_write(const dynamic::Write& _write_stmt) {
if (stmt_) {
return error(
@@ -157,6 +173,10 @@ Result<Nothing> Connection::start_write(const dynamic::Write& _write_stmt) {
});
}
std::string Connection::to_sql(const dynamic::Statement& _stmt) noexcept {
return to_sql_impl(_stmt);
}
Result<Nothing> Connection::write_impl(
const std::vector<std::vector<std::optional<std::string>>>& _data) {
if (!stmt_) {

View File

@@ -7,6 +7,8 @@ Iterator::Iterator(const ResPtr& _res, const ConnPtr& _conn)
Iterator::~Iterator() = default;
bool Iterator::end() const { return end_; }
Result<std::vector<std::vector<std::optional<std::string>>>> Iterator::next(
const size_t _batch_size) {
std::vector<std::vector<std::optional<std::string>>> vec;

View File

@@ -12,12 +12,21 @@
namespace sqlgen::postgres {
Connection::Connection(const Credentials& _credentials)
: conn_(make_conn(_credentials.to_str())), credentials_(_credentials) {}
Connection::~Connection() = default;
Result<Nothing> Connection::begin_transaction() noexcept {
return execute("BEGIN TRANSACTION;");
}
Result<Nothing> Connection::commit() noexcept { return execute("COMMIT;"); }
Result<Nothing> Connection::execute(const std::string& _sql) noexcept {
return exec(conn_, _sql).transform([](auto&&) { return Nothing{}; });
}
Result<Nothing> Connection::end_write() {
if (PQputCopyEnd(conn_.get(), NULL) == -1) {
return error(PQerrorMessage(conn_.get()));
@@ -114,11 +123,10 @@ typename Connection::ConnPtr Connection::make_conn(
return ConnPtr::make(std::shared_ptr<PGconn>(raw_ptr, &PQfinish)).value();
}
Result<Ref<IteratorBase>> Connection::read_impl(
const dynamic::SelectFrom& _query) {
Result<Ref<Iterator>> Connection::read_impl(const dynamic::SelectFrom& _query) {
const auto sql = postgres::to_sql_impl(_query);
try {
return Ref<IteratorBase>(Ref<Iterator>::make(sql, conn_));
return Ref<Iterator>::make(sql, conn_);
} catch (std::exception& e) {
return error(e.what());
}
@@ -146,6 +154,14 @@ std::string Connection::to_buffer(
"\n";
}
std::string Connection::to_sql(const dynamic::Statement& _stmt) noexcept {
return postgres::to_sql_impl(_stmt);
}
Result<Nothing> Connection::start_write(const dynamic::Write& _stmt) {
return execute(postgres::to_sql_impl(_stmt));
}
Result<Nothing> Connection::write_impl(
const std::vector<std::vector<std::optional<std::string>>>& _data) {
for (const auto& line : _data) {

View File

@@ -6,11 +6,15 @@
#include "sqlgen/internal/collect/vector.hpp"
#include "sqlgen/internal/strings/strings.hpp"
#include "sqlgen/sqlite/Iterator.hpp"
#include "sqlgen/sqlite/to_sql.hpp"
namespace sqlgen::sqlite {
Connection::Connection(const std::string& _fname)
: stmt_(nullptr), conn_(make_conn(_fname)) {}
Connection::~Connection() = default;
Result<Nothing> Connection::actual_insert(
const std::vector<std::vector<std::optional<std::string>>>& _data,
sqlite3_stmt* _stmt) const noexcept {
@@ -97,8 +101,7 @@ typename Connection::ConnPtr Connection::make_conn(const std::string& _fname) {
return ConnPtr::make(std::shared_ptr<sqlite3>(conn, &sqlite3_close)).value();
}
Result<Ref<IteratorBase>> Connection::read_impl(
const dynamic::SelectFrom& _query) {
Result<Ref<Iterator>> Connection::read_impl(const dynamic::SelectFrom& _query) {
const auto sql = to_sql_impl(_query);
sqlite3_stmt* p_stmt = nullptr;
@@ -115,9 +118,7 @@ Result<Ref<IteratorBase>> Connection::read_impl(
}
return Ref<sqlite3_stmt>::make(StmtPtr(p_stmt, &sqlite3_finalize))
.transform([&](auto _stmt) -> Ref<IteratorBase> {
return Ref<Iterator>::make(_stmt, conn_);
});
.transform([&](auto _stmt) { return Ref<Iterator>::make(_stmt, conn_); });
}
Result<Connection::StmtPtr> Connection::prepare_statement(
@@ -141,6 +142,10 @@ Result<Connection::StmtPtr> Connection::prepare_statement(
Result<Nothing> Connection::rollback() noexcept { return execute("ROLLBACK;"); }
std::string Connection::to_sql(const dynamic::Statement& _stmt) noexcept {
return sqlite::to_sql_impl(_stmt);
}
Result<Nothing> Connection::start_write(const dynamic::Write& _stmt) {
if (stmt_) {
return error(

View File

@@ -8,11 +8,11 @@ add_executable(
)
target_precompile_headers(sqlgen-mysql-tests PRIVATE [["sqlgen.hpp"]] <iostream> <string> <functional> <gtest/gtest.h>)
target_link_libraries(sqlgen-mysql-tests PRIVATE sqlgen_tests_crt)
target_link_libraries(
sqlgen-mysql-tests
PRIVATE
"${SQLGEN_GTEST_LIB}"
add_custom_command(TARGET sqlgen-mysql-tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:sqlgen-mysql-tests> $<TARGET_RUNTIME_DLLS:sqlgen-mysql-tests>
COMMAND_EXPAND_LISTS
)
find_package(GTest)

View File

@@ -8,11 +8,11 @@ add_executable(
)
target_precompile_headers(sqlgen-postgres-tests PRIVATE [["sqlgen.hpp"]] <iostream> <string> <functional> <gtest/gtest.h>)
target_link_libraries(sqlgen-postgres-tests PRIVATE sqlgen_tests_crt)
target_link_libraries(
sqlgen-postgres-tests
PRIVATE
"${SQLGEN_GTEST_LIB}"
add_custom_command(TARGET sqlgen-postgres-tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:sqlgen-postgres-tests> $<TARGET_RUNTIME_DLLS:sqlgen-postgres-tests>
COMMAND_EXPAND_LISTS
)
find_package(GTest)

View File

@@ -8,11 +8,11 @@ add_executable(
)
target_precompile_headers(sqlgen-sqlite-tests PRIVATE [["sqlgen.hpp"]] <iostream> <string> <functional> <gtest/gtest.h>)
target_link_libraries(sqlgen-sqlite-tests PRIVATE sqlgen_tests_crt)
target_link_libraries(
sqlgen-sqlite-tests
PRIVATE
"${SQLGEN_GTEST_LIB}"
add_custom_command(TARGET sqlgen-sqlite-tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:sqlgen-sqlite-tests> $<TARGET_RUNTIME_DLLS:sqlgen-sqlite-tests>
COMMAND_EXPAND_LISTS
)
find_package(GTest)