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

underdb

v2.0.0-alpha.0

Published

> Minimalist JSON database for small projects

Downloads

2

Readme

UnderDB

Minimalist JSON database for small projects

db.data.posts.push({ id: 1, title: 'underdb is awesome' });

db.write();
{
  "posts": [{ "id": 1, "title": "underdb is awesome" }]
}

Highlights

  • Extremely minimalist API
  • Query and modify data using plain JS
  • TypeScript support out of the box
  • Hackable
    • Change storage, file format or add encryption via adapters
    • Add lodash, ramda, ... for super powers!

Install

npm install underdb

Usage

import path from 'path';
import UnderDB from 'underdb';
import JSONFile from 'underdb/adapters/JSONFile';

// Ensure that the path to db.json is not relative to proces.cwd()
const file = path.join(__dirname, 'db.json');

const adapter = new JSONFile(file);
const db = new UnderDB(adapter);

const defaultData = { messages: [] }(async () => {
  // Read data from JSON file, this will set db.data
  await db.read();

  // If db.json doesn't exist, db.data is null
  if (db.data === null) {
    // If db.data is null, set some default data
    // db.data can be anything: object, array, string, ...
    db.data = { messages: [] };
  }

  // Push new message
  db.data.messages.push('hello world');

  // Write to db.data to db.json
  await db.write();
})();
// db.json
{
  "messages": [ "hello world" ]
}

API

Classes

UnderDB comes with 2 classes to be used with asynchronous or synchronous adapters.

new UnderDB(adapter)

import UnderDB from 'underdb';
import JSONFile from 'underdb/lib/adapters/JSONFile';

const db = new UnderDB(new JSONFile('db.json'));
await db.read();
await db.write();

new UnderDB.sync(adapterSync)

import UnderDB from 'underdb';
import JSONFileSync from 'underdb/lib/adapters/JSONFileSync';

const db = new UnderDB.sync(new JSONFileSync('db.json'));
db.read();
db.write();

Methods

read()

Calls adaper.read() and sets instance data.

Note JSONFile and JSONFileSync adapters will set data to null if file doesn't exist.

db.data; // === undefined
db.read();
db.data; // !== undefined

write()

Calls adapter.write(data) and passes instance data

db.data = { posts: [] };
db.write(); // db.json will be { posts: [] }
db.data = {};
db.write(); // db.json will be {}

Properties

data

data is your db state. If you're using the adapters coming with UnderDB, it can be any type supported by JSON.stringify.

db.data = 'string';
db.data = [1, 2, 3];
db.data = { key: 'value' };

Adapters

Bundled adapters

UnderDB comes with 3 adapters, but you can write your own.

lib/adapters/JSONFile

Asynchronous adapter for reading and writng JSON files.

new UnderDB(new JSONFile(file));

lib/adapters/JSONFile

Synchronous adapter for reading and writng JSON files.

new UnderDB.sync(new JSONFileSync(file));

lib/adapters/LocalStorage

Synchronous adapter for window.localStorage use it with UnderDB.sync.

new UnderDB.sync(new LocalStorage())

Third-party adapters

  • ...
  • ...

Recipes

Using UnderDB with lodash

In this example, we're going to use lodash but you can apply the same principles to other libraries like ramda.

import lodash from lodash

// After db.read, add a new chain property
db.chain = lodash.chain(db.data)

// And use chain instead of db.data if you want to use the powerful API that lodash provides
db.chain
  .get('messages')
  .first()
  .value()

If you're building for the web, and want to make the bundle smaller, you can just use the functions that you need

import find from 'lodash/find';

const message = find(db.data.message, { id: 1 });

Synchronous file operations

If you prefer to write data synchronously, use UnderDB and JSONFileSync

import UnderDB from 'underdb';
import JSONFileSync from 'underdb/JSONFileSync';

const db = new UnderDB.sync(JSONFile('db.json'));

// db.read and db.write will be synchronous

Creating your own adapter

Adapter let's you persist your data to any storage. By default, UnderDB comes with JSONFile, JSONFileSync and LocalStorage but you can find on npm third-party adapters to store your data to GitHub, Dat, ...

But creating your own is super simple, your adapter just has to provide the following methods:

// If it's asynchronous
read: () => Promise<void>
write: (data: any) => void

// If it's synchronous
read: () => void
write: (data: any) => void

For example, let's say you have some remote storage:

import UnderDB from 'underdb';
import api from './MyAsyncStorage';

class MyAsyncAdapter {
  // this is optional but your Adapter could take some arguments
  constructor(someArgs) {
    // ...
  }

  read() {
    return api.read(); // should return a Promise
  }

  write() {
    return api.write(); // should return a Promise
  }
}

const adapter = new MyAsyncAdapter();
const db = new UnderDB(adapter);

Using it with TypeScript

UnderDB comes with definitions files out of the box, but since there's no way of telling what the data will look like you will need to provide an interface via a generic.

interface IData {
  messages: string[];
}

const db = new UnderDB<IData>(adapter);

Limits

UnderDB isn't meant to scale and doesn't support Cluster.

If you have large JavaScript objects (~10-100MB) you may hit some performance issues. This is because whenever you call write, the whole object will be serialized and written to the storage.

This can be fine depending on your projects. It can also be mitigated by doing batch operations and calling write only when you need it.

But if you plan to scale, it's highly recommended to use databases like PostgreSQL, MongoDB, ...

License

MIT