A7 Data Server: управление данными онлайн

в 13:43, , рубрики: javascript, piterjs, QML, Блог компании PiterJS, Программирование, управление данными

Привет!

Все записи митапа доступны здесь: https://youtu.be/kJS5rfCWmPI

Мы пилотируем публикации с расшифровками докладов, прозвучавших на PiterJS.
Так как это первый опыт, будем рады услышать конструктивную критику и предложения по улучшению.

Смотрите видео и слайды, а за расшифровкой — добро пожаловать под кат.

Доклад и расшифровку подготовил Андрей Логинов, технический директор в «A7 Systems».
A7 Data Server: управление данными онлайн - 2

Начнем

Fast Big Data Server — cервер для больших быстрых данных. Изначально A7 DS предназначен для Digital Twin, управления ролями и паттернами данных. Но это не всё, что он умеет.

Что внутри.

Давайте посмотрим:
A7 Data Server: управление данными онлайн - 3

  • Объектная база данных
  • Темпоральная (хронологическая) база данных
  • Виртуальная машина JavaScript (если быть честным, то js-like языка)
  • Система уровня доступа
  • Cервер приложения

Объектная база данных помимо типизации и наследования идеревьевмеет несколько особенностей:

  • поддержка деревьев
  • поддержка графов
  • монтирование и ссылки
  • Spaces (пространства)
  • поддержка биндинга (реактивность)

Space

Самое необычное здесь — это Space (пространство).
Space — это экземпляр типовой рабочей области.
A7 Data Server: управление данными онлайн - 4
Space включает:

  • data (данные)
  • shared-data (общие данные для нескольких пространств. Например, погода или курс валюты)
  • roles (owner, users, groups)
    То есть, Space является достаточно изолированным от сервера A7 DS и других Spaces пространством.

Как пользоваться

Теперь вопрос: как этим пользоваться. Это наверное самый главный вопрос.
Создадим небольшое мобильное приложение на ECMAScript.

Нам потребуется:

  • Минимальное знание С++. (возможно в рамках школьной программы)
  • Знание ECMAScript и QML (Qt)
  • Android NDK (просто чтобы скомпилировать это)

По моему ощущению, лучшие примеры всегда связаны с деньгами, поэтому попробуем создать онлайн семейный кошелёк)).

Создадим объекты в объектной базе данных. Точнее мы создадим типы. Для описания объектов удобнее использовать редактор, но мы “не такие”, и создадим описание объектов в JSON.

Сначала создадим объект деньги, в котором у нас есть есть наличные, кредитка, и итоговая сумма:

{
  "name": "Money",
  "fields": [
    {"name": "card","fieldtype": "value","datatype": "double", "def": 0},
    {"name": "cash","fieldtype": "value","datatype": "double","def": 0},
    {"name": "sum","fieldtype": "formula","datatype": "double",
      "def": "card+credit"}
  ]
}

Поля card и cash это простые значения (по умолчанию равные 0), можно записать немного короче:

{"name": "card","value": 0.0},
{"name": "cash","value": 0.0}

Поле sum это формула (привет реактивность!), тоже можно записать немного короче:

{"name": "sum","formula":"card+credit"}

Теперь мы создадим пару из юноши и девушки.

{
  "name": "Pair",
  "fields": [
    {"name": "boyfriend","fieldtype": "value","datatype": "Money", "def": "Money"},
    {"name": "girlfriend","fieldtype": "value","datatype": "Money","def": "Money"},
    {"name": "sum","fieldtype": "formula","datatype": "double",
      "def": "boyfriend.sum+girlfriend.sum"}
  ]
}

Поле sum (снова привет реактивность!), стало включать ссылки на подобъекты:

{"name": "sum","formula":"boyfriend.sum+girlfriend.sum"}

Теперь, при каждом изменении любой цифры мы автоматически будем получать пересчет текущего баланса.

Но нам полезно добавить немного истории.

