Открыть меню
Платформа Эра. Документация
Toggle preferences menu
Открыть персональное меню
Вы не представились системе
Your IP address will be publicly visible if you make any edits.

Работа с данными платформы. API

Материал из Платформа Эра. Документации
Предыдущая статья курса: Получение информации о пользователе

Общая информация

В рамках разработки сервисов, одной из ключевых задач является работа с данными платформы.

Основной способ работы с данными классов в хранилище - это использование классов-обёрток. Такие классы автоматически генерируются платформой на основании настроек классов в пакетах. Эти классы выгружаются вместе с исходными кодами сервисов и могут использоваться в коде сервисов для быстрого и удобного взаимодействия с данными.

С помощью классов-обёрток возможны следующие действия с данными:

  • Коллекция (classMultiName)
    • Подписка на события объекта класса (Insert, Update, Delete)
    • Получение объекта класса по ID
    • Поиск объекта класса
  • Объект класса (className)
    • Создание
    • Модификация
    • Удаление
Приложение Объектная модель

Рассмотрим каждое возможное действие более детально и с примерами.

Так же, для большего удоства и ориентирования по базовым классам платформы и других пакетов, удобно использовать приложение Объектная модель, которое позволяет быстро посмотреть список полей классов во всех пакетах, а также значения перечислений.

Если при работе в IDE, например Visual Studio Code, autocompletion не предлагает для выбора классы-обертки из каких либо пакетов, рекомендуется открыть в IDE index.ts файл этого пакета. В этом случае, IDE дозагрузит необходимые данные классов и они начнут появляться.

Подписка на события класса

Для доступа к событиям классов используется коллекция объектов этих классов. Её название аналогично названию classMultiName.

В примере кода ниже, создается приватное свойство класса для хранения коллекции, затем в конструкторе эта коллекция инициализируется, и далее происходит бинд события на метод внутри класса сервиса.

import { GlobalUtils, Converter } from "./../../utils";
import { Service } from "./../../platform/core";
import { ITicket, ITickets } from "../model";
import { Tickets } from "../classes";
import { IBaseEntity, IDataUpdateParams } from "../../base/model";

class Server2Service extends Service {
    private _tickets: ITickets; //свойство класса, через которое мы будем доступаться к коллекции Tickets
    
    constructor() {
        super("creomate_tutorial.Server2Service");
        
        // onCreateCode
        this._tickets = new Tickets(this.context); //инициализируем коллекцию Tickets
        this._tickets.onAfterInsert(this.onTicketAfterInsert.bind(this)); //привязываем метод onTicketAfterInsert к событию onAfterInsert коллекции Tickets
        this.load();
    } 
    onTicketAfterInsert(params_: IDataUpdateParams<ITicket>){
        this.log.info(params_.updateKind); //В этом свойстве хранится тип опецации (удаление, изменение, добавление)
        this.log.info(params_.id); //В этом свойстве хранится ID объекта, над которым была совершена операция
        this.log.info(params_.entity?.subject); //В свойстве entity хранятся данные объекта, в данном случае получаем поле subject из объекта класса

        
    }
}
export default Server2Service;

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

Для каждого класса доступны следующие события для обработки в рамках сервиса:

  • onAfterInsert - событие вызывается после добавления нового объекта класса
  • onBeforeDelete - событие вызывается перед удалением объекта класса
  • onAfterDelete - событие вызывается после удаления объекта класса
  • onAfterModify - событие вызвается после модификации объекта класса
  • onAfterReload - TODO/////
  • onAfterUpdate - TODO/////

В параметр функции, вызываемой каждым событием передается дженерик-параметр IDataUpdateParams, который может быть типизирован каким-либо интерфейсом.

Вариантом по-умолчанию можно считать IDataUpdateParams<IBaseEntity>, в таком случае в параметре невозможно будет получить значения свойств класса, вызвавшего событие. Будет доступен только его ID.

Однако, если использовать типизацию интерфейсом того класса, чьи изменения ожидаются, например - IDataUpdateParams<ITicket>, то через свойство entity моно получить доступ к свойствам экземпляра класса.

Также, в данном параметре передаются две коллекции - oldData и newData. В этих коллекциях можно получить изначальные и новые значения свойств объекта, при обработке событий изменения объекта.


Получение объекта класса по ID

Для получения объекта класса по его идентификатору, в коллекции присутствует два метода:

getByID - метод, позволяющий получить экземпляр класса по ID из кеша или из хранилища. Если экземпляр по ID не найден, вернет undefined

getbyIDStrong - метод, позволяющий получить экземпляр класса по ID из кеша или из хранилища. Если экземпляр по ID не найден, возникнет исключение

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

import { GlobalUtils, Converter } from "./../../utils";
import { Service } from "./../../platform/core";
import { ITicket, ITickets } from "../model";
import { Tickets } from "../classes";
import { IBaseEntity, IDataUpdateParams } from "../../base/model";

class Server2Service extends Service {
    private _tickets: ITickets; //свойство класса, через которое мы будем доступаться к коллекции Tickets
    
