npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@storynode/jql

v0.2.3

Published

A sql-like querying and aggregating interface for javascript objects and the DOM

Downloads

15

Readme

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 😈