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

example.cpp

Try it

  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.