Вы любите из раза в раз повторять рутинные операции? Вот и я нет. Но каждый раз в SQL-клиенте при работе с хранилищем Ростелекома приходилось прописывать все джойны между таблицами ручками. И это притом, что в 90% случаев поля и условия соединения таблиц совпадали от запроса к запросу! Казалось бы, любой SQL-клиент имеет функции автозаполнения, но для хранилищ оно не всегда работает: в них редко заводятся unique constraint и foreign key в целях повышения производительности, а без этого программе не узнать, как между собой связаны сущности и что она может тебе предложить.
Пройдя через отрицание, гнев, торг, депрессию и приближаясь к принятию, я решил — а почему бы самому не попробовать реализовать автозаполнение с блекджеком и как положено? Я пользуюсь клиентом dbeaver, написанным на java, у него есть комьюнити версия с открытым исходным кодом. Созрел нехитрый план:
- Найти в исходном коде классы, отвечающие за автозаполнение
- Переориентировать их на работу с внешними метаданными и подтягивать оттуда информацию о джойнах
- ??????
- PROFIT
С первым пунктом достаточно быстро разобрался — нашел в багтрекере запрос на корректировку автозаполнения и в связанном коммите обнаружил класс SQLCompletionAnalyzer. Посмотрел код — то, что надо. Осталось переписать его так, чтобы все работало. Дождался свободного вечера и начал продумывать реализацию. Правила связей таблиц (метаданные) решил вести в json. У меня не было практического опыта работы с этим форматом и текущая задача виделась возможностью это упущение исправить.
Для работы с json решил использовать библиотеку json-simple от гугла. Тут начались сюрпризы. Как выяснилось, dbeaver, как труъ-приложение, написан на платформе эклипса с использованием OSGi-фреймворка. Для опытных разработчиков эта штука дает удобство управления зависимостями, для меня же больше была похожа на темную магию, к которой я был явно не готов: как обычно прописываю импорт нужных мне классов из библиотеки json-simple в шапке редактируемого класса, указываю ее в pom.xml, после чего проект категорически отказывается нормально собираться и валится с ошибками.
Исправить ошибки сборки в итоге получилось: прописал библиотеку не в pom.xml, а в манифесте manifest.mf, как того требует OSGI, при этом указав ее как import-package. Не самое красивое решение, но зато работает. Тут появился следующий сюрприз. Если ты ведешь разработку в intellij idea, нельзя просто так взять и запустить дебаг своего проекта, основанного на платформе eclipse: неопытный разработчик должен страдать не меньше, чем аналитик без автодополнения запросов. На помощь пришли сами разработчики бобра, указавшие в wiki все танцы с бубном, которые надо проделать. Самое обидное, что даже после всех этих приседаний проект не хотел запускаться в дебаге с подключенной через import-package библиотекой json (притом, что в готовый продукт он по-прежнему успешно собирался).
К тому моменту я успел прочувствовать неудобство использования json для моей задачи — все-таки метаданные предполагалось редактировать вручную, и для этого формат xml лучше подходит. Вторым аргументом в пользу xml было наличие в JDK всех необходимых классов, что дало возможность прекратить борьбу с внешней библиотекой. С большим удовольствием перенес все метаданные из json в xml и приступил к правкам логики автозаполнения.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tableRelations>
<tableRelation>
<leftTable>dim_account</leftTable>
<rightTable>dim_partner</rightTable>
<joinColumnPair leftColumn="partner_key" rightColumn="partner_key"/>
<joinColumnPair leftColumn="src_id" rightColumn="src_id"/>
</tableRelation>
<tableRelation>
<leftTable>dim_account</leftTable>
<rightTable>dim_branch</rightTable>
<joinColumnPair leftColumn="src_id" rightColumn="src_id"/>
<joinColumnPair leftColumn="branch_key" rightColumn="branch_key"/>
</tableRelation>
</tableRelations>
В результате я внес изменения в классы SQLUtils и SQLCompletionAnalyzer. Идея такая: если проге не удалось подобрать подходящие предложения автозаполнения по базовой логике, то она проверяет наличие возможных джойнов по внешнему файлу xml. В самом файле хранятся пары таблиц с указанием полей, по которым эти таблицы нужно связывать. Ограничения на технические даты действия записей eff_dttm и exp_dttm и флаг логического удаления deleted_ind при этом проставляются по умолчанию.
Когда правки в код были внесены, появился вопрос — кто будет наполнять файл с метаданными? Сущностей в хранилище много, самому все связи прописывать накладно. В итоге решил повесить эту задачу на своих коллег-аналитиков. Файл метаданных выложил в svn, откуда делается чекаут в локальную директорию с программой. Принцип такой: в хранилище появилась новая сущность? Один аналитик вносит возможные джойны в файл, коммитит изменения, остальные делают чекаут к себе и наслаждаются работающим автозаполнением: комьюнити, накопление знаний и все такое. Провел для коллег воркшоп по использованию проги, написал статью в конфлюенс — теперь в компании одним удобным инструментом больше.
Работа над этой фичей дала мне понимание, что не стоит бояться ковырять опенсорсные проекты — как правило, у них понятная архитектура, и даже базовых знаний языка будет достаточно для экспериментов. А при определенной доле упорства даже получится избавиться от ненавистных рутинных операций, сэкономив себе время на новые эксперименты.
Автор: Вадим Петров