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

mfdb

v0.0.22-alpha

Published

MFdb is a portable P2P database backed by the IPFS Mutable File System.

Downloads

27

Readme

MFdb

MFdb is a portable P2P database backed by the IPFS Mutable File System.

Create large searchable datasets and easily share them with others. Works in Node and the browser.

Create a database locally and store it in IPFS. Then share the hash with others. They load it and can instantly search it after downloading. Since each commit is written to MFS you can also load a database at each intermediate state if you have the CID. Broadcast these changes and mirrored copies can stay up to date in real time. All merging happens at the Mutable File System level.

  • A database contain multiple tables.
  • Each table has a schema.
  • Index multiple fields.
  • Create unique and non-unique indexes. A b-tree is created for each index.
  • Broadcast updates to peers via IPNS. (coming soon)
  • Backup/load full database from hash.
  • Lightweight. Less than 300kb total.

Query data by primary and non-primary indexes. Each table has a schema and when records are inserted we build btree indexes. B-trees are loaded into memory when fields are searched.

The entire database is stored in an IPFS Mutable File System folder and can be exchanged with a single hash. Broadcast the hash via IPNS and any peers can sync up to the latest version. The sync speed depends on many different factors but should be faster the more peers you have.

Install

npm install ipfs mfdb

Usage

First initialize MFdb with IPFS.

import assert from 'assert'
import { MFdb } from "mfdb"

const ipfs = await IPFS.create()

const db = new MFdb(ipfs)

Create a database definition and use it to create the database. In this example we're saving baseball players.

We'll add a single table with 4 different indexed fields. Indexes can be unique. A table must have exactly 1 primary key field defined.


let definition: DatabaseDefinition = {
    name: "test",
    tables: [
        {
            name: "player",
            columns: [
                { name: "id", unique: true, primary: true },
                { name: "name", unique: false },
                { name: "currentTeam", unique: false },
                { name: "battingHand", unique: false },
                { name: "throwingHand", unique: false }
            ]
        }
    ]
}

await db.createDatabase(definition)

Use the database

await db.useDatabase("my-database")

Add a record and retreive it by the primary key. Note: The primary key must be a string.


//Start transaction
db.startTransaction()

//Save it
db.insert("player", {
    id: '101',
    name: "Andrew McCutchen",
    currentTeam: "PIT",
    battingHand: "R",
    throwingHand: "R"
})

//Commit changes
await db.commit()


//Retrieve it
let player = await store.get("player", '101')

Now we're going to add a few more players


//Start transaction
db.startTransaction()

store.insert("player", {
  id: '102',
  name: "Pedro Alvarez",
  currentTeam: "BAL",
  battingHand: "R",
  throwingHand: "R"
})

store.insert("player", {
    id: '103',
    name: "Jordy Mercer",
    currentTeam: "PIT",
    battingHand: "L",
    throwingHand: "R"
})

store.insert("player", {
    id: '104',
    name: "Doug Drabek",
    currentTeam: "BAL",
    battingHand: "L",
    throwingHand: "R"
})

//Commit changes
await db.commit()

Now retreive the values by the secondary indexes.

//Get players who play for PIT
let teamPIT = await store.searchIndex({
    table: "players",
    index: "currentTeam",
    value: "PIT",
    sortDirection: "desc",
    offset: 0,
    limit: 100
})


//Get players who who bat right handed. 
let battingR = await store.searchIndex({
    table: "players",
    index: "battingHand",
    value: "R",
    sortDirection: "desc",
    offset: 0,
    limit: 100
})

Update a player with new info

db.startTransaction()

db.update("test-table", {
    id: '101',
    name: "Andrew McCutchen",
    currentTeam: "PIT",
    battingHand: "L", //was R
    throwingHand: "R"
})

await db.commit()

Delete a row


db.startTransaction()
db.delete("test-table", '103')

await db.commit()

Get the CID of the database.

let cid = await db.getDatabaseCid('players')

Load database from CID.

await db.updateFromCid("test", "QmSRtaj7Vu8Q4YhcU32xaiHvmKR4KD5h7WR27azzeECCki")

Examples can be found in the tests.

API

MFdb exposes the following functions:

startTransaction()

  • Discard any uncommitted changes and begin a new transaction. All puts and deletes must have an active transaction.

async commit()

  • Flushes uncommitted changes to disk.

async createDatabase(definition: DatabaseDefinition)

  • Creates a database with the passed in name.

async databaseExists(database: string) : Promise

  • Checks whether a database exists or not.

async dropDatabase(name: string)

  • Drops a database by name.

async useDatabase(name: string)

  • Switch the active database to the passed in one. All table related functions will use this value.

insert(table: string, value: any)

  • Stores a record in a table. Throws exception if a record already exists with that primary key.

update(table:string, value:any)

  • Updates a record in a table. Throws exception if the record does NOT exist already.

put(table:strig, value:any)

  • Calls insert if the record doesn't already exists. Calls update if it does exist. Slower than calling insert or update directly.

async get(table: string, key: any)

  • Query a table by primary key. Returns a single record.

async getCID(table: string, key: any)

  • Gets the CID of the value stored in a specific table with key.

async searchIndex(indexSearch:IndexSearch)

  • Get rows in a table that match the passed value for the supplied index. If no index is supplied it will search the primary index.

Search request is an object with the following fields:

interface IndexSearch {
    table: string, 
    index:string, 
    value?:any, 
    sortDirection:SortDirection  
    offset: number
    limit: number 
}

//Example:

//Get players who who bat right handed. 
let battingR = await store.searchIndex({
    table: "players",
    index: "battingHand",
    value: "R",
    sortDirection: "desc",
    offset: 0,
    limit: 100
})

delete(table:string, key: any)

  • Delete a row in a table by key.

async count(table: string)

  • Count the records in a table.

async flushToMFS(table: string)

  • Flushes the database to MFS for backup.

async getDatabaseCID(name: string)

  • Get the IPFS CID for the mutable file system folder where the database is stored.

Data Definition Interface

interface DatabaseDefinition {
    name:string 
    tables:TableDefinition[]
}

interface TableDefinition {
    name: string
    columns: ColumnDefinition[]
}

interface ColumnDefinition {
    name: string
    primary?: boolean
    unique: boolean
}