Bläddra i källkod

* Fixed gcc compiler errors

* Improved examples in the README
master
bergmann 7 år sedan
förälder
incheckning
c17694586b
8 ändrade filer med 181 tillägg och 52 borttagningar
  1. +130
    -1
      README.md
  2. +8
    -8
      include/cpphibernate/driver/mariadb/impl/limit.h
  3. +21
    -21
      include/cpphibernate/driver/mariadb/impl/where.h
  4. +1
    -1
      include/cpphibernate/schema/macros.h
  5. +2
    -2
      src/cpphibernate/driver/mariadb/schema/schema.cpp
  6. +14
    -14
      src/cpphibernate/driver/mariadb/schema/table.cpp
  7. +3
    -3
      src/cpphibernate/types.cpp
  8. +2
    -2
      test/CMakeLists.txt

+ 130
- 1
README.md Visa fil

@@ -10,7 +10,136 @@ Before you can use cpphibernate you need to download and install [the official m

[The cpputils libary](https://git.bergmann89.de/cpp/cpputils) and [the cppmariadb library](https://github.com/Bergmann89/cppmariadb) will be automatically downladed during the build.

### Small Usage Example
### Simple Usage Example

In this simple example we use a single and simple object, that is stored in the database. The create, update, read and destroy methods and the corresponding SQL queries are shown in the code below.

```cpp
#include <memory>
#include <iostream>
#include <exception>
#include <cpphibernate.h>
#include <cpphibernate/driver/mariadb.h>

/* define the class to hibernate */

struct test_data
{
size_t id; //!< ID of the class instance (this field is mandatory for the hibernate engine)
std::string str_data; //!< Add string data field
::cpphibernate::string<64> str64_data; //!< Add a special string data field with a mex length of 64

uint32_t u32; //!< Add a normal integer data field
std::unique_ptr<uint32_t> u32_ptr_u; //!< Add a nullable integer data field
};

/* create the database schema */

constexpr decltype(auto) test_schema = cpphibernate_make_schema(
test_schema, // this is the schema name
cpphibernate_make_table_name(
tbl_test_data, // this is the table name
test_data, // this is the referenced class
1, // a unique id for the table
cpphibernate_make_id (&test_data::id), // pointer to the ID member
cpphibernate_make_field (test_data, str_data), // define a normal member field
cpphibernate_make_field (test_data, str64_data), // [...]
cpphibernate_make_field (test_data, u32), // [...]
cpphibernate_make_field (test_data, u32_ptr_u), // [...]
)
);

int main(int argc, char** argv)
{
try
{
using namespace ::cppmariadb;
using namespace ::cpphibernate;

/* establish connection to database */
connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty());

/* create a hibernation context */
auto context = make_context_ptr<driver::mariadb>(test_schema, c);

/* initialize the database schema */
context.init(); /* CREATE SCHEMA IF NOT EXISTS `test_schema` DEFAULT CHARACTER SET utf8;
USE `test_schema`;
CREATE TABLE IF NOT EXISTS `tbl_test_data`
(
`tbl_test_data_id` INT UNSIGNED NOT NULL,
`str_data` VARCHAR(100) NOT NULL,
`str64_data` VARCHAR(64) NOT NULL,
`u32` INT UNSIGNED NOT NULL,
`u32_ptr_u` INT UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY ( `tbl_test_data_id` ),
UNIQUE INDEX `index_tbl_test_data_id` ( `tbl_test_data_id` ASC )
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8; */

/* create some test data */
test_data data;
data.str_data = "this is a simple string";
data.str64_data = "this is a string with max 64 characters";
data.u32 = 123;

/* create a new dataset in the database:
* the new IDs of the object are stored in the corresponding members */
context.create(data); /* INSERT INTO
`tbl_test_data`
SET
`str_data`='this is a simple string',
`str64_data`='this is a string with max 64 characters',
`u32`=123,
`u32_ptr_u`=NULL; */

/* change some data and update the database */
t1.u32_ptr_u.reset(new uint32_t(456));
context.update(data); /* UPDATE
`tbl_test_data`
SET
`str_data`='this is a simple string',
`str64_data`='this is a string with max 64 characters',
`u32`=123,
`u32_ptr_u`=456
WHERE
`tbl_test_data_id`=1; */

/* read back the created object:
* if no selector is passed here, the ID member of the object is used */
context.read(data); /* SELECT "
`tbl_test_data`.`tbl_test_data_id`),
`tbl_test_data`.`str_data`,
`tbl_test_data`.`str64_data`,
`tbl_test_data`.`u32`,
`tbl_test_data`.`u32_ptr_u`
FROM
`tbl_test_data`
WHERE
`tbl_test_data`.`tbl_test_data_id`=1; */

/* delete the object from the database */
context.destroy(data); /* DELETE
`tbl_test_data`
FROM
`tbl_test_data`
WHERE
`tbl_test_data`.`tbl_test_data_id`=1; */

return 0;
}
catch(const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
return 1
}
```

### More Advanced Usage Example

The more advanced example uses a more complex database schema, containing custom defined enum types, one to one and one to many correleation of different tables, a polymorphic class hierarchy with inheritance and some of the std containers like std::unique_ptr or std::vector.

```cpp
#include <memory>


+ 8
- 8
include/cpphibernate/driver/mariadb/impl/limit.h Visa fil

@@ -14,25 +14,25 @@ beg_namespace_cpphibernate_driver_mariadb
{
::cppmariadb::statement statement;

limit_builder(const T_modifiers& modifier)
limit_builder(const T_modifiers& p_modifier)
{
ssize_t limit = -1;
ssize_t offset = -1;

hana::for_each(modifier, [&limit, &offset](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
hana::for_each(p_modifier, [&limit, &offset](auto& x_modifier){
using modifier_type = mp::decay_t<decltype(x_modifier)>;
using is_limit_type = modifier::is_limit_modifier<modifier_type>;
using is_offset_type = modifier::is_offset<modifier_type>;
hana::eval_if(
is_limit_type { },
[&limit, &modifier](auto _){
limit = static_cast<ssize_t>(hana::value(_(modifier).value));
[&limit, &x_modifier](auto _){
limit = static_cast<ssize_t>(hana::value(_(x_modifier).value));
},
[&offset, &modifier](){
[&offset, &x_modifier](){
hana::eval_if(
is_offset_type { },
[&offset, &modifier](auto _){
offset = static_cast<ssize_t>(hana::value(_(modifier).value));
[&offset, &x_modifier](auto _){
offset = static_cast<ssize_t>(hana::value(_(x_modifier).value));
},
[]{
/* no-op */


+ 21
- 21
include/cpphibernate/driver/mariadb/impl/where.h Visa fil

@@ -26,51 +26,51 @@ beg_namespace_cpphibernate_driver_mariadb
{ }

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_and<mp::decay_t<T_clause>>>
{
os << "(";
build_clause(os, clause.clauses[hana::size_c<0>]);
build_clause(os, p_clause.clauses[hana::size_c<0>]);
os << ")";
hana::for_each(
hana::remove_at(clause.clauses, hana::size_c<0>),
[&](auto& clause) {
hana::remove_at(p_clause.clauses, hana::size_c<0>),
[&](auto& x_clause) {
os << " AND (";
build_clause(os, clause);
build_clause(os, x_clause);
os << ")";
});
}

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_or<mp::decay_t<T_clause>>>
{
os << "(";
build_clause(os, clause.clauses[hana::size_c<0>]);
build_clause(os, p_clause.clauses[hana::size_c<0>]);
os << ")";
hana::for_each(
hana::remove_at(clause.clauses, hana::size_c<0>),
[&](auto& clause) {
hana::remove_at(p_clause.clauses, hana::size_c<0>),
[&](auto& x_clause) {
os << " OR (";
build_clause(os, clause);
build_clause(os, x_clause);
os << ")";
});
}

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_not<mp::decay_t<T_clause>>>
{
os << "NOT (";
build_clause(os, clause.clause);
build_clause(os, p_clause.clause);
os << ")";
}

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_equal<mp::decay_t<T_clause>>>
{
auto field_id = misc::get_type_id(hana::type_c<mp::decay_t<decltype(clause.field)>>);
auto field_id = misc::get_type_id(hana::type_c<mp::decay_t<decltype(p_clause.field)>>);
auto& field = schema.field(field_id);
os << "`"
<< field.table_name
@@ -114,28 +114,28 @@ beg_namespace_cpphibernate_driver_mariadb
{ }

template<typename T_clause>
inline auto assign_clause(T_clause&& clause)
inline auto assign_clause(T_clause&& p_clause)
-> mp::enable_if_c<
modifier::is_where_clause_and<mp::decay_t<T_clause>>::value
|| modifier::is_where_clause_or <mp::decay_t<T_clause>>::value>
{
hana::for_each([&](auto& clause) {
assign_clause(clause);
hana::for_each(std::forward<T_clause>(p_clause).clauses, [&](auto& x_clause) {
assign_clause(x_clause);
});
}

template<typename T_clause>
inline auto assign_clause(T_clause&& clause)
inline auto assign_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_not<mp::decay_t<T_clause>>>
{
assign_clause(clause.clause);
assign_clause(std::forward<T_clause>(p_clause).clause);
}

template<typename T_clause>
inline auto assign_clause(T_clause&& clause)
inline auto assign_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_equal<mp::decay_t<T_clause>>>
{
statement.set(index, clause.value);
statement.set(index, std::forward<T_clause>(p_clause).value);
++index;
}



+ 1
- 1
include/cpphibernate/schema/macros.h Visa fil

@@ -40,4 +40,4 @@
cpphibernate_make_field_name( \
id, \
p_member_ptr, \
cpphibernate::schema::attribute::primary_key)
cpphibernate::schema::attribute::primary_key)

+ 2
- 2
src/cpphibernate/driver/mariadb/schema/schema.cpp Visa fil

@@ -111,8 +111,8 @@ void schema_t::print(std::ostream& os) const
os << indent << '{'
<< incindent
<< indent << "\"schema_name\": \"" << schema_name << "\","
<< indent << "\"tables\": " << misc::print_container(tables, true, [](auto& os, auto& kvp) {
kvp.second->print(os);
<< indent << "\"tables\": " << misc::print_container(tables, true, [](auto& s, auto& kvp) {
kvp.second->print(s);
})
<< decindent
<< indent << '}';


+ 14
- 14
src/cpphibernate/driver/mariadb/schema/table.cpp Visa fil

@@ -1316,28 +1316,28 @@ void table_t::print(std::ostream& os) const
<< indent << "\"derived_dataset_ids\": " << misc::print_container(derived_dataset_ids, false) << ","
<< indent << "\"schema_name\": \"" << schema_name << "\","
<< indent << "\"table_name\": \"" << table_name << "\","
<< indent << "\"fields\":" << misc::print_container(fields, true, [](auto& os, auto& field) {
field->print(os);
<< indent << "\"fields\":" << misc::print_container(fields, true, [](auto& s, auto& field) {
field->print(s);
}) << ","
<< indent << "\"base_table\": " << (base_table ? std::string("\"") + base_table->table_name + "\"" : "null") << ","
<< indent << "\"derived_tables\":" << misc::print_container(derived_tables, true, [](auto& os, auto& ptr){
os << indent << '"' << ptr->table_name << '"';
<< indent << "\"derived_tables\":" << misc::print_container(derived_tables, true, [](auto& s, auto& ptr){
s << indent << '"' << ptr->table_name << '"';
}) << ","
<< indent << "\"primary_key_field\": " << (primary_key_field ? std::string("\"") + primary_key_field->field_name + "\"" : "null") << ","
<< indent << "\"foreign_key_fields\": " << misc::print_container(foreign_key_fields, true, [](auto& os, auto& ptr){
os << indent << '"' << ptr->table_name << '.' << ptr->field_name << '"';
<< indent << "\"foreign_key_fields\": " << misc::print_container(foreign_key_fields, true, [](auto& s, auto& ptr){
s << indent << '"' << ptr->table_name << '.' << ptr->field_name << '"';
}) << ","
<< indent << "\"foreign_table_fields\": " << misc::print_container(foreign_table_fields, true, [](auto& os, auto& ptr){
os << indent << '"' << ptr->field_name << '"';
<< indent << "\"foreign_table_fields\": " << misc::print_container(foreign_table_fields, true, [](auto& s, auto& ptr){
s << indent << '"' << ptr->field_name << '"';
}) << ","
<< indent << "\"foreign_table_one_fields\": " << misc::print_container(foreign_table_one_fields, true, [](auto& os, auto& ptr){
os << indent << '"' << ptr->field_name << '"';
<< indent << "\"foreign_table_one_fields\": " << misc::print_container(foreign_table_one_fields, true, [](auto& s, auto& ptr){
s << indent << '"' << ptr->field_name << '"';
}) << ","
<< indent << "\"foreign_table_many_fields\": " << misc::print_container(foreign_table_many_fields, true, [](auto& os, auto& ptr){
os << indent << '"' << ptr->field_name << '"';
<< indent << "\"foreign_table_many_fields\": " << misc::print_container(foreign_table_many_fields, true, [](auto& s, auto& ptr){
s << indent << '"' << ptr->field_name << '"';
}) << ","
<< indent << "\"data_fields\": " << misc::print_container(data_fields, true, [](auto& os, auto& ptr){
os << indent << '"' << ptr->field_name << '"';
<< indent << "\"data_fields\": " << misc::print_container(data_fields, true, [](auto& s, auto& ptr){
s << indent << '"' << ptr->field_name << '"';
})
<< decindent
<< indent << '}';


+ 3
- 3
src/cpphibernate/types.cpp Visa fil

@@ -37,11 +37,11 @@ bool uuid::from_string(const std::string& str, uuid& val)
while(i < 32 && c < e)
{
if (*c >= '0' && *c <= '9')
val[i >> 1] |= ((*c - '0') << (4 * (1 - (i & 1))));
val[i >> 1] = static_cast<uint8_t>(val[i >> 1] | ((*c - '0' + 0) << (4 * (1 - (i & 1)))));
else if (*c >= 'a' && *c <= 'f')
val[i >> 1] |= ((*c - 'a' + 10) << (4 * (1 - (i & 1))));
val[i >> 1] = static_cast<uint8_t>(val[i >> 1] | ((*c - 'a' + 10) << (4 * (1 - (i & 1)))));
else if (*c >= 'A' && *c <= 'F')
val[i >> 1] |= ((*c - 'A' + 10) << (4 * (1 - (i & 1))));
val[i >> 1] = static_cast<uint8_t>(val[i >> 1] | ((*c - 'A' + 10) << (4 * (1 - (i & 1)))));
else if (*c != '-')
return false;
if (*c != '-')


+ 2
- 2
test/CMakeLists.txt Visa fil

@@ -18,9 +18,9 @@ List ( FILTER SOURCE_FILES EXCLUDE REGEX "/_[A-Za-z0-9_-]
Add_Executable ( test_cpphibernate EXCLUDE_FROM_ALL ${SOURCE_FILES} )
Target_Link_Libraries ( test_cpphibernate
cpphibernate
gtest
gmock
gmock_main
gmock
gtest
pthread )
If ( __COTIRE_INCLUDED )
Cotire ( test_cpphibernate )


Laddar…
Avbryt
Spara