From f70b64e2c4f9861d7013492b609212ed78e840f5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 16 Sep 2011 16:03:26 +0200 Subject: Support for views; integrated part --- common/view/driver.cxx | 449 +++++++++++++++++++++++++++++++++++++++++++++---- common/view/test.hxx | 339 +++++++++++++++++++++++++++++++++---- 2 files changed, 723 insertions(+), 65 deletions(-) diff --git a/common/view/driver.cxx b/common/view/driver.cxx index 89ef304..8450b34 100644 --- a/common/view/driver.cxx +++ b/common/view/driver.cxx @@ -21,6 +21,148 @@ using namespace std; using namespace odb::core; +template +void +view1_check (odb::result& r) +{ + typedef odb::result result; + + typename result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first == "Jane" && i->last == "Doe" && i->age == 29); + + assert (++i != r.end ()); + V v; + i.load (v); + assert (v.first == "John" && v.last == "Doe" && v.age == 30); + + assert (++i == r.end ()); +} + +template +void +view2_test (const auto_ptr& db) +{ + typedef odb::query query; + typedef odb::result result; + typedef typename result::iterator iterator; + + transaction t (db->begin ()); + + { + result r (db->query ()); + iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->count == 4); + } + + { + result r (db->query ("age < 31")); + iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->count == 2); + } + + { + result r (db->query (query::age < 31)); + iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->count == 2); + } + + t.commit (); +} + +template +void +view4_test (const auto_ptr& db) +{ + typedef odb::query query; + typedef odb::result result; + typedef typename result::iterator iterator; + + transaction t (db->begin ()); + + { + result r (db->query ("age > 30 ORDER BY age")); + + iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first_name == "Joe" && i->last_name == "Dirt" && + i->name == "United States"); + + assert (++i != r.end ()); + assert (i->first_name == "Johan" && i->last_name == "Johansen" && + i->name == "Sweden"); + + assert (++i == r.end ()); + } + + { + result r (db->query ( + (query::person::age > 30) + "ORDER BY age")); + + iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first_name == "Joe" && i->last_name == "Dirt" && + i->name == "United States"); + + assert (++i != r.end ()); + assert (i->first_name == "Johan" && i->last_name == "Johansen" && + i->name == "Sweden"); + + assert (++i == r.end ()); + } + + { + result r (db->query (query::residence::code == "US")); + + iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first_name == "Joe" && i->last_name == "Dirt" && + i->name == "United States"); + + assert (++i == r.end ()); + } + + t.commit (); +} + +template +void +view6_test (const auto_ptr& db) +{ + typedef odb::query query; + typedef odb::result result; + typedef typename result::iterator iterator; + + transaction t (db->begin ()); + + { + result r ( + db->query ( + query::employer::name == "Simple Tech, Inc")); + + iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first_name == "John" && i->last_name == "Doe" && + i->employer == "Simple Tech, Inc"); + + assert (++i != r.end ()); + assert (i->first_name == "Joe" && i->last_name == "Dirt" && + i->employer == "Simple Tech, Inc"); + + assert (++i == r.end ()); + } + + t.commit (); +} + int main (int argc, char* argv[]) { @@ -31,15 +173,32 @@ main (int argc, char* argv[]) // // { - country* ca (new country ("CA", "Canada")); - country* za (new country ("ZA", "South Africa")); - country* us (new country ("US", "United States")); - country* se (new country ("SE", "Sweden")); + country ca ("CA", "Canada"); + country za ("ZA", "South Africa"); + country us ("US", "United States"); + country se ("SE", "Sweden"); + + person p1 (1, "John", "Doe", 30, male, measures (60, 160), &ca, &ca); + person p2 (2, "Jane", "Doe", 29, female, measures (70, 170), &za, &us); + person p3 (3, "Joe", "Dirt", 31, male, measures (80, 180), &us, &za); + person p4 (4, "Johan", "Johansen", 32, male, measures (90, 190), &se, + &se); + + p2.husband = &p1; + + employer st ("Simple Tech, Inc"); + employer ct ("Complex Tech, Inc"); - person p1 (1, "John", "Doe", 30, ca); - person p2 (2, "Jane", "Doe", 29, za); - person p3 (3, "Joe", "Dirt", 31, us); - person p4 (4, "Johansen", "Johansen", 32, se); + p2.previous_employer = st.name; + p3.previous_employer = ct.name; + + st.employees.push_back (&p1); + st.employees.push_back (&p3); + st.head_count = 2; + + ct.employees.push_back (&p2); + ct.employees.push_back (&p4); + ct.head_count = 2; transaction t (db->begin ()); db->persist (ca); @@ -51,6 +210,9 @@ main (int argc, char* argv[]) db->persist (p2); db->persist (p3); db->persist (p4); + + db->persist (st); + db->persist (ct); t.commit (); } @@ -75,48 +237,88 @@ main (int argc, char* argv[]) { result r (db->query ("age < 31 ORDER BY age")); - result::iterator i (r.begin ()); - - assert (i != r.end ()); - assert (i->first == "Jane" && i->last == "Doe" && i->age == 29); - - assert (++i != r.end ()); - view1 v; - i.load (v); - assert (v.first == "John" && v.last == "Doe" && v.age == 30); + view1_check (r); } t.commit (); } } - // view2 + // view1a // { - typedef odb::query query; - typedef odb::result result; + typedef odb::query query; + typedef odb::result result; { transaction t (db->begin ()); + result r (db->query ()); + view1_check (r); + + t.commit (); + } + } + + // view1b + // + { + typedef odb::query query; + typedef odb::result result; + + { { - result r (db->query ()); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->count == 4); + transaction t (db->begin ()); + + result r (db->query (query (true))); + view1_check (r); + + t.commit (); } { - result r (db->query ("age < 31")); + transaction t (db->begin ()); + + result r (db->query ("first = " + query::_val ("Jane"))); result::iterator i (r.begin ()); + assert (i != r.end ()); - assert (i->count == 2); + assert (i->first == "Jane" && i->last == "Doe"); + assert (++i == r.end ()); + + t.commit (); } + } + } + + // view1c + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + result r ( + db->query ( + "SELECT first, last, age " + "FROM common_view_person " + "WHERE age < 31 ORDER BY age")); + + view1_check (r); t.commit (); } } + // view2 + // + view2_test (db); + view2_test (db); + view2_test (db); + view2_test (db); + // view3 // { @@ -132,10 +334,10 @@ main (int argc, char* argv[]) size_t count (0); for (result::iterator i (r.begin ()); i != r.end (); ++i) { - if (i->last == "Doe") + if (i->last_name == "Doe") assert (i->count == 2); - else if (i->last == "Dirt" || - i->last == "Johansen") + else if (i->last_name == "Dirt" || + i->last_name == "Johansen") assert (i->count == 1); else assert (false); @@ -150,27 +352,202 @@ main (int argc, char* argv[]) } } + // view3a + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + { + result r (db->query (query::last_name == "Doe")); + result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->last_name == "Doe" && i->count == 2); + assert (++i == r.end ()); + } + + t.commit (); + } + } + // view4 // + view4_test (db); + view4_test (db); + + // view5 + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + { + result r ( + db->query ( + query::residence::name == query::nationality::name)); + + result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first_name == "John" && i->last_name == "Doe" && + i->rname == "Canada" && i->rname == "Canada"); + + assert (++i != r.end ()); + assert (i->first_name == "Johan" && i->last_name == "Johansen" && + i->rname == "Sweden" && i->rname == "Sweden"); + + assert (++i == r.end ()); + } + + t.commit (); + } + } + + // view6 + // + view6_test (db); + view6_test (db); + view6_test (db); + + // view7 + // { - typedef odb::query query; - typedef odb::result result; + typedef odb::query query; + typedef odb::result result; { transaction t (db->begin ()); { - result r (db->query ("age > 30 ORDER BY age")); + result r (db->query (query::person::last_name == "Doe")); result::iterator i (r.begin ()); assert (i != r.end ()); - assert (i->first == "Joe" && i->last == "Dirt" && - i->location == "United States"); + assert (i->first_name == "Jane" && i->last_name == "Doe" && + !i->head_count.null () && *i->head_count == 2); assert (++i != r.end ()); - assert (i->first == "Johansen" && i->last == "Johansen" && - i->location == "Sweden"); + assert (i->first_name == "John" && i->last_name == "Doe" && + i->head_count.null ()); + + assert (++i == r.end ()); + } + + t.commit (); + } + } + + // view8 + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + { + result r (db->query ()); + + result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->wife_name == "Jane" && i->husb_name == "John"); + assert (++i == r.end ()); + } + + t.commit (); + } + } + + // view9 + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + { + // Test case-insensitive clause prefix detection. + // + result r (db->query ("where" + (query::gender == female))); + + result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->first_name == "Jane" && i->last_name == "Doe" && + i->gender == female); + assert (++i == r.end ()); + } + + t.commit (); + } + } + + // view10 + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + { + result r (db->query ( + query::measures::weight > 60 && + query::measures::hight < 190)); + + result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->last_name == "Doe" && + i->measures.weight == 70 && i->measures.hight == 170); + + assert (++i != r.end ()); + assert (i->last_name == "Dirt" && + i->measures.weight == 80 && i->measures.hight == 180); + + assert (++i == r.end ()); + } + + t.commit (); + } + } + + // view11 + // + { + typedef odb::query query; + typedef odb::result result; + + { + transaction t (db->begin ()); + + { + result r (db->query ( + query::measures::weight > 60 && + query::measures::hight < 190)); + + result::iterator i (r.begin ()); + + assert (i != r.end ()); + assert (i->last_name == "Doe" && i->hight == 170); + + assert (++i != r.end ()); + assert (i->last_name == "Dirt" && i->hight == 180); + + assert (++i == r.end ()); } t.commit (); diff --git a/common/view/test.hxx b/common/view/test.hxx index 5eba5d5..3ba6745 100644 --- a/common/view/test.hxx +++ b/common/view/test.hxx @@ -7,11 +7,13 @@ #define TEST_HXX #include -#include +#include #include // std::size_t -#include #include +#include + +struct employer; #pragma db object struct country @@ -31,23 +33,43 @@ struct country std::string name; }; +enum gender_type {male, female}; + +#pragma db value +struct measures +{ + measures (unsigned short w, unsigned short h) : weight (w), hight (h) {} + measures () {} + + unsigned short weight; + unsigned short hight; +}; + #pragma db object struct person { + typedef ::measures measures_type; + person (unsigned long i, const std::string& fn, const std::string& ln, unsigned short a, - country* l) - : id (i), first_name (fn), last_name (ln), age (a), location (l) + gender_type g, + const measures_type m, + country* r, + country* n) + : id (i), + first_name_ (fn), + last_name_ (ln), + age (a), + gender (g), + measures (m), + residence (r), + nationality (n), + husband (0) { } - ~person () - { - delete location; - } - person () { } @@ -56,18 +78,57 @@ struct person unsigned long id; #pragma db column ("first") - std::string first_name; + std::string first_name_; #pragma db column ("last") - std::string last_name; + std::string last_name_; unsigned short age; + // #pragma db type("INT") - in MySQL test type pragma copying + gender_type gender; + + measures_type measures; + + #pragma db not_null + country* residence; + #pragma db not_null - country* location; + country* nationality; + + #pragma db inverse(employees) + employer* employed_by; + + // A non-pointer relationship. + // + odb::nullable previous_employer; + + person* husband; // Self-reference. +}; + +#pragma db object +struct employer +{ + employer (const std::string& n) + : name (n) + { + } + + employer () + { + } + + #pragma db id + std::string name; + std::size_t head_count; + std::vector employees; }; -// General view with a custom query. +// +// General view with no associated objects. +// + +// Complete suffix query template. // #pragma db view query("SELECT first, last, age FROM common_view_person") struct view1 @@ -77,37 +138,257 @@ struct view1 unsigned short age; }; -// Count view. +// Complete query. +// +#pragma db view query("SELECT first, last, age " \ + "FROM common_view_person " \ + "WHERE age < 31 ORDER BY age") +struct view1a +{ + std::string first; + std::string last; + unsigned short age; +}; + +// Complete placeholder query template. +// +#pragma db view query("SELECT first, last, age " \ + "FROM common_view_person " \ + "WHERE age < 31 AND (?) ORDER BY age") +struct view1b +{ + std::string first; + std::string last; + unsigned short age; +}; + +// Runtime query. // -#pragma db view query("SELECT count(id) FROM common_view_person") +#pragma db view query() +struct view1c +{ + std::string first; + std::string last; + unsigned short age; +}; + +// +// Count view plus associated object. +// + +// Complete suffix query. +// +#pragma db view object(person) \ + query("SELECT count(id) FROM common_view_person") struct view2 { std::size_t count; }; -// Aggregate view. +// Generated query, literal column. +// +#pragma db view object(person) +struct view2a +{ + #pragma db column("count(id)") + std::size_t count; +}; + +// Generated query, qualified literal column. // -#pragma db view query("SELECT last, count(last) " \ - "FROM common_view_person " \ - "GROUP BY last") +#pragma db view object(person) +struct view2b +{ + #pragma db column("count(common_view_person.id)") + std::size_t count; +}; + +// Generated query, expression column. +// +#pragma db view object(person) +struct view2c +{ + #pragma db column("count(" + person::id + ")") + std::size_t count; +}; + +// +// Aggregate view plus associated object with a custom alias. +// + +// Complete suffix query. +// +#pragma db view object(person = test) \ + query("SELECT last, count(last) " \ + "FROM common_view_person " \ + "GROUP BY last") struct view3 { - std::string last; + std::string last_name; std::size_t count; }; -// JOIN view. +// Generated query with integrated query condition and placeholder. // -#pragma db view query("SELECT first, last, common_view_country.name " \ - "FROM common_view_person " \ - "LEFT JOIN common_view_country " \ - "ON common_view_person.location = " \ - "common_view_country.code") +#pragma db view object(person = test) \ + query((?) + "GROUP BY" + test::last_name_) +struct view3a +{ + // Automatically resolved to test::last_name_. + // + std::string last_name; + + #pragma db column("count(" + test::last_name_ + ")") + std::size_t count; +}; + +// +// JOIN view plus associated objects, some with custom aliases. +// + +// Complete suffix query. +// +#pragma db view object(person) object(country = residence) \ + query("SELECT first, last, residence.name " \ + "FROM common_view_person " \ + "LEFT JOIN common_view_country AS residence " \ + "ON common_view_person.residence = residence.code") struct view4 { - std::string first; - std::string last; - std::string location; + std::string first_name; + std::string last_name; + std::string name; +}; + +// Generated query. +// +#pragma db view object(person) \ + object(country = residence: person::residence) +struct view4a +{ + std::string first_name; + std::string last_name; + std::string name; +}; + +// +// JOIN the same object twice. +// +#pragma db view object(person) \ + object(country = residence: person::residence) \ + object(country = nationality: person::nationality) \ + query((?) + "ORDER BY" + person::age) +struct view5 +{ + std::string first_name; + std::string last_name; + + #pragma db column(residence::name) + std::string rname; + + #pragma db column(nationality::name) + std::string nname; +}; + +// +// JOIN via one(i)-to-many relationship. +// + +// Automatic relationship discovery. +// +#pragma db view object(person) object(employer) +struct view6 +{ + std::string first_name; + std::string last_name; + + #pragma db column(::employer::name) + std::string employer; +}; + +// Manual relationship specification, left side. +// +#pragma db view object(person) object(employer: person::employed_by) +struct view6a +{ + std::string first_name; + std::string last_name; + + #pragma db column(::employer::name) + std::string employer; +}; + +// Manual relationship specification, right side. +// +#pragma db view object(person) object(employer: employer::employees) +struct view6b +{ + std::string first_name; + std::string last_name; + + #pragma db column(::employer::name) + std::string employer; +}; + +// +// JOIN via a custom condition. +// +#pragma db view object(person) \ + object(employer: person::previous_employer == employer::name)\ + query((?) + "ORDER BY" + person::age) +struct view7 +{ + std::string first_name; + std::string last_name; + + odb::nullable head_count; +}; + +// +// Self-JOIN. +// +#pragma db view object(person = wife) object(person = husb) \ + query (wife::husband.is_not_null ()) +struct view8 +{ + #pragma db column (wife::first_name_) + std::string wife_name; + + #pragma db column (husb::first_name_) + std::string husb_name; +}; + +// +// Enum mapping. +// +#pragma db view object(person) +struct view9 +{ + std::string first_name; + std::string last_name; + gender_type gender; +}; + +// +// Composite in view. +// +#pragma db view object(person) query((?) + "ORDER BY" + person::age) +struct view10 +{ + std::string last_name; + ::measures measures; +}; + +// +// Composite in object. +// +#pragma db view object(person) query((?) + "ORDER BY" + person::age) +struct view11 +{ + std::string last_name; + + #pragma db column (person::measures.hight) + unsigned short hight; }; #endif // TEST_HXX -- cgit v1.1