Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Tuple expansion for statement and row binding
Browse files Browse the repository at this point in the history
  • Loading branch information
trueqbit committed May 18, 2022
1 parent 605cbac commit a6831ac
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 285 deletions.
61 changes: 13 additions & 48 deletions dev/row_extractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,11 @@ namespace sqlite_orm {
return nullptr;
}

nullptr_t extract(sqlite3_stmt* /*stmt*/, int /*columnIndex*/) const {
nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const {
return nullptr;
}

nullptr_t extract(sqlite3_value* /*value*/) const {
nullptr_t extract(sqlite3_value*) const {
return nullptr;
}
};
Expand All @@ -276,77 +276,42 @@ namespace sqlite_orm {
template<>
struct row_extractor<std::vector<char>> {
std::vector<char> extract(const char* row_value) const {
if(row_value) {
auto len = ::strlen(row_value);
return this->go(row_value, len);
} else {
return {};
}
return {row_value, row_value + (row_value ? ::strlen(row_value) : 0)};
}

std::vector<char> extract(sqlite3_stmt* stmt, int columnIndex) const {
auto bytes = static_cast<const char*>(sqlite3_column_blob(stmt, columnIndex));
auto len = static_cast<size_t>(sqlite3_column_bytes(stmt, columnIndex));
return this->go(bytes, len);
return {bytes, bytes + len};
}

std::vector<char> extract(sqlite3_value* value) const {
auto bytes = static_cast<const char*>(sqlite3_value_blob(value));
auto len = static_cast<size_t>(sqlite3_value_bytes(value));
return this->go(bytes, len);
}

protected:
std::vector<char> go(const char* bytes, size_t len) const {
if(len) {
std::vector<char> res;
res.reserve(len);
std::copy(bytes, bytes + len, std::back_inserter(res));
return res;
} else {
return {};
}
return {bytes, bytes + len};
}
};

template<class... Args>
struct row_extractor<std::tuple<Args...>> {

std::tuple<Args...> extract(char** argv) const {
std::tuple<Args...> res;
this->extract<std::tuple_size<decltype(res)>::value>(res, argv);
return res;
return this->extract(argv, std::make_index_sequence<sizeof...(Args)>{});
}

std::tuple<Args...> extract(sqlite3_stmt* stmt, int /*columnIndex*/) const {
std::tuple<Args...> res;
this->extract<std::tuple_size<decltype(res)>::value>(res, stmt);
return res;
return this->extract(stmt, std::make_index_sequence<sizeof...(Args)>{});
}

protected:
template<size_t I, std::enable_if_t<I != 0, bool> = true>
void extract(std::tuple<Args...>& t, sqlite3_stmt* stmt) const {
using tuple_type = std::tuple_element_t<I - 1, std::tuple<Args...>>;
std::get<I - 1>(t) = row_extractor<tuple_type>().extract(stmt, I - 1);
this->extract<I - 1>(t, stmt);
}

template<size_t I, std::enable_if_t<I == 0, bool> = true>
void extract(std::tuple<Args...>&, sqlite3_stmt*) const {
//..
}

template<size_t I, std::enable_if_t<I != 0, bool> = true>
void extract(std::tuple<Args...>& t, char** argv) const {
using tuple_type = std::tuple_element_t<I - 1, std::tuple<Args...>>;
std::get<I - 1>(t) = row_extractor<tuple_type>().extract(argv[I - 1]);
this->extract<I - 1>(t, argv);
template<size_t... Idx>
std::tuple<Args...> extract(sqlite3_stmt* stmt, std::index_sequence<Idx...>) const {
return std::tuple<Args...>{row_extractor<Args>{}.extract(stmt, Idx)...};
}

template<size_t I, std::enable_if_t<I == 0, bool> = true>
void extract(std::tuple<Args...>&, char**) const {
//..
template<size_t... Idx>
std::tuple<Args...> extract(char** argv, std::index_sequence<Idx...>) const {
return std::tuple<Args...>{row_extractor<Args>{}.extract(argv[Idx])...};
}
};

Expand Down
47 changes: 46 additions & 1 deletion dev/statement_binder.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include <sqlite3.h>
#include <type_traits> // std::enable_if_t, std::is_arithmetic, std::is_same, std::true_type, std::false_type
#include <type_traits> // std::enable_if_t, std::is_arithmetic, std::is_same, std::true_type, std::false_type, std::make_index_sequence, std::index_sequence
#include <memory> // std::default_delete
#include <string> // std::string, std::wstring
#include <vector> // std::vector
Expand All @@ -12,6 +12,7 @@

#include "functional/cxx_universal.h"
#include "functional/cxx_polyfill.h"
#include "functional/cxx_functional_polyfill.h"
#include "is_std_ptr.h"
#include "tuple_helper/tuple_filter.h"
#include "error_code.h"
Expand Down Expand Up @@ -307,6 +308,50 @@ namespace sqlite_orm {
}
};

struct tuple_value_binder {
sqlite3_stmt* stmt = nullptr;

explicit tuple_value_binder(sqlite3_stmt* stmt) : stmt{stmt} {}

template<class Tpl, class Proj>
void operator()(const Tpl& tpl, Proj&& project) const {
(*this)(tpl, std::make_index_sequence<std::tuple_size<Tpl>::value>{}, std::forward<Proj>(project));
}

private:
#ifdef SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED
template<class Tpl, size_t... Idx, class Proj>
void operator()(const Tpl& tpl, std::index_sequence<Idx...>, Proj&& project) const {
(this->bind(polyfill::invoke(std::forward<Proj>(project), std::get<Idx>(tpl)), Idx), ...);
}
#else
template<class Tpl, size_t I, size_t... Idx, class Proj>
void operator()(const Tpl& tpl, std::index_sequence<I, Idx...>, Proj&& project) const {
this->bind(polyfill::invoke(std::forward<Proj>(project), std::get<I>(tpl)), I);
(*this)(tpl, std::index_sequence<Idx...>{}, std::forward<Proj>(project));
}

template<class Tpl, size_t... Idx, class Proj>
void operator()(const Tpl& tpl, std::index_sequence<Idx...>, Proj&& project) const {}
#endif

template<class T>
void bind(const T& t, size_t idx) const {
int rc = statement_binder<T>{}.bind(this->stmt, int(idx + 1), t);
if(SQLITE_OK != rc) {
throw_translated_sqlite_error(stmt);
}
}

template<class T>
void bind(const T* value, size_t idx) const {
if(!value) {
throw std::system_error{orm_error_code::value_is_null};
}
(*this)(*value, idx);
}
};

template<class T>
struct bindable_filter;

Expand Down
19 changes: 8 additions & 11 deletions dev/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -1174,12 +1174,11 @@ namespace sqlite_orm {

sqlite3_stmt* stmt = reset(statement.stmt);

iterate_tuple(statement.expression.columns.columns,
[&tImpl = this->get_impl<object_type>(),
bind_value = field_value_binder{stmt},
&object = statement.expression.obj](auto& memberPointer) mutable {
bind_value(tImpl.table.object_field_value(object, memberPointer));
});
tuple_value_binder{stmt}(
statement.expression.columns.columns,
[&tImpl = this->get_impl<object_type>(), &object = statement.expression.obj](auto& memberPointer) {
return tImpl.table.object_field_value(object, memberPointer);
});
perform_step(stmt);
return sqlite3_last_insert_rowid(sqlite3_db_handle(stmt));
}
Expand Down Expand Up @@ -1483,11 +1482,9 @@ namespace sqlite_orm {
statement_finalizer finalizer{stmt};

auto& tImpl = this->get_impl<O>();
iterate_tuple(
foreignKey.references,
[&tImpl, bind_value = field_value_binder{stmt}, &object](auto& memberPointer) mutable {
bind_value(tImpl.table.object_field_value(object, memberPointer));
});
tuple_value_binder{stmt}(foreignKey.references, [&tImpl, &object](auto& memberPointer) {
return tImpl.table.object_field_value(object, memberPointer);
});
if(SQLITE_ROW != sqlite3_step(stmt)) {
throw_translated_sqlite_error(stmt);
}
Expand Down
Loading

0 comments on commit a6831ac

Please sign in to comment.