Small file-based database for node.js
npm install leaf-db$gt
$gte
$lt
$lte
$regexp
$length
$includes
$not
$and
$or
id()
docs
open()
close()
get()
insert()
query()
update()
delete()
drop()
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.
leaf-db can be used in the browser if persistent read / write isn't required.
sh
npm i leaf-db
`
$3
Create a database using file storage with strong-typed documents:
`TS
import LeafDB from 'leaf-db';
type Document = {
title: string
name: string
}
const db = new LeafDB();
await db.open({ name: 'db', dir: process.cwd() });
const drafts = [
{ title: 'Lady', name: 'Mipha' },
{ title: 'Young Rito Warrior', name: 'Tulin' }
]
await Promise.all(drafts.map(async draft => db.insert(draft)));
// [{ _id: , 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
$3
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.
$3
Leaf-db only supports JSON values, which is defined as:
`TS
type Json =
string |
number |
boolean |
null |
Json[] |
{ [key: string]: Json };
`
$3
Leaf-db stores the database in memory by default. To make use of persistence, simply open the database.
`TS
import LeafDB from 'leaf-db';
/* Create a new database, db.jsonl, in process.cwd() /
const db = new LeafDB();
await db.open({ name: 'db', dir: process.cwd() });
`
$3
When opening a database from storage, leaf-db will return documents that are corrupt. These documents are deleted once opened and cannot be recovered afterwards.
`TS
import LeafDB from 'leaf-db';
const db = new LeafDB({ name: 'db', dir: process.cwd() });
const corrupt = await db.open(); // Corrupt[]
`
`TS
type Corrupt = {
raw: string;
error: Error;
};
`
$3
Leaf-db supports both literal values and operators. Example:
`TS
/**
* 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
`TS
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
`TS
const query = { a: { $gte: 3 } };
const a = { a: 2 }; // false
const b = { a: 3 }; // true
const c = { a: 4 }; // true
`
###### $lt
Is less than
`TS
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
`TS
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
`TS
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
`TS
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.
`TS
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
`TS
const query = { $not: { a: { $lt: 3 } } };
const a = { a: 2 }; // false
const b = { a: 4 }; // true
`
###### $and
Must match all queries
`TS
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
`TS
const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };
const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // true
`
API
$3
Generate a new, unique id with format [timestamp]-[random].
`TS
import LeafDB from 'leaf-db';
const id = LeafDB.id();
`
$3
Get all documents
`TS
const docs = db.docs // Doc[]
`
$3
Open persistent storage.
`TS
import LeafDB from 'leaf-db';
const db = new LeafDB();
const corrupted = await db.open({ name: 'db', dir: process.cwd() }); // Corrupt[]
`
$3
Close persistent storage.
`TS
await db.close();
`
$3
Get document by id
`TS
db.get('a'); // { _id: 'a' }
`
$3
Insert document(s) into the database. Will throw an error if duplicate _id's are found.
`TS
const drafts = [{ name: 'Tulin', }, { name: 'Mipha' }];
// [{ _id: , name: 'Tulin' }, { _id: , name: 'Mipha' }]
const docs = await Promise.all(drafts.map(async draft => draft.insert(draft)));
`
$3
Find document(s) based by query.
`TS
// 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' }] });
`
$3
Update existing document. Throws if document does not exist
`TS
// Update document a with new name Tulin
const docs = db.update({ _id: 'a', name: 'Tulin' });
`
$3
Delete document by _id
`TS
// Delete document a
await db.delete('a');
`
$3
Delete all documents in the database.
`TS
await db.drop();
``