Можно ли извлечь части дерева выражений Boost.Proto, оценить их индивидуально (внешне), а затем изменить дерево выражений, заменив извлеченные части результатом?
В моем конкретном случае я пытаюсь оценить, могу ли я переписать какой-то устаревший код, который повторяется:
То, что я надеялся сделать, было:
1. Создайте одно большое дерево выражений
2. Получить SQL из дерева выражений. Это состоит из:
б. посетите дерево и проверьте подзапросы, которые должны быть оценены до того, как будет получен отдельный sql
с. если есть подзапросы, создайте sql и верните в виде строки, оцените sql извне и измените дерево, заменив подзапросы результатами
(также я хотел бы идентифицировать идентичные подзапросы и оценивать их только один раз, если это возможно)
Возможно ли это сделать? Требуется ли код, который трудно понять / изучить?
Я просмотрел документацию Boost.Proto, но не уверен, предназначен ли он для этого сценария, где мне нужно внешне оценивать поддеревья и заменять его результатом, пока все дерево не будет сведено к одному запросу.
РЕДАКТИРОВАТЬ:
Допустим, у меня есть следующие таблицы:
объекты
id | название
attribute_link
объект | attributeid
атрибуты
id | парентид | имя | значение
Мои запросы поступают как пользовательский объект «запрос» — (двоичное) дерево с несколькими предложениями AND, OR.
Пример:
query1 = object.id = 10 OR (attribute.name = «name» ИЛИ attribute.name = «name2»)
Это означает: получить атрибут (ы) для объекта 10, где именем атрибута является «имя». Обратите внимание на поле parentid, которое означает, что мы ищем attribute.name может быть вложенным и напрямую не связанным с нашим объектом.
Что мне нужно сделать, это:
1. Переведите это в дерево выражений с достаточным количеством информации.
2. Отправить это дерево в слой БД
3. Обработайте дерево (иногда в несколько этапов), как описано выше
Возможно, дерево выражений будет выглядеть примерно так:
find_attributes (object_id = 10 AND attribute_name = («name» ИЛИ «name2»))
Есть несколько баз данных, где синтаксис SQL отличается, поэтому я хочу сделать это таким образом. Поэтому мне нужно иметь возможность переопределить некоторые этапы обработки на основе базы данных.
Например, PostgreSQL:
обработка сначала распознает узел find_attributes и узнает, что мы ищем атрибуты
Если посмотреть дальше, атрибут должен быть связан с object.id = 10, мы сразу генерируем и запускаем запрос, чтобы получить все атрибуты с object.id = 10, и заменяем узел object_id = 10 в дереве выражений фактическим атрибутом. ids (object_id = 10) => (attribute_id = (20 ИЛИ 21)).
затем мы находим узел attribute_name и, поскольку атрибуты вложены, нам нужно найти все строки атрибутов, которые имеют name = «name» или «name2»
в качестве (необязательного) шага оптимизации, поскольку существуют миллионы атрибутов, нам необходимо объединить узлы attribute_id и attribute_name в один запрос
Результирующие запросы могут выглядеть примерно так:
(найти атрибуты) SELECT ID ИЗ атрибутов, ГДЕ objectid = 10)
(окончательный запрос) —
С
get_roots AS (SELECT * FROM атрибутов WHERE (id = 20 или id = 21)),
get_childs AS (SELECT * FROM get_roots, атрибуты WHERE attribute.parentid = get_roots.id),
get_grandchilds AS (SELECT * FROM get_childs, атрибуты WHERE attribute.parentid = get_childs.id)
SELECT * FROM get_roots
UNION
SELECT * FROM get_childs
UNION
SELECT * FROM get_grandchilds
(если предположить, что атрибуты здесь всего три уровня, его можно переписать как рекурсивный CTE)
Я предполагаю, что это возможно, но будет ли это слишком большой работой? Существует ограниченный набор запросов, и представленный здесь является наиболее сложным.
Древовидная структура прототипа устанавливается во время компиляции и, следовательно, не является изменяемой. Обычно вы восстанавливаете новое дерево с нужными вам элементами. Это можно сделать тривиально, когда прототрансформирует дерево и возвращает новое дерево.
Других решений пока нет …