1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-11-25 22:12:29 +02:00

MongoDB: Работа с базами и коллекциями

This commit is contained in:
Anton Titovets
2025-11-03 18:45:51 +03:00
parent f9debc0e2e
commit 47f3df6f21
22 changed files with 18051 additions and 321 deletions

View File

@@ -148,7 +148,7 @@ const DownloadPage = () => {
Скачать последнюю версию
</Heading>
<p className={styles.downloadSubtitle}>
Выберите подходящий язык и вариант поставки
Текущая версия: 1.29.0 | Выберите подходящий язык и вариант поставки
</p>
</div>
</div>

View File

@@ -100,7 +100,7 @@
}
.otherVersions {
text-align: center;
text-align: left;
margin-top: 2rem;
}

View File

@@ -11034,5 +11034,6 @@
"Работа с Twitter подразумевает работу с двумя API - v1 (1.1) и v2, которые, при этом, не относятся к разным видам действий, но просто являются версиями друг друга. Несмотря на то, что Twitter настаивает на использовании v2, вышло так, что некоторые механизмы (в частности механизм загрузки файлов) в ней так и не появилися. Поэтому, даже для создания обычного твита с картинкой необходима работа с обеими версиями API, а, как следствие, двойной набор авторизационных данны. Этот набор описан в функции": "Working with Twitter involves using two APIs - v1 (1.1) and v2, which are not separate types of actions but simply different versions of the API. Despite Twitter's preference for v2, it turned out that some mechanisms (such as the file upload mechanism) did not appear in it. Therefore, even for creating a regular tweet with an image, you need to work with both API versions, resulting in a double set of authentication data. This set is described in the function",
"Не рекомендуется использовать методы служебных модулей в других местах вашей конфигурации (если вы собираетесь обновляться до новых версий в дальнейшем). Для сохранения обратной совместимости, количество/назначение параметров и типы возвращаемых значений для методов работы с API не изменяются, но это не применимо к служебным модулям, которые могут изменяться как угодно для оптимизации и дополнения под новые нужды. Если вам необходим функционал из служебных модулей, рекомендуется скопировать его себе отдельно": "It is not recommended to use the methods of utility modules in other parts of your configuration (if you plan to update to new versions in the future). To maintain backward compatibility, the number/purpose of parameters and the return types for API interaction methods do not change, but this does not apply to utility modules, which can be modified in any way for optimization and adaptation to new requirements. If you need functionality from the utility modules, it is recommended to copy it separately",
"Ввести домееное имя и URL обработчика перенаправлений. Тут нужно отметить, что данный механизм создания приложений - новый. Еще недавно приложения VK создавались иначе и иметь redirect_url для них было не нужно. На данный момент не совсем понятно, зачем он нужен нам для серверного приложения - просто такого понятия как серверное приложение у VK теперь нет. Теоретически, туда можно вписать что угодно - для работы с библиотекой в получении обратных данных нет необходимости. Однако, с течением времени, это может измениться": "Enter the domain name and the URL of the redirect handler. It's worth noting that this mechanism for creating VK applications is new. Until recently, VK applications were created differently, and having a redirect URL was unnecessary. At the moment, it's not entirely clear why it's needed for our server application - VK no longer distinguishes server applications as such. Theoretically, you can enter anything there - there is no need for receiving callback data to work with the library. However, this may change over time",
"Перечень необходимых данных в виде структуры содержится в функции *ПолучитьСтандартныеПараметры()*. Вы можете указывать значения параметров прямо в ней или же передавать их структурой при вызове любых других методов библиотеки в качестве необязательного параметра *Параметры* (последний во всех методах билиотеки). В последнем случае стандартные параметры будут перезаписаны по ключам теми, которые переданы при вызове метода. Перезаписаны будут только совпадающие по ключам данные. Если какой то параметр есть в наборе стандартных, но не был передан при вызове метода, то он сохранит стандартное значение": "The list of necessary data in the form of a structure is contained in the function *GetStandardParameters()*. You can specify parameter values directly within it or pass them as a structure when calling any other library methods as an optional parameter *Parameters* (the last one in all library methods). In the latter case, the standard parameters will be overwritten by the ones passed during the method call. Only the data with matching keys will be overwritten. If a parameter exists in the standard set but was not passed during the method call, it will retain its default value"
"Перечень необходимых данных в виде структуры содержится в функции *ПолучитьСтандартныеПараметры()*. Вы можете указывать значения параметров прямо в ней или же передавать их структурой при вызове любых других методов библиотеки в качестве необязательного параметра *Параметры* (последний во всех методах билиотеки). В последнем случае стандартные параметры будут перезаписаны по ключам теми, которые переданы при вызове метода. Перезаписаны будут только совпадающие по ключам данные. Если какой то параметр есть в наборе стандартных, но не был передан при вызове метода, то он сохранит стандартное значение": "The list of necessary data in the form of a structure is contained in the function *GetStandardParameters()*. You can specify parameter values directly within it or pass them as a structure when calling any other library methods as an optional parameter *Parameters* (the last one in all library methods). In the latter case, the standard parameters will be overwritten by the ones passed during the method call. Only the data with matching keys will be overwritten. If a parameter exists in the standard set but was not passed during the method call, it will retain its default value",
"Текущая версия": "Current version"
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,11 @@
use serde_json::Value;
use serde_json::{json, Value};
use std::sync::mpsc::{self, Sender};
use std::thread::{self, JoinHandle};
use mongodb::bson::{Bson, Document};
use mongodb::Client;
use serde::{Deserialize, Serialize};
use crate::component::bson::{bson_to_json_value, json_value_to_bson};
use crate::component::format_json_error;
pub struct MongoBackend {
pub(crate) tx: Sender<BackendCommand>,
@@ -51,7 +52,7 @@ impl MongoBackend {
match client_result {
Ok(new_client) => {
client = Some(new_client);
let _ = response.send("Connection established successfully".to_string());
let _ = response.send("".to_string());
}
Err(error_msg) => {
let _ = response.send(error_msg);
@@ -69,7 +70,19 @@ impl MongoBackend {
&params
));
let _ = response.send(result.unwrap_or_else(|e| e));
let result_string = match result {
Ok(d) => {
let result_value = match serde_json::from_str(&d){
Ok (value) => value,
Err(_) => Value::String(d)
};
json!({"result": true, "data": result_value}).to_string()
},
Err(e) => format_json_error(&e)
};
let _ = response.send(result_string);
},
BackendCommand::Disconnect { response } => {
client = None;
@@ -106,8 +119,10 @@ async fn execute_operation(
params: &ExecuteParams,
) -> Result<String, String> {
let db_name = params.database.as_deref().unwrap_or("admin");
let db = client.database(db_name);
let db = match &params.database {
Some(d) => client.database(d),
None => client.default_database().unwrap_or(client.database("admin")),
};
let mut command = Document::new();
@@ -130,6 +145,7 @@ async fn execute_operation(
.await
.map_err(|e| format!("MongoDB command '{}' failed: {}", &params.operation, e))?;
let json_result = bson_to_json_value(&Bson::Document(result_doc));
serde_json::to_string(&json_result)
.map_err(|e| format!("Failed to serialize command result: {}", e))

View File

@@ -11,10 +11,15 @@ impl MongoBackend {
})
.map_err(|e| format!("Sending error: {}", e))?;
response_rx
let result = response_rx
.recv()
.map_err(|e| format!("Response receiver error: {}", e))?;
Ok(())
match result.is_empty(){
true => Ok(()),
false => Err(result),
}
}
pub fn disconnect(&self) -> Result<(), String> {

View File

@@ -17,6 +17,7 @@ pub fn json_value_to_bson(value: &Value) -> Bson {
},
Value::Object(obj) => {
if let Some(oid) = obj.get("__OPI_OID__") {
if let Some(oid_str) = oid.as_str() {
if let Ok(oid) = oid_str.parse::<bson::oid::ObjectId>() {

View File

@@ -5,7 +5,7 @@ mod bson;
use std::sync::{Arc, Mutex};
use addin1c::{name, Variant};
use crate::core::getset;
use serde_json::json;
use serde_json::{json};
// МЕТОДЫ КОМПОНЕНТЫ
@@ -111,10 +111,7 @@ impl AddIn {
Err(e) => return format_json_error(&e.to_string())
};
match guard.execute(json_string){
Ok(result) => json!({"result": true, "data": result}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
guard.execute(json_string).unwrap_or_else(|e| format_json_error(&e.to_string()))
}
pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {

File diff suppressed because one or more lines are too long

View File

@@ -160,6 +160,15 @@ impl MSSQLBackend {
}
pub fn shutdown(&mut self) {
let _ = self.tx.send(BackendCommand::Shutdown);
if let Some(handle) = self.thread_handle.take() {
if let Err(e) = handle.join() {
eprintln!("Backend thread panicked during shutdown: {:?}", e);
}
}
}
async fn execute_query_internal(
client: &mut Client<Compat<TcpStream>>,
query: &str,

View File

@@ -191,7 +191,19 @@ impl AddIn {
}
pub fn close_connection(&mut self) -> String {
match self.backend.lock() {
Ok(mut guard) => {
guard.shutdown();
}
Err(e) => {
return format_json_error(format!("Failed to acquire backend lock during close: {}", e).as_str());
}
}
self.backend = Arc::new(Mutex::new(backend::MSSQLBackend::new()));
self.initialized = false;
json!({"result": true}).to_string()
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,4 @@
// OneScript: ./OInt/core/Modules/OPI_MongoDB.os
// OneScript: ./OInt/core/Modules/OPI_MongoDB.os
// Lib: MongoDB
// CLI: mongodb
// Keywords: mongodb, mongo, nosql
@@ -184,22 +184,22 @@
КонецФункции
// Выполнить комманду
// Выполняет комманду по ее описанию
// Выполнить команду
// Выполняет команду по ее описанию
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
// Комманда - Строка - Имя комманды для выполнения - comm
// Комманда - Строка - Имя команды для выполнения - comm
// Аргумент - Произвольный - Аргумент команды - arg
// База - Строка - База данных, в которой необходимо провести операцию - db
// Данные - Структура Из КлючИЗначение - Основные поля данных для выполнения операции - data
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
Функция ВыполнитьКомманду(Знач Соединение
Функция ВыполнитьКоманду(Знач Соединение
, Знач Комманда
, Знач Аргумент = 1
, Знач База = "admin"
, Знач База = Неопределено
, Знач Данные = Неопределено) Экспорт
Если ЭтоКоннектор(Соединение) Тогда
@@ -223,7 +223,8 @@
КонецЕсли;
Если Аргумент <> Неопределено Тогда
OPI_Инструменты.ДобавитьПоле("argument", Аргумент, "Строка", СтруктураОперации);
ОбработанныйАргумент = ОбработатьДанныеДляОперации(Аргумент);
СтруктураОперации.Вставить("argument", ОбработанныйАргумент);
КонецЕсли;
Если Данные <> Неопределено Тогда
@@ -246,17 +247,184 @@
#КонецОбласти
#Область РаботаСБазами
// Получить список баз
// Получает список баз данных
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
Функция ПолучитьСписокБаз(Знач Соединение) Экспорт
Результат = ВыполнитьКоманду(Соединение, "listDatabases");
Возврат Результат;
КонецФункции
// Получить базу данных
// Получает информацию о базе данных
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
// База - Строка - Имя базы. Текущая база, если не указано - db
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
Функция ПолучитьБазуДанных(Знач Соединение, Знач База = Неопределено) Экспорт
OPI_ПреобразованиеТипов.ПолучитьСтроку(База);
Результат = ВыполнитьКоманду(Соединение, "dbStats", , База);
Возврат Результат;
КонецФункции
// Удалить базу данных
// Удаляет базу данных
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
// База - Строка - Имя базы. Текущая база, если не указано - db
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
Функция УдалитьБазуДанных(Знач Соединение, Знач База = Неопределено) Экспорт
OPI_ПреобразованиеТипов.ПолучитьСтроку(База);
Результат = ВыполнитьКоманду(Соединение, "dropDatabase", , База);
Возврат Результат;
КонецФункции
#КонецОбласти
#Область РаботаСКоллекциями
// Создать коллекцию
// Создает новую коллекцию с указанными параметрами
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
// Наименование - Строка - Имя новой коллекции - name
// База - Строка - Имя базы. Текущая база, если не указано - db
// Параметры - Структура Из КлючИЗначение - Дополнительные параметры создания - params
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
Функция СоздатьКоллекцию(Знач Соединение
, Знач Наименование
, Знач База = Неопределено
, Знач Параметры = Неопределено) Экспорт
OPI_ПреобразованиеТипов.ПолучитьСтроку(Наименование);
Если Параметры <> Неопределено Тогда
OPI_ПреобразованиеТипов.ПолучитьКоллекциюКлючИЗначение(Параметры);
КонецЕсли;
Если База <> Неопределено Тогда
OPI_ПреобразованиеТипов.ПолучитьСтроку(База);
КонецЕсли;
Результат = ВыполнитьКоманду(Соединение, "createCollection", Наименование, База, Параметры);
Возврат Результат;
КонецФункции
// Удалить коллекцию
// Удаляет выбранную коллекцию базы
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
// Коллекция - Строка - Имя коллекции - coll
// База - Строка - Имя базы. Текущая база, если не указано - db
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
Функция УдалитьКоллекцию(Знач Соединение, Знач Коллекция, Знач База = Неопределено) Экспорт
OPI_ПреобразованиеТипов.ПолучитьСтроку(Коллекция);
Если База <> Неопределено Тогда
OPI_ПреобразованиеТипов.ПолучитьСтроку(База);
КонецЕсли;
Результат = ВыполнитьКоманду(Соединение, "drop", Коллекция, База);
Возврат Результат;
КонецФункции
#КонецОбласти
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ОбработатьДанныеДляОперации(Знач Данные)
OPI_ПреобразованиеТипов.ПолучитьКоллекциюКлючИЗначение(Данные);
ОбработанныеДанные = OPI_Инструменты.КопироватьКоллекцию(Данные);
Попытка
ОбработанныеДанные = Данные;
OPI_ПреобразованиеТипов.ПолучитьКоллекциюКлючИЗначение(ОбработанныеДанные);
ОбработанныеДанные = ОбработатьКоллекциюДляОперации(ОбработанныеДанные);
Исключение
ОбработанныеДанные = Данные;
Если OPI_Инструменты.ЭтоКоллекция(ОбработанныеДанные) Тогда
ОбработанныеДанные = ОбработатьКоллекциюДляОперации(ОбработанныеДанные);
ИначеЕсли ТипЗнч(ОбработанныеДанные) = Тип("ДвоичныеДанные") Тогда
ОбработанныеДанные = Новый Структура("__OPI_BINARY__", ПолучитьBase64СтрокуИзДвоичныхДанных(ОбработанныеДанные));
ИначеЕсли ТипЗнч(ОбработанныеДанные) = Тип("Дата") Тогда
ОбработанныеДанные = Новый Структура("__OPI_DATE__", OPI_Инструменты.ДатаRFC3339(ОбработанныеДанные));
ИначеЕсли Не ТипЗнч(ОбработанныеДанные) = Тип("Число") И Не ТипЗнч(ОбработанныеДанные) = Тип("Булево") Тогда
OPI_ПреобразованиеТипов.ПолучитьСтроку(ОбработанныеДанные);
КонецЕсли;
КонецПопытки;
Возврат ОбработанныеДанные;
КонецФункции
Функция ОбработатьКоллекциюДляОперации(Знач Данные)
ОбработанныеДанные = Тип(ТипЗнч(Данные));
Если OPI_Инструменты.ЭтоКоллекция(ОбработанныеДанные) Тогда
Для Каждого ЧастьДанных Из Данные Цикл
ТекущийКлюч = Строка(ЧастьДанных.Ключ);
ТекущееЗначение = ОбработатьДанныеДляОперации(ЧастьДанных.Значение);
ОбработанныеДанные.Вставить(ТекущийКлюч, ТекущееЗначение);
КонецЦикла;
Иначе
Для Каждого Элемент Из Данные Цикл
ОбработанныеДанные.Добавить(ОбработатьДанныеДляОперации(Элемент));
КонецЦикла;
КонецЕсли;
Возврат ОбработанныеДанные;
КонецФункции
#КонецОбласти

View File

@@ -394,6 +394,7 @@
НовыйТест(ТаблицаТестов, "MSS_ОсновныеМетоды" , "Основные методы" , MSSQL);
НовыйТест(ТаблицаТестов, "MSS_ORM" , "ORM" , MSSQL);
НовыйТест(ТаблицаТестов, "Mongo_ОсновныеМетоды" , "Основные методы" , MongoDB);
НовыйТест(ТаблицаТестов, "Mongo_РаботаСБазами" , "Работа с базами" , MongoDB);
НовыйТест(ТаблицаТестов, "GAPI_УправлениеГруппами" , "Управление группами" , GreenAPI);
НовыйТест(ТаблицаТестов, "GAPI_ОтправкаСообщений" , "Отправка сообщений" , GreenAPI);
НовыйТест(ТаблицаТестов, "GAPI_ПолучениеУведомлений" , "Получение уведомлений" , GreenAPI);
@@ -11768,7 +11769,7 @@
Функция Проверка_MongoDB_СформироватьСтрокуПодключения(Знач Результат, Знач Вариант, Параметры = "")
Адрес = ПолучитьLocalhost() + Параметры["MongoDB_Port"];
Адрес = "127.0.0.1:1234";
Логин = Параметры["MongoDB_User"];
Пароль = Параметры["MongoDB_Password"];
База = Параметры["MongoDB_DB"];
@@ -11797,7 +11798,22 @@
Функция Проверка_MongoDB_ВыполнитьКоманду(Знач Результат, Знач Вариант)
Если Вариант = "Подключение" Тогда
Результат = Строка(ТипЗнч(Результат));
ОжидаетЧто(Результат).Равно("AddIn.OPI_MongoDB.Main");
Иначе
ОжидаетЧто(Результат["result"]).Равно(Истина);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция Проверка_MongoDB_ПолучитьБазуДанных(Знач Результат, Знач Вариант)
ОжидаетЧто(Результат["result"]).Равно(Истина);
ОжидаетЧто(Результат["data"]["ok"]).Равно(1);
ОжидаетЧто(Результат["data"]["db"]).Равно("test_db");
Возврат Результат;

View File

@@ -3117,7 +3117,20 @@
MongoDB_СформироватьСтрокуПодключения(ПараметрыТеста);
MongoDB_ОткрытьСоединение(ПараметрыТеста);
MongoDB_ВыполнитьКомманду(ПараметрыТеста);
MongoDB_ВыполнитьКоманду(ПараметрыТеста);
КонецПроцедуры
Процедура Mongo_РаботаСБазами() Экспорт
ПараметрыТеста = Новый Структура;
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("MongoDB_Port" , ПараметрыТеста);
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("MongoDB_User" , ПараметрыТеста);
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("MongoDB_Password", ПараметрыТеста);
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("MongoDB_DB" , ПараметрыТеста);
MongoDB_ПолучитьБазуДанных(ПараметрыТеста);
КонецПроцедуры
@@ -24276,8 +24289,6 @@
Пароль = ПараметрыФункции["MongoDB_Password"];
База = ПараметрыФункции["MongoDB_DB"];
Адрес = OPI_ПолучениеДанныхТестов.ПолучитьLocalhost() + ПараметрыФункции["MongoDB_Port"]; // END
ПараметрыПодключения = Новый Структура("authSource", "admin");
Результат = OPI_MongoDB.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль, ПараметрыПодключения);
@@ -24294,7 +24305,7 @@
Пароль = ПараметрыФункции["MongoDB_Password"];
База = ПараметрыФункции["MongoDB_DB"];
Адрес = OPI_ПолучениеДанныхТестов.ПолучитьLocalhost() + ПараметрыФункции["MongoDB_Port"]; // END
Адрес = OPI_ПолучениеДанныхТестов.ПолучитьLocalhost() + ":" + ПараметрыФункции["MongoDB_Port"]; // END
ПараметрыПодключения = Новый Структура("authSource", "admin");
СтрокаПодключения = OPI_MongoDB.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль, ПараметрыПодключения);
@@ -24311,14 +24322,14 @@
КонецПроцедуры
Процедура MongoDB_ВыполнитьКомманду(ПараметрыФункции)
Процедура MongoDB_ВыполнитьКоманду(ПараметрыФункции)
Адрес = "127.0.0.1:1234";
Логин = ПараметрыФункции["MongoDB_User"];
Пароль = ПараметрыФункции["MongoDB_Password"];
База = ПараметрыФункции["MongoDB_DB"];
Адрес = OPI_ПолучениеДанныхТестов.ПолучитьLocalhost() + ПараметрыФункции["MongoDB_Port"]; // END
Адрес = OPI_ПолучениеДанныхТестов.ПолучитьLocalhost() + ":" + ПараметрыФункции["MongoDB_Port"]; // END
ПараметрыПодключения = Новый Структура("authSource", "admin");
СтрокаПодключения = OPI_MongoDB.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль, ПараметрыПодключения);
@@ -24327,11 +24338,37 @@
Данные = Новый Структура("nameOnly", Истина);
Соединение = OPI_MongoDB.ОткрытьСоединение(СтрокаПодключения);
Результат = OPI_MongoDB.ВыполнитьКомманду(Соединение, Комманда, , , Данные);
Обработать(Соединение, "MongoDB", "ВыполнитьКоманду", "Подключение"); // SKIP
Результат = OPI_MongoDB.ВыполнитьКоманду(Соединение, Комманда, , , Данные);
// END
Обработать(Результат, "MongoDB", "ВыполнитьКомманду");
Обработать(Результат, "MongoDB", "ВыполнитьКоманду");
КонецПроцедуры
Процедура MongoDB_ПолучитьБазуДанных(ПараметрыФункции)
Адрес = "127.0.0.1:1234";
Логин = ПараметрыФункции["MongoDB_User"];
Пароль = ПараметрыФункции["MongoDB_Password"];
База = ПараметрыФункции["MongoDB_DB"];
Адрес = OPI_ПолучениеДанныхТестов.ПолучитьLocalhost() + ":" + ПараметрыФункции["MongoDB_Port"]; // END
ПараметрыПодключения = Новый Структура("authSource", "admin");
СтрокаПодключения = OPI_MongoDB.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль, ПараметрыПодключения);
Соединение = OPI_MongoDB.ОткрытьСоединение(СтрокаПодключения);
База = "test_db";
Результат = OPI_MongoDB.ПолучитьБазуДанных(Соединение, База);
// END
Обработать(Результат, "MongoDB", "ПолучитьБазуДанных");
КонецПроцедуры