Skip to content

Commit

Permalink
Merge pull request #1137 from FireDaemon/issues/no-rtti
Browse files Browse the repository at this point in the history
Removed dependency on RTTI
  • Loading branch information
fnc12 committed Feb 8, 2023
2 parents 3b960a1 + f7f55c1 commit aeb2fff
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 473 deletions.
11 changes: 7 additions & 4 deletions dev/alias.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <sstream> // std::stringstream
#include <string> // std::string

#include "type_traits.h"

namespace sqlite_orm {

/**
Expand Down Expand Up @@ -86,10 +88,11 @@ namespace sqlite_orm {
* @return column with table alias attached. Place it instead of a column statement in case you need to specify a
* column with table alias prefix like 'a.column'. For more information please look through self_join.cpp example
*/
template<class T, class C>
internal::alias_column_t<T, C> alias_column(C c) {
static_assert(std::is_member_pointer<C>::value,
"alias_column argument must be a member pointer mapped to a storage");
template<class A, class C>
internal::alias_column_t<A, C> alias_column(C c) {
using table_type = internal::type_t<A>;
static_assert(std::is_same<internal::table_type_of_t<C>, table_type>::value,
"Column must be from aliased table");
return {c};
}

Expand Down
45 changes: 7 additions & 38 deletions dev/ast/set.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <sstream> // std::stringstream
#include <type_traits> // std::false_type, std::true_type

#include "table_name_collector.h"
#include "../table_name_collector.h"

namespace sqlite_orm {

Expand Down Expand Up @@ -38,43 +38,12 @@ namespace sqlite_orm {
using entry_t = dynamic_set_entry;
using const_iterator = typename std::vector<entry_t>::const_iterator;

dynamic_set_t(const context_t& context_) :
context(context_), collector([this](const std::type_index& ti) {
return find_table_name(this->context.db_objects, ti);
}) {}
dynamic_set_t(const context_t& context_) : context(context_), collector(this->context.db_objects) {}

dynamic_set_t(const dynamic_set_t& other) :
entries(other.entries), context(other.context), collector([this](const std::type_index& ti) {
return find_table_name(this->context.db_objects, ti);
}) {
collector.table_names = other.collector.table_names;
}

dynamic_set_t(dynamic_set_t&& other) :
entries(std::move(other.entries)), context(std::move(other.context)),
collector([this](const std::type_index& ti) {
return find_table_name(this->context.db_objects, ti);
}) {
collector.table_names = std::move(other.collector.table_names);
}

dynamic_set_t& operator=(const dynamic_set_t& other) {
this->entries = other.entries;
this->context = other.context;
this->collector = table_name_collector([this](const std::type_index& ti) {
return find_table_name(this->context.db_objects, ti);
});
this->collector.table_names = other.collector.table_names;
}

dynamic_set_t& operator=(dynamic_set_t&& other) {
this->entries = std::move(other.entries);
this->context = std::move(other.context);
this->collector = table_name_collector([this](const std::type_index& ti) {
return find_table_name(this->context.db_objects, ti);
});
this->collector.table_names = std::move(other.collector.table_names);
}
dynamic_set_t(const dynamic_set_t& other) = default;
dynamic_set_t(dynamic_set_t&& other) = default;
dynamic_set_t& operator=(const dynamic_set_t& other) = default;
dynamic_set_t& operator=(dynamic_set_t&& other) = default;

template<class L, class R>
void push_back(assign_t<L, R> assign) {
Expand Down Expand Up @@ -102,7 +71,7 @@ namespace sqlite_orm {

std::vector<entry_t> entries;
context_t context;
table_name_collector collector;
table_name_collector<typename context_t::db_objects_type> collector;
};

template<class C>
Expand Down
13 changes: 10 additions & 3 deletions dev/ast_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ namespace sqlite_orm {
* which will be called for any node of provided expression.
* E.g. if we pass `where(is_equal(5, max(&User::id, 10))` then
* callable object will be called with 5, &User::id and 10.
* ast_iterator is used mostly in finding literals to be bound to
* a statement. To use it just call `iterate_ast(object, callable);`
* T is an ast element. E.g. where_t
* ast_iterator is used in finding literals to be bound to
* a statement, and to collect table names.
*
* Note that not all leaves of the expression tree are always visited:
* Column expressions can be more complex, but are passed as a whole to the callable.
* Examples are `column_pointer<>` and `alias_column_t<>`.
*
* To use `ast_iterator` call `iterate_ast(object, callable);`
*
* `T` is an ast element, e.g. where_t
*/
template<class T, class SFINAE = void>
struct ast_iterator {
Expand Down
2 changes: 2 additions & 0 deletions dev/functional/static_magic.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED
#include <type_traits> // std::false_type, std::true_type, std::integral_constant
#endif
#include <utility> // std::forward

namespace sqlite_orm {
Expand Down
4 changes: 2 additions & 2 deletions dev/statement_binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,15 +240,15 @@ namespace sqlite_orm {
template<>
struct statement_binder<std::vector<char>, void> {
int bind(sqlite3_stmt* stmt, int index, const std::vector<char>& value) const {
if(value.size()) {
if(!value.empty()) {
return sqlite3_bind_blob(stmt, index, (const void*)&value.front(), int(value.size()), SQLITE_TRANSIENT);
} else {
return sqlite3_bind_blob(stmt, index, "", 0, SQLITE_TRANSIENT);
}
}

void result(sqlite3_context* context, const std::vector<char>& value) const {
if(value.size()) {
if(!value.empty()) {
sqlite3_result_blob(context, (const void*)&value.front(), int(value.size()), nullptr);
} else {
sqlite3_result_blob(context, "", 0, nullptr);
Expand Down
96 changes: 37 additions & 59 deletions dev/statement_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <memory>
#include <array>
#include "functional/cxx_string_view.h"
#include "functional/cxx_optional.h"

#include "functional/cxx_universal.h"
#include "functional/cxx_functional_polyfill.h"
Expand Down Expand Up @@ -135,7 +136,7 @@ namespace sqlite_orm {
* Serializer for literal values.
*/
template<class T>
struct statement_serializer<T, internal::match_specialization_of<T, literal_holder>> {
struct statement_serializer<T, match_specialization_of<T, literal_holder>> {
using statement_type = T;

template<class Ctx>
Expand Down Expand Up @@ -1076,7 +1077,7 @@ namespace sqlite_orm {
using statement_type = dynamic_set_t<C>;

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) const {
std::string operator()(const statement_type& statement, const Ctx&) const {
std::stringstream ss;
ss << "SET ";
int index = 0;
Expand Down Expand Up @@ -1110,40 +1111,30 @@ namespace sqlite_orm {
}
};

template<class S>
struct table_name_collector_holder;

template<class... Args>
struct table_name_collector_holder<set_t<Args...>> {

table_name_collector_holder(table_name_collector::find_table_name_t find_table_name) :
collector(std::move(find_table_name)) {}

table_name_collector collector;
};

template<class C>
struct table_name_collector_holder<dynamic_set_t<C>> {

table_name_collector_holder(const table_name_collector& collector) : collector(collector) {}
template<class Ctx, class... Args>
std::set<std::pair<std::string, std::string>> collect_table_names(const set_t<Args...>& set, const Ctx& ctx) {
auto collector = make_table_name_collector(ctx.db_objects);
iterate_ast(set, collector);
return std::move(collector.table_names);
}

const table_name_collector& collector;
};
template<class Ctx, class C>
const std::set<std::pair<std::string, std::string>>& collect_table_names(const dynamic_set_t<C>& set,
const Ctx&) {
return set.collector.table_names;
}

template<class Ctx, class... Args>
table_name_collector_holder<set_t<Args...>> make_table_name_collector_holder(const set_t<Args...>& set,
const Ctx& context) {
table_name_collector_holder<set_t<Args...>> holder([&context](const std::type_index& ti) {
return find_table_name(context.db_objects, ti);
});
iterate_ast(set, holder.collector);
return holder;
template<class Ctx, class T, satisfies<is_select, T> = true>
std::set<std::pair<std::string, std::string>> collect_table_names(const T& sel, const Ctx& ctx) {
auto collector = make_table_name_collector(ctx.db_objects);
iterate_ast(sel.col, collector);
iterate_ast(sel.conditions, collector);
return std::move(collector.table_names);
}

template<class C, class Ctx>
table_name_collector_holder<dynamic_set_t<C>> make_table_name_collector_holder(const dynamic_set_t<C>& set,
const Ctx&) {
return {set.collector};
template<class Ctx, class T, satisfies<is_table, T> = true>
std::set<std::pair<std::string, std::string>> collect_table_names(const T& table, const Ctx&) {
return {{table.name, ""}};
}

template<class S, class... Wargs>
Expand All @@ -1152,19 +1143,15 @@ namespace sqlite_orm {

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) const {
std::string tableName;

auto collectorHolder = make_table_name_collector_holder(statement.set, context);
const table_name_collector& collector = collectorHolder.collector;
if(collector.table_names.empty()) {
const auto& tableNames = collect_table_names(statement.set, context);
if(tableNames.empty()) {
throw std::system_error{orm_error_code::no_tables_specified};
}
tableName = collector.table_names.begin()->first;
const std::string& tableName = tableNames.begin()->first;

std::stringstream ss;
ss << "UPDATE " << streaming_identifier(tableName);
ss << ' ' << serialize(statement.set, context);
ss << streaming_conditions_tuple(statement.conditions, context);
ss << "UPDATE " << streaming_identifier(tableName) << ' ' << serialize(statement.set, context)
<< streaming_conditions_tuple(statement.conditions, context);
return ss.str();
}
};
Expand Down Expand Up @@ -1375,17 +1362,12 @@ namespace sqlite_orm {
std::string serialize_get_all_impl(const T& get, const Ctx& context) {
using primary_type = type_t<T>;

table_name_collector collector;
collector.table_names.emplace(lookup_table_name<primary_type>(context.db_objects), "");
// note: not collecting table names from get.conditions;

auto& table = pick_table<primary_type>(context.db_objects);
auto tableNames = collect_table_names(table, context);

std::stringstream ss;
ss << "SELECT " << streaming_table_column_names(table, true);
if(!collector.table_names.empty()) {
ss << " FROM " << streaming_identifiers(collector.table_names);
}
ss << streaming_conditions_tuple(get.conditions, context);
ss << "SELECT " << streaming_table_column_names(table, true) << " FROM "
<< streaming_identifiers(tableNames) << streaming_conditions_tuple(get.conditions, context);
return ss.str();
}

Expand Down Expand Up @@ -1524,24 +1506,20 @@ namespace sqlite_orm {
ss << static_cast<std::string>(distinct(0)) << " ";
}
ss << streaming_serialized(get_column_names(sel.col, context));
table_name_collector collector([&context](const std::type_index& ti) {
return find_table_name(context.db_objects, ti);
});
constexpr bool explicitFromItemsCount = count_tuple<std::tuple<Args...>, is_from>::value;
if(!explicitFromItemsCount) {
iterate_ast(sel.col, collector);
iterate_ast(sel.conditions, collector);
join_iterator<Args...>()([&collector, &context](const auto& c) {
auto tableNames = collect_table_names(sel, context);
join_iterator<Args...>()([&tableNames, &context](const auto& c) {
using original_join_type = typename std::decay_t<decltype(c)>::join_type::type;
using cross_join_type = mapped_type_proxy_t<original_join_type>;
auto crossJoinedTableName = lookup_table_name<cross_join_type>(context.db_objects);
auto tableAliasString = alias_extractor<original_join_type>::get();
std::pair<std::string, std::string> tableNameWithAlias{std::move(crossJoinedTableName),
std::move(tableAliasString)};
collector.table_names.erase(tableNameWithAlias);
tableNames.erase(tableNameWithAlias);
});
if(!collector.table_names.empty() && !isCompoundOperator) {
ss << " FROM " << streaming_identifiers(collector.table_names);
if(!tableNames.empty() && !isCompoundOperator) {
ss << " FROM " << streaming_identifiers(tableNames);
}
}
ss << streaming_conditions_tuple(sel.conditions, context);
Expand Down
26 changes: 6 additions & 20 deletions dev/storage_impl.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
#pragma once

#include <tuple> // std::tuple_size
#include <typeindex> // std::type_index
#include <string> // std::string
#include <type_traits> // std::is_same, std::decay, std::make_index_sequence, std::index_sequence

#include "functional/cxx_universal.h"
#include "functional/cxx_universal.h" // ::nullptr_t
#include "functional/static_magic.h"
#include "tuple_helper/tuple_filter.h"
#include "tuple_helper/tuple_iteration.h"
#include "type_traits.h"
#include "select_constraints.h"
Expand All @@ -28,7 +26,7 @@ namespace sqlite_orm {
return res;
}

template<class Lookup, class DBOs, satisfies<is_db_objects, DBOs> = true>
template<class Lookup, class DBOs, satisfies<is_db_objects, DBOs>>
auto lookup_table(const DBOs& dbObjects) {
return static_if<is_mapped_v<DBOs, Lookup>>(
[](const auto& dbObjects) {
Expand All @@ -37,22 +35,10 @@ namespace sqlite_orm {
empty_callable<nullptr_t>())(dbObjects);
}

template<class DBOs, satisfies<is_db_objects, DBOs> = true>
std::string find_table_name(const DBOs& dbObjects, const std::type_index& ti) {
std::string res;
iterate_tuple<true>(dbObjects, tables_index_sequence<DBOs>{}, [&ti, &res](const auto& table) {
using table_type = std::decay_t<decltype(table)>;
if(ti == typeid(object_type_t<table_type>)) {
res = table.name;
}
});
return res;
}

template<class Lookup, class DBOs, satisfies<is_db_objects, DBOs> = true>
std::string lookup_table_name(const DBOs& dbObjects) {
template<class Lookup, class DBOs, satisfies<is_db_objects, DBOs>>
decltype(auto) lookup_table_name(const DBOs& dbObjects) {
return static_if<is_mapped_v<DBOs, Lookup>>(
[](const auto& dbObjects) {
[](const auto& dbObjects) -> const std::string& {
return pick_table<Lookup>(dbObjects).name;
},
empty_callable<std::string>())(dbObjects);
Expand Down
7 changes: 7 additions & 0 deletions dev/storage_lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,12 @@ namespace sqlite_orm {
using table_type = storage_pick_table_t<Lookup, DBOs>;
return std::get<table_type>(dbObjects);
}

template<class Lookup, class DBOs, satisfies<is_db_objects, DBOs> = true>
auto lookup_table(const DBOs& dbObjects);

template<class Lookup, class DBOs, satisfies<is_db_objects, DBOs> = true>
decltype(auto) lookup_table_name(const DBOs& dbObjects);

}
}
Loading

0 comments on commit aeb2fff

Please sign in to comment.