From 0d65234bc5c6742721c00360a0e3117d51d89c5f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 3 Jul 2015 18:23:51 +0200 Subject: Implement nested id support Now the 'id' specifier can optionally include the data member path to the id inside the composite value. For example: #pragma db id(first) std::pair p; Note that one somewhat counter-intuitive aspect of this new feature is that the whole member marked with id ('p' in the above example) and not just the actual id member ('p.first' in the above example) is treated as readonly. Such nested id also cannot be automatically assigned (auto specifier). --- common/auto/driver.cxx | 95 ------ common/auto/makefile | 117 ------- common/auto/test.hxx | 41 --- common/auto/test.std | 0 common/composite-id/driver.cxx | 730 ----------------------------------------- common/composite-id/makefile | 118 ------- common/composite-id/test.hxx | 520 ----------------------------- common/composite-id/test.std | 0 common/id/auto/driver.cxx | 95 ++++++ common/id/auto/makefile | 118 +++++++ common/id/auto/test.hxx | 41 +++ common/id/auto/test.std | 0 common/id/composite/driver.cxx | 730 +++++++++++++++++++++++++++++++++++++++++ common/id/composite/makefile | 118 +++++++ common/id/composite/test.hxx | 520 +++++++++++++++++++++++++++++ common/id/composite/test.std | 0 common/id/nested/driver.cxx | 265 +++++++++++++++ common/id/nested/makefile | 118 +++++++ common/id/nested/test.hxx | 218 ++++++++++++ common/id/nested/test.std | 0 common/makefile | 5 +- 21 files changed, 2226 insertions(+), 1623 deletions(-) delete mode 100644 common/auto/driver.cxx delete mode 100644 common/auto/makefile delete mode 100644 common/auto/test.hxx delete mode 100644 common/auto/test.std delete mode 100644 common/composite-id/driver.cxx delete mode 100644 common/composite-id/makefile delete mode 100644 common/composite-id/test.hxx delete mode 100644 common/composite-id/test.std create mode 100644 common/id/auto/driver.cxx create mode 100644 common/id/auto/makefile create mode 100644 common/id/auto/test.hxx create mode 100644 common/id/auto/test.std create mode 100644 common/id/composite/driver.cxx create mode 100644 common/id/composite/makefile create mode 100644 common/id/composite/test.hxx create mode 100644 common/id/composite/test.std create mode 100644 common/id/nested/driver.cxx create mode 100644 common/id/nested/makefile create mode 100644 common/id/nested/test.hxx create mode 100644 common/id/nested/test.std diff --git a/common/auto/driver.cxx b/common/auto/driver.cxx deleted file mode 100644 index 9033a01..0000000 --- a/common/auto/driver.cxx +++ /dev/null @@ -1,95 +0,0 @@ -// file : common/auto/driver.cxx -// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -// Test automatic id assignment. -// - -#include // std::auto_ptr -#include -#include - -#include -#include - -#include - -#include "test.hxx" -#include "test-odb.hxx" - -using namespace std; -using namespace odb::core; - -int -main (int argc, char* argv[]) -{ - try - { - auto_ptr db (create_database (argc, argv)); - - // object - // - { - unsigned long id1, id2, id3; - { - object o1 ("one"); - object o2 ("two"); - object o3 ("three"); - - transaction t (db->begin ()); - db->persist (o1); - db->persist (o2); - db->persist (o3); - t.commit (); - - id1 = o1.id_; - id2 = o2.id_; - id3 = o3.id_; - - assert (id1 != id2); - assert (id1 != id3); - assert (id2 != id3); - } - - { - transaction t (db->begin ()); - auto_ptr o1 (db->load (id1)); - auto_ptr o2 (db->load (id2)); - auto_ptr o3 (db->load (id3)); - t.commit (); - - assert (o1->id_ == id1 && o1->str_ == "one"); - assert (o2->id_ == id2 && o2->str_ == "two"); - assert (o3->id_ == id3 && o3->str_ == "three"); - } - } - - // auto_only - // - { - unsigned short id; - { - auto_only o; - - transaction t (db->begin ()); - db->persist (o); - t.commit (); - - id = o.id_; - } - - { - transaction t (db->begin ()); - auto_ptr o (db->load (id)); - t.commit (); - - assert (o->id_ == id); - } - } - } - catch (const odb::exception& e) - { - cerr << e.what () << endl; - return 1; - } -} diff --git a/common/auto/makefile b/common/auto/makefile deleted file mode 100644 index a8562c2..0000000 --- a/common/auto/makefile +++ /dev/null @@ -1,117 +0,0 @@ -# file : common/auto/makefile -# copyright : Copyright (c) 2009-2015 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 --table-prefix auto_ -$(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 vc8projs,$(name)) \ -$(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)) - -# 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/vc8proj.make) -$(call include,$(bld_root)/meta/vc9proj.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/auto/test.hxx b/common/auto/test.hxx deleted file mode 100644 index 0052bee..0000000 --- a/common/auto/test.hxx +++ /dev/null @@ -1,41 +0,0 @@ -// file : common/auto/test.hxx -// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef TEST_HXX -#define TEST_HXX - -#include - -#include - -#pragma db object -struct object -{ - object (const std::string& str) - : id_ (1), str_ (str) - { - } - - #pragma db auto id - unsigned long id_; - std::string str_; - -private: - object () - { - } - - friend class odb::access; -}; - -// Test the case where the object has just the auto id. -// -#pragma db object -struct auto_only -{ - #pragma db auto id pgsql:type("BIGINT") - unsigned short id_; -}; - -#endif // TEST_HXX diff --git a/common/auto/test.std b/common/auto/test.std deleted file mode 100644 index e69de29..0000000 diff --git a/common/composite-id/driver.cxx b/common/composite-id/driver.cxx deleted file mode 100644 index 3137fe1..0000000 --- a/common/composite-id/driver.cxx +++ /dev/null @@ -1,730 +0,0 @@ -// file : common/composite-id/driver.cxx -// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -// Test composite object ids. -// - -#include // std::auto_ptr -#include -#include - -#include -#include -#include - -#include - -#include "test.hxx" -#include "test-odb.hxx" - -using namespace std; -using namespace odb::core; - -int -main (int argc, char* argv[]) -{ - try - { - auto_ptr db (create_database (argc, argv)); - - // Test 1. - // - { - using namespace test1; - - object o1 (scomp ("aaa", "bbb", "ccc"), 123); - o1.vec.push_back (scomp ("xxx", "xxx", "xxx")); - o1.vec.push_back (scomp ("yyy", "yyy", "yyy")); - - object o2 (scomp ("aaa", "bbb", "ccd"), 234); - o2.vec.push_back (scomp ("zzz", "", "zzz")); - - object o3 (scomp ("baa", "bbb", "ccc"), 345); - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o1); - db->persist (o2); - db->persist (o3); - t.commit (); - } - - // Load. - // - { - transaction t (db->begin ()); - auto_ptr p1 (db->load (o1.id)); - auto_ptr p2 (db->load (o2.id)); - auto_ptr p3 (db->load (o3.id)); - t.commit (); - - assert (*p1 == o1); - assert (*p2 == o2); - assert (*p3 == o3); - } - - // Update. - // - { - transaction t (db->begin ()); - auto_ptr p (db->load (o1.id)); - p->num++; - db->update (*p); - t.commit (); - } - - { - transaction t (db->begin ()); - auto_ptr p (db->load (o1.id)); - t.commit (); - - assert (p->num == o1.num + 1); - } - - // Erase. - // - { - transaction t (db->begin ()); - db->erase (o1.id); - t.commit (); - } - - { - transaction t (db->begin ()); - auto_ptr p (db->find (o1.id)); - assert (p.get () == 0); - t.commit (); - } - } - - // Test 2. - // - { - using namespace test2; - - object2 o2 (ncomp (2, 0, 1)); - o2.o1 = new object1 (scomp ("o1", "o2", "aaa")); - - object3 o3 (ncomp (3, 0, 1)); - o3.o1.push_back (new object1 (scomp ("o1", "o3", "aaa"))); - o3.o1.push_back (new object1 (scomp ("o1", "o3", "bbb"))); - - object4 o4 (ncomp (4, 0, 1)); - o4.c.o2 = new object2 (ncomp (2, 4, 1)); - o4.c.o2->o1 = new object1 (scomp ("o1", "o2", "ccc")); - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o2.o1); - db->persist (o2); - db->persist (o3.o1[0]); - db->persist (o3.o1[1]); - db->persist (o3); - db->persist (o4.c.o2->o1); - db->persist (o4.c.o2); - db->persist (o4); - t.commit (); - } - - // Load. - // - { - transaction t (db->begin ()); - auto_ptr p2 (db->load (o2.id)); - auto_ptr p3 (db->load (o3.id)); - auto_ptr p4 (db->load (o4.id)); - t.commit (); - - assert (p2->o1->id == o2.o1->id); - assert (p3->o1.size () == o3.o1.size ()); - assert (p3->o1[0]->id == o3.o1[0]->id); - assert (p3->o1[1]->id == o3.o1[1]->id); - assert (p4->c.o2->id == o4.c.o2->id); - assert (p4->c.o2->o1->id == o4.c.o2->o1->id); - } - - // Update. - // - { - scomp id2, id3; - - { - transaction t (db->begin ()); - - auto_ptr p2 (db->load (o2.id)); - delete p2->o1; - p2->o1 = new object1 (scomp ("o1", "o2", "bbb")); - id2 = db->persist (p2->o1); - db->update (*p2); - - auto_ptr p3 (db->load (o3.id)); - delete p3->o1.back (); - p3->o1.pop_back (); - p3->o1.push_back (new object1 (scomp ("o1", "o3", "ccc"))); - id3 = db->persist (p3->o1.back ()); - db->update (*p3); - - t.commit (); - } - - { - transaction t (db->begin ()); - auto_ptr p2 (db->load (o2.id)); - auto_ptr p3 (db->load (o3.id)); - t.commit (); - - assert (p2->o1->id == id2); - assert (p3->o1.back ()->id == id3); - } - } - - // Query. - // - { - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - { - result r (db->query (query::o1->id.str3 == "bbb")); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->id == o2.id); - assert (++i == r.end ()); - } - - { - // As id (dual interface). - // - result r (db->query (query::o1.str3 == "bbb")); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->id == o2.id); - assert (++i == r.end ()); - } - - t.commit (); - } - - // Second level composite object pointer. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - result r (db->query (query::c.o2->o1.str3 == "ccc")); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->id == o4.id); - assert (++i == r.end ()); - - t.commit (); - } - } - - // View. - // - { - transaction t (db->begin ()); - - { - typedef odb::query query; - typedef odb::result result; - - result r (db->query (query::object2::id.num2 == 0)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num == 1 && i->str == "bbb"); - assert (++i == r.end ()); - } - - { - typedef odb::query query; - typedef odb::result result; - - result r (db->query ((query::object3::id.num2 == 0) + - "ORDER BY" + query::object1::id.str3)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num == 1 && i->str == "aaa"); - assert (++i != r.end ()); - assert (i->num == 1 && i->str == "ccc"); - assert (++i == r.end ()); - } - - { - typedef odb::query query; - typedef odb::result result; - - result r (db->query (query::object4::id.num2 == 0)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num4 == 1 && i->num2 == 1 && i->str == "ccc"); - assert (++i == r.end ()); - } - - t.commit (); - } - } - - // Test 3. - // - { - using namespace test3; - - object2 o2 (ncomp (2, 0, 1)); - o2.o1 = new object1 (scomp ("o1", "o2", "aaa")); - o2.o1->o2 = &o2; - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o2.o1); - db->persist (o2); - t.commit (); - } - - // Load. - // - { - session s; - transaction t (db->begin ()); - auto_ptr p2 (db->load (o2.id)); - t.commit (); - - assert (p2->o1->o2->id == o2.id); - } - - // Query. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - { - session s; - - result r (db->query (query::o2->id.num2 == 0)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->id == o2.o1->id); - - i->o2->o1 = 0; - delete i->o2; - - assert (++i == r.end ()); - } - - t.commit (); - } - - // View. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - result r (db->query (query::object1::id.str2 == "o2")); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num == 1 && i->str == "aaa"); - assert (++i == r.end ()); - - t.commit (); - } - } - - // Test 4. - // - { - using namespace test4; - - object2 o2 (ncomp (2, 0, 1)); - - o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); - o2.o1.back ()->o2 = &o2; - - o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); - o2.o1.back ()->o2 = &o2; - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o2.o1[0]); - db->persist (o2.o1[1]); - db->persist (o2); - t.commit (); - } - - // Load. - // - { - session s; - transaction t (db->begin ()); - auto_ptr p2 (db->load (o2.id)); - t.commit (); - - assert (p2->o1.size () == 2); - assert (p2->o1[0]->o2->id == o2.id); - assert (p2->o1[1]->o2->id == o2.id); - } - - // Query. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - { - session s; - - result r (db->query (query::o2->id.num2 == 0)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->id == o2.o1[0]->id); - i->o2->o1.clear (); - - assert (++i != r.end ()); - assert (i->id == o2.o1[1]->id); - - i->o2->o1.clear (); - delete i->o2; - - assert (++i == r.end ()); - } - - t.commit (); - } - - // View. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - result r (db->query (query::object1::id.str3 == "bbb")); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num == 1 && i->str == "bbb"); - assert (++i == r.end ()); - - t.commit (); - } - } - - // Test 5. - // - { - using namespace test5; - - object2 o2 (ncomp (2, 0, 1)); - - o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); - o2.o1.back ()->o2 = &o2; - - o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); - o2.o1.back ()->o2 = &o2; - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o2.o1[0]); - db->persist (o2.o1[1]); - db->persist (o2); - t.commit (); - } - - // Load. - // - { - session s; - transaction t (db->begin ()); - auto_ptr p2 (db->load (o2.id)); - t.commit (); - - assert (p2->o1.size () == 2); - - assert (p2->o1[0]->id == o2.o1[0]->id); - assert (p2->o1[0]->o2->id == o2.id); - - assert (p2->o1[1]->id == o2.o1[1]->id); - assert (p2->o1[1]->o2->id == o2.id); - } - - // View. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - result r (db->query ((query::object2::id.num2 == 0) + - "ORDER BY" + query::object1::id.str3)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num == 1 && i->str == "aaa"); - assert (++i != r.end ()); - assert (i->num == 1 && i->str == "bbb"); - assert (++i == r.end ()); - - t.commit (); - } - } - - // Test 6. - // - { - using namespace test6; - - object2 o2 (ncomp (2, 0, 1)); - - o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); - o2.o1.back ()->o2.push_back (&o2); - - o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); - o2.o1.back ()->o2.push_back (&o2); - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o2.o1[0]); - db->persist (o2.o1[1]); - db->persist (o2); - t.commit (); - } - - // Load. - // - { - session s; - transaction t (db->begin ()); - auto_ptr p2 (db->load (o2.id)); - t.commit (); - - assert (p2->o1.size () == 2); - - assert (p2->o1[0]->id == o2.o1[0]->id); - assert (p2->o1[0]->o2[0]->id == o2.id); - - assert (p2->o1[1]->id == o2.o1[1]->id); - assert (p2->o1[1]->o2[0]->id == o2.id); - } - - // View. - // - { - typedef odb::query query; - typedef odb::result result; - - transaction t (db->begin ()); - - result r (db->query ((query::object2::id.num2 == 0) + - "ORDER BY" + query::object1::id.str3)); - result::iterator i (r.begin ()); - assert (i != r.end ()); - assert (i->num == 1 && i->str == "aaa"); - assert (++i != r.end ()); - assert (i->num == 1 && i->str == "bbb"); - assert (++i == r.end ()); - - t.commit (); - } - } - - // Test 7. - // - { - using namespace test7; - - object o (scomp ("aaa", "bbb", "ccc"), 123); - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o); - t.commit (); - } - - // Load. - // - { - transaction t (db->begin ()); - auto_ptr p (db->load (o.id)); - t.commit (); - - assert (*p == o); - } - - // Update. - // - { - transaction t (db->begin ()); - auto_ptr p (db->load (o.id)); - p->num++; - db->update (*p); - - try - { - db->update (o); - assert (false); - } - catch (const object_changed&) - { - } - - t.commit (); - } - - { - transaction t (db->begin ()); - auto_ptr p (db->load (o.id)); - t.commit (); - - assert (p->num == o.num + 1); - } - - // Erase. - // - { - transaction t (db->begin ()); - - try - { - db->update (o); - assert (false); - } - catch (const object_changed&) - { - } - - t.commit (); - } - } - - // Test 8. - // - { - using namespace test8; - - object2 o2a, o2b; - object3 o3; - - o2b.o1 = new object1 (scomp ("222", "aaa", "bbb"), 123); - o3.o1.push_back (0); - o3.o1.push_back (new object1 (scomp ("333", "aaa", "bbb"), 234)); - - // Persist. - // - { - transaction t (db->begin ()); - db->persist (o2a); - db->persist (o2b); - db->persist (o2b.o1); - db->persist (o3); - db->persist (o3.o1[1]); - t.commit (); - } - - // Load. - // - { - transaction t (db->begin ()); - auto_ptr p2a (db->load (o2a.id)); - auto_ptr p2b (db->load (o2b.id)); - auto_ptr p3 (db->load (o3.id)); - t.commit (); - - assert (p2a->o1 == 0); - assert (p2b->o1 != 0 && *p2b->o1 == *o2b.o1); - assert (p3->o1[0] == 0); - assert (p3->o1[1] != 0 && *p3->o1[1] == *o3.o1[1]); - } - - // Update. - // - { - object1* o1 (o3.o1[1]); - - o3.o1.clear (); - o3.o1.push_back (o2b.o1); - o3.o1.push_back (0); - - o2a.o1 = o1; - o2b.o1 = 0; - - transaction t (db->begin ()); - db->update (o2a); - db->update (o2b); - db->update (o3); - t.commit (); - } - - { - transaction t (db->begin ()); - auto_ptr p2a (db->load (o2a.id)); - auto_ptr p2b (db->load (o2b.id)); - auto_ptr p3 (db->load (o3.id)); - t.commit (); - - assert (p2a->o1 != 0 && *p2a->o1 == *o2a.o1); - assert (p2b->o1 == 0); - assert (p3->o1[0] != 0 && *p3->o1[0] == *o3.o1[0]); - assert (p3->o1[1] == 0); - } - } - - // Test 9. - { - using namespace test9; - - object o (123, "abc"); - o.v.push_back (123); - - // persist - // - { - transaction t (db->begin ()); - db->persist (o); - t.commit (); - } - - // load & check - // - { - transaction t (db->begin ()); - result r (db->query ()); - result::iterator i (r.begin ()); - assert (i != r.end () && o == *i && ++i == r.end ()); - t.commit (); - } - } - } - catch (const odb::exception& e) - { - cerr << e.what () << endl; - return 1; - } -} diff --git a/common/composite-id/makefile b/common/composite-id/makefile deleted file mode 100644 index 4c8a655..0000000 --- a/common/composite-id/makefile +++ /dev/null @@ -1,118 +0,0 @@ -# file : common/composite-id/makefile -# copyright : Copyright (c) 2009-2015 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 \ ---generate-session --table-prefix t_comp_id_ -$(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 vc8projs,$(name)) \ -$(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)) - -# 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/vc8proj.make) -$(call include,$(bld_root)/meta/vc9proj.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/composite-id/test.hxx b/common/composite-id/test.hxx deleted file mode 100644 index 427a162..0000000 --- a/common/composite-id/test.hxx +++ /dev/null @@ -1,520 +0,0 @@ -// file : common/composite-id/test.hxx -// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#ifndef TEST_HXX -#define TEST_HXX - -#include -#include - -#include - -#pragma db value -struct scomp -{ - scomp () {} - scomp (const std::string& s1, const std::string& s2, const std::string& s3) - : str1 (s1), str2 (s2), str3 (s3) - { - } - - std::string str1; - std::string str2; - std::string str3; -}; - -inline bool -operator== (const scomp& x, const scomp& y) -{ - return x.str1 == y.str1 && x.str2 == y.str2 && x.str3 == y.str3; -} - -inline bool -operator< (const scomp& x, const scomp& y) -{ - return x.str1 < y.str1 || - (x.str1 == y.str1 && x.str2 < y.str2) || - (x.str1 == y.str1 && x.str2 == y.str2 && x.str3 < y.str3); -} - -#pragma db value -struct ncomp -{ - ncomp () {} - ncomp (unsigned short n1, unsigned short n2, unsigned short n3) - : num1 (n1), num2 (n2), num3 (n3) - { - } - - unsigned short num1; - unsigned short num2; - unsigned short num3; -}; - -inline bool -operator== (const ncomp& x, const ncomp& y) -{ - return x.num1 == y.num1 && x.num2 == y.num2 && x.num3 == y.num3; -} - -inline bool -operator< (const ncomp& x, const ncomp& y) -{ - return x.num1 < y.num1 || - (x.num1 == y.num1 && x.num2 < y.num2) || - (x.num1 == y.num1 && x.num2 == y.num2 && x.num3 < y.num3); -} - -// Test object with composite id, container. -// -#pragma db namespace table("t1_") -namespace test1 -{ - #pragma db object - struct object - { - object () {} - object (const scomp& i, unsigned long n): id (i), num (n) {} - - #pragma db id - scomp id; - - unsigned long num; - std::vector vec; - }; - - inline bool - operator== (const object& x, const object& y) - { - return x.id == y.id && x.num == y.num && x.vec == y.vec; - } -} - -// Test to-one and to-many relationships with composite id as well as -// queries and views. -// -#pragma db namespace table("t2_") -namespace test2 -{ - #pragma db object - struct object1 - { - object1 () {} - object1 (const scomp& i): id (i) {} - - #pragma db id - scomp id; - }; - - #pragma db object - struct object2 - { - object2 (): o1 (0) {} - object2 (const ncomp& i): id (i), o1 (0) {} - ~object2 () {delete o1;} - - #pragma db id - ncomp id; - - object1* o1; - }; - - #pragma db object - struct object3 - { - object3 () {} - object3 (const ncomp& i): id (i) {} - - ~object3 () - { - for (std::vector::iterator i (o1.begin ()); - i != o1.end (); ++i) - delete *i; - } - - #pragma db id - ncomp id; - - std::vector o1; - }; - - // Test second-level query pointer test as well as pointers in - // composite types. - // - #pragma db value - struct comp - { - comp (): o2 (0) {} - ~comp () {delete o2;} - - object2* o2; - }; - - #pragma db object - struct object4 - { - object4 () {} - object4 (const ncomp& i): id (i) {} - - #pragma db id - ncomp id; - - comp c; - }; - - #pragma db view object(object2) object(object1) - struct view2 - { - #pragma db column (object2::id.num3) - unsigned short num; - - #pragma db column (object1::id.str3) - std::string str; - }; - - #pragma db view object(object3) object(object1) - struct view3 - { - #pragma db column (object3::id.num3) - unsigned short num; - - #pragma db column (object1::id.str3) - std::string str; - }; - - #pragma db view object(object4) object(object2) object(object1) - struct view4 - { - #pragma db column (object4::id.num3) - unsigned short num4; - - #pragma db column (object2::id.num3) - unsigned short num2; - - #pragma db column (object1::id.str3) - std::string str; - }; -} - -// Test one-to-one(i) relationship with composite id. -// -#pragma db namespace table("t3_") -namespace test3 -{ - struct object2; - - #pragma db object - struct object1 - { - object1 () {} - object1 (const scomp& i): id (i) {} - - #pragma db id - scomp id; - - #pragma db inverse(o1) - object2* o2; - }; - - #pragma db object - struct object2 - { - object2 (): o1 (0) {} - object2 (const ncomp& i): id (i), o1 (0) {} - ~object2 () {delete o1;} - - #pragma db id - ncomp id; - - object1* o1; - }; - - #pragma db view object(object2) object(object1) - struct view - { - #pragma db column (object2::id.num3) - unsigned short num; - - #pragma db column (object1::id.str3) - std::string str; - }; -} - -// Test many-to-one(i) relationship with composite id. -// -#pragma db namespace table("t4_") -namespace test4 -{ - struct object2; - - #pragma db object - struct object1 - { - object1 () {} - object1 (const scomp& i): id (i) {} - - #pragma db id - scomp id; - - #pragma db inverse(o1) - object2* o2; - }; - - #pragma db object - struct object2 - { - object2 () {} - object2 (const ncomp& i): id (i) {} - - ~object2 () - { - for (std::vector::iterator i (o1.begin ()); - i != o1.end (); ++i) - delete *i; - } - - #pragma db id - ncomp id; - - std::vector o1; - }; - - #pragma db view object(object2) object(object1) - struct view - { - #pragma db column (object2::id.num3) - unsigned short num; - - #pragma db column (object1::id.str3) - std::string str; - }; -} - -// Test one-to-many(i) relationship with composite id. -// -#pragma db namespace table("t5_") -namespace test5 -{ - struct object2; - - #pragma db object - struct object1 - { - object1 () {} - object1 (const scomp& i): id (i) {} - - #pragma db id - scomp id; - - object2* o2; - }; - - #pragma db object - struct object2 - { - object2 () {} - object2 (const ncomp& i): id (i) {} - - ~object2 () - { - for (std::vector::iterator i (o1.begin ()); - i != o1.end (); ++i) - delete *i; - } - - #pragma db id - ncomp id; - - #pragma db inverse(o2) - std::vector o1; - }; - - #pragma db view object(object2) object(object1) - struct view - { - #pragma db column (object2::id.num3) - unsigned short num; - - #pragma db column (object1::id.str3) - std::string str; - }; -} - -// Test many-to-many(i) relationship with composite id. -// -#pragma db namespace table("t6_") -namespace test6 -{ - struct object2; - - #pragma db object - struct object1 - { - object1 () {} - object1 (const scomp& i): id (i) {} - - #pragma db id - scomp id; - - std::vector o2; - }; - - #pragma db object - struct object2 - { - object2 () {} - object2 (const ncomp& i): id (i) {} - - ~object2 () - { - for (std::vector::iterator i (o1.begin ()); - i != o1.end (); ++i) - delete *i; - } - - #pragma db id - ncomp id; - - #pragma db inverse(o2) - std::vector o1; - }; - - #pragma db view object(object2) object(object1) - struct view - { - #pragma db column (object2::id.num3) - unsigned short num; - - #pragma db column (object1::id.str3) - std::string str; - }; -} - -// Test object with composite id and version (optimistic concurrency). -// -#pragma db namespace table("t7_") -namespace test7 -{ - #pragma db object optimistic - struct object - { - object () {} - object (const scomp& i, unsigned long n): id (i), num (n) {} - - #pragma db id - scomp id; - - #pragma db version - unsigned long ver; - - unsigned long num; - }; - - inline bool - operator== (const object& x, const object& y) - { - return x.id == y.id && x.ver == y.ver && x.num == y.num; - } -} - -// Test composite NULL pointers. -// -#pragma db namespace table("t8_") -namespace test8 -{ - #pragma db object - struct object1 - { - object1 () {} - object1 (const scomp& i, unsigned long n): id (i), num (n) {} - - #pragma db id - scomp id; - - unsigned long num; - }; - - inline bool - operator== (const object1& x, const object1& y) - { - return x.id == y.id && x.num == y.num; - } - - #pragma db object - struct object2 - { - object2 (): o1 (0) {} - ~object2 () {delete o1;} - - #pragma db id auto - unsigned long id; - - object1* o1; - }; - - #pragma db object - struct object3 - { - ~object3 () - { - for (std::vector::iterator i (o1.begin ()); - i != o1.end (); ++i) - delete *i; - } - - #pragma db id auto - unsigned long id; - - std::vector o1; - }; -} - -// Test composite id definition inside object. -// -#pragma db namespace table("t9_") -namespace test9 -{ - #pragma db object - struct object - { - object (unsigned long n = 0, const std::string& s = "") - { - id_.num = n; - id_.str = s; - } - - unsigned long num () const {return id_.num;} - const std::string& str () const {return id_.str;} - - std::vector v; - - private: - friend class odb::access; - - #pragma db value - struct comp - { - unsigned long num; - std::string str; - - bool - operator< (const comp& x) const - { - return num < x.num || (num == x.num && str < x.str); - } - }; - - #pragma db id - comp id_; - }; - - inline bool - operator== (const object& x, const object& y) - { - return x.num () == y.num () && x.str () == y.str () && x.v == y.v; - } -} - - -#endif // TEST_HXX diff --git a/common/composite-id/test.std b/common/composite-id/test.std deleted file mode 100644 index e69de29..0000000 diff --git a/common/id/auto/driver.cxx b/common/id/auto/driver.cxx new file mode 100644 index 0000000..76ed756 --- /dev/null +++ b/common/id/auto/driver.cxx @@ -0,0 +1,95 @@ +// file : common/id/auto/driver.cxx +// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +// Test automatic id assignment. +// + +#include // std::auto_ptr +#include +#include + +#include +#include + +#include + +#include "test.hxx" +#include "test-odb.hxx" + +using namespace std; +using namespace odb::core; + +int +main (int argc, char* argv[]) +{ + try + { + auto_ptr db (create_database (argc, argv)); + + // object + // + { + unsigned long id1, id2, id3; + { + object o1 ("one"); + object o2 ("two"); + object o3 ("three"); + + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o3); + t.commit (); + + id1 = o1.id_; + id2 = o2.id_; + id3 = o3.id_; + + assert (id1 != id2); + assert (id1 != id3); + assert (id2 != id3); + } + + { + transaction t (db->begin ()); + auto_ptr o1 (db->load (id1)); + auto_ptr o2 (db->load (id2)); + auto_ptr o3 (db->load (id3)); + t.commit (); + + assert (o1->id_ == id1 && o1->str_ == "one"); + assert (o2->id_ == id2 && o2->str_ == "two"); + assert (o3->id_ == id3 && o3->str_ == "three"); + } + } + + // auto_only + // + { + unsigned short id; + { + auto_only o; + + transaction t (db->begin ()); + db->persist (o); + t.commit (); + + id = o.id_; + } + + { + transaction t (db->begin ()); + auto_ptr o (db->load (id)); + t.commit (); + + assert (o->id_ == id); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/common/id/auto/makefile b/common/id/auto/makefile new file mode 100644 index 0000000..760719a --- /dev/null +++ b/common/id/auto/makefile @@ -0,0 +1,118 @@ +# file : common/id/auto/makefile +# copyright : Copyright (c) 2009-2015 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 \ +--table-prefix t_id_auto_ +$(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 vc8projs,$(name)) \ +$(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)) + +# 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/vc8proj.make) +$(call include,$(bld_root)/meta/vc9proj.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/id/auto/test.hxx b/common/id/auto/test.hxx new file mode 100644 index 0000000..1605cfe --- /dev/null +++ b/common/id/auto/test.hxx @@ -0,0 +1,41 @@ +// file : common/id/auto/test.hxx +// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include + +#include + +#pragma db object +struct object +{ + object (const std::string& str) + : id_ (1), str_ (str) + { + } + + #pragma db auto id + unsigned long id_; + std::string str_; + +private: + object () + { + } + + friend class odb::access; +}; + +// Test the case where the object has just the auto id. +// +#pragma db object +struct auto_only +{ + #pragma db auto id pgsql:type("BIGINT") + unsigned short id_; +}; + +#endif // TEST_HXX diff --git a/common/id/auto/test.std b/common/id/auto/test.std new file mode 100644 index 0000000..e69de29 diff --git a/common/id/composite/driver.cxx b/common/id/composite/driver.cxx new file mode 100644 index 0000000..0df4c98 --- /dev/null +++ b/common/id/composite/driver.cxx @@ -0,0 +1,730 @@ +// file : common/id/composite/driver.cxx +// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +// Test composite object ids. +// + +#include // std::auto_ptr +#include +#include + +#include +#include +#include + +#include + +#include "test.hxx" +#include "test-odb.hxx" + +using namespace std; +using namespace odb::core; + +int +main (int argc, char* argv[]) +{ + try + { + auto_ptr db (create_database (argc, argv)); + + // Test 1. + // + { + using namespace test1; + + object o1 (scomp ("aaa", "bbb", "ccc"), 123); + o1.vec.push_back (scomp ("xxx", "xxx", "xxx")); + o1.vec.push_back (scomp ("yyy", "yyy", "yyy")); + + object o2 (scomp ("aaa", "bbb", "ccd"), 234); + o2.vec.push_back (scomp ("zzz", "", "zzz")); + + object o3 (scomp ("baa", "bbb", "ccc"), 345); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o3); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id)); + auto_ptr p2 (db->load (o2.id)); + auto_ptr p3 (db->load (o3.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + assert (*p3 == o3); + } + + // Update. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (o1.id)); + p->num++; + db->update (*p); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->load (o1.id)); + t.commit (); + + assert (p->num == o1.num + 1); + } + + // Erase. + // + { + transaction t (db->begin ()); + db->erase (o1.id); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->find (o1.id)); + assert (p.get () == 0); + t.commit (); + } + } + + // Test 2. + // + { + using namespace test2; + + object2 o2 (ncomp (2, 0, 1)); + o2.o1 = new object1 (scomp ("o1", "o2", "aaa")); + + object3 o3 (ncomp (3, 0, 1)); + o3.o1.push_back (new object1 (scomp ("o1", "o3", "aaa"))); + o3.o1.push_back (new object1 (scomp ("o1", "o3", "bbb"))); + + object4 o4 (ncomp (4, 0, 1)); + o4.c.o2 = new object2 (ncomp (2, 4, 1)); + o4.c.o2->o1 = new object1 (scomp ("o1", "o2", "ccc")); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o2.o1); + db->persist (o2); + db->persist (o3.o1[0]); + db->persist (o3.o1[1]); + db->persist (o3); + db->persist (o4.c.o2->o1); + db->persist (o4.c.o2); + db->persist (o4); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + auto_ptr p2 (db->load (o2.id)); + auto_ptr p3 (db->load (o3.id)); + auto_ptr p4 (db->load (o4.id)); + t.commit (); + + assert (p2->o1->id == o2.o1->id); + assert (p3->o1.size () == o3.o1.size ()); + assert (p3->o1[0]->id == o3.o1[0]->id); + assert (p3->o1[1]->id == o3.o1[1]->id); + assert (p4->c.o2->id == o4.c.o2->id); + assert (p4->c.o2->o1->id == o4.c.o2->o1->id); + } + + // Update. + // + { + scomp id2, id3; + + { + transaction t (db->begin ()); + + auto_ptr p2 (db->load (o2.id)); + delete p2->o1; + p2->o1 = new object1 (scomp ("o1", "o2", "bbb")); + id2 = db->persist (p2->o1); + db->update (*p2); + + auto_ptr p3 (db->load (o3.id)); + delete p3->o1.back (); + p3->o1.pop_back (); + p3->o1.push_back (new object1 (scomp ("o1", "o3", "ccc"))); + id3 = db->persist (p3->o1.back ()); + db->update (*p3); + + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p2 (db->load (o2.id)); + auto_ptr p3 (db->load (o3.id)); + t.commit (); + + assert (p2->o1->id == id2); + assert (p3->o1.back ()->id == id3); + } + } + + // Query. + // + { + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + { + result r (db->query (query::o1->id.str3 == "bbb")); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->id == o2.id); + assert (++i == r.end ()); + } + + { + // As id (dual interface). + // + result r (db->query (query::o1.str3 == "bbb")); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->id == o2.id); + assert (++i == r.end ()); + } + + t.commit (); + } + + // Second level composite object pointer. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + result r (db->query (query::c.o2->o1.str3 == "ccc")); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->id == o4.id); + assert (++i == r.end ()); + + t.commit (); + } + } + + // View. + // + { + transaction t (db->begin ()); + + { + typedef odb::query query; + typedef odb::result result; + + result r (db->query (query::object2::id.num2 == 0)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num == 1 && i->str == "bbb"); + assert (++i == r.end ()); + } + + { + typedef odb::query query; + typedef odb::result result; + + result r (db->query ((query::object3::id.num2 == 0) + + "ORDER BY" + query::object1::id.str3)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num == 1 && i->str == "aaa"); + assert (++i != r.end ()); + assert (i->num == 1 && i->str == "ccc"); + assert (++i == r.end ()); + } + + { + typedef odb::query query; + typedef odb::result result; + + result r (db->query (query::object4::id.num2 == 0)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num4 == 1 && i->num2 == 1 && i->str == "ccc"); + assert (++i == r.end ()); + } + + t.commit (); + } + } + + // Test 3. + // + { + using namespace test3; + + object2 o2 (ncomp (2, 0, 1)); + o2.o1 = new object1 (scomp ("o1", "o2", "aaa")); + o2.o1->o2 = &o2; + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o2.o1); + db->persist (o2); + t.commit (); + } + + // Load. + // + { + session s; + transaction t (db->begin ()); + auto_ptr p2 (db->load (o2.id)); + t.commit (); + + assert (p2->o1->o2->id == o2.id); + } + + // Query. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + { + session s; + + result r (db->query (query::o2->id.num2 == 0)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->id == o2.o1->id); + + i->o2->o1 = 0; + delete i->o2; + + assert (++i == r.end ()); + } + + t.commit (); + } + + // View. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + result r (db->query (query::object1::id.str2 == "o2")); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num == 1 && i->str == "aaa"); + assert (++i == r.end ()); + + t.commit (); + } + } + + // Test 4. + // + { + using namespace test4; + + object2 o2 (ncomp (2, 0, 1)); + + o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); + o2.o1.back ()->o2 = &o2; + + o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); + o2.o1.back ()->o2 = &o2; + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o2.o1[0]); + db->persist (o2.o1[1]); + db->persist (o2); + t.commit (); + } + + // Load. + // + { + session s; + transaction t (db->begin ()); + auto_ptr p2 (db->load (o2.id)); + t.commit (); + + assert (p2->o1.size () == 2); + assert (p2->o1[0]->o2->id == o2.id); + assert (p2->o1[1]->o2->id == o2.id); + } + + // Query. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + { + session s; + + result r (db->query (query::o2->id.num2 == 0)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->id == o2.o1[0]->id); + i->o2->o1.clear (); + + assert (++i != r.end ()); + assert (i->id == o2.o1[1]->id); + + i->o2->o1.clear (); + delete i->o2; + + assert (++i == r.end ()); + } + + t.commit (); + } + + // View. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + result r (db->query (query::object1::id.str3 == "bbb")); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num == 1 && i->str == "bbb"); + assert (++i == r.end ()); + + t.commit (); + } + } + + // Test 5. + // + { + using namespace test5; + + object2 o2 (ncomp (2, 0, 1)); + + o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); + o2.o1.back ()->o2 = &o2; + + o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); + o2.o1.back ()->o2 = &o2; + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o2.o1[0]); + db->persist (o2.o1[1]); + db->persist (o2); + t.commit (); + } + + // Load. + // + { + session s; + transaction t (db->begin ()); + auto_ptr p2 (db->load (o2.id)); + t.commit (); + + assert (p2->o1.size () == 2); + + assert (p2->o1[0]->id == o2.o1[0]->id); + assert (p2->o1[0]->o2->id == o2.id); + + assert (p2->o1[1]->id == o2.o1[1]->id); + assert (p2->o1[1]->o2->id == o2.id); + } + + // View. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + result r (db->query ((query::object2::id.num2 == 0) + + "ORDER BY" + query::object1::id.str3)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num == 1 && i->str == "aaa"); + assert (++i != r.end ()); + assert (i->num == 1 && i->str == "bbb"); + assert (++i == r.end ()); + + t.commit (); + } + } + + // Test 6. + // + { + using namespace test6; + + object2 o2 (ncomp (2, 0, 1)); + + o2.o1.push_back (new object1 (scomp ("o1", "o2", "aaa"))); + o2.o1.back ()->o2.push_back (&o2); + + o2.o1.push_back (new object1 (scomp ("o1", "o2", "bbb"))); + o2.o1.back ()->o2.push_back (&o2); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o2.o1[0]); + db->persist (o2.o1[1]); + db->persist (o2); + t.commit (); + } + + // Load. + // + { + session s; + transaction t (db->begin ()); + auto_ptr p2 (db->load (o2.id)); + t.commit (); + + assert (p2->o1.size () == 2); + + assert (p2->o1[0]->id == o2.o1[0]->id); + assert (p2->o1[0]->o2[0]->id == o2.id); + + assert (p2->o1[1]->id == o2.o1[1]->id); + assert (p2->o1[1]->o2[0]->id == o2.id); + } + + // View. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + + result r (db->query ((query::object2::id.num2 == 0) + + "ORDER BY" + query::object1::id.str3)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (i->num == 1 && i->str == "aaa"); + assert (++i != r.end ()); + assert (i->num == 1 && i->str == "bbb"); + assert (++i == r.end ()); + + t.commit (); + } + } + + // Test 7. + // + { + using namespace test7; + + object o (scomp ("aaa", "bbb", "ccc"), 123); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id)); + t.commit (); + + assert (*p == o); + } + + // Update. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id)); + p->num++; + db->update (*p); + + try + { + db->update (o); + assert (false); + } + catch (const object_changed&) + { + } + + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id)); + t.commit (); + + assert (p->num == o.num + 1); + } + + // Erase. + // + { + transaction t (db->begin ()); + + try + { + db->update (o); + assert (false); + } + catch (const object_changed&) + { + } + + t.commit (); + } + } + + // Test 8. + // + { + using namespace test8; + + object2 o2a, o2b; + object3 o3; + + o2b.o1 = new object1 (scomp ("222", "aaa", "bbb"), 123); + o3.o1.push_back (0); + o3.o1.push_back (new object1 (scomp ("333", "aaa", "bbb"), 234)); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o2a); + db->persist (o2b); + db->persist (o2b.o1); + db->persist (o3); + db->persist (o3.o1[1]); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + auto_ptr p2a (db->load (o2a.id)); + auto_ptr p2b (db->load (o2b.id)); + auto_ptr p3 (db->load (o3.id)); + t.commit (); + + assert (p2a->o1 == 0); + assert (p2b->o1 != 0 && *p2b->o1 == *o2b.o1); + assert (p3->o1[0] == 0); + assert (p3->o1[1] != 0 && *p3->o1[1] == *o3.o1[1]); + } + + // Update. + // + { + object1* o1 (o3.o1[1]); + + o3.o1.clear (); + o3.o1.push_back (o2b.o1); + o3.o1.push_back (0); + + o2a.o1 = o1; + o2b.o1 = 0; + + transaction t (db->begin ()); + db->update (o2a); + db->update (o2b); + db->update (o3); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p2a (db->load (o2a.id)); + auto_ptr p2b (db->load (o2b.id)); + auto_ptr p3 (db->load (o3.id)); + t.commit (); + + assert (p2a->o1 != 0 && *p2a->o1 == *o2a.o1); + assert (p2b->o1 == 0); + assert (p3->o1[0] != 0 && *p3->o1[0] == *o3.o1[0]); + assert (p3->o1[1] == 0); + } + } + + // Test 9. + { + using namespace test9; + + object o (123, "abc"); + o.v.push_back (123); + + // persist + // + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + // load & check + // + { + transaction t (db->begin ()); + result r (db->query ()); + result::iterator i (r.begin ()); + assert (i != r.end () && o == *i && ++i == r.end ()); + t.commit (); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/common/id/composite/makefile b/common/id/composite/makefile new file mode 100644 index 0000000..4f0f44e --- /dev/null +++ b/common/id/composite/makefile @@ -0,0 +1,118 @@ +# file : common/id/composite/makefile +# copyright : Copyright (c) 2009-2015 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 \ +--generate-session --table-prefix t_id_comp_ +$(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 vc8projs,$(name)) \ +$(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)) + +# 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/vc8proj.make) +$(call include,$(bld_root)/meta/vc9proj.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/id/composite/test.hxx b/common/id/composite/test.hxx new file mode 100644 index 0000000..e7a0424 --- /dev/null +++ b/common/id/composite/test.hxx @@ -0,0 +1,520 @@ +// file : common/id/composite/test.hxx +// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include +#include + +#include + +#pragma db value +struct scomp +{ + scomp () {} + scomp (const std::string& s1, const std::string& s2, const std::string& s3) + : str1 (s1), str2 (s2), str3 (s3) + { + } + + std::string str1; + std::string str2; + std::string str3; +}; + +inline bool +operator== (const scomp& x, const scomp& y) +{ + return x.str1 == y.str1 && x.str2 == y.str2 && x.str3 == y.str3; +} + +inline bool +operator< (const scomp& x, const scomp& y) +{ + return x.str1 < y.str1 || + (x.str1 == y.str1 && x.str2 < y.str2) || + (x.str1 == y.str1 && x.str2 == y.str2 && x.str3 < y.str3); +} + +#pragma db value +struct ncomp +{ + ncomp () {} + ncomp (unsigned short n1, unsigned short n2, unsigned short n3) + : num1 (n1), num2 (n2), num3 (n3) + { + } + + unsigned short num1; + unsigned short num2; + unsigned short num3; +}; + +inline bool +operator== (const ncomp& x, const ncomp& y) +{ + return x.num1 == y.num1 && x.num2 == y.num2 && x.num3 == y.num3; +} + +inline bool +operator< (const ncomp& x, const ncomp& y) +{ + return x.num1 < y.num1 || + (x.num1 == y.num1 && x.num2 < y.num2) || + (x.num1 == y.num1 && x.num2 == y.num2 && x.num3 < y.num3); +} + +// Test object with composite id, container. +// +#pragma db namespace table("t1_") +namespace test1 +{ + #pragma db object + struct object + { + object () {} + object (const scomp& i, unsigned long n): id (i), num (n) {} + + #pragma db id + scomp id; + + unsigned long num; + std::vector vec; + }; + + inline bool + operator== (const object& x, const object& y) + { + return x.id == y.id && x.num == y.num && x.vec == y.vec; + } +} + +// Test to-one and to-many relationships with composite id as well as +// queries and views. +// +#pragma db namespace table("t2_") +namespace test2 +{ + #pragma db object + struct object1 + { + object1 () {} + object1 (const scomp& i): id (i) {} + + #pragma db id + scomp id; + }; + + #pragma db object + struct object2 + { + object2 (): o1 (0) {} + object2 (const ncomp& i): id (i), o1 (0) {} + ~object2 () {delete o1;} + + #pragma db id + ncomp id; + + object1* o1; + }; + + #pragma db object + struct object3 + { + object3 () {} + object3 (const ncomp& i): id (i) {} + + ~object3 () + { + for (std::vector::iterator i (o1.begin ()); + i != o1.end (); ++i) + delete *i; + } + + #pragma db id + ncomp id; + + std::vector o1; + }; + + // Test second-level query pointer test as well as pointers in + // composite types. + // + #pragma db value + struct comp + { + comp (): o2 (0) {} + ~comp () {delete o2;} + + object2* o2; + }; + + #pragma db object + struct object4 + { + object4 () {} + object4 (const ncomp& i): id (i) {} + + #pragma db id + ncomp id; + + comp c; + }; + + #pragma db view object(object2) object(object1) + struct view2 + { + #pragma db column (object2::id.num3) + unsigned short num; + + #pragma db column (object1::id.str3) + std::string str; + }; + + #pragma db view object(object3) object(object1) + struct view3 + { + #pragma db column (object3::id.num3) + unsigned short num; + + #pragma db column (object1::id.str3) + std::string str; + }; + + #pragma db view object(object4) object(object2) object(object1) + struct view4 + { + #pragma db column (object4::id.num3) + unsigned short num4; + + #pragma db column (object2::id.num3) + unsigned short num2; + + #pragma db column (object1::id.str3) + std::string str; + }; +} + +// Test one-to-one(i) relationship with composite id. +// +#pragma db namespace table("t3_") +namespace test3 +{ + struct object2; + + #pragma db object + struct object1 + { + object1 () {} + object1 (const scomp& i): id (i) {} + + #pragma db id + scomp id; + + #pragma db inverse(o1) + object2* o2; + }; + + #pragma db object + struct object2 + { + object2 (): o1 (0) {} + object2 (const ncomp& i): id (i), o1 (0) {} + ~object2 () {delete o1;} + + #pragma db id + ncomp id; + + object1* o1; + }; + + #pragma db view object(object2) object(object1) + struct view + { + #pragma db column (object2::id.num3) + unsigned short num; + + #pragma db column (object1::id.str3) + std::string str; + }; +} + +// Test many-to-one(i) relationship with composite id. +// +#pragma db namespace table("t4_") +namespace test4 +{ + struct object2; + + #pragma db object + struct object1 + { + object1 () {} + object1 (const scomp& i): id (i) {} + + #pragma db id + scomp id; + + #pragma db inverse(o1) + object2* o2; + }; + + #pragma db object + struct object2 + { + object2 () {} + object2 (const ncomp& i): id (i) {} + + ~object2 () + { + for (std::vector::iterator i (o1.begin ()); + i != o1.end (); ++i) + delete *i; + } + + #pragma db id + ncomp id; + + std::vector o1; + }; + + #pragma db view object(object2) object(object1) + struct view + { + #pragma db column (object2::id.num3) + unsigned short num; + + #pragma db column (object1::id.str3) + std::string str; + }; +} + +// Test one-to-many(i) relationship with composite id. +// +#pragma db namespace table("t5_") +namespace test5 +{ + struct object2; + + #pragma db object + struct object1 + { + object1 () {} + object1 (const scomp& i): id (i) {} + + #pragma db id + scomp id; + + object2* o2; + }; + + #pragma db object + struct object2 + { + object2 () {} + object2 (const ncomp& i): id (i) {} + + ~object2 () + { + for (std::vector::iterator i (o1.begin ()); + i != o1.end (); ++i) + delete *i; + } + + #pragma db id + ncomp id; + + #pragma db inverse(o2) + std::vector o1; + }; + + #pragma db view object(object2) object(object1) + struct view + { + #pragma db column (object2::id.num3) + unsigned short num; + + #pragma db column (object1::id.str3) + std::string str; + }; +} + +// Test many-to-many(i) relationship with composite id. +// +#pragma db namespace table("t6_") +namespace test6 +{ + struct object2; + + #pragma db object + struct object1 + { + object1 () {} + object1 (const scomp& i): id (i) {} + + #pragma db id + scomp id; + + std::vector o2; + }; + + #pragma db object + struct object2 + { + object2 () {} + object2 (const ncomp& i): id (i) {} + + ~object2 () + { + for (std::vector::iterator i (o1.begin ()); + i != o1.end (); ++i) + delete *i; + } + + #pragma db id + ncomp id; + + #pragma db inverse(o2) + std::vector o1; + }; + + #pragma db view object(object2) object(object1) + struct view + { + #pragma db column (object2::id.num3) + unsigned short num; + + #pragma db column (object1::id.str3) + std::string str; + }; +} + +// Test object with composite id and version (optimistic concurrency). +// +#pragma db namespace table("t7_") +namespace test7 +{ + #pragma db object optimistic + struct object + { + object () {} + object (const scomp& i, unsigned long n): id (i), num (n) {} + + #pragma db id + scomp id; + + #pragma db version + unsigned long ver; + + unsigned long num; + }; + + inline bool + operator== (const object& x, const object& y) + { + return x.id == y.id && x.ver == y.ver && x.num == y.num; + } +} + +// Test composite NULL pointers. +// +#pragma db namespace table("t8_") +namespace test8 +{ + #pragma db object + struct object1 + { + object1 () {} + object1 (const scomp& i, unsigned long n): id (i), num (n) {} + + #pragma db id + scomp id; + + unsigned long num; + }; + + inline bool + operator== (const object1& x, const object1& y) + { + return x.id == y.id && x.num == y.num; + } + + #pragma db object + struct object2 + { + object2 (): o1 (0) {} + ~object2 () {delete o1;} + + #pragma db id auto + unsigned long id; + + object1* o1; + }; + + #pragma db object + struct object3 + { + ~object3 () + { + for (std::vector::iterator i (o1.begin ()); + i != o1.end (); ++i) + delete *i; + } + + #pragma db id auto + unsigned long id; + + std::vector o1; + }; +} + +// Test composite id definition inside object. +// +#pragma db namespace table("t9_") +namespace test9 +{ + #pragma db object + struct object + { + object (unsigned long n = 0, const std::string& s = "") + { + id_.num = n; + id_.str = s; + } + + unsigned long num () const {return id_.num;} + const std::string& str () const {return id_.str;} + + std::vector v; + + private: + friend class odb::access; + + #pragma db value + struct comp + { + unsigned long num; + std::string str; + + bool + operator< (const comp& x) const + { + return num < x.num || (num == x.num && str < x.str); + } + }; + + #pragma db id + comp id_; + }; + + inline bool + operator== (const object& x, const object& y) + { + return x.num () == y.num () && x.str () == y.str () && x.v == y.v; + } +} + + +#endif // TEST_HXX diff --git a/common/id/composite/test.std b/common/id/composite/test.std new file mode 100644 index 0000000..e69de29 diff --git a/common/id/nested/driver.cxx b/common/id/nested/driver.cxx new file mode 100644 index 0000000..28dac6a --- /dev/null +++ b/common/id/nested/driver.cxx @@ -0,0 +1,265 @@ +// file : common/id/nested/driver.cxx +// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +// Test nested ids. +// + +#include // std::auto_ptr +#include +#include + +#include +#include +#include + +#include + +#include "test.hxx" +#include "test-odb.hxx" + +using namespace std; +using namespace odb::core; + +struct failed {}; + +int +main (int argc, char* argv[]) +{ + try + { + auto_ptr db (create_database (argc, argv)); + + + // Simple nested id. + // + { + using namespace test1; + + object o1 (1, "a", 3); + o1.v.push_back (123); + + object o2 (4, "b", 6); + o2.v.push_back (234); + + object1 o (new object (10, "abc", 11)); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o.p); + db->persist (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.y)); + auto_ptr p2 (db->load (o2.id.y)); + auto_ptr p (db->load (o.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + assert (*p == o); + } + + o1.z++; + o1.v.pop_back (); + o1.v.push_back (234); + + o2.z--; + o2.v.back ()++; + o2.v.push_back (123); + + delete o.p; + o.p = new object (20, "xyz", 11); + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + db->persist (o.p); + db->update (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.y)); + auto_ptr p2 (db->load (o2.id.y)); + auto_ptr p (db->load (o.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + assert (*p == o); + } + } + + // Composite nested id. + // + { + using namespace test2; + + object o1 (1, 2, "a", 123); + o1.v.push_back (123); + + object o2 (1, 3, "b", 234); + o2.v.push_back (234); + + object1 o (new object (2, 2, "abc", 123)); + o.p->v.push_back (345); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o.p); + db->persist (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.c)); + auto_ptr p2 (db->load (o2.id.c)); + auto_ptr p (db->load (o.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + assert (*p == o); + } + + o1.z++; + o1.v.pop_back (); + o1.v.push_back (234); + + o2.z--; + o2.v.modify_back ()++; + o2.v.push_back (123); + + delete o.p; + o.p = new object (2, 3, "xyz", 234); + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + db->persist (o.p); + db->update (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.c)); + auto_ptr p2 (db->load (o2.id.c)); + auto_ptr p (db->load (o.id)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + assert (*p == o); + } + } + + // Custom/by-value access. + // + { + using namespace test3; + + object o1 (1, "a", 3); + object o2 (4, "b", 6); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.y)); + auto_ptr p2 (db->load (o2.id.y)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + + o1.z++; + o2.z--; + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.y)); + auto_ptr p2 (db->load (o2.id.y)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + + // Polymorphic. + // + { + using namespace test4; + + base o1 (1, "a"); + object o2 (2, "b", 1); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.y)); + auto_ptr p2 (db->load (o2.id.y)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + + o2.z--; + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p1 (db->load (o1.id.y)); + auto_ptr p2 (db->load (o2.id.y)); + t.commit (); + + assert (*p1 == o1); + assert (*p2 == o2); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/common/id/nested/makefile b/common/id/nested/makefile new file mode 100644 index 0000000..c2e5b0e --- /dev/null +++ b/common/id/nested/makefile @@ -0,0 +1,118 @@ +# file : common/id/nested/makefile +# copyright : Copyright (c) 2009-2015 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_id_nested_ +$(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 vc8projs,$(name)) \ +$(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)) + +# 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/vc8proj.make) +$(call include,$(bld_root)/meta/vc9proj.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/id/nested/test.hxx b/common/id/nested/test.hxx new file mode 100644 index 0000000..6449fd4 --- /dev/null +++ b/common/id/nested/test.hxx @@ -0,0 +1,218 @@ +// file : common/id/nested/test.hxx +// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include +#include + +#include +#include + +// Simple nested id. +// +#pragma db namespace table("t1_") +namespace test1 +{ + #pragma db value + struct comp + { + int x; + std::string y; + }; + + #pragma db object + struct object + { + #pragma db id(y) + comp id; + + int z; + std::vector v; + + object () {} + object (int x, std::string y, int z_): z (z_) {id.x = x; id.y = y;} + }; + + inline bool + operator== (object a, object b) + { + return a.id.x == b.id.x && a.id.y == b.id.y && a.z == b.z && a.v == b.v; + } + + #pragma db object + struct object1 + { + #pragma db id auto + int id; + + object* p; + + object1 (object* p_ = 0): p (p_) {} + ~object1 () {delete p;} + }; + + inline bool + operator== (const object1& a, const object1& b) + { + return a.id == b.id && *a.p == *b.p; + } +} + +// Composite nested id. +// +#pragma db namespace table("t2_") +namespace test2 +{ + #pragma db value + struct comp1 + { + int x; + int y; + }; + + #pragma db value + struct comp2 + { + comp1 c; + std::string s; + }; + + #pragma db object + struct object + { + #pragma db id(c) + comp2 id; + + int z; + odb::vector v; + + object () {} + object (int x, int y, std::string s, int z_) + : z (z_) {id.c.x = x; id.c.y = y; id.s = s;} + }; + + inline bool + operator== (object a, object b) + { + return a.id.c.x == b.id.c.x && a.id.c.y == b.id.c.y && + a.id.s == b.id.s && a.z == b.z && a.v == b.v; + } + + #pragma db object + struct object1 + { + #pragma db id auto + int id; + + object* p; + + object1 (object* p_ = 0): p (p_) {} + ~object1 () {delete p;} + }; + + inline bool + operator== (const object1& a, const object1& b) + { + return a.id == b.id && *a.p == *b.p; + } + + // Multiple levels of nesting, just a compile test. + // + #pragma db object + struct object2 + { + #pragma db id(c.x) + comp2 id; + + int z; + }; +} + +// Custom/by-value access. +// +#pragma db namespace table("t3_") +namespace test3 +{ + #pragma db value + struct comp + { + int x; + + std::string get_y () const {return y;} + void set_y (std::string v) {y = v;} + + #pragma db get(get_y) set(set_y) + std::string y; + }; + + #pragma db object + struct object + { + comp get_id () const {return id;} + void set_id (comp v) {id = v;} + + #pragma db id(y) get(get_id) set(set_id) + comp id; + + int z; + + object () {} + object (int x, std::string y, int z_): z (z_) {id.x = x; id.y = y;} + }; + + inline bool + operator== (object a, object b) + { + return a.id.x == b.id.x && a.id.y == b.id.y && a.z == b.z; + } +} + +// Polymorphic. +// +#pragma db namespace table("t4_") +namespace test4 +{ + #pragma db value + struct comp + { + int x; + std::string y; + }; + + #pragma db object polymorphic + struct base + { + #pragma db id(y) + comp id; + + virtual ~base () {} + base () {} + base (int x, std::string y) {id.x = x; id.y = y;} + }; + + inline bool + operator== (const base& a, const base& b) + { + return a.id.x == b.id.x && a.id.y == b.id.y; + } + + #pragma db object + struct object: base + { + int z; + + object () {} + object (int x, std::string y, int z_): base (x, y), z (z_) {} + }; + + inline bool + operator== (const object& a, const object& b) + { + return a.id.x == b.id.x && a.id.y == b.id.y && a.z == b.z; + } +} + +#endif // TEST_HXX diff --git a/common/id/nested/test.std b/common/id/nested/test.std new file mode 100644 index 0000000..e69de29 diff --git a/common/makefile b/common/makefile index 1e57ed4..b3b2bac 100644 --- a/common/makefile +++ b/common/makefile @@ -7,7 +7,6 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make tests := \ access \ as \ -auto \ blob \ bulk \ callback \ @@ -15,7 +14,6 @@ changelog \ circular/single \ circular/multiple \ composite \ -composite-id \ const-object \ const-member \ container/basics \ @@ -25,6 +23,9 @@ default \ definition \ enum \ erase-query \ +id/auto \ +id/composite \ +id/nested \ include \ index \ inheritance/polymorphism \ -- cgit v1.1