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

flickerdb

v0.2.2

Published

Local JSON database for Node.

Downloads

246

Readme

💾FlickerDB

Create posts db and add the first post:

import FlickerDB from 'flickerdb';

const postsDB = new FlickerDB('db/posts');

postsDB.addOne({ title: 'post 1', content: 'this is my first post' });

Description

Local JSON database based on the file system. Designed for maximum memory efficiency, it features robust error handling, and a variety and easy-to-use methods for seamless integration 🚀

Requirements

Node.js

Node.js version 16 or newer.

⚡Features

  • Type-safe (made in Typescript).
  • Atomic write.
  • Memmory-friendly.
  • Robust error handling 💪

Installation

npm install flickerdb

Usage

Create posts db and add the first post:

import FlickerDB from 'flickerdb';

type Post = { title: string; content: string };

const postsDB = new FlickerDB<Post>('db/posts');

postsDB
	.addOne({ title: 'post 1', content: 'this is my first post' })
	.then(id => console.log("post's id:", id))
	.catch(err => console.error('could not add the post. error code:', err.code));

In db/posts.json:

{"d98821f5-87a6-47c8-bb46-8af04a65c7ba":{"title":"post 1","content":"this is my first post"}}

Get 10 posts where the title property contains the substring 'funko pop'

postsDB
	.find(entry => entry.data.title.includes('funko pop'), { limit: 10 })
	.then(result => {
		if (!result) return console.log('no matches found');

		console.log('posts found:', result.entries);
	})
	.catch(() => console.log('something went wrong'));

More examples here.

[!WARNING] Manipulating the database file manually could arise unexpected behaviors and frequent thrown exceptions. Avoid doing it in favor to keep things working 😎

API

💾FlickerDB

Initializes db. Usage: new FlickerDB(PathLike, FlickerOptions).

  • PathLike: string, URL or Buffer.
  • FlickerOptions:
    • overwrite: Whether overwrite the previous content when init db or not. Default: true.
    • stringify: The desired serialization method to use. Default: JSON.stringify.
import FlickerDB from 'flickerdb';

const db = new FlickerDB('db', { overwrite: false });

Instance methods:

  • add: add new entries to db. Usage: db.add(Array<data>).
const ids = await db.add(['data1', 'data2']);

console.log(ids.length); // output: 2
  • addOne: add new entry to db. Usage: db.addOne(data).
const id = await db.addOne('data1');

console.log("entry's id:", id);

[!NOTE] You should use add over addOne in those cases where you want to add more than one entry at a time. addOne uses add under the hood so using it several times instead of using add is slower. This behavior is not exclusive of add and addOne, since other methods do similar things.

  • find: get an object that contains a list of entries and other properties. Usage: db.find(matcherFn, FilterOptions).

    • matcherFn: a function that takes each entry as argument. A return value of true indicates that the entry meet the match.
    • FilterOptions:
      • limit: limits the number of entries to search. Default: Infinity.
      • offset: indicates from where to start saving the entries. For example, if the offset is set to 3, the first 3 entries matched are ignore. Values less than 0 are interpreted as 0. Default: 0.
      • holdTillMatch: once the limit has been reached, the search is intended to stop. If holdTillMatch is true, the search stops just after one more match is found (which is not added to final entries), preventing from stop when limit is reached. This is useful in scenarios where you wanna know whether there are more matches in addition to offset + limit. For example, if you apply pagination maybe you wanna know whether some entry left or not. Default: false.
// get 10 entries whose data content includes the word "empanada",
// ignoring the first 3 matches (offset = 3)
const result = await db.find(({ data }) => /empanada/gi.test(data), {
	limit: 10,
	offset: 3,
	// if exactly 13 matches were found (offset + limit),
	// the search will stop after finding one more entry,
	// which is not added to the final entries in the return value.
	holdTillMatch: true,
});

if (!result) return console.log('no match found');

const { entries, wereThereMatchesLeft } = result;

console.log('matches found:', entries);

console.log(
	wereThereMatchesLeft
		? 'there are still more matches in db'
		: 'these are all matches in db',
);

// if holdTillMatch were false, wereThereMatchesLeft would be false too
  • findById: get the entry's data identified by the id argument. Usage: db.findById(id).
const data = await db.findById('d98821f5-87a6-47c8-bb46-8af04a65c7ba');

if (!data) return console.log('entry not found');

console.log("entry's data:", data);
  • remove: remove entries from db. Usage: db.remove(matcherFn).

    • matcherFn: a function that takes each entry as argument. A return value of true indicates that the entry must be removed.
// remove all entries whose data content doesn't include the word "empanada"
const removedEntries = await db.remove(
	({ data }) => !/empanada/gi.test(data),
);

if (!removedEntries) return console.log('no match found');

console.log(`${removedEntries} entries were removed`);
  • removeById: remove an entry by its id. Usage: db.removeById(id).
const result = await db.removeById('d98821f5-87a6-47c8-bb46-8af04a65c7ba');

if (!result) return console.log('entry not found');

console.log('entry removed correctly!');
  • clearAll: remove all entries from db. Usage: db.clearAll().
await db.clearAll();
  • update: update entries from db. Usage: db.update(fn).

    • fn: a function that takes each entry as argument. A return value of undefined means that that entry must be ignored (do not update).
const beerReg = /beer/gi;

// update all entries whose data content includes the word "beer"
const updatedEntries = await db.update(({ data }) => {
	// do not update those entries whose data content does not include the word "beer"
	if (!beerReg.test(data)) return;

	return data.replace(beerReg, '🍺');
});

if (!updatedEntries) return console.log('no match found');

console.log(`${updatedEntries} entries were updated`);
  • updateById: update entry by its id. Usage: db.updateById(id, modifierFn).

    • id: entry's id.
    • modifierFn: a function that takes the entry's data identified by id as argument. The entry's data will be replaced by the return value of modifierFn.
const result = await db.updateById(
	'd98821f5-87a6-47c8-bb46-8af04a65c7ba',
	data => 'new value',
);

if (!result) return console.log('entry not found');

console.log('entry updated correctly!');
  • getTotalEntries: get the total number of entries in db. Usage: db.getTotalEntries().
const totalEntries = await db.getTotalEntries();

console.log({ totalEntries });

[!NOTE] Almost all methods require reading the database file during execution, so the time it takes to execute each method depends on the size of the database 😱. When possible, consider splitting databases that are intended to store large amounts of data to improve performance.

💥FlickerError

FlickerDB's instances methods might throw exceptions. These errors are instances of FlickerError. FlickerError objects have two important properties: message and code.

  • code: error code assigned to each type of error. Example values: 'MISSING_FILE', 'SERIALIZATION_ERROR'.

🦉Final thoughts

This library is not intended to replace more scalable, secure and, in general, better solutions like MySQL, MongoDB, etc. It has limited capabilities and use cases. You can use it for small projects or as a complement to other options. Use it wisely within its intended scope for optimal results ✨