Представляю вашему вниманию небольшую js-библиотеку Jsqry.
Проще всего проиллюстрировать её назначение следующим примером.
До:
var name;
for (var i = 0; i < users.length; i++) {
if (users[i].id == 123) {
name = users[i].name;
break;
}
}
После:
var name = one(users, '[_.id==?].name', 123);
Библиотечка позволяет извлекать информацию из объектов/массивов в одну строку, используя несложный язык запросов, вместо написания циклов (подчас вложенных).
По сути, она реализует всего две функции:
- query — для возвращения списка результатов и
- one — для возвращения первого найденного результата.
Список возможностей включает:
- Фильтрацию
- Трансформацию
- Индексы/срезы в стиле Python
Библиотека появилась спонтанно в одном проекте, построенном на модном ныне подходе одностраничного приложения. Мы загружаем один большой JSON, части которого затем используются для рендеринга на клиенте разных представлений сайта. И вот для выдирания этих самых частей и захотелось более удобного способа. Затем, впрочем, библиотека оказалась востребована и в других случаях.
Поясню немного по функционалу. Запрос в общем случае может иметь вид
field1.field2[ condition or index or slice ].field3{ transformation }.field4
Тут:
- field1.field2.field3... — обычный доступ к полям объектов, как в js
- [ condition ] — фильтрация
- [ index ] — доступ по индексу, тоже как в js
- [ from:to:step ] — срезы в стиле Python
- { transformation } — преобразование объектов
На condition и transformation стоит остановиться подробнее.
На самом деле тут все очень просто. Достаточно понять, что каждое выражение внутри квадратных/фигурных скобок при выполнении заменяется на функцию по такому принципу:
condition_or_transformation ⟶ function(_,i) { return condition_or_transformation }
(тут _ — значение передаваемого элемента, i — его индекс).
Пример:
query([1,2,3,4,5],'[_>2]{_+10}') // [13, 14, 15]
Также поддерживаются параметризация запроса:
query([1,2,3,4,5],'[_>?]{_+?}', 2, 10) // [13, 14, 15]
Комбинируя эти возможности можно строить весьма сложные и гибкие запросы. Больше примеров использования можно посмотреть тут.
Из интересного в реализации — AST дерево запроса кешируется, что придает библиотеке скорости.
Разумеется, моя библиотека не уникальна в своём роде. Стоит привести "небольшой" список аналогов:
- SpahQL — http://danski.github.io/spahql/
- Objectpath — http://objectpath.org/
- Sift.js — https://github.com/crcn/sift.js
- DefiantJS — http://defiantjs.com/
- и так далее...
Зачем еще одна библиотека? На самом деле, она поддерживает не весь возможный спектр типов запросов, а только то что было нужно в нашем проекте в большинстве случаев. За счет этого простота и скорость. Также, чрезвычайно простой API, вдохновленный подходом JQuery.
Буду рад выслушать критику и предложения по улучшению.