Xpoint
   [напомнить пароль]

Универсальный язык/протокол/... описания запросов

Метки: [без меток]
2008-05-12 20:22:17 [обр] Jared(0/26)[досье]

Допустим, существует некая система, которая должна уметь работать с различными backend решениями хранения данных. То есть, система общается с хранилищем через некий интерфейс (назовем его ds; положим, это некий объект), который не меняется в зависимости от условий. Но в данной конкретной среде могут быть доступны только какие-то определенные варианты внешнего хранилища. Например, есть вариант хранить данные в XML файлах и запрашивать данные с совсем внешнего источника по HTTP, но SQL БД нет. Или есть SQL БД и все. Кроме того, данные могут быть предоставлены одновременно с нескольких источников (вопрос приоритета и конкуренции между источниками - дело десятое). Для непосредственной работы с конкретным источником существует некий "драйвер". То есть, код для общения с той или иной БД, или с DOM каких-то XML файлов. Ну, функция такого "драйвера", вобщем понятна.

Непонятен только язык/протокол/... (не знаю как назвать даже =)) между ds и "драйвером". Ясно, что данный язык должен быть единым для всех "драйверов". Но при этом должен конкретным драйвером преобразовываться в серию, например SQL запросов, или xpath выражений.

Желательно также учитывать возможное появление каких-то других источников, для которых нужно будет писать соответствующий "драйвер", не модифицируя код ds.

Просто соблюсти единый интерфейс для всех драйверов не получится, потому что системе, вероятно понадибится делать кастом-запросы.

Хочется абстрагировать систему от способа хранения данных, но при этом, использовать все плюсы конкретного хранилища с помощью драйвера, который должен либо использовать эти самые плюсы своего backend-а, либо эмулировать те или иные критичные вещи (эмулировать - например, join для пары xml-файлов).

Так вот, в курсе ли вы, есть ли какие-нибудь готовые наработки/проекты по поводу такого вот универсального языка ("кхм"). Или, может есть какие-нибудь соображения по данному поводу.

P.S. Вопрос довольно размазанный. Это от того, что никакого конкретного проекта или ситуации, где мне это нужно не существует. Возможно, еще не существует. Так, просто мысли бродят.

спустя 3 часа 1 минуту [обр] Алексей Севрюков(0/1292)[досье]
Просто соблюсти единый интерфейс для всех драйверов не получится, потому что системе, вероятно понадибится делать кастом-запросы.
Это как? Нет единого интерфейса - нет кастом запросов. Драйвер в любом случае должен уметь обрабатывать такие запросы, иначе никак.
спустя 11 часов [обр] Thirteensmay(0/157)[досье]

Кастом это расширение к общей части, единый интерфейс представляет метод для выполнения кастом запросов на кастом языке, грубо говоря:

if source.properties == someType
  source.execute_custom_query(/* здесь кастом запрос */);
else
  source.get_field_list;
  source.set_condition;
  source.select;

Методологию работы с данными единого интерфейса точить в сторону ЯП общего назначения, т.е. представлять массивы, записи, циклы, ветвления и т.п., будет страшно геморойно, но универсально, раз у вас такая задача, оптимальность если что за счет кастом. Но сначала прикиньте а надо ли оно вообще ?

спустя 2 дня 8 часов [обр] Jared(0/26)[досье]

Спасибо за ответы.

Это как? Нет единого интерфейса - нет кастом запросов. Драйвер в любом случае должен уметь обрабатывать такие запросы, иначе никак.

Я не совсем верно выразился. Единые интерфейсы разумеется, должны быть. И принимать описания запросов в каком-то едином формате, преобразуя его в запрос(ы) для уже конкретного backend.

Драйвер xSQL (JavaScript-like код):

function get(query)
{
   // Тут преобразования query в SQL запрос/запросы
   //....
   data = xSQLbackend.query(xSQLquery);
   return data;
}

Драйвер XML (JavaScript-like код):

function get(query)
{
   // Тут преобразования query в серию XPaths 
   //....
   while (XPath = XPaths.shift()) { data.push = XMLbackend.query(XPath) );
   // Тут манипуляции над data, чтобы вернуть ожидаемый результат
   //....
   return data;
}

Вот собственно, в том, какого плана должен быть тот самый аргумент query, чтобы с той или иной степенью сложности он мог быть преобразован в запросы реального backend и заключался вопрос.

Кастом это расширение к общей части, единый интерфейс представляет метод для выполнения кастом запросов на кастом языке, грубо говоря:

В Вашем примере любая часть системы, которая общается с ds и его драйверами должна поддерживать набор кода для любого возможного реального backend. То есть, в конкретных уловиях, в которых XML нет и не предвидится, будет довольно много лишнего кода, связанного с кастом-выборками именно из XML. С другой стороны, при создании нового backend, необходимо дополнять довольно большое количество кусков. Таким образом, ds и драйвер, как уровень абстракции доступа к данным не то чтобы становятся совсем ненужными, но их функция сведется к некому общему функционалу - так, для удобства. Абстракция "протекает" совсем по Сполски =).

Методологию работы с данными единого интерфейса точить в сторону ЯП общего назначения, т.е. представлять массивы, записи, циклы, ветвления и т.п., будет страшно геморойно, но универсально, раз у вас такая задача, оптимальность если что за счет кастом. Но сначала прикиньте а надо ли оно вообще ?

Да, тут вы, похоже правы. В вашем вопросе, в том числе, такой уровень геморройности того не стоит.

