Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/dev' into update-static-assert2
Browse files Browse the repository at this point in the history
  • Loading branch information
trueqbit committed Oct 24, 2023
2 parents c05c6f8 + 0cf48ec commit 55b7be6
Show file tree
Hide file tree
Showing 20 changed files with 269 additions and 95 deletions.
6 changes: 3 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ for:
install:
- |-
cd C:\Tools\vcpkg
git fetch --tags && git checkout 2023.06.20
git fetch --tags && git checkout 2023.10.19
cd %APPVEYOR_BUILD_FOLDER%
C:\Tools\vcpkg\bootstrap-vcpkg.bat -disableMetrics
C:\Tools\vcpkg\vcpkg integrate install
Expand Down Expand Up @@ -140,7 +140,7 @@ for:
install:
- |-
pushd $HOME/vcpkg
git fetch --tags && git checkout 2023.06.20
git fetch --tags && git checkout 2023.10.19
popd
$HOME/vcpkg/bootstrap-vcpkg.sh -disableMetrics
$HOME/vcpkg/vcpkg integrate install --overlay-triplets=vcpkg/triplets
Expand Down Expand Up @@ -168,7 +168,7 @@ for:
# using custom vcpkg triplets for building and linking dynamic dependent libraries
install:
- |-
git clone --depth 1 --branch 2023.06.20 https://github.com/microsoft/vcpkg.git $HOME/vcpkg
git clone --depth 1 --branch 2023.10.19 https://github.com/microsoft/vcpkg.git $HOME/vcpkg
$HOME/vcpkg/bootstrap-vcpkg.sh -disableMetrics
$HOME/vcpkg/vcpkg integrate install --overlay-triplets=vcpkg/triplets
vcpkg install sqlite3[core,dbstat,math,json1,fts5] catch2 --overlay-triplets=vcpkg/triplets
Expand Down
84 changes: 70 additions & 14 deletions dev/alias.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "functional/cxx_type_traits_polyfill.h"
#include "type_traits.h"
#include "alias_traits.h"
#include "table_type_of.h"
#include "tags.h"

