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

requrse

v0.2.9

Published

Lightweight driven query language

Downloads

101

Readme

reQurse

Lightweight driven query language

NPM Version requrse CI Coverage Status

What is reQurse

reQurse introduces an innovative approach that overcomes the complexities of CRUD operations. The focus is on delivering a streamlined and efficient CRUD library solution, simplifying API development, and effortlessly handling complex data management tasks. reQurse utilized JSON-based queries, allows multi-tenant API sources, avoid writing lengthy procedural APIs and truly embrace Javascript core philosophy as OOP language. This approach promotes a modular and streamlined code structure, retaining the complexity of Object tree while enhancing flexibility and maintainability.

Here's the first example to get you started. Try it here—no build step required!

This library take some inspirations from NextQL and GraphQL

Usage

A basic usage of reQurse.

import rq from 'requrse'

rq(query, { methods, config })
  • query: (object) required JSON like query.
  • methods: (object) required define methods/computed fields that exist in the query.
  • config: (object) optional extend and added parameterize control over methods.
await rq({
  Test: {
    test: {
      greeting: '*'
    }
  }
},
{
  methods: {
    greeting () {
      return 'hello world'
    }
  }
}).then(console.log, console.error)
// { Test: { test: { greeting: 'hello world' } } }

Advance usage

A proper query should do more, to demystify the capability of this library, create a few data samples, you can imagine this as a setup that your database may have.

const acolyte = { id: '0', progression: ['1', '4'], name: 'Acolyte' }
const priest = { id: '1', progression: ['4'], name: 'Priest' }
const squire = { id: '2', progression: ['3', '4'], name: 'Squire' }
const paladin = { id: '3', progression: ['4'], name: 'Paladin' }
const inquisitor = { id: '4', progression: [], name: 'Inquisitor' }

// we also create the relations between them
const supportData = {
  0: acolyte,
  1: priest,
  4: inquisitor
}

const vanguardData = {
  2: squire,
  3: paladin,
  4: inquisitor
}

Then the helper functions to access these data

/**
 * Helper function to get a class by ID.
 */
function getClass (id) {
  // Returning a promise just to illustrate query support.
  return Promise.resolve(supportData[id] || vanguardData[id])
}
/**
 * Allows us to query for a classes's progression.
 */
function getProgression (classes) {
  return classes.progression.map(id => getClass(id))
}
/**
 * Allows us to query for the support class with the given id.
 */
function getSupport (id) {
  return supportData[id]
}
/**
 * Allows us to query for the vanguard class with the given id.
 */
function getVanguard (id) {
  return vanguardData[id]
}
/**
 * Allows us to query for the player class by gameId.
 */
function getPlayer (gameId) {
  if (gameId === 0) {
    return acolyte
  }
  return inquisitor
}

Then configure reQurse to use these methods

const confParams = {
  getPlayer, getClass, getProgression, getSupport, getVanguard
}

const config = (param) => confParams[param]

const methods = {
  player: 'getPlayer',
  class: 'getClass',
  progression: 'getProgression',
  support: 'getSupport',
  vanguard: 'getVanguard'
}

Simple usage

await rq({
  PlayerClass: {
    player: {
      name: 1
    }
  }
}, { methods, config }).then(console.log)
// { PlayerClass: { player: { name: 'Inquisitor' } } }

Use $params to filter result

await rq({
  PlayerClass: {
    player: {
      $params: { gameId: 0 },
      name: 1
    }
  }
}, { methods, config }).then(console.log)
// { PlayerClass: { player: { name: 'Acolyte' } } }

Optimize your query by writing efficient methods, i.e., here progression return the class next progression seamlessly

await rq({
  PlayerClass: {
    player: {
      $params: { gameId: 0 },
      id: 1,
      name: 1,
      progression: {
        name: 1
      }
    }
  }
}, { methods, config }).then(console.log)
// {
//   PlayerClass: {
//     player: {
//       id: '0',
//       name: 'Acolyte',
//       progression: [
//         { name: 'Priest' },
//         { name: 'Inquisitor' }
//       ]
//     }
//   }
// }

You can have multiple same dataset key name by / naming

await rq({
  vanguard: {
    'vanguard/paladin': {
      $params: { id: 3 },
      name: 1
    },
    'vanguard/inquisitor': {
      $params: { id: 4 },
      name: 1
    }
  }
}, { methods, config }).then(console.log)
// {
//   vanguard: {
//     'vanguard/paladin': { name: 'Paladin' },
//     'vanguard/inquisitor': { name: 'Inquisitor' }
//   }
// }

Now we expand the dataset to the inventory of the player

const healingPotion = { id: '0', effect: 'heal', dmg: 4, name: 'Healing Potion' }
const bandage = { id: '1', effect: 'heal', dmg: 1, name: 'Bandage' }
const holyWater = { id: '2', effect: 'cleansing', dmg: 2, name: 'Holy Water' }

// add relations to the inventory data
const itemData = {
  0: healingPotion,
  1: bandage,
  2: holyWater
}

// add relations to how many each class have these items in their inventory
const inventoryData = {
  0: [7, 1, 0],
  1: [3, 2, 2],
  2: [0, 5, 0],
  3: [1, 6, 2],
  4: [0, 0, 10]
}

Demonstrate usage of method/computed field to return value that you need, in this case count which came from a relational collection that store the value only, you can use such logic to build a powerful query for your api.

/**
 * Helper function to get an item by ID.
 */
function getItem (count, id) {
  // Returning a promise just to illustrate query support.
  return Promise.resolve({ ...itemData[id], count })
}

/**
 * Allows us to query for the player class inventoryData.
 */
function getInventory ({ id }) {
  return inventoryData[id].map(getItem)
}

Extends the reQurse methods/config

const extConfig = {
  methods: {
    ...methods,
    item: 'getItem',
    inventory: 'getInventory'
  },
  config: (param) => ({
    ...confParams,
    getItem,
    getInventory
  })[param]
}

Now see how it perform!

await rq({
  PlayerClass: {
    player: {
      $params: { gameId: 0 },
      name: 1,
      inventory: {
        id: 1,
        name: 1,
        count: 1
      }
    }
  }
}, extConfig).then(console.log)
// {
//   PlayerClass: {
//     player: {
//       name: "Acolyte",
//       inventory: [
//         {
//           id: "0",
//           name: "Healing Potion",
//           count: 7
//         },
//         {
//           id: "1",
//           name: "Bandage",
//           count: 1
//         },
//         {
//           id: "2",
//           name: "Holy Water",
//           count: 0
//         }
//       ]
//     }
//   }
// }

You can also return as dataUrl

await rq({
  PlayerClass: {
    player: {
      $params: { gameId: 0 },
      name: 1,
      inventory: {
        id: 1,
        name: 1,
        count: 1
      }
    }
  }
}, { ...extConfig, dataUrl: 'PlayerClass/player/inventory' }).then(console.log)
// [
//   {
//     id: '0',
//     name: 'Healing Potion',
//     count: 7
//   },
//   {
//     id: '1',
//     name: 'Bandage',
//     count: 1
//   },
//   {
//     id: '2',
//     name: 'Holy Water',
//     count: 0
//   }
// ]

More Samples

You can check samples folder to see more usage cases with Mongoose, Redis and the Starwars examples.