Если вы не слышали ранее об Открытом Пакете Интеграций (что вполне вероятно), то небольшая вводная часть ниже, под катом. Тем, кто уже знаком с ОПИ, данный раздел можно пропустить.
Что такое Открытый Пакет Интеграций

Открытый Пакет Интеграций (ОПИ) - это open-source набор методов для простой и быстрой интеграции с различными популярными API. Он состоит из аналогичных по функционалу 1С-расширения (CFE), OS-пакета и программы для Windows и Linux, которые предоставляют готовые функции для работы с целым набором различных онлайн-сервисов.

- ОПИ бесплатен и имеет открытый исходный код на GitHub. Вы всегда можете получить последнюю версию библиотеки на странице репозитория, а подписавшись - узнавать о выходе обновлений. Все релизы сопровождаются статьями на Инфостарт и разделами единой документации. На Инфостарт вы можете подписаться уже хоть сейчас, а про документацию я расскажу далее.

- Удобная единая документация. Она расположена на сайте openintegrations.dev и содержит в себе всю информацию, необходимую для работы: инструкции по предварительным действиям для начала интеграции, описания всех методов с параметрами и возвращаемыми значениями, примеры кода и т.д. Каждый API имеет там свой раздел.
- Простая установка. ОПИ распространяется во множестве вариантах: как XML файлы расширения, как EDT проект расширения, как файл расширения формата .cfe (версия 1С 8.3.9), как файл пакета для OneScript и еще в целом наборе пакетов и файлов для Windows и Linux. Из этого набора вы всегда сможете выбрать тот способ установки, который лучше подойдет для вашей конкретной задачи
На момент последнего обновления данной статьи, доступны следующие API:





















Наиболее актуальную информацию можно посмотреть в репозитории или на вводной странице документации.