    constructor() {
        super("creomate_tutorial.Server2Service");
        
        // onCreateCode
        this._tickets = new Tickets(this.context); //инициализируем коллекцию Tickets
       
        this.load();
    } 
    async myServiceMethod(ticketId: string){

        const ticket = await this._tickets.getByID(ticketId);
        try{
            const ticketStrong = await this._tickets.getByIDStrong(ticketId);
        }catch(e){

            this.log.exception("myServiceMethod: get ticket strong", e);

        }
        
    }
}
export default Server2Service;

Поиск объекта класса

Метод коллекции find позволяет осуществлять поиск по коллекции с помощью предиката.

В данном примере, по коллекции _tickets осуществляется поиск такого ticket, у котрого subject не заполнен.

import { GlobalUtils, Converter } from "./../../utils";
import { Service } from "./../../platform/core";
import { ITicket, ITickets } from "../model";
import { Tickets } from "../classes";
import { IBaseEntity, IDataUpdateParams } from "../../base/model";

class Server2Service extends Service {
    private _tickets: ITickets; //свойство класса, через которое мы будем доступаться к коллекции Tickets
    
    constructor() {
        super("creomate_tutorial.Server2Service");
        
        // onCreateCode
        this._tickets = new Tickets(this.context); //инициализируем коллекцию Tickets
       
        this.load();
    } 
    myFindTicketMethod(ticketId: string){

        const ticket = this._tickets.find(item_ => item_.subject === "");
    
        
    }
}
export default Server2Service;

Создание объекта класса

Для создания нового объекта используется метод коллекции addNew.

Данный метод является асинхронным и создает новый объект класса, либо генерирует исключение.

import { GlobalUtils, Converter } from "./../../utils";
import { Service } from "./../../platform/core";
import { ITicket, ITickets } from "../model";
import { Tickets } from "../classes";
import { IBaseEntity, IDataUpdateParams } from "../../base/model";

class Server2Service extends Service {
    private _tickets: ITickets; //свойство класса, через которое мы будем доступаться к коллекции Tickets
    
    constructor() {
        super("creomate_tutorial.Server2Service");
        
        // onCreateCode
        this._tickets = new Tickets(this.context); //инициализируем коллекцию Tickets
       
        this.load();
    } 
    async createTicketMethod(subject:string, description:string){

        const newTicket = await this._tickets.addNew(ticket_=>{
            ticket_.subject = subject,
            ticket_.description = description
        })
        
    }
}
export default Server2Service;

Модификация объекта класса

Для изменения объекта класса, необходимо каким-либо образом получить его экземпляр. Примеры возможных вариантов получения:

  • Получение entity с помощью подписки на событие
  • Получение entity по ID
  • Получение entity с помощью поиска find
  • Получение entity как параметра метода из другого метода

После получения entity, можно напрямую изменять его свойства. Для убоства конвертации данных, представлен класс Converter, содержащий основные методы конвертации данных для их представления пользователю.

После внесения изменений в свойства класса, необходимо применить их с помощью асинхронного метода applyUpdates().

import { GlobalUtils, Converter } from "./../../utils";
import { Service } from "./../../platform/core";
import { ITicket, ITickets } from "../model";
import { Tickets } from "../classes";
import { IBaseEntity, IDataUpdateParams } from "../../base/model";

class Server2Service extends Service {
    private _tickets: ITickets; //свойство класса, через которое мы будем доступаться к коллекции Tickets
    
    constructor() {
        super("creomate_tutorial.Server2Service");
        
        // onCreateCode
        this._tickets = new Tickets(this.context); //инициализируем коллекцию Tickets
       
        this.load();
    } 
    async modifyTicketDescription(id: string){
        try{
            const ticket = await this._tickets.getByIDStrong(id);
            ticket.description = ticket.description + "\n" + Converter.dateTimeToFullDateDisplay(GlobalUtils.nowDateTime());
            await ticket.applyUpdates();
        }catch(e){

            this.log.exception("modifyTicketDescription: get ticket by ID", e);

        }
        
    }
}
export default Server2Service;

Удаление объекта класса

Для удаления объекта класса, его экземпляр необходимо также получить любым из способов.

Для удаления объекта класса используется асинхронный метод delete.

Использование метода может вызвать исключение, например если какие-либо проверки прерывают операцию удаления объекта.

import { GlobalUtils, Converter } from "./../../utils";
import { Service } from "./../../platform/core";
import { ITicket, ITickets } from "../model";
import { Tickets } from "../classes";
import { IBaseEntity, IDataUpdateParams } from "../../base/model";

class Server2Service extends Service {
    private _tickets: ITickets; //свойство класса, через которое мы будем доступаться к коллекции Tickets
    
    constructor() {
        super("creomate_tutorial.Server2Service");
        
        // onCreateCode
        this._tickets = new Tickets(this.context); //инициализируем коллекцию Tickets
       
        this.load();
    } 
    async deleteTicketById(id: string){
        try{
            const ticket = await this._tickets.getByIDStrong(id);
            try{
                await ticket.delete();
            }catch(e){

                this.log.exception("deleteTicketById", e);

            }
        }catch(e){

            this.log.exception("deleteTicketById: get ticket by ID", e);

        }
        
    }
}
export default Server2Service;

Вызов сервисов платформы и работа с внутренним API

Работу с сервисами платформы можно условно разделить

Следующая статья курса: Работа с внешними системами. Возможности интеграции
Предыдущая статья курса: Получение информации о пользователе