Funq — различия между версиями

Материал из YourcmcWiki
Перейти к: навигация, поиск
(Новая: Funq - концепция околофункционального, гибкого язык запросов к реляционным базам данных, чем-то похожег...)
 
Строка 1: Строка 1:
Funq - концепция околофункционального, гибкого язык запросов к реляционным базам данных, чем-то похожего на LINQ и призванного заменить SQL для разработчиков, к тому же, скрывая диалекты, свойственные отдельным СУБД.
+
Funq — концепция околофункционального, гибкого язык запросов к реляционным базам данных, чем-то похожего на LINQ и призванного заменить SQL для разработчиков, к тому же, скрывая диалекты, свойственные отдельным СУБД.
  
 
== Идея ==
 
== Идея ==
  
Сейчас стандартом языка запросов к реляционным базам данных является SQL - громоздкий, некрасивый и тяжёлый язык. SQL - декларативный язык, но он не оперирует сущностями каких-то явных типов, а синтаксис команд очень жёсткий, то есть, негибкий. Например, чтобы автоматически наложить на уже созданный запрос какое-то ограничение, нужно сначала понять, в какое место и в каком виде его добавлять, а способа адекватно и надёжно сделать это без синтаксического анализа запроса не существует.
+
Сейчас стандартом языка запросов к реляционным базам данных является SQL — громоздкий, некрасивый и тяжёлый язык. SQL — декларативный язык, но он не оперирует сущностями каких-то явных типов, а синтаксис команд очень жёсткий, то есть, негибкий. Например, чтобы автоматически наложить на уже созданный запрос какое-то ограничение, нужно сначала понять, в какое место и в каком виде его добавлять, а способа адекватно и надёжно сделать это без синтаксического анализа запроса не существует.
  
Таким образом, было бы неплохо создать ''не SQL-подобный'' язык запросов, который был бы к тому же элегантен и удобен для использования в клиентских приложениях. Например, можно максимально приблизить формирование запросов к заданию выражения над таблицами, как алгебраическими объектами, с использованием различных операций реляционного исчисления - JOIN-ов, ограничений, проекций и т.д, а также других нереляционных преобразований - они необходимы потому, что возможностей построения запросов разработчики различных СУБД создали великое множество, а на замену SQL годится по меньшей мере равномощный ему язык. Сразу оговоримся, что основные проблемы написания запросов к базам данных связаны с запросами выборки. Запросы удаления/обновления часто используют базу просто как хеш-таблицу, а запросы вставки и [[wikipedia:DDL|DDL]]-запросы просто имеют достаточно бедный синтаксис. Их также нужно реализовать, как часть языка запросов, но основной интерес представляют запросы выборки. Ими-то мы в первую очередь и займёмся.
+
Таким образом, было бы неплохо создать ''не SQL-подобный'' язык запросов, который был бы к тому же элегантен и удобен для использования в клиентских приложениях. Например, можно максимально приблизить формирование запросов к заданию выражения над таблицами, как алгебраическими объектами, с использованием различных операций реляционного исчисления — JOIN-ов, ограничений, проекций и т.д, а также других нереляционных преобразований — они необходимы потому, что возможностей построения запросов разработчики различных СУБД создали великое множество, а на замену SQL годится по меньшей мере равномощный ему язык. Сразу оговоримся, что основные проблемы написания запросов к базам данных связаны с запросами выборки. Запросы удаления/обновления часто используют базу просто как хеш-таблицу, а запросы вставки и [[wikipedia:DDL|DDL]]-запросы просто имеют достаточно бедный синтаксис. Их также нужно реализовать, как часть языка запросов, но основной интерес представляют запросы выборки. Ими-то мы в первую очередь и займёмся.
  
Например, рассмотрим вот такой SQL-запрос. Можно заметить, что это не чистый SQL - здесь ещё присутствуют подстановки имён таблиц из хеша <code>$t</code> и имён полей <code>$child</code> и <code>$parent</code>.
+
Например, рассмотрим вот такой SQL-запрос. Можно заметить, что это не чистый SQL — здесь ещё присутствуют подстановки имён таблиц из хеша <code>$t</code> и имён полей <code>$child</code> и <code>$parent</code>.
  
 
<source lang="sql">
 
<source lang="sql">
Строка 42: Строка 42:
 
Заметно две основных идеи: во-первых, логически после применения каждого преобразования .something() к отношению мы снова получаем отношение, имеющее все те же самые методы; и во-вторых, язык должен уметь интерполировать различные конструкции в различные места запросов.
 