{"name": "history","fieldtype": "list", "list":{"datatype": "History"}}

В короткой записи

{"name": "history", "list":{"datatype": "History"}}

Ну и сам объект истории. Кто, что, и сколько изменил.

{
  "name": "History",
  "fields": [
    {"name": "who","fieldtype": "value","datatype": "string", "def": “”},
    {"name": "which","fieldtype": "value","datatype": "string","def": “”},
    {"name": "delta","fieldtype": "value","datatype": "double","def": 0}
  ]
}

Добавим триггеров к Pair:

"functions": [{"functiontype": "before",
      "arguments": [boyfriend.cash],
      "code": "..."
   }
]

И сам код триггера:

{
  var historyItem= history.add(new History());
  historyItem.who=”boyfriend”;
  historyItem.which=”cash”;
  history.delta=value-boyfriend.cash;
  return true;
}

По аналогии добавим триггеры для boyfriend.card, girlfriend.card, girlfriend.cash.

Поскольку мы хотим сделать наше приложение большому количеству пар, то создаем типовое пространство SpacePair, и делаем его корневым элементом Pair.
Добавляем двух пользователей по умолчанию
Girl
Boy

Собственно все, генератор пространств для контроля кошельков готов.

Добавим несколько пространств. При добавлении пространства автоматически создается область данных (и сами данные со значениями по умолчанию). Также создаются предустановленные пользователи и группы (для пространства).
Каждое пространство имеет своих пользователей и свои группы.

Начинаем делать клиент:

Добавим в проект библиотеки

android {
    debug{
        LIBS+= ../A7DS/Libs/android/libA17EDboClientBaseBind.a
        LIBS+= ../A7DS/Libs/android/libA17ClientLibBind.a
    }
    release{
        LIBS+= ../A7DS/Libs/android/libA17EDboClientBaseBin.a
        LIBS+= ../A7DS/Libs/android/libA17ClientLibBin.a
    }
}

Немного поправим файл main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QVariant>
#include <QQmlEngine>

// Добавим ссылку на *.h файлы
#include "../A7DS/A17EBase/A17EDboClientBaseBin/a17edboclientbasebin.h"

int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   QQmlApplicationEngine engine;

   // Создаем клиент для A7DS
   A17EDboClientBaseBin*client=new A17EDboClientBaseBin(engine,&app);

   // Инициализируем клиент для A7DS
   client->init(engine);

   // Дальше стандартный код

   engine.load(QUrl(QLatin1String(QString("qrc:/main.qml").toLatin1())));
   return app.exec();
}

На этом C++ часть закончена, и мы можем переходить к QML.

Сначала создадим пару компонентов.

Добавим компонент для отображения данных

MyLabelView.qml

import QtQuick 2.7
import Astra.Dbo 17.0

Item {id: viewItem
   property alias field: field
   property string label: "что и кто"
   width: parent.width
   height: 100

   DboField{
       id: field
   }
   Text {
       id: labelItem
       text: viewItem.label
       anchors.left: parent.left
       anchors.right: parent.horizontalCenter
       anchors.top: parent.top
       anchors.bottom: parent.bottom
   }

   Text {
       id: valueItem
       text: field.value
       anchors.right: parent.right
       anchors.left: parent.horizontalCenter
       anchors.top: parent.top
       anchors.bottom: parent.bottom
   }
}

MyLabelEdit.qml

import QtQuick 2.7
import Astra.Dbo 17.0

Item {id: viewItem
   property alias field: field
   property string label: "что и кто"
   width: parent.width
   height: 100

   DboField{
       id: field
   }
   Text {
       id: labelItem
       text: viewItem.label
       anchors.left: parent.left
       anchors.right: parent.horizontalCenter
       anchors.top: parent.top
       anchors.bottom: parent.bottom
   }

   TextInput {
       id: valueItem
       text: field.value
       anchors.right: parent.right
       anchors.left: parent.horizontalCenter
       anchors.top: parent.top
       anchors.bottom: parent.bottom
       onEditingFinished:{
           field.value=text;
       }
   }
}

