mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2025-01-12 04:34:10 +02:00
Начало SQLite
This commit is contained in:
parent
b70b695407
commit
a11a31d0d8
1
.gitignore
vendored
1
.gitignore
vendored
@ -23,3 +23,4 @@ target/
|
||||
!oscript.exe
|
||||
addin.zip
|
||||
src/addins/tcp_server/OPI_TCPServer.zip
|
||||
src/addins/sqlite/OPI_SQLite.zip
|
||||
|
275
src/addins/sqlite/Cargo.lock
generated
Normal file
275
src/addins/sqlite/Cargo.lock
generated
Normal file
@ -0,0 +1,275 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addin1c"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef34e8b7ff4c43e87491a4cc30a4779a9f67c50db43378a36362c7a56246e05b"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"utf16_lit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "opi_sqlite"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"addin1c",
|
||||
"base64",
|
||||
"rusqlite",
|
||||
"serde_json",
|
||||
"serde_rusqlite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.134"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_rusqlite"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b741cc5ef185cd96157e762c3bba743c4e94c8dc6af0edb053c48d2b3c27e691"
|
||||
dependencies = [
|
||||
"rusqlite",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "utf16_lit"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
20
src/addins/sqlite/Cargo.toml
Normal file
20
src/addins/sqlite/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "opi_sqlite"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
lto = true # Enable Link Time Optimization
|
||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||
panic = "abort" # Abort on panic
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
|
||||
[dependencies]
|
||||
addin1c = "0.5.0"
|
||||
rusqlite = { version = "0.32.1", features = ["bundled"]}
|
||||
serde_json = "1.0"
|
||||
serde_rusqlite = "0.36.0"
|
||||
base64 = "0.22.1"
|
7
src/addins/sqlite/MANIFEST.XML
Normal file
7
src/addins/sqlite/MANIFEST.XML
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<bundle xmlns='http://v8.1c.ru/8.2/addin/bundle' name='OPIADDIN'>
|
||||
<component os='Windows' path='AddIn_x86_windows.dll' type='native' arch='i386' />
|
||||
<component os='Windows' path='AddIn_x64_windows.dll' type='native' arch='x86_64' />
|
||||
<component os='Linux' path='AddIn_x86_linux.so' type='native' arch='i386' />
|
||||
<component os='Linux' path='AddIn_x64_linux.so' type='native' arch='x86_64' />
|
||||
</bundle>
|
69
src/addins/sqlite/release.bat
Normal file
69
src/addins/sqlite/release.bat
Normal file
@ -0,0 +1,69 @@
|
||||
@echo off
|
||||
|
||||
:: Установить переменную
|
||||
set CARGO_NAME=opi_sqlite
|
||||
set LIB_NAME=OPI_SQLite
|
||||
set OPENSSL_DIR=C:\msys64\mingw64
|
||||
set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
|
||||
set OPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include
|
||||
|
||||
|
||||
:: Перейти в директорию проекта
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: Создать папку для артефактов
|
||||
set OUTPUT_DIR=artifacts
|
||||
if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
|
||||
|
||||
:: Сборка для x86_64-pc-windows-msvc
|
||||
cargo build --release --target x86_64-pc-windows-msvc
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Сборка для x86_64-unknown-linux-gnu
|
||||
cargo zigbuild --release --target x86_64-unknown-linux-gnu
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Сборка для i686-pc-windows-msvc
|
||||
cargo build --release --target i686-pc-windows-msvc
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Сборка для i686-unknown-linux-gnu
|
||||
cargo zigbuild --release --target i686-unknown-linux-gnu
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Копирование файлов .dll и .so
|
||||
copy /y target\x86_64-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\i686-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\x86_64-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\i686-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Архивация
|
||||
powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip"
|
||||
copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip"
|
||||
|
||||
copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
|
||||
copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
|
||||
|
||||
if exist "%OUTPUT_DIR%" (
|
||||
rmdir /S /Q "%OUTPUT_DIR%"
|
||||
)
|
||||
|
||||
@echo Build and packaging completed successfully.
|
||||
exit /b 0
|
||||
|
||||
:error
|
||||
@echo An error occurred during the build or packaging process.
|
||||
exit /b 1
|
126
src/addins/sqlite/src/component/methods.rs
Normal file
126
src/addins/sqlite/src/component/methods.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use rusqlite::{types::ValueRef};
|
||||
use serde_json::{Value, json, Map};
|
||||
use crate::component;
|
||||
use serde_rusqlite::{to_params};
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
|
||||
pub fn execute_query(
|
||||
client: &mut component::AddIn,
|
||||
query: String,
|
||||
params_json: String,
|
||||
) -> String {
|
||||
|
||||
let conn = match client.get_connection() {
|
||||
Some(c) => c,
|
||||
None => return r#"{"result": false, "error": "No connection initialized"}"#.to_string(),
|
||||
};
|
||||
|
||||
// Парсинг JSON параметров
|
||||
let parsed_params: Value = match serde_json::from_str(¶ms_json) {
|
||||
Ok(params) => params,
|
||||
Err(e) => {
|
||||
return format!(
|
||||
r#"{{"result": false, "error": "Invalid JSON parameters: {}"}}"#,
|
||||
e.to_string()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let params_array = match parsed_params.as_array() {
|
||||
Some(array) => array,
|
||||
None => {
|
||||
return r#"{"result": false, "error": "Parameters must be a JSON array"}"#.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let convert = to_params(params_array).unwrap();
|
||||
|
||||
// Определяем тип запроса
|
||||
if query.trim_start().to_uppercase().starts_with("SELECT") {
|
||||
// Выполняем SELECT
|
||||
match conn.prepare(&query) {
|
||||
Ok(mut query_result) => {
|
||||
|
||||
let cols: Vec<String> = query_result
|
||||
.column_names()
|
||||
.iter()
|
||||
.map(|name| name.to_string())
|
||||
.collect();
|
||||
|
||||
let res = query_result.query(convert);
|
||||
|
||||
match res{
|
||||
Ok(mut rows) => {
|
||||
rows_to_json_array(&mut rows, &cols)
|
||||
}
|
||||
Err(e) => {
|
||||
format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Err(e) => {
|
||||
format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
match conn.execute(&query, convert) {
|
||||
Ok(_) => r#"{"result": true}"#.to_string(),
|
||||
Err(e) => format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rows_to_json_array(rows: &mut rusqlite::Rows, cols: &Vec<String>) -> String {
|
||||
|
||||
let mut json_array = Vec::new();
|
||||
|
||||
loop {
|
||||
|
||||
let mut current: Map<String, Value> = Map::new();
|
||||
|
||||
match rows.next() {
|
||||
|
||||
Ok(Some(row)) => {
|
||||
|
||||
for i in 0..cols.len() {
|
||||
|
||||
let val = row.get_ref_unwrap(i);
|
||||
let jval = from_sql_to_json(val);
|
||||
|
||||
current.insert(cols[i].to_string(), jval);
|
||||
};
|
||||
|
||||
json_array.push(current);
|
||||
|
||||
}
|
||||
|
||||
Ok(None) => break,
|
||||
Err(e) => {
|
||||
current.insert("error".to_string(), Value::String(e.to_string()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
json!(json_array).to_string()
|
||||
}
|
||||
|
||||
fn from_sql_to_json(value: ValueRef) -> Value {
|
||||
match value {
|
||||
ValueRef::Null => Value::Null,
|
||||
ValueRef::Integer(i) => Value::Number(i.into()),
|
||||
ValueRef::Real(f) => {
|
||||
serde_json::Number::from_f64(f).map(Value::Number).unwrap_or(Value::Null)
|
||||
}
|
||||
ValueRef::Text(t) => Value::String(String::from_utf8_lossy(t).into_owned()),
|
||||
ValueRef::Blob(b) => {
|
||||
let base64_string = general_purpose::STANDARD.encode(b); // Кодируем в Base64
|
||||
let mut blob_object = serde_json::Map::new();
|
||||
blob_object.insert("blob".to_string(), Value::String(base64_string)); // Оборачиваем в объект
|
||||
Value::Object(blob_object)
|
||||
},
|
||||
}
|
||||
}
|
108
src/addins/sqlite/src/component/mod.rs
Normal file
108
src/addins/sqlite/src/component/mod.rs
Normal file
@ -0,0 +1,108 @@
|
||||
mod methods;
|
||||
|
||||
use addin1c::{name, Variant};
|
||||
use crate::core::getset;
|
||||
use rusqlite::{Connection};
|
||||
|
||||
// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
|
||||
|
||||
// Синонимы
|
||||
pub const METHODS: &[&[u16]] = &[
|
||||
name!("Connect"),
|
||||
name!("Execute"), // 0
|
||||
|
||||
];
|
||||
|
||||
// Число параметров функций компоненты
|
||||
pub fn get_params_amount(num: usize) -> usize {
|
||||
match num {
|
||||
0 => 0,
|
||||
1 => 2,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Соответствие функций Rust функциям компоненты
|
||||
// Вызовы должны быть обернуты в Box::new
|
||||
pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn getset::ValueType> {
|
||||
|
||||
match num {
|
||||
|
||||
0 =>{
|
||||
Box::new(obj.initialize())
|
||||
},
|
||||
|
||||
1 => {
|
||||
|
||||
let query = params[0].get_string().unwrap_or("".to_string());
|
||||
let params_json = params[1].get_string().unwrap_or("".to_string());
|
||||
|
||||
Box::new(methods::execute_query(obj, query, params_json))
|
||||
},
|
||||
_ => Box::new(false), // Неверный номер команды
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// ПОЛЯ КОМПОНЕНТЫ ---------------------------------------------------------------------------------
|
||||
|
||||
// Синонимы
|
||||
pub const PROPS: &[&[u16]] = &[
|
||||
name!("Database")
|
||||
];
|
||||
|
||||
|
||||
pub struct AddIn {
|
||||
connection_string: String,
|
||||
connection: Option<Connection>,
|
||||
}
|
||||
|
||||
impl AddIn {
|
||||
/// Создает новый объект
|
||||
pub fn new() -> Self {
|
||||
AddIn {
|
||||
connection_string: String::new(),
|
||||
connection: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self) -> String {
|
||||
let conn_result = if self.connection_string.is_empty() {
|
||||
Connection::open_in_memory()
|
||||
} else {
|
||||
Connection::open(&self.connection_string)
|
||||
};
|
||||
|
||||
match conn_result {
|
||||
Ok(conn) => {
|
||||
self.connection = Some(conn);
|
||||
r#"{"result": true}"#.to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_connection(&self) -> Option<&Connection> {
|
||||
self.connection.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {
|
||||
match index {
|
||||
0 => &self.connection_string as &dyn getset::ValueType as *const _,
|
||||
_ => panic!("Index out of bounds"),
|
||||
}
|
||||
}
|
||||
pub fn get_field_ptr_mut(&mut self, index: usize) -> *mut dyn getset::ValueType { self.get_field_ptr(index) as *mut _ }
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// УНИЧТОЖЕНИЕ ОБЪЕКТА -----------------------------------------------------------------------------
|
||||
|
||||
// Обработка удаления объекта
|
||||
impl Drop for AddIn {
|
||||
fn drop(&mut self) {}
|
||||
}
|
78
src/addins/sqlite/src/core/getset.rs
Normal file
78
src/addins/sqlite/src/core/getset.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use addin1c::{Variant, Tm};
|
||||
|
||||
|
||||
pub trait ValueType {
|
||||
fn get_value(&self, val: &mut Variant) -> bool;
|
||||
fn set_value(&mut self, val: &Variant);
|
||||
}
|
||||
|
||||
// Реализация для i32
|
||||
impl ValueType for i32 {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_i32(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_i32().unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для f64
|
||||
impl ValueType for f64 {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_f64(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_f64().unwrap_or(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для bool
|
||||
impl ValueType for bool {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_bool(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_bool().unwrap_or(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для tm
|
||||
impl ValueType for Tm {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_date(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_date().unwrap_or(Tm::default());
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для String
|
||||
impl ValueType for String {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
let s: Vec<u16> = self.encode_utf16().collect();
|
||||
val.set_str1c(s.as_slice()).is_ok()
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_string().unwrap_or("".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для Vec<u8>
|
||||
impl ValueType for Vec<u8> {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_blob(self.as_slice()).is_ok()
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_blob().unwrap_or(&[]).to_vec()
|
||||
}
|
||||
}
|
53
src/addins/sqlite/src/core/mod.rs
Normal file
53
src/addins/sqlite/src/core/mod.rs
Normal file
@ -0,0 +1,53 @@
|
||||
pub mod getset;
|
||||
|
||||
use addin1c::{name, RawAddin, Variant};
|
||||
|
||||
use crate::component::METHODS;
|
||||
use crate::component::PROPS;
|
||||
use crate::component::get_params_amount;
|
||||
use crate::component::cal_func;
|
||||
use crate::component::AddIn;
|
||||
|
||||
// Определение класса
|
||||
impl RawAddin for AddIn {
|
||||
|
||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||
name!("Main")
|
||||
}
|
||||
fn get_n_props(&mut self) -> usize {
|
||||
PROPS.len()
|
||||
}
|
||||
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
|
||||
PROPS.iter().position(|&x| x == name)
|
||||
}
|
||||
fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { PROPS.get(num).copied() }
|
||||
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {let field: &dyn getset::ValueType = &self[num]; field.get_value(val) }
|
||||
fn set_prop_val(&mut self, num: usize, val: &Variant) -> bool {let field: &mut dyn getset::ValueType = &mut self[num]; field.set_value(val); true }
|
||||
fn is_prop_readable(&mut self, _num: usize) -> bool { true }
|
||||
fn is_prop_writable(&mut self, _num: usize) -> bool { true }
|
||||
fn get_n_methods(&mut self) -> usize { METHODS.len() }
|
||||
fn find_method(&mut self, name: &[u16]) -> Option<usize> { METHODS.iter().position(|&x| x == name) }
|
||||
fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { METHODS.get(num).copied() }
|
||||
fn get_n_params(&mut self, num: usize) -> usize { get_params_amount(num) }
|
||||
fn get_param_def_value(&mut self, _method_num: usize, _param_num: usize, _value: Variant, ) -> bool { true }
|
||||
fn has_ret_val(&mut self, _num: usize) -> bool { true }
|
||||
fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool { false }
|
||||
fn call_as_func(&mut self, num: usize, params: &mut [Variant], ret_value: &mut Variant, ) -> bool { cal_func(self, num, params).get_value(ret_value) }
|
||||
|
||||
}
|
||||
|
||||
impl std::ops::Index<usize> for AddIn {
|
||||
type Output = dyn getset::ValueType;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
unsafe { &*self.get_field_ptr(index) }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::IndexMut<usize> for AddIn {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
unsafe { &mut *self.get_field_ptr_mut(index) }
|
||||
}
|
||||
}
|
||||
|
||||
|
49
src/addins/sqlite/src/lib.rs
Normal file
49
src/addins/sqlite/src/lib.rs
Normal file
@ -0,0 +1,49 @@
|
||||
pub mod component;
|
||||
mod core;
|
||||
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_long, c_void},
|
||||
sync::atomic::{AtomicI32, Ordering},
|
||||
};
|
||||
|
||||
use component::AddIn;
|
||||
use addin1c::{create_component, destroy_component, name, AttachType};
|
||||
|
||||
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long {
|
||||
|
||||
let addin = AddIn::new();
|
||||
create_component(component, addin)
|
||||
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long {
|
||||
destroy_component(component)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn GetClassNames() -> *const u16 {
|
||||
// small strings for performance
|
||||
name!("Main").as_ptr()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
#[allow(static_mut_refs)]
|
||||
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
|
||||
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
|
||||
3
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn GetAttachType() -> AttachType {
|
||||
AttachType::Any
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
@echo off
|
||||
|
||||
:: Установить переменную
|
||||
set LIB_NAME=opi_addin
|
||||
set CARGO_NAME=opi_addin
|
||||
set LIB_NAME=OPI_AddIn
|
||||
set OPENSSL_DIR=C:\msys64\mingw64
|
||||
set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
|
||||
set OPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include
|
||||
@ -31,26 +32,31 @@ cargo zigbuild --release --target i686-unknown-linux-gnu
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Копирование файлов .dll и .so
|
||||
copy /y target\x86_64-pc-windows-msvc\release\%LIB_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
|
||||
copy /y target\x86_64-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\i686-pc-windows-msvc\release\%LIB_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
|
||||
copy /y target\i686-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\x86_64-unknown-linux-gnu\release\lib%LIB_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
|
||||
copy /y target\x86_64-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\i686-unknown-linux-gnu\release\lib%LIB_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
|
||||
copy /y target\i686-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Архивация
|
||||
set ZIP_NAME=addin.zip
|
||||
powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%ZIP_NAME%'"
|
||||
powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip"
|
||||
copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip"
|
||||
|
||||
copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
|
||||
copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
|
||||
|
||||
if exist "%OUTPUT_DIR%" (
|
||||
rmdir /S /Q "%OUTPUT_DIR%"
|
||||
)
|
||||
|
@ -24,13 +24,13 @@ impl RawAddin for AddIn {
|
||||
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {let field: &dyn getset::ValueType = &self[num]; field.get_value(val) }
|
||||
fn set_prop_val(&mut self, num: usize, val: &Variant) -> bool {let field: &mut dyn getset::ValueType = &mut self[num]; field.set_value(val); true }
|
||||
fn is_prop_readable(&mut self, _num: usize) -> bool { true }
|
||||
fn is_prop_writable(&mut self, num: usize) -> bool { true }
|
||||
fn is_prop_writable(&mut self, _num: usize) -> bool { true }
|
||||
fn get_n_methods(&mut self) -> usize { METHODS.len() }
|
||||
fn find_method(&mut self, name: &[u16]) -> Option<usize> { METHODS.iter().position(|&x| x == name) }
|
||||
fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { METHODS.get(num).copied() }
|
||||
fn get_n_params(&mut self, num: usize) -> usize { get_params_amount(num) }
|
||||
fn get_param_def_value(&mut self, _method_num: usize, _param_num: usize, _value: Variant, ) -> bool { true }
|
||||
fn has_ret_val(&mut self, num: usize) -> bool { true }
|
||||
fn has_ret_val(&mut self, _num: usize) -> bool { true }
|
||||
fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool { false }
|
||||
fn call_as_func(&mut self, num: usize, params: &mut [Variant], ret_value: &mut Variant, ) -> bool { cal_func(self, num, params).get_value(ret_value) }
|
||||
|
||||
|
@ -14,7 +14,7 @@ pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn GetClassObject(name: *const u16, component: *mut *mut c_void) -> c_long {
|
||||
pub unsafe extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long {
|
||||
|
||||
let addin = AddIn::new();
|
||||
create_component(component, addin)
|
||||
@ -35,6 +35,7 @@ pub extern "C" fn GetClassNames() -> *const u16 {
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(static_mut_refs)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
|
||||
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
|
||||
|
BIN
src/en/OInt/addins/OPI_SQLite.zip
Normal file
BIN
src/en/OInt/addins/OPI_SQLite.zip
Normal file
Binary file not shown.
BIN
src/ru/OInt/addins/OPI_SQLite.zip
Normal file
BIN
src/ru/OInt/addins/OPI_SQLite.zip
Normal file
Binary file not shown.
9
src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo
Normal file
9
src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mdclass:CommonTemplate xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="b732dedd-b9cd-40d8-9482-847467424ab2">
|
||||
<name>OPI_SQLite</name>
|
||||
<synonym>
|
||||
<key>ru</key>
|
||||
<value>SQLite</value>
|
||||
</synonym>
|
||||
<templateType>AddIn</templateType>
|
||||
</mdclass:CommonTemplate>
|
BIN
src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin
Normal file
BIN
src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin
Normal file
Binary file not shown.
@ -40,6 +40,7 @@
|
||||
</configurationInformationAddress>
|
||||
<subsystems>Subsystem.OPI_Интеграция</subsystems>
|
||||
<commonTemplates>CommonTemplate.OPI_TCPClient</commonTemplates>
|
||||
<commonTemplates>CommonTemplate.OPI_SQLite</commonTemplates>
|
||||
<commonModules>CommonModule.OPI_Инструменты</commonModules>
|
||||
<commonModules>CommonModule.OPI_Криптография</commonModules>
|
||||
<commonModules>CommonModule.OPI_ПреобразованиеТипов</commonModules>
|
||||
|
Loading…
Reference in New Issue
Block a user