Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Поддержка коннектора inmemory #87

Merged
merged 5 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
* <a href="#library-structure-connector-sqlite">КоннекторSQLite</a>
* <a href="#library-structure-connector-postgresql">КоннекторPostgreSQL</a>
* <a href="#library-structure-connector-json">КоннекторJSON</a>
* <a href="#library-structure-connector-inmemory">КоннекторJSON</a>
* <a href="#versioning-strategy">Версионирование и обратная совместимость</a>
Nivanchenko marked this conversation as resolved.
Show resolved Hide resolved

<a id="entity-example" />
Expand Down Expand Up @@ -522,6 +523,16 @@

Все операциями по записи и удалению сущностей одного типа проводятся **синхронно**, блокируя файл таблицы целиком. Для контроля над синхронным доступом используется библиотека [semaphore](https://github.com/nixel2007/semaphore).

<a id="library-structure-connector-inmemory" />

### КоннекторInMemory

В состав библиотеки входит референсная реализация интерфейса коннектора в виде упрощенного коннектора к виртуальной базе данных в памяти. База данных состоит из соответствия, где ключ - имя таблицы модели данных, значение таблицы.

В качестве строки соединения произвольная строка, которая будет являться разделителем данных.

Коннектор поддерживает все CRUD-операции над сущностями, простой и сложный поиск, но не поддерживает работу с транзакциями. При вызове операций по работе с транзакциями будут выданы исключения.

<a id="versioning-strategy" />

## Версионирование и обратная совместимость
Expand Down
1 change: 1 addition & 0 deletions lib.config
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<class name="ОбъектМодели" file="src/Классы/ОбъектМодели.os"/>
<class name="ЭлементОтбора" file="src/Классы/ЭлементОтбора.os"/>
<class name="ХранилищеСущностей" file="src/Классы/ХранилищеСущностей.os"/>
<class name="КоннекторInMemory" file="src/Классы/КоннекторInMemory.os"/>
<module name="ТипыКолонок" file="src/Модули/ТипыКолонок.os"/>
<module name="ТипыПодчиненныхТаблиц" file="src/Модули/ТипыПодчиненныхТаблиц.os"/>
<module name="ВидСравнения" file="src/Модули/ВидСравнения.os"/>
Expand Down
24 changes: 24 additions & 0 deletions src/internal/Модули/ХранилищеВПамяти.os
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

Перем КешиТаблиц;

Функция КешТаблиц(СтрокаПодключения = "default") Экспорт
Результат = КешиТаблиц.Получить(СтрокаПодключения);

Если Результат = Неопределено Тогда
Результат = Новый Соответствие();
КешиТаблиц.Вставить(СтрокаПодключения, Результат);
КонецЕсли;

Возврат Результат;

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

Процедура Очистить(СтрокаПодключения = "default") Экспорт
КешиТаблиц.Вставить(СтрокаПодключения, Новый Соответствие());
КонецПроцедуры

Процедура Инициализация()
КешиТаблиц = Новый Соответствие();
КонецПроцедуры

Инициализация();
261 changes: 261 additions & 0 deletions src/Классы/КоннекторInMemory.os
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
#Использовать "../internal"

// Для хранения статуса соединения
Перем Открыт;
Перем КешТаблиц;
Перем Рефлектор;

// Конструктор объекта АбстрактныйКоннектор.
//
Процедура ПриСозданииОбъекта()
Открыт = Ложь;
Рефлектор = Новый Рефлектор;
КонецПроцедуры

// Открыть соединение с БД.
//
// Параметры:
// СтрокаСоединения - Строка - Строка соединения с БД.
// ПараметрыКоннектора - Массив - Дополнительные параметры инициализации коннектора.
//
Процедура Открыть(СтрокаСоединения, ПараметрыКоннектора) Экспорт
КешТаблиц = ХранилищеВПамяти.КешТаблиц(СтрокаСоединения);
Открыт = Истина;
КонецПроцедуры

// Закрыть соединение с БД.
//
Процедура Закрыть() Экспорт
Открыт = Ложь;
КонецПроцедуры

// Получить статус соединения с БД.
//
// Возвращаемое значение:
// Булево - Состояние соединения. Истина, если соединение установлено и готово к использованию.
// В обратном случае - Ложь.
//
Функция Открыт() Экспорт
Возврат Открыт;
КонецФункции

// Начинает новую транзакцию в БД.
//
Процедура НачатьТранзакцию() Экспорт
ВызватьИсключение "Не поддерживается";
КонецПроцедуры

// Фиксирует открытую транзакцию в БД.
//
Процедура ЗафиксироватьТранзакцию() Экспорт
ВызватьИсключение "Не поддерживается";
КонецПроцедуры

// Отменяет открытую транзакцию в БД.
//
Процедура ОтменитьТранзакцию() Экспорт
ВызватьИсключение "Не поддерживается";
КонецПроцедуры

// Создает таблицу в БД по данным модели.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
//
Процедура ИнициализироватьТаблицу(ОбъектМодели) Экспорт
ИмяТаблицы = ОбъектМодели.ИмяТаблицы();

Если КешТаблиц.Получить(ИмяТаблицы) = Неопределено Тогда
Таблица = Новый ТаблицаЗначений();

Таблица.Колонки.Добавить("_Идентификатор");
Таблица.Колонки.Добавить("_Сущность");

Таблица.Индексы.Добавить("_Идентификатор");

КешТаблиц.Вставить(ИмяТаблицы, Таблица);
КонецЕсли;

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

// Сохраняет сущность в БД.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
// Сущность - Произвольный - Объект (экземпляр класса, зарегистрированного в модели) для сохранения в БД.
//
Процедура Сохранить(ОбъектМодели, Сущность) Экспорт

ИмяТаблицы = ОбъектМодели.ИмяТаблицы();

Таблица = КешТаблиц.Получить(ИмяТаблицы);

Если Таблица = Неопределено Тогда
ВызватьИсключение "Таблица " + ИмяТаблицы + " не найдена";
КонецЕсли;

Идентификатор = ОбъектМодели.ПолучитьЗначениеИдентификатора(Сущность);
Если НЕ ЗначениеЗаполнено(Идентификатор) Тогда

Если ОбъектМодели.Идентификатор().ТипКолонки <> ТипыКолонок.Целое Тогда
Сообщение = СтрШаблон(
"Ошибка при сохранении сущности с типом %1.
|Генерация идентификаторов поддерживается только для колонок с типом ""Целое""",
ОбъектМодели.ТипСущности()
);
ВызватьИсключение Сообщение;
КонецЕсли;

МаксимальныйИдентификатор = ПроцессорыКоллекций.ИзКоллекции(Таблица)
.Обработать("Результат = Число(Элемент._Идентификатор)")
.Максимум();

Если МаксимальныйИдентификатор = Неопределено Тогда
МаксимальныйИдентификатор = 0;
КонецЕсли;

Идентификатор = МаксимальныйИдентификатор + 1;

ОбъектМодели.УстановитьЗначениеКолонкиВПоле(
Сущность,
ОбъектМодели.Идентификатор().ИмяКолонки,
Идентификатор
);

КонецЕсли;
Если ТипЗнч(Идентификатор) = Тип("Число") Тогда
Идентификатор = Формат(Идентификатор, "ЧГ=");
КонецЕсли;

СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор");

Если СтрокаТЗ = Неопределено Тогда
СтрокаТЗ = Таблица.Добавить();
КонецЕсли;

СущностьВБД = Новый (ОбъектМодели.ТипСущности());

Для Каждого Колонка Из ОбъектМодели.Колонки() Цикл
Значение = ОбъектМодели.ПолучитьПриведенноеЗначениеПоля(
Сущность,
Колонка.ИмяПоля);
Рефлектор.УстановитьСвойство(СущностьВБД, Колонка.ИмяПоля, Значение);
КонецЦикла;

СтрокаТЗ._Идентификатор = Идентификатор;
СтрокаТЗ._Сущность = СущностьВБД;

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

// Удаляет сущность из таблицы БД.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
// Сущность - Произвольный - Объект (экземпляр класса, зарегистрированного в модели) для удаления из БД.
//
Процедура Удалить(ОбъектМодели, Сущность) Экспорт

ИмяТаблицы = ОбъектМодели.ИмяТаблицы();

Таблица = КешТаблиц.Получить(ИмяТаблицы);

Если Таблица = Неопределено Тогда
ВызватьИсключение "Таблица " + ИмяТаблицы + " не найдена";
КонецЕсли;

Идентификатор = ОбъектМодели.ПолучитьЗначениеИдентификатора(Сущность);
Если ТипЗнч(Идентификатор) = Тип("Число") Тогда
Идентификатор = Формат(Идентификатор, "ЧГ=");
КонецЕсли;

СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор");

Если НЕ СтрокаТЗ = Неопределено Тогда
Таблица.Удалить(СтрокаТЗ);
КонецЕсли;

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

// Осуществляет поиск строк в таблице по указанному отбору.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
// Отбор - Массив - Отбор для поиска. Каждый элемент массива должен иметь тип "ЭлементОтбора".
// Каждый элемент отбора преобразуется к условию поиска. В качестве "ПутьКДанным" указываются имена колонок.
//
// Возвращаемое значение:
// Массив - Массив, элементами которого являются "Соответствия". Ключом элемента соответствия является имя колонки,
// значением элемента соответствия - значение колонки.
//
Функция НайтиСтрокиВТаблице(ОбъектМодели, Отбор = Неопределено) Экспорт

ИмяТаблицы = ОбъектМодели.ИмяТаблицы();

Таблица = КешТаблиц.Получить(ИмяТаблицы);

Если Таблица = Неопределено Тогда
ВызватьИсключение "Таблица " + ИмяТаблицы + " не найдена";
КонецЕсли;

ПроцессорКоллекций = ПроцессорыКоллекций.ИзКоллекции(Таблица);

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

ДанныеТаблицы = ПроцессорКоллекций.ВМассив();

Результат = Новый Массив();

Колонки = ОбъектМодели.Колонки();

Для Каждого СтрокаДанныхТаблицы Из ДанныеТаблицы Цикл
ЗначенияКолонок = Новый Соответствие;
Для Каждого Колонка Из Колонки Цикл
Значение = Рефлектор.ПолучитьСвойство(СтрокаДанныхТаблицы._Сущность, Колонка.ИмяПоля);
ЗначенияКолонок.Вставить(Колонка.ИмяКолонки, Значение);
КонецЦикла;
Результат.Добавить(ЗначенияКолонок);
КонецЦикла;

Возврат Результат;

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

// Удаляет строки в таблице по указанному отбору.
//
// Параметры:
// ОбъектМодели - ОбъектМодели - Объект, содержащий описание класса-сущности и настроек таблицы БД.
// Отбор - Массив - Отбор для поиска. Каждый элемент массива должен иметь тип "ЭлементОтбора".
// Каждый элемент отбора преобразуется к условию поиска. В качестве "ПутьКДанным" указываются имена колонок.
//
Процедура УдалитьСтрокиВТаблице(ОбъектМодели, Знач Отбор) Экспорт
СтрокиКУдалению = НайтиСтрокиВТаблице(ОбъектМодели, Отбор);
Если СтрокиКУдалению.Количество() > 0 Тогда

ИмяКлонкиИдентификатора = ОбъектМодели.Идентификатор().ИмяКолонки;

ИмяТаблицы = ОбъектМодели.ИмяТаблицы();
Таблица = КешТаблиц.Получить(ИмяТаблицы);

Для Каждого СтрокаКУдалению Из СтрокиКУдалению Цикл
Идентификатор = СтрокаКУдалению.Получить(ИмяКлонкиИдентификатора);
Если ТипЗнч(Идентификатор) = Тип("Число") Тогда
Идентификатор = Формат(Идентификатор, "ЧГ=");
КонецЕсли;

СтрокаТЗ = Таблица.Найти(Идентификатор, "_Идентификатор");

Если НЕ СтрокаТЗ = Неопределено Тогда
Таблица.Удалить(СтрокаТЗ);
КонецЕсли;
КонецЦикла;

КонецЕсли;
КонецПроцедуры
Loading
Loading