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 🙏

© 2026 – Pkg Stats / Ryan Hefner

min-model

v0.2.8

Published

A model layer for MinDB.

Readme

min-model

This is a model layer for MinDB. It can make MinDB more human-friendly and more fit to the real application development.

Installation

min-model can be install by NPM.

$ npm install min-model --save --production

Of course, you can include it into your page with <script> tag.

<script type="application/javascript" src="/path/to/script/model.js"></script>

BTW, min-model is also friendly with browserify, webpack and rollup.

Polyfill

min-model is using Symbol, Map and Promise that are new features in ES2015. So unfortunately if you want to use min-model in the old browsers, you are need to include the polyfills to make them work. Such as es6-shim and es6-symbol.

$ npm i es6-shim es6-symbol --save-dev
import 'es6-shim'
import 'es6-symbol/implement'

Usage

Obviously, min-model is depends on MinDB. So you need to install MinDB first.

import min from 'min'
import Model from 'min-model'

// And then you must make `min-model` knows
// which MinDB database it should use.
// Bc MinDB has the `min.fork()` method to
// fork a new database.

Model.use(min)

Now, you can extend a model which you need to use. For example, here is a Contacts app, so we need to create a Contact model to perform every person in the list.

// Syntax: Model.extend(name: String, columns: Object)

const Contact = Model.extend('contact', {
  name: String,
  memo: 'There is nothing about him/her.',
  // `min-model` will automatically detect
  // this column is a String column.
  number: Number
})

Model.extend receives an object that declares columns of the model. Is can include the native type constructor or the default value of a new one.

const contact = new Contact({
  name: 'Will Wen Gunn',
  number: 13800138000
})

Here are the constructor of the Model and its subclasses.

| Key | Function | Return | | ----------------- | ---------------------------------------- | -------------------------- | | key | The unique key of the instance | String | | get(key) | Fetch the value on the key | Promise(Any) | | set(key, value) | Modify the value on the key | Promise([ String, Any ]) | | reset(key) | Reset the value on the key back the default one | Promise | | reset() | Reset the whole instance | Promise | | remove() | Remove the instance from the database | Promise |

The instances also have an event will be emitted.

| Event | Trigger | | ------- | ---------------------------------------- | | ready | When the instance data was stored in the database and be ready to process |

Lifecyle

The model instance have a lifecyle like following:

  • beforeValidate
  • beforeStore
  • ready
  • beforeUpdate
  • afterUpdate
  • beforeRemove
  • afterRemove

These lifecycle hook can simply use in the Model.extend().

const Contact = Model.extend('contact', {
  name: String,
  memo: 'There is nothing about him/her.',
  number: Number,

  beforeValidata(content) {
    // convert the number to integer
    content.age = parseInt(content)
  }
})

For real application development, the subclasses of Model also have some static methods for management and searching.

| Key | Function | Return | | ----------------------- | ---------------------------------------- | ------------------ | | fetch(key) | Fetch the exists instance by its key | Promise(Model) | | setIndex(column) | Set a indexer on the column for fast searching | Indexer | | search(column, query) | Searching the instances by the column | Promise([Model]) |

Indexes

For fast searching, min-model provide a set of simple but strong algorithms for creating some indexes on the database.

By default, min-model support the native types following.

  • String (which can be split by comma(,), dot(.), colon(:), semicolon(;), exclamation mark(!), quotation mark(" and ') and spaces)
  • Number
  • Boolean
  • Object
  • Array
  • Date
  • Error (base on the messages of the errors)

Indexes Usage

For creating indexes, you need to call a static method of the subclasses.

// Syntax: Model.setIndex(column) : Indexer

let indexer = Contact.setIndex('name')
indexer = Contact.setIndex('number')

Indexer also has a ready event will be emitted when it is ready for use, but it is not necessary for listening.

// Syntax: Model.search(column, query)

Contact
  .search('name', 'Mike') // maybe there are not just one Mike
  .search('memo', 'Engineer')
   // Yes, you can search a column without creating a indexer
   // `min-model` will use the last search result as the pre-flight data
   // in this search operation.
   .then(result => console.log(result))

Custom Indexer

If you think the default indexers are not fit for your application, you can build a custom indexer for it.

min-model provides a BaseIndexer which is bases on Inverted index algorithm. You can extends a subclass from it and overwrite the indexMapper method and search (not required) method easily to build your own indexer.

After that, you can use Model.setIndexer(type, Indexer) to set up.

| Method | Function | Return | Requred | | ------------------------ | ---------------------------------------- | ------- | ------- | | indexMapper(value) | The method to convert the value into the indexes | Array | √ | | search(query, preData) | The layer method to receive the search result from the BaseIndexer and return it to the logical program | Promise | |

import moment from 'moment'
// Here is a 3rd module named moment.js

class FormatedDateIndexer extends Model.BaseIndexer {
  indexMapper(value) {
    // ...
    // value would like '2016-05-01'
    return moment(value).format('YYYY-MM-DD').split('-').map(Number)
  }
}

Model.setIndexer(Date, FormatedDateIndexer)

search method is a upper layer method for receive the result from the bottom layer and passing it back to the logical program. When indexes from indexMapper could not filter the result correctly, you will need to overwrite the search method for the last processing.

search method must receive two arguments, the first one is the query condition and another is the previous data from the last searching operation. The result from the bottom layer can be received by calling the this._search, you should call it and passing the same arguments.

export default class NumberIndexer extends Model.BaseIndexer {

  indexMapper(number) {
    return [
      number % 3,
      number % 5,
      number % 7
    ]
  }

  search(query, preData) {
    return this._search(query, preData)
      .then(result => Promise.resolve(
        result.filter(item => item[this.key] === query)
      ))
  }
}

Of course, you can set the custom indexer just for a single column too.

Contact.setIndexerForColumn('number', NumberIndexer)

Async Indexer

In sometime, computing the indexes in the local device is not wise so we need to use some API to achieve.

You need to set a property named async to be true and indexMapper method should returns a Promise object.

class ChineseStringIndexer extends Model.BaseIndexer {
  get async() { return true }

  indexMapper(val) {
    return new Promise((resolve, reject) => {
      fetch(`http://api.pullword.com/get.php?source=${encodeURIComponent(val)}&param1=0.5&param2=0`)
        .then(res => res.text())
        .then(body => resolve(body.split('\r\n').filter(Boolean)))
        .catch(reject)
    })
  }
}

Contact.setIndexerForColumn('name', ChineseStringIndexer)

Build min-model

If you wanna build min-model by yourself, you need to clone the project to your machine and install the development dependences.

$ cd min-model
$ npm install .

Make your change and run.

$ npm run-script build

Test cases

Test cases are coming soon.