From da9f37e292c9f490e0c0e9b467114d5df70a9a53 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 15 Aug 2012 11:46:00 +0200 Subject: Add support for member accessors/modifiers New pragmas: get, set, access. New test: common/access. --- common/access/driver.cxx | 228 ++++++++++++++++++++ common/access/makefile | 113 ++++++++++ common/access/test.hxx | 501 +++++++++++++++++++++++++++++++++++++++++++ common/access/test.std | 0 common/makefile | 1 + common/polymorphism/test.hxx | 13 +- 6 files changed, 851 insertions(+), 5 deletions(-) create mode 100644 common/access/driver.cxx create mode 100644 common/access/makefile create mode 100644 common/access/test.hxx create mode 100644 common/access/test.std diff --git a/common/access/driver.cxx b/common/access/driver.cxx new file mode 100644 index 0000000..3e3c96d --- /dev/null +++ b/common/access/driver.cxx @@ -0,0 +1,228 @@ +// file : common/access/driver.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +// Test accessor/modifier expressions. +// + +#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)); + + // Test basic accessor/modifier functionality. + // + { + using namespace test1; + + object o (1, 623, 723); + o.i1 () = 123; + o.i2 (223); + o.i3 () = 323; + o.i4 () = 423; + o.set_i5 (423); + o.s1 ("1bc"); + memcpy (o.b1 (), "123456789012345", 16); + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id ())); + t.commit (); + + assert (o == *p); + } + } + + // Test composite accessor/modifier functionality. + // + { + using namespace test2; + + object o (1); + + o.v1 () = value (1123, 1234); + o.v2 (value (2123, 2234)); + o.v3_i1 (3123); + o.v3_i2 (3223); + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id ())); + t.commit (); + + assert (o == *p); + } + } + + // Test object pointer accessor/modifier functionality. + // + { + using namespace test3; + + object2 o (1); + o.p1 ().reset (new object1 (1)); + o.p2 (object1_ptr (new object1 (2))); + + { + transaction t (db->begin ()); + db->persist (o.p1 ()); + db->persist (o.p2 ()); + db->persist (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id ())); + t.commit (); + + assert (p->p1 ()->id () == o.p1 ()->id () && + p->p2 ()->id () == o.p2 ()->id ()); + } + } + + // Test container accessor/modifier functionality. + // + { + using namespace test4; + + object o (1); + o.c1 ().push_back (1123); + o.c1 ().push_back (1124); + o.c1 ().push_back (1125); + + { + std::vector v; + v.push_back (2123); + v.push_back (2124); + v.push_back (2125); + o.c2 (v); + } + + o.v1 ().c1 ().push_back (1123); + o.v1 ().c1 ().push_back (1124); + o.v1 ().c1 ().push_back (1125); + + { + std::vector v; + v.push_back (2123); + v.push_back (2124); + v.push_back (2125); + o.v1 ().c2 (v); + } + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + { + transaction t (db->begin ()); + auto_ptr p (db->load (o.id ())); + t.commit (); + + assert (o == *p); + } + } + + // Test id accessor/modifier functionality. + // + { + using namespace test5; + + object1 o1; + object2 o2; + object3 o3; + object4 o4; + o4.id (uuid ("\x60\x1D\x17\xF0-\x60\x05-\x47\x23-\x95\x37-" + "\xC1\xF8\x94\x41\x2B\xEC")); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o3); + db->persist (o4); + t.commit (); + } + + { + 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_)); + auto_ptr p4 (db->load (o4.id ())); + t.commit (); + } + } + + // Test version accessor/modifier functionality. + // + { + using namespace test6; + + object1 o1 (1); + object2 o2; + object3 o3 (1); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o3); + t.commit (); + + assert (o1.version () == 1); + assert (o2.version () == 1); + assert (o3.version_ == 1); + } + + { + transaction t (db->begin ()); + db->update (o1); + db->update (o2); + db->update (o3); + t.commit (); + + assert (o1.version () == 2); + assert (o2.version () == 2); + assert (o3.version_ == 2); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/common/access/makefile b/common/access/makefile new file mode 100644 index 0000000..674128d --- /dev/null +++ b/common/access/makefile @@ -0,0 +1,113 @@ +# file : common/access/makefile +# copyright : Copyright (c) 2009-2012 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 +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o) $(odb_hdr:.hxx=-odb.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 + +driver := $(out_base)/driver +dist := $(out_base)/.dist +test := $(out_base)/.test +clean := $(out_base)/.clean + +# 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) + +genf := $(addprefix $(odb_hdr:.hxx=-odb),.hxx .ixx .cxx) $(odb_hdr:.hxx=.sql) +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(odb) +$(gen): odb := $(odb) +$(gen) $(dist): export odb_options += --database $(db_id) --generate-schema \ +--table-prefix access_ +$(gen): cpp_options := -I$(src_base) +$(gen): $(common.l.cpp-options) + +$(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): db_id := @database@ +$(dist): sources := $(cxx_tun) +$(dist): headers := $(odb_hdr) +$(dist): data_dist := test.std +$(dist): export name := $(name) +$(dist): export extra_dist := $(data_dist) $(call vc9projs,$(name)) \ +$(call vc10projs,$(name)) +$(dist): + $(call dist-data,$(sources) $(headers) $(data_dist)) + $(call meta-automake,../template/Makefile.am) + $(call meta-vc9projs,../template/template,$(name)) + $(call meta-vc10projs,../template/template,$(name)) + +# Test. +# +$(test): $(driver) $(src_base)/test.std + $(call schema) + $(call message,test $<,$< --options-file $(dcf_root)/db.options \ +>$(out_base)/test.out) + $(call message,,diff -u $(src_base)/test.std $(out_base)/test.out) + $(call message,,rm -f $(out_base)/test.out) + +# Clean. +# +$(clean): \ + $(driver).o.clean \ + $(addsuffix .cxx.clean,$(cxx_obj)) \ + $(addsuffix .cxx.clean,$(cxx_od)) \ + $(addprefix $(out_base)/,$(odb_hdr:.hxx=-odb.cxx.hxx.clean)) + $(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/vc9proj.make) +$(call include,$(bld_root)/meta/vc10proj.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/access/test.hxx b/common/access/test.hxx new file mode 100644 index 0000000..7964edb --- /dev/null +++ b/common/access/test.hxx @@ -0,0 +1,501 @@ +// file : common/access/test.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include // HAVE_CXX11 + +#include +#include +#include // std::memcpy, std::memcmp, std::memset +#include // std::auto_ptr/std::unique_ptr +#include // std::move + +#include + +#ifdef ODB_COMPILER +# if defined(ODB_DATABASE_MYSQL) +# define BINARY16_TYPE "BINARY(16)" +# elif defined(ODB_DATABASE_SQLITE) +# define BINARY16_TYPE "BLOB" +# elif defined(ODB_DATABASE_PGSQL) +# define BINARY16_TYPE "BYTEA" +# elif defined(ODB_DATABASE_ORACLE) +# define BINARY16_TYPE "RAW(16)" +# elif defined(ODB_DATABASE_MSSQL) +# define BINARY16_TYPE "BINARY(16)" +# else +# error unknown database +# endif +#endif + +// Test basic accessor/modifier functionality. +// +#pragma db namespace table("t1_") +namespace test1 +{ + #pragma db object + struct object + { + object (): i6_ (0), i7_ (0) {} + object (unsigned long id, int i6, int i7): id_ (id), i6_ (i6), i7_ (i7) {} + + public: + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id access(id) + unsigned long id_; + + public: + int i1 () const {return i1_;} + int& i1 () {return i1_;} + private: + #pragma db access(i1) + int i1_; + + public: + int i2 () const {return i2_;} + void i2 (int i2) {i2_ = i2;} + private: + #pragma db access(i2) + int i2_; + + // Prefer reference accessor to modifier. + // + public: + int i3 () const {return i3_;} + int& i3 () {return i3_;} + private: + void i3 (int i3) {i3_ = i3;} + #pragma db access(i3) + int i3_; + + // Prefer reference accessor to modifier (reverse function order). + // + void i4 (int i4) {i4_ = i4;} + public: + int i4 () const {return i4_;} + int& i4 () {return i4_;} + private: + #pragma db access(i4) + int i4_; + + public: + int get_i5 () const {return i5_;} + void set_i5 (int i5) {i5_ = i5;} + private: + #pragma db get(get_i5) set(set_i5) + int i5_; + + // Const member via reference. + // + public: + const int& i6 () const {return i6_;} + private: + #pragma db get(i6) set(const_cast (this.i6 ())) + const int i6_; + + // Const member via modifier. + // + public: + int i7 () const {return i7_;} + void i7 (int i7) const {const_cast (i7_) = i7;} + private: + #pragma db access(i7) + const int i7_; + + public: + const char* s1 () const {return s1_.c_str ();} + void s1 (const char* s1) {s1_ = s1;} + private: + #pragma db get(s1) set(s1((?).c_str ())) + std::string s1_; + + // Array member via ref. + // + public: + const char* b1 () const {return b1_;} + char* b1 () {return b1_;} + private: + #pragma db type(BINARY16_TYPE) access(b1) + char b1_[16]; + + // Array member via modifier. + // + public: + const char* b2 () const {return b2_;} + void b2 (char* b2) {std::memcpy (b2_, b2, sizeof (b2_));} + private: + #pragma db type(BINARY16_TYPE) access(b2) + char b2_[16]; + + public: + bool operator== (const object& o) const + { + return id_ == o.id_ && + i1_ == o.i1_ && + i2_ == o.i2_ && + i3_ == o.i3_ && + i4_ == o.i4_ && + i5_ == o.i5_ && + i6_ == o.i6_ && + i7_ == o.i7_ && + s1_ == o.s1_ && + std::memcmp (b1_, o.b1_, sizeof (b1_)) == 0 && + std::memcmp (b2_, o.b2_, sizeof (b2_)) == 0; + } + }; +} + +// Test composite accessor/modifier functionality. +// +#pragma db namespace table("t2_") +namespace test2 +{ + #pragma db value + struct value + { + value () {} + value (int i1, int i2): i1_ (i1), i2_ (i2) {} + + bool operator== (const value& v) const + { + return i1_ == v.i1_ && i2_ == v.i2_; + } + + public: + int i1 () const {return i1_;} + int& i1 () {return i1_;} + private: + #pragma db access(i1) + int i1_; + + public: + int i2 () const {return i2_;} + void i2 (int i2) {i2_ = i2;} + private: + #pragma db access(i2) + int i2_; + }; + + #pragma db object + struct object + { + object () {} + object (unsigned long id): id_ (id) {} + + bool operator== (const object& o) const + { + return id_ == o.id_ && + v1_ == o.v1_ && + v2_ == o.v2_ && + v3_ == o.v3_; + } + + public: + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id access(id) + unsigned long id_; + + public: + const value& v1 () const {return v1_;} + value& v1 () {return v1_;} + private: + #pragma db access(v1) + value v1_; + + public: + const value& v2 () const {return v2_;} + void v2 (const value& v2) {v2_ = v2;} + private: + #pragma db access(v2) + value v2_; + + public: + int v3_i1 () const {return v3_.i1 ();} + int v3_i2 () const {return v3_.i2 ();} + void v3_i1 (int i1) {v3_.i1 () = i1;} + void v3_i2 (int i2) {v3_.i2 (i2);} + private: + #pragma db get(test2::value (this.v3_i1 (), this.v3_i2 ())) \ + set(this.v3_i1 ((?).i1 ()); this.v3_i2 ((?).i2 ())) + value v3_; + }; +} + +// Test object pointer accessor/modifier functionality. +// +#pragma db namespace table("t3_") +namespace test3 +{ + struct object1; + +#ifdef HAVE_CXX11 + typedef std::unique_ptr object1_ptr; +#else + typedef std::auto_ptr object1_ptr; +#endif + + #pragma db object pointer(object1_ptr) + struct object1 + { + object1 () {} + object1 (unsigned long id): id_ (id) {} + + public: + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id access(id) + unsigned long id_; + }; + + #pragma db object + struct object2 + { + object2 () {} + object2 (unsigned long id): id_ (id) {} + + public: + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id access(id) + unsigned long id_; + + public: + const object1_ptr& p1 () const {return p1_;} + object1_ptr& p1 () {return p1_;} + private: + #pragma db access(p1) + object1_ptr p1_; + + public: + const object1_ptr& p2 () const {return p2_;} + +#ifdef HAVE_CXX11 + void p2 (object1_ptr p2) {p2_ = std::move (p2);} +#else + void p2 (object1_ptr p2) {p2_ = p2;} +#endif + private: +#ifdef HAVE_CXX11 + #pragma db get(p2) set(p2 (std::move (?))) +#else + #pragma db access(p2) +#endif + object1_ptr p2_; + }; +} + +// Test container accessor/modifier functionality. +// +#pragma db namespace table("t4_") +namespace test4 +{ + #pragma db value + struct value + { + value (): c3_ (3, 999) {} + value (int v): c1_ (3, v), c2_ (3, v + 1), c3_ (3, v + 2) {} + + bool operator== (const value& v) const + { + return c1_ == v.c1_ && c2_ == v.c2_ && c3_ == v.c3_; + } + + public: + const std::vector& c1 () const {return c1_;} + std::vector& c1 () {return c1_;} + private: + #pragma db access(c1) + std::vector c1_; + + public: + const std::vector& c2 () const {return c2_;} + void c2 (const std::vector& c2) {c2_ = c2;} + private: + #pragma db access(c2) + std::vector c2_; + + public: + const std::vector c3_; + }; + + #pragma db object + struct object + { + object () {} + object (unsigned long id): id_ (id), c3_ (3, 3123), v2_ (2123) {} + + bool operator== (const object& o) const + { + return id_ == o.id_ && + c1_ == o.c1_ && + c2_ == o.c2_ && + c3_ == o.c3_ && + v1_ == o.v1_ && + v2_ == o.v2_; + } + + public: + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id access(id) + unsigned long id_; + + public: + const std::vector& c1 () const {return c1_;} + std::vector& c1 () {return c1_;} + private: + #pragma db access(c1) + std::vector c1_; + + public: + const std::vector& c2 () const {return c2_;} + void c2 (const std::vector& c2) {c2_ = c2;} + private: + #pragma db access(c2) + std::vector c2_; + + public: + const std::vector& c3 () const {return c3_;} + private: + #pragma db get(c3) set(const_cast&> (this.c3 ())) + const std::vector c3_; + + public: + const value& v1 () const {return v1_;} + value& v1 () {return v1_;} + private: + #pragma db access(v1) + value v1_; + + public: + const value v2_; + }; +} + +// Test id accessor/modifier functionality. +// +#pragma db namespace table("t5_") +namespace test5 +{ + #pragma db object + struct object1 + { + object1 (): id_ (0) {} + + public: + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id auto access(id) + unsigned long id_; + }; + + #pragma db object + struct object2 + { + object2 (): id_ (0) {} + + public: + unsigned long id () const {return id_;} + unsigned long& id () {return id_;} + private: + #pragma db id auto access(id) + unsigned long id_; + }; + + #pragma db object + struct object3 + { + object3 (): id_ (0) {} + + #pragma db id auto + const unsigned long id_; + }; + + #pragma db value + struct uuid + { + uuid () {std::memset (data_, 0, sizeof (data_));} + explicit uuid (const char* d) {data (d);} + + public: + const char* data () const {return data_;} + void data (const char* d) {std::memcpy (data_, d, sizeof (data_));} + private: + #pragma db type(BINARY16_TYPE) column("") access(data) + char data_[16]; + }; + + #pragma db object + struct object4 + { + public: + const uuid& id () const {return id_;} + void id (const uuid& id) {id_ = id;} + private: + #pragma db id access(id) + uuid id_; + }; +} + +// Test version accessor/modifier functionality. +// +#pragma db namespace table("t6_") +namespace test6 +{ + #pragma db object optimistic + struct object1 + { + object1 (unsigned long id = 0): id_ (id), version_ (0) {} + + #pragma db id + unsigned long id_; + + public: + unsigned long version () const {return version_;} + void version (unsigned long version) {version_ = version;} + private: + #pragma db version access(version) + unsigned long version_; + }; + + #pragma db object optimistic + struct object2 + { + object2 (): version_ (0) {} + + #pragma db id auto + unsigned long id_; + + public: + unsigned long version () const {return version_;} + unsigned long& version () {return version_;} + private: + #pragma db version access(version) + unsigned long version_; + }; + + #pragma db object optimistic + struct object3 + { + object3 (unsigned long id = 0): id_ (id), version_ (0) {} + + #pragma db id + unsigned long id_; + + #pragma db version + const unsigned long version_; + }; +} + +#endif // TEST_HXX diff --git a/common/access/test.std b/common/access/test.std new file mode 100644 index 0000000..e69de29 diff --git a/common/makefile b/common/makefile index e1a5f13..9965095 100644 --- a/common/makefile +++ b/common/makefile @@ -5,6 +5,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make tests := \ +access \ auto \ blob \ callback \ diff --git a/common/polymorphism/test.hxx b/common/polymorphism/test.hxx index d0a6ed5..9994fdd 100644 --- a/common/polymorphism/test.hxx +++ b/common/polymorphism/test.hxx @@ -984,7 +984,7 @@ namespace test11 }; } -// Test polymorphic classes with auto id. +// Test polymorphic classes with private auto id. // #pragma db namespace table("t12_") namespace test12 @@ -994,17 +994,20 @@ namespace test12 { virtual ~root () = 0; // Auto-abstract. - #pragma db id auto - unsigned long id; - virtual bool compare (const root& r, bool tc = true) const { if (tc && typeid (r) != typeid (root)) return false; - return id == r.id; + return id_ == r.id_; } + + unsigned long id () const {return id_;} + void id (unsigned long id) {id_ = id;} + private: + #pragma db id auto access(id) + unsigned long id_; }; inline root:: -- cgit v1.1