Skip to content

Commit b833423

Browse files
More sophisticated approach for appender_create
1 parent b20f211 commit b833423

File tree

1 file changed

+68
-19
lines changed

1 file changed

+68
-19
lines changed

include/sqlgen/duckdb/Connection.hpp

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#include "DuckDBConnection.hpp"
2828
#include "Iterator.hpp"
2929
#include "parsing/Parser.hpp"
30+
#include "sqlgen/dynamic/Operation.hpp"
31+
#include "sqlgen/dynamic/SelectFrom.hpp"
32+
#include "sqlgen/transpilation/get_schema.hpp"
33+
#include "sqlgen/transpilation/to_table_or_query.hpp"
3034
#include "to_sql.hpp"
3135

3236
namespace sqlgen::duckdb {
@@ -35,27 +39,41 @@ class Connection {
3539
using ConnPtr = Ref<DuckDBConnection>;
3640

3741
public:
38-
Connection(const ConnPtr& _conn) : conn_(_conn) {}
42+
Connection(const ConnPtr &_conn) : conn_(_conn) {}
3943

4044
static rfl::Result<Ref<Connection>> make(
41-
const std::optional<std::string>& _fname) noexcept;
45+
const std::optional<std::string> &_fname) noexcept;
4246

4347
~Connection() = default;
4448

4549
Result<Nothing> begin_transaction() noexcept;
4650

4751
Result<Nothing> commit() noexcept;
4852

49-
Result<Nothing> execute(const std::string& _sql) noexcept;
53+
Result<Nothing> execute(const std::string &_sql) noexcept;
5054

5155
template <class ItBegin, class ItEnd>
52-
Result<Nothing> insert(const dynamic::Insert&, ItBegin _begin,
56+
Result<Nothing> insert(const dynamic::Insert &_insert_stmt, ItBegin _begin,
5357
ItEnd _end) noexcept {
54-
return error("TODO");
58+
const auto sql = to_sql(_insert_stmt);
59+
60+
return get_duckdb_logical_types(_insert_stmt.table, _insert_stmt.columns)
61+
.and_then([&](const auto &_types) -> Result<Nothing> {
62+
duckdb_appender appender{};
63+
if (duckdb_appender_create_query(
64+
conn_->conn(), sql.c_str(),
65+
static_cast<idx_t>(_insert_stmt.columns.size()),
66+
_types.data(), nullptr, nullptr, &appender) == DuckDBError) {
67+
return error("Could not create appender.");
68+
}
69+
const auto res = write_to_appender(_begin, _end, appender);
70+
duckdb_appender_destroy(&appender);
71+
return res;
72+
});
5573
}
5674

5775
template <class ContainerType>
58-
Result<ContainerType> read(const dynamic::SelectFrom& _query) {
76+
Result<ContainerType> read(const dynamic::SelectFrom &_query) {
5977
using ValueType = transpilation::value_t<ContainerType>;
6078
auto res = Ref<duckdb_result>();
6179
duckdb_query(conn_->conn(), to_sql(_query).c_str(), res.get());
@@ -65,42 +83,74 @@ class Connection {
6583

6684
Result<Nothing> rollback() noexcept;
6785

68-
std::string to_sql(const dynamic::Statement& _stmt) noexcept {
86+
std::string to_sql(const dynamic::Statement &_stmt) noexcept {
6987
return duckdb::to_sql_impl(_stmt);
7088
}
7189

72-
Result<Nothing> start_write(const dynamic::Write&) { return Nothing{}; }
90+
Result<Nothing> start_write(const dynamic::Write &) { return Nothing{}; }
7391

7492
Result<Nothing> end_write() { return Nothing{}; }
7593

7694
template <class ItBegin, class ItEnd>
7795
Result<Nothing> write(ItBegin _begin, ItEnd _end) {
7896
using T =
7997
std::remove_cvref_t<typename std::iterator_traits<ItBegin>::value_type>;
80-
const auto tablename = transpilation::get_tablename<T>();
98+
const auto schema = transpilation::get_schema<T>();
99+
const auto table = transpilation::get_tablename<T>();
81100
duckdb_appender appender{};
82-
if (duckdb_appender_create(conn_->conn(), nullptr, tablename.c_str(),
83-
&appender) == DuckDBError) {
101+
if (duckdb_appender_create(conn_->conn(),
102+
schema ? schema->c_str() : nullptr,
103+
table.c_str(), &appender) == DuckDBError) {
84104
return error("Could not create appender.");
85105
}
106+
const auto res = write_to_appender(_begin, _end, appender);
107+
duckdb_appender_destroy(&appender);
108+
return res;
109+
}
110+
111+
private:
112+
Result<std::vector<duckdb_logical_type>> get_duckdb_logical_types(
113+
const dynamic::Table &_table, const std::vector<std::string> &_columns) {
114+
using namespace std::ranges::views;
115+
116+
const auto fields = internal::collect::vector(
117+
_columns | transform([](const auto &_name) {
118+
return dynamic::SelectFrom::Field{
119+
.val = dynamic::Operation{dynamic::Column{.alias = std::nullopt,
120+
.name = _name}},
121+
.as = std::nullopt};
122+
}));
123+
124+
const auto select_from = dynamic::SelectFrom{
125+
.table_or_query = _table, .fields = fields, .limit = dynamic::Limit{0}};
126+
127+
auto res = Ref<duckdb_result>();
128+
129+
duckdb_query(conn_->conn(), to_sql(select_from).c_str(), res.get());
130+
131+
return internal::collect::vector(
132+
iota(static_cast<idx_t>(fields.size())) |
133+
transform(std::bind_front(duckdb_column_logical_type, res.get())));
134+
}
135+
136+
template <class ItBegin, class ItEnd>
137+
Result<Nothing> write_to_appender(ItBegin _begin, ItEnd _end,
138+
duckdb_appender _appender) {
86139
for (auto it = _begin; it < _end; ++it) {
87-
const auto res = write_row(*it, appender);
140+
const auto res = write_row(*it, _appender);
88141
if (!res) {
89-
duckdb_appender_destroy(&appender);
90142
return res;
91143
}
92-
duckdb_appender_end_row(appender);
144+
duckdb_appender_end_row(_appender);
93145
}
94-
duckdb_appender_destroy(&appender);
95146
return Nothing{};
96147
}
97148

98-
private:
99149
template <class StructT>
100-
Result<Nothing> write_row(const StructT& _struct,
150+
Result<Nothing> write_row(const StructT &_struct,
101151
duckdb_appender _appender) noexcept {
102152
Result<Nothing> res = Nothing{};
103-
rfl::to_view(_struct).apply([&](const auto& _field) {
153+
rfl::to_view(_struct).apply([&](const auto &_field) {
104154
using ValueType = std::remove_cvref_t<std::remove_pointer_t<
105155
typename std::remove_cvref_t<decltype(_field)>::Type>>;
106156
if (res) {
@@ -124,7 +174,6 @@ static_assert(is_connection<Transaction<Connection>>,
124174
} // namespace sqlgen::duckdb
125175

126176
namespace sqlgen::internal {
127-
128177
template <class ValueType>
129178
struct IteratorType<ValueType, duckdb::Connection> {
130179
using Type = duckdb::Iterator<ValueType>;

0 commit comments

Comments
 (0)