aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-02-04 17:23:54 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-02-04 17:23:54 +0200
commit504fa38f3f71c345f41dfbb7e59b1d2f88308987 (patch)
treed4328b3cb9de151699232c9722e2f8899ac2f36b
parentcbad49a571dfff9a046997b18776fd3cee6d7b51 (diff)
Implement object loading views
See section 10.2 in the manual for details.
-rw-r--r--common/makefile4
-rw-r--r--common/session/custom/makefile3
-rw-r--r--common/view/basics/driver.cxx (renamed from common/view/driver.cxx)8
-rw-r--r--common/view/basics/makefile (renamed from common/view/makefile)18
-rw-r--r--common/view/basics/test.hxx (renamed from common/view/test.hxx)64
-rw-r--r--common/view/basics/test.std (renamed from common/view/test.std)0
-rw-r--r--common/view/olv/driver.cxx615
-rw-r--r--common/view/olv/makefile113
-rw-r--r--common/view/olv/test.hxx687
-rw-r--r--common/view/olv/test.std0
10 files changed, 1463 insertions, 49 deletions
diff --git a/common/makefile b/common/makefile
index 7f99cf4..f933484 100644
--- a/common/makefile
+++ b/common/makefile
@@ -55,12 +55,12 @@ template \
transaction/basics \
transaction/callback \
types \
-view \
+view/basics \
virtual \
wrapper
thread_tests := threads
-cxx11_tests := session/custom
+cxx11_tests := session/custom view/olv
no_dist_tests := changelog include
diff --git a/common/session/custom/makefile b/common/session/custom/makefile
index 87016e1..ad92aa8 100644
--- a/common/session/custom/makefile
+++ b/common/session/custom/makefile
@@ -57,8 +57,7 @@ $(dist): export extra_sources := $(filter-out driver.cxx,$(cxx_tun))
$(dist): data_dist := test.std
$(dist): export name := $(name)
$(dist): export extra_dist := $(data_dist) $(call vc10projs,$(name)) \
-$(call vc11projs,$(name)) \
-$(call vc12projs,$(name))
+$(call vc11projs,$(name)) $(call vc12projs,$(name))
$(dist):
$(call dist-data,$(sources) $(headers) $(extra_headers) $(data_dist))
$(call meta-automake,../../template/Makefile.am)
diff --git a/common/view/driver.cxx b/common/view/basics/driver.cxx
index 28c3ba0..e1a72f7 100644
--- a/common/view/driver.cxx
+++ b/common/view/basics/driver.cxx
@@ -1,8 +1,8 @@
-// file : common/view/driver.cxx
+// file : common/view/basics/driver.cxx
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
-// Test views.
+// Test view basics.
//
#include <memory> // std::auto_ptr
@@ -344,11 +344,11 @@ main (int argc, char* argv[])
result r;
if (db->id () != odb::id_oracle)
r = db->query<view1c> ("SELECT first, last, age "
- "FROM t_view_person "
+ "FROM t_view_b_person "
"WHERE age < 31 ORDER BY age");
else
r = db->query<view1c> ("SELECT \"first\", \"last\", \"age\" "
- "FROM \"t_view_person\" "
+ "FROM \"t_view_b_person\" "
"WHERE \"age\" < 31 ORDER BY \"age\"");
view1_check (r);
diff --git a/common/view/makefile b/common/view/basics/makefile
index f7010ed..7598bb7 100644
--- a/common/view/makefile
+++ b/common/view/basics/makefile
@@ -1,8 +1,8 @@
-# file : common/view/makefile
+# file : common/view/basics/makefile
# copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
# license : GNU GPL v2; see accompanying LICENSE file
-include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
cxx_tun := driver.cxx
odb_hdr := test.hxx
@@ -29,7 +29,7 @@ $(cxx_obj) $(cxx_od): $(common.l.cpp-options)
$(gen): $(odb)
$(gen): odb := $(odb)
$(gen) $(dist): export odb_options += --generate-schema --generate-query \
---generate-prepared --table-prefix t_view_
+--generate-prepared --table-prefix t_view_b_
$(gen): cpp_options := -I$(src_base)
$(gen): $(common.l.cpp-options)
@@ -58,12 +58,12 @@ $(call vc9projs,$(name)) $(call vc10projs,$(name)) $(call vc11projs,$(name)) \
$(call vc12projs,$(name))
$(dist):
$(call dist-data,$(sources) $(headers) $(data_dist))
- $(call meta-automake,../template/Makefile.am)
- $(call meta-vc8projs,../template/template,$(name))
- $(call meta-vc9projs,../template/template,$(name))
- $(call meta-vc10projs,../template/template,$(name))
- $(call meta-vc11projs,../template/template,$(name))
- $(call meta-vc12projs,../template/template,$(name))
+ $(call meta-automake,../../template/Makefile.am)
+ $(call meta-vc8projs,../../template/template,$(name))
+ $(call meta-vc9projs,../../template/template,$(name))
+ $(call meta-vc10projs,../../template/template,$(name))
+ $(call meta-vc11projs,../../template/template,$(name))
+ $(call meta-vc12projs,../../template/template,$(name))
# Test.
#
diff --git a/common/view/test.hxx b/common/view/basics/test.hxx
index ae30e25..18fae4b 100644
--- a/common/view/test.hxx
+++ b/common/view/basics/test.hxx
@@ -1,4 +1,4 @@
-// file : common/view/test.hxx
+// file : common/view/basics/test.hxx
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
@@ -130,10 +130,10 @@ struct employer
// Complete suffix query template.
//
#ifndef ODB_DATABASE_ORACLE
-# pragma db view query("SELECT first, last, age FROM t_view_person")
+# pragma db view query("SELECT first, last, age FROM t_view_b_person")
#else
# pragma db view query("SELECT \"first\", \"last\", \"age\" " \
- "FROM \"t_view_person\"")
+ "FROM \"t_view_b_person\"")
#endif
struct view1
{
@@ -146,11 +146,11 @@ struct view1
//
#ifndef ODB_DATABASE_ORACLE
# pragma db view query("SELECT first, last, age " \
- "FROM t_view_person " \
+ "FROM t_view_b_person " \
"WHERE age < 31 ORDER BY age")
#else
# pragma db view query("SELECT \"first\", \"last\", \"age\" " \
- "FROM \"t_view_person\" " \
+ "FROM \"t_view_b_person\" " \
"WHERE \"age\" < 31 ORDER BY \"age\"")
#endif
struct view1a
@@ -164,11 +164,11 @@ struct view1a
//
#ifndef ODB_DATABASE_ORACLE
# pragma db view query("SELECT first, last, age " \
- "FROM t_view_person " \
+ "FROM t_view_b_person " \
"WHERE age < 31 AND (?) ORDER BY age")
#else
# pragma db view query("SELECT \"first\", \"last\", \"age\" " \
- "FROM \"t_view_person\" " \
+ "FROM \"t_view_b_person\" " \
"WHERE \"age\" < 31 AND (?) ORDER BY \"age\"")
#endif
struct view1b
@@ -190,7 +190,7 @@ struct view1c
// Assembled SELECT and FROM-lists.
//
-#pragma db view table("t_view_person")
+#pragma db view table("t_view_b_person")
struct view1d
{
#pragma db column("first")
@@ -211,10 +211,10 @@ struct view1d
//
#ifndef ODB_DATABASE_ORACLE
# pragma db view object(person) \
- query("SELECT count(id) FROM t_view_person")
+ query("SELECT count(id) FROM t_view_b_person")
#else
# pragma db view object(person) \
- query("SELECT count(\"id\") FROM \"t_view_person\"")
+ query("SELECT count(\"id\") FROM \"t_view_b_person\"")
#endif
struct view2
{
@@ -240,9 +240,9 @@ struct view2a
struct view2b
{
#ifndef ODB_DATABASE_ORACLE
- #pragma db column("count(t_view_person.id)")
+ #pragma db column("count(t_view_b_person.id)")
#else
- #pragma db column("count(\"t_view_person\".\"id\")")
+ #pragma db column("count(\"t_view_b_person\".\"id\")")
#endif
std::size_t count;
};
@@ -265,12 +265,12 @@ struct view2c
#ifndef ODB_DATABASE_ORACLE
# pragma db view object(person = test) \
query("SELECT last, count(last) " \
- "FROM t_view_person " \
+ "FROM t_view_b_person " \
"GROUP BY last")
#else
# pragma db view object(person = test) \
query("SELECT \"last\", count(\"last\") " \
- "FROM \"t_view_person\" " \
+ "FROM \"t_view_b_person\" " \
"GROUP BY \"last\"")
#endif
struct view3
@@ -302,15 +302,15 @@ struct view3a
#ifndef ODB_DATABASE_ORACLE
# pragma db view object(person) object(country = residence) \
query("SELECT first, last, residence.name " \
- "FROM t_view_person " \
- "LEFT JOIN t_view_country AS residence " \
- "ON t_view_person.residence = residence.code")
+ "FROM t_view_b_person " \
+ "LEFT JOIN t_view_b_country AS residence " \
+ "ON t_view_b_person.residence = residence.code")
#else
# pragma db view object(person) object(country = residence) \
query("SELECT \"first\", \"last\", \"residence\".\"name\" " \
- "FROM \"t_view_person\" " \
- "LEFT JOIN \"t_view_country\" \"residence\" " \
- "ON \"t_view_person\".\"residence\" = \"residence\".\"code\"")
+ "FROM \"t_view_b_person\" " \
+ "LEFT JOIN \"t_view_b_country\" \"residence\" " \
+ "ON \"t_view_b_person\".\"residence\" = \"residence\".\"code\"")
#endif
struct view4
{
@@ -392,21 +392,21 @@ struct view6b
// The same using tables.
//
#if defined(ODB_DATABASE_ORACLE)
-#pragma db view table("t_view_person" = "p") \
- table("t_view_employer_employees" = "ee": "\"ee\".\"value\" = \"p\".\"id\"")\
- table("t_view_employer" = "e": "\"ee\".\"object_id\" = \"e\".\"name\"")
+#pragma db view table("t_view_b_person" = "p") \
+ table("t_view_b_employer_employees" = "ee": "\"ee\".\"value\" = \"p\".\"id\"")\
+ table("t_view_b_employer" = "e": "\"ee\".\"object_id\" = \"e\".\"name\"")
#elif defined(ODB_DATABASE_MSSQL)
-#pragma db view table("t_view_person" = "p") \
- table("t_view_employer_employees" = "ee": "ee.value = p.id") \
- table("t_view_employer" = "e": "[ee].[object_id] = e.name")
+#pragma db view table("t_view_b_person" = "p") \
+ table("t_view_b_employer_employees" = "ee": "ee.value = p.id") \
+ table("t_view_b_employer" = "e": "[ee].[object_id] = e.name")
#elif defined(ODB_DATABASE_MYSQL)
-#pragma db view table("t_view_person" = "p") \
- table("t_view_employer_employees" = "ee": "ee.value = p.id") \
- table("t_view_employer" = "e": "`ee`.`object_id` = e.name")
+#pragma db view table("t_view_b_person" = "p") \
+ table("t_view_b_employer_employees" = "ee": "ee.value = p.id") \
+ table("t_view_b_employer" = "e": "`ee`.`object_id` = e.name")
#else
-#pragma db view table("t_view_person" = "p") \
- table("t_view_employer_employees" = "ee": "ee.value = p.id") \
- table("t_view_employer" = "e": "\"ee\".\"object_id\" = e.name")
+#pragma db view table("t_view_b_person" = "p") \
+ table("t_view_b_employer_employees" = "ee": "ee.value = p.id") \
+ table("t_view_b_employer" = "e": "\"ee\".\"object_id\" = e.name")
#endif
struct view6c
{
diff --git a/common/view/test.std b/common/view/basics/test.std
index e69de29..e69de29 100644
--- a/common/view/test.std
+++ b/common/view/basics/test.std
diff --git a/common/view/olv/driver.cxx b/common/view/olv/driver.cxx
new file mode 100644
index 0000000..6ef2467
--- /dev/null
+++ b/common/view/olv/driver.cxx
@@ -0,0 +1,615 @@
+// file : common/view/olv/driver.cxx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test object loading views.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+#include <typeinfo>
+
+#include <odb/session.hxx>
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+
+#include <common/common.hxx>
+
+#include "test.hxx"
+#include "test-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv));
+
+ // Test basic object loading functionality.
+ //
+ {
+ using namespace test1;
+
+ {
+ object1 o1a (1, 123);
+ object2 o2 (1, "abc");
+
+ transaction t (db->begin ());
+ db->persist (o1a);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view1> query;
+
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> (query::object1::n == 123));
+ assert (v.o2->s == "abc");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view2 v (db->query_value<view2> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view3 v (db->query_value<view3> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc");
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view4 v (db->query_value<view4> ());
+ assert (v.s == "abc" && v.o2->s == "abc" && v.id == 1 &&
+ v.o1->n == 123 && v.n == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view4 v (db->query_value<view4> ());
+ assert (v.s == "abc" && v.o2->s == "abc" && v.id == 1 &&
+ v.o1->n == 123 && v.n == 123);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view5> query;
+
+ object1 o1b (123, 1);
+
+ transaction t (db->begin ());
+ db->persist (o1b);
+ view5 v (db->query_value<view5> (query::o1b::n == 1));
+ assert (v.o1a->n == 123 && v.o2->s == "abc" && v.o1b->n == 1);
+ t.commit ();
+ }
+ }
+
+ // Test loading of object pointers inside objects.
+ //
+ {
+ using namespace test2;
+
+ shared_ptr<object1> o1 (new object1 (123));
+ shared_ptr<object2> o2 (new object2 ("abc", o1));
+
+ {
+
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> ());
+ assert (v.o2->s == "abc" && v.o2->o1->n == 123);
+ t.commit ();
+ }
+
+ {
+ // Check session interaction.
+ //
+ transaction t (db->begin ());
+ session s;
+ shared_ptr<object2> o2a (db->load<object2> (o2->id));
+ view1 v (db->query_value<view1> ());
+ assert (v.o2 == o2a);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view2 v (db->query_value<view2> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1);
+ t.commit ();
+ }
+
+ shared_ptr<object3> o3 (new object3 (o2));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view3 v (db->query_value<view3> ());
+ assert (v.o1->n == 123 && v.o3->o2->s == "abc" &&
+ v.o3->o2->o1 == v.o1);
+ t.commit ();
+ }
+
+ shared_ptr<object1> o1b (new object1 (234));
+ shared_ptr<object2> o2b (new object2 ("bcd", o1b));
+ shared_ptr<object4> o4 (new object4);
+ o4->o2.push_back (o2);
+ o4->o2.push_back (o2b);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1b);
+ db->persist (o2b);
+ db->persist (o4);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view4 v (db->query_value<view4> ());
+ assert (v.o4->o2[0]->s == "abc" && v.o4->o2[0]->o1->n == 123 &&
+ v.o4->o2[1]->s == "bcd" && v.o4->o2[1]->o1->n == 234);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view5> query;
+ typedef odb::result<view5> result;
+
+ transaction t (db->begin ());
+ session s;
+ result r (db->query<view5> ("ORDER BY" + query::object1::id));
+ result::iterator i (r.begin ());
+
+ assert (i != r.end ());
+ {
+ view5 const& v (*i);
+
+ assert (v.o4->o2[0]->s == "abc" && v.o4->o2[0]->o1->n == 123 &&
+ v.o4->o2[1]->s == "bcd" && v.o4->o2[1]->o1->n == 234 &&
+ v.o4->o2[0]->o1 == v.o1);
+ }
+ assert (++i != r.end ());
+ {
+ view5 const& v (*i);
+
+ assert (v.o4->o2[0]->s == "abc" && v.o4->o2[0]->o1->n == 123 &&
+ v.o4->o2[1]->s == "bcd" && v.o4->o2[1]->o1->n == 234 &&
+ v.o4->o2[1]->o1 == v.o1);
+ }
+ assert (++i == r.end ());
+ t.commit ();
+ }
+
+ shared_ptr<object5> o5 (new object5 (o1b, o2));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o5);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view6 v (db->query_value<view6> ());
+ assert (v.o1a->n == 123 && v.o1b->n == 234);
+ t.commit ();
+ }
+ }
+
+ // Test JOINs for pointed-to objects, existing and automatically added.
+ //
+ {
+ using namespace test3;
+
+ shared_ptr<object1> o1 (new object1 (123));
+ shared_ptr<object2> o2 (new object2 ("abc"));
+
+ o1->o2 = o2;
+ o2->o1 = o1;
+
+ {
+
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1a v (db->query_value<view1a> ());
+ assert (v.o1->n == 123 && v.o1->o2.object_id () == o2->id);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1b v (db->query_value<view1b> ());
+ assert (v.o1->n == 123 && v.o1->o2.object_id () == o2->id);
+ t.commit ();
+ }
+
+ // Container case.
+ //
+
+ shared_ptr<object3> o3 (new object3 (123));
+ shared_ptr<object4> o4 (new object4 ("abc"));
+
+ o3->o4 = o4;
+ o4->o3.push_back (o3);
+
+ {
+
+ transaction t (db->begin ());
+ db->persist (o3);
+ db->persist (o4);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view2a v (db->query_value<view2a> ());
+ assert (v.o3->n == 123 && v.o3->o4.object_id () == o4->id);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view2b v (db->query_value<view2b> ());
+ assert (v.o3->n == 123 && v.o3->o4.object_id () == o4->id);
+ t.commit ();
+ }
+ }
+
+ // Test by-value load.
+ //
+ {
+ using namespace test4;
+
+ {
+ object1 o1 (1, 123);
+ object2 o2 (1, "abc", &o1);
+
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> ());
+ assert (v.o1.n == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1a v (db->query_value<view1a> ());
+ assert (!v.o1_null && v.o1.n == 123);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1b v (db->query_value<view1b> ());
+ assert (/*v.o1_p == &v.o1 && */ v.o1.n == 123); // Copy ctor.
+ t.commit ();
+ }
+
+ {
+ typedef odb::result<view1c> result;
+
+ transaction t (db->begin ());
+ result r (db->query<view1c> ());
+ result::iterator i (r.begin ());
+ assert (i != r.end ());
+
+ object1 o1;
+ view1c v (o1);
+ i.load (v);
+
+ assert (v.o1_p == &o1 && o1.n == 123);
+
+ assert (++i == r.end ());
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view2 v (db->query_value<view2> ());
+ assert (v.o1.n == 123 && v.o2.s == "abc" && v.o2.o1 == &v.o1);
+ t.commit ();
+ }
+
+ object1 o1b (2, 234);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1b);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view2a> query;
+
+ transaction t (db->begin ());
+ session s;
+ view2a v (db->query_value<view2a> (query::object1::id == 2));
+ assert (v.o1.n == 234 && v.o2_null);
+ t.commit ();
+ }
+
+ shared_ptr<object3> o3 (new object3 (1, 123));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ {
+ view3 v (db->query_value<view3> ());
+ assert (v.o3_p == &v.o3 && v.o3.n == 123); // Load into value.
+ }
+ session s; // Load into cache.
+ shared_ptr<object3> o3a (db->load<object3> (o3->id));
+ {
+ view3 v (db->query_value<view3> ());
+ assert (v.o3_p == o3a.get ()); // Load from cache.
+ }
+ t.commit ();
+ }
+ }
+
+ // Test NULL object pointers.
+ //
+ {
+ using namespace test5;
+
+ shared_ptr<object1> o1a (new object1 (123));
+ shared_ptr<object1> o1b (new object1 (234));
+ shared_ptr<object2> o2 (new object2 ("abc", o1a));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1a);
+ db->persist (o1b);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view1> query;
+ typedef odb::result<view1> result;
+
+ transaction t (db->begin ());
+ session s;
+ result r (db->query<view1> ("ORDER BY" + query::object1::id));
+ result::iterator i (r.begin ());
+
+ assert (i != r.end ());
+ {
+ view1 const& v (*i);
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1);
+ }
+ assert (++i != r.end ());
+ {
+ view1 const& v (*i);
+ assert (v.o1->n == 234 && !v.o2);
+ }
+ assert (++i == r.end ());
+ t.commit ();
+ }
+
+ shared_ptr<object3> o3a (new object3 (make_pair (1, 1), 123));
+ shared_ptr<object3> o3b (new object3 (make_pair (2, 2), 234));
+ shared_ptr<object4> o4 (new object4 ("abc", o3a));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o3a);
+ db->persist (o3b);
+ db->persist (o4);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view2> query;
+ typedef odb::result<view2> result;
+
+ transaction t (db->begin ());
+ session s;
+ result r (db->query<view2> ("ORDER BY" + query::object3::n));
+ result::iterator i (r.begin ());
+
+ assert (i != r.end ());
+ {
+ view2 const& v (*i);
+ assert (v.o3->n == 123 && v.o4->s == "abc" && v.o4->o3 == v.o3);
+ }
+ assert (++i != r.end ());
+ {
+ view2 const& v (*i);
+ assert (v.o3->n == 234 && !v.o4);
+ }
+ assert (++i == r.end ());
+ t.commit ();
+ }
+ }
+
+ // Test interaction with sections.
+ //
+ {
+ using namespace test6;
+
+ shared_ptr<object1> o1 (new object1 (123));
+ shared_ptr<object2> o2 (new object2 ("abc", o1));
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ view1 v (db->query_value<view1> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" &&
+ !v.o2->r.loaded () && !v.o2->o1);
+ t.commit ();
+ }
+ }
+
+ // Test explicit conversion to smart pointer member.
+ //
+ {
+ using namespace test7;
+
+ object1 o1 (123);
+ object2 o2 ("abc", &o1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view1 v (db->query_value<view1> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1.get ());
+ t.commit ();
+ }
+ }
+
+ // Test loading objects without id.
+ //
+ {
+ using namespace test8;
+
+ object1 o1 (123);
+ object2 o2 ("abc", &o1);
+
+ {
+ transaction t (db->begin ());
+ db->persist (o1);
+ db->persist (o2);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ session s;
+ view1 v (db->query_value<view1> ());
+ assert (v.o1->n == 123 && v.o2->s == "abc" && v.o2->o1 == v.o1.get ());
+ t.commit ();
+ }
+ }
+
+ // Test loading polymorphic objects.
+ //
+ {
+ using namespace test9;
+
+ root r (1);
+ base b (2, "a");
+ derived d (3, "b", true);
+
+ {
+ transaction t (db->begin ());
+ db->persist (r);
+ db->persist (b);
+ db->persist (d);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+
+ // Load via root.
+ //
+ {
+ view1r r (db->query_value<view1r> (query<view1r>::n == 1));
+ assert (r.n == 1 && r.o->n == 1 && typeid (*r.o) == typeid (root));
+ }
+
+ {
+ view1r r (db->query_value<view1r> (query<view1r>::n == 2));
+ assert (r.n == 2 && r.o->n == 2 && typeid (*r.o) == typeid (base));
+ base& b (dynamic_cast<base&> (*r.o));
+ assert (b.s == "a");
+ }
+
+ {
+ view1r r (db->query_value<view1r> (query<view1r>::n == 3));
+ assert (r.n == 3 && r.o->n == 3 && typeid (*r.o) == typeid (derived));
+ derived& d (dynamic_cast<derived&> (*r.o));
+ assert (d.s == "b" && d.b);
+ }
+
+ // Load via base.
+ //
+ {
+ view1b r (db->query_value<view1b> (query<view1b>::n == 2));
+ assert (r.s == "a" && r.n == 2 && r.o->n == 2 && b.s == "a");
+ }
+
+ {
+ view1b r (db->query_value<view1b> (query<view1b>::n == 3));
+ assert (r.s == "b" && r.n == 3 && r.o->n == 3 &&
+ typeid (*r.o) == typeid (derived));
+ derived& d (dynamic_cast<derived&> (*r.o));
+ assert (d.s == "b" && d.b);
+ }
+
+ // Load via derived.
+ //
+ {
+ view1d r (db->query_value<view1d> ());
+ assert (r.s == "b" && r.n == 3 &&
+ r.o->n == 3 && r.o->s == "b" && r.o->b);
+ }
+
+ t.commit ();
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/common/view/olv/makefile b/common/view/olv/makefile
new file mode 100644
index 0000000..9da28db
--- /dev/null
+++ b/common/view/olv/makefile
@@ -0,0 +1,113 @@
+# file : common/view/olv/makefile
+# copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+# license : GNU GPL v2; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
+
+cxx_tun := driver.cxx
+odb_hdr := test.hxx
+genf := $(call odb-gen,$(odb_hdr))
+gen := $(addprefix $(out_base)/,$(genf))
+cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) $(filter %.o,$(gen:.cxx=.o))
+cxx_od := $(cxx_obj:.o=.o.d)
+
+common.l := $(out_root)/libcommon/common/common.l
+common.l.cpp-options := $(out_root)/libcommon/common/common.l.cpp-options
+
+# Import.
+#
+$(call import,\
+ $(scf_root)/import/odb/stub.make,\
+ odb: odb,odb-rules: odb_rules)
+
+# Build.
+#
+$(driver): $(cxx_obj) $(common.l)
+$(cxx_obj) $(cxx_od): cpp_options := -I$(out_base) -I$(src_base)
+$(cxx_obj) $(cxx_od): $(common.l.cpp-options)
+
+$(gen): $(odb)
+$(gen): odb := $(odb)
+$(gen) $(dist): export odb_options += --generate-schema --generate-query \
+--table-prefix t_view_olv_
+$(gen): cpp_options := -I$(src_base)
+$(gen): $(common.l.cpp-options)
+
+ifneq ($(db_id),common)
+$(gen): odb_options += --database $(db_id)
+else
+$(gen): odb_options += --multi-database dynamic
+endif
+
+$(call include-dep,$(cxx_od),$(cxx_obj),$(gen))
+
+# Alias for default target.
+#
+$(out_base)/: $(driver)
+
+# Dist
+#
+name := $(subst /,-,$(subst $(src_root)/common/,,$(src_base)))
+
+$(dist): sources := $(cxx_tun)
+$(dist): headers := $(odb_hdr)
+$(dist): data_dist := test.std
+$(dist): export name := $(name)
+$(dist): export extra_dist := $(data_dist) $(call vc10projs,$(name)) \
+$(call vc11projs,$(name)) $(call vc12projs,$(name))
+$(dist):
+ $(call dist-data,$(sources) $(headers) $(data_dist))
+ $(call meta-automake,../../template/Makefile.am)
+ $(call meta-vc10projs,../../template/template,$(name))
+ $(call meta-vc11projs,../../template/template,$(name))
+ $(call meta-vc12projs,../../template/template,$(name))
+
+# Test.
+#
+ifneq ($(db_id),common)
+$(eval $(call test-rule))
+else
+$(foreach d,$(databases),$(eval $(call test-rule,$d)))
+endif
+
+# Clean.
+#
+$(clean): \
+ $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(cxx_obj)) \
+ $(addsuffix .cxx.clean,$(cxx_od)) \
+ $(addsuffix .hxx.clean,$(filter %.cxx,$(gen)))
+ $(call message,,rm -f $(out_base)/test.out)
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver $(genf)
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+# How to.
+#
+$(call include,$(bld_root)/dist.make)
+$(call include,$(bld_root)/meta/vc10proj.make)
+$(call include,$(bld_root)/meta/vc11proj.make)
+$(call include,$(bld_root)/meta/vc12proj.make)
+$(call include,$(bld_root)/meta/automake.make)
+
+$(call include,$(bld_root)/cxx/standard.make) # cxx_standard
+ifdef cxx_standard
+$(gen): odb_options += --std $(cxx_standard)
+$(call include,$(odb_rules))
+endif
+
+$(call include,$(bld_root)/cxx/cxx-d.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/o-e.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/libcommon/makefile)
diff --git a/common/view/olv/test.hxx b/common/view/olv/test.hxx
new file mode 100644
index 0000000..8f358d3
--- /dev/null
+++ b/common/view/olv/test.hxx
@@ -0,0 +1,687 @@
+// file : common/view/olv/test.hxx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef TEST_HXX
+#define TEST_HXX
+
+#include <string>
+#include <vector>
+#include <memory> // unique_ptr
+#include <utility> // pair
+
+#include <odb/core.hxx>
+#include <odb/lazy-ptr.hxx>
+#include <odb/section.hxx>
+
+// Test basic object loading functionality.
+//
+#pragma db namespace table("t1_") pointer(std::unique_ptr)
+namespace test1
+{
+ #pragma db object
+ struct object1
+ {
+ object1 (int id_ = 0, int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (int id_ = 0, const char* s_ = ""): id (id_), s (s_) {}
+
+ #pragma db id
+ int id;
+
+ std::string s;
+ };
+
+ #pragma db view object(object1) object(object2: object1::id == object2::id)
+ struct view1
+ {
+ std::unique_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1) object(object2: object1::id == object2::id)
+ struct view2
+ {
+ std::unique_ptr<object2> o2;
+ std::unique_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1 = o1) object(object2 = o2: o1::id == o2::id)
+ struct view3
+ {
+ std::unique_ptr<object1> o1;
+ std::unique_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1 = o1) object(object2 = o2: o1::id == o2::id)
+ struct view4
+ {
+ std::string s;
+ std::unique_ptr<object2> o2;
+
+ #pragma db column(o1::id)
+ int id;
+
+ std::unique_ptr<object1> o1;
+ int n;
+ };
+
+ #pragma db view \
+ object(object1) \
+ object(object2: object1::id == object2::id) \
+ object(object1 = o1b: object1::id == o1b::n)
+ struct view5
+ {
+ std::unique_ptr<object1> o1a;
+ std::unique_ptr<object2> o2;
+ std::unique_ptr<object1> o1b;
+ };
+}
+
+// Test loading of object pointers inside objects.
+//
+#pragma db namespace table("t2_") pointer(std::shared_ptr) session
+namespace test2
+{
+ using std::shared_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, shared_ptr<object1> o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ shared_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view2
+ {
+ shared_ptr<object2> o2; // "Unfortunate" order.
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db object
+ struct object3
+ {
+ object3 () {}
+ object3 (shared_ptr<object2> o2_): o2 (o2_) {}
+
+ #pragma db id auto
+ int id;
+
+ shared_ptr<object2> o2;
+ };
+
+ #pragma db view object(object1) object(object2) object(object3)
+ struct view3
+ {
+ shared_ptr<object3> o3; // "Unfortunate" order.
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db object
+ struct object4
+ {
+ #pragma db id auto
+ int id;
+
+ std::vector<shared_ptr<object2>> o2;
+ };
+
+ #pragma db view object(object4)
+ struct view4
+ {
+ shared_ptr<object4> o4;
+ };
+
+ #pragma db view object(object4) object (object2) object(object1)
+ struct view5
+ {
+ shared_ptr<object4> o4; // "Unfortunate" order.
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db object
+ struct object5
+ {
+ object5 () {}
+ object5 (shared_ptr<object1> o1_, shared_ptr<object2> o2_)
+ : o1 (o1_), o2 (o2_) {}
+
+ #pragma db id auto
+ int id;
+
+ shared_ptr<object1> o1;
+ shared_ptr<object2> o2;
+ };
+
+ #pragma db view object(object5) object (object2) \
+ object(object1 = o1a: object2::o1) \
+ object(object1 = o1b: object5::o1)
+ struct view6
+ {
+ shared_ptr<object1> o1a;
+ shared_ptr<object1> o1b;
+ };
+}
+
+// Test JOINs for pointed-to objects, existing and automatically added.
+//
+#pragma db namespace table("t3_") pointer(std::shared_ptr) session
+namespace test3
+{
+ using std::shared_ptr;
+
+ struct object2;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+
+ #pragma db inverse(o1)
+ odb::lazy_weak_ptr<object2> o2;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (const char* s_ = ""): s (s_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1a // Existing JOIN.
+ {
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1)
+ struct view1b // Automatic JOIN.
+ {
+ shared_ptr<object1> o1;
+ };
+
+ // Container case.
+ //
+ struct object4;
+
+ #pragma db object
+ struct object3
+ {
+ object3 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+
+ #pragma db inverse(o3)
+ odb::lazy_weak_ptr<object4> o4;
+ };
+
+ #pragma db object
+ struct object4
+ {
+ object4 (const char* s_ = ""): s (s_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+
+ std::vector<shared_ptr<object3>> o3;
+ };
+
+ #pragma db view object(object3) object(object4 = o4)
+ struct view2a // Existing JOIN.
+ {
+ shared_ptr<object3> o3;
+ };
+
+ #pragma db view object(object3)
+ struct view2b // Automatic JOIN.
+ {
+ shared_ptr<object3> o3;
+ };
+}
+
+// Test by-value load.
+//
+#pragma db namespace table("t4_") session
+namespace test4
+{
+ #pragma db object
+ struct object1
+ {
+ object1 (int id_ = 0, int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 (int id_ = 0, const char* s_ = "", object1* o1_ = 0)
+ : id (id_), s (s_), o1 (o1_) {}
+
+ #pragma db id
+ int id;
+
+ std::string s;
+ object1* o1; // Shallow copy.
+ };
+
+ typedef object1* object1_ptr;
+ typedef object2* object2_ptr;
+
+ #pragma db view object(object1)
+ struct view1
+ {
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) set()
+
+ #pragma db transient
+ object1 o1;
+ };
+
+ #pragma db view object(object1) transient
+ struct view1a
+ {
+ view1a (): o1_null (true) {}
+
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) \
+ set(this.o1_null = !(?))
+
+ object1 o1;
+ bool o1_null;
+ };
+
+ #pragma db view object(object1)
+ struct view1b
+ {
+ view1b (): o1_p (0) {}
+
+ #pragma db transient
+ object1 o1;
+
+ #pragma db get(&this.o1) set(o1_p = (?))
+ object1* o1_p;
+ };
+
+ #pragma db view object(object1)
+ struct view1c
+ {
+ view1c (object1& o1): o1_p (&o1) {}
+
+ object1* o1_p;
+ };
+
+ #pragma db view object(object1) object(object2) transient
+ struct view2
+ {
+ #pragma db member(o2_) virtual(object2_ptr) get(&this.o2) set()
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) set()
+
+ object1 o1;
+ object2 o2;
+ };
+
+ #pragma db view object(object1) object(object2) transient
+ struct view2a
+ {
+ #pragma db member(o2_) virtual(object2_ptr) get(&this.o2) \
+ set(o2_null = !(?))
+ #pragma db member(o1_) virtual(object1_ptr) get(&this.o1) set()
+
+ object1 o1;
+ object2 o2;
+ bool o2_null;
+ };
+
+ // Test loading into raw pointer with non-raw object pointer.
+ //
+ using std::shared_ptr;
+
+ #pragma db object pointer(shared_ptr)
+ struct object3
+ {
+ object3 (int id_ = 0, int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ int id;
+
+ int n;
+ };
+
+ #pragma db view object(object3)
+ struct view3
+ {
+ // This view implements the following slightly twisted logic: if the
+ // object is already in the cache, then set o3_p to that. Otherwise,
+ // load it into the by-value instance. We can also check whether o3_p
+ // points to o3 to distinguish between the two outcomes.
+ //
+
+ // Since we may be getting the pointer as both smart and raw, we
+ // need to create a bit of support code to use in the modifier
+ // expression.
+ //
+ void set_o3 (object3* p) {o3_p = p;} // &o3 or NULL.
+ void set_o3 (shared_ptr<object3> p) {o3_p = p.get ();} // From cache.
+
+ #pragma db get(&this.o3) set(set_o3(?))
+ object3* o3_p;
+
+ #pragma db transient
+ object3 o3;
+
+ // Return-by-value support (query_value()).
+ //
+ view3 (): o3_p (0) {}
+ view3 (const view3& x): o3_p (x.o3_p == &x.o3 ? &o3 : x.o3_p), o3 (x.o3) {}
+ };
+}
+
+// Test NULL object pointers.
+//
+#pragma db namespace table("t5_") pointer(std::shared_ptr) session
+namespace test5
+{
+ using std::shared_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, shared_ptr<object1> o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ shared_ptr<object1> o1;
+ shared_ptr<object2> o2;
+ };
+
+ typedef std::pair<int, int> comp_id;
+ #pragma db value(comp_id)
+
+ #pragma db object
+ struct object3
+ {
+ object3 (comp_id id_ = comp_id (), int n_ = 0): id (id_), n (n_) {}
+
+ #pragma db id
+ comp_id id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object4
+ {
+ object4 () {}
+ object4 (const char* s_, shared_ptr<object3> o3_): s (s_), o3 (o3_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ shared_ptr<object3> o3;
+ };
+
+ #pragma db view object(object3) object(object4)
+ struct view2
+ {
+ shared_ptr<object4> o4;
+ shared_ptr<object3> o3;
+ };
+}
+
+// Test interaction with sections.
+//
+#pragma db namespace table("t6_") pointer(std::shared_ptr)
+namespace test6
+{
+ using std::shared_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, shared_ptr<object1> o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+
+ #pragma db load(lazy)
+ odb::section r;
+
+ #pragma db section(r)
+ shared_ptr<object1> o1;
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ shared_ptr<object1> o1;
+ shared_ptr<object2> o2;
+ };
+}
+
+// Test explicit conversion to smart pointer member.
+//
+#pragma db namespace table("t7_") pointer(*) session
+namespace test7
+{
+ using std::unique_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, object1* o1_): s (s_), o1 (o1_) {}
+
+ #pragma db id auto
+ int id;
+
+ std::string s;
+ object1* o1; // Shallow.
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ unique_ptr<object2> o2;
+ unique_ptr<object1> o1;
+ };
+}
+
+// Test loading objects without id.
+//
+#pragma db namespace table("t8_") pointer(*) session
+namespace test8
+{
+ using std::unique_ptr;
+
+ #pragma db object
+ struct object1
+ {
+ object1 (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object no_id
+ struct object2
+ {
+ object2 () {}
+ object2 (const char* s_, object1* o1_): s (s_), o1 (o1_) {}
+
+ std::string s;
+ object1* o1; // Shallow.
+ };
+
+ #pragma db view object(object1) object(object2)
+ struct view1
+ {
+ unique_ptr<object2> o2;
+ unique_ptr<object1> o1;
+ };
+}
+
+// Test loading polymorphic objects.
+//
+#pragma db namespace table("t9_") session
+namespace test9
+{
+ using std::shared_ptr;
+
+ #pragma db object polymorphic pointer(shared_ptr)
+ struct root
+ {
+ virtual ~root () {}
+ root (int n_ = 0): n (n_) {}
+
+ #pragma db id auto
+ int id;
+
+ int n;
+ };
+
+ #pragma db object
+ struct base: root
+ {
+ base (int n_ = 0, const char* s_ = ""): root (n_), s (s_) {}
+
+ std::string s;
+ };
+
+ #pragma db object
+ struct derived: base
+ {
+ derived (int n_ = 0, const char* s_ = "", bool b_ = false)
+ : base (n_, s_), b (b_) {}
+
+ bool b;
+ };
+
+ // Load via root.
+ //
+ #pragma db view object(root)
+ struct view1r
+ {
+ shared_ptr<root> o;
+ int n;
+ };
+
+ // Load via base.
+ //
+ #pragma db view object(base)
+ struct view1b
+ {
+ std::string s;
+ shared_ptr<base> o;
+ int n;
+ };
+
+ // Load via derived.
+ //
+ #pragma db view object(derived)
+ struct view1d
+ {
+ std::string s;
+ shared_ptr<derived> o;
+ int n;
+ };
+}
+
+#endif // TEST_HXX
diff --git a/common/view/olv/test.std b/common/view/olv/test.std
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/common/view/olv/test.std