MySQL и PostgreSQL как штатные backend-варианты
Зачем разделять backend и прикладной контракт
Sapphire I.C.D.S. поддерживает MySQL и PostgreSQL как штатные варианты backend для разных конфигураций развёртывания. При этом прикладной модуль не должен зависеть от конкретного драйвера и не должен смешивать настройки подключения с бизнес-логикой. Общий слой доступа к данным сохраняет единый контракт для модулей, а SQL-шаблоны и особенности диалекта остаются в соответствующих каталогах.
Что остаётся общим
Модули работают со структурированными входными данными, таблицами результатов и согласованными операциями чтения и изменения. Проверка прав, владельца, layout, типа данных и допустимого диапазона выполняется в модуле до обращения к базе. Транзакции, обработка ошибок, журналирование и проекция результата также должны подчиняться общему контракту платформы.
Такой подход позволяет одному модулю обслуживать публичную страницу, административную форму, AJAX-сценарий или API, не копируя отдельную бизнес-логику под каждый backend. Клиент получает предусмотренную проекцию данных, а не прямое соединение с базой и не произвольный SQL.
Почему SQL-файлы диалектов разделяются
Похожие запросы для MySQL и PostgreSQL не всегда являются взаимозаменяемыми. Различаются кавычки идентификаторов, функции дат и строк, приведение типов, операции upsert, агрегаты и отдельные ограничения синтаксиса. Поэтому для поддерживаемых backend следует хранить короткие отдельные SQL-шаблоны и проверять каждый из них в соответствующей среде.
SQLMacros помогает формировать итоговый текст из подготовленной таблицы значений, но не выбирает backend, не открывает соединение, не начинает транзакцию и не решает, какой запрос разрешено выполнить. Выбор шаблона и разрешение операции остаются обязанностью модуля и DB-слоя.
Типизация и экранирование
Числовые параметры, флаги, limit, offset и идентификаторы должны быть созданы как проверенные числа и ограничены по диапазону до рендера. Строковые значения помещаются в строковые литералы и проходят DB-escape provider активного драйвера. HTML escaping или ручная замена апострофов не являются заменой экранированию для SQL.
Пользовательская строка не может становиться именем таблицы, колонки или оператором. Допустимые варианты сортировки и полей выбираются через allowlist, после чего вызывается заранее известный шаблон. Экранирование значения не превращает динамический идентификатор в безопасный.
Переносимость не отменяет эксплуатационные решения
Единый слой доступа уменьшает зависимость модулей от конкретной СУБД, но не выбирает за заказчика архитектуру развёртывания. Нужно определить резервное копирование, репликацию, обновление версии СУБД, мониторинг, лимиты соединений, хранение секретов и требования к восстановлению. Наличие двух поддерживаемых backend также не означает, что переключение между ними происходит без миграции и тестирования.
Проверка нового модуля
- Проверить схему и типы входных данных до SQL-рендера.
- Сопоставить условия основного запроса и count-запроса для Pager.
- Проверить пустой поиск, Unicode, апостроф, проценты, нулевой результат и граничные limit/offset.
- Проверить SELECT на тестовых данных, а изменение — в контролируемой транзакции или изолированной базе.
- Проверить оба диалекта и убедиться, что успешный результат не содержит нераскрытых макросов.
Реальная граница обещаний
Поддержка MySQL и PostgreSQL означает наличие согласованного пути для модулей, а не автоматическую совместимость с любым сторонним запросом или произвольной схемой. Производительность, индексы, настройки транзакций и поведение под нагрузкой нужно измерять на целевой конфигурации. Переносимость возникает из общего контракта, статической структуры SQL и дисциплины тестирования, а не из одного переключателя.