diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2011-03-01 11:56:33 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-03-01 11:56:33 +0200 |
commit | 5a14aa4978cca949f3d07561ba35f8fd3af76ab2 (patch) | |
tree | 4c5e54ca7daf83130fd06f16db56b517ea254ce6 | |
parent | 2ef165437ce47f50110a9b230f302c5cd5fde1d4 (diff) |
Add support for embedded database schemas
New options: --schema-format, --default-schema. New example: schema/embedded.
-rw-r--r-- | README | 10 | ||||
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | schema/embedded/README | 51 | ||||
-rw-r--r-- | schema/embedded/database.hxx | 46 | ||||
-rw-r--r-- | schema/embedded/driver.cxx | 97 | ||||
-rw-r--r-- | schema/embedded/makefile | 117 | ||||
-rw-r--r-- | schema/embedded/person.hxx | 60 |
7 files changed, 379 insertions, 4 deletions
@@ -6,7 +6,7 @@ For more information see: http://www.codesynthesis.com/products/odb/ -This package contains the ODB examples. The following list gives an +This package contains the ODB examples. The following list gives an overview of the available examples. See the README file accompanying each example for more information. @@ -25,7 +25,7 @@ container Shows how to use containers as data members in persistent objects. relationship - Shows how to declare and use unidirectional to-one and to-many + Shows how to declare and use unidirectional to-one and to-many relationships. inverse @@ -36,6 +36,10 @@ boost Shows how to persist objects that use Boost smart pointers, containers, and value types with the help of the Boost profile library (libodb-boost). +schema/embedded + Shows how to generate and use a database schema that is embedded into the + application. + schema/custom Shows how to map persistent C++ classes to a custom database schema. @@ -49,5 +53,5 @@ See the LICENSE file for distribution conditions. See the INSTALL file for prerequisites and installation instructions. -Send questions, bug reports, or any other feedback to the +Send questions, bug reports, or any other feedback to the odb-users@codesynthesis.com mailing list. @@ -5,7 +5,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))build/bootstrap.make -dirs := composite container hello query mapping +dirs := composite container hello query mapping schema/embedded tr1_dirs := relationship inverse schema/custom boost_dirs := boost diff --git a/schema/embedded/README b/schema/embedded/README new file mode 100644 index 0000000..d353bd0 --- /dev/null +++ b/schema/embedded/README @@ -0,0 +1,51 @@ +This example shows how to generate and use a database schema that is embedded +into the application rather than stored as a separate SQL file. + +The example consists of the following files: + +person.hxx + Header file defining the 'person' persistent class. + +person-odb.hxx +person-odb.ixx +person-odb.cxx + These files contain the database support code as well as the embedded + database schema for the person.hxx header. They are generated by the ODB + compiler from person.hxx using the following command line: + + odb -d <database> --generate-schema --schema-format embedded \ + --generate-query person.hxx + + Where <database> stands for the database system we are using, for example, + 'mysql'. + + The --generate-schema option requests the generation of the database schema. + The --schema-format option is used to instruct the ODB compiler to embed the + schema into the generated C++ files. + +database.hxx + Contains the create_database() function which instantiates the concrete + database class corresponding to the database system we are using. + +driver.cxx + Driver for the example. It includes the person.hxx and person-odb.hxx + headers to gain access to the persistent classes and their database support + code. It also includes database.hxx for the create_database() function + declaration. + + In main() the driver first calls create_database() to obtain the database + instance. It then uses the ODB schema catalog to create the database + schema. During this step the generated code issues a number of SQL + statements that drop and create necessary database tables, etc. + + After the database schema is ready, the driver persists a number of 'person' + objects, performs a database query, and prints the information about the + returned objects. + +To run the driver, using MySQL as an example, we can execute the following +command: + +./driver --user odb_test --database odb_test + +Here we use 'odb_test' as the database login and also 'odb_test' as the +database name. diff --git a/schema/embedded/database.hxx b/schema/embedded/database.hxx new file mode 100644 index 0000000..7483f52 --- /dev/null +++ b/schema/embedded/database.hxx @@ -0,0 +1,46 @@ +// file : schema/embedded/database.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +// +// Create concrete database instance based on the DATABASE_* macros. +// + +#ifndef DATABASE_HXX +#define DATABASE_HXX + +#include <string> +#include <memory> // std::auto_ptr +#include <cstdlib> // std::exit +#include <iostream> + +#include <odb/database.hxx> + +#if defined(DATABASE_MYSQL) +# include <odb/mysql/database.hxx> +#endif + +inline std::auto_ptr<odb::database> +create_database (int& argc, char* argv[]) +{ + using namespace std; + using namespace odb::core; + + if (argc > 1 && argv[1] == string ("--help")) + { + cerr << "Usage: " << argv[0] << " [options]" << endl + << "Options:" << endl; + +#if defined(DATABASE_MYSQL) + odb::mysql::database::print_usage (cerr); +#endif + + exit (0); + } + +#if defined(DATABASE_MYSQL) + return auto_ptr<database> (new odb::mysql::database (argc, argv)); +#endif +} + +#endif // DATABASE_HXX diff --git a/schema/embedded/driver.cxx b/schema/embedded/driver.cxx new file mode 100644 index 0000000..aeba3ee --- /dev/null +++ b/schema/embedded/driver.cxx @@ -0,0 +1,97 @@ +// file : schema/embedded/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#include <memory> // std::auto_ptr +#include <iostream> + +#include <odb/database.hxx> +#include <odb/transaction.hxx> +#include <odb/schema-catalog.hxx> + +#include "database.hxx" // create_database + +#include "person.hxx" +#include "person-odb.hxx" + +using namespace std; +using namespace odb::core; + +int +main (int argc, char* argv[]) +{ + try + { + typedef odb::query<person> query; + typedef odb::result<person> result; + + auto_ptr<database> db (create_database (argc, argv)); + + // Create the database schema. + // + { + transaction t (db->begin ()); + schema_catalog::create_schema (*db); + t.commit (); + } + + // The following alternative version only creates the schema if it + // hasn't already been created. To detect the existence of the schema + // this version tries to query the database for a person object. If + // the corresponding table does not exist, then an exceptions will be + // thrown in which case we proceed to creating the schema. + // + /* + { + transaction t (db->begin ()); + + try + { + db->query<person> (false); + } + catch (const odb::exception& e) + { + schema_catalog::create_schema (*db); + } + + t.commit (); + } + */ + + // Create a few persistent person objects. + // + { + person john ("John", "Doe", 33); + person jane ("Jane", "Doe", 32); + person joe ("Joe", "Dirt", 30); + + transaction t (db->begin ()); + + db->persist (john); + db->persist (jane); + db->persist (joe); + + t.commit (); + } + + // Print those over 30. + // + { + transaction t (db->begin ()); + + result r (db->query<person> (query::age > 30)); + + for (result::iterator i (r.begin ()); i != r.end (); ++i) + { + cout << i->first () << " " << i->last () << endl; + } + + t.commit (); + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/schema/embedded/makefile b/schema/embedded/makefile new file mode 100644 index 0000000..639505e --- /dev/null +++ b/schema/embedded/makefile @@ -0,0 +1,117 @@ +# file : schema/embedded/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2009-2011 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 := person.hxx +cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o) $(odb_hdr:.hxx=-odb.o)) +cxx_od := $(cxx_obj:.o=.o.d) + +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) + +$(call import,\ + $(scf_root)/import/libodb/stub.make,\ + l: odb.l,cpp-options: odb.l.cpp-options) + +ifdef db_id +$(call import,\ + $(scf_root)/import/libodb-$(db_id)/stub.make,\ + l: odb_db.l,cpp-options: odb_db.l.cpp-options) +endif + +ifeq ($(odb_db.l.cpp-options),) +odb_db.l.cpp-options := $(out_base)/.unbuildable +endif + +# Build. +# +$(driver): $(cxx_obj) $(odb_db.l) $(odb.l) +$(cxx_obj) $(cxx_od): cpp_options := -I$(out_base) +$(cxx_obj) $(cxx_od): $(odb.l.cpp-options) $(odb_db.l.cpp-options) + +ifeq ($(db_id),mysql) +$(cxx_obj) $(cxx_od): cpp_options += -DDATABASE_MYSQL +endif + +genf := $(addprefix $(odb_hdr:.hxx=-odb),.hxx .ixx .cxx) +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(odb) +$(gen): odb := $(odb) +$(gen) $(dist): export odb_options += --database $(db_id) --generate-query \ +--generate-schema --schema-format embedded + +$(gen): cpp_options := -I$(out_base) +$(gen): $(odb.l.cpp-options) + +$(call include-dep,$(cxx_od),$(cxx_obj),$(gen)) + +# Alias for default target. +# +$(out_base)/: $(driver) + +# Dist +# +name := $(subst /,-,$(subst $(src_root)/,,$(src_base))) + +$(dist): db_id := @database@ +$(dist): sources := $(cxx_tun) +$(dist): headers := $(odb_hdr) +$(dist): export name := $(name) +$(dist): export odb_header_stem := $(basename $(odb_hdr)) +$(dist): export extra_dist := README $(call vc9projs,$(name)) \ +$(call vc10projs,$(name)) +$(dist): + $(call dist-data,$(sources) $(headers) README database.hxx) + $(call meta-automake,../../template/Makefile.am) + $(call meta-vc9projs,../../template/template,$(name)) + $(call meta-vc10projs,../../template/template,$(name)) + +# Test. +# +$(test): $(driver) + $(call message,test $<,$< --options-file $(dcf_root)/db.options) + +# 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)) + +# 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,$(odb_rules)) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/o-e.make) + diff --git a/schema/embedded/person.hxx b/schema/embedded/person.hxx new file mode 100644 index 0000000..a3d44b9 --- /dev/null +++ b/schema/embedded/person.hxx @@ -0,0 +1,60 @@ +// file : schema/embedded/person.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : not copyrighted - public domain + +#ifndef PERSON_HXX +#define PERSON_HXX + +#include <string> + +#include <odb/core.hxx> + +#pragma db object +class person +{ +public: + person (const std::string& first, + const std::string& last, + unsigned short age) + : first_ (first), last_ (last), age_ (age) + { + } + + const std::string& + first () const + { + return first_; + } + + const std::string& + last () const + { + return last_; + } + + unsigned short + age () const + { + return age_; + } + + void + age (unsigned short age) + { + age_ = age; + } + +private: + friend class odb::access; + + person () {} + + #pragma db id auto + unsigned long id_; + + std::string first_; + std::string last_; + unsigned short age_; +}; + +#endif // PERSON_HXX |