diff options
Diffstat (limited to 'odb-tests/common/as')
-rw-r--r-- | odb-tests/common/as/buildfile | 49 | ||||
-rw-r--r-- | odb-tests/common/as/driver.cxx | 348 | ||||
-rw-r--r-- | odb-tests/common/as/test.hxx | 270 | ||||
-rw-r--r-- | odb-tests/common/as/testscript | 33 |
4 files changed, 700 insertions, 0 deletions
diff --git a/odb-tests/common/as/buildfile b/odb-tests/common/as/buildfile new file mode 100644 index 0000000..dcdc961 --- /dev/null +++ b/odb-tests/common/as/buildfile @@ -0,0 +1,49 @@ +# file : common/as/buildfile +# license : GNU GPL v2; see accompanying LICENSE file + +import libodb = libodb%lib{odb} + +libs = + +for db: $databases + import libs += libodb-$db%lib{odb-$db} + +import libs += lib{common} + +exe{driver}: {hxx cxx}{* -*-odb -*-odb-*} {hxx ixx cxx}{test-odb} testscript + +# Introduce the metadata library target to make sure the libodb library is +# resolved for the odb_compile ad hoc rule (see build/root.build for details). +# +libue{test-meta}: $libodb + +<{hxx ixx cxx}{test-odb}>: hxx{test} libue{test-meta} + +for db: $databases +{ + exe{driver}: {hxx ixx cxx}{test-odb-$db}: include = $multi + <{hxx ixx cxx}{test-odb-$db}>: hxx{test} libue{test-meta} +} + +exe{driver}: libue{test-meta} $libs + +# Specify the ODB custom options to be used by the odb_compile ad hoc rule +# (see build/root.build for details). +# +odb_options = --table-prefix as_ \ + --generate-schema \ + --generate-query \ + --generate-session + +cxx.poptions =+ "-I$out_base" "-I$src_base" + +# @@ BUILD@ Temporarily suppress the following warning: +# +# test-odb.cxx(6234): warning C4244: 'argument': conversion from 'id_type::value_type' to 'test5::version_type::value_type', possible loss of data +# +if ($cxx.class == 'msvc') + cxx.coptions += /wd4244 + +# Testscript's run-time prerequisites. +# +exe{driver}: ../../alias{database-client}: include = adhoc diff --git a/odb-tests/common/as/driver.cxx b/odb-tests/common/as/driver.cxx new file mode 100644 index 0000000..578eb23 --- /dev/null +++ b/odb-tests/common/as/driver.cxx @@ -0,0 +1,348 @@ +// file : common/as/driver.cxx +// license : GNU GPL v2; see accompanying LICENSE file + +// Test C++ type mapping (#pragma map type as ...). +// + +#include <memory> // std::unique_ptr +#include <iostream> + +#include <odb/session.hxx> +#include <odb/database.hxx> +#include <odb/transaction.hxx> + +#include <libcommon/common.hxx> + +#include "test.hxx" +#include "test-odb.hxx" + +#undef NDEBUG +#include <cassert> + +using namespace std; +using namespace odb::core; + +int +main (int argc, char* argv[]) +{ + try + { + unique_ptr<database> db (create_database (argc, argv)); + + // Test basic type mapping functionality. + // + { + using namespace test1; + + object o1 (true, green, 123, 234); + o1.m[false] = 123; + o1.v.push_back (o1.ip); + o1.cv.push_back (red); + o1.cv.push_back (green); + + object o2 (false, blue, 234, 456); + o2.m[true] = 234; + o2.v.push_back (o2.ip); + o2.cv.push_back (green); + o2.cv.push_back (blue); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + + o1.b = false; + o1.c = blue; + o1.ip.first++; + o1.ip.second--; + o1.m[false]++; + o1.m[true] = 234; + o1.v.back () = o1.ip; + o1.cv.modify_front () = green; + o1.cv.push_back (red); + + o2.b = true; + o2.c = red; + o2.ip.first--; + o2.ip.second++; + o2.m[true]--; + o2.m[false] = 345; + o2.v.push_back (o2.ip); + o2.cv.pop_back (); + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + + // Test wrapped simple type mapping. + // + { + using namespace test2; + + object o1; + o1.v.push_back (null_bool ()); + o1.v.push_back (false); + + object o2; + o2.b = true; + o2.v.push_back (true); + o2.v.push_back (null_bool ()); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + + o1.b = false; + o1.v[0] = true; + o1.v[1].reset (); + + o2.b.reset (); + o2.v.push_back (false); + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + + // Test wrapped composite type mapping. + // + { + using namespace test3; + + object o1; + o1.ip = intp (0, 0); // NULL + o1.npv.push_back (o1.np); + o1.ipv.push_back (o1.ip); + + object o2; + o2.np = intp (123, 234); + o1.ip = intp (234, 123); + o2.npv.push_back (o2.np); + o2.ipv.push_back (o2.ip); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + + o1.np = o1.npv[0] = intp (234, 456); + o1.ip = o1.ipv.modify_at (0) = intp (456, 234); + + o2.np.reset (); + o2.npv[0].reset (); + o2.ip = o2.ipv.modify_at (0) = intp (0, 0); // NULL + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + + // Test id type mapping. + // + { + using namespace test4; + + object o1 (123); + o1.v.push_back (1); + o1.v.push_back (2); + o1.v.push_back (3); + + object o2 (234); + o2.v.push_back (3); + o2.v.push_back (2); + o2.v.push_back (1); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + + o1.i++; + o1.v.pop_back (); + o1.v.modify_front ()++; + + o2.i--; + o2.v.clear (); + o2.v.push_back (4); + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + + // Test version type mapping. + // + { + using namespace test5; + + object o1 (100, 123); + object o2 (200, 234); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + + assert (*p1 == o1); + assert (*p2 == o2); + + p1->i--; + p2->i++; + + db->update (*p1); + db->update (*p2); + + t.commit (); + } + + { + transaction t (db->begin ()); + + for (;;) + { + o1.i++; + o2.i--; + + try + { + + db->update (o1); + db->update (o2); + break; + } + catch (const odb::object_changed&) + { + db->reload (o1); + db->reload (o2); + } + } + + t.commit (); + } + + { + transaction t (db->begin ()); + unique_ptr<object> p1 (db->load<object> (o1.id)); + unique_ptr<object> p2 (db->load<object> (o2.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/odb-tests/common/as/test.hxx b/odb-tests/common/as/test.hxx new file mode 100644 index 0000000..963abeb --- /dev/null +++ b/odb-tests/common/as/test.hxx @@ -0,0 +1,270 @@ +// file : common/as/test.hxx +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include <map> +#include <vector> +#include <string> +#include <utility> // pair + +#include <odb/core.hxx> +#include <odb/vector.hxx> +#include <odb/nullable.hxx> + +// Test basic type mapping functionality. +// +#pragma db namespace table("t1_") +namespace test1 +{ + enum color {red, green, blue}; + + inline const char* + color_to_string (color c) + { + return c == red ? "RED" : (c == green ? "GREEN" : "BLUE"); + } + + inline color + string_to_color (const std::string& s) + { + return s == "RED" ? red : (s == "GREEN" ? green : blue); + } + + #pragma db map type(color) as(std::string) \ + to(test1::color_to_string (?)) \ + from(test1::string_to_color (?)) + + typedef std::pair<int, int> intp; + + #pragma db value + struct comp + { + comp () {} + comp (int n1_, int n2_): n1 (n1_), n2 (n2_) {} + + int n1; + int n2; + }; + + #pragma db map type(intp) as(comp) \ + to(test1::comp ((?).first, (?).second)) \ + from(test1::intp ((?).n1, (?).n2)) + + #pragma db object + struct object + { + // Class-scope mapping. + // + #pragma db map type(bool) as(std::string) \ + to((?) ? "true" : "false") \ + from((?) == "true") + + #pragma db id auto + unsigned long id; + + bool b; + color c; + intp ip; + + std::map<bool, int> m; + std::vector<intp> v; + odb::vector<color> cv; + + object () {} + object (bool b_, color c_, int n1, int n2): b (b_), c (c_), ip (n1, n2) {} + }; + + inline bool + operator== (const object& x, const object y) + { + return + x.b == y.b && + x.c == y.c && + x.ip == y.ip && + x.m == y.m && + x.v == y.v && + x.cv == y.cv; + } +} + +// Test wrapped simple type mapping. +// +#pragma db namespace table("t2_") +namespace test2 +{ + #pragma db map type(bool) as(std::string) \ + to((?) ? "true" : "false") \ + from((?) == "true") + + typedef odb::nullable<bool> null_bool; + typedef odb::nullable<std::string> null_string; + + /* + #pragma db map type(null_bool) as(null_string) \ + to((?) \ + ? test2::null_string (*(?) ? "true" : "false") \ + : test2::null_string ()) \ + from((?) \ + ? test2::null_bool (*(?) == "true") \ + : test2::null_bool ()) + */ + + #pragma db map type(null_bool) as(std::string) \ + to((?) ? (*(?) ? "true" : "false") : "null") \ + from((?) != "null" \ + ? test2::null_bool ((?) == "true") \ + : test2::null_bool ()) + + #pragma db object + struct object + { + #pragma db id auto + unsigned long id; + + odb::nullable<bool> b; + std::vector<odb::nullable<bool> > v; + }; + + inline bool + operator== (const object& x, const object y) + { + return x.b == y.b && x.v == y.v; + } +} + +// Test wrapped simple type mapping. +// +#pragma db namespace table("t3_") +namespace test3 +{ + typedef std::pair<int, int> intp; + + #pragma db value + struct comp + { + comp () {} + comp (int n1_, int n2_): n1 (n1_), n2 (n2_) {} + + int n1; + int n2; + }; + + typedef odb::nullable<intp> null_intp; + typedef odb::nullable<comp> null_comp; + + #pragma db map type(null_intp) as(null_comp) \ + to((?) \ + ? test3::null_comp (test3::comp ((?)->first, (?)->second)) \ + : test3::null_comp ()) \ + from((?) \ + ? test3::null_intp (test3::intp ((?)->n1, (?)->n2)) \ + : test3::null_intp ()) + + // Map int pair with both members equal 0 to NULL comp. + // + #pragma db map type(intp) as(null_comp) \ + to((?).first != 0 || (?).second != 0 \ + ? test3::null_comp (test3::comp ((?).first, (?).second)) \ + : test3::null_comp ()) \ + from((?) \ + ? test3::intp (test3::intp ((?)->n1, (?)->n2)) \ + : test3::intp (0, 0)) + + #pragma db object + struct object + { + #pragma db id auto + unsigned long id; + + odb::nullable<intp> np; + intp ip; + + std::vector<odb::nullable<intp> > npv; + odb::vector<intp> ipv; + }; + + inline bool + operator== (const object& x, const object y) + { + return x.np == y.np && x.ip == y.ip && x.npv == y.npv && x.ipv == y.ipv; + } +} + +// Test id type mapping. +// +struct id_type +{ + typedef unsigned long value_type; + value_type value; + + id_type (value_type v = 0): value (v) {} + operator value_type () const {return value;} +}; + +#pragma db map type(id_type) as(id_type::value_type) + +#pragma db namespace table("t4_") +namespace test4 +{ + #pragma db object + struct object + { + #pragma db id auto + id_type id; + + int i; + odb::vector<int> v; + + object () {} + object (int i_): i (i_) {} + }; + + inline bool + operator== (const object& x, const object y) + { + return x.id == y.id && x.i == y.i && x.v == y.v; + } +} + +// Test version type mapping. +// +#pragma db namespace table("t5_") +namespace test5 +{ + struct version_type + { + typedef unsigned short value_type; + value_type value; + + version_type (value_type v = 0): value (v) {} + operator value_type () const {return value;} + version_type& operator++ () {value++; return *this;} + }; + + #pragma db map type(version_type) as(id_type::value_type) + + #pragma db object optimistic + struct object + { + #pragma db id + id_type id; + + #pragma db version + version_type v; + + int i; + + object () {} + object (id_type id_, int i_): id (id_), i (i_) {} + }; + + inline bool + operator== (const object& x, const object y) + { + return x.id == y.id && x.v == y.v && x.i == y.i; + } +} + +#endif // TEST_HXX diff --git a/odb-tests/common/as/testscript b/odb-tests/common/as/testscript new file mode 100644 index 0000000..12d9753 --- /dev/null +++ b/odb-tests/common/as/testscript @@ -0,0 +1,33 @@ +# file : common/as/testscript +# license : GNU GPL v2; see accompanying LICENSE file + +.include ../../database-options.testscript + +: mysql +: +if $mysql +{ + .include ../../mysql.testscript + + $create_schema; + $* +} + +: sqlite +: +if $sqlite +{ + .include ../../sqlite.testscript + + $* +} + +: pgsql +: +if $pgsql +{ + .include ../../pgsql.testscript + + $create_schema; + $* +} |