In previous chapter you’ve might noticed, that data model with dinemic framework is not defined straight. Reason for that is to make whole data very flexible. Imagine, that one of nodes is updated to new version. With no exact schema for whole cluster, any node can update and add any new field. However you can define your own data model related to DModel class.

How it does it work? Finally you will get the class, based on DModel with fields similar to standard C++ fields:


class Person {
    std::string name;
    int age;
};

The difference between get/set from key-value store via DModel and dedicated fields is obvious. Code of class written with fields is more clean and accessing data is more elegant. Other advantage is that DField and DList allows to encrypt and decrypt such data transparently.

Creating class with DField

Let’s create class similar to above Person, with two fields: name and age:


#include <libdinemic/dmodel.h>
#include <libdinemic/dfield.h>

class Person : public DModel {
    // DModel constructors ...
    DField name;
    DField age;
}

Then it is necessary to initialize such field in constructor of class (exactly in three constructors inherited from DModel):


Person::Person(string db_id, StoreInterface *store, SyncInterface *sync)
    : name(this, "name", false),
      age(this, "age", true)
{
    ...
}

// Another two constructors inherited by DModel

Initialization should be done in the same order for each constructor. Parameters of DFIeld constructor are:

  • parent object, which contains this field – usually this parameter is “this”
  • name of key in data store – data stored via DField or DList canwill be accessible under the same name with set/get methods, or by related list methods
  • Encryption flag. If true, data is automatically encrypted by framework. Only authorized for read objects will be able to read such field.
Using DField

To store data in DField object, inside your DModel just type:


Person person(...);
...

person.name = "John";
person.age = 33;

Dinemic framework will convert each of above calls into strings and send several digitally signed updates across whole network. First updates will be related to creating object (Action CREATE) and assigning to it its public cryptographic keys. Last ones will be related to our change: set string John (base64 encoded) in store’s key value_name and set string “33” under store’s key value_age. Second string will be additionally encrypted and then base64 encoded.

Finally, you can access your data directly from object:


cout << person.name.to_string() << endl;
cout << person.age.to_string() << endl;

Again, as above. person.name.to_string() will return base64 decoded string. person.age.to_string will base64 decode its value from store, decrypt and return proper value.

You can access this value also by get/set methods on object, under its names, passed to DField constructor.

Accessing updated data

Changes in DModel are not visible immediately. If you need to do something on your changed data, use DAction mechanisms instead. This is caused, becouse all application nodes should work in the same way. At the beginning it might be a bit annoying, but such approach, forced by dinemic framework guarantees that all nodes with your application will behave in exactly the same way.

DList

To store more than one value under one name, you can use DList class. Usage is very similar to DField class:


#include <libdinemic/dmodel.h>
#include <libdinemic/dlist.h>

class Person : public DModel {
    // DModel constructors ...
    DList colors;
}

Also it is necessary to initialize such list in constructor of class (exactly in three constructors inherited from DModel):


Person::Person(string db_id, StoreInterface *store, SyncInterface *sync)
    : colors(this, "custom_list_colors", false)
{
    ...
}

Above example also shows using different name of list in database – you will be able to access if via methods list_set/list_at/… under key name custom_list_colors.

To access your list’s data, use folowing code:


colors.append("red");
colors.append("green");
colors.append("blue");

// Wait for data propagation

cout << "Third element of list is " << colors.at(2) << endl;
cout << "List has " << colors.length() << " elements" << endl;
cout << "Red is at " << colors.index("red") << " position" << end;

list.delete(1);

As in DField, any change in DList is not visible immediately. If you need to do something on your changed data, use DAction mechanisms instead.

Using read_authorized_objects and update_authorized_objects lists

Mentioned above encryption flag causes that fields and lists are encrypted/decrypted with object's keys. This happens, because each object puts its cryptographic keys into proper lists inside each object. Basing on this two lists:

  • read_authorized_objects
  • update_authorized_objects

dinemic framework is able to validate all changes incoming from cluster and prevent unauthorized changes (if you setup properly its behavior, what will be described later). To do this, list update_authorized_objects is used. If database update arrives, then dinemic checks if there is any object in this list, whose public key could digitally verify such update.

If DField or DList are marked as encrypted, then dinemic uses public keys related to objects in read_authorized_objects to encrypt data, when data in field or list is updated. Encryption is done by multiple keys, related to all objects listed in read_authorized_objects. When you are trying to access such object's data, then dinemic checks if private key of object, which tries to decrypt data is able to decrypt this field or list element. If not, then proper exception is thrown.

You can find more about encryption and data access in chapter Managing permissions.