Skip to content
Merged
17 changes: 5 additions & 12 deletions docs/ОбъектМодели.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
### Колонки

```bsl

// Возвращает таблицу колонок модели.
//
// Возвращаемое значение:
// ТаблицаЗначений - Колонки модели, только для чтения.
//
Функция Колонки() Экспорт
```

Expand All @@ -28,17 +32,6 @@
Функция ПодчиненныеТаблицы() Экспорт
```

### Служебный_Колонки

```bsl
// @internal
// TODO: вынести отсюда. Возможно стоит разработать отдельный служебный билдер Объекта модели,
// вытащив заполнение из конструктора в этот билдер, а в конструктор передавать уже готовые для сохранения
// в объект данные.
//
Функция Служебный_Колонки() Экспорт
```

### Служебный_ИмяТаблицы

```bsl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@
);

ОбъектМоделиЭлементКоллекции.Служебный_ИмяТаблицы(ПодчиненнаяТаблица.ИмяТаблицы);
КолонкиОбъектаМодели = ОбъектМоделиЭлементКоллекции.Служебный_Колонки();
// Колонки модели только для чтения, но этот объект модели только что создан и еще никому не отдан.
КолонкиОбъектаМодели = ОбъектМоделиЭлементКоллекции.Колонки();

КолонкаKey = КолонкиОбъектаМодели.Найти("key", "ИмяКолонки");
КолонкаKey.ТипКолонки = ТипКолонкиКлюч;
Expand Down
67 changes: 44 additions & 23 deletions src/Классы/ОбъектМодели.os
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,25 @@
Перем Колонки;
Перем ПодчиненныеТаблицы;
// TODO: Первичный ключ из нескольких полей?
// ФиксированнаяСтруктура.
Перем Идентификатор;

// Соответствие типа колонки модели его ОписаниюТипов. Строится в конструкторе и дальше только читается.
Перем ОписанияТиповКолонок;

Перем МодельДанных;

Перем Рефлектор;

Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных)

МодельДанных = ПМодельДанных;
ТипСущности = ПТипСущности;
ОписанияТиповКолонок = СоответствиеТиповМоделиОписанийТипов();
ЗаполнитьКолонки();
ЗаполнитьПодчиненныеТаблицы();
Рефлектор = Новый Рефлектор;

КонецПроцедуры

Функция ИмяТаблицы() Экспорт
Expand All @@ -32,30 +37,26 @@
Возврат ИсточникиДанных;
КонецФункции

// Возвращает таблицу колонок модели.
//
// Возвращаемое значение:
// ТаблицаЗначений - Колонки модели, только для чтения.
//
Функция Колонки() Экспорт
Возврат Колонки.Скопировать();
Возврат Колонки;
КонецФункции

Функция ПодчиненныеТаблицы() Экспорт
Возврат ПодчиненныеТаблицы.Скопировать();
КонецФункции

// @internal
// TODO: вынести отсюда. Возможно стоит разработать отдельный служебный билдер Объекта модели,
// вытащив заполнение из конструктора в этот билдер, а в конструктор передавать уже готовые для сохранения
// в объект данные.
//
Функция Служебный_Колонки() Экспорт
Возврат Колонки;
КонецФункции

// @internal
Процедура Служебный_ИмяТаблицы(ПИмяТаблицы) Экспорт
ИмяТаблицы = ПИмяТаблицы;
КонецПроцедуры

Функция Идентификатор() Экспорт
Возврат Новый ФиксированнаяСтруктура(Идентификатор);
Возврат Идентификатор;
КонецФункции

Функция МодельДанных() Экспорт
Expand All @@ -72,10 +73,9 @@
КонецФункции

Функция ПолучитьПриведенноеЗначениеПоля(Сущность, ИмяПоля) Экспорт
Колонка = КолонкаПоИмениПоля(ИмяПоля);
ЗначениеПоля = ПолучитьЗначениеПоля(Сущность, ИмяПоля);

Колонка = Колонки().Найти(ИмяПоля, "ИмяПоля");


Если Колонка.ТипКолонки = ТипыКолонок.Ссылка Тогда
ОбъектМоделиСсылки = МодельДанных.Получить(Колонка.ТипСсылки);
Если ЗначениеПоля = Неопределено Тогда
Expand All @@ -94,8 +94,8 @@

Процедура УстановитьЗначениеКолонкиВПоле(Сущность, ИмяКолонки, ЗначениеПоля) Экспорт

Колонка = Колонки().Найти(ИмяКолонки, "ИмяКолонки");
Колонка = КолонкаПоИмениКолонки(ИмяКолонки);

Если Колонка.ТипКолонки = ТипыКолонок.Ссылка Тогда
УстанавливаемоеЗначениеПоля = ЗначениеПоля;
Иначе
Expand All @@ -112,11 +112,27 @@