Заметно две основных идеи: во-первых, логически после применения каждого преобразования .something() к отношению мы снова получаем отношение, имеющее все те же самые методы; и во-вторых, язык должен уметь интерполировать различные конструкции в различные места запросов.
  
Вообще-то, внезапно можно осознать, что relation.something().something().something() - функциональный стиль программирования, а точнее, что это очень похоже на [http://www.martinfowler.com/bliki/FluentInterface.html Fluent Interfaces]. Собственно, они и сами являются пародией на ФП, хотя и довольно жалкой.
+
Вообще-то, внезапно можно осознать, что <code>relation.something().something().something()</code> — функциональный стиль программирования, а точнее, что это очень похоже на [http://www.martinfowler.com/bliki/FluentInterface.html Fluent Interfaces]. Собственно, они и сами являются пародией на ФП, хотя и довольно жалкой.
  
Кроме того, можно вспомнить язык [http://msdn.microsoft.com/en-us/netframework/aa904594.aspx LINQ] (Language INtegrated Query) от Microsoft. Если в LINQ пользоваться только объектным стилем задания запроса, то LINQ тоже станет похож на Funq. Другое дело, что на практике делать именно так в LINQ практически невозможно и в любом случае неудобно. Важно также, что и цель у создателей LINQ изначально была другая - встроить язык запросов в .NET с помощью обычных его средств и научить языки .NET работать через одни и те же классы и интерфейсы с базами данных, XML-файлами, да и вообще любыми источниками данных, вплоть до обычных массивов.
+
Кроме того, можно вспомнить язык [http://msdn.microsoft.com/en-us/netframework/aa904594.aspx LINQ] (Language INtegrated Query) от Microsoft. Если в LINQ пользоваться только объектным стилем задания запроса, то LINQ тоже станет похож на Funq. Другое дело, что на практике делать именно так в LINQ практически невозможно и в любом случае неудобно. Важно также, что и цель у создателей LINQ изначально была другая — встроить язык запросов в .NET с помощью обычных его средств и научить языки .NET работать через одни и те же классы и интерфейсы с базами данных, XML-файлами, да и вообще любыми источниками данных, вплоть до обычных массивов.
  
А ещё, раз уж мы вспомнили про LINQ, можно сразу заметить, что описанная идея позволяет легко реализовать "язык запросов" на объектном интерфейсе в родном синтаксисе многих языков программирования. Конкретно автора (меня - ~~~~) интересует язык [[Perl]], он-то и будет рассмотрен в данной статье.
+
А ещё, раз уж мы вспомнили про LINQ, можно сразу заметить, что описанная идея позволяет легко реализовать «язык запросов» на объектном интерфейсе в родном синтаксисе многих языков программирования. Конкретно автора (меня — ~~~~) интересует язык [[Perl]], он-то и будет рассмотрен в данной статье.
  
Нужно отметить, что формирование запроса в родном синтаксисе языка имеет и недостаток - затруднение кэширования скомпилированных запросов. Из-за этого может пострадать производительность; однако, если объекты запросов кэшируются самим приложением, этого не произойдёт. Этот недостаток говорит нам о том, что имеет смысл реализовать одновременно и объектный подход к формированию запроса, и просто трансляцию из Funq-кода.
+
Нужно отметить, что формирование запроса в родном синтаксисе языка имеет и недостаток — затруднение кэширования скомпилированных запросов. Из-за этого может пострадать производительность; однако, если объекты запросов кэшируются самим приложением, этого не произойдёт. Этот недостаток говорит нам о том, что имеет смысл реализовать одновременно и объектный подход к формированию запроса, и просто трансляцию из Funq-кода.
  
 
=== Другие нужные фичи ===
 
=== Другие нужные фичи ===
  
* Автоматическая трансляция имён таблиц, и вообще запросов к таблицам. Это значит, что всегда можно переопределить <source lang="perl">$dbh->query("some_table")</source> так, что на самом деле этот конструктор будет возвращать не новый, девственно чистый, объект запроса к таблице some_table, а некоторый другой объект запроса - с заданными дополнительными ограничениями, к другой таблице, или вообще результат сложного запроса (хотя так делать, наверное, не надо). То есть, по сути, "программные представления".
+
* Автоматическая трансляция имён таблиц, и вообще запросов к таблицам. Это значит, что всегда можно переопределить <source lang="perl">$dbh->query("some_table")</source> так, что на самом деле этот конструктор будет возвращать не новый, девственно чистый, объект запроса к таблице some_table, а некоторый другой объект запроса — с заданными дополнительными ограничениями, к другой таблице, или вообще результат сложного запроса (хотя так делать, наверное, не надо). То есть, по сути, «программные представления».
* Именованные параметры (placeholder'ы) - задаются как '''?name''' - и автоматическое определение имени из контекста в простых выражениях. Например, параметр из условия '''config=?''' будет, очевидно, называться ''config'', если только уже не задан другой параметр с таким именем. Кроме того, один и тот же явно именованный параметр можно использовать в различных местах выражения и даже в разных операторах в процессе формирования запроса.
+
* Именованные параметры (placeholder’ы) — задаются как <code>?name</code> — и автоматическое определение имени из контекста в простых выражениях. Например, параметр из условия <code>config=?</code> будет, очевидно, называться <code>config</code>, если только уже не задан другой параметр с таким именем. Кроме того, один и тот же явно именованный параметр можно использовать в различных местах выражения и даже в разных операторах в процессе формирования запроса.
* Персонализация условий заданием имени таблицы (или имён таблиц) - к примеру, если в запросе записано условие <code>exif.?placeholder</code>, а значение placeholder-а равняется <code>.file=? and .config=?</code>, то в запрос будет подставлено преобразованное условие <code>exif.file=? and exif.config=?</code>. Если аналогично требуется сделать для нескольких таблиц (ситуация редкая), синтаксис усложняется - теперь условие в запросе, например, может звучать как <code>[exif, configs].?placeholder</code>, а в placeholder-е, например, как <code>_1.file=? and _1.config=_2.id</code>. При этом _1 будет заменено на имя первой таблицы, _2 - на имя второй, и так далее.
+
* Персонализация условий заданием имени таблицы (или имён таблиц) — к примеру, если в запросе записано условие <code>exif.?placeholder</code>, а значение placeholder-а равняется <code>.file=? and .config=?</code>, то в запрос будет подставлено преобразованное условие <code>exif.file=? and exif.config=?</code>. Если аналогично требуется сделать для нескольких таблиц (ситуация редкая), синтаксис усложняется — теперь условие в запросе, например, может звучать как <code>[exif, configs].?placeholder</code>, а в placeholder-е, например, как <code>_1.file=? and _1.config=_2.id</code>. При этом _1 будет заменено на имя первой таблицы, _2 — на имя второй, и так далее.
* Наличие хинта (подсказки) для последовательного выполнения подзапросов, т.е. выполнения сначала внутреннего запроса, а потом внешнего.
+
* Наличие хинта (подсказки) для последовательного выполнения подзапросов, то есть выполнения сначала внутреннего запроса, а потом внешнего.
* Автоматическое кэширование компилируемых из Funq-кода (т.е. **не** формируемых объектно) запросов. Кэширование детализированных условиями и порядками сортировки/группировки запросов. Следует отметить, что если в процессе выполнения появляется слишком много (неограниченное относительно вариации входных данных количество) детализированных условиями и порядками запросов, значит, что-то //"Defective By Design"//, а точнее, кто-то забыл про placeholder'ы...
+
* Автоматическое кэширование компилируемых из Funq-кода (то есть **не** формируемых объектно) запросов. Кэширование детализированных условиями и порядками сортировки/группировки запросов. Следует отметить, что если в процессе выполнения появляется слишком много (неограниченное относительно вариации входных данных количество) детализированных условиями и порядками запросов, значит, что-то //«Defective By Design»//, а точнее, кто-то забыл про placeholder’ы…
 
* Автоматическая проверка соединения, переподключение к БД и пересоздание кэшированных SQL-объектов запроса в случае необходимости.
 
* Автоматическая проверка соединения, переподключение к БД и пересоздание кэшированных SQL-объектов запроса в случае необходимости.
 
* Поддержка разделения соединённых отношений на отдельные хеши в результатах запроса.
 
* Поддержка разделения соединённых отношений на отдельные хеши в результатах запроса.
Строка 66: Строка 66:
 
На данный момент из запланированных идей реализованы ([http://svn.yourcmc.ru/viewvc.py/vitaphoto/head/lib-sway/Funq/ обзор исходных кодов]):
 
На данный момент из запланированных идей реализованы ([http://svn.yourcmc.ru/viewvc.py/vitaphoto/head/lib-sway/Funq/ обзор исходных кодов]):
  
* Собственно работающий компилятор запросов ;) начал с MySQL. Компилятор с полной поддержкой синтаксиса SELECT, с корректной оптимизацией / добавлением подзапросов, разрешением спорных ситуаций по семантике, поддержкой хинтов типа CALC_FOUND_ROWS, SQL_CACHE и т.п., заменой имён таблиц и прочими;
+
* Собственно работающий компилятор запросов ;) начал с MySQL. Компилятор с полной поддержкой синтаксиса SELECT, с корректной оптимизацией / добавлением подзапросов, разрешением спорных ситуаций по семантике, поддержкой хинтов типа CALC_FOUND_ROWS, SQL_CACHE и т. п., заменой имён таблиц и прочими;
 
* Связывание именованных параметров (?name) со скалярами, с массивами или массивами массивов значений, с выражениями или подзапросами;
 
* Связывание именованных параметров (?name) со скалярами, с массивами или массивами массивов значений, с выражениями или подзапросами;
 
* Корректное кэширование всех артефактов трансляции, чтобы не мучаться этим постоянно;
 
* Корректное кэширование всех артефактов трансляции, чтобы не мучаться этим постоянно;
* "Аппликация" имён таблиц к выражениям (замена `_` на имя нужной таблицы при подстановке выражения вместо `table`.?expression;
+
* «Аппликация» имён таблиц к выражениям (замена `_` на имя нужной таблицы при подстановке выражения вместо `table`.?expression;
 
* Автоматическое контекстное именование параметров, если имя не указано;
 
* Автоматическое контекстное именование параметров, если имя не указано;
 
* Возможность разделения каждой строки на несколько хешей, чтобы выбирать отдельные строки одновременно из нескольких таблиц;
 
* Возможность разделения каждой строки на несколько хешей, чтобы выбирать отдельные строки одновременно из нескольких таблиц;
* Удобные функции получения результатов запросов (в основном аналогично DBI): успешность выполнения / массив хешей / массив разделённых хешей / массив массивов / хеш хешей / одна строка / одно значение. Или ручками - тоже можно.
+
* Удобные функции получения результатов запросов (в основном аналогично DBI): успешность выполнения / массив хешей / массив разделённых хешей / массив массивов / хеш хешей / одна строка / одно значение. Или ручками — тоже можно.
* Разделение функционала на "ядро" и "драйверы";
+
* Разделение функционала на «ядро» и «драйверы»;
 
* Выбран способ передачи доп. информации типа SELECT FOUND_ROWS();
 
* Выбран способ передачи доп. информации типа SELECT FOUND_ROWS();
 
* Поддержка запросов вставки/обновления/удаления.
 
* Поддержка запросов вставки/обновления/удаления.
  
 
Чего пока нет:
 
Чего пока нет:
- Автоматической генерации алиасов например для подзапросов, если они не задаются явно;
+
Автоматической генерации алиасов например для подзапросов, если они не задаются явно;
- Поддержки подстановки хешей в текст запроса (например в виде field=value AND field=value);
+
Поддержки подстановки хешей в текст запроса (например в виде field=value AND field=value);
- Возможности программного последовательного выполнения подзапросов - сначала внутреннего, а потом внешнего, с программной передачей результата первого во второй (в MySQL бывают ситуации когда это ускоряет запрос В РАЗЫ);
+
Возможности программного последовательного выполнения подзапросов — сначала внутреннего, а потом внешнего, с программной передачей результата первого во второй (в MySQL бывают ситуации когда это ускоряет запрос В РАЗЫ);
- Нет ORM'а, и даже не обдуман. А возможно, стоит. А возможно, и не стоит.
+
Нет ORM’а, и даже не обдуман. А возможно, стоит. А возможно, и не стоит.

Версия 16:00, 13 июля 2009

Funq — концепция околофункционального, гибкого язык запросов к реляционным базам данных, чем-то похожего на LINQ и призванного заменить SQL для разработчиков, к тому же, скрывая диалекты, свойственные отдельным СУБД.

Идея

Сейчас стандартом языка запросов к реляционным базам данных является SQL — громоздкий, некрасивый и тяжёлый язык. SQL — декларативный язык, но он не оперирует сущностями каких-то явных типов, а синтаксис команд очень жёсткий, то есть, негибкий. Например, чтобы автоматически наложить на уже созданный запрос какое-то ограничение, нужно сначала понять, в какое место и в каком виде его добавлять, а способа адекватно и надёжно сделать это без синтаксического анализа запроса не существует.

Таким образом, было бы неплохо создать не SQL-подобный язык запросов, который был бы к тому же элегантен и удобен для использования в клиентских приложениях. Например, можно максимально приблизить формирование запросов к заданию выражения над таблицами, как алгебраическими объектами, с использованием различных операций реляционного исчисления — JOIN-ов, ограничений, проекций и т.д, а также других нереляционных преобразований — они необходимы потому, что возможностей построения запросов разработчики различных СУБД создали великое множество, а на замену SQL годится по меньшей мере равномощный ему язык. Сразу оговоримся, что основные проблемы написания запросов к базам данных связаны с запросами выборки. Запросы удаления/обновления часто используют базу просто как хеш-таблицу, а запросы вставки и DDL-запросы просто имеют достаточно бедный синтаксис. Их также нужно реализовать, как часть языка запросов, но основной интерес представляют запросы выборки. Ими-то мы в первую очередь и займёмся.

Например, рассмотрим вот такой SQL-запрос. Можно заметить, что это не чистый SQL — здесь ещё присутствуют подстановки имён таблиц из хеша $t и имён полей $child и $parent.

SELECT t0.*, (t3.`$parent` IS NULL) AS `_direct`
FROM `$t->{album2album}` AS t1
INNER JOIN `$t->{albums}` AS t0 ON t0.`id`=t1.`$child` AND $t0_where
LEFT JOIN (`$t->{album2album}` AS t3
INNER JOIN `$t->{album2album}` AS t4)
ON t3.`pid`=? AND t4.`pid`=? AND t3.`$parent`=t1.`$parent`
AND t3.`$child`=t4.`$parent` AND t4.`$child`=t1.`$child`
WHERE t1.`$parent`=? AND t1.`pid`=?
GROUP BY t0.`id`
HAVING `_direct`=1
ORDER BY t0.`ord` DESC, t0.`name`
LIMIT ?, ?

А теперь попробуем представить, как этот запрос должен был бы выглядеть на языке Funq:

(album2album as t1)
.where (t1.?parent=? and t1.pid=?pid)
.join ((albums as t0).where(t0.id=t1.?child and t0.?t0where))
.join[left] ((album2album as t3).where(t3.?parent=t1.?parent and t3.pid=?pid))
.join ((album2album as t4).where(t4.?parent=t3.?child and t4.?child=t1.?child and t4.pid=?pid))
.select (t0.*, (t3.?parent is null) as t1._direct)
.hint[calc-found-rows]
.group (t0.id)
.where (t1._direct=1)
.order (t0.ord desc, t0.name)
.limit (?offset, ?limit)
Заметно две основных идеи: во-первых, логически после применения каждого преобразования .something() к отношению мы снова получаем отношение, имеющее все те же самые методы; и во-вторых, язык должен уметь интерполировать различные конструкции в различные места запросов. Вообще-то, внезапно можно осознать, что relation.something().something().something() — функциональный стиль программирования, а точнее, что это очень похоже на [http://www.martinfowler.com/bliki/FluentInterface.html Fluent Interfaces]. Собственно, они и сами являются пародией на ФП, хотя и довольно жалкой. Кроме того, можно вспомнить язык [http://msdn.microsoft.com/en-us/netframework/aa904594.aspx LINQ] (Language INtegrated Query) от Microsoft. Если в LINQ пользоваться только объектным стилем задания запроса, то LINQ тоже станет похож на Funq. Другое дело, что на практике делать именно так в LINQ практически невозможно и в любом случае неудобно. Важно также, что и цель у создателей LINQ изначально была другая — встроить язык запросов в .NET с помощью обычных его средств и научить языки .NET работать через одни и те же классы и интерфейсы с базами данных, XML-файлами, да и вообще любыми источниками данных, вплоть до обычных массивов. А ещё, раз уж мы вспомнили про LINQ, можно сразу заметить, что описанная идея позволяет легко реализовать «язык запросов» на объектном интерфейсе в родном синтаксисе многих языков программирования. Конкретно автора (меня — ~~~~) интересует язык [[Perl]], он-то и будет рассмотрен в данной статье. Нужно отметить, что формирование запроса в родном синтаксисе языка имеет и недостаток — затруднение кэширования скомпилированных запросов. Из-за этого может пострадать производительность; однако, если объекты запросов кэшируются самим приложением, этого не произойдёт. Этот недостаток говорит нам о том, что имеет смысл реализовать одновременно и объектный подход к формированию запроса, и просто трансляцию из Funq-кода. === Другие нужные фичи === * Автоматическая трансляция имён таблиц, и вообще запросов к таблицам. Это значит, что всегда можно переопределить $dbh->query("some_table") так, что на самом деле этот конструктор будет возвращать не новый, девственно чистый, объект запроса к таблице some_table, а некоторый другой объект запроса — с заданными дополнительными ограничениями, к другой таблице, или вообще результат сложного запроса (хотя так делать, наверное, не надо). То есть, по сути, «программные представления». * Именованные параметры (placeholder’ы) — задаются как ?name — и автоматическое определение имени из контекста в простых выражениях. Например, параметр из условия config=? будет, очевидно, называться config, если только уже не задан другой параметр с таким именем. Кроме того, один и тот же явно именованный параметр можно использовать в различных местах выражения и даже в разных операторах в процессе формирования запроса. * Персонализация условий заданием имени таблицы (или имён таблиц) — к примеру, если в запросе записано условие exif.?placeholder, а значение placeholder-а равняется .file=? and .config=?, то в запрос будет подставлено преобразованное условие exif.file=? and exif.config=?. Если аналогично требуется сделать для нескольких таблиц (ситуация редкая), синтаксис усложняется — теперь условие в запросе, например, может звучать как [exif, configs].?placeholder, а в placeholder-е, например, как _1.file=? and _1.config=_2.id. При этом _1 будет заменено на имя первой таблицы, _2 — на имя второй, и так далее. * Наличие хинта (подсказки) для последовательного выполнения подзапросов, то есть выполнения сначала внутреннего запроса, а потом внешнего. * Автоматическое кэширование компилируемых из Funq-кода (то есть **не** формируемых объектно) запросов. Кэширование детализированных условиями и порядками сортировки/группировки запросов. Следует отметить, что если в процессе выполнения появляется слишком много (неограниченное относительно вариации входных данных количество) детализированных условиями и порядками запросов, значит, что-то //«Defective By Design»//, а точнее, кто-то забыл про placeholder’ы… * Автоматическая проверка соединения, переподключение к БД и пересоздание кэшированных SQL-объектов запроса в случае необходимости. * Поддержка разделения соединённых отношений на отдельные хеши в результатах запроса. * Поддержка различных диалектов языка SQL. * Поддержка возможности тихо игнорировать заданные при вставках/обновлениях несуществующие поля. == Статус реализации == На данный момент из запланированных идей реализованы ([http://svn.yourcmc.ru/viewvc.py/vitaphoto/head/lib-sway/Funq/ обзор исходных кодов]): * Собственно работающий компилятор запросов ;) начал с MySQL. Компилятор с полной поддержкой синтаксиса SELECT, с корректной оптимизацией / добавлением подзапросов, разрешением спорных ситуаций по семантике, поддержкой хинтов типа CALC_FOUND_ROWS, SQL_CACHE и т. п., заменой имён таблиц и прочими; * Связывание именованных параметров (?name) со скалярами, с массивами или массивами массивов значений, с выражениями или подзапросами; * Корректное кэширование всех артефактов трансляции, чтобы не мучаться этим постоянно; * «Аппликация» имён таблиц к выражениям (замена `_` на имя нужной таблицы при подстановке выражения вместо `table`.?expression; * Автоматическое контекстное именование параметров, если имя не указано; * Возможность разделения каждой строки на несколько хешей, чтобы выбирать отдельные строки одновременно из нескольких таблиц; * Удобные функции получения результатов запросов (в основном аналогично DBI): успешность выполнения / массив хешей / массив разделённых хешей / массив массивов / хеш хешей / одна строка / одно значение. Или ручками — тоже можно. * Разделение функционала на «ядро» и «драйверы»; * Выбран способ передачи доп. информации типа SELECT FOUND_ROWS(); * Поддержка запросов вставки/обновления/удаления. Чего пока нет: — Автоматической генерации алиасов например для подзапросов, если они не задаются явно; — Поддержки подстановки хешей в текст запроса (например в виде field=value AND field=value); — Возможности программного последовательного выполнения подзапросов — сначала внутреннего, а потом внешнего, с программной передачей результата первого во второй (в MySQL бывают ситуации когда это ускоряет запрос В РАЗЫ); — Нет ORM’а, и даже не обдуман. А возможно, стоит. А возможно, и не стоит.