@storynode/jql

0.2.3 • Public • Published

jql

jql is a small library that provides a sql-like interface for querying and aggregating javascript objects and DOM nodes.

Features

  • 🤏 Small size: ~9kb gzipped
  • ☝️ Only one small external dependency
  • 👣 Small footprint: no prototype polluting
  • 🤷 No reason behind it

Usage

Installation

npm i @storynode/jql

DOM querying

import { select } from "@storynode/jql"

const results = await select("tagName", "textContent")
  .from(document)
  .where(
    and(
      tagName("div"),
      hasClass("foo"),
      not(hasClass("bar"))
    )
  )
  .limit(10) // Fetch first 10 results
  .offset(0) // Starting from the first one (the default)
  .run()

Would yield something like this:

[{
  tagName: "DIV",
  textContent: "I am the content of a div"
}, {
  tagName: "DIV",
  textContent: "I am the content of some other div"
}]

Objects / collections

const sampleObj = { name: "obj1", description: "Some object" };

const sampleCollection = [
  { name: "obj23", description: "Object 23" },
  { name: "obj111", description: "My name is Inigo Montoya" },
  { name: "trash", description: "This will not be selected" }
];

const results = await select()
  .from(sampleObj, sampleCollection)
  .where(
      prop("name", /^obj/)
  )
  .run()

Projections and builtin filters support nested properties out of the box:

const sample = [{
    parent: {
      a: 1,
      b: {
        c: 2
      }
    }
  }, {
    some: {
      prop: 1,
      some: {
        prop: 2
      }
    }
  }];

  const result = await select("parent.a").from(sample).run();
  // [{ parent: { a: 1 }}, { parent: { a: null }}]

  const result = await select().from(sample).where(prop("parent.a", 1)).run();
  // [{ parent: { a: 1, b: { c: 2 }}}]

Custom query filters

In the previous examples the provided builtin filters are used for simplicity's sake, but keep in mind that filters are just predicates, namely just functions that take an input and return a boolean, so you can provide any logic you want in those function bodies.

These predicates can be async.

As an extreme example, if you would like to filter all elements based on a flip of a coin:

const sampleObj = { name: "obj1", description: "Some object" };

const sampleCollection = [
  { name: "obj23", description: "Object 23" },
  { name: "obj111", description: "My name is Inigo Montoya" },
  { name: "trash", description: "This will not be selected" }
];

const results = await select()
  .from(sampleObj, sampleCollection)
  .where(
      (el) => Math.random() >= 0.5
  )
  .run()

Data sources

Joining sources

By default, when more than one datasource is specified in a from method call, all datasources are fully joined with one another.

If you want to perform different types of joins you can use one of the provided join operators

For example:

const orders = [{
  orderId: 1,
  userId: 1,
  description: "Foo"
}, {
  orderId: 2,
  userId: 2,
  description: "Bar"
}]

const users = [{
  id: 1,
  userName: "Bob"
}]

const results = await select("user.id", "user.userName", "orders")
  .from(
    innerJoin(users, orders, (user, order) => user.id === order.userId))
  )
  .run()

would yield

[{
  id: 1,
  userName: "Bob",
  orderId: 1,
  description: "Foo"
}]

Mixing datasources

You can mix DOM / collections / objects as datasources in a single query

FAQ

Why, in the name of all that is holy, did you do this?

- Coworkers and friends


Q: Why this library?

A: For absolutely no reason, I just had some time to spare


Q: In what situations is this actually helpful?

A: If you need to combine results from different objects / nodes / collections in a single result set then this is actually useful!


Q: Should I use jql instead of plain old query selectors?

A: It depends: if the filtering you need can be done with document.querySelector[All] and you know how to use it then, by all means, go for it. This can still be usefull if you need to filter results with a function and you want to add some readability to your code.


Q: Does this support joining datasources?

A: Not yet, but it will eventually Yes 😈

Package Sidebar

Install

npm i @storynode/jql

Weekly Downloads

0

Version

0.2.3

License

MIT

Unpacked Size

1.06 MB

Total Files

40

Last publish

Collaborators

  • sixpounder