From 7ecedd2647fe523f2219a3ed3c734051676b8311 Mon Sep 17 00:00:00 2001 From: sfaqer Date: Fri, 2 Oct 2026 23:06:57 +1000 Subject: [PATCH] =?UTF-8?q?fix(model):=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=20=D0=B8=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BE=D0=BA=20=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20=D0=B3=D0=BE=D0=BD=D0=BE=D0=BA=20=D0=BC=D0=B5?= =?UTF-8?q?=D0=B6=D0=B4=D1=83=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BA=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - МодельДанных хранит объекты модели в СинхронизированнаяКарта и обходит ее через ДляКаждого: регистрация класса параллельно операциям больше не роняет обход модели ("Collection was modified"). Повторная регистрация типа не подменяет объект модели, с которым уже работают хранилища. - ОбъектМодели.Колонки() снова отдает копию: правка результата не меняет общую модель. Библиотека и встроенные коннекторы читают таблицу без копии через служебный Служебный_Колонки(). - Имя таблицы объекта модели подчиненной таблицы передается третьим параметром конструктора ОбъектМодели; мутатор Служебный_ИмяТаблицы удален. - ТипыКолонок.Типы() и ТипыПодчиненныхТаблиц.Типы() отдают ФиксированныйМассив. Изменения поведения: Колонки() - копия, как до #151; Типы() нельзя менять. Co-Authored-By: Claude Opus 5.5 --- ...20\276\321\201\321\202\320\265\320\271.md" | 4 + ...20\260\320\275\320\275\321\213\321\205.md" | 32 ++- ...20\276\320\264\320\265\320\273\320\270.md" | 24 +- ...20\273\320\276\320\275\320\276\320\272.md" | 7 +- ...20\260\320\261\320\273\320\270\321\206.md" | 6 +- ...20\265\320\272\321\206\320\270\320\271.os" | 6 +- ...20\276\321\200\320\260\320\274\320\270.os" | 6 +- ...265\320\272\321\202\320\276\321\200SQL.os" | 6 +- ...20\272\321\202\320\276\321\200InMemory.os" | 10 +- ...65\320\272\321\202\320\276\321\200JSON.os" | 8 +- ...\272\321\202\320\276\321\200PostgreSQL.os" | 2 +- ...\320\272\321\202\320\276\321\200SQLite.os" | 2 +- ...20\276\321\201\321\202\320\265\320\271.os" | 4 + ...20\260\320\275\320\275\321\213\321\205.os" | 55 ++++- ...20\276\320\264\320\265\320\273\320\270.os" | 41 +++- ...20\273\320\276\320\275\320\276\320\272.os" | 47 ++-- ...20\260\320\261\320\273\320\270\321\206.os" | 13 +- ...20\260\320\275\320\275\321\213\321\205.os" | 214 ++++++++++++++++++ ...20\276\320\264\320\265\320\273\320\270.os" | 64 +++++- ...20\273\320\276\320\275\320\276\320\272.os" | 21 ++ 20 files changed, 489 insertions(+), 83 deletions(-) create mode 100644 "tests/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" create mode 100644 "tests/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" diff --git "a/docs/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.md" "b/docs/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.md" index dd16e32b..2398e1d0 100644 --- "a/docs/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.md" +++ "b/docs/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.md" @@ -25,6 +25,10 @@ ```bsl // Регистрирует переданный тип класса-сценария в модели данных. // +// Повторная регистрация типа модель не меняет: остается прежний объект модели, с которым уже +// работают хранилища. Регистрировать классы можно и после передачи менеджера другим потокам, но +// таблицы создает Инициализировать, поэтому обычно классы регистрируют до него. +// // Параметры: // ТипСущности - Тип - Тип для добавления в модель // diff --git "a/docs/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.md" "b/docs/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.md" index 0d428dd5..08463e69 100644 --- "a/docs/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.md" +++ "b/docs/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.md" @@ -1,5 +1,8 @@ ## МодельДанных +Модель общая у всех потоков, работающих с менеджером: операции читают ее на каждом шаге, а классы +можно регистрировать и после передачи менеджера другим потокам. + ### ПриСозданииОбъекта ```bsl @@ -10,21 +13,44 @@ ### Получить ```bsl - +// Возвращает объект модели типа сущности. +// +// Параметры: +// ТипСущности - Тип - Тип сущности. +// +// Возвращаемое значение: +// ОбъектМодели - Объект модели типа. +// Неопределено - Тип не зарегистрирован в модели. +// Функция Получить(ТипСущности) Экспорт ``` ### ПолучитьОбъектыМодели ```bsl - +// Возвращает объекты модели всех зарегистрированных типов. +// +// Возвращаемое значение: +// Массив из ОбъектМодели - Копия на момент вызова: типы, зарегистрированные позже, в нее не +// попадут. +// Функция ПолучитьОбъектыМодели() Экспорт ``` ### СоздатьОбъектМодели ```bsl - +// Регистрирует тип сущности в модели. +// +// Если тип уже зарегистрирован, возвращается существующий объект модели: с ним уже могут работать +// хранилища и операции других потоков, поэтому он не подменяется. +// +// Параметры: +// ТипСущности - Тип - Тип сущности. +// +// Возвращаемое значение: +// ОбъектМодели - Объект модели типа. +// Функция СоздатьОбъектМодели(ТипСущности) Экспорт ``` diff --git "a/docs/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.md" "b/docs/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.md" index 3c3d21b7..b6c9f178 100644 --- "a/docs/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.md" +++ "b/docs/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.md" @@ -3,8 +3,16 @@ ### ПриСозданииОбъекта ```bsl - -Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных) +// Создает объект модели по аннотациям класса сущности. +// +// Параметры: +// ПТипСущности - Тип - Тип класса сущности. +// ПМодельДанных - МодельДанных - Модель, к которой относится объект. +// ПИмяТаблицы - Строка - Имя таблицы вместо имени из аннотации класса. Так создаются объекты +// модели подчиненных таблиц: класс элемента у них один, а таблицы разные. +// - Неопределено - Имя таблицы берется из аннотации класса. +// +Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных, ПИмяТаблицы = Неопределено) ``` ### ИмяТаблицы @@ -19,8 +27,11 @@ ```bsl // Возвращает таблицу колонок модели. // +// Объект модели общий у всех потоков, работающих с менеджером, поэтому отдается копия: ее можно +// менять, модель от этого не изменится. +// // Возвращаемое значение: -// ТаблицаЗначений - Колонки модели, только для чтения. +// ТаблицаЗначений - Копия колонок модели. // Функция Колонки() Экспорт ``` @@ -32,13 +43,6 @@ Функция ПодчиненныеТаблицы() Экспорт ``` -### Служебный_ИмяТаблицы - -```bsl -// @internal -Процедура Служебный_ИмяТаблицы(ПИмяТаблицы) Экспорт -``` - ### Идентификатор ```bsl diff --git "a/docs/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.md" "b/docs/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.md" index 22568002..21d52667 100644 --- "a/docs/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.md" +++ "b/docs/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.md" @@ -10,11 +10,16 @@ * Время * ДатаВремя * Ссылка +* ДвоичныеДанные ### Типы ```bsl - +// Возвращает все типы колонок модели. +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка - Имена типов колонок. +// Функция Типы() Экспорт ``` diff --git "a/docs/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.md" "b/docs/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.md" index dcc4b5a3..6b06169c 100644 --- "a/docs/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.md" +++ "b/docs/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.md" @@ -8,7 +8,11 @@ ### Типы ```bsl - +// Возвращает все типы подчиненных таблиц. +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка - Имена типов подчиненных таблиц. +// Функция Типы() Экспорт ``` diff --git "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\232\320\276\320\273\320\273\320\265\320\272\321\206\320\270\320\271.os" "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\232\320\276\320\273\320\273\320\265\320\272\321\206\320\270\320\271.os" index e2af1cf6..f7e4e64c 100644 --- "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\232\320\276\320\273\320\273\320\265\320\272\321\206\320\270\320\271.os" +++ "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\232\320\276\320\273\320\273\320\265\320\272\321\206\320\270\320\271.os" @@ -89,12 +89,12 @@ ОбъектМоделиЭлементКоллекции = Новый ОбъектМодели( Тип("СлужебнаяСущность_ЭлементКоллекцииКлючЗначение"), - РодительскийОбъектМодели.МодельДанных() + РодительскийОбъектМодели.МодельДанных(), + ПодчиненнаяТаблица.ИмяТаблицы ); - ОбъектМоделиЭлементКоллекции.Служебный_ИмяТаблицы(ПодчиненнаяТаблица.ИмяТаблицы); // Колонки модели только для чтения, но этот объект модели только что создан и еще никому не отдан. - КолонкиОбъектаМодели = ОбъектМоделиЭлементКоллекции.Колонки(); + КолонкиОбъектаМодели = ОбъектМоделиЭлементКоллекции.Служебный_Колонки(); КолонкаKey = КолонкиОбъектаМодели.Найти("key", "ИмяКолонки"); КолонкаKey.ТипКолонки = ТипКолонкиКлюч; diff --git "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\240\320\260\320\261\320\276\321\202\320\260\320\241\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200\320\260\320\274\320\270.os" "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\240\320\260\320\261\320\276\321\202\320\260\320\241\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200\320\260\320\274\320\270.os" index 5cd1bc2c..20114742 100644 --- "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\240\320\260\320\261\320\276\321\202\320\260\320\241\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200\320\260\320\274\320\270.os" +++ "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\240\320\260\320\261\320\276\321\202\320\260\320\241\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200\320\260\320\274\320\270.os" @@ -68,7 +68,7 @@ // Функция Получить(Менеджер, ОбъектМодели, ПулСущностей, ОпцииПоиска) Экспорт - ПередаваемыеОпцииПоиска = ПреобразоватьОпцииПоиска(ОбъектМодели.Колонки(), ОпцииПоиска); + ПередаваемыеОпцииПоиска = ПреобразоватьОпцииПоиска(ОбъектМодели.Служебный_Колонки(), ОпцииПоиска); Возврат НайтиСущности(Менеджер, ОбъектМодели, ПулСущностей, ПередаваемыеОпцииПоиска, "Получить"); @@ -139,7 +139,7 @@ ПередаваемыеОпцииПоиска.Отбор(ОбъектМодели.Идентификатор().ИмяПоля, ВидСравнения.Равно, ОпцииПоиска); КонецЕсли; - ПередаваемыеОпцииПоиска = ПреобразоватьОпцииПоиска(ОбъектМодели.Колонки(), ПередаваемыеОпцииПоиска); + ПередаваемыеОпцииПоиска = ПреобразоватьОпцииПоиска(ОбъектМодели.Служебный_Колонки(), ПередаваемыеОпцииПоиска); НайденныеСущности = НайтиСущности(Менеджер, ОбъектМодели, ПулСущностей, ПередаваемыеОпцииПоиска, "ПолучитьОдно"); @@ -539,7 +539,7 @@ // Процедура ЗаполнитьКолонки(Сущность, НайденнаяСтрока, Менеджер, ОбъектМодели, Знач ЗначениеИдентификатора) - Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл + Для Каждого Колонка Из ОбъектМодели.Служебный_Колонки() Цикл ЗначениеКолонки = НайденнаяСтрока.Получить(Колонка.ИмяКолонки); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\261\321\201\321\202\321\200\320\260\320\272\321\202\320\275\321\213\320\271\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQL.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\261\321\201\321\202\321\200\320\260\320\272\321\202\320\275\321\213\320\271\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQL.os" index 388e077e..86a2c4b8 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\261\321\201\321\202\321\200\320\260\320\272\321\202\320\275\321\213\320\271\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQL.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\261\321\201\321\202\321\200\320\260\320\272\321\202\320\275\321\213\320\271\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQL.os" @@ -184,8 +184,8 @@ Функция НайтиСтрокиВТаблице(ОбъектМодели, ОпцииПоиска) Экспорт НайденныеСтроки = Новый Массив; - Колонки = ОбъектМодели.Колонки(); - + Колонки = ОбъектМодели.Служебный_Колонки(); + Запрос = Коннектор.КонструкторКоннектора.НовыйЗапрос(Коннектор.Соединение); ТекстЗапроса = СтрШаблон( @@ -304,7 +304,7 @@ ТекстЗапроса = ШаблонСозданияТаблицы; - КолонкиТаблицы = ОбъектМодели.Колонки(); + КолонкиТаблицы = ОбъектМодели.Служебный_Колонки(); Идентификатор = ОбъектМодели.Идентификатор(); СтрокаОпределенийКолонок = ""; СтрокаВнешнихКлючей = ""; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" index 8b5c9d4b..c7fae573 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" @@ -249,7 +249,7 @@ СущностьВБД = Новый (ОбъектМодели.ТипСущности()); - Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл + Для Каждого Колонка Из ОбъектМодели.Служебный_Колонки() Цикл Значение = ОбъектМодели.ПолучитьПриведенноеЗначениеПоля( Сущность, Колонка.ИмяПоля); @@ -374,8 +374,8 @@ ПроцессорКоллекций = ПроцессорыКоллекций.ИзКоллекции(Таблица); - Колонки = ОбъектМодели.Колонки(); - + Колонки = ОбъектМодели.Служебный_Колонки(); + Для Каждого ЭлементОтбора Из Отборы Цикл НайденныеКолонки = Колонки.НайтиСтроки(Новый Структура("ИмяКолонки", ЭлементОтбора.ПутьКДанным)); @@ -455,8 +455,8 @@ Результат = Новый Массив(); - Колонки = ОбъектМодели.Колонки(); - + Колонки = ОбъектМодели.Служебный_Колонки(); + Для Каждого СтрокаДанныхТаблицы Из ДанныеТаблицы Цикл ЗначенияКолонок = Новый Соответствие; Для Каждого Колонка Из Колонки Цикл diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200JSON.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200JSON.os" index a0498f6a..06df4353 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200JSON.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200JSON.os" @@ -368,7 +368,7 @@ Для Каждого СтрокаДанныхТаблицы Из ДанныеТаблицы Цикл ЗначенияКолонок = Новый Соответствие; - Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл + Для Каждого Колонка Из ОбъектМодели.Служебный_Колонки() Цикл Значение = ПрочитатьЗначениеКолонки(Колонка, СтрокаДанныхТаблицы.Значение.Получить(Колонка.ИмяКолонки)); ЗначенияКолонок.Вставить(Колонка.ИмяКолонки, Значение); КонецЦикла; @@ -424,7 +424,7 @@ // Функция ПолучитьВыражениеСортировки(ОбъектМодели, ОпцииПоиска) - Колонки = ОбъектМодели.Колонки(); + Колонки = ОбъектМодели.Служебный_Колонки(); СтрокаСортировка = ""; Для Каждого ЭлементПорядка Из ОпцииПоиска.Сортировки() Цикл @@ -537,7 +537,7 @@ Функция РазложитьОбъектВСоответствие(Значение, ОбъектМодели) Соответствие = Новый Соответствие; - Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл + Для Каждого Колонка Из ОбъектМодели.Служебный_Колонки() Цикл ЗначениеПараметра = ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(Значение, Колонка.ИмяПоля); Если Колонка.ТипКолонки = ТипыКолонок.ДвоичныеДанные И ЗначениеПараметра <> Неопределено Тогда ЗначениеПараметра = ПолучитьBase64СтрокуИзДвоичныхДанных(ЗначениеПараметра); @@ -557,7 +557,7 @@ Процедура ВосстановитьДатыВТаблице(Таблица, ОбъектМодели) КолонкиДат = Новый Массив; - Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл + Для Каждого Колонка Из ОбъектМодели.Служебный_Колонки() Цикл Если Колонка.ТипКолонки = ТипыКолонок.Дата ИЛИ Колонка.ТипКолонки = ТипыКолонок.Время ИЛИ Колонка.ТипКолонки = ТипыКолонок.ДатаВремя Тогда diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200PostgreSQL.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200PostgreSQL.os" index 30e0b43c..1abb7e43 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200PostgreSQL.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200PostgreSQL.os" @@ -133,7 +133,7 @@ Процедура Сохранить(ОбъектМодели, Сущность) Экспорт ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); - КолонкиТаблицы = ОбъектМодели.Колонки(); + КолонкиТаблицы = ОбъектМодели.Служебный_Колонки(); Запрос = КонструкторКоннектора.НовыйЗапрос(Соединение); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQLite.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQLite.os" index 6a22b4bd..477fde52 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQLite.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200SQLite.os" @@ -132,7 +132,7 @@ Процедура Сохранить(ОбъектМодели, Сущность) Экспорт ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); - КолонкиТаблицы = ОбъектМодели.Колонки(); + КолонкиТаблицы = ОбъектМодели.Служебный_Колонки(); Запрос = КонструкторКоннектора.НовыйЗапрос(Соединение); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.os" index 8d5fe2f3..eb0c9c91 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\241\321\203\321\211\320\275\320\276\321\201\321\202\320\265\320\271.os" @@ -67,6 +67,10 @@ // Регистрирует переданный тип класса-сценария в модели данных. // +// Повторная регистрация типа модель не меняет: остается прежний объект модели, с которым уже +// работают хранилища. Регистрировать классы можно и после передачи менеджера другим потокам, но +// таблицы создает Инициализировать, поэтому обычно классы регистрируют до него. +// // Параметры: // ТипСущности - Тип - Тип для добавления в модель // diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" index 538f3bbc..02f1479e 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" @@ -1,25 +1,60 @@ +#Использовать collectionos + +// СинхронизированнаяКарта - Тип сущности: ее объект модели. Модель общая у всех потоков, работающих +// с менеджером: операции читают ее на каждом шаге, а классы можно регистрировать и после передачи +// менеджера другим потокам. Поэтому карта синхронизированная, и обходится только через ДляКаждого - +// под ее блокировкой. Перем ХранилищеМодели; Процедура ПриСозданииОбъекта() - ХранилищеМодели = Новый Соответствие; + ХранилищеМодели = Новый СинхронизированнаяКарта(Новый КартаСоответствие()); КонецПроцедуры +// Возвращает объект модели типа сущности. +// +// Параметры: +// ТипСущности - Тип - Тип сущности. +// +// Возвращаемое значение: +// ОбъектМодели - Объект модели типа. +// Неопределено - Тип не зарегистрирован в модели. +// Функция Получить(ТипСущности) Экспорт - Возврат ХранилищеМодели.Получить(ТипСущности); + Возврат ХранилищеМодели.ПолучитьИлиУмолчание(ТипСущности, Неопределено); КонецФункции +// Возвращает объекты модели всех зарегистрированных типов. +// +// Возвращаемое значение: +// Массив из ОбъектМодели - Копия на момент вызова: типы, зарегистрированные позже, в нее не +// попадут. +// Функция ПолучитьОбъектыМодели() Экспорт - ВсеОбъектыМодели = Новый Массив; - Для Каждого КлючИЗначение Из ХранилищеМодели Цикл - ВсеОбъектыМодели.Добавить(КлючИЗначение.Значение); - КонецЦикла; - - Возврат ВсеОбъектыМодели; + + Результат = Новый Массив; + ХранилищеМодели.ДляКаждого("(К, З) -> Результат.Добавить(З)", Новый Структура("Результат", Результат)); + + Возврат Результат; + КонецФункции +// Регистрирует тип сущности в модели. +// +// Если тип уже зарегистрирован, возвращается существующий объект модели: с ним уже могут работать +// хранилища и операции других потоков, поэтому он не подменяется. +// +// Параметры: +// ТипСущности - Тип - Тип сущности. +// +// Возвращаемое значение: +// ОбъектМодели - Объект модели типа. +// Функция СоздатьОбъектМодели(ТипСущности) Экспорт + + // Объект строится вне карты: конструктор разбирает аннотации класса, и держать на это время + // блокировку карты, которую читают все операции, незачем. ОбъектМодели = Новый ОбъектМодели(ТипСущности, ЭтотОбъект); - ХранилищеМодели.Вставить(ТипСущности, ОбъектМодели); - Возврат ОбъектМодели; + Возврат ХранилищеМодели.ВставитьЕслиОтсутствует(ТипСущности, ОбъектМодели).Иначе_(ОбъектМодели); + КонецФункции diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" index c5704879..d55feeb6 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" @@ -18,7 +18,16 @@ Перем Рефлектор; -Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных) +// Создает объект модели по аннотациям класса сущности. +// +// Параметры: +// ПТипСущности - Тип - Тип класса сущности. +// ПМодельДанных - МодельДанных - Модель, к которой относится объект. +// ПИмяТаблицы - Строка - Имя таблицы вместо имени из аннотации класса. Так создаются объекты +// модели подчиненных таблиц: класс элемента у них один, а таблицы разные. +// - Неопределено - Имя таблицы берется из аннотации класса. +// +Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных, ПИмяТаблицы = Неопределено) МодельДанных = ПМодельДанных; ТипСущности = ПТипСущности; @@ -27,6 +36,10 @@ ЗаполнитьПодчиненныеТаблицы(); Рефлектор = Новый Рефлектор; + Если ПИмяТаблицы <> Неопределено Тогда + ИмяТаблицы = ПИмяТаблицы; + КонецЕсли; + КонецПроцедуры Функция ИмяТаблицы() Экспорт @@ -39,10 +52,29 @@ // Возвращает таблицу колонок модели. // +// Объект модели общий у всех потоков, работающих с менеджером, поэтому отдается копия: ее можно +// менять, модель от этого не изменится. +// // Возвращаемое значение: -// ТаблицаЗначений - Колонки модели, только для чтения. +// ТаблицаЗначений - Копия колонок модели. // Функция Колонки() Экспорт + Возврат Колонки.Скопировать(); +КонецФункции + +// BSLLS:UsingServiceTag-off +// @internal +// BSLLS:UsingServiceTag-on +// Возвращает саму таблицу колонок модели, без копии. Так колонки читают библиотека и встроенные +// коннекторы: копия на каждое обращение стоила бы дорого. +// +// Таблица общая у всех потоков и только читается. Менять ее можно лишь у объекта модели, который +// еще никому не передан: так ОбработкаКоллекций настраивает объект модели элемента коллекции. +// +// Возвращаемое значение: +// ТаблицаЗначений - Колонки модели. +// +Функция Служебный_Колонки() Экспорт Возврат Колонки; КонецФункции @@ -50,11 +82,6 @@ Возврат ПодчиненныеТаблицы.Скопировать(); КонецФункции -// @internal -Процедура Служебный_ИмяТаблицы(ПИмяТаблицы) Экспорт - ИмяТаблицы = ПИмяТаблицы; -КонецПроцедуры - Функция Идентификатор() Экспорт Возврат Идентификатор; КонецФункции diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" index a31fe188..11e78d8d 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" @@ -8,9 +8,16 @@ Перем Ссылка Экспорт; Перем ДвоичныеДанные Экспорт; +// ФиксированныйМассив - Все типы колонок. Перем Типы; +// ФиксированныйМассив - Примитивные типы колонок. Перем ПримитивныеТипы; +// Возвращает все типы колонок модели. +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка - Имена типов колонок. +// Функция Типы() Экспорт Возврат Типы; КонецФункции @@ -68,23 +75,25 @@ Ссылка = "Ссылка"; ДвоичныеДанные = "ДвоичныеДанные"; -Типы = Новый Массив; -Типы.Добавить(Целое); -Типы.Добавить(Дробное); -Типы.Добавить(Булево); -Типы.Добавить(Строка); -Типы.Добавить(Дата); -Типы.Добавить(Время); -Типы.Добавить(ДатаВремя); -Типы.Добавить(Ссылка); -Типы.Добавить(ДвоичныеДанные); +ВсеТипы = Новый Массив; +ВсеТипы.Добавить(Целое); +ВсеТипы.Добавить(Дробное); +ВсеТипы.Добавить(Булево); +ВсеТипы.Добавить(Строка); +ВсеТипы.Добавить(Дата); +ВсеТипы.Добавить(Время); +ВсеТипы.Добавить(ДатаВремя); +ВсеТипы.Добавить(Ссылка); +ВсеТипы.Добавить(ДвоичныеДанные); +Типы = Новый ФиксированныйМассив(ВсеТипы); -ПримитивныеТипы = Новый Массив; -ПримитивныеТипы.Добавить(Целое); -ПримитивныеТипы.Добавить(Дробное); -ПримитивныеТипы.Добавить(Булево); -ПримитивныеТипы.Добавить(Строка); -ПримитивныеТипы.Добавить(Дата); -ПримитивныеТипы.Добавить(Время); -ПримитивныеТипы.Добавить(ДатаВремя); -ПримитивныеТипы.Добавить(ДвоичныеДанные); \ No newline at end of file +Примитивные = Новый Массив; +Примитивные.Добавить(Целое); +Примитивные.Добавить(Дробное); +Примитивные.Добавить(Булево); +Примитивные.Добавить(Строка); +Примитивные.Добавить(Дата); +Примитивные.Добавить(Время); +Примитивные.Добавить(ДатаВремя); +Примитивные.Добавить(ДвоичныеДанные); +ПримитивныеТипы = Новый ФиксированныйМассив(Примитивные); \ No newline at end of file diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.os" index a8d1edd3..eca59a98 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\321\213\320\237\320\276\320\264\321\207\320\270\320\275\320\265\320\275\320\275\321\213\321\205\320\242\320\260\320\261\320\273\320\270\321\206.os" @@ -1,8 +1,14 @@ Перем Массив Экспорт; Перем Структура Экспорт; +// ФиксированныйМассив - Все типы подчиненных таблиц. Перем Типы; +// Возвращает все типы подчиненных таблиц. +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка - Имена типов подчиненных таблиц. +// Функция Типы() Экспорт Возврат Типы; КонецФункции @@ -10,6 +16,7 @@ Массив = "Массив"; Структура = "Структура"; -Типы = Новый Массив; -Типы.Добавить(Массив); -Типы.Добавить(Структура); +ВсеТипы = Новый Массив; +ВсеТипы.Добавить(Массив); +ВсеТипы.Добавить(Структура); +Типы = Новый ФиксированныйМассив(ВсеТипы); diff --git "a/tests/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" "b/tests/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" new file mode 100644 index 00000000..5df345ab --- /dev/null +++ "b/tests/\320\234\320\276\320\264\320\265\320\273\321\214\320\224\320\260\320\275\320\275\321\213\321\205.os" @@ -0,0 +1,214 @@ +// Модель данных менеджера: регистрация классов и чтение объектов модели. +// +// Модель общая у всех потоков, работающих с менеджером: операции читают ее на каждом шаге, а +// классы можно регистрировать и после передачи менеджера другим потокам. Тесты проверяют, что +// поздняя регистрация не ломает идущие операции, а повторная не подменяет объект модели, с которым +// уже работают хранилища. +// +// BSLLS:MagicNumber-off +// BSLLS:LatinAndCyrillicSymbolInWord-off +// BSLLS:DuplicateStringLiteral-off + +#Использовать ".." +#Использовать "utils" + +// ИсточникДанных - Источник тестовой базы; закрывается после каждого теста. +Перем Источник; +// МенеджерСущностей - Менеджер, который тесты создают заново перед каждым тестом. +Перем МенеджерСущностей; +// Строка - Каталог классов, сгенерированных тестом; Неопределено, если тест их не создавал. +Перем КаталогКлассов; + +&ПередКаждым +Процедура ПередЗапускомТеста() Экспорт + + ХранилищеВПамяти.Очистить("МодельДанных"); + ТестовыеУтилиты.ПодключитьКлассыСущностей(); + ПодключитьСценарий(ОбъединитьПути(ТекущийКаталог(), "tests", "fixtures", "СигналСобытия.os"), "СигналСобытия"); + + Источник = Новый ИсточникДанных("Тесты", Тип("КоннекторInMemory"), "МодельДанных"); + // oneunit исполняет подготовку и тест в разных потоках: источник живет до ПослеКаждого. + Источник.УстановитьАвтоЗакрытие(Ложь); + МенеджерСущностей = Новый МенеджерСущностей(Источник); + + // Автор ссылается на СущностьБезГенерируемогоИдентификатора, поэтому в модели нужны обе. + МенеджерСущностей.ДобавитьКлассВМодель(Тип("СущностьБезГенерируемогоИдентификатора")); + МенеджерСущностей.ДобавитьКлассВМодель(Тип("Автор")); + + КаталогКлассов = Неопределено; + +КонецПроцедуры + +&ПослеКаждого +Процедура ПослеЗапускаТеста() Экспорт + + МенеджерСущностей.Закрыть(); + МенеджерСущностей = Неопределено; + Источник.Закрыть(); + + Если КаталогКлассов <> Неопределено Тогда + УдалитьФайлы(КаталогКлассов); + КаталогКлассов = Неопределено; + КонецЕсли; + +КонецПроцедуры + +// Класс регистрируют повторно, когда с ним уже работают. Модель должна вернуть тот же объект +// модели: иначе хранилище, созданное раньше, и новые операции работали бы с разными объектами +// одного типа. +// +&Тест +Процедура ПовторнаяРегистрацияНеПодменяетОбъектМодели() Экспорт + + Модель = МенеджерСущностей.ПолучитьМодельДанных(); + Прежний = Модель.Получить(Тип("Автор")); + Хранилище = МенеджерСущностей.ПолучитьХранилищеСущностей(Тип("Автор")); + + МенеджерСущностей.ДобавитьКлассВМодель(Тип("Автор")); + + Ожидаем.Что(Модель.Получить(Тип("Автор")) = Прежний, "Модель отдает прежний объект модели").ЭтоИстина(); + Ожидаем.Что( + Хранилище.ПолучитьОбъектМодели() = Модель.Получить(Тип("Автор")), + "Хранилище и модель работают с одним объектом модели" + ).ЭтоИстина(); + Ожидаем.Что( + Модель.СоздатьОбъектМодели(Тип("Автор")) = Прежний, + "Создание объекта модели для известного типа возвращает существующий" + ).ЭтоИстина(); + +КонецПроцедуры + +// Задание обходит модель так же, как Инициализировать, и ищет в ней каждый найденный тип, а тест в +// это время регистрирует 50 новых классов. Обход не должен падать на изменяемой модели, и все +// классы должны стать видны. +// +&Тест +Процедура РегистрацияКлассовПараллельноОбходуМоделиНеЛомаетОбход() Экспорт + + Типы = ПодключитьКлассыРегистрации(50); + Модель = МенеджерСущностей.ПолучитьМодельДанных(); + ОжидаемоеКоличество = Модель.ПолучитьОбъектыМодели().Количество() + Типы.Количество(); + НачалОбход = Новый СигналСобытия; + Стоп = Новый СигналСобытия; + + Параметры = Новый Массив; + Параметры.Добавить(Модель); + Параметры.Добавить(ОжидаемоеКоличество); + Параметры.Добавить(НачалОбход); + Параметры.Добавить(Стоп); + Задания = Новый Массив; + Задания.Добавить(ФоновыеЗадания.Выполнить(ЭтотОбъект, "ОбходитьМодельВФоне", Параметры, Истина)); + + Попытка + Ожидаем.Что(НачалОбход.Дождаться(), "Задание начало обход модели").ЭтоИстина(); + Для Каждого ТипСущности Из Типы Цикл + МенеджерСущностей.ДобавитьКлассВМодель(ТипСущности); + КонецЦикла; + Исключение + Ошибка = ИнформацияОбОшибке(); + Стоп.Отметить(); + ТестовыеУтилиты.СообщитьОЗаданиях(ТестовыеУтилиты.ДождатьсяЗаданий(Задания, СрокЗадания())); + ВызватьИсключение; + КонецПопытки; + + ТестовыеУтилиты.ПроверитьЗадания(Задания, СрокЗадания()); + + Для Каждого ТипСущности Из Типы Цикл + ОбъектМодели = Модель.Получить(ТипСущности); + Ожидаем.Что(ОбъектМодели <> Неопределено, СтрШаблон("Класс %1 есть в модели", ТипСущности)).ЭтоИстина(); + Ожидаем.Что(ОбъектМодели.ТипСущности(), "Объект модели описывает свой класс").Равно(ТипСущности); + КонецЦикла; + +КонецПроцедуры + +// Обходит модель в цикле, пока в ней не окажутся все ожидаемые классы. Каждый найденный при обходе +// объект модели ищется в модели по типу и должен найтись тем же. Запускается в фоновом задании. +// +// Параметры: +// Модель - МодельДанных - Модель менеджера теста. +// ОжидаемоеКоличество - Число - Сколько объектов модели будет после регистрации всех классов. +// НачалОбход - СигналСобытия - Отмечается после первого обхода. +// Стоп - СигналСобытия - Отмечается тестом, если регистрация упала. +// +Процедура ОбходитьМодельВФоне(Модель, ОжидаемоеКоличество, НачалОбход, Стоп) Экспорт + + КрайнийСрок = ТекущаяУниверсальнаяДатаВМиллисекундах() + 20000; + + Пока НЕ Стоп.Отмечен() Цикл + + ОбъектыМодели = Модель.ПолучитьОбъектыМодели(); + Для Каждого ОбъектМодели Из ОбъектыМодели Цикл + Если Модель.Получить(ОбъектМодели.ТипСущности()) <> ОбъектМодели Тогда + ВызватьИсключение СтрШаблон("Модель отдала по типу %1 другой объект", ОбъектМодели.ТипСущности()); + КонецЕсли; + КонецЦикла; + + НачалОбход.Отметить(); + + Если ОбъектыМодели.Количество() >= ОжидаемоеКоличество Тогда + Возврат; + КонецЕсли; + + Если ТекущаяУниверсальнаяДатаВМиллисекундах() >= КрайнийСрок Тогда + ВызватьИсключение СтрШаблон( + "За 20 с в модели не появились все классы: %1 из %2", + ОбъектыМодели.Количество(), + ОжидаемоеКоличество + ); + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +// Создает и подключает классы сущностей с уникальными в процессе именами. +// +// Подключение идет в потоке теста до запуска заданий: на движке 2.2 параллельное подключение +// сценариев само не потокобезопасно, а проверяется здесь модель, а не движок. +// +// Параметры: +// Количество - Число - Сколько классов создать. +// +// Возвращаемое значение: +// Массив из Тип - Типы подключенных классов. +// +Функция ПодключитьКлассыРегистрации(Знач Количество) + + КаталогКлассов = ОбъединитьПути(КаталогВременныхФайлов(), "entity-model-" + Новый УникальныйИдентификатор); + СоздатьКаталог(КаталогКлассов); + + Типы = Новый Массив; + Номер = 1; + Пока Номер <= Количество Цикл + + ИмяКласса = "КлассРегистрацииВМодели" + Формат(Номер, "ЧГ="); + ИмяФайла = ОбъединитьПути(КаталогКлассов, ИмяКласса + ".os"); + + ЗаписьТекста = Новый ЗаписьТекста(ИмяФайла, "UTF-8"); + ЗаписьТекста.ЗаписатьСтроку("&Идентификатор"); + ЗаписьТекста.ЗаписатьСтроку("Перем Идентификатор Экспорт;"); + ЗаписьТекста.ЗаписатьСтроку("Перем Поле Экспорт;"); + ЗаписьТекста.ЗаписатьСтроку(СтрШаблон("&Сущность(ИмяТаблицы = ""%1"")", ИмяКласса)); + ЗаписьТекста.ЗаписатьСтроку("Процедура ПриСозданииОбъекта()"); + ЗаписьТекста.ЗаписатьСтроку("КонецПроцедуры"); + ЗаписьТекста.Закрыть(); + + ПодключитьСценарий(ИмяФайла, ИмяКласса); + Типы.Добавить(Тип(ИмяКласса)); + + Номер = Номер + 1; + + КонецЦикла; + + Возврат Типы; + +КонецФункции + +// Срок ожидания задания теста. +// +// Возвращаемое значение: +// Число - Срок в миллисекундах. +// +Функция СрокЗадания() + Возврат 30000; +КонецФункции diff --git "a/tests/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" "b/tests/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" index 619d6764..ac9743bd 100644 --- "a/tests/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" +++ "b/tests/\320\236\320\261\321\212\320\265\320\272\321\202\320\234\320\276\320\264\320\265\320\273\320\270.os" @@ -44,14 +44,47 @@ КонецПроцедуры -// Колонки() отдает саму таблицу модели, без копии на каждое обращение. +// Объект модели общий у всех потоков менеджера, поэтому Колонки() отдает копию: правка результата +// не должна менять модель. &Тест -Процедура КолонкиОтдаютТаблицуМодели() Экспорт +Процедура КолонкиОтдаютКопию() Экспорт ОбъектМодели = НовыйОбъектМоделиАвтора(); - Ожидаем.Что(ОбъектМодели.Колонки(), "Повторное обращение отдает ту же таблицу") - .Равно(ОбъектМодели.Колонки()); + Ожидаем.Что(ОбъектМодели.Колонки() = ОбъектМодели.Колонки(), "Каждое обращение отдает свою таблицу") + .ЭтоЛожь(); + +КонецПроцедуры + +// Правка таблицы, полученной из Колонки(), не меняет ни поиск колонок, ни приведение значений. +&Тест +Процедура ИзменениеКопииКолонокНеМеняетМодель() Экспорт + + ОбъектМодели = НовыйОбъектМоделиАвтора(); + + Колонки = ОбъектМодели.Колонки(); + Колонки.Найти("Имя", "ИмяПоля").ТипКолонки = ТипыКолонок.Целое; + Колонки.Удалить(Колонки.Найти("Фамилия", "ИмяКолонки")); + + Ожидаем.Что(ОбъектМодели.Колонки(), "В модели остались все колонки").ИмеетДлину(4); + Ожидаем.Что(ОбъектМодели.ПривестиЗначениеПоля(12, "Имя"), "Поле приводится по типу модели") + .Равно("12"); + + Автор = Новый Автор; + ОбъектМодели.УстановитьЗначениеКолонкиВПоле(Автор, "Фамилия", "Иванов"); + Ожидаем.Что(Автор.ВтороеИмя, "Колонка Фамилия по-прежнему ищется").Равно("Иванов"); + +КонецПроцедуры + +// Библиотека и встроенные коннекторы читают колонки через Служебный_Колонки(): саму таблицу модели, +// без копии на каждое обращение. +&Тест +Процедура СлужебныеКолонкиОтдаютТаблицуМодели() Экспорт + + ОбъектМодели = НовыйОбъектМоделиАвтора(); + + Ожидаем.Что(ОбъектМодели.Служебный_Колонки() = ОбъектМодели.Служебный_Колонки(), "Повторное обращение отдает ту же таблицу") + .ЭтоИстина(); КонецПроцедуры @@ -62,7 +95,7 @@ ОбъектМодели = НовыйОбъектМоделиАвтора(); Индексы = Новый Массив; - Для Каждого Индекс Из ОбъектМодели.Колонки().Индексы Цикл + Для Каждого Индекс Из ОбъектМодели.Служебный_Колонки().Индексы Цикл Индексы.Добавить(Строка(Индекс)); КонецЦикла; @@ -71,14 +104,14 @@ КонецПроцедуры -// Так ОбработкаКоллекций донастраивает типы колонок объекта модели элемента коллекции: правка -// таблицы колонок видна и поиску колонки, и приведению значения. +// Так ОбработкаКоллекций донастраивает типы колонок своего объекта модели элемента коллекции: правка +// служебной таблицы колонок видна и поиску колонки, и приведению значения. &Тест -Процедура ИзменениеКолонокМеняетПриведение() Экспорт +Процедура ИзменениеСлужебныхКолонокМеняетПриведение() Экспорт ОбъектМодели = НовыйОбъектМоделиАвтора(); - ОбъектМодели.Колонки().Найти("Имя", "ИмяПоля").ТипКолонки = ТипыКолонок.Целое; + ОбъектМодели.Служебный_Колонки().Найти("Имя", "ИмяПоля").ТипКолонки = ТипыКолонок.Целое; Ожидаем.Что(ОбъектМодели.Колонки().Найти("Имя", "ИмяПоля").ТипКолонки, "Модель видит правку") .Равно(ТипыКолонок.Целое); @@ -158,6 +191,19 @@ КонецПроцедуры +// Имя таблицы, переданное при создании, заменяет имя из аннотации класса. Так создаются объекты +// модели подчиненных таблиц: класс элемента у них один, а таблицы разные. +&Тест +Процедура ИмяТаблицыЗадаетсяПриСоздании() Экспорт + + НовыйОбъектМоделиАвтора(); + + ОбъектМодели = Новый ОбъектМодели(Тип("Автор"), Неопределено, "Авторы_Подчиненная"); + + Ожидаем.Что(ОбъектМодели.ИмяТаблицы(), "Имя таблицы взято из параметра").Равно("Авторы_Подчиненная"); + +КонецПроцедуры + // Идентификатор отдается неизменяемым: правка результата невозможна и модель не меняет. &Тест Процедура ИдентификаторНеизменяем() Экспорт diff --git "a/tests/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" "b/tests/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" new file mode 100644 index 00000000..293efc12 --- /dev/null +++ "b/tests/\320\242\320\270\320\277\321\213\320\232\320\276\320\273\320\276\320\275\320\276\320\272.os" @@ -0,0 +1,21 @@ +// Перечни типов из глобальных модулей библиотеки отдаются неизменяемыми. + +#Использовать ".." + +&Тест +Процедура ТипыКолонокНеизменяемы() Экспорт + + Ожидаем.Что(ТипЗнч(ТипыКолонок.Типы()), "Типы колонок - фиксированный массив") + .Равно(Тип("ФиксированныйМассив")); + Ожидаем.Что(ТипыКолонок.Типы(), "Перечень содержит все типы колонок").ИмеетДлину(9); + +КонецПроцедуры + +&Тест +Процедура ТипыПодчиненныхТаблицНеизменяемы() Экспорт + + Ожидаем.Что(ТипЗнч(ТипыПодчиненныхТаблиц.Типы()), "Типы подчиненных таблиц - фиксированный массив") + .Равно(Тип("ФиксированныйМассив")); + Ожидаем.Что(ТипыПодчиненныхТаблиц.Типы(), "Перечень содержит все типы подчиненных таблиц").ИмеетДлину(2); + +КонецПроцедуры