Skip to content

chronoDave/leaf-db

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

leaf-db

leaf-db

leaf-db is a simple NoSQL embeddable database for Node.js.

Features

  • Strong-typed documents and queries.
  • Easy to embed as it does not require an HTTP server to run.
  • Uses JSON documents.
  • Tiny and 0 depedencies.

Table of Contents

Getting Started

leaf-db is meant as a simple database that allows for basic querying over JSON data without needing to set up a database server / connection like with MongoDB or SQLite.

Node does support working with SQLite directly, if you prefer a more stable, feature-complete database.

Installation

npm i leaf-db

Example

Create a database using file storage with strong-typed documents:

import LeafDB from 'leaf-db';

type Document = {
  title: string
  name: string
}

const db = new LeafDB<Document>({ name: 'db', dir: process.cwd() });

await db.open();

const drafts = [
  { title: 'Lady', name: 'Mipha' },
  { title: 'Young Rito Warrior', name: 'Tulin' }
]
await Promise.all(drafts.map(async draft => db.insert(draft)));

// [{ _id: <string>, title: 'Young Rito Warrior', name: 'Tulin' }]
const characters = db.query({ name: 'Tulin' });

const tulin = characters[0];
tulin.title = 'Rito Warrior';

await db.update(tulin); // Overwrite existing document

await db.close();

Concepts

Document

Leaf-db stores data as JSON documents and saves them inside a JSONL file.

Keys

Document keys must be of type string and cannot start with $.

Every document is required to have an _id field. Leaf-db automatically creates an _id if the field does not exist on insertion. _id is required to be unique when inserting documents.

Values

Leaf-db only supports JSON values, which is defined as:

type Json =
  string |
  number |
  boolean |
  null |
  Json[] |
  { [key: string]: Json };

Persistence

Leaf-db stores the database in memory by default. To make use of persistence, simply provide a path in the constructor and open the database.

import LeafDB from 'leaf-db';

/**
 * Create a new database under process.cwd()
 * This will create `db.jsonl` in process.cwd() 
 */
const db = new LeafDB({ name: 'db', dir: process.cwd() });
await db.open();

Corruption

When opening a database from storage, leaf-db will return any documents that are corrupt. These documents will be deleted once opened.

import LeafDB from 'leaf-db';

const db = new LeafDB({ name: 'db', dir: process.cwd() });
const corrupt = await db.open(); // Corrupt[]
type Corrupt = {
  raw: string;
  error: Error;
};

Queries

Leaf-db supports both literal values and operators. Example:

/**
 * Literal query where value must equal the query value
 * { name: 'tulin' } // No match
 * { name: 'Mipha' } // No match
 */
const a = { name: 'Tulin' };

/**
 * Objects and arrays match on partial matches
 * { eras: [] } // Match
 * { eras: ['era of the wilds'] } // No match
 * { eras: [Sky Era'] } // No Match
 */
const b = { eras: ['Era of the Wilds'] }

Operators

Operators allow for more complex queries. Operators must always be used in combination with values.

Number
$gt

Is greater than

const query = { a: { $gt: 3 } };

const a = { a: 2 }; // false
const b = { a: 3 }; // false
const c = { a: 4 }; // true
$gte

Is greater than or equal to

const query = { a: { $gte: 3 } };

const a = { a: 2 }; // false
const b = { a: 3 }; // true
const c = { a: 4 }; // true
$lt

Is less than

const query = { a: { $lt: 3 } };

const a = { a: 2 }; // true
const b = { a: 3 }; // false
const c = { a: 4 }; // false
$lte

Is less than or equal to

const query = { a: { $lte: 3 } };

const a = { a: 2 }; // true
const b = { a: 3 }; // true
const c = { a: 4 }; // false
String
$regexp

Matches strings against RegExp

const query = { a: { $regexp: /\w+/g } }

const a = { a: '' }; // false
const b = { a: '0' }; // false
const c = { a: 'a' }; // true
Array
$length

Equal to length

const query = { a: { $length: 3 } }

const a = { a: [] }; // false
const b = { a: [1, 2, 3] }; // true
const c = { a: [1, 2, 3, 4] }; // false
$includes

Has value in array. Does not partial match on arrays or objects.

const query = { a: { $includes: 3 } };

const a = { a: [] }; // false
const b = { a: [1, 2, 3] }; // true

const query = { b: { $includes: [3] } };

const a = { b: [ [3] ] }; // true
const b = { b: [ [3, 4] ] }; // false
Logic
$not

Invert query

const query = { $not: { a: { $lt: 3 } } };

const a = { a: 2 }; // false
const b = { a: 4 }; // true
$and

Must match all queries

const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };

const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // false
$or

Matches any query

const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };

const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // true

API

id()

Generate a new, unique id.

import LeafDB from 'leaf-db';

const id = LeafDB.id();

docs

Get all documents

const docs = db.docs // Doc<T>[]

open()

Open persistent storage.

import LeafDB from 'leaf-db';

const db = new LeafDB({ name: 'db', dir: process.cwd() });

const corrupted = await db.open(); // Corrupt[]

close()

Close persistent storage.

await db.close();

get()

Get document by id

db.get('a'); // { _id: 'a' }

insert()

Insert document(s) into the database. Will throw an error if duplicate _id's are found.

const drafts = [{ name: 'Tulin', }, { name: 'Mipha' }];
// [{ _id: <string>, name: 'Tulin' }, { _id: <string>, name: 'Mipha' }]
const docs = await Promise.all(drafts.map(async draft => draft.insert(draft)));

query()

Find document(s) based by query.

// Return docs where `name` is equal to `Mipha`
const docs = db.query({ name: 'Mipha' });
// Return docs where `name` is equal to `Mipha` or where `name` is equal to `Tulin`
const docs = db.query({ $or: [{ name: 'Mipha' }, { name: 'Tulin' }] });

update()

Update existing document. Throws if document does not exist

// Update document `a` with new name `Tulin`
const docs = db.update({ _id: 'a', name: 'Tulin' });

delete()

Delete document by _id

// Delete document `a`
await db.delete('a');

drop()

Delete all documents in the database.

await db.drop();

Acknowledgements

About

Simple, small and embeddable NoSQL database for Node.js.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •