Dinemic framework provides data mapper for C++ classes. Once you inherit DModel class, you will be able to use simple API to store and read data in your objects. In this article you will learn how to use get/set properties (and similar), related to object. DField and DLists are described in separate document.
Inherit DModel class
In previous chapters you’ve read some basic information about DModel. Let’s take a deep look into this class.
Constructors
Each class inheriting from DModel should implement all two constructors. One for creating new object (first in following example) and one to re-create object anywhere in cluster (second constructor)
#include <libdinemic/dmodel.h>
class MyModel : public DModel
{
public:
// Create new object
MyModel(StoreInterface *store,
SyncInterface *sync,
const std::vector &authorized_keys);
// Re-create instance of existing object anywhere in cluster
MyModel(const std::string &db_id, StoreInterface *store, SyncInterface *sync, DModel *parent=NULL, DModel *caller=NULL);
// Create new object as child
MyModel(const std::string model_name, DModel *parent);
...
Better understanding the purpose of each constructor will help you take all benefits comming from using dinemic ecosystem. First constructor is most similar to one known from standard C++ approach. It creates new object. As parameters it gets pointers to store and sync interfaces to communicate with framework. This constructor should be used only in case, when we want to create new object in dinemic database. Calling it causes, that pair of private/public keys are generated on host, that calls this constructor. Such pair of keys is stored in dinemic keyring. After creating object dinemic framework creates notification about new object and broadcasts it over network to all other applications. Once object is created with this constructor, whole cluster should know its database ID, public cryptographic key, and public signature key. Additional parameter is list of authorized IDs. With this property you can define who can modify your object and who can read its encrypted data (if encryption was enabled on particular fields – this will be covered in next chapter).
Second one is used to recreate objects. This is most important constructor of concept that drives dinemic architecture. By better understanding it you will faster create properly designed applications in dinemic architecture. Use of first constructor is usually
Imagine, that you are receiving information about new object created somewhere in cluster of dinemic nodes. Then, depending on context, you should be able to get such object with the same data inside, in your application/ Described in Chat tutorial DActions are using this constructor in this way. Once DAction is called, you probably will need to get into some interaction with such object. This constructor could be easily used to create such object temporarily:
...
my_model_id = config.get("my_important_object");
MyModel object(my_model_id);
...
Then you can execute gets/sets on this object to update its data. All updates should be visible soon in all neighbor nodes.
Simple get and set
The simplest way to update object’s data is to use its get and set properties. Once object is (re)created in you application, you can execute following code:
object.set("MyKey", "Some value");
...
object.get("MyKey");
Remember, that dinemic provides asynchronous data propagation. It means, that any changes in your objects, even local will appear with some delay. Your local instance of dinemic application should first process such chage and update object’s status in local database. Then change should be visible in your object. You can also use local variables instead, but remember, that non-dinemic fields will be visible only in your local object. Any other node with this object will not see such field.
Dinemic provides key-value database backend with no strict schema required. It means, that if you try to get non-existing value from key-value store, you will get empty string or passed as parameter, default value for get method. You should remember that, in context of data synchronization. In case of split brains of your application’s cluster your code might get not up to date values. Dealing with it should make your application more resistant for failures.
To get list of all fields you can call keys method on your object:
vector keys;
keys = object.keys();
Lists
Key-value store is not only data type. You are able to use lists in dinemic application. Let’s create one:
MyModel object("MyModel:12039ufrw...", store, sync);
object.list_append("first_list", "a");
object.list_append("first_list", "b");
As you see, it is not necessary to declare such list before using it. You can just append new values to it. No declaration means also, that there is no guarantee, that other instance of your model will not make the same list somewhere else in cluster. This is why list elements are indexed, but theirs primary index is in fact random string, internally.
You can use set method to tell explicit which element you want to set. If that is existing element, then it will be replaced:
object.list_set("first_list", 1, "x");
Finally, to get element of list you can call:
object.list_at("first_list", 0); // == "a"
object.list_length("first_list"); // == 2
object.list_index("first_list", "x"); // == 1, check above - we've just replaced b with x
Last thing what we might want to do with list is to remove one element:
object.list_delete("first_list", 0);