drupe
Tiny helper that lets you run Mango selectors anywhere you need a JavaScript predicate.
drupe is inspired by the ergonomics of sift but speaks Mango—the JSON-based query language used by CouchDB and PouchDB. Pass a Mango selector in and get back a function that tests plain JavaScript objects, arrays, or any iterable source.
Why drupe?
- Reuse the same Mango selectors you ship to CouchDB/PouchDB on the client or in tests.
- Drop into
Array.prototype.filter, find, or any higher-order utility—no extra plumbing required.
- Ships as a single function that delegates to PouchDB’s battle-tested
matchesSelector implementation.
- Zero configuration, fully typed, and framework/runtime agnostic.
Installation
Install from JSR:
yarn add @edge.app/drup
npx jsr add @edgeapp/drupe
Quick start
import { drupe } from 'drupe'
const isPublishedTechArticle = drupe({
type: 'article',
publishedAt: { $exists: true },
tags: { $in: ['databases', 'javascript'] }
})
const articles = [
{ type: 'article', slug: 'mango-101', tags: ['databases'], publishedAt: '2024-05-02' },
{ type: 'article', slug: 'draft-post', tags: ['javascript'] },
{ type: 'note', slug: 'retro' }
]
const published = articles.filter(isPublishedTechArticle)
The same selector you use in a db.find() call now works as an in-memory predicate.
More examples
All Mango selector operators are supported because drupe simply forwards to PouchDB’s selector engine. For a full reference, see the PouchDB guide on Mango queries and the CouchDB documentation linked above.
import { drupe } from 'drupe'
const isHighValueCustomer = drupe({
$and: [
{ spend: { $gte: 1000 } },
{ status: { $in: ['gold', 'platinum'] } }
]
})
const customers = [
{ name: 'Ada', spend: 3200, status: 'platinum' },
{ name: 'Lin', spend: 840, status: 'gold' },
{ name: 'Edsger', spend: 1500, status: 'silver' }
]
customers.filter(isHighValueCustomer)
You can also use $not, $regex, $size, $elemMatch, and any other Mango operator:
const containsLargeAttachment = drupe({
attachments: {
$elemMatch: {
content_type: { $regex: '^image/' },
length: { $gt: 1_000_000 }
}
}
})
docs.filter(containsLargeAttachment)
API
const predicate = drupe(selector)
predicate(document)
selector – Any valid Mango selector object.
- Returns a predicate function that can be reused across collections, iterables, or bespoke logic.
TypeScript: The exported signature is intentionally loose—(selector: any) => (subject: unknown) => boolean—so you can refine the shape that makes sense for your app.
How it works
drupe is intentionally tiny:
import { matchesSelector } from 'pouchdb-selector-core'
export const drupe = (selector: any) => (subject: unknown) => {
return matchesSelector(subject, selector)
}
When you call drupe(selector), it defers entirely to matchesSelector, the same function PouchDB uses internally to evaluate Mango selectors. That means:
- Behaviour matches CouchDB/PouchDB exactly (including quirks and edge cases).
- New Mango features arrive as soon as they land in
pouchdb-selector-core.
- There is no custom query engine to maintain.
Related resources
License
MIT © Sam Holmes