namespace sqlite_orm {
Expand Down Expand Up @@ -67,6 +68,10 @@ namespace sqlite_orm {
column_type column;
};

template<class T>
SQLITE_ORM_INLINE_VAR constexpr bool
is_operator_argument_v<T, std::enable_if_t<polyfill::is_specialization_of_v<T, alias_column_t>>> = true;

struct basic_table;

/*
Expand Down Expand Up @@ -166,30 +171,81 @@ 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'.
* Using a column pointer, create a column reference to an aliased table column.
*
* Example:
* using als = alias_u<User>;
* select(alias_column<als>(column<User>(&User::id)))
*/
template<class A, class C, std::enable_if_t<internal::is_table_alias_v<A>, bool> = true>
internal::alias_column_t<A, C> alias_column(C c) {
using aliased_type = internal::type_t<A>;
static_assert(std::is_same<polyfill::detected_t<internal::table_type_of_t, C>, aliased_type>::value,
"Column must be from aliased table");
return {c};
constexpr auto alias_column(C field) {
using namespace ::sqlite_orm::internal;
using aliased_type = type_t<A>;
static_assert(is_field_of_v<C, aliased_type>, "Column must be from aliased table");

return alias_column_t<A, C>{std::move(field)};
}

/**
* Using an object member field, create a column reference to an aliased table column.
*
* @note The object member pointer can be from a derived class without explicitly forming a column pointer.
*
* Example:
* using als = alias_u<User>;
* select(alias_column<als>(&User::id))
*/
template<class A, class F, class O, std::enable_if_t<internal::is_table_alias_v<A>, bool> = true>
constexpr auto alias_column(F O::*field) {
using namespace ::sqlite_orm::internal;
using aliased_type = type_t<A>;
static_assert(is_field_of_v<F O::*, aliased_type>, "Column must be from aliased table");

using C1 =
std::conditional_t<std::is_same<O, aliased_type>::value, F O::*, column_pointer<aliased_type, F O::*>>;
return alias_column_t<A, C1>{{field}};
}

#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
/**
* Create a column reference to an aliased table column.
*
* @note An object member pointer can be from a derived class without explicitly forming a column pointer.
*
* Example:
* constexpr auto als = "u"_alias.for_<User>();
* select(alias_column<als>(&User::id))
*/
template<orm_table_alias auto als, class C>
auto alias_column(C c) {
constexpr auto alias_column(C field) {
using namespace ::sqlite_orm::internal;
using A = std::remove_const_t<decltype(als)>;
using aliased_type = internal::type_t<A>;
static_assert(std::is_same_v<polyfill::detected_t<internal::table_type_of_t, C>, aliased_type>,
"Column must be from aliased table");
return internal::alias_column_t<A, decltype(c)>{c};
using aliased_type = type_t<A>;
static_assert(is_field_of_v<C, aliased_type>, "Column must be from aliased table");

if constexpr(is_column_pointer_v<C>) {
return alias_column_t<A, C>{std::move(field)};
} else if constexpr(std::is_same_v<member_object_type_t<C>, aliased_type>) {
return alias_column_t<A, C>{field};
} else {
// wrap in column_pointer
using C1 = column_pointer<aliased_type, C>;
return alias_column_t<A, C1>{{field}};
}
}

/**
* Create a column reference to an aliased table column.
*
* @note An object member pointer can be from a derived class without explicitly forming a column pointer.
*
* Example:
* constexpr auto als = "u"_alias.for_<User>();
* select(als->*&User::id)
*/
template<orm_table_alias A, class F>
constexpr auto operator->*(const A&, F field) {
return internal::alias_column_t<A, decltype(field)>{field};
constexpr auto operator->*(const A& /*tableAlias*/, F field) {
return alias_column<A>(std::move(field));
}
#endif

Expand Down
7 changes: 3 additions & 4 deletions dev/column_pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ namespace sqlite_orm {
*/
template<class T, class F>
struct column_pointer {
using self = column_pointer<T, F>;
using type = T;
using field_type = F;

Expand All @@ -36,8 +35,8 @@ namespace sqlite_orm {
* struct MyType : BaseType { ... };
* storage.select(column<MyType>(&BaseType::id));
*/
template<class T, class F>
internal::column_pointer<T, F> column(F f) {
return {std::move(f)};
template<class Object, class F, internal::satisfies_not<internal::is_recordset_alias, Object> = true>
constexpr internal::column_pointer<Object, F> column(F field) {
return {std::move(field)};
}
}
4 changes: 0 additions & 4 deletions dev/functional/cxx_core_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@
#define SQLITE_ORM_FOLD_EXPRESSIONS_SUPPORTED
#endif

#if __cpp_inline_variables >= 201606L
#define SQLITE_ORM_INLINE_VARIABLES_SUPPORTED
#endif

#if __cpp_if_constexpr >= 201606L
#define SQLITE_ORM_IF_CONSTEXPR_SUPPORTED
#endif
Expand Down
8 changes: 5 additions & 3 deletions dev/schema/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,10 @@ namespace sqlite_orm {

module_details_type module_details;

#ifndef SQLITE_ORM_AGGREGATE_BASES_SUPPORTED
virtual_table_t(std::string name, module_details_type module_details) :
basic_table{std::move(name)}, module_details{std::move(module_details)} {}
#endif

/**
* Call passed lambda with columns not having the specified constraint trait `OpTrait`.
Expand Down Expand Up @@ -386,7 +388,7 @@ namespace sqlite_orm {

/**
* Factory function for a table definition.
*
*
* The mapped object type is determined implicitly from the first column definition.
*/
template<class... Cs, class T = typename std::tuple_element_t<0, std::tuple<Cs...>>::object_type>
Expand All @@ -397,7 +399,7 @@ namespace sqlite_orm {

/**
* Factory function for a table definition.
*
*
* The mapped object type is explicitly specified.
*/
template<class T, class... Cs>
Expand All @@ -408,6 +410,6 @@ namespace sqlite_orm {

template<class M>
internal::virtual_table_t<M> make_virtual_table(std::string name, M module_details) {
return internal::virtual_table_t<M>(std::move(name), std::move(module_details));
SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(module_details)});
}
}
2 changes: 1 addition & 1 deletion dev/select_constraints.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ namespace sqlite_orm {
* Example:
* constexpr auto m = "m"_alias.for_<Employee>();
* auto reportingTo =
* storage.select(asterisk<m>(), inner_join<m>(on(m->*&Employee::reportsTo == c(&Employee::employeeId))));
* storage.select(asterisk<m>(), inner_join<m>(on(m->*&Employee::reportsTo == &Employee::employeeId)));
*/
template<orm_recordset_alias auto alias>
auto asterisk(bool definedOrder = false) {
Expand Down
6 changes: 3 additions & 3 deletions dev/statement_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ namespace sqlite_orm {
using statement_type = current_time_t;

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) {
std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) {
return "CURRENT_TIME";
}
};
Expand All @@ -173,7 +173,7 @@ namespace sqlite_orm {
using statement_type = current_date_t;

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) {
std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) {
return "CURRENT_DATE";
}
};
Expand All @@ -183,7 +183,7 @@ namespace sqlite_orm {
using statement_type = current_timestamp_t;

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) {
std::string operator()(const statement_type& /*statement*/, const Ctx& /*context*/) {
return "CURRENT_TIMESTAMP";
}
};
Expand Down
27 changes: 24 additions & 3 deletions dev/table_type_of.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#pragma once
#include <type_traits> // std::declval
#include "functional/cxx_type_traits_polyfill.h"

namespace sqlite_orm {

Expand Down Expand Up @@ -33,11 +35,30 @@ namespace sqlite_orm {
};

template<class C>
struct table_type_of<indexed_column_t<C>> {
using type = typename table_type_of<C>::type;
};
struct table_type_of<indexed_column_t<C>> : table_type_of<C> {};

template<class T>
using table_type_of_t = typename table_type_of<T>::type;

/*
* This trait can be used to check whether the object type of a member pointer or column pointer matches the target type.
*
* One use case is the ability to create column reference to an aliased table column of a derived object field without explicitly using a column pointer.
* E.g.
* regular: `alias_column<alias_d<Derived>>(column<Derived>(&Base::field))`
* short: `alias_column<alias_d<Derived>>(&Base::field)`
*/
template<class F, class T, class SFINAE = void>
SQLITE_ORM_INLINE_VAR constexpr bool is_field_of_v = false;

/*
* `true` if a pointer-to-member operator is a valid expression for an object of type `T` and a member pointer of type `F O::*`.
*/
template<class F, class O, class T>
SQLITE_ORM_INLINE_VAR constexpr bool
is_field_of_v<F O::*, T, polyfill::void_t<decltype(std::declval<T>().*std::declval<F O::*>())>> = true;

template<class F, class T>
SQLITE_ORM_INLINE_VAR constexpr bool is_field_of_v<column_pointer<T, F>, T, void> = true;
}
}
2 changes: 1 addition & 1 deletion examples/custom_aliases.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ int main(int, char** argv) {
// WHERE COMPANY_ID = DEPARTMENT.EMP_ID;
auto rowsWithColumnAliases = storage.select(
columns(&Employee::id >>= empId, as<CompanyNameAlias>(&Employee::name), &Employee::age, &Department::dept),
where(get<empId>() == c(&Department::empId)));
where(get<empId>() == &Department::empId));
assert(rowsWithColumnAliases == rowsWithTableAliases);

// SELECT C.ID AS COMPANY_ID, C.NAME AS COMPANY_NAME, C.AGE, D.DEPT
Expand Down
6 changes: 3 additions & 3 deletions examples/exists.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ int main(int, char**) {
auto where_clause = select(d->*&Customer::agentCode,
from<d>(),
where(is_equal(c_als->*&Customer::paymentAmt, std::ref(amount)) and
(d->*&Customer::agentCode == c(c_als->*&Customer::agentCode))));
(d->*&Customer::agentCode == c_als->*&Customer::agentCode)));

amount = 7000;

Expand All @@ -502,7 +502,7 @@ int main(int, char**) {
select(alias_column<als_2>(&Customer::agentCode),
from<als_2>(),
where(is_equal(alias_column<als>(&Customer::paymentAmt), std::ref(amount)) and
(alias_column<als_2>(&Customer::agentCode) == c(alias_column<als>(&Customer::agentCode)))));
(alias_column<als_2>(&Customer::agentCode) == alias_column<als>(&Customer::agentCode))));

amount = 7000;

Expand All @@ -513,7 +513,7 @@ int main(int, char**) {
&Order::custCode,
alias_column<als>(&Customer::paymentAmt)),
from<Order>(),
inner_join<als>(on(alias_column<als>(&Customer::agentCode) == c(&Order::agentCode))),
inner_join<als>(on(alias_column<als>(&Customer::agentCode) == &Order::agentCode)),
where(not exists(where_clause)),
order_by(alias_column<als>(&Customer::paymentAmt))));
#endif
Expand Down
24 changes: 12 additions & 12 deletions examples/self_join.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,19 +201,19 @@ int main() {
// ON m.ReportsTo = employees.EmployeeId
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
constexpr auto m = "m"_alias.for_<Employee>();
auto firstNames = storage.select(columns(m->*&Employee::firstName || c(" ") || m->*&Employee::lastName,
&Employee::firstName || c(" ") || &Employee::lastName),
inner_join<m>(on(m->*&Employee::reportsTo == c(&Employee::employeeId))));
auto firstNames = storage.select(columns(m->*&Employee::firstName || " " || m->*&Employee::lastName,
&Employee::firstName || " " || &Employee::lastName),
inner_join<m>(on(m->*&Employee::reportsTo == &Employee::employeeId)));
cout << "firstNames count = " << firstNames.size() << endl;
for(auto& row: firstNames) {
cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl;
}
#else
using als = alias_m<Employee>;
auto firstNames = storage.select(
columns(alias_column<als>(&Employee::firstName) || c(" ") || alias_column<als>(&Employee::lastName),
&Employee::firstName || c(" ") || &Employee::lastName),
inner_join<als>(on(alias_column<als>(&Employee::reportsTo) == c(&Employee::employeeId))));
columns(alias_column<als>(&Employee::firstName) || " " || alias_column<als>(&Employee::lastName),
&Employee::firstName || " " || &Employee::lastName),
inner_join<als>(on(alias_column<als>(&Employee::reportsTo) == &Employee::employeeId)));
cout << "firstNames count = " << firstNames.size() << endl;
for(auto& row: firstNames) {
cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl;
Expand All @@ -233,19 +233,19 @@ int main() {
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
static_assert(std::is_empty_v<custom_alias<Employee>>);
constexpr auto emp = custom_alias<Employee>{};
auto firstNames = storage.select(columns(emp->*&Employee::firstName || c(" ") || emp->*&Employee::lastName,
&Employee::firstName || c(" ") || &Employee::lastName),
inner_join<emp>(on(emp->*&Employee::reportsTo == c(&Employee::employeeId))));
auto firstNames = storage.select(columns(emp->*&Employee::firstName || " " || emp->*&Employee::lastName,
&Employee::firstName || " " || &Employee::lastName),
inner_join<emp>(on(emp->*&Employee::reportsTo == &Employee::employeeId)));
cout << "firstNames count = " << firstNames.size() << endl;
for(auto& row: firstNames) {
cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl;
}
#else
using als = custom_alias<Employee>;
auto firstNames = storage.select(
columns(alias_column<als>(&Employee::firstName) || c(" ") || alias_column<als>(&Employee::lastName),
&Employee::firstName || c(" ") || &Employee::lastName),
inner_join<als>(on(alias_column<als>(&Employee::reportsTo) == c(&Employee::employeeId))));
columns(alias_column<als>(&Employee::firstName) || " " || alias_column<als>(&Employee::lastName),
&Employee::firstName || " " || &Employee::lastName),
inner_join<als>(on(alias_column<als>(&Employee::reportsTo) == &Employee::employeeId)));
cout << "firstNames count = " << firstNames.size() << endl;
for(auto& row: firstNames) {
cout << std::get<0>(row) << '\t' << std::get<1>(row) << endl;
Expand Down
Loading

0 comments on commit 55b7be6

Please sign in to comment.