Data Model Builder Core (DMBCore)

DMBCore is a small library aimed to utilize VL for building and using external data models in end applications. It relies on such  VL extentions and features as JSONConverter and Prototyping.

The main data model stored in the root of a JSON file can be considered as a database as it has an organized collection of structured data including not only the output data model used in an application directly, but also an underlying part including the internal data structure that is used for storing the application’s data in convenient, reusable, and extensible way.

Speed up dev process

With DMBCore there is no need to manually convert vl::Object to JSON including JSONConverter to your project and writing your own TypeResolver. All these steps are encapsulated inside one library which also provides some additional features as initial database structure.

Features

Database structure

The database program interface is represented by class dmb::Model (called Model as it is an internal data model of the database). It includes and maintains the following data structures:

(see example “Empty database”)

The main intention of the implementation is to separate the resulting data model used by an end app from internal structures that are used as a building bricks for the data model construction.

DMBCore also allows the end app to use internal types (from the “types” field) to modify and extend the existent data model.

Content

The end application uses a data model which is created specifically for it. That model is stored in the “content” field of the database.

Composite types

The “types” section comprises of composite types (that is containing several properties in self) represented by vl::Object. These types are used in the “content” field that in turn comprises fields of any types. It may be a Basic type, List or Object. If it is a composite type from “types” section then it is a vl::Object with “proto” field set to type’s id (see the example below “Type used in Content").

Private types

Private types are composites too, but they can’t be used in the content. The only purpose to use private types is to construct some type in “types” section.

Prototyping

VL Prototyping feature is utilized for:

Prototyping is used to let an end application use types from the “types” section. Every type is used as a prototype for any instance of it in the “content” field. A designer of a data model creates types and may instantiate any of them into the content, and the end application may use instances directly from the content or instantiate it’s own during the runtime, put them into the content, store and then load for the future reuse. Thus DMBCore provides the full stack of operations with data:

(see the example “In-content types”)

Designing a model

The ideology of DMBCore as of any DBMS implies separation between a database creation and utilization. Designing a model for an application is nothing but creating a “content” field of a database.

Creation

Creating a database in terms of DMBCore implies:

DataModelBuilder

There is a user-friendly application with GUI based on Qt called DataModelBuilder that is aimed to fully cover the creation process of a database.

As an alternative you can create a database without DataModelBuilder using any text editor writing and modifying JSON content of the database.

Utilization

Utilization of a database means:

Examples

The following examples show how the data is stored in JSON format using DMBCore.

Empty database

dmb::Model in initial state is convertable to the following JSON:

{

    "content": {},

    "types": {},

    "private": {}

}

Every section is a vl::Object converted to JSON object.

Type used in Content

The composite type “Skill” is referenced as a prototype in object “rootSkill” located in the content

{

    "content": {

        "rootSkill": {

            "proto": "Skill",

            "name": "Root skill"

        }

    },

    "types": {

        "Skill": {

            "name": "Skill"

        }

    },

    "private": {}

}

In-content types

Here you can see how the prototyping VL feature can be used to set any object as a prototype of another. It means that you can create your own types during the runtime of the application and store them in the content for reusing.

{

    "content": {

        "rootSkill": {

            "proto": "Skill",

            "children": [

                {

                    "proto": "content.skillLibrary.[0]",

                    "x": 6.0,

                    "y": 2.0,

                    "children": []

                },

                {

                    "proto": "content.skillLibrary.[2]",

                    "x": 1.0,

                    "y": 5.0,

                    "children": []

                }

            ]

        },

        "skillLibrary": [

            {

                "proto": "Skill",

                "description": "The Programming skill",

                "name": "Programming",

                "iconPath": "resources/programming.jpg"

            },

            {

                "proto": "Skill",

                "description": "The Development skill",

                "name": "Development",

                "iconPath": "resources/development.png"

            },

            {

                "proto": "Skill",

                "description": "",

                "name": "C++",

                "iconPath": "resources/c++.png"

            }

        ]

    },

    "types": {

        "Skill": {

            "name": "Skill",

            "frameImgPath": "resources/border.png",

            "description": "",

            "iconPath": "",

            "children": []

        }

    },

    "private": {}

}

Content with differently-typed elements

Here we can see several fields in the content with different types:

{

    "fruitTree": {

        "typeid": "bush",

        "leafColor": "Gold",

        "isTree": true,

        "y": 0.0,

        "leafPerBranch": 6.0,

        "branches": [

            {

                "leafCount": 9.0,

                "fruit": {},

                "branches": [

                    {

                        "leafCount": 3.0,

                        "fruit": {

                            "isFruit": true,

                            "color": "Yellow",

                            "radius": 0.30000001192092896,

                            "branchCount": 1.0

                        },

                        "branches": []

                    }

                ]

            }

        ],

        "x": 0.0

    },

    "fieldSize": 4.0,

    "animalsAround": [

        {

            "typeid": "animal",

            "type": "bear",

            "isMammal": true

        },

        {

            "typeid": "animal",

            "type": "bird"

        },

        {}

    ]

}

JSON

DMBCore uses JSON as a format for storing and loading the data. VL extension JSONConverter covers this need.

Usage

Create an empty database

dmb::Model model;

// Here are fields of the database allowed through the hight-level interfaces Registry and Content

auto& registry = model.GetRegistry();

auto& privateScope = model.GetPrivateScope();

auto& content = model.GetContent();

Register a new type

// … continuing the previous example …

auto& animal = registry.CreateType("animal");

// reference vl::Object& of a newly created type anmial

// is returned

Instantiate into the content

// … continuing the previous example …

auto& tree = content.Add("fruitTree", model.GetType("bush"));

tree.Set("leafColor", "Gold");

content.Add("fieldSize", vl::NumberVar(4));

auto& animals = content.Add("animalsAround", vl::List()).AsList();

Use prototyping inside the content

// … continuing the previous example …

animal.Set("type", "");

vl::Object bear;

bear.SetPrototype(animal);

bear.Set("type", "bear");

bear.Set("isMammal", true);

vl::Object bird;

bird.SetPrototype(animal);

bird.Set("type", "bird");

animals.Add(bear);

animals.Add(bird);

animals.Add(vl::Object());

Store the model

// … continuing the previous example …

model.Store("output.json", { true });

The second argument is a structure named  vl::CnvParams

struct CnvParams

{

        bool pretty = false;

        bool useProtoRefs = true;

        bool storeTypeId = true;

};

And we have passed the first argument pretty as true to generate a visually structured JSON.

Load a model

std::string fName = "model.json";

dmb::Model model;

if (model.Load(fName))

        std::cout << "Model loaded from '" << fName << "'\n";

else

{

        std::cout << "Error while loading a model from '" << fName << "'\n";

        return;

}

Projects using DMBCore

QVL

QVL is a Qt plugin used to serve Qt data models (including ListModel and QObject) using VL and DMBCore as its data layer for Qt models. It also uses database control interface functions of DMBCore like Store and Load.