Инструмент для «интернализации» внешнего DSL в Java - PullRequest
2 голосов
/ 12 июля 2011

Я занимаюсь разработкой и обслуживанием библиотеки абстракции базы данных под названием jOOQ , которая направлена ​​на "интернализацию" SQL как внешнего DSL в Java. Целью этого усилия является обеспечение безопасного создания типов и выполнения всех возможных элементов синтаксиса SQL наиболее популярных СУБД. Внутренний DSL в jOOQ становится все более и более сложным, и я хотел бы получить его официально. Идея заключается в том, что я хотел бы иметь какое-то формальное определение SQL в качестве входных данных, например

select ::= subquery [ for-update-clause ]
subquery ::= SELECT [ { ALL | DISTINCT | UNIQUE } ] select-list 
           [ FROM table-reference ] ..
select-list ::= expression [ [ AS ] alias ] [, expression ... ]
expression ::= ...
alias ::= ...
table-reference ::= ...

Входные данные также могут быть определены в XML или любом другом описательном метаязыке. Как только у меня будет этот вход, я бы хотел сгенерировать из этого входа набор интерфейсов Java, которые моделируют определенный синтаксис в Java. Пример интерфейсов будет:

// The first "step" of query creation is modelled with this interface
interface Select0 {

    // The various SELECT keywords are modelled with methods
    // returning the subsequent generated syntax-element
    Select1 select(Expression...);
    Select1 selectAll(Expression...);
    Select1 selectDistinct(Expression...);
    Select1 selectUnique(Expression...);
}

// The second "step" of query creation is optional, hence it
// inherits from the third "step"
interface Select1 extends Select2 {

    // Here a FROM clause may be added optionally
    Select2 from(TableReference...);
}

// To keep it simple, the third "step" is the last for this example
interface Select2 extends SelectEnd {
    // WHERE, CONNECT BY, PIVOT, UNPIVOT, GROUP BY, HAVING, ORDER BY, etc...
}

С помощью вышеупомянутых интерфейсов можно будет создавать запросы SQL в Java, как jOOQ уже позволяет делать сегодня:

create.select(ONE, TWO).from(TABLE)...
create.selectDistinct(ONE, TWO).from(TABLE)...
// etc...

Кроме того, я бы хотел исключить некоторые элементы синтаксиса для некоторых конкретных сборок. Например. когда я собираю jOOQ для эксклюзивного использования с MySQL, нет необходимости поддерживать оператор SQL MERGE.

Существует ли какая-либо существующая библиотека, реализующая такой общий подход для формальной интернализации и внешнего DSL в Java? Или я должен свернуть свой собственный?

1 Ответ

1 голос
/ 02 декабря 2011

Что вы действительно пытаетесь сделать, так это преобразовать универсальный SQL в вызовы ваших внутренних API. Кажется разумным.

Чтобы сделать это, вам нужен анализатор для «универсального SQL» и средство для генерации кода из этого анализатора. Как правило, вам нужен синтаксический анализатор для построения абстрактного синтаксического дерева, вам в значительной степени нужна таблица символов (чтобы вы знали, что такое имена таблиц, каковы имена столбцов, и являются ли эти имена столбцов из таблицы A или таблицы B, поэтому где-то вам нужен доступ к SQL DDL, который определяет модель данных .... который требует повторного анализа SQL :).

Используя AST и таблицу символов, вы можете генерировать код множеством способов, но простой способ - пройти AST по конструкциям translate по мере их появления. Это не позволит создавать оптимизированные запросы; это требует более сложной генерации кода, но я ожидаю, что она будет адекватной, если будет поддерживаться соответствующими функциями API, которые вы предоставляете.

Фактическую генерацию кода можно выполнить, просто распечатав текст Java; если вы пойдете по маршруту ANTLR, вам придется сделать что-то вроде этого. Альтернативой является буквальное преобразование фрагментов кода SQL (как AST) в фрагменты кода Java (как AST). Последняя схема дает вам больше контроля (вы можете на самом деле выполнять преобразования фрагментов кода Java, если они являются AST) и, если все сделано правильно, может быть проверена инструментом генерации кода.

Наш инструментарий реинжиниринга программного обеспечения DMS будет хорошей основой для этого. DMS предоставляет экосистему для создания инструментов перевода, включая надежный механизм синтаксического анализа, поддержку таблиц символов, правила перевода на основе шаблонов поверхностного синтаксиса, а также универсальный SQL (SQL 2011, стандарт) в качестве доступного, протестированного синтаксического анализатора, а также Java, для использования на стороне генерации кода.

...