Модели данных — это специализированные структуры, предназначенные для эффективной работы с данными в приложении. SDK предоставляет комплексный набор инструментов для:
Весь необходимый функционал для работы с моделями данных находится в неймспейсе Universe.Platform.Model. Этот неймспейс содержит базовые классы, декораторы, валидаторы и утилиты для создания и управления моделями данных
В основе создания модели лежит наследование от класса Universe.Platform.Model.AbstractModel. Такой подход позволяет определить структуру данных через декларативное описание полей с указанием их типов, правил валидации и других метаданных:
import {Universe} from '@universe-dg/sdk';
class Product extends Universe.Platform.Model.AbstractModel {
@Universe.Platform.Model.stringField({
validators: () => [new Universe.Platform.Model.Required()]
})
public name: Universe.Platform.Model.StringField;
@Universe.Platform.Model.stringField({allowNull: true})
public description: Universe.Platform.Model.StringField;
@Universe.Platform.Model.numberField({
validators: () => [
new Universe.Platform.Model.Required(),
new Universe.Platform.Model.AllowedMin(0)
]
})
public price: Universe.Platform.Model.NumberField;
}
const product = new Product({
name: 'Product name',
description: 'Product description',
price: 450
});
Получить значение поля модели можно с помощью метода getValue:
console.log(product.name.getValue()); // 'Prduct 1'
console.log(product.price.getValue()); // 450
Так же возможно получить сериализованные данные всей модели:
console.log(product.serialize()); // {
// name: 'Product name'
// description: 'Product description'
// price: 450
// }
Изменить значение поля можно с помощью метода setValue:
pruduct.name.setValue('New product');
console.log(product.name.getValue()); // 'New product'
При этом, после изменения всё ещё есть доступ к оригинальному значению поля:
console.log(product.name.getOriginalValue()); // 'Product name'
Проверить изменено ли поле или модель, можно с помощью метода getDirty:
// Есть ли изменения в конкретном поле
console.log(product.name.getDirty()); // true
// Есть ли ихзменения в модели
console.log(product.getDirty());
Всегда можно сбросить текущее значение к оригинальному:
// Сросить значение для поля
product.name.revert();
// Или для всей модели
product.revert();
console.log(product.name.getValue()); // 'Product name'
console.log(product.name.getDirty()); // false
Так же возможно зафиксировать изменения в модели:
product.name.setValue('New product');
product.commit();
console.log(product.name.getOriginalValue()); // 'New product';
console.log(product.name.getDirty()); // false
console.log(product.getDirty()); // false
Валидация всей модели:
product.name.setValue('');
product.price.setValue(-1);
const validationResult = product.validate();
console.log(validationResult); // Map(2) {
// 'name' => ['Обязательное поле'],
// 'price' => ['Error message']
// }
Валидация отдельных полей модели:
// Выполнить валидацию
console.log(product.name.validate()) // ['Обязательное поле']
// Получить последний результат валидации
console.log(product.name.validationResult); // ['Обязательное поле']
// Получить первое сообщение об валидационной ошибке
console.log(product.name.getErrorMessage()); // 'Обязательное поле'
В качестве полей модели можно задавать не только простые поля, но и другие модели или даже коллекции моделей:
class ProductDimensions extends Universe.Platform.Model.AbstractModel {
@Universe.Platform.Model.numberField()
public width: Universe.Platform.Model.NumberField;
@Universe.Platform.Model.numberField()
public height: Universe.Platform.Model.NumberField;
@Universe.Platform.Model.numberField()
public depth: Universe.Platform.Model.NumberField;
}
class Tag extends Universe.Platform.Model.AbstractModel {
@Universe.Platform.Model.stringField()
public name: Universe.Platform.Model.StringField;
}
class ExtendedProduct extends Product {
/**
* Вложенная модель
*/
@Universe.Vendor.Mobx.observable
@Universe.Platform.Model.@hasOne({ofType: () => ProductDimensions})
public dimensions: ProductDimensions;
/**
* Коллекция вложенных моделей
*/
@Universe.Platform.Model.@hasMany({ofType: () => Tag})
public tags: ModelCollection<Tag>;
}
const product = new ExtendedProduct({
name: 'Product name',
description: 'Product description',
price: 450,
dimensions: {
width: 10,
height: 20,
depth: 30
},
tags: [
{name: 'Tag 1'},
{name: 'tag 2'}
]
});
console.log(product.dimensions.width.getValue()); // 10;
product.tags.add(new Tag({name: 'Tag 3'}));
console.log(product.tags.serialize()); // [
// {name: 'Tag 1'},
// {name: 'tag 2'},
// {name: 'Tag 3'}
// ]
Все изменения в моделях и их полях являются реактивными. Реактивность достигается за счёт использования Universe.Vendor.Mobx:
Universe.Vendor.Mobx.reaction(
() => product.price.getValue(),
(price) => console.log(`New price: ${price}`)
);
product.price.setValue(100);
// New price: 100
product.price.setValue(200);
// New price: 200
И Universe.Vendor.MobxReact в react-компонентах:
@Universe.Vendor.MobxReact.observer
class SomeComponent extends Universe.Vendor.React.Component<{product: Product}> {
onChange = (name: string, value: any) => {
this.props.product.getField(name)?.setValue(value);
};
override render() {
return (
<Universe.Platform.Uikit.Field.Number
name={'price'}
value={this.props.product.price.getValue()}
onChange={this.onChange}
/>
);
}
}
Если необходимого поля нет в списке, можно создать своё собственное поле, наследовавшись от абстрактного класса Universe.Platform.Model.AbstractField:
export class CustomField extends Universe.Platform.Model.AbstractField {
// ...
}
Если необходимого правила нет в списке, можно создать своё собственное правило, реализовав интерфейс Universe.Platform.Model.IFieldValidator или наследоваться от абстрактного класса Universe.Platform.Model.AbstractValidator:
export class JsonValidator extends Universe.Platform.Model.AbstractValidator {
constructor () {
super('Некорректный JSON');
}
public validate (params: Universe.Platform.Model.IFieldValidationParams) {
try {
JSON.parse(params.value);
return true;
} catch {
return false;
};
}
}