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
3236namespace 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
126176namespace sqlgen ::internal {
127-
128177template <class ValueType >
129178struct IteratorType <ValueType, duckdb::Connection> {
130179 using Type = duckdb::Iterator<ValueType>;
0 commit comments