C++ example
This example shows a small c++ program which defines two classes, product and purchase. You can add objects to the database by running it from the command line with different options. The example shows how to create a server, user and database, and how to build the c++ code. It also shows how to use the dboo command line tool to run search queries on the database.
Code
1#include <dboo/rfx.h>
2#include <dboo/odb.h>
3#include <dboo/osl/format_json.h>
4
5#include <string>
6#include <vector>
7#include <memory>
8
9using namespace std;
10
11string host = "localhost";
12int port = 8822;
13string database = "testdb";
14string user = "testuser";
15string password = "mypassword";
16
17// An example class product, which defines purchasable products.
18class product
19{
20public:
21 product() = default;
22 product(const string& name)
23 : _name{name} {};
24
25 inline static void dboo_class_init(dboo::cls<product>& c) {
26 c.member(&product::_name, "_name");
27 }
28 inline static dboo::cls<product> cls{"product"};
29
30private:
31 string _name;
32};
33
34// An example class purchase, which defines actual purchased of a product.
35class purchase
36{
37public:
38 purchase() = default;
39 purchase(product * prod, double quantity)
40 : _product{prod}, _quantity{quantity} {};
41
42 inline static void dboo_class_init(dboo::cls<purchase>& c) {
43 c.member(&purchase::_product, "_product");
44 c.member(&purchase::_quantity, "_quantity");
45 }
46 inline static dboo::cls<purchase> cls{"purchase"};
47
48private:
49 product *_product = nullptr;
50 double _quantity = 0.;
51};
52
53int main(int argc, char** argv)
54{
55 dboo::init();
56
57 vector<string> args{argv, argv + argc};
58
59 if (args.size() == 1) {
60 cout << "Usage: " << endl;
61 cout << " " << argv[0] << " init" << endl;
62 cout << " " << argv[0] << " product <product name>" << endl;
63 cout << " " << argv[0] << " purchase <product name> <quantity>" << endl;
64 cout << " " << argv[0] << " products" << endl;
65 cout << " " << argv[0] << " purchases" << endl;
66 return 0;
67 }
68
69 try {
70
71 dboo::odb odb;
72 odb.connect(host, port, database, user, password);
73
74 if (args.size() == 2 && args[1] == "init") {
75 // First argument == "init":
76
77 // Define product and purchase classes for dboo.
78 // This creates indices and allows for searching on the classes
79 odb.define<product>();
80 odb.define<purchase>();
81
82 } else if (args.size() == 3 && args[1] == "product") {
83 // First argument == "product", create a product:
84
85 vector<unique_ptr<product>> products;
86 auto prod_name = args[2];
87
88 // First check if product exist, search on product name
89 odb.select<product>(products, dboo::eq("_name", prod_name));
90
91 if (products.empty()) {
92 // No results from search, so we can add this product
93
94 auto prod = make_unique<product>(prod_name);
95
96 // Commit it the new product to the database
97 odb.commit(prod);
98
99 } else {
100 cout << "Product " << prod_name << " already exist!" << endl;
101 }
102
103 } else if (args.size() == 4 && args[1] == "purchase") {
104 // First argument == purchase, create a purchase object
105
106 // Using unique_ptr here, however that is not always possible, depending on
107 // how other objects links to this and what life span is expected.
108 vector<unique_ptr<product>> products;
109 auto prod_name = args[2];
110
111 // First check if product exist, search on product name
112 odb.select<product>(products, dboo::eq("_name", prod_name));
113
114 if (!products.empty()) {
115 // Product exist, so we can purchase items
116
117 // convert last argument to double (no checking here, just assume it works...)
118 auto quantity = stod(args[3]);
119
120 // Make a purchase
121 auto trade = make_unique<purchase>(products[0].get(), quantity);
122
123 // Commit it the new trade to the database
124 odb.commit(trade.get());
125
126 } else {
127 cout << "No product named " << prod_name << endl;
128 }
129 } else if (args[1] == "products") {
130 odb.load_types();
131 dboo::format_json out{std::cout};
132 odb.select("product", out);
133 } else if (args[1] == "purchases") {
134 odb.load_types();
135 dboo::format_json out{std::cout};
136 // select to a formatter selects only objects of the specified type by default.
137 // add fetch_referenced_objects to include any referenced objects
138 odb.select("purchase", out, dboo::fetch_referenced_objects);
139 }
140
141 } catch (exception& e) {
142 cout << typeid(e).name() << ": " << e.what() << endl;
143 }
144
145 return 0;
146}
Build with DBOO
With this example comes a cmake file, but you can easily build it directly from the command line with gcc. Assuming the dboo server package as well as sdk are installed in /opt/dboo. If installed somewhere else you may have to modify the paths.
> gcc -o example example.cpp -std=c++17 -I/opt/dboo/current/include -L/opt/dboo/current/lib -ldboo -lstdc++
or, with cmake:
> mkdir build
> cd build
> cmake ..
> make
Running DBOO
DBOO is a server/client application that can manage any number of databases. You will need to create a server, start the server, create a database. dbood is the server process, normally run in daemon mode. dboo is a management tool with which you create users, databases etc.
# Create a server in your home directory (~/.dboo/dboo.cfg and server directory ~/.dboo/server)
> dbood create
Creating server
Base directory for databases: /Users/tomas/.dboo/databases
Log directory: /Users/tomas/.dboo/log
Server directory: /Users/tomas/.dboo/server
Host name: localhost
Listening port: 8822
Server started from '/Users/tomas/.dboo/server': localhost:8822.
Shutting down, tidying up.
Shutting down, exiting.
# Start the server in daemon mode
> dbood -d
Next step is to create a database and user. This is shown here using interactive mode:
# Create a database
> dboo -u=root -p=
> dboo root@dboo::server> create database example --groups=example
Created database 'example'
dboo root@dboo::server>
# Create a user
dboo root@dboo::server> add user me --groups=example --password=123
Created user 'me'
dboo root@dboo::server> exit
Try the example program
Run the example program, first initialize:
> ./example init
Create some products:
> ./example product milk
> ./example product sugar
> ./example product bread
> ./example product tea
Use the dboo tool to search for data, using batch mode:
> dboo example -u=me -p=123 -- "select<product>()"
{"dboo::objectid" : "3600807991f00014", "dboo::class" : "product", "_name" : "bread"}
{"dboo::objectid" : "5c00807991f80014", "dboo::class" : "product", "_name" : "tea"}
{"dboo::objectid" : "680080798adc0014", "dboo::class" : "product", "_name" : "milk"}
{"dboo::objectid" : "c40080798e580014", "dboo::class" : "product", "_name" : "sugar"}
exiting
Same thing but in xml:
> dboo example -u=me -p=123 -- "select<product>()" --format=xml
<product dboo:objectid="3600807991f00014"><_name>bread</_name></product>
<product dboo:objectid="5c00807991f80014"><_name>tea</_name></product>
<product dboo:objectid="680080798adc0014"><_name>milk</_name></product>
<product dboo:objectid="c40080798e580014"><_name>sugar</_name></product>
exiting
Make some purchases:
> ./example purchase milk 10
> ./example purchase sugar 2
> ./example purchase tea 2
> ./example purchase bread 3
> ./example purchase bread 2
> ./example purchase milk 1
Select all purchase objects from the database:
> dboo example -u=me -p=123 -- "select<purchase>()"
{"dboo::objectid" : "5c00807993840017", "dboo::class" : "purchase", "_product" : "680080798adc0014", "_quantity" : 10}
{"dboo::objectid" : "6b00807993e00017", "dboo::class" : "purchase", "_product" : "680080798adc0014", "_quantity" : 1}
{"dboo::objectid" : "9800807993a40017", "dboo::class" : "purchase", "_product" : "c40080798e580014", "_quantity" : 2}
{"dboo::objectid" : "c400807993cc0017", "dboo::class" : "purchase", "_product" : "3600807991f00014", "_quantity" : 3}
{"dboo::objectid" : "d100807993c00017", "dboo::class" : "purchase", "_product" : "5c00807991f80014", "_quantity" : 2}
{"dboo::objectid" : "e000807993d40017", "dboo::class" : "purchase", "_product" : "3600807991f00014", "_quantity" : 2}
exiting
Select all purchase objects and include all referenced objects in the result:
> dboo example -u=me -p=123 -- "select<purchase>()" --fetch_referenced_objects
{"dboo::objectid" : "3600807991f00014", "dboo::class" : "product", "_name" : "bread"}
{"dboo::objectid" : "5c00807991f80014", "dboo::class" : "product", "_name" : "tea"}
{"dboo::objectid" : "5c00807993840017", "dboo::class" : "purchase", "_product" : "680080798adc0014", "_quantity" : 10}
{"dboo::objectid" : "680080798adc0014", "dboo::class" : "product", "_name" : "milk"}
{"dboo::objectid" : "6b00807993e00017", "dboo::class" : "purchase", "_product" : "680080798adc0014", "_quantity" : 1}
{"dboo::objectid" : "9800807993a40017", "dboo::class" : "purchase", "_product" : "c40080798e580014", "_quantity" : 2}
{"dboo::objectid" : "c40080798e580014", "dboo::class" : "product", "_name" : "sugar"}
{"dboo::objectid" : "c400807993cc0017", "dboo::class" : "purchase", "_product" : "3600807991f00014", "_quantity" : 3}
{"dboo::objectid" : "d100807993c00017", "dboo::class" : "purchase", "_product" : "5c00807991f80014", "_quantity" : 2}
{"dboo::objectid" : "e000807993d40017", "dboo::class" : "purchase", "_product" : "3600807991f00014", "_quantity" : 2}
exiting
The object ids are 64 bit numbers based on process and thread id, time and a sequence number so as to make it unique.