sqlpp11 - An SQL Library Worthy of Modern C++ - Roland Bock - CppCon 2014
sqlpp11 - An SQL Library Worthy of Modern C++ - Roland Bock - CppCon 2014
EDSL
sqlpp11 Mechanics
Adding Vendor Specifics
2014-09-11
sqlpp11
We then looked at examples from sqlpp11:
https://github.com/rbock/sqlpp11/blob/develop/examples/insert.cpp
https://github.com/rbock/sqlpp11/blob/develop/examples/select.cpp
The compiler finds all those errors and more with sqlpp11 and reports
them in a decent way. Check it out for yourself or watch the video.
Member Template
template<typename T>
struct _member_t
{
T feature;
};
Member Template
template<typename T>
struct _member_t
{
T feature;
};
Basic Usage
struct my_struct: public _member_t<int>
{
};
A real-world column
struct Feature
{
struct _name_t
{
static constexpr const char* _get_name() { return "feature"; }
template<typename T>
struct _member_t
{
T feature;
T& operator()() { return feature; }
const T& operator()() const { return feature; }
};
};
using _traits = sqlpp::make_traits<sqlpp::integer, sqlpp::tag::require_insert>;
};
A real-world table
struct TabPerson: sqlpp::table_t<TabPerson,
TabPerson_::Id,
TabPerson_::Name,
TabPerson_::Feature>
{
struct _name_t
{
static constexpr const char* _get_name() { return "tab_person"; }
template<typename T>
struct _member_t
{
T tabPerson;
T& operator()() { return tabPerson; }
const T& operator()() const { return tabPerson; }
};
};
};
Usage in tables
template<typename Table, typename... ColumnSpec>
struct table_t:
public ColumnSpec::_name_t::template _member_t<column_t<Table, ColumnSpec>>...
{
// ...
};
Usage in rows
template<typename Db, std::size_t index, typename FieldSpec>
struct result_field:
public FieldSpec::_name_t::template
_member_t<result_field_t<value_type_of<FieldSpec>, Db, FieldSpec>>
{
//....
};
Constraints
Insert assignments
// Basics
static_assert(sizeof...(Assignments), "");
static_assert(all_t<is_assignment_t<Assignments>::value...>::value, "");
static_assert(not has_duplicates<lhs_t<Assignments>...>::value, "");
Code Layers
Vendor Specific
Serialization
template<typename Select>
result_t select(const Select& x)
{
_serializer_context_t context;
::sqlpp::serialize(x, context);
return {...};
}
Vendor Specific
Serialization
template<typename T, typename Context>
auto serialize(const T& t, Context& context)
-> decltype(serializer_t<Context, T>::_(t, context))
{
return serializer_t<Context, T>::_(t, context);
}
Vendor Specific
Serialization
template<typename Context, typename T, typename Enable = void>
struct serializer_t
{
static void _(const T& t, Context& context)
{
static_assert(wrong_t<serializer_t>::value,
"missing serializer specialization");
}
};
Vendor Specific
Disable a feature
template<typename Lhs, typename Rhs, typename On>
struct serializer_t<sqlite3::serializer_t, join_t<outer_join_t, Lhs, Rhs, On>>
{
using T = join_t<outer_join_t, Lhs, Rhs, On>;
Vendor Specific
Vendor Specific
select(streets.name)
.from(streets)
.where(streets.geometry.within(from_wkt("POLYGON((0 0,10 0,10 10,0 10,0 0))")))
select(streets.name)
.from(streets)
.where(streets.geometry.distance(some_point) < 100)
Vendor Specific
Add a value type
struct integral
{
using _traits = make_traits<integral, tag::is_value_type>;
using _tag = tag::is_integral;
using _cpp_value_type = int64_t;
};
template<typename Base>
struct expression_operators<Base, integral> { /*...*/ };
template<typename Base>
struct column_operators<Base, integral> { /*...*/ };
template<>
struct parameter_value_t<integral> { /*...*/ };
Vendor Specific
Vendor Specific
struct _name_t
{
static constexpr const char* _get_name() { return "LIKE"; }
template<typename T>
struct _member_t
{
T like;
T& operator()() { return like; }
const T& operator()() const { return like; }
};
};
Operand _operand;
Pattern _pattern;
};
Vendor Specific
Add a serializer
template<typename Context, typename Operand, typename Pattern>
struct serializer_t<Context, like_t<Operand, Pattern>>
{
using T = like_t<Operand, Pattern>;
Vendor Specific
Add/Change/Remove subclauses
template<typename Database>
using blank_select_t = statement_t<Database,
select_t,
no_select_flag_list_t,
no_select_column_list_t,
no_from_t,
no_where_t<true>,
no_group_by_t,
no_having_t,
no_order_by_t,
no_limit_t,
no_offset_t>;
template<typename... Columns>
auto select(Columns... columns)
-> decltype(blank_select_t<void>().columns(columns...))
{
return blank_select_t<void>().columns(columns...);
}
Dr. Roland Bock sqlpp11 - An SQL Library Worthy of Modern C++
Strings vs. EDSL Extending the EDSL
sqlpp11 Mechanics Other than string-based backends
Adding Vendor Specifics What’s next?
Unchartered territory
template<typename Context, typename T, typename Enable = void>
struct interpreter_t
{
static void _(const T& t, Context& context)
{
static_assert(wrong_t<interpreter_t>::value,
"missing interpreter specialization");
}
};
Unchartered territory
Serialize into source code
A python script for extracting data from HTML
Transform at compile-time into another expression tree
Reinterpreted Assignment
template<typename Lhs, typename Rhs>
struct assignment_t
{
template<typename T>
void operator()(T& t)
{
_lhs(t) = _rhs(t);
}
Lhs _lhs;
Rhs _rhs;
};
It took less than a day to write a working (partial) SQL Interface for
std::vector.
See https://github.com/rbock/sqlpp11-connector-stl
struct sample
{
int64_t alpha;
std::string beta;
bool gamma;
};
int main()
{
sql::connection<std::vector<sample>> db{{}};
db(insert_into(tab).set(tab.alpha = 17));
db(insert_into(tab).set(tab.beta = "cheesecake"));
db(insert_into(tab).set(tab.alpha = 42, tab.beta = "hello", tab.gamma = true));
db(insert_into(tab).set(tab.gamma = true));
What’s next?
Acknowledgements
Thank You!