Вобщем, по трезвому размышлению, прихожу к тому, что проще представлять данные и их структуры в качестве некого изначального набора... хм.. типов что ли. То есть, например: вот тут у нас дерево, тут список "подобных" (юзеры, например), тут список "бесподобных" (например, разношерстные настройки для разных модулей). Поддержка целостности лежит подностью на драйвере и, во многом, завязана на мета-информацию. Собствнно, от этой самой мета-информации, да входных настроек и должнен формироваться как и запрос нижнего для системы уровня (SQL, XPath), так и вывод информаци. Сама мета хранится в том же источнике, и для ее вытаскивания существуют "зашитые" в драйвер возможности.

Тем не менее, вопрос о некотором "языке" обмена между ds и драйвером все еще открыт. Хочется, например, возложить на ds, например, обязанности по авторизации доступа к тем или иным данным:
ds (JavaScript-like код; пример query, которым таким образом манипулируют, ниже):

function getData(query)
{
   //Какие-то манипуляции
   //...
   if( this.protectedModeOn )
   {
      // Цепляем новый джойн, чтобы забрать права
      query[source][set1] = query[source];
      query[source][set2] = 'permissions';
      query[source][join-type] = 'inner';
      query[source][join-conditions] = 
      (
         'primary-record-key',
         'equals',
         'some-record-key'
      )
      // Нам нужен только текущий юзер - ставим условие
      query[conditions] = array( query[conditions] );
      query[conditions].push( 
         'AND',
         (
            ('permissions.user_id', 'equals', this.user.id ), 
            'AND', 
            ('permissions.read', 'equals', 1)
         )
      )
   }
   //Какие-то манипуляции
   //...
   query = {'source': source, 'conditions': conditions};
   //Какие-то манипуляции
   //...
   return this.xSQLdriver.get(query)
}

Пример упрощен. Вообще, для каждого конечного мм... набора данных (таблица, файл, whatever) проверяется его "защищенность", и добавляются нужные условия.

Вцелом мне в качестве query видится только что-то вроде:

query = 
{
   // Описание источника и джойнов
   'source':
   {
      'set1':
      {
         'set1': 'data-1',
         'set2': 'data-2'

         'join-type': 'left',
         'join-conditions': ( 'data-1.field_1-1', 'equals', 'data-2.field_2-1' )
      },
      'set2': 'data-3',

      'join-type': 'left',
      'join-conditions': ( 'data-2.field_2-1', 'equals', 'data-3.field_3-1' )
   }

   'conditions':
   (
      (
         ('data-2.field_2-5', 'equals', 'FOO'),
         'AND',
         ('data-3.field_3-4', 'more', 4)
      ),

      'OR',
      (
         ('data-2.field_2-5', 'equals', 'BAR'),
         'AND',
         ('data-3.field_3-4', 'more', 7)
      )
   )
}

Это то, что принимает ds, модифицирует для тех или иных целей (авторизация, или, например, версионинг) и передает дальше драйверу.
xSQL драйвер должен собрать из этого монстрика запрос.
XML драйвер должен по сетам открывать нужные файлы, выбирать, исходя из 'conditions' соответствующие ноды, джойнить их к уже выбранным данным.
HTTP драйвер, например, запрашивать данные по URL`ам, соответствующим сетам.

Причем поддержка базовых структур данных (например, дерево), эмулируется драйвером (например, xSQL) в случае, если встроенной поддержки нет (как в XML например). Причем, для построения этого дерева, xSQL драйвер использует meta-информацию (например, parent_id поле) и это должно происходить прозрачно. То есть, система знает, что определенные данные - суть иерархия. Она не в курсе, как конкретно реализовано хранилище данных, но ожидает на свой запрос получить дерево (вложенные хэши/массивы/объекты/whatever). Построение этого дерева происходит на уровне драйвера.

P.S. Прошу прощения за портянку, но мысли бродят как призрак коммунизма, аж прям есть не могу (шучу) =).

P.P.S. У меня создается ощущение, что я придумываю велосипед. Что что-то подобное уже должно быть реализовано как в идеологии, так и в алгоритмах/коде.

спустя 21 час [обр] Thirteensmay(0/157)[досье]

Думаю надо понять в чем корень проблемы, помоему в том что вы пытаетесь скрестить совершенно несовместимые вещи, универсальность и оптимальность (кастом). Оптимальность возможна только в жестком ОПРЕДЕЛЕННОМ контексте, если контекст жестко неопределен (универсальность), то не о какой оптимальность речи быть не может, потому как непонятно за счет чего оптимизировать, на что можно опереться.

Так как я вам предлагал делать кастом запросы, подразумевалось что они выполняются из жесткого контекста, т.е. мы более менее знаем с каким хранилищем собираемся работать. Если контекст универсальный то как я сказал не о каких кастом речи быть не может.

Вы ответили:

В Вашем примере любая часть системы, которая общается с ds и его драйверами должна поддерживать набор кода для любого возможного реального backend

Так вот, не любая часть системы должна поддерживать все остальное, этого какраз вы хотите, и это как понимаете геморрой.
А только та относительно жесткая часть, определенный контекст, тот кусок в котором мы знаем что будем работать с таким-то или таким-то типом хранилища, должен поддерживать эти хранилища.

У нас есть 2 варианта, либо страшный гемор - все поддерживает все, либо выделение и изолирование жестких кусков в которых возможен кастом. Первый вариант - не вариант, ибо нафиг оно нужно, он ничем не отличается от написания кода впрямую. Поэтому при условии что необходимо обеспечить возможность кастом запросов остается только второй вариант.

Здесь для просветления циклически читать первый абзац сего поста.

А в плане универсальности, вы знаете, я тут подумал, не надо никаких имитаций ЯП общего назначения или как вы предлагаете структур и типов данных, достаточно обычного XML, ну или возмите любой другой более менее универсальный формат описания. Все равно это универсальность, и требовать от нее оптимальности вы не вправе.

Powered by POEM™ Engine Copyright © 2002-2005