diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca370ac..98310cc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,10 +16,10 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] oscript_version: ['1.8.3', 'stable'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Onescript Action - uses: otymko/setup-onescript@v1.1 + uses: otymko/setup-onescript@v1.4 with: version: ${{ matrix.oscript_version }} @@ -28,22 +28,26 @@ jobs: opm install opm@1.0.2 opm install -l --dev + - name: Prepare macOS env + if: matrix.os == 'macos-latest' + run: | + echo "SIGN_QEMU_BINARY=1" >> "$GITHUB_ENV" + - name: Install docker - if: matrix.os != 'windows-latest' - uses: crazy-max/ghaction-setup-docker@v1 + uses: crazy-max/ghaction-setup-docker@v3 timeout-minutes: 12 - name: Setup PostgreSQL - if: matrix.os != 'windows-latest' + shell: bash run: | - docker run --rm --name postgres -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_USERNAME=postgres -e POSTGRES_DB=postgres -e POSTGRES_HOST_AUTH_METHOD=password --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 postgres + docker run --rm --name postgres -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_USERNAME=postgres -e POSTGRES_DB=postgres -e POSTGRES_HOST_AUTH_METHOD=password --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 satrapu/postgresql docker ps while [ "`docker inspect -f {{.State.Health.Status}} postgres`" != "healthy" ]; do docker ps && sleep 2; done docker ps - name: Run tests env: - TESTRUNNER_RUN_POSTGRES_TESTS: "${{ matrix.os != 'windows-latest' }}" + TESTRUNNER_RUN_POSTGRES_TESTS: true TESTRUNNER_RUN_SQLITE_TESTS: "${{ matrix.os == 'windows-latest' }}" run: | oscript ./tasks/test.os diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index a409178..50dd9cc 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -9,13 +9,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # Disabling shallow clone is recommended for improving relevancy of reporting fetch-depth: 0 - name: Setup Onescript Action - uses: otymko/setup-onescript@v1.1 + uses: otymko/setup-onescript@v1.4 with: version: "1.8.3" @@ -25,7 +25,7 @@ jobs: opm install -l --dev - name: Install docker - uses: crazy-max/ghaction-setup-docker@v1 + uses: crazy-max/ghaction-setup-docker@v3 timeout-minutes: 12 - name: Setup PostgreSQL @@ -50,28 +50,30 @@ jobs: run: | oscript ./tasks/coverage.os - - name: SonarCloud Scan on push - if: github.repository == 'nixel2007/entity' && github.event_name == 'push' - uses: nixel2007/sonarcloud-github-action@v1.5 + - name: Setup sonarqube + uses: warchant/setup-sonar-scanner@v8 + + # Анализ проекта в SonarQube (ветка) + - name: Анализ в SonarQube (branch) + if: github.event_name == 'push' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - with: - args: > - -Dsonar.host.url=https://sonar.openbsl.ru - -Dsonar.branch.name=${{ env.BRANCH_NAME }} - -Dsonar.projectVersion=${{ steps.extract_version.outputs.version }} - - - name: SonarCloud Scan on PR - if: github.repository == 'nixel2007/entity' && github.event_name == 'pull_request' - uses: nixel2007/sonarcloud-github-action@v1.5 + run: sonar-scanner + -Dsonar.host.url=https://sonar.openbsl.ru + -Dsonar.branch.name=${{ env.BRANCH_NAME }} + -Dsonar.projectVersion=${{ steps.extract_version.outputs.version }} + + # Анализ проекта в SonarQube (PR) + # https://docs.sonarqube.org/latest/analysis/pull-request/ + - name: Анализ в SonarQube (pull-request) + if: github.event_name == 'pull_request' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - with: - args: > - -Dsonar.host.url=https://sonar.openbsl.ru - -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} - -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} - -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} - -Dsonar.scm.revision=${{ github.event.pull_request.head.sha }} + run: sonar-scanner + -Dsonar.host.url=https://sonar.openbsl.ru + -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} + -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} + -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} + -Dsonar.scm.revision=${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8299db5..32a5876 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,11 +23,11 @@ jobs: steps: # Загрузка проекта - name: Актуализация - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Установка OneScript конкретной версии - name: Установка OneScript - uses: otymko/setup-onescript@v1.1 + uses: otymko/setup-onescript@v1.4 with: version: ${{ matrix.oscript_version }} @@ -41,7 +41,7 @@ jobs: run: opm build . - name: Заливка артефактов - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: package.zip path: ./${{ env.PACKAGE_MASK }} diff --git a/README.md b/README.md index 54db276..c2f7424 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ * КоннекторSQLite * КоннекторPostgreSQL * КоннекторJSON + * КоннекторInMemory * Версионирование и обратная совместимость @@ -522,6 +523,16 @@ Все операциями по записи и удалению сущностей одного типа проводятся **синхронно**, блокируя файл таблицы целиком. Для контроля над синхронным доступом используется библиотека [semaphore](https://github.com/nixel2007/semaphore). + + +### КоннекторInMemory + +В состав библиотеки входит референсная реализация интерфейса коннектора в виде упрощенного коннектора к виртуальной базе данных в памяти. База данных состоит из соответствия, где ключ - имя таблицы модели данных, значение таблицы. + +В качестве строки соединения произвольная строка, которая будет являться разделителем данных. + +Коннектор поддерживает все CRUD-операции над сущностями, простой и сложный поиск, но не поддерживает работу с транзакциями. При вызове операций по работе с транзакциями будут выданы исключения. + ## Версионирование и обратная совместимость diff --git a/lib.config b/lib.config index cc868f2..efbf7b1 100644 --- a/lib.config +++ b/lib.config @@ -9,6 +9,7 @@ + diff --git a/packagedef b/packagedef index 493da64..88f41cc 100644 --- a/packagedef +++ b/packagedef @@ -4,7 +4,7 @@ // // BSLLS:CodeOutOfRegion-off Описание.Имя("entity") - .Версия("2.3.5.0") + .Версия("2.3.6.0") .Автор("Nikita Gryzlov") .АдресАвтора("nixel2007@gmail.com") .Описание("entity") diff --git "a/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\222\320\237\320\260\320\274\321\217\321\202\320\270.os" "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\222\320\237\320\260\320\274\321\217\321\202\320\270.os" new file mode 100644 index 0000000..afa3cd9 --- /dev/null +++ "b/src/internal/\320\234\320\276\320\264\321\203\320\273\320\270/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\222\320\237\320\260\320\274\321\217\321\202\320\270.os" @@ -0,0 +1,24 @@ + +Перем КешиТаблиц; + +Функция КешТаблиц(СтрокаПодключения = "default") Экспорт + Результат = КешиТаблиц.Получить(СтрокаПодключения); + + Если Результат = Неопределено Тогда + Результат = Новый Соответствие(); + КешиТаблиц.Вставить(СтрокаПодключения, Результат); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Процедура Очистить(СтрокаПодключения = "default") Экспорт + КешиТаблиц.Вставить(СтрокаПодключения, Новый Соответствие()); +КонецПроцедуры + +Процедура Инициализация() + КешиТаблиц = Новый Соответствие(); +КонецПроцедуры + +Инициализация(); \ No newline at end of file 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" new file mode 100644 index 0000000..8c18847 --- /dev/null +++ "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" @@ -0,0 +1,261 @@ +#Использовать "../internal" + +// Для хранения статуса соединения +Перем Открыт; +Перем КешТаблиц; +Перем Рефлектор; + +// Конструктор объекта АбстрактныйКоннектор. +// +Процедура ПриСозданииОбъекта() + Открыт = Ложь; + Рефлектор = Новый Рефлектор; +КонецПроцедуры + +// Открыть соединение с БД. +// +// Параметры: +// СтрокаСоединения - Строка - Строка соединения с БД. +// ПараметрыКоннектора - Массив - Дополнительные параметры инициализации коннектора. +// +Процедура Открыть(СтрокаСоединения, ПараметрыКоннектора) Экспорт + КешТаблиц = ХранилищеВПамяти.КешТаблиц(СтрокаСоединения); + Открыт = Истина; +КонецПроцедуры + +// Закрыть соединение с БД. +// +Процедура Закрыть() Экспорт + Открыт = Ложь; +КонецПроцедуры + +// Получить статус соединения с БД. +// +// Возвращаемое значение: +// Булево - Состояние соединения. Истина, если соединение установлено и готово к использованию. +// В обратном случае - Ложь. +// +Функция Открыт() Экспорт + Возврат Открыт; +КонецФункции + +// Начинает новую транзакцию в БД. +// +Процедура НачатьТранзакцию() Экспорт + ВызватьИсключение "Не поддерживается"; +КонецПроцедуры + +// Фиксирует открытую транзакцию в БД. +// +Процедура ЗафиксироватьТранзакцию() Экспорт + ВызватьИсключение "Не поддерживается"; +КонецПроцедуры + +// Отменяет открытую транзакцию в БД. +// +Процедура ОтменитьТранзакцию() Экспорт + ВызватьИсключение "Не поддерживается"; +КонецПроцедуры + +// Создает таблицу в БД по данным модели. +// +// Параметры: +// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД. +// +Процедура ИнициализироватьТаблицу(ОбъектМодели) Экспорт + ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); + + Если КешТаблиц.Получить(ИмяТаблицы) = Неопределено Тогда + Таблица = Новый ТаблицаЗначений(); + + Таблица.Колонки.Добавить("_Идентификатор"); + Таблица.Колонки.Добавить("_Сущность"); + + Таблица.Индексы.Добавить("_Идентификатор"); + + КешТаблиц.Вставить(ИмяТаблицы, Таблица); + КонецЕсли; + +КонецПроцедуры + +// Сохраняет сущность в БД. +// +// Параметры: +// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД. +// Сущность - Произвольный - Объект (экземпляр класса, зарегистрированного в модели) для сохранения в БД. +// +Процедура Сохранить(ОбъектМодели, Сущность) Экспорт + + ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); + + Таблица = КешТаблиц.Получить(ИмяТаблицы); + + Если Таблица = Неопределено Тогда + ВызватьИсключение "Таблица " + ИмяТаблицы + " не найдена"; + КонецЕсли; + + Идентификатор = ОбъектМодели.ПолучитьЗначениеИдентификатора(Сущность); + Если НЕ ЗначениеЗаполнено(Идентификатор) Тогда + + Если ОбъектМодели.Идентификатор().ТипКолонки <> ТипыКолонок.Целое Тогда + Сообщение = СтрШаблон( + "Ошибка при сохранении сущности с типом %1. + |Генерация идентификаторов поддерживается только для колонок с типом ""Целое""", + ОбъектМодели.ТипСущности() + ); + ВызватьИсключение Сообщение; + КонецЕсли; + + МаксимальныйИдентификатор = ПроцессорыКоллекций.ИзКоллекции(Таблица) + .Обработать("Результат = Число(Элемент._Идентификатор)") + .Максимум(); + + Если МаксимальныйИдентификатор = Неопределено Тогда + МаксимальныйИдентификатор = 0; + КонецЕсли; + + Идентификатор = МаксимальныйИдентификатор + 1; + + ОбъектМодели.УстановитьЗначениеКолонкиВПоле( + Сущность, + ОбъектМодели.Идентификатор().ИмяКолонки, + Идентификатор + ); + + КонецЕсли; + Если ТипЗнч(Идентификатор) = Тип("Число") Тогда + Идентификатор = Формат(Идентификатор, "ЧГ="); + КонецЕсли; + + СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор"); + + Если СтрокаТЗ = Неопределено Тогда + СтрокаТЗ = Таблица.Добавить(); + КонецЕсли; + + СущностьВБД = Новый (ОбъектМодели.ТипСущности()); + + Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл + Значение = ОбъектМодели.ПолучитьПриведенноеЗначениеПоля( + Сущность, + Колонка.ИмяПоля); + Рефлектор.УстановитьСвойство(СущностьВБД, Колонка.ИмяПоля, Значение); + КонецЦикла; + + СтрокаТЗ._Идентификатор = Идентификатор; + СтрокаТЗ._Сущность = СущностьВБД; + +КонецПроцедуры + +// Удаляет сущность из таблицы БД. +// +// Параметры: +// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД. +// Сущность - Произвольный - Объект (экземпляр класса, зарегистрированного в модели) для удаления из БД. +// +Процедура Удалить(ОбъектМодели, Сущность) Экспорт + + ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); + + Таблица = КешТаблиц.Получить(ИмяТаблицы); + + Если Таблица = Неопределено Тогда + ВызватьИсключение "Таблица " + ИмяТаблицы + " не найдена"; + КонецЕсли; + + Идентификатор = ОбъектМодели.ПолучитьЗначениеИдентификатора(Сущность); + Если ТипЗнч(Идентификатор) = Тип("Число") Тогда + Идентификатор = Формат(Идентификатор, "ЧГ="); + КонецЕсли; + + СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор"); + + Если НЕ СтрокаТЗ = Неопределено Тогда + Таблица.Удалить(СтрокаТЗ); + КонецЕсли; + +КонецПроцедуры + +// Осуществляет поиск строк в таблице по указанному отбору. +// +// Параметры: +// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД. +// Отбор - Массив - Отбор для поиска. Каждый элемент массива должен иметь тип "ЭлементОтбора". +// Каждый элемент отбора преобразуется к условию поиска. В качестве "ПутьКДанным" указываются имена колонок. +// +// Возвращаемое значение: +// Массив - Массив, элементами которого являются "Соответствия". Ключом элемента соответствия является имя колонки, +// значением элемента соответствия - значение колонки. +// +Функция НайтиСтрокиВТаблице(ОбъектМодели, Отбор = Неопределено) Экспорт + + ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); + + Таблица = КешТаблиц.Получить(ИмяТаблицы); + + Если Таблица = Неопределено Тогда + ВызватьИсключение "Таблица " + ИмяТаблицы + " не найдена"; + КонецЕсли; + + ПроцессорКоллекций = ПроцессорыКоллекций.ИзКоллекции(Таблица); + + Для Каждого ЭлементОтбора Из Отбор Цикл + СтрокаУсловие = СтрШаблон( + "Результат = Элемент._Сущность.%1 %2 ДополнительныеПараметры.Значение", + ЭлементОтбора.ПутьКДанным, + ЭлементОтбора.ВидСравнения + ); + ДополнительныеПараметры = Новый Структура("Значение", ЭлементОтбора.Значение); + ПроцессорКоллекций = ПроцессорКоллекций.Фильтровать(СтрокаУсловие, ДополнительныеПараметры); + КонецЦикла; + + ДанныеТаблицы = ПроцессорКоллекций.ВМассив(); + + Результат = Новый Массив(); + + Колонки = ОбъектМодели.Колонки(); + + Для Каждого СтрокаДанныхТаблицы Из ДанныеТаблицы Цикл + ЗначенияКолонок = Новый Соответствие; + Для Каждого Колонка Из Колонки Цикл + Значение = Рефлектор.ПолучитьСвойство(СтрокаДанныхТаблицы._Сущность, Колонка.ИмяПоля); + ЗначенияКолонок.Вставить(Колонка.ИмяКолонки, Значение); + КонецЦикла; + Результат.Добавить(ЗначенияКолонок); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Удаляет строки в таблице по указанному отбору. +// +// Параметры: +// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД. +// Отбор - Массив - Отбор для поиска. Каждый элемент массива должен иметь тип "ЭлементОтбора". +// Каждый элемент отбора преобразуется к условию поиска. В качестве "ПутьКДанным" указываются имена колонок. +// +Процедура УдалитьСтрокиВТаблице(ОбъектМодели, Знач Отбор) Экспорт + СтрокиКУдалению = НайтиСтрокиВТаблице(ОбъектМодели, Отбор); + Если СтрокиКУдалению.Количество() > 0 Тогда + + ИмяКлонкиИдентификатора = ОбъектМодели.Идентификатор().ИмяКолонки; + + ИмяТаблицы = ОбъектМодели.ИмяТаблицы(); + Таблица = КешТаблиц.Получить(ИмяТаблицы); + + Для Каждого СтрокаКУдалению Из СтрокиКУдалению Цикл + Идентификатор = СтрокаКУдалению.Получить(ИмяКлонкиИдентификатора); + Если ТипЗнч(Идентификатор) = Тип("Число") Тогда + Идентификатор = Формат(Идентификатор, "ЧГ="); + КонецЕсли; + + СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор"); + + Если НЕ СтрокаТЗ = Неопределено Тогда + Таблица.Удалить(СтрокаТЗ); + КонецЕсли; + КонецЦикла; + + КонецЕсли; +КонецПроцедуры \ No newline at end of file diff --git "a/tests/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" "b/tests/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" new file mode 100644 index 0000000..28e872f --- /dev/null +++ "b/tests/\320\232\320\276\320\275\320\275\320\265\320\272\321\202\320\276\321\200InMemory.os" @@ -0,0 +1,232 @@ +#Использовать fs +#Использовать ".." + +Перем Коннектор; +Перем СтрокаСоединения; + +Процедура ПередЗапускомТеста() Экспорт + ХранилищеВПамяти.Очистить(); + ПодключитьСценарий(ОбъединитьПути(ТекущийКаталог(), "tests", "fixtures", "СущностьСоВсемиТипамиКолонок.os"), "СущностьСоВсемиТипамиКолонок"); + ПодключитьСценарий(ОбъединитьПути(ТекущийКаталог(), "tests", "fixtures", "АвтоинкрементныйКлючБезКолонок.os"), "АвтоинкрементныйКлючБезКолонок"); + + Коннектор = Новый КоннекторInMemory(); + Коннектор.Открыть(СтрокаСоединения, Новый Массив); +КонецПроцедуры + +Процедура ПослеЗапускаТеста() Экспорт + Коннектор.Закрыть(); +КонецПроцедуры + +&Тест +Процедура КоннекторInMemoryРеализуетИнтерфейсКоннектора() Экспорт + ИнтерфейсОбъекта = Новый ИнтерфейсОбъекта(); + ИнтерфейсОбъекта.ИзОбъекта(Тип("АбстрактныйКоннектор")); + + РефлекторОбъекта = Новый РефлекторОбъекта(Тип("КоннекторInMemory")); + РефлекторОбъекта.РеализуетИнтерфейс(ИнтерфейсОбъекта, Истина); +КонецПроцедуры + +&Тест +Процедура НайтиСтрокиВТаблице() Экспорт + МодельДанных = Новый МодельДанных(); + ОбъектМодели = МодельДанных.СоздатьОбъектМодели(Тип("СущностьСоВсемиТипамиКолонок")); + Коннектор.ИнициализироватьТаблицу(ОбъектМодели); + + ЗависимаяСущность = Новый СущностьСоВсемиТипамиКолонок; + ЗависимаяСущность.Целое = 2; + + Сущность = Новый СущностьСоВсемиТипамиКолонок; + Сущность.Целое = 1; + Сущность.Дробное = 1.2; + Сущность.БулевоИстина = Истина; + Сущность.БулевоЛожь = Ложь; + Сущность.Строка = "Строка"; + Сущность.Дата = Дата(2018, 1, 1); + Сущность.Время = Дата(1, 1, 1, 10, 53, 20); + Сущность.ДатаВремя = Дата(2018, 1, 1, 10, 53, 20); + Сущность.Ссылка = ЗависимаяСущность; + Сущность.ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки("ДвоичныеДанные"); + + Коннектор.Сохранить(ОбъектМодели, ЗависимаяСущность); + Коннектор.Сохранить(ОбъектМодели, Сущность); + + Отбор = Новый Массив; + Отбор.Добавить(Новый ЭлементОтбора("Целое", ВидСравнения.Равно, Сущность.Целое)); + НайденныеСтроки = Коннектор.НайтиСтрокиВТаблице(ОбъектМодели, Отбор); + Ожидаем.Что(НайденныеСтроки, "Сущность сохранилась").ИмеетДлину(1); + + ЗначенияКолонок = НайденныеСтроки[0]; + + Ожидаем.Что(ЗначенияКолонок.Получить("Целое"), "ЗначенияКолонок.Целое получено корректно").Равно(Сущность.Целое); + Ожидаем.Что(ЗначенияКолонок.Получить("Дробное"), "ЗначенияКолонок.Дробное получено корректно").Равно(Сущность.Дробное); + Ожидаем.Что(ЗначенияКолонок.Получить("БулевоИстина"), "ЗначенияКолонок.БулевоИстина получено корректно").Равно(Сущность.БулевоИстина); + Ожидаем.Что(ЗначенияКолонок.Получить("БулевоЛожь"), "ЗначенияКолонок.БулевоЛожь получено корректно").Равно(Сущность.БулевоЛожь); + Ожидаем.Что(ЗначенияКолонок.Получить("Строка"), "ЗначенияКолонок.Строка получено корректно").Равно(Сущность.Строка); + Ожидаем.Что(ЗначенияКолонок.Получить("Дата"), "ЗначенияКолонок.Дата получено корректно").Равно(Сущность.Дата); + Ожидаем.Что(ЗначенияКолонок.Получить("Время"), "ЗначенияКолонок.Время получено корректно").Равно(Сущность.Время); + Ожидаем.Что(ЗначенияКолонок.Получить("ДатаВремя"), "ЗначенияКолонок.ДатаВремя получено корректно").Равно(Сущность.ДатаВремя); + Ожидаем.Что(ЗначенияКолонок.Получить("Ссылка"), "ЗначенияКолонок.Ссылка получено корректно").Равно(Сущность.Ссылка.Целое); + Ожидаем.Что(ЗначенияКолонок.Получить("ДвоичныеДанные"), "ЗначенияКолонок.ДвоичныеДанные получено корректно").Равно(Сущность.ДвоичныеДанные); +КонецПроцедуры + +&Тест +Процедура УдалитьСтрокиВТаблице() Экспорт + МодельДанных = Новый МодельДанных(); + ОбъектМодели = МодельДанных.СоздатьОбъектМодели(Тип("СущностьСоВсемиТипамиКолонок")); + Коннектор.ИнициализироватьТаблицу(ОбъектМодели); + + Сущность = Новый СущностьСоВсемиТипамиКолонок; + Сущность.Целое = 1; + + Коннектор.Сохранить(ОбъектМодели, Сущность); + + Отбор = Новый Массив; + Отбор.Добавить(Новый ЭлементОтбора("Целое", ВидСравнения.Равно, Сущность.Целое)); + + Коннектор.УдалитьСтрокиВТаблице(ОбъектМодели, Отбор); + + НайденныеСтроки = Коннектор.НайтиСтрокиВТаблице(ОбъектМодели, Отбор); + Ожидаем.Что(НайденныеСтроки, "Сущность удалилась").ИмеетДлину(0); +КонецПроцедуры + +&Тест +Процедура УдалениеСущности() Экспорт + МодельДанных = Новый МодельДанных(); + ОбъектМодели = МодельДанных.СоздатьОбъектМодели(Тип("СущностьСоВсемиТипамиКолонок")); + Коннектор.ИнициализироватьТаблицу(ОбъектМодели); + + Сущность = Новый СущностьСоВсемиТипамиКолонок(); + Сущность.Целое = 1; + Коннектор.Сохранить(ОбъектМодели, Сущность); + + Коннектор.Удалить(ОбъектМодели, Сущность); + + Отбор = Новый Массив; + Отбор.Добавить(Новый ЭлементОтбора("Целое", ВидСравнения.Равно, Сущность.Целое)); + НайденныеСтроки = Коннектор.НайтиСтрокиВТаблице(ОбъектМодели, Отбор); + + Ожидаем.Что(НайденныеСтроки, "Сущность удалилась").ИмеетДлину(0); + +КонецПроцедуры + +&Тест +Процедура Автоинкремент() Экспорт + МодельДанных = Новый МодельДанных(); + ОбъектМодели = МодельДанных.СоздатьОбъектМодели(Тип("АвтоинкрементныйКлючБезКолонок")); + Коннектор.ИнициализироватьТаблицу(ОбъектМодели); + + Сущность = Новый АвтоинкрементныйКлючБезКолонок(); + Коннектор.Сохранить(ОбъектМодели, Сущность); + + Ожидаем.Что(Сущность.Идентификатор).Равно(1); + + Сущность = Новый АвтоинкрементныйКлючБезКолонок(); + Коннектор.Сохранить(ОбъектМодели, Сущность); + + Ожидаем.Что(Сущность.Идентификатор).Равно(2); + +КонецПроцедуры + +&Тест +Процедура СущностьМожетЗаписатьСебя() Экспорт + // Дано + ПодключитьСценарий("tests/fixtures/ПростойОбъект.os", "ПростойОбъект"); + + ТипКоннектора = "КоннекторInMemory"; + МенеджерСущностей = Новый МенеджерСущностей(Тип(ТипКоннектора)); + МенеджерСущностей.ДобавитьКлассВМодель(Тип("ПростойОбъект")); + МенеджерСущностей.Инициализировать(); + + // Когда + ПростойОбъект = МенеджерСущностей.СоздатьЭлемент(Тип("ПростойОбъект")); + ПростойОбъект.Идентификатор = "1"; + ПростойОбъект.Поле = "2"; + ПростойОбъект.Сохранить(); + + // Тогда + НайденныйПростойОбъект = МенеджерСущностей.ПолучитьОдно(Тип("ПростойОбъект"), "1"); + + Ожидаем.Что(НайденныйПростойОбъект).Не_().Равно(Неопределено); + Ожидаем.Что(НайденныйПростойОбъект.Идентификатор).Равно("1"); + Ожидаем.Что(НайденныйПростойОбъект.Поле).Равно("2"); + +КонецПроцедуры + +&Тест +Процедура СущностьМожетПерезаписатьСебя() Экспорт + // Дано + ПодключитьСценарий("tests/fixtures/ПростойОбъект.os", "ПростойОбъект"); + ТипКоннектора = "КоннекторInMemory"; + МенеджерСущностей = Новый МенеджерСущностей(Тип(ТипКоннектора)); + МенеджерСущностей.ДобавитьКлассВМодель(Тип("ПростойОбъект")); + МенеджерСущностей.Инициализировать(); + + // Когда + ПростойОбъект = МенеджерСущностей.СоздатьЭлемент(Тип("ПростойОбъект")); + ПростойОбъект.Идентификатор = "1"; + ПростойОбъект.Поле = "2"; + ПростойОбъект.Сохранить(); + НайденныйПростойОбъект = МенеджерСущностей.ПолучитьОдно(Тип("ПростойОбъект"), "1"); + НайденныйПростойОбъект.Поле = "3"; + НайденныйПростойОбъект.Сохранить(); + + // Тогда + НайденныйПростойОбъект = МенеджерСущностей.ПолучитьОдно(Тип("ПростойОбъект"), "1"); + + Ожидаем.Что(НайденныйПростойОбъект).Не_().Равно(Неопределено); + Ожидаем.Что(НайденныйПростойОбъект.Идентификатор).Равно("1"); + Ожидаем.Что(НайденныйПростойОбъект.Поле).Равно("3"); + +КонецПроцедуры + +&Тест +Процедура МенеджерСущностейМожетЗаписать() Экспорт + // Дано + ПодключитьСценарий("tests/fixtures/ПростойОбъект.os", "ПростойОбъект"); + ТипКоннектора = "КоннекторInMemory"; + МенеджерСущностей = Новый МенеджерСущностей(Тип(ТипКоннектора)); + МенеджерСущностей.ДобавитьКлассВМодель(Тип("ПростойОбъект")); + МенеджерСущностей.Инициализировать(); + + // Когда + ПростойОбъект = МенеджерСущностей.СоздатьЭлемент(Тип("ПростойОбъект")); + ПростойОбъект.Идентификатор = "1"; + ПростойОбъект.Поле = "2"; + МенеджерСущностей.Сохранить(ПростойОбъект); + + // Тогда + НайденныйПростойОбъект = МенеджерСущностей.ПолучитьОдно(Тип("ПростойОбъект"), "1"); + + Ожидаем.Что(НайденныйПростойОбъект).Не_().Равно(Неопределено); + Ожидаем.Что(НайденныйПростойОбъект.Идентификатор).Равно("1"); + Ожидаем.Что(НайденныйПростойОбъект.Поле).Равно("2"); + +КонецПроцедуры + +&Тест +Процедура ХранилищеСущностейМожетЗаписать() Экспорт + + // Дано + ПодключитьСценарий("tests/fixtures/ПростойОбъект.os", "ПростойОбъект"); + ТипКоннектора = "КоннекторInMemory"; + МенеджерСущностей = Новый МенеджерСущностей(Тип(ТипКоннектора)); + МенеджерСущностей.ДобавитьКлассВМодель(Тип("ПростойОбъект")); + МенеджерСущностей.Инициализировать(); + + // Когда + + ХранилищеПростойОбъект = МенеджерСущностей.ПолучитьХранилищеСущностей(Тип("ПростойОбъект")); + + ПростойОбъект = ХранилищеПростойОбъект.СоздатьЭлемент(); + ПростойОбъект.Идентификатор = "1"; + ПростойОбъект.Поле = "2"; + ПростойОбъект.Сохранить(); + + // Тогда + НайденныйПростойОбъект = ХранилищеПростойОбъект.ПолучитьОдно("1"); + + Ожидаем.Что(НайденныйПростойОбъект).Не_().Равно(Неопределено); + Ожидаем.Что(НайденныйПростойОбъект.Идентификатор).Равно("1"); + Ожидаем.Что(НайденныйПростойОбъект.Поле).Равно("2"); + +КонецПроцедуры \ No newline at end of file