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

idb-entity

v0.1.2

Published

Entity manager for the HTML5 IndexedDB

Downloads

5

Readme

idb-entity

Build Status npm License

The idb-entity is an ORM-like Entity manager for the HTML5 IndexedDB. The idb-entity has Promise-oriented API and provides an advanced query API (provided by the indexed-db.es6 library).

Quickstart

Here you will find the basic information on how to use the idb-entity library. Please check the Wiki and the indexed-db.es6 library for a more detailed description and examples.

You can install the idb-entity library into your project using npm:

npm install --save idb-entity

Next you can choose to use either the ES2015 modules (located in es2015/), or you may use any transpiler you like (for example Babel or Traceur) to transpile the ES2015 modules to a module system of your choice.

Connecting to a database

The idb-entity relies on the indexed-db.es6 for database connection and low-level operations. A quick example is shown below, more detailed description can be found at the indexed-db.es6 project's website.

import DBFactory from "indexed-db.es6/es2015/DBFactory"
import EntityManagerFactory from "idb-entity/es2015/EntityManagerFactory"

let entityManagerFactoryPromise = DBFactory.open("my database", {
  version: 1,
  objectStores: [{
    name: "fooBar",
    keyPath: null,
    autoIncrement: true,
    indexes: [{
      name: "some index",
      keyPath: "id",
      unique: false,
      multiEntry: true
    }]
  }]
}).then((database) => {
  return new EntityManagerFactory(database)
})

Alternatively, the EntityManagerFactory also accepts a connection promise:

import DBFactory from "indexed-db.es6/es2015/DBFactory"
import EntityManagerFactory from "idb-entity/es2015/EntityManagerFactory"

let connectionPromise = DBFactory.open("my database", {
  ... // database schema goes here
})

let entityManagerFactory = new EntityManagerFactory(connectionPromise)

Once you are done communicating with the database, you can close the connection using the close() method:

entityManagerFactory.close().then(() => {
  // the connection is now terminated
})

Defining entity types

The entity manager relies on typed entities instead of plain objects and object store names for practical reasons (this also makes code debugging easier). To define an entity type, create a new class that extends the AbstractEntity class and defines the static objectStore property:

import AbstractEntity from "idb-entity/es2015/AbstractEntity"

export default class FooBar extends AbstractEntity {
  static get objectStore() {
    return "fooBar" // must be a non-empty string
  }
}

The objectStore property defines the name of the Indexed DB object store the entity manager will use to store the entities of this type. The object stores must not be shared among entity types.

Getting an entity manager

The entity manager is used to handle entity manipulation. To get an instance of the entity manager, use the createEntityManager() method:

let entityManager = entityManagerFactory.createEntityManager()

Every entity manager instance should be used only for a single operation (for example reacting to a user action or a message received from the server). Once the operation at hand has been handled, the entity manager instance should be discarded.

Entity manager instances should never be used between operations, nor should a single instance be shared across the whole application - this would most likely lead to data consistency issues and errors caused by attempting to start multiple (read-write) transactions on the same entity manager.

Note that the entity manager manages entities in a persistence context only while a transaction is active, because the data consistency is impossible to assure outside a transaction. The entity manager's persistence context is automatically cleared after a transaction is ended.

Fetching entities

The entity manager allows you to fetch entities from an Indexed DB database without having to explicitly start a new transaction. Single records can be fetched using the find() method:

entityManager.find(FooBar /* entity class */, primaryKey).then((entity) => {
  // do something
})

It is also possible to execute high-level queries on an entity object store:

entityManager.query(
  FooBar /* entity class */,
  optionalFilter,
  optionalOrderBy,
  optionalOffset,
  optionalLimit
).then((entities) => {
  // do something
})

The query API is quite powerful, you can learn more about it at the indexed-db.es6 wiki.

It is also possible to reload an entity from the database:

entityManager.refresh(entity).then((refreshedEntity) => {
  entity === refreshedEntity // true
  // do something
})

Saving and deleting single entities

Entities can be saved in the database using the persist() method:

let entity = new FooBar({
  foo: "bar",
  created: new Date()
})
entityManager.persist(entity).then((savedEntity) => {
  entity === savedEntity // true
  // the entity will have its primary key set on its key path
})

To delete a previously created entity, use the remove() method:

entityManager.remove(FooBar /* entity class */, primaryKey).then(() => {
  // the entity has been deleted
})

Updating and deleting groups of entities

Groups of entities can be easily modified using the updateQuery() method:

entityManager.updateQuery(
  FooBar /* entity class */,
  optionalFilter,
  optionalOrderBy,
  optionalOffset,
  optionalLimit
)((entity) => {
  // modify the entity as needed, there is no need to return the entity
}).then((updatedEntitiesCount) => {
  // do something
})

To delete a group of entities, use the deleteQuery() method:

entityManager.deleteQuery(
  FooBar /* entity class */,
  optionalFilter,
  optionalOrderBy,
  optionalOffset,
  optionalLimit
).then((deletedEntitiesCount) => {
   // do something
 })

Updating single records and running transactions

To update a single record, it must be modified within a transaction. The preferred and safe way to run a transaction is using the runTransaction() method:

entityManager.runTransaction(() => {
  return entityManager.find(FooBar, primaryKey).then((entity) => {
    entity.modified = true // example modification
  })
}).then(() => {
  // transaction has ended and the entity has been saved
  
  // re-fetch the entity from the database
  return entityManager.find(FooBar, primaryKey)
}).then((entity) => {
  entity.modified // true
})

So how does this work? The entity manager keeps track of entities used within a transaction using its persistence context.

When a transaction is to be committed, the entity manager determines which entities in its persistence context have been modified, and saved the modified ones into the database.

Likewise, if a transaction is aborted, the entity manager reverts any modifications done to the entities in its persistence context.

The transaction run using the runTransaction() method is committed when the promised returned from the passed-in callback is resolved. The transaction will be aborted if the returned promise is rejected.

API Documentation

The source code is well documented using JSDoc docblock comments. Go ahead and take a look!

Browser support

The browser compatibility is provided by the indexed-db.es6 library. To see the current browser compatibility, see the library documentation.

The current state of this project

There are no current plans for additional features (unless a good case for adding them is made), but the project accepts bug fixes if new bugs are discovered.

Contributing

Time is precious, so, if you would like to contribute (bug fixing, test writing or feature addition), follow these steps:

  • fork
  • implement (follow the code style)
  • pull request
  • wait for approval/rejection of the pull request

Filing a bug issue might get me to fix the bug, but filing a feature request will not as I don't have the time to work on this project full-time. Thank you for understanding.