Функция ПривестиЗначениеПоля(ЗначениеПоля, ИмяПоля) Экспорт

Колонка = Колонки().Найти(ИмяПоля, "ИмяПоля");
Колонка = КолонкаПоИмениПоля(ИмяПоля);
Возврат ВыполнитьПриведениеЗначения(Колонка, ЗначениеПоля);

КонецФункции

Функция КолонкаПоИмениПоля(Знач ИмяПоля)
Колонка = Колонки.Найти(ИмяПоля, "ИмяПоля");
Если Колонка = Неопределено Тогда
ВызватьИсключение СтрШаблон("В модели сущности %1 нет поля %2", ТипСущности, ИмяПоля);
КонецЕсли;
Возврат Колонка;
КонецФункции

Функция КолонкаПоИмениКолонки(Знач ИмяКолонки)
Колонка = Колонки.Найти(ИмяКолонки, "ИмяКолонки");
Если Колонка = Неопределено Тогда
ВызватьИсключение СтрШаблон("В модели сущности %1 нет колонки %2", ТипСущности, ИмяКолонки);
КонецЕсли;
Возврат Колонка;
КонецФункции

Функция ПолучитьЗначениеПоля(Сущность, ИмяПоля) Экспорт
ЗначениеПоля = Рефлектор.ПолучитьСвойство(Сущность, ИмяПоля);
Возврат ЗначениеПоля;
Expand Down Expand Up @@ -173,6 +189,13 @@
ЗаполнитьЗначенияСвойств(Колонки.Добавить(), ДанныеОКолонке);
КонецЦикла;

Колонки.Индексы.Добавить("ИмяПоля");
Колонки.Индексы.Добавить("ИмяКолонки");

Если Идентификатор <> Неопределено Тогда
Идентификатор = Новый ФиксированнаяСтруктура(Идентификатор);

Check warning on line 196 in src/Классы/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

src/Классы/ОбъектМодели.os#L196

Укажите обязательный параметр 'args'
КонецЕсли;

КонецПроцедуры

Процедура ЗаполнитьПодчиненныеТаблицы()
Expand Down Expand Up @@ -300,10 +323,8 @@
КонецЕсли;

ОбработанноеЗначение = Значение;

КартаОписанийТипов = СоответствиеТиповМоделиОписанийТипов();

ОписаниеТипов = КартаОписанийТипов.Получить(Колонка.ТипКолонки);

ОписаниеТипов = ОписанияТиповКолонок.Получить(Колонка.ТипКолонки);
Если ОписаниеТипов = Неопределено Тогда
ВызватьИсключение "Неизвестный тип колонки " + Колонка.ИмяКолонки;
КонецЕсли;
Expand Down
135 changes: 134 additions & 1 deletion tests/ОбъектМодели.os
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,138 @@
Ожидаем.Что(ИсточникиДанных, "Объект модели имеет источники данных").ИмеетДлину(2);
Ожидаем.Что(ИсточникиДанных[0], "Первый источник данных имеет корректное имя").Равно("Основной");
Ожидаем.Что(ИсточникиДанных[1], "Второй источник данных имеет корректное имя").Равно("Дополнительный");


КонецПроцедуры

// Колонки() отдает саму таблицу модели, без копии на каждое обращение.
&Тест
Процедура КолонкиОтдаютТаблицуМодели() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Ожидаем.Что(ОбъектМодели.Колонки(), "Повторное обращение отдает ту же таблицу")
.Равно(ОбъектМодели.Колонки());

КонецПроцедуры

// Колонка ищется по имени поля и по имени колонки - по каждому из них есть индекс.
&Тест
Процедура КолонкиИндексированыПоИменам() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Индексы = Новый Массив;
Для Каждого Индекс Из ОбъектМодели.Колонки().Индексы Цикл
Индексы.Добавить(Строка(Индекс));
КонецЦикла;

Ожидаем.Что(Индексы, "Есть индекс по имени поля").Содержит("ИмяПоля");
Ожидаем.Что(Индексы, "Есть индекс по имени колонки").Содержит("ИмяКолонки");

КонецПроцедуры

// Так ОбработкаКоллекций донастраивает типы колонок объекта модели элемента коллекции: правка
// таблицы колонок видна и поиску колонки, и приведению значения.
&Тест
Процедура ИзменениеКолонокМеняетПриведение() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

ОбъектМодели.Колонки().Найти("Имя", "ИмяПоля").ТипКолонки = ТипыКолонок.Целое;

Check notice on line 81 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L81

Необходимо избавиться от многократного использования строкового литерала "Имя"

Ожидаем.Что(ОбъектМодели.Колонки().Найти("Имя", "ИмяПоля").ТипКолонки, "Модель видит правку")
.Равно(ТипыКолонок.Целое);
Ожидаем.Что(ОбъектМодели.ПривестиЗначениеПоля("12", "Имя"), "Поле приводится по новому типу")
.Равно(12);

