ODB, Advanced Weapons and Tactics - Boris Kolpackov - CppCon 2014
ODB, Advanced Weapons and Tactics - Boris Kolpackov - CppCon 2014
Boris Kolpackov
Code Synthesis
CODE
SYNTHESIS
-1-
Schema Evolution
.
#pragma db model version(1, 2)
#pragma db object
class user
{
std::string first_;
std::string last_;
};
#pragma db object
class user
{
std::string name_;
};
-2-
Data Migration
.
schema_catalog::data_migration_function (
3,
[] (database& db)
{
for (bug& b: db.query<bug> ())
{
b.name (b.first () + ” ” + b.last ());
db.update (b);
}
});
-3-
Versioned Namespace?
namespace version2
{
#pragma db object
class user
{
std::string first_;
std::string last_;
};
}
-4-
Soft-Delete
.
#pragma db model version(1, 3)
#pragma db object
class user
{
#pragma db deleted(3)
std::string first_;
#pragma db deleted(3)
std::string last_;
std::string name_;
};
-5-
Soft-Delete
.
#pragma db model version(1, 3)
#pragma db object
class user
{
#pragma db deleted(3)
std::string first_;
#pragma db deleted(3)
std::string last_;
std::string name_;
};
-5-
Soft-Delete
.
#pragma db object
class user
{
std::string name_;
#pragma db value
struct deleted_data
{
#pragma db deleted(3)
std::string first_;
#pragma db deleted(3)
std::string last_;
};
#pragma db column(””)
std::unique_ptr<deleted_data> dd_;
};
-6-
Soft-Add
.
#pragma db object
class user
{
std::string name_;
#pragma db value
struct deleted_data
{
#pragma db deleted(3)
std::string first_;
#pragma db deleted(3)
std::string last_;
};
#pragma db column(””)
std::unique_ptr<deleted_data> dd_;
};
-7-
Soft-Add
.
schema_catalog::data_migration_function (
2,
[] (database& db)
{
for (bug& b: db.query<bug> ())
{
b.platform (”Unknown”);
db.update (b);
}
});
-8-
Soft-Add
.
schema_catalog::data_migration_function (
2,
[] (database& db)
{
for (bug& b: db.query<bug> ())
{
b.platform (”Unknown”);
db.update (b);
}
});
-8-
Soft-Add
.
schema_catalog::data_migration_function (
2,
[] (database& db)
{
for (bug& b: db.query<bug> ())
{
b.platform (”Unknown”);
db.update (b);
}
});
-8-
Soft-Add
.
class user
{
#pragma db added(3)
std::string name_;
#pragma db value
struct deleted_data
{
#pragma db deleted(3)
std::string first_;
#pragma db deleted(3)
std::string last_;
};
#pragma db column(””)
std::unique_ptr<deleted_data> dd_;
};
-9-
Containers
.
#pragma db object
class bug
{
...
#pragma db id auto
unsigned long long id_;
status status_;
std::string summary_;
std::string description_;
std::vector<std::string> comments_;
};
-10-
Containers
t.commit ();
-11-
Change-Tracking Containers
-12-
Containers
.
#pragma db object
class bug
{
...
odb::vector<std::string> comments_;
};
-13-
Object Cache
.
#pragma db object
class user
{
...
#pragma db inverse(reporter_)
std::vector<std::weak_ptr<bug>> reported_bugs_;
};
#pragma db object
class bug
{
...
std::shared_ptr<user> reporter_;
};
-14-
Object Cache
.
transaction t (db.begin ());
session s;
t.commit ();
-15-
Object Cache
.
transaction t (db.begin ());
session s;
t.commit ();
-15-
Object Cache
.
transaction t (db.begin ());
session s;
t.commit ();
-15-
Lazy Pointers
• Finer-grained control over relationship loading
• Every supported pointer has a corresponding lazy version
-16-
Lazy Pointers
• Finer-grained control over relationship loading
• Every supported pointer has a corresponding lazy version
.
#pragma db object
class user
{
...
#pragma db inverse(reporter_)
std::vector<odb::lazy_weak_ptr<bug>> reported_bugs_;
};
odb::lazy_weak_ptr<bug> lb = ...
std::shared_ptr<bug> b (lb.load ()); // Load and lock.
-16-
Object Sections
.
#pragma db object
class bug
{
...
std::string description_;
odb::vector<std::string> comments_;
};
-17-
Object Sections
-18-
Object Sections
.
#pragma db object
class bug
{
...
#pragma db section(details_)
std::string description_;
#pragma db section(details_)
odb::vector<std::string> comments_;
};
-19-
Object Sections
.
#pragma db object
class bug
{
...
#pragma db section(details_)
std::string description_;
#pragma db section(details_)
odb::vector<std::string> comments_;
};
-19-
Object Sections
.
#pragma db object
class bug
{
...
#pragma db section(details_)
std::string description_;
#pragma db section(details_)
odb::vector<std::string> comments_;
};
-19-
Object Sections
.
#pragma db object
class bug
{
...
#pragma db section(details_)
std::string description_;
#pragma db section(details_)
odb::vector<std::string> comments_;
};
-19-
Object Sections
.
transaction t (db.begin ());
db.update (b);
}
t.commit ();
-20-
Object Sections
.
transaction t (db.begin ());
db.update (b);
}
t.commit ();
-20-
Object Sections
.
transaction t (db.begin ());
db.update (b);
}
t.commit ();
-20-
Object Sections
.
transaction t (db.begin ());
db.update (b);
}
t.commit ();
-20-
Object Sections
.
transaction t (db.begin ());
db.update (b);
}
t.commit ();
-20-
Object Sections
.
#pragma db object
class user
{
...
#pragma db load(lazy)
odb::section details_;
#pragma db section(details_)
std::vector<odb::lazy_weak_ptr<bug>> reported_bugs_;
};
-21-
Views
t.commit ();
-22-
Views
-23-
Declaring Views
.
#pragma db view object(bug) object(user)
struct bug_summary
{
unsigned long long id;
std::string summary;
std::string first;
std::string last;
};
-24-
Using Views
-25-
Using Views
-25-
Aggregate View
.
#pragma db view object(bug)
struct bug_stats
{
#pragma db column(”COUNT(” + bug::id_ + ”)”)
std::size_t count;
};
-26-
Aggregate View
.
#pragma db view object(bug)
struct bug_stats
{
#pragma db column(”COUNT(” + bug::id_ + ”)”)
std::size_t count;
};
-26-
Aggregate View
.
#pragma db view object(bug)
struct bug_stats
{
#pragma db column(”COUNT(” + bug::id_ + ”)”)
std::size_t count;
};
bug_stats bs (
*db.query<bug_stats> (
query::status == closed).begin ());
-26-
Aggregate View
.
#pragma db view object(user) object(bug) \
query ((?) + ”GROUP BY” + user::email_)
struct user_stats
{
std::string first;
std::string last;
-27-
Aggregate View
.
#pragma db view object(user) object(bug) \
query ((?) + ”GROUP BY” + user::email_)
struct user_stats
{
std::string first;
std::string last;
-27-
Aggregate View
.
#pragma db view object(user) object(bug) \
query ((?) + ”GROUP BY” + user::email_)
struct user_stats
{
std::string first;
std::string last;
.
#pragma db view query(”EXEC analyze_bugs (?)”)
struct report
{
unsigned long long id;
std::string result;
};
-28-
Stored Procedure Call
.
#pragma db view query(”EXEC analyze_bugs (?)”)
struct report
{
unsigned long long id;
std::string result;
};
-28-
Stored Procedure Call
.
#pragma db view query(”EXEC analyze_bugs (?)”)
struct report
{
unsigned long long id;
std::string result;
};
-28-
Native Query
.
#pragma db view
struct sequence_value
{
unsigned long long value;
};
-29-
Native Query
.
#pragma db view
struct sequence_value
{
unsigned long long value;
};
sequence_value sv (
*db.query<sequence_value> (
”SELECT nextval(’my_sequence’)”).begin ());
-29-
Optimistic Concurrency
status s;
cin >> s;
b->status (s);
db.update (b);
t.commit ();
-30-
Optimistic Concurrency
std::shared_ptr<bug> b;
{
transaction t (db.begin ());
b = db.load<bug> (id);
t.commit ();
}
status s;
cin >> s;
b->status (s);
{
transaction t (db.begin ());
db.update (b);
t.commit ();
}
-31-
Optimistic Concurrency
-32-
Declaring Optimistic Classes
.
#pragma db object optimistic
class bug
{
...
#pragma db id auto
unsigned long long id_;
#pragma db version
unsigned long long version_;
status status_;
std::string summary_;
std::string description_;
};
-33-
Declaring Optimistic Classes
.
#pragma db object optimistic
class bug
{
...
#pragma db id auto
unsigned long long id_;
#pragma db version
unsigned long long version_;
status status_;
std::string summary_;
std::string description_;
};
-33-
Using Optimistic Classes
for (bool done (false); !done;)
{
cout << ”current status: ” << b->status () << endl
<< ”enter new status: ”;
cin >> s;
b->status (s);
try {
db.update (b);
done = true;
}
catch (const odb::object_changed&) {
db.reload (b);
}
t.commit ();
}
-34-
Polymorphism
class issue
{
unsigned long long id_;
status status_;
std::string summary_;
std::string description_;
};
-36-
Polymorphism
.
CREATE TABLE issue(
id BIGSERIAL NOT NULL PRIMARY KEY,
typeid TEXT NOT NULL,
status INTEGER NOT NULL,
summary TEXT NOT NULL,
description TEXT NOT NULL)
-36-
Polymorphism
.
CREATE TABLE issue(
id BIGSERIAL NOT NULL PRIMARY KEY,
typeid TEXT NOT NULL,
status INTEGER NOT NULL,
summary TEXT NOT NULL,
description TEXT NOT NULL)
-36-
Polymorphism
.
CREATE TABLE issue(
id BIGSERIAL NOT NULL PRIMARY KEY,
typeid TEXT NOT NULL,
status INTEGER NOT NULL,
summary TEXT NOT NULL,
description TEXT NOT NULL)
-36-
Declaring Polymorphic Classes
.
#pragma db object polymorphic
class issue
{
...
virtual ~issue () = 0;
#pragma db id auto
unsigned long long id_;
status status_;
std::string summary_;
std::string description_;
};
-37-
Declaring Polymorphic Classes
.
#pragma db object polymorphic
class issue
{
...
virtual ~issue () = 0;
#pragma db id auto
unsigned long long id_;
status status_;
std::string summary_;
std::string description_;
};
-37-
Declaring Polymorphic Classes
#pragma db object
class bug: public issue
{
...
std::string platform_;
};
#pragma db object
class feature: public issue
{
...
-38-
Using Polymorphic Classes
.
std::shared_ptr<issue> i (new bug (...));
i->status (confirmed);
db.update (i); // Update bug.
t.commit ();
-39-
Using Polymorphic Classes
.
typedef odb::query<issue> query;
t.commit ();
-40-
Using Polymorphic Classes
.
typedef odb::query<issue> query;
t.commit ();
-40-
Using Polymorphic Classes
.
typedef odb::query<issue> query;
t.commit ();
-40-
Using Polymorphic Classes
.
typedef odb::query<issue> query;
t.commit ();
-40-
Using Polymorphic Classes
.
typedef odb::query<issue> query;
t.commit ();
-40-
Bulk Operations
-41-
Bulk Operations
-42-
Bulk Exceptions
catch (const multiple_exceptions& mex)
{
for (const auto& e: mex)
{
cerr << ”exception at ” << e.position ();
try
{
throw e.exception ();
}
catch (const odb::...)
{
}
catch (const odb::...)
{
}
}
}
-43-
Pimpl Idiom
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
...
private:
class impl;
std::unique_ptr<impl> pimpl_;
};
-44-
Pimpl Idiom
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
...
private:
class impl;
std::unique_ptr<impl> pimpl_;
};
-44-
Virtual Data Members
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
private:
class impl;
#pragma db transient
std::unique_ptr<impl> pimpl_;
};
-45-
Virtual Data Members
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
private:
class impl;
#pragma db transient
std::unique_ptr<impl> pimpl_;
};
-45-
Virtual Data Members
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
private:
class impl;
#pragma db transient
std::unique_ptr<impl> pimpl_;
};
-45-
Virtual Data Members
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
private:
class impl;
#pragma db transient
std::unique_ptr<impl> pimpl_;
};
-45-
Virtual Data Members
.
#pragma db object
class bug
{
unsigned long long id () const;
void id (unsigned long long);
private:
class impl;
#pragma db transient
std::unique_ptr<impl> pimpl_;
};
-45-
Accessor/Modifier Expressions
.
#pragma db value
struct name
{
name (std::string, std::string);
std::string first, last;
};
#pragma db object
class user
{
const std::string& first () const;
const std::string& last () const;
void first (std::string);
void last (std::string);
private:
#pragma db get(name (this.first (), this.last ())) \
set(this.first ((?).first); this.last ((?).last))
name name_;
}; -46-
Accessor/Modifier Expressions
.
#pragma db value
struct name
{
name (std::string, std::string);
std::string first, last;
};
#pragma db object
class user
{
const std::string& first () const;
const std::string& last () const;
void first (std::string);
void last (std::string);
private:
#pragma db get(name (this.first (), this.last ())) \
set(this.first ((?).first); this.last ((?).last))
name name_;
}; -46-
Accessor/Modifier Expressions
.
#pragma db value
struct name
{
name (std::string, std::string);
std::string first, last;
};
#pragma db object
class user
{
const std::string& first () const;
const std::string& last () const;
void first (std::string);
void last (std::string);
private:
#pragma db get(name (this.first (), this.last ())) \
set(this.first ((?).first); this.last ((?).last))
name name_;
}; -46-
Accessor/Modifier Expressions
.
#pragma db value
struct name
{
name (std::string, std::string);
std::string first, last;
};
#pragma db object
class user
{
const std::string& first () const;
const std::string& last () const;
void first (std::string);
void last (std::string);
private:
#pragma db get(name (this.first (), this.last ())) \
set(this.first ((?).first); this.last ((?).last))
name name_;
}; -46-
Accessor/Modifier Expressions
.
#pragma db value
struct name
{
name (std::string, std::string);
std::string first, last;
};
#pragma db object
class user
{
const std::string& first () const;
const std::string& last () const;
void first (std::string);
void last (std::string);
private:
#pragma db get(name (this.first (), this.last ())) \
set(this.first ((?).first); this.last ((?).last))
name name_;
}; -46-
Accessor/Modifier Expressions
.
#pragma db value
struct name
{
name (std::string, std::string);
std::string first, last;
};
#pragma db object
class user
{
const std::string& first () const;
const std::string& last () const;
void first (std::string);
void last (std::string);
private:
#pragma db get(name (this.first (), this.last ())) \
set(this.first ((?).first); this.last ((?).last))
name name_;
}; -46-
Index Definition
.
#pragma db object
class user
{
...
#pragma db id
std::string email_;
#pragma db index
std::string first_;
std::string last_;
#pragma db index(”name_i”) \
unique \
method(”BTREE”) \
members(first_, last_)
};
-47-
Index Definition
.
#pragma db object
class user
{
...
#pragma db id
std::string email_;
#pragma db index
std::string first_;
std::string last_;
#pragma db index(”name_i”) \
unique \
method(”BTREE”) \
members(first_, last_)
};
-47-
Index Definition
.
#pragma db object
class user
{
...
#pragma db id
std::string email_;
#pragma db index
std::string first_;
std::string last_;
#pragma db index(”name_i”) \
unique \
method(”BTREE”) \
members(first_, last_)
};
-47-
Prepared and Cached Queries
.
typedef odb::query<bug> query;
typedef odb::prepared_query<person> prep_query;
status s;
query q (query::status == query::_ref (s));
prep_query pq (db.prepare_query<bug> (”bug-query”, q));
s = open;
pq.execute ();
s = confirmed;
pq.execute ();
...
t.commit ();
-48-
Prepared and Cached Queries
.
typedef odb::query<bug> query;
typedef odb::prepared_query<person> prep_query;
status s;
query q (query::status == query::_ref (s));
prep_query pq (db.prepare_query<bug> (”bug-query”, q));
s = open;
pq.execute ();
s = confirmed;
pq.execute ();
...
t.commit ();
-48-
Prepared and Cached Queries
.
typedef odb::query<bug> query;
typedef odb::prepared_query<person> prep_query;
status s;
query q (query::status == query::_ref (s));
prep_query pq (db.prepare_query<bug> (”bug-query”, q));
s = open;
pq.execute ();
s = confirmed;
pq.execute ();
...
t.commit ();
-48-
Prepared and Cached Queries
.
typedef odb::query<bug> query;
typedef odb::prepared_query<person> prep_query;
status s;
query q (query::status == query::_ref (s));
prep_query pq (db.prepare_query<bug> (”bug-query”, q));
s = open;
pq.execute ();
s = confirmed;
pq.execute ();
...
t.commit ();
-48-
Other Features
-49-
Customizations
-50-
Future
-51-
Maybe Future
-52-
Resources
• ODB Page
• www.codesynthesis.com/products/odb/
• ODB Manual
• www.codesynthesis.com/products/odb/doc/manual.xhtml
• Blog
• www.codesynthesis.com/~boris/blog/
-53-