summaryrefslogtreecommitdiff
path: root/odb-tests/common/as
diff options
context:
space:
mode:
Diffstat (limited to 'odb-tests/common/as')
-rw-r--r--odb-tests/common/as/buildfile49
-rw-r--r--odb-tests/common/as/driver.cxx348
-rw-r--r--odb-tests/common/as/test.hxx270
-rw-r--r--odb-tests/common/as/testscript33
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;
+ $*
+}