Check notice on line 86 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L86

Создайте константу с понятным названием, присвойте ей значение "12" и используйте эту константу вместо магического числа.

Автор = Новый Автор;
ОбъектМодели.УстановитьЗначениеКолонкиВПоле(Автор, "Имя", "12");
Ожидаем.Что(Автор.Имя, "Колонка устанавливается по новому типу").Равно(12);

Check notice on line 90 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L90

Создайте константу с понятным названием, присвойте ей значение "12" и используйте эту константу вместо магического числа.

Автор.Имя = "34";
Ожидаем.Что(ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(Автор, "Имя"), "Значение поля приводится по новому типу")
.Равно(34);

Check notice on line 94 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L94

Создайте константу с понятным названием, присвойте ей значение "34" и используйте эту константу вместо магического числа.

КонецПроцедуры

// Поле ищется по имени поля, колонка - по имени колонки: у поля ВтороеИмя колонка Фамилия.
&Тест
Процедура ПолеИКолонкаИщутсяКаждыйПоСвоемуИмени() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Автор = Новый Автор;
ОбъектМодели.УстановитьЗначениеКолонкиВПоле(Автор, "Фамилия", "Иванов");

Check notice on line 105 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L105

Необходимо избавиться от многократного использования строкового литерала "Иванов"
Ожидаем.Что(Автор.ВтороеИмя, "Колонка Фамилия пишется в поле ВтороеИмя").Равно("Иванов");

Ожидаем.Что(ОбъектМодели.ПривестиЗначениеПоля(5, "ВтороеИмя"), "Поле ВтороеИмя приводится к строке")

Check notice on line 108 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L108

Создайте константу с понятным названием, присвойте ей значение "5" и используйте эту константу вместо магического числа.
.Равно("5");
Ожидаем.Что(ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(Автор, "ВтороеИмя"), "Поле ВтороеИмя читается")
.Равно("Иванов");

КонецПроцедуры

&Тест
Процедура НеизвестноеПолеНеПриводится() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Параметры = Новый Массив;
Параметры.Добавить(1);
Параметры.Добавить("НетТакогоПоля");

Ожидаем.Что(ОбъектМодели)
.Метод("ПривестиЗначениеПоля", Параметры)
.ВыбрасываетИсключение("В модели сущности Автор нет поля НетТакогоПоля");

КонецПроцедуры

&Тест
Процедура НеизвестнаяКолонкаНеУстанавливается() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Параметры = Новый Массив;
Параметры.Добавить(Новый Автор);
Параметры.Добавить("НетТакойКолонки");
Параметры.Добавить(1);

Ожидаем.Что(ОбъектМодели)
.Метод("УстановитьЗначениеКолонкиВПоле", Параметры)
.ВыбрасываетИсключение("В модели сущности Автор нет колонки НетТакойКолонки");

КонецПроцедуры

&Тест
Процедура НеизвестноеПолеНеЧитается() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Параметры = Новый Массив;
Параметры.Добавить(Новый Автор);
Параметры.Добавить("НетТакогоПоля");

Ожидаем.Что(ОбъектМодели)
.Метод("ПолучитьПриведенноеЗначениеПоля", Параметры)
.ВыбрасываетИсключение("В модели сущности Автор нет поля НетТакогоПоля");

КонецПроцедуры

// Идентификатор отдается неизменяемым: правка результата невозможна и модель не меняет.
&Тест
Процедура ИдентификаторНеизменяем() Экспорт

ОбъектМодели = НовыйОбъектМоделиАвтора();

Ожидаем.Что(ТипЗнч(ОбъектМодели.Идентификатор()), "Идентификатор - фиксированная структура")
.Равно(Тип("ФиксированнаяСтруктура"));
Ожидаем.Что(ОбъектМодели.Идентификатор(), "Повторное обращение отдает тот же идентификатор")
.Равно(ОбъектМодели.Идентификатор());

КонецПроцедуры

Функция НовыйОбъектМоделиАвтора()
ПодключитьСценарий(ОбъединитьПути(ТекущийКаталог(), "tests", "fixtures", "Автор.os"), "Автор");
ПодключитьСценарий(ОбъединитьПути(ТекущийКаталог(), "tests", "fixtures", "СущностьБезГенерируемогоИдентификатора.os"), "СущностьБезГенерируемогоИдентификатора");

Check notice on line 176 in tests/ОбъектМодели.os

View check run for this annotation

sonar.openbsl.ru qa-bot / SonarQube Code Analysis

tests/ОбъектМодели.os#L176

Длина строки 162 превышает максимально допустимую 120
Возврат Новый ОбъектМодели(Тип("Автор"), Неопределено);
КонецФункции
Loading