Вчера я коротенько описал процесс создания анализатора.
Мы остановились на том, что у нас есть AST парсер, типы результатов запросов.
Из этого мы уже можем собрать себе инструменты, которые уже довольно сильно улучшат текущую ситуацию.
Но чтобы перейти на следующий уровень, нам нужен инструмент для компиляции SQL в объекты промежуточных представлений (IR), с которыми можно бы было работать в коде.
К сожалению, нет универсального инструмента, который можно было бы взять и начать использовать.
В идеале хорошо бы было сделать подборку инструментов компиляции и сравнить их, но с этим есть одна существенная проблема:
мне такие инструменты не известны.
Есть несколько продуктов, которые пытаются сделать универсальный AST парсер разных SQL-диалектов, но они не работают :)
Есть только один путь - написать компилятор самостоятельно.
Я не буду рассказывать как это сделать. Это долго, сложно и не так весело, как может показаться.
Стоит знать лишь одно - рабочая версия компилятора существует и им можно пользоваться уже сейчас.
У выбранного пути есть несколько существенных минусов:
- невозможно сделать универсальный компилятор для разных БД
- поведение компилятора не будет совпадать с поведением реальных БД
Но в любом случае это лучше, чем ничего :)
На данный момент у нас есть 2 комилятора: для PostgreSQL и Snowflake.
Компиляторы покрывают все основные юзкейсы и мы постоянно их улучшаем.
Компилятор для PostgreSQL и Snowflake (parsers.dev)
1) DDL компилируется в объект, описывающий схему БД
2) DML + DDL IR компилируется в IR, описывающий имена, типы, nullability и класс количества строк запроса, список зависимых объектов
1) Берем все команды из DDL (CREATE, ALTER, DROP) и "выполняем" их по очереди.
В итоге мы получим состояние схемы, которое по идее могли бы вытащить из INFORMATION_SCHEMA.
Зачем так сложно?
Мы сможем не зависеть от наличия БД под рукой. Это будет актуально, когда мы переключимся на работу с облачными БД.
2) Имея состояние схемы, разбираем запрос и ищем в нем связи между известными нам объектами.
Видим поле - ищем в текущем scope.
Видим функцию - ищем в списке.
Видим JOIN - ищем FK и пытаемся вычеслить информацию о nullability.
Как можно использовать компилятор parsers.dev прямо сейчас?
1) По DDL + DML сгенерировать типы, модели и вообще все что угодно для своего языка программирования.
PostgreSQL поддерживается неплохо, и скорее всего подойдет для абсолютного большинства проектов.
Snowflake в preview
Таблицы, вью, системные функции, пользовательские функции, системные типы, некоторые extensions - должно хватить :)
Как получить все что угодно для своего языка программирования?
Сгенерировать самостоятельно из того объекта, который выдаст наш API
2) AST парсеры
Для создания своих инструментов для работы с SQL можно воспользоваться AST-парсерами.
Для PostgreSQL используется оригинальный парсер.
Для Snowflake пришлось написать парсер самостоятельно. Большая часть конструкций протестирована, структура приближена к PG
3) Существует готовый npm модуль, который автоматизирует проверку изменений типов запросов между коммитами.
Текущие запросы сравниваются с последними закомиченными на предмет соответствия типов, nullability, класса количества строк и lineage колонок
https://github.com/parsers-dev/sql-type-tracker
Aнализатор (holistic.dev)
Проверяет Postgresql запросы по существующему списку правил, основываясь на данных из парсера и компилятора.
Анализатору доступны все внутренние состояния (CTE, подзапросы и тд), поэтому получается найти проблемы даже в подзапросах.
В Postgresql есть такая вьюха - pg_stat_statements, в ней лежат очищенные от данных запросы.
Можно запустить крон на своей стороне и по расписанию отправлять содержимое этой вьюхи на анализ.
Идеальный вариант для проектов на ORM.
Вся интеграция займет минут 10.
Есть готовые интеграции с облачными провайдерами.
Или если вы все-таки вынесете запросы в отдельные файлы, сможете подключить анализ через API в ваших CI пайплайнах.
Можно будет обнаружить проблемные места еще до попадания их в прод.