Теперь соберем главное окно
MyLabelEdit.qml

import QtQuick 2.7
import Astra.Dbo 17.0
import QtQuick.Controls 1.5

{id:appWindow
    visible: true
    width: 640
    height: 480
    property var component;
    property var sprite;

ApplicationWindow {id: viewItem
property alias field: field
property string label: "что и кто"
property string host: "127.0.0.1" //// адрес A7 DS
property int port: 8989 // порт A7 DS
property string isBoy: (dboconnection.login=="Boy")
property var myselfMoney: (isBoy)?boyfriend:girlfriend
property var myfriendMoney: (!isBoy)?boyfriend:girlfriend

/* 
Данные, которые начнут автоматическую синхронизацию с сервером после соединения
*/

DboObject{id:boyfriend
parentObject: rootData
        parentFieldName:  "boyfriend"
}
DboObject{id:girlfriend
       parentObject: rootData 
       parentFieldName:  "girlfriend"
}
DboModel{id:history
       parentObject: rootData 
       parentFieldName:  "history"
}

/*
То, что мы отображаем, если нет соединения с сервером A7 DS
*/
Column{

     z: 10
     visible: (! dboconnection.isConnect)
     anchors.fill: parent
     TextInput{id:login
width: parent.width
            height: 100
     }
     TextInput{id:password
width: parent.width
height: 100
     }
     Button{id:btn
width: parent.width
height: 100
text: ”Подключиться”
onClicked: dboconnection.connectToDbo(
login.text,
password..text,
           viewItem.host,
           viewItem.port);
}
   }

   SwipeView{
        anchors.fill: parent
        currentIndex: 1
        /// Здесь таблица отражающая историю изменений
        Page{
                  ListView{
        model: history
        delegate: Text{
        text: model.who+” ”+model.which+” ”+model.delta
}
      }    
            }
     /// Здесь список дающий текущую картину
            Page{
                Column{
            anchors.fill: parent
                    MyLabelEdit{id:myCash; label: “мои наличные”
                field.name: “cash”; field.parentObject: myselfMoney
        }
                    MyLabelEdit{id:myCard; label: “моя карта”
                field.name: “card”; field.parentObject: myselfMoney
        }
                   MyLabelView{id:mySum; label: “все мои деньги”
                field.name: “sum”; field.parentObject: myselfMoney
        }
                   MyLabelView{id:myfriendCash; label: “наличные друга”
                field.name: “cash”; field.parentObject: myfriendMoney
        }
                    MyLabelView{id:myfriendCard; label: “карта друга”
                field.name: “card”; field.parentObject: myfriendMoney
        }
                   MyLabelView{id:myfriendSum; label: “все деньги друга”
                field.name: “sum”; field.parentObject: myfriendMoney
        }
                   MyLabelView{id:mypairSum; label: “все наши деньги”
                field.name: “sum”; field.parentObject: mypairMoney
        }
     }
            }
        }
    }

   Text {
       id: labelItem
       text: viewItem.label
       anchors.left: parent.left
       anchors.right: parent.horizontalCenter
       anchors.top: parent.top
       anchors.bottom: parent.bottom
   }

   TextInput {
       id: valueItem
       text: field.value
       anchors.right: parent.right
       anchors.left: parent.horizontalCenter
       anchors.top: parent.top
       anchors.bottom: parent.bottom
       onEditingFinished:{
           field.value=text;
       }
   }
}

Эмм. “А как же обещанные Digital Twin, и прочие ништяки?” – спросит внимательный читатель.
“Биндинг это конечно хорошо, но где монтирование и графы?” – добавит он.

Это справедливые вопросы, и на ответы на них будут дан в следующих статьях ;).

Автор: bmsdave

Источник

* - обязательные к заполнению поля