PostgreSQL - крайне популярная реляционная SQL СУБД - одна из самых популярных в мире, хорошо известная в том числе и в 1С-сообществе
Несмотря на то, что тема PostgreSQL в нашей среде наиболее актуальна сейчас, когда дело касается внедрения и оптимизации для работы с самой платформой 1С:Предприятие, она также часто встречается и как просто связующее звено 1С с другими системами, использующими ее как источник данных (вроде сайтов или приложений)
О втором варианте работы сегодня и пойдет речь: в данном обновлении Открытого пакета интеграций были добавлены методы для работы с базами данных PostgreSQL без необходимости в установке дополнительных драйверов или создании внешних источников данных. Но обо всем по порядку
Реализованные методы
PostgreSQL - вторая СУБД в наборе ОПИ. Не так давно, в одном из предыдущих обновлений, уже был добавлен коннектор для работы с базами SQLite, состоящий из основных функций, вроде выполнения произвольных SQL запросов, и небольшой ORM, реализующей набор основных действий, наиболее часто встречающихся при работе с подобными источниками данных. Сегодняшний набор не сильно отличается от предыдущего, хотя и был слегка расширен. На данный момент в него входят:
- Основные методы
- Открытие соединения
- Закрытие соединения
- Выполнение SQL-запроса
- Формирование строки подключения из основных данных
- Методы ORM
- Создание базы данных
- Удаление базы данных
- Отключение всех соединений базы данных
- Получение информации о таблице
- Создание таблицы
- Очистка таблицы
- Удаление таблицы
- Добавление записей
- Получение записей
- Обновление данных записей
- Удаление записей
А, собственно, и все: вы просто можете работать с произвольными базами postgres при помощи этих методов без каких-либо дополнительных действий! Разве что мы еще остановимся на паре моментов, которые мне кажутся важными и могут вызывать вопросы
Параметры запросов
Данное решение позволяет не только выполнять произвольные запросы, но и устанавливать позиционные параметры в них. Каждый такой параметр должен представлять из себя структуру с одним КлючЗначением, где ключ - название типа данных, а значение - непосредственно значение параметра. Ниже приведены все доступные типы данных и подходящие значения 1С:
🟢 - Реализовано, проверено; 🟡 - Реализовано, не проверено
Тип |
Поддержка |
Синонимы |
Допустимые нативные типы |
BOOL |
🟢 |
- |
Булево |
"char" |
🟢 |
OLDCHAR |
Число |
SMALLINT |
🟢 |
- |
Число |
SMALLSERIAL |
🟢 |
- |
Число |
INT |
🟢 |
- |
Число |
SERIAL |
🟢 |
- |
Число |
BIGINT |
🟢 |
- |
Число |
BIGSERIAL |
🟢 |
- |
Число |
OID |
🟢 |
- |
Число |
REAL |
🟢 |
- |
Число |
DOUBLE PRECISION |
🟢 |
DOUBLE_PRECISION |
Число |
VARCHAR |
🟢 |
- |
Строка |
TEXT |
🟢 |
- |
Строка |
CHAR |
🟢 |
- |
Строка |
CITEXT |
🟢 |
- |
Строка |
NAME |
🟢 |
- |
Строка |
INET |
🟢 |
- |
Строка |
UUID |
🟢 |
- |
Строка, УникальныйИдентификатор |
TIMESTAMP |
🟢 |
- |
Дата, Строка (ISO 8601, RFC 3339) |
TIMESTAMP WITH TIME ZONE |
🟢 |
TIMESTAMP_WITH_TIME_ZONE |
Дата (часовой пояс будет указан как UTC), Строка (RFC 3339) |
DATE |
🟢 |
- |
Дата (с любым временем), Строка (ISO 8601, RFC 3339) |
TIME |
🟢 |
- |
Дата (с любой датой), Строка (ISO 8601, RFC 3339) |
BYTEA |
🟢 |
- |
ДвоичныеДанные, Путь к файлу, Base64 строка (все приводится к Base64 строке) |
JSON |
🟢 |
- |
Массив, Структура, Соответствие, Строка (в JSON формате) |
JSONB |
🟢 |
- |
Массив, Структура, Соответствие, Строка (в JSON формате) |
LTREE |
🟡 |
- |
Строка |
LQUERY |
🟡 |
- |
Строка |
LTXTQUERY |
🟡 |
- |
Строка |
HSTORE |
🟡 |
- |
Структура, Соответствие |
Также вы всегда можете найти эту таблицу на основной странице библиотеки PostgreSQL в документации проекта ОПИ. Некоторые типы здесь имеют синонимы - это было введено для использования их в структурах, где ключи могут быть только подходящими строками без пробелов и символов. Вот, кстати, как это выглядит в коде:
Адрес = "127.0.0.1";
Логин = "bayselonarrend";
Пароль = "12we...";
База = "test_data";
СтрокаПодключения = OPI_PostgreSQL.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль);
Соединение = OPI_PostgreSQL.ОткрытьСоединение(СтрокаПодключения);
// INSERT с параметрами
ТекстЗапроса = "
|INSERT INTO test_table (name, age, salary, is_active, created_at, data)
|VALUES ($1, $2, $3, $4, $5, $6);";
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(Новый Структура("NAME" , "Vitaly"));
МассивПараметров.Добавить(Новый Структура("INT" , 25));
МассивПараметров.Добавить(Новый Структура("REAL" , 1000.12));
МассивПараметров.Добавить(Новый Структура("BOOL" , Истина));
МассивПараметров.Добавить(Новый Структура("DATE" , ТекущаяДатаСеанса());
МассивПараметров.Добавить(Новый Структура("BYTEA", Новый ДвочиныеДанные("C:/pic.png")));
Результат = OPI_PostgreSQL.ВыполнитьЗапросSQL(ТекстЗапроса, МассивПараметров, , Соединение);
Что под капотом?
Как и коннектор SQLite, коннектор для PostgreSQL это внешняя Native API компонента на Rust. Она не очень сложная и просто использует крейт (пакет) postgres, в котором уже вся основа реализована и проверена, собственно, Rust сообществом
Найти ее можно в общем макете расширения ОПИ как zip с версиями под все основные системы: x86 и x64 Windows и Linux. Фактическое тестирование проводилось на Windows x64 и, косвенно (через OneScript), на Linux x64. Исходники лежат, как и весь проект, в репозитории на GitHub (ставьте звездочки, спасибо :Р)
Примеры работы
И еще немного примеров работы для некоторых функций. Их также можно найти в основной документации, но здесь они позволяют понять уже сейчас, то ли это, что вам нужно. Поэтому, под катом:
Большой пример произвольных SQL-запросов
Картинка = "https://api.athenaeum.digital/test_data/picture.jpg";
OPI_ПреобразованиеТипов.ПолучитьДвоичныеДанные(Картинка); // Картинка - Тип: ДвоичныеДанные
Адрес = "127.0.0.1";
Логин = "bayselonarrend";
Пароль = "12we...";
База = "test_data";
СтрокаПодключения = OPI_PostgreSQL.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль);
Соединение = OPI_PostgreSQL.ОткрытьСоединение(СтрокаПодключения);
// CREATE
ТекстЗапроса = "
|CREATE TABLE test_table (
|id SERIAL PRIMARY KEY,
|name NAME,
|age INT,
|salary REAL,
|is_active BOOL,
|created_at DATE,
|data BYTEA
|);";
Результат = OPI_PostgreSQL.ВыполнитьЗапросSQL(ТекстЗапроса, , , Соединение);
// INSERT с параметрами
ТекстЗапроса = "
|INSERT INTO test_table (name, age, salary, is_active, created_at, data)
|VALUES ($1, $2, $3, $4, $5, $6);";
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(Новый Структура("NAME" , "Vitaly"));
МассивПараметров.Добавить(Новый Структура("INT" , 25));
МассивПараметров.Добавить(Новый Структура("REAL" , 1000.12));
МассивПараметров.Добавить(Новый Структура("BOOL" , Истина));
МассивПараметров.Добавить(Новый Структура("DATE" , OPI_Инструменты.ПолучитьТекущуюДату()));
МассивПараметров.Добавить(Новый Структура("BYTEA", Картинка));
Результат = OPI_PostgreSQL.ВыполнитьЗапросSQL(ТекстЗапроса, МассивПараметров, , Соединение);
// SELECT (Результат этого запроса приведен в следующем блоке)
ТекстЗапроса = "SELECT id, name, age, salary, is_active, created_at, data FROM test_table;";
Результат = OPI_PostgreSQL.ВыполнитьЗапросSQL(ТекстЗапроса, , , Соединение);
// DO + Транзакция
ТекстЗапроса = "DO $$
|BEGIN
| CREATE TABLE users (
| id SMALLSERIAL,
| name TEXT NOT NULL,
| age INT NOT NULL
| );
| INSERT INTO users (name, age) VALUES ('Alice', 30);
| INSERT INTO users (name, age) VALUES ('Bob', 25);
| INSERT INTO users (name, age) VALUES ('Charlie', 35);
| COMMIT;
|END $$ LANGUAGE plpgsql;";
Результат = OPI_PostgreSQL.ВыполнитьЗапросSQL(ТекстЗапроса, , , Соединение);
// SQL запрос из файла
ФайлSQL = "https://api.athenaeum.digital/test_data/TEST_DATA.sql"; // Двоичные данные, URL или путь к файлу
Результат = OPI_PostgreSQL.ВыполнитьЗапросSQL(ФайлSQL, , , Соединение);
Закрытие = OPI_PostgreSQL.ЗакрытьСоединение(Соединение);
Адрес = "127.0.0.1";
Логин = "bayselonarrend";
Пароль = "12we...";
База = "testbase1";
СтрокаПодключения = OPI_PostgreSQL.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль);
Таблица = "testtable";
СтруктураКолонок = Новый Структура;
СтруктураКолонок.Вставить("bool_field" , "BOOL");
СтруктураКолонок.Вставить("oldchar_field" , """char""");
СтруктураКолонок.Вставить("smallint_field" , "SMALLINT");
СтруктураКолонок.Вставить("smallserial_field", "SMALLSERIAL");
СтруктураКолонок.Вставить("int_field" , "INT");
СтруктураКолонок.Вставить("serial_field" , "SERIAL");
СтруктураКолонок.Вставить("oid_field" , "OID");
СтруктураКолонок.Вставить("bigint_field" , "BIGINT");
СтруктураКолонок.Вставить("bigserial_field" , "BIGSERIAL");
СтруктураКолонок.Вставить("real_field" , "REAL");
СтруктураКолонок.Вставить("dp_field" , "DOUBLE PRECISION");
СтруктураКолонок.Вставить("text_field" , "TEXT");
СтруктураКолонок.Вставить("varchar_field" , "VARCHAR");
СтруктураКолонок.Вставить("charn_field" , "CHAR(3)");
СтруктураКолонок.Вставить("char_field" , "CHAR");
СтруктураКолонок.Вставить("name_field" , "NAME");
СтруктураКолонок.Вставить("bytea_field" , "BYTEA");
СтруктураКолонок.Вставить("ts_field" , "TIMESTAMP");
СтруктураКолонок.Вставить("tswtz_field" , "TIMESTAMP WITH TIME ZONE");
СтруктураКолонок.Вставить("ip_field" , "INET");
СтруктураКолонок.Вставить("json_field" , "JSON");
СтруктураКолонок.Вставить("jsonb_field" , "JSONB");
СтруктураКолонок.Вставить("date_field" , "DATE");
СтруктураКолонок.Вставить("time_field" , "TIME");
СтруктураКолонок.Вставить("uuid_field" , "UUID");
// При использовании строки подключения инициализируется новое соединение,
// которое будет закрыто после выполнения функции.
// В случае выполнения нескольких операций желательно использовать одно соединение,
// заранее созданное функцией ОткрытьСоединение()
Результат = OPI_PostgreSQL.СоздатьТаблицу(Таблица, СтруктураКолонок, СтрокаПодключения);
Добавление записей в таблицу
Адрес = "127.0.0.1";
Логин = "bayselonarrend";
Пароль = "12we...";
База = "testbase1";
СтрокаПодключения = OPI_PostgreSQL.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль);
Таблица = "testtable";
МассивЗаписей = Новый Массив;
Картинка = "https://api.athenaeum.digital/test_data/picture.jpg";
OPI_ПреобразованиеТипов.ПолучитьДвоичныеДанные(Картинка); // Картинка - Тип: ДвоичныеДанные
СлучайнаяСтруктура = Новый Структура("key,value", "ItsKey", 10);
ТекущаяДата = OPI_Инструменты.ПолучитьТекущуюДату();
ТекущаяДатаЧП = OPI_Инструменты.ДатаRFC3339(ТекущаяДата, "+05:00");
СтруктураЗаписи = Новый Структура;
СтруктураЗаписи.Вставить("bool_field" , Новый Структура("BOOL" , Истина));
СтруктураЗаписи.Вставить("oldchar_field" , Новый Структура("OLDCHAR" , 1)); // или "char"
СтруктураЗаписи.Вставить("smallint_field" , Новый Структура("SMALLINT" , 5));
СтруктураЗаписи.Вставить("smallserial_field", Новый Структура("SMALLSERIAL" , 6));
СтруктураЗаписи.Вставить("int_field" , Новый Структура("INT" , 100));
СтруктураЗаписи.Вставить("serial_field" , Новый Структура("SERIAL" , 100));
СтруктураЗаписи.Вставить("oid_field" , Новый Структура("OID" , 24576));
СтруктураЗаписи.Вставить("bigint_field" , Новый Структура("BIGINT" , 9999999));
СтруктураЗаписи.Вставить("bigserial_field" , Новый Структура("BIGSERIAL" , 9999999));
СтруктураЗаписи.Вставить("real_field" , Новый Структура("REAL" , 15.2));
СтруктураЗаписи.Вставить("dp_field" , Новый Структура("DOUBLE_PRECISION" , 1.0002)); // или DOUBLE PRECISION
СтруктураЗаписи.Вставить("text_field" , Новый Структура("TEXT" , "Some text"));
СтруктураЗаписи.Вставить("varchar_field" , Новый Структура("VARCHAR" , "Some varchar"));
СтруктураЗаписи.Вставить("charn_field" , Новый Структура("CHAR" , "AAA"));
СтруктураЗаписи.Вставить("char_field" , Новый Структура("CHAR" , "A"));
СтруктураЗаписи.Вставить("name_field" , Новый Структура("NAME" , "Vitaly"));
СтруктураЗаписи.Вставить("bytea_field" , Новый Структура("BYTEA" , Картинка));
СтруктураЗаписи.Вставить("ts_field" , Новый Структура("TIMESTAMP" , ТекущаяДата));
СтруктураЗаписи.Вставить("tswtz_field" , Новый Структура("TIMESTAMP_WITH_TIME_ZONE", ТекущаяДатаЧП)); // или TIMESTAMP WITH TIME ZONE
СтруктураЗаписи.Вставить("ip_field" , Новый Структура("INET" , "127.0.0.1"));
СтруктураЗаписи.Вставить("json_field" , Новый Структура("JSON" , СлучайнаяСтруктура));
СтруктураЗаписи.Вставить("jsonb_field" , Новый Структура("JSONB" , СлучайнаяСтруктура));
СтруктураЗаписи.Вставить("date_field" , Новый Структура("DATE" , ТекущаяДата));
СтруктураЗаписи.Вставить("time_field" , Новый Структура("TIME" , ТекущаяДата));
СтруктураЗаписи.Вставить("uuid_field" , Новый Структура("UUID" , Новый УникальныйИдентификатор()));
МассивЗаписей.Добавить(СтруктураЗаписи);
// При использовании строки подключения инициализируется новое соединение,
// которое будет закрыто после выполнения функции.
// В случае выполнения нескольких операций желательно использовать одно соединение,
// заранее созданное функцией ОткрытьСоединение()
Результат = OPI_PostgreSQL.ДобавитьЗаписи(Таблица, МассивЗаписей, Истина, СтрокаПодключения);
Удаление записей по фильтру
Адрес = "127.0.0.1";
Логин = "bayselonarrend";
Пароль = "12we...";
База = "test_data";
СтрокаПодключения = OPI_PostgreSQL.СформироватьСтрокуПодключения(Адрес, База, Логин, Пароль);
Таблица = "test_data";
Фильтры = Новый Массив;
СтруктураФильтра = Новый Структура;
СтруктураФильтра.Вставить("field", "gender");
СтруктураФильтра.Вставить("type" , "=");
СтруктураФильтра.Вставить("value", Новый Структура("VARCHAR", "Male"));
СтруктураФильтра.Вставить("raw" , Ложь);
СтруктураФильтра.Вставить("union", "AND");
Фильтры.Добавить(СтруктураФильтра);
СтруктураФильтра = Новый Структура;
СтруктураФильтра.Вставить("field", "ip_address");
СтруктураФильтра.Вставить("type" , "=");
СтруктураФильтра.Вставить("value", Новый Структура("VARCHAR", "127.0.0.1"));
СтруктураФильтра.Вставить("raw" , Ложь);
// При использовании строки подключения инициализируется новое соединение,
// которое будет закрыто после выполнения функции.
// В случае выполнения нескольких операций желательно использовать одно соединение,
// заранее созданное функцией ОткрытьСоединение()
Результат = OPI_PostgreSQL.УдалитьЗаписи(Таблица, Фильтры, СтрокаПодключения);
Ну, вот, собственно, и все! Если в не слышали ранее про ОПИ, то напомню, что кроме PostgreSQL тут есть куча других решений для интеграции с популярными сервисами и технологиями, которые доступны не только как расширение для 1С, но и как OneScript-пакет и даже полноценное консольное приложений для Windows и Linux. А в онлайн-документации всегда есть описание и примеры для каждого реализованного метода!
Все ссылки для перехода ниже
Спасибо за внимание!
Если вам нравится ОПИ, то не забывайте поддерживать его на GitHub и Инфостарт!

Репозиторий ОПИ: github.com/Bayselonarrend/OpenIntegrations
Последний релиз: github.com/Bayselonarrend/OpenIntegrations/releases/latest
Другие статьи про Открытый пакет интеграций на Инфостарт:

Мой GitHub: https://gitub.com/Bayselonarrend
OpenYellow: https://openyellow.org
Лицензия MIT: https://mit-license.org