Перейти к содержимому

Сущности и модели

Эта страница переведена с английского. Читать страницу на английском

Данные описываются один раз, как структура Rust с атрибутами. Это же описание управляет формами, столбцами таблицы, проверкой на сервере и в браузере, JSON API и его схемой OpenAPI.

Entity

#[entity(table = "...")] помечает строку таблицы. Ему нужно одно поле #[key]; он создаёт типизированный идентификатор, например ProductId, и ссылку на каждое поле, например Product::code.

#[entity(table = "products")]
pub struct Product {
    #[key]
    pub id: ProductId,
    #[rule(required, max_len = 20, unique)]
    pub code: String,
    #[rule(required, max_len = 200)]
    pub name: String,
    pub unit: Unit,
    #[rule(min = 0)]
    pub price: Money,
    #[readonly]
    pub stock: i64,
    pub active: bool,
    #[version]
    pub version: i64,
}

Ссылки на поля типизированы: Product::price это Field<Product, Money>. Итог таблицы по текстовому столбцу или поле формы из другой модели не скомпилируются.

Model

#[model] это данные, которые не являются строкой таблицы: фильтры, шаги мастера, ввод формы.

#[model]
pub struct Visit {
    #[rule(required, min = 2026_01_01, max = 2027_12_31)]
    pub day: Option<Date>,
    pub arrives: Time,
}

Choice

#[choice] превращает enum из вариантов без данных в выпадающий список, группу переключателей или сегментированный переключатель. Подписи берутся из файлов локалей.

#[choice]
pub enum Unit {
    Piece,
    Kg,
    Liter,
}

Атрибуты полей

АтрибутЗначение
#[key]Первичный ключ entity
#[version]Версия строки типа i64. Сохранение со старой версией завершается ошибкой Error::Conflict
#[readonly]Показывается, но формы никогда его не записывают
#[label("...")]Запасная подпись, если в файлах локалей её нет
#[rule(...)]Правила проверки, см. ниже

Правила

ПравилоДляЗначение
requiredлюбогоЗначение обязательно
min_len = n, max_len = nтекстаДлина в символах
emailтекстаАдрес электронной почты
embedтекстаАдрес для встраивания через Embed: https на хосте из frame-src приложения (App::csp). Формы также принимают вставленный код <iframe> и сохраняют только его канонический адрес, без параметров отслеживания. См. Display
min = n, max = nчисел, денег, десятичных чисел, датГраницы. Даты записываются как 2026_01_01
scale = n, precision = nDecimalНаибольшее число знаков после запятой (2 без правила) и наибольшее общее число цифр (18 без правила). Они также задают тип столбца, NUMERIC(precision, scale)
mask = "..."текстаИсходное значение заполняет шаблон: 9 цифра, a буква, A заглавная буква, * любой из них; остальные символы показываются при вводе, но не сохраняются. См. Controls
uniqueлюбогоПроверяется хранилищем; форма показывает ошибку из action

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

#[model(validate = check_stay)]
pub struct Stay {
    pub from: Option<Date>,
    pub to: Option<Date>,
}

fn check_stay(s: &Stay, errors: &mut ValidationErrors) {
    if let (Some(a), Some(b)) = (s.from, s.to) {
        if b < a {
            errors.add(Stay::to, t!("stay.before_start"));
        }
    }
}

Valid

Action, который сохраняет данные, принимает Valid<M>. Значение Valid можно создать только выполнив все правила, поэтому action не может забыть о проверке:

#[action(permission = "stock.product.write", audit)]
pub async fn save_product(product: Valid<Product>, store: ProductStore) -> Result<Product> {
    store.save(product.into_inner())
}

Типы полей

String, i32, i64, bool, Money, Decimal, Date, Time, DateTime, LocalDateTime, enum #[choice], идентификаторы entity и Option<T> любого из них. Vec<M> из модели становится в формах редактором строк (см. Line editor).

Money хранится в целых минимальных единицах вместе с валютой. Никогда не используйте f64 для денег. Decimal это точное число для всего остального, что имеет дробную часть: количеств, цен с более чем двумя знаками после запятой, ставок. Он вмещает до 38 цифр, никогда не проходит через число с плавающей запятой и передаётся в JSON как строка ("12.50"). Даты и время описаны в разделе Time and languages.