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

fstreestore

v1.0.0

Published

Key-value store on filesystem using a simple tree structure

Downloads

3

Readme

FSTREESTORE

FSTREESTORE is a key-value store that relies entirely on the filesystem and file/folder tree structure. No server.

Here are some features:

  • Entirely based on the filesystem
  • Five simple operations: has, set, get, remove, list
  • Fast listing with indexing and self sanitizing
  • No server required
  • A database is just a folder (easy backup, migrate, delete)
  • Need multiple stores? Just instanciate multiple Store on different folders
  • No low-level dependencies
  • OK fast
  • Keys can contain any utf-8 characters (emoji, Chinese, etc.) and as long as 36 characters
  • Values can be null, String, Number, Array, Object, TypedArray (including BigInt and Float64) and Boolean
  • Numerical values are automatically saved as float or int on 64 bits. Strings are utf-8
  • Serialization file format is efficient, versatile and simple

Install

npm install fstreestore

Usage

const Store = require('fstreestore')

// A diretory path is expected here. Can be absolute or relative
let s = new Store('/somewhere/on/filesystem/myDb')

// All the functions are asynchronous and return promises, so they need to be called
// with 'await' from an 'async' function (or with '.then() and .catch())
async function main() {
  // Create the provided directory if necessary
  await s.init()
  
  // ** Store a key-value 

  // with a string
  await s.set('a-key', 'a value')

  // with a number (serialized as int64)
  await s.set('a-key-02', 42)

  // with a number (serialized as float64)
  await s.set('a-key-03', 42.42)

  // with an Object (serialized as JSON string, utf-8)
  await s.set('a-key-04', {firstname: 'Johnny', lastname: 'Bravo'})

  // with an (untyped) Array (serialized as JSON string, utf-8)
  await s.set('a-key-05', [42, 'Johnny Bravo', {foo: 'bar'}])
  
  // with a typed array (all flavours are possible)
  await s.set('a-key-06', new Uin32Array([12, 13, 14]))
  await s.set('a-key-07', new Float64Array([12.5, 13.3, 14]))

  // with boolean
  await s.set('a-key-08', true)

  // with null
  await s.set('a-key-09', null)


  // ** Retrieve/get a value, under the type they were saved

  let val02 = await s.get('a-key-02') // 42 --> number
  let val07 = await s.get('a-key-07') // Float64Array([12.5, 13.3, 14]) --> typed array
  let val04 = await s.set('a-key-04') // {firstname: 'Johnny', lastname: 'Bravo'} --> object


  // ** List all the available keys

  let allKeys = await s.list()


  // ** remove data, using the key

  await s.remove('a-key-02') 
}

main()

Key format

The only constraint for the keys is that they are at least 1 character long and at most 36. Apart from that, all the utf-8 charaters are possible, including emojis, accentuated, Chinese, etc.

Example:

await s.set('drum 🥁', new Float32Array([12, 34.34, Math.PI]))

A word on Errors

FSTREESTORE will throw errors if the provided key does not respect (empty string or longer than 36 characters).

In addition, the .get() will throw an error if the key is not existing. To prevent get from thowing, it must be used as follow .get('some key', {throw: false}), then a null value will be returned if 'some key' does not exist.

Listing and precautions

Since FSTREESTORE's database are entirely based on the filesystem, it makes all the data easily accessible, but the files and folder in there are to be accessed only by FSTREESTORE and should not be modified manually, otherwise the whole DB might get corrupted.

This is particularly true for the list file, that makes the listing possible in a reasonable amount of time. This file keeps an index of what is added and removed. Every time .list() is called, the list file gets sanitized under the hood, removing duplicates and deleted keys to keep only the remaining keys. The list is automatically sanitized every 5000 set/remove operations.

Compatibility

FSTREESTORE was developed and tested on MacOS and probably works on Linux. It was not tested on Windows and I am pretty sure it would not work due to the Windows filesystem being very different from Unix-like fs.

Why?

The idea first came when I started to look for a key-value store that I could run close to a Nodejs app, that did not require a server and was fast and versatile enough. I stumbled upon the excellent LMDB (and its Node wrapper) and started playing with it. Then I wondered how it was working under the hood and looked up B+ trees and stuff like that, and even though FSTREESTORE does not use a B+ tree, it's still loosely inspired by this concept. Also, not relying on low level dependencies can prevent having some plateform issues.
Finally, the main reason is that it was fun to to and I was curious about the performance of such a naive store implementation.

Performance

In the first part, performances were said to be "OK fast", this is obviously relative to one's habit and expectation (as well as one's configuration). In other word, let's just say it's a hobby store that is tailords for hobby projects, and it costs zero in DB server money.

CREATE time (ms): 822.414488017559   iterations: 1000  ops: 1215
READ time (ms): 372.39405900239944   iterations: 1000  ops: 2685
DELETE time (ms): 651.8716329932213   iterations: 1000  ops: 1534

Obviously, these are nowhere near the ~50000 operations per seconds (ops) I get with LMDB in the same conditions, but I knew since the very begining that I would never be even close with such a naive approach that relies entirely on creating folders and files on